• 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 
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