// Glaze Library // For the license information refer to glaze.hpp #pragma once #include "glaze/core/common.hpp" #include "glaze/core/read.hpp" #include "glaze/core/write.hpp" #include "glaze/json/read.hpp" #include "glaze/json/write.hpp" namespace glz { template struct flatten_map_wrapper final { static constexpr auto glaze_reflect = false; using value_type = T; T& value; }; template requires(range && pair_t>) flatten_map_wrapper(T&) -> flatten_map_wrapper; template constexpr auto flatten_map_impl() noexcept { return [](auto&& value) { using Value = std::decay_t; using Member = std::decay_t>; return flatten_map_wrapper{get_member(value, MemPtr)}; }; } template inline constexpr auto flatten_map = flatten_map_impl(); template void write_flatten_map_elements(const T& value, is_context auto&& ctx, B&& b, auto& ix, bool& first) { using V = std::remove_cvref_t; auto write_value = [&](const auto& item) { if (!first) { write_array_entry_separator(ctx, b, ix); } serialize::op()>(item, ctx, b, ix); first = false; }; if constexpr (pair_t) { write_flatten_map_elements(value.first, ctx, b, ix, first); if (bool(ctx.error)) [[unlikely]] { return; } write_flatten_map_elements(value.second, ctx, b, ix, first); } else if constexpr (glaze_array_t) { static constexpr auto N = glz::tuple_size_v>; for_each([&]() { if (bool(ctx.error)) [[unlikely]] { return; } write_flatten_map_elements(get_member(value, glz::get(meta_v)), ctx, b, ix, first); }); } else if constexpr (is_std_tuple) { static constexpr auto N = glz::tuple_size_v; for_each([&]() { if (bool(ctx.error)) [[unlikely]] { return; } write_flatten_map_elements(std::get(value), ctx, b, ix, first); }); } else if constexpr (tuple_t) { static constexpr auto N = glz::tuple_size_v; for_each([&]() { if (bool(ctx.error)) [[unlikely]] { return; } write_flatten_map_elements(glz::get(value), ctx, b, ix, first); }); } else if constexpr (has_fixed_size_container) { static constexpr auto N = get_size(); for_each([&]() { if (bool(ctx.error)) [[unlikely]] { return; } write_flatten_map_elements(value[I], ctx, b, ix, first); }); } else { write_value(value); } } template void write_flatten_map_container(const T& value, is_context auto&& ctx, B&& b, auto& ix) { if constexpr (!check_opening_handled(Opts)) { dump('[', b, ix); } bool first = true; if (!empty_range(value) && Opts.prettify && check_new_lines_in_arrays(Opts)) { ctx.depth += check_indentation_width(Opts); dump_newline_indent(check_indentation_char(Opts), ctx.depth, b, ix); } for (auto&& [key, entry_val] : value) { write_flatten_map_elements(key, ctx, b, ix, first); if (bool(ctx.error)) [[unlikely]] { return; } if (!first) { write_array_entry_separator(ctx, b, ix); } serialize::op()>(entry_val, ctx, b, ix); if (bool(ctx.error)) [[unlikely]] { return; } first = false; } if (!empty_range(value) && Opts.prettify && check_new_lines_in_arrays(Opts)) { ctx.depth -= check_indentation_width(Opts); dump_newline_indent(check_indentation_char(Opts), ctx.depth, b, ix); } if constexpr (!check_closing_handled(Opts)) { dump(']', b, ix); } } template void read_flatten_map_elements(T& value, is_context auto&& ctx, auto&& it, auto end, bool& first) { using V = std::remove_cvref_t; auto parse_value = [&](auto& item) { if (!first) { if (skip_ws(ctx, it, end)) { return; } if (match_invalid_end<',', Opts>(ctx, it, end)) { return; } if (skip_ws(ctx, it, end)) { return; } } parse::op()>(item, ctx, it, end); if (bool(ctx.error)) [[unlikely]] { return; } first = false; }; if constexpr (pair_t) { read_flatten_map_elements(value.first, ctx, it, end, first); if (bool(ctx.error)) [[unlikely]] { return; } read_flatten_map_elements(value.second, ctx, it, end, first); } else if constexpr (glaze_array_t) { static constexpr auto N = reflect::size; for_each([&]() { if (bool(ctx.error)) [[unlikely]] { return; } read_flatten_map_elements(get_member(value, glz::get(meta_v)), ctx, it, end, first); }); } else if constexpr (is_std_tuple) { static constexpr auto N = glz::tuple_size_v; for_each([&]() { if (bool(ctx.error)) [[unlikely]] { return; } read_flatten_map_elements(std::get(value), ctx, it, end, first); }); } else if constexpr (tuple_t) { static constexpr auto N = glz::tuple_size_v; for_each([&]() { if (bool(ctx.error)) [[unlikely]] { return; } read_flatten_map_elements(glz::get(value), ctx, it, end, first); }); } else if constexpr (has_fixed_size_container) { static constexpr auto N = get_size(); for_each([&]() { if (bool(ctx.error)) [[unlikely]] { return; } read_flatten_map_elements(value[I], ctx, it, end, first); }); } else { parse_value(value); } } template requires(pair_t>) void read_flatten_map_container(T& value, is_context auto&& ctx, auto&& it, auto end) { static constexpr auto Opts = opening_handled_off()>(); if constexpr (!check_opening_handled(Options)) { if constexpr (!check_ws_handled(Options)) { if (skip_ws(ctx, it, end)) { return; } } if (match_invalid_end<'[', Opts>(ctx, it, end)) { return; } if constexpr (not Opts.null_terminated) { if (it == end) [[unlikely]] { ctx.error = error_code::unexpected_end; return; } ++ctx.depth; } } if constexpr (readable_array_t) { value.clear(); } if (skip_ws(ctx, it, end)) { return; } if (*it == ']') { ++it; if constexpr (not Opts.null_terminated) { --ctx.depth; if (it == end) { ctx.error = error_code::end_reached; } } return; } while (it < end) { using entry_t = range_value_t; using key_t = std::remove_const_t; key_t key{}; bool first = true; read_flatten_map_elements(key, ctx, it, end, first); if (bool(ctx.error)) [[unlikely]] { return; } if (skip_ws(ctx, it, end)) { return; } if (match_invalid_end<',', Opts>(ctx, it, end)) { return; } if (skip_ws(ctx, it, end)) { return; } if constexpr (readable_array_t) { if constexpr (has_try_emplace_back) { if (not value.try_emplace_back()) [[unlikely]] { ctx.error = error_code::exceeded_static_array_size; return; } } else { value.emplace_back(); } auto& entry = value.back(); entry.first = std::move(key); parse::op()>(entry.second, ctx, it, end); } else { parse::op()>(value[key], ctx, it, end); } if (bool(ctx.error)) [[unlikely]] { return; } if (skip_ws(ctx, it, end)) { return; } if (*it == ',') { ++it; if constexpr (not Opts.null_terminated) { if (it == end) [[unlikely]] { ctx.error = error_code::unexpected_end; return; } } continue; } if (*it == ']') { ++it; if constexpr (not Opts.null_terminated) { --ctx.depth; if (it == end) { ctx.error = error_code::end_reached; } } return; } ctx.error = error_code::expected_bracket; return; } ctx.error = error_code::unexpected_end; } template requires(is_specialization_v) struct from { template static void op(auto&& wrapper, is_context auto&& ctx, auto&& it, auto end) { using V = typename std::remove_cvref_t::value_type; static_assert(range && pair_t>, "glz::flatten_map requires a map-like container or a range of pairs"); read_flatten_map_container(wrapper.value, ctx, it, end); } }; template requires(is_specialization_v) struct to { template static void op(auto&& wrapper, is_context auto&& ctx, Args&&... args) { using V = typename std::remove_cvref_t::value_type; static_assert(range && pair_t>, "glz::flatten_map requires a map-like container or a range of pairs"); write_flatten_map_container(wrapper.value, ctx, std::forward(args)...); } }; }