1 #pragma once
2
3 #include <cstddef> // size_t
4 #include <iterator> // input_iterator_tag
5 #include <string> // string, to_string
6 #include <tuple> // tuple_size, get, tuple_element
7
8 #include <nlohmann/detail/meta/type_traits.hpp>
9 #include <nlohmann/detail/value_t.hpp>
10
11 namespace nlohmann
12 {
13 namespace detail
14 {
15 template<typename string_type>
int_to_string(string_type & target,std::size_t value)16 void int_to_string( string_type& target, std::size_t value )
17 {
18 // For ADL
19 using std::to_string;
20 target = to_string(value);
21 }
22 template<typename IteratorType> class iteration_proxy_value
23 {
24 public:
25 using difference_type = std::ptrdiff_t;
26 using value_type = iteration_proxy_value;
27 using pointer = value_type * ;
28 using reference = value_type & ;
29 using iterator_category = std::input_iterator_tag;
30 using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
31
32 private:
33 /// the iterator
34 IteratorType anchor;
35 /// an index for arrays (used to create key names)
36 std::size_t array_index = 0;
37 /// last stringified array index
38 mutable std::size_t array_index_last = 0;
39 /// a string representation of the array index
40 mutable string_type array_index_str = "0";
41 /// an empty string (to return a reference for primitive values)
42 const string_type empty_str = "";
43
44 public:
iteration_proxy_value(IteratorType it)45 explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}
46
47 /// dereference operator (needed for range-based for)
operator *()48 iteration_proxy_value& operator*()
49 {
50 return *this;
51 }
52
53 /// increment operator (needed for range-based for)
operator ++()54 iteration_proxy_value& operator++()
55 {
56 ++anchor;
57 ++array_index;
58
59 return *this;
60 }
61
62 /// equality operator (needed for InputIterator)
operator ==(const iteration_proxy_value & o) const63 bool operator==(const iteration_proxy_value& o) const
64 {
65 return anchor == o.anchor;
66 }
67
68 /// inequality operator (needed for range-based for)
operator !=(const iteration_proxy_value & o) const69 bool operator!=(const iteration_proxy_value& o) const
70 {
71 return anchor != o.anchor;
72 }
73
74 /// return key of the iterator
key() const75 const string_type& key() const
76 {
77 JSON_ASSERT(anchor.m_object != nullptr);
78
79 switch (anchor.m_object->type())
80 {
81 // use integer array index as key
82 case value_t::array:
83 {
84 if (array_index != array_index_last)
85 {
86 int_to_string( array_index_str, array_index );
87 array_index_last = array_index;
88 }
89 return array_index_str;
90 }
91
92 // use key from the object
93 case value_t::object:
94 return anchor.key();
95
96 // use an empty key for all primitive types
97 default:
98 return empty_str;
99 }
100 }
101
102 /// return value of the iterator
value() const103 typename IteratorType::reference value() const
104 {
105 return anchor.value();
106 }
107 };
108
109 /// proxy class for the items() function
110 template<typename IteratorType> class iteration_proxy
111 {
112 private:
113 /// the container to iterate
114 typename IteratorType::reference container;
115
116 public:
117 /// construct iteration proxy from a container
iteration_proxy(typename IteratorType::reference cont)118 explicit iteration_proxy(typename IteratorType::reference cont) noexcept
119 : container(cont) {}
120
121 /// return iterator begin (needed for range-based for)
begin()122 iteration_proxy_value<IteratorType> begin() noexcept
123 {
124 return iteration_proxy_value<IteratorType>(container.begin());
125 }
126
127 /// return iterator end (needed for range-based for)
end()128 iteration_proxy_value<IteratorType> end() noexcept
129 {
130 return iteration_proxy_value<IteratorType>(container.end());
131 }
132 };
133 // Structured Bindings Support
134 // For further reference see https://blog.tartanllama.xyz/structured-bindings/
135 // And see https://github.com/nlohmann/json/pull/1391
136 template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
get(const nlohmann::detail::iteration_proxy_value<IteratorType> & i)137 auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
138 {
139 return i.key();
140 }
141 // Structured Bindings Support
142 // For further reference see https://blog.tartanllama.xyz/structured-bindings/
143 // And see https://github.com/nlohmann/json/pull/1391
144 template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
get(const nlohmann::detail::iteration_proxy_value<IteratorType> & i)145 auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
146 {
147 return i.value();
148 }
149 } // namespace detail
150 } // namespace nlohmann
151
152 // The Addition to the STD Namespace is required to add
153 // Structured Bindings Support to the iteration_proxy_value class
154 // For further reference see https://blog.tartanllama.xyz/structured-bindings/
155 // And see https://github.com/nlohmann/json/pull/1391
156 namespace std
157 {
158 #if defined(__clang__)
159 // Fix: https://github.com/nlohmann/json/issues/1401
160 #pragma clang diagnostic push
161 #pragma clang diagnostic ignored "-Wmismatched-tags"
162 #endif
163 template<typename IteratorType>
164 class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
165 : public std::integral_constant<std::size_t, 2> {};
166
167 template<std::size_t N, typename IteratorType>
168 class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
169 {
170 public:
171 using type = decltype(
172 get<N>(std::declval <
173 ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
174 };
175 #if defined(__clang__)
176 #pragma clang diagnostic pop
177 #endif
178 } // namespace std
179