1 // __ _____ _____ _____
2 // __| | __| | | | JSON for Modern C++
3 // | | |__ | | | | | | version 3.11.2
4 // |_____|_____|_____|_|___| https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2022 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
25 NLOHMANN_JSON_NAMESPACE_BEGIN
26 namespace detail
27 {
28
29 template<typename string_type>
int_to_string(string_type & target,std::size_t value)30 void 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 }
36 template<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;
iteration_proxy_value(IteratorType it,std::size_t array_index_=0)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;
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;
76 ~iteration_proxy_value() = default;
77
78 /// dereference operator (needed for range-based for)
operator *() const79 const iteration_proxy_value& operator*() const
80 {
81 return *this;
82 }
83
84 /// increment operator (needed for range-based for)
operator ++()85 iteration_proxy_value& operator++()
86 {
87 ++anchor;
88 ++array_index;
89
90 return *this;
91 }
92
operator ++(int)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)
operator ==(const iteration_proxy_value & o) const102 bool operator==(const iteration_proxy_value& o) const
103 {
104 return anchor == o.anchor;
105 }
106
107 /// inequality operator (needed for range-based for)
operator !=(const iteration_proxy_value & o) const108 bool operator!=(const iteration_proxy_value& o) const
109 {
110 return anchor != o.anchor;
111 }
112
113 /// return key of the iterator
key() const114 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
value() const150 typename IteratorType::reference value() const
151 {
152 return anchor.value();
153 }
154 };
155
156 /// proxy class for the items() function
157 template<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
iteration_proxy(typename IteratorType::reference cont)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)
begin() const177 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)
end() const183 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
192 template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
get(const nlohmann::detail::iteration_proxy_value<IteratorType> & i)193 auto 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
200 template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
get(const nlohmann::detail::iteration_proxy_value<IteratorType> & i)201 auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
202 {
203 return i.value();
204 }
205
206 } // namespace detail
207 NLOHMANN_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
213 namespace 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
221 template<typename IteratorType>
222 class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
223 : public std::integral_constant<std::size_t, 2> {};
224
225 template<std::size_t N, typename IteratorType>
226 class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
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