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