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
11namespace nlohmann
12{
13namespace detail
14{
15template<typename string_type>
16void int_to_string( string_type& target, std::size_t value )
17{
18 target = std::to_string(value);
19}
20template <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:
43 explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}
44
45 /// dereference operator (needed for range-based for)
46 iteration_proxy_value& operator*()
47 {
48 return *this;
49 }
50
51 /// increment operator (needed for range-based for)
52 iteration_proxy_value& operator++()
53 {
54 ++anchor;
55 ++array_index;
56
57 return *this;
58 }
59
60 /// equality operator (needed for InputIterator)
61 bool operator==(const iteration_proxy_value& o) const
62 {
63 return anchor == o.anchor;
64 }
65
66 /// inequality operator (needed for range-based for)
67 bool operator!=(const iteration_proxy_value& o) const
68 {
69 return anchor != o.anchor;
70 }
71
72 /// return key of the iterator
73 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
101 typename IteratorType::reference value() const
102 {
103 return anchor.value();
104 }
105};
106
107/// proxy class for the items() function
108template<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
116 explicit iteration_proxy(typename IteratorType::reference cont) noexcept
117 : container(cont) {}
118
119 /// return iterator begin (needed for range-based for)
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)
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
134template <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
135auto 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
142template <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
143auto 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
154namespace 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
161template <typename IteratorType>
162class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
163 : public std::integral_constant<std::size_t, 2> {};
164
165template <std::size_t N, typename IteratorType>
166class 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