#pragma once #include // size_t #include // input_iterator_tag #include // string, to_string #include // tuple_size, get, tuple_element #include // move #if JSON_HAS_RANGES #include // enable_borrowed_range #endif #include #include namespace nlohmann { namespace detail { template void int_to_string( string_type& target, std::size_t value ) { // For ADL using std::to_string; target = to_string(value); } template class iteration_proxy_value { public: using difference_type = std::ptrdiff_t; using value_type = iteration_proxy_value; using pointer = value_type *; using reference = value_type &; using iterator_category = std::input_iterator_tag; using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; private: /// the iterator IteratorType anchor{}; /// an index for arrays (used to create key names) std::size_t array_index = 0; /// last stringified array index mutable std::size_t array_index_last = 0; /// a string representation of the array index mutable string_type array_index_str = "0"; /// an empty string (to return a reference for primitive values) string_type empty_str{}; public: explicit iteration_proxy_value() = default; explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0) noexcept(std::is_nothrow_move_constructible::value && std::is_nothrow_default_constructible::value) : anchor(std::move(it)) , array_index(array_index_) {} iteration_proxy_value(iteration_proxy_value const&) = default; iteration_proxy_value& operator=(iteration_proxy_value const&) = default; // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions iteration_proxy_value(iteration_proxy_value&&) noexcept(std::is_nothrow_move_constructible::value && std::is_nothrow_move_constructible::value) = default; iteration_proxy_value& operator=(iteration_proxy_value&&) noexcept(std::is_nothrow_move_assignable::value && std::is_nothrow_move_assignable::value) = default; ~iteration_proxy_value() = default; /// dereference operator (needed for range-based for) const iteration_proxy_value& operator*() const { return *this; } /// increment operator (needed for range-based for) iteration_proxy_value& operator++() { ++anchor; ++array_index; return *this; } iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp) { auto tmp = iteration_proxy_value(anchor, array_index); ++anchor; ++array_index; return tmp; } /// equality operator (needed for InputIterator) bool operator==(const iteration_proxy_value& o) const { return anchor == o.anchor; } /// inequality operator (needed for range-based for) bool operator!=(const iteration_proxy_value& o) const { return anchor != o.anchor; } /// return key of the iterator const string_type& key() const { JSON_ASSERT(anchor.m_object != nullptr); switch (anchor.m_object->type()) { // use integer array index as key case value_t::array: { if (array_index != array_index_last) { int_to_string( array_index_str, array_index ); array_index_last = array_index; } return array_index_str; } // use key from the object case value_t::object: return anchor.key(); // use an empty key for all primitive types case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: case value_t::discarded: default: return empty_str; } } /// return value of the iterator typename IteratorType::reference value() const { return anchor.value(); } }; /// proxy class for the items() function template class iteration_proxy { private: /// the container to iterate typename IteratorType::pointer container = nullptr; public: explicit iteration_proxy() = default; /// construct iteration proxy from a container explicit iteration_proxy(typename IteratorType::reference cont) noexcept : container(&cont) {} iteration_proxy(iteration_proxy const&) = default; iteration_proxy& operator=(iteration_proxy const&) = default; iteration_proxy(iteration_proxy&&) noexcept = default; iteration_proxy& operator=(iteration_proxy&&) noexcept = default; ~iteration_proxy() = default; /// return iterator begin (needed for range-based for) iteration_proxy_value begin() const noexcept { return iteration_proxy_value(container->begin()); } /// return iterator end (needed for range-based for) iteration_proxy_value end() const noexcept { return iteration_proxy_value(container->end()); } }; // Structured Bindings Support // For further reference see https://blog.tartanllama.xyz/structured-bindings/ // And see https://github.com/nlohmann/json/pull/1391 template = 0> auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) { return i.key(); } // Structured Bindings Support // For further reference see https://blog.tartanllama.xyz/structured-bindings/ // And see https://github.com/nlohmann/json/pull/1391 template = 0> auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) { return i.value(); } } // namespace detail } // namespace nlohmann // The Addition to the STD Namespace is required to add // Structured Bindings Support to the iteration_proxy_value class // For further reference see https://blog.tartanllama.xyz/structured-bindings/ // And see https://github.com/nlohmann/json/pull/1391 namespace std { #if defined(__clang__) // Fix: https://github.com/nlohmann/json/issues/1401 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmismatched-tags" #endif template class tuple_size<::nlohmann::detail::iteration_proxy_value> : public std::integral_constant {}; template class tuple_element> { public: using type = decltype( get(std::declval < ::nlohmann::detail::iteration_proxy_value> ())); }; #if defined(__clang__) #pragma clang diagnostic pop #endif } // namespace std #if JSON_HAS_RANGES template inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy> = true; #endif