9#include <userver/formats/json/value.hpp>
10#include <userver/formats/parse/common_containers.hpp>
11#include <userver/formats/serialize/common_containers.hpp>
12#include <userver/utils/impl/transparent_hash.hpp>
14USERVER_NAMESPACE_BEGIN
23[[noreturn]]
void ThrowNoValueException(std::string_view dict_name, std::string_view key);
41template <
typename ValueType>
42class DefaultDict final {
44 using DictType = utils::impl::TransparentMap<std::string, ValueType>;
45 using const_iterator =
typename DictType::const_iterator;
46 using iterator = const_iterator;
47 using value_type =
typename DictType::value_type;
48 using key_type = std::string;
49 using mapped_type = ValueType;
50 using init_list = std::initializer_list<std::pair<std::string_view, ValueType>>;
52 DefaultDict() =
default;
54 DefaultDict(init_list contents) : dict_(contents.begin(), contents.end()) {}
56 DefaultDict(DictType dict) : dict_(std::move(dict)) {}
58 DefaultDict(std::string name, init_list contents)
59 : name_(std::move(name)), dict_(contents.begin(), contents.end()) {}
61 DefaultDict(std::string name, DictType dict) : name_(std::move(name)), dict_(std::move(dict)) {}
65 bool HasDefaultValue()
const noexcept {
return HasValue(kDefaultDictDefaultName); }
68 bool HasValue(std::string_view key)
const noexcept {
69 return utils::impl::FindTransparent(dict_, key) != dict_.end();
75 const auto it = utils::impl::FindTransparent(dict_, kDefaultDictDefaultName);
76 if (it == dict_.end()) {
77 impl::ThrowNoValueException(name_, kDefaultDictDefaultName);
85 const ValueType&
operator[](std::string_view key)
const {
86 auto it = utils::impl::FindTransparent(dict_, key);
87 if (it == dict_.end()) {
88 it = utils::impl::FindTransparent(dict_, kDefaultDictDefaultName);
89 if (it == dict_.end()) {
90 impl::ThrowNoValueException(name_, key);
97 template <
typename StringType>
98 const ValueType&
operator[](
const std::optional<StringType>& key)
const {
103 const ValueType& Get(std::string_view key)
const {
return (*
this)[key]; }
106 template <
typename StringType>
107 const ValueType&
Get(
const std::optional<StringType>& key)
const {
114 std::optional<ValueType>
GetOptional(std::string_view key)
const {
115 auto it = utils::impl::FindTransparent(dict_, key);
116 if (it == dict_.end()) {
117 it = utils::impl::FindTransparent(dict_, kDefaultDictDefaultName);
118 if (it == dict_.end())
return std::nullopt;
128 void SetDefault(ValueType value) { Set(kDefaultDictDefaultName, std::move(value)); }
134 template <
typename StringType>
135 void Set(StringType&& key, ValueType value) {
136 utils::impl::TransparentInsertOrAssign(dict_, std::forward<StringType>(key), std::move(value));
139 auto begin()
const noexcept {
return dict_.begin(); }
141 auto end()
const noexcept {
return dict_.end(); }
143 const std::string& GetName()
const noexcept {
return name_; }
145 bool operator==(
const DefaultDict& r)
const noexcept {
return dict_ == r.dict_; }
147 bool operator!=(
const DefaultDict& r)
const noexcept {
return !(*
this == r); }
154template <
typename Value,
typename T>
155std::enable_if_t<formats::common::kIsFormatValue<Value>, DefaultDict<T>>
156Parse(
const Value& value, formats::parse::To<DefaultDict<T>>) {
157 return DefaultDict<T>{value.GetPath(), value.
template As<
typename DefaultDict<T>::DictType>()};