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