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