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 kVariantSize = std::variant_size_v<VariantType>;
80 std::optional<VariantType> result;
82 utils::WithConstexprIndex<kVariantSize>(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));
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>>());
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);
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>()};
133std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const std::optional<T>& value) {
134 writer.Write(value.has_value());
136 writer.Write(*value);
142std::enable_if_t<kIsReadable<T>, std::optional<T>>
Read(
Reader& reader, To<std::optional<T>>) {
146 return impl::ReadLazyPrvalue<T>(reader);
150template <
typename... Args>
151std::enable_if_t<(
true && ... && kIsWritable<Args>)>
Write(
Writer& writer,
const std::variant<Args...>& value) {
152 writer.Write(value.index());
153 std::visit([&writer](
const auto& inner) { writer.Write(inner); }, value);
157template <
typename... Args>
158std::enable_if_t<(
true && ... && (std::is_move_constructible_v<Args> && kIsReadable<Args>)), std::variant<Args...>>
161 if (index >=
sizeof...(Args)) {
162 impl::ThrowInvalidVariantIndex(
typeid(std::variant<Args...>), index);
164 return impl::ReadVariant<std::variant<Args...>>(reader, index);
170std::enable_if_t<kIsReadable<T>, T>
Read(
Reader& reader, To<
const T>) {
171 return Read(reader, To<T>{});
175template <
typename Tag,
typename T, utils::StrongTypedefOps Ops>
176std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const utils::StrongTypedef<Tag, T, Ops>& object) {
177 writer.Write(object.GetUnderlying());
181template <
typename Tag,
typename T, utils::StrongTypedefOps Ops>
182std::enable_if_t<kIsReadable<T>, utils::StrongTypedef<Tag, T, Ops>>
184 return utils::StrongTypedef<Tag, T, Ops>{reader.Read<T>()};
189std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const std::unique_ptr<T>& ptr) {
190 writer
.Write(static_cast<
bool>(ptr)
);
198std::enable_if_t<kIsReadable<T>, std::unique_ptr<T>>
Read(
Reader& reader, To<std::unique_ptr<T>>) {
202 return std::make_unique<T>(impl::ReadLazyPrvalue<T>(reader));
209std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const std::shared_ptr<T>& ptr) {
210 writer
.Write(static_cast<
bool>(ptr)
);
220std::enable_if_t<kIsReadable<T>, std::shared_ptr<T>>
Read(
Reader& reader, To<std::shared_ptr<T>>) {
224 return std::make_shared<T>(impl::ReadLazyPrvalue<T>(reader));
228template <
typename L,
typename R,
typename... Args>
230 kIsWritable<impl::BoostBimapLeftKey<L, R, Args...>> && kIsWritable<impl::BoostBimapRightKey<L, R, Args...>>>
232 writer.Write(map.size());
234 for (
const auto& [left, right] : map) {
241template <
typename L,
typename R,
typename... Args>
243 kIsReadable<impl::BoostBimapLeftKey<L, R, Args...>> && kIsReadable<impl::BoostBimapRightKey<L, R, Args...>>,
244 boost::bimap<L, R, Args...>>
246 using BoostBimap = impl::BoostBimap<L, R, Args...>;
248 using BoostBimapLeftKey = impl::BoostBimapLeftKey<L, R, Args...>;
249 using BoostBimapRightKey = impl::BoostBimapRightKey<L, R, Args...>;
251 using BoostBimapSizeType =
typename BoostBimap::size_type;
256 const auto size = reader.Read<BoostBimapSizeType>();
257 for (BoostBimapSizeType i = 0; i < size; ++i) {
260 reader.Read<BoostBimapLeftKey>(),
261 reader.Read<BoostBimapRightKey>(),
269template <
typename T,
typename Index,
typename Alloc>
270std::enable_if_t<kIsWritable<T>>
Write(
Writer& writer,
const boost::multi_index_container<T, Index, Alloc>& container) {
271 writer.Write(container.
template get<0>().size());
272 for (
auto& item : container.
template get<0>()) {
278template <
typename T,
typename Index,
typename Alloc>
279std::enable_if_t<kIsReadable<T>, boost::multi_index_container<T, Index, Alloc>>
280Read(
Reader& reader, To<boost::multi_index_container<T, Index, Alloc>>) {
282 boost::multi_index_container<T, Index, Alloc> container;
285 if constexpr (meta::kIsReservable<boost::multi_index_container<T, Index, Alloc>>) {
286 container.reserve(size);
289 for (std::size_t i = 0; i < size; ++i) {
290 container.insert(reader.Read<T>());