1// __ _____ _____ _____
2// __| | __| | | | JSON for Modern C++
3// | | |__ | | | | | | version 3.11.3
4// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#pragma once
10
11#include <cstddef> // size_t
12#include <iterator> // input_iterator_tag
13#include <string> // string, to_string
14#include <tuple> // tuple_size, get, tuple_element
15#include <utility> // move
16
17#if JSON_HAS_RANGES
18 #include <ranges> // enable_borrowed_range
19#endif
20
21#include <nlohmann/detail/abi_macros.hpp>
22#include <nlohmann/detail/meta/type_traits.hpp>
23#include <nlohmann/detail/value_t.hpp>
24
25NLOHMANN_JSON_NAMESPACE_BEGIN
26namespace detail
27{
28
29template<typename string_type>
30void int_to_string( string_type& target, std::size_t value )
31{
32 // For ADL
33 using std::to_string;
34 target = to_string(value);
35}
36template<typename IteratorType> class iteration_proxy_value
37{
38 public:
39 using difference_type = std::ptrdiff_t;
40 using value_type = iteration_proxy_value;
41 using pointer = value_type *;
42 using reference = value_type &;
43 using iterator_category = std::input_iterator_tag;
44 using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
45
46 private:
47 /// the iterator
48 IteratorType anchor{};
49 /// an index for arrays (used to create key names)
50 std::size_t array_index = 0;
51 /// last stringified array index
52 mutable std::size_t array_index_last = 0;
53 /// a string representation of the array index
54 mutable string_type array_index_str = "0";
55 /// an empty string (to return a reference for primitive values)
56 string_type empty_str{};
57
58 public:
59 explicit iteration_proxy_value() = default;
60 explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0)
61 noexcept(std::is_nothrow_move_constructible<IteratorType>::value
62 && std::is_nothrow_default_constructible<string_type>::value)
63 : anchor(std::move(it))
64 , array_index(array_index_)
65 {}
66
67 iteration_proxy_value(iteration_proxy_value const&) = default;
68 iteration_proxy_value& operator=(iteration_proxy_value const&) = default;
69 // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions
70 iteration_proxy_value(iteration_proxy_value&&)
71 noexcept(std::is_nothrow_move_constructible<IteratorType>::value
72 && std::is_nothrow_move_constructible<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
73 iteration_proxy_value& operator=(iteration_proxy_value&&)
74 noexcept(std::is_nothrow_move_assignable<IteratorType>::value
75 && std::is_nothrow_move_assignable<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
76 ~iteration_proxy_value() = default;
77
78 /// dereference operator (needed for range-based for)
79 const iteration_proxy_value& operator*() const
80 {
81 return *this;
82 }
83
84 /// increment operator (needed for range-based for)
85 iteration_proxy_value& operator++()
86 {
87 ++anchor;
88 ++array_index;
89
90 return *this;
91 }
92
93 iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp)
94 {
95 auto tmp = iteration_proxy_value(anchor, array_index);
96 ++anchor;
97 ++array_index;
98 return tmp;
99 }
100
101 /// equality operator (needed for InputIterator)
102 bool operator==(const iteration_proxy_value& o) const
103 {
104 return anchor == o.anchor;
105 }
106
107 /// inequality operator (needed for range-based for)
108 bool operator!=(const iteration_proxy_value& o) const
109 {
110 return anchor != o.anchor;
111 }
112
113 /// return key of the iterator
114 const string_type& key() const
115 {
116 JSON_ASSERT(anchor.m_object != nullptr);
117
118 switch (anchor.m_object->type())
119 {
120 // use integer array index as key
121 case value_t::array:
122 {
123 if (array_index != array_index_last)
124 {
125 int_to_string( array_index_str, array_index );
126 array_index_last = array_index;
127 }
128 return array_index_str;
129 }
130
131 // use key from the object
132 case value_t::object:
133 return anchor.key();
134
135 // use an empty key for all primitive types
136 case value_t::null:
137 case value_t::string:
138 case value_t::boolean:
139 case value_t::number_integer:
140 case value_t::number_unsigned:
141 case value_t::number_float:
142 case value_t::binary:
143 case value_t::discarded:
144 default:
145 return empty_str;
146 }
147 }
148
149 /// return value of the iterator
150 typename IteratorType::reference value() const
151 {
152 return anchor.value();
153 }
154};
155
156/// proxy class for the items() function
157template<typename IteratorType> class iteration_proxy
158{
159 private:
160 /// the container to iterate
161 typename IteratorType::pointer container = nullptr;
162
163 public:
164 explicit iteration_proxy() = default;
165
166 /// construct iteration proxy from a container
167 explicit iteration_proxy(typename IteratorType::reference cont) noexcept
168 : container(&cont) {}
169
170 iteration_proxy(iteration_proxy const&) = default;
171 iteration_proxy& operator=(iteration_proxy const&) = default;
172 iteration_proxy(iteration_proxy&&) noexcept = default;
173 iteration_proxy& operator=(iteration_proxy&&) noexcept = default;
174 ~iteration_proxy() = default;
175
176 /// return iterator begin (needed for range-based for)
177 iteration_proxy_value<IteratorType> begin() const noexcept
178 {
179 return iteration_proxy_value<IteratorType>(container->begin());
180 }
181
182 /// return iterator end (needed for range-based for)
183 iteration_proxy_value<IteratorType> end() const noexcept
184 {
185 return iteration_proxy_value<IteratorType>(container->end());
186 }
187};
188
189// Structured Bindings Support
190// For further reference see https://blog.tartanllama.xyz/structured-bindings/
191// And see https://github.com/nlohmann/json/pull/1391
192template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
193auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
194{
195 return i.key();
196}
197// Structured Bindings Support
198// For further reference see https://blog.tartanllama.xyz/structured-bindings/
199// And see https://github.com/nlohmann/json/pull/1391
200template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
201auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
202{
203 return i.value();
204}
205
206} // namespace detail
207NLOHMANN_JSON_NAMESPACE_END
208
209// The Addition to the STD Namespace is required to add
210// Structured Bindings Support to the iteration_proxy_value class
211// For further reference see https://blog.tartanllama.xyz/structured-bindings/
212// And see https://github.com/nlohmann/json/pull/1391
213namespace std
214{
215
216#if defined(__clang__)
217 // Fix: https://github.com/nlohmann/json/issues/1401
218 #pragma clang diagnostic push
219 #pragma clang diagnostic ignored "-Wmismatched-tags"
220#endif
221template<typename IteratorType>
222class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
223 : public std::integral_constant<std::size_t, 2> {};
224
225template<std::size_t N, typename IteratorType>
226class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp)
227{
228 public:
229 using type = decltype(
230 get<N>(std::declval <
231 ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
232};
233#if defined(__clang__)
234 #pragma clang diagnostic pop
235#endif
236
237} // namespace std
238
239#if JSON_HAS_RANGES
240 template <typename IteratorType>
241 inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true;
242#endif
243