22#include <userver/utils/constexpr_indices.hpp>
23#include <userver/utils/lazy_prvalue.hpp>
24#include <userver/utils/meta.hpp>
25#include <userver/utils/strong_typedef.hpp>
27#include <userver/dump/common.hpp>
28#include <userver/dump/meta.hpp>
29#include <userver/dump/meta_containers.hpp>
30#include <userver/dump/operations.hpp>
37template <
typename L,
typename R,
typename AP1,
typename AP2,
typename AP3>
42namespace multi_index {
44template <
typename Value,
typename IndexSpecifierList,
typename Allocator>
45class multi_index_container;
50using multi_index::multi_index_container;
55USERVER_NAMESPACE_BEGIN
61template <
typename L,
typename R,
typename... Args>
62using BoostBimap = boost::bimap<L, R, Args...>;
64template <
typename L,
typename R,
typename... Args>
65using BoostBimapLeftKey =
typename BoostBimap<L, R, Args...>::left_key_type;
67template <
typename L,
typename R,
typename... Args>
68using BoostBimapRightKey =
typename BoostBimap<L, R, Args...>::right_key_type;
71auto ReadLazyPrvalue(
Reader& reader) {
72 return utils::LazyPrvalue([&reader] {
return reader.Read<T>(); });
75[[noreturn]]
void ThrowInvalidVariantIndex(
const std::type_info& type, std::size_t index);
77template <
typename VariantType>
78VariantType ReadVariant(
Reader& reader, std::size_t index) {
79 static constexpr auto VariantSize = std::variant_size_v<VariantType>;
80 std::optional<VariantType> result;
82 utils::WithConstexprIndex<VariantSize>(index, [&](
auto index_constant) {
83 static constexpr auto kIndex =
decltype(index_constant)::value;
84 using Alternative = std::variant_alternative_t<kIndex, VariantType>;
86 result.emplace(std::in_place_index<kIndex>, reader.Read<Alternative>());
89 return std::move(*result);
96std::enable_if_t<kIsContainer<T> && kIsWritable<meta::RangeValueType<T>>>
Write(
Writer& writer,
const T& value) {
97 writer.Write(std::size(value));
98 for (
const auto& item : value) {
100 writer.Write(
static_cast<
const meta::RangeValueType<T>&>(item));
96std::enable_if_t<kIsContainer<T> && kIsWritable<meta::RangeValueType<T>>>
Write(
Writer& writer,
const T& value) {
…}
106std::enable_if_t<kIsContainer<T> && kIsReadable<meta::RangeValueType<T>>, T>
Read(
Reader& reader,
To<T>) {
109 if constexpr (meta::kIsReservable<T>) {
110 result.reserve(size);
112 for (std::size_t i = 0; i < size; ++i) {
113 dump::Insert(result, reader.Read<meta::RangeValueType<T>>());
106std::enable_if_t<kIsContainer<T> && kIsReadable<meta::RangeValueType<T>>, T>
Read(
Reader& reader,
To<T>) {
…}
119template <
typename T,
typename U>
120std::enable_if_t<kIsWritable<T> && kIsWritable<U>,
void>
Write(
Writer& writer,
const std::pair<T, U>& value) {
121 writer.Write(value.first);
122 writer.Write(value.second);
120std::enable_if_t<kIsWritable<T> && kIsWritable<U>,
void>
Write(
Writer& writer,
const std::pair<T, U>& value) {
…}
126template <
typename T,
typename U>
127std::enable_if_t<kIsReadable<T> && kIsReadable<U>, std::pair<T, U>>
Read(
Reader& reader,
To<std::pair<T, U>>) {
128 return {reader.Read<T>(), reader.Read<U>()};
127std::enable_if_t<kIsReadable<T> && kIsReadable<U>, std::pair<T, U>>
Read(
Reader& reader,
To<std::pair<T, U>>) {
…}
133std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const std::optional<T>& value) {
134 writer.Write(value.has_value());
135 if (value) writer.Write(*value);
133std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const std::optional<T>& value) {
…}
140std::enable_if_t<kIsReadable<T>, std::optional<T>>
Read(
Reader& reader,
To<std::optional<T>>) {
141 if (!reader
.Read<bool>())
return std::nullopt;
142 return impl::ReadLazyPrvalue<T>(reader);
140std::enable_if_t<kIsReadable<T>, std::optional<T>>
Read(
Reader& reader,
To<std::optional<T>>) {
…}
146template <
typename... Args>
147std::enable_if_t<(
true && ... && kIsWritable<Args>)>
Write(
Writer& writer,
const std::variant<Args...>& value) {
148 writer.Write(value.index());
149 std::visit([&writer](
const auto& inner) { writer.Write(inner); }, value);
147std::enable_if_t<(
true && ... && kIsWritable<Args>)>
Write(
Writer& writer,
const std::variant<Args...>& value) {
…}
153template <
typename... Args>
154std::enable_if_t<(
true && ... && (std::is_move_constructible_v<Args> && kIsReadable<Args>)), std::variant<Args...>>
157 if (index >=
sizeof...(Args)) {
158 impl::ThrowInvalidVariantIndex(
typeid(std::variant<Args...>), index);
160 return impl::ReadVariant<std::variant<Args...>>(reader, index);
167 return Read(reader,
To<T>{});
172std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const utils::StrongTypedef<Tag, T, Ops>& object) {
173 writer.Write(object.GetUnderlying());
172std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const utils::StrongTypedef<Tag, T, Ops>& object) {
…}
178std::enable_if_t<kIsReadable<T>,
utils::StrongTypedef<Tag, T, Ops>>
180 return utils::StrongTypedef<Tag, T, Ops>{reader.Read<T>()};
185std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const std::unique_ptr<T>& ptr) {
186 writer
.Write(static_cast<
bool>(ptr)
);
187 if (ptr) writer.Write(*ptr);
185std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const std::unique_ptr<T>& ptr) {
…}
192std::enable_if_t<kIsReadable<T>, std::unique_ptr<T>>
Read(
Reader& reader,
To<std::unique_ptr<T>>) {
194 return std::make_unique<T>(impl::ReadLazyPrvalue<T>(reader));
192std::enable_if_t<kIsReadable<T>, std::unique_ptr<T>>
Read(
Reader& reader,
To<std::unique_ptr<T>>) {
…}
201std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const std::shared_ptr<T>& ptr) {
202 writer
.Write(static_cast<
bool>(ptr)
);
203 if (ptr) writer.Write(*ptr);
201std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const std::shared_ptr<T>& ptr) {
…}
210std::enable_if_t<kIsReadable<T>, std::shared_ptr<T>>
Read(
Reader& reader,
To<std::shared_ptr<T>>) {
212 return std::make_shared<T>(impl::ReadLazyPrvalue<T>(reader));
210std::enable_if_t<kIsReadable<T>, std::shared_ptr<T>>
Read(
Reader& reader,
To<std::shared_ptr<T>>) {
…}
216template <
typename L,
typename R,
typename... Args>
218 kIsWritable<impl::BoostBimapLeftKey<L, R, Args...>> && kIsWritable<impl::BoostBimapRightKey<L, R, Args...>>>
220 writer.Write(map.size());
222 for (
const auto& [left, right] : map) {
229template <
typename L,
typename R,
typename... Args>
231 kIsReadable<impl::BoostBimapLeftKey<L, R, Args...>> && kIsReadable<impl::BoostBimapRightKey<L, R, Args...>>,
232 boost::bimap<L, R, Args...>>
234 using BoostBimap = impl::BoostBimap<L, R, Args...>;
236 using BoostBimapLeftKey = impl::BoostBimapLeftKey<L, R, Args...>;
237 using BoostBimapRightKey = impl::BoostBimapRightKey<L, R, Args...>;
239 using BoostBimapSizeType =
typename BoostBimap::size_type;
244 const auto size = reader.Read<BoostBimapSizeType>();
245 for (BoostBimapSizeType i = 0; i < size; ++i) {
248 reader.Read<BoostBimapLeftKey>(),
249 reader.Read<BoostBimapRightKey>(),
257template <
typename T,
typename Index,
typename Alloc>
258std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const boost::multi_index_container<T, Index, Alloc>& container) {
259 writer.Write(container.
template get<0>().size());
260 for (
auto& item : container.
template get<0>()) {
258std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const boost::multi_index_container<T, Index, Alloc>& container) {
…}
266template <
typename T,
typename Index,
typename Alloc>
267std::enable_if_t<kIsReadable<T>, boost::multi_index_container<T, Index, Alloc>>
268Read(
Reader& reader,
To<boost::multi_index_container<T, Index, Alloc>>) {
270 boost::multi_index_container<T, Index, Alloc> container;
273 if constexpr (meta::kIsReservable<boost::multi_index_container<T, Index, Alloc>>) {
274 container.reserve(size);
277 for (std::size_t i = 0; i < size; ++i) {
278 container.insert(reader.Read<T>());