Horizon
iteration_proxy.hpp
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>
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;
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:
32  IteratorType anchor;
34  std::size_t array_index = 0;
36  mutable std::size_t array_index_last = 0;
38  mutable string_type array_index_str = "0";
40  const string_type empty_str = "";
41 
42  public:
43  explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}
44 
47  {
48  return *this;
49  }
50 
53  {
54  ++anchor;
55  ++array_index;
56 
57  return *this;
58  }
59 
61  bool operator==(const iteration_proxy_value& o) const
62  {
63  return anchor == o.anchor;
64  }
65 
67  bool operator!=(const iteration_proxy_value& o) const
68  {
69  return anchor != o.anchor;
70  }
71 
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 
101  typename IteratorType::reference value() const
102  {
103  return anchor.value();
104  }
105 };
106 
108 template<typename IteratorType> class iteration_proxy
109 {
110  private:
112  typename IteratorType::reference container;
113 
114  public:
116  explicit iteration_proxy(typename IteratorType::reference cont) noexcept
117  : container(cont) {}
118 
121  {
122  return iteration_proxy_value<IteratorType>(container.begin());
123  }
124 
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>
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>
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 <
172 };
173 #if defined(__clang__)
174  #pragma clang diagnostic pop
175 #endif
176 } // namespace std
Definition: iteration_proxy.hpp:21
iteration_proxy_value & operator*()
dereference operator (needed for range-based for)
Definition: iteration_proxy.hpp:46
bool operator!=(const iteration_proxy_value &o) const
inequality operator (needed for range-based for)
Definition: iteration_proxy.hpp:67
IteratorType::reference value() const
return value of the iterator
Definition: iteration_proxy.hpp:101
iteration_proxy_value & operator++()
increment operator (needed for range-based for)
Definition: iteration_proxy.hpp:52
const string_type & key() const
return key of the iterator
Definition: iteration_proxy.hpp:73
bool operator==(const iteration_proxy_value &o) const
equality operator (needed for InputIterator)
Definition: iteration_proxy.hpp:61
proxy class for the items() function
Definition: iteration_proxy.hpp:109
iteration_proxy_value< IteratorType > begin() noexcept
return iterator begin (needed for range-based for)
Definition: iteration_proxy.hpp:120
iteration_proxy_value< IteratorType > end() noexcept
return iterator end (needed for range-based for)
Definition: iteration_proxy.hpp:126
iteration_proxy(typename IteratorType::reference cont) noexcept
construct iteration proxy from a container
Definition: iteration_proxy.hpp:116
@ object
object (unordered set of name/value pairs)
@ array
array (ordered collection of values)
namespace for Niels Lohmann
Definition: adl_serializer.hpp:9