Horizon
iter_impl.hpp
1 #pragma once
2 
3 #include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
4 #include <type_traits> // conditional, is_const, remove_const
5 
6 #include <nlohmann/detail/exceptions.hpp>
7 #include <nlohmann/detail/iterators/internal_iterator.hpp>
8 #include <nlohmann/detail/iterators/primitive_iterator.hpp>
9 #include <nlohmann/detail/macro_scope.hpp>
10 #include <nlohmann/detail/meta/cpp_future.hpp>
11 #include <nlohmann/detail/meta/type_traits.hpp>
12 #include <nlohmann/detail/value_t.hpp>
13 
14 namespace nlohmann
15 {
16 namespace detail
17 {
18 // forward declare, to be able to friend it later on
19 template<typename IteratorType> class iteration_proxy;
20 template<typename IteratorType> class iteration_proxy_value;
21 
38 template<typename BasicJsonType>
39 class iter_impl
40 {
42  using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
44  friend other_iter_impl;
45  friend BasicJsonType;
48 
49  using object_t = typename BasicJsonType::object_t;
50  using array_t = typename BasicJsonType::array_t;
51  // make sure BasicJsonType is basic_json or const basic_json
52  static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
53  "iter_impl only accepts (const) basic_json");
54 
55  public:
56 
62  using iterator_category = std::bidirectional_iterator_tag;
63 
65  using value_type = typename BasicJsonType::value_type;
67  using difference_type = typename BasicJsonType::difference_type;
69  using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
70  typename BasicJsonType::const_pointer,
71  typename BasicJsonType::pointer>::type;
73  using reference =
74  typename std::conditional<std::is_const<BasicJsonType>::value,
75  typename BasicJsonType::const_reference,
76  typename BasicJsonType::reference>::type;
77 
78  iter_impl() = default;
79  ~iter_impl() = default;
80  iter_impl(iter_impl&&) noexcept = default;
81  iter_impl& operator=(iter_impl&&) noexcept = default;
82 
89  explicit iter_impl(pointer object) noexcept : m_object(object)
90  {
91  JSON_ASSERT(m_object != nullptr);
92 
93  switch (m_object->m_type)
94  {
95  case value_t::object:
96  {
97  m_it.object_iterator = typename object_t::iterator();
98  break;
99  }
100 
101  case value_t::array:
102  {
103  m_it.array_iterator = typename array_t::iterator();
104  break;
105  }
106 
107  case value_t::null:
108  case value_t::string:
109  case value_t::boolean:
113  case value_t::binary:
114  case value_t::discarded:
115  default:
116  {
118  break;
119  }
120  }
121  }
122 
140  : m_object(other.m_object), m_it(other.m_it)
141  {}
142 
150  {
151  if (&other != this)
152  {
153  m_object = other.m_object;
154  m_it = other.m_it;
155  }
156  return *this;
157  }
158 
164  iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
165  : m_object(other.m_object), m_it(other.m_it)
166  {}
167 
174  iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)
175  {
176  m_object = other.m_object;
177  m_it = other.m_it;
178  return *this;
179  }
180 
181  JSON_PRIVATE_UNLESS_TESTED:
186  void set_begin() noexcept
187  {
188  JSON_ASSERT(m_object != nullptr);
189 
190  switch (m_object->m_type)
191  {
192  case value_t::object:
193  {
194  m_it.object_iterator = m_object->m_value.object->begin();
195  break;
196  }
197 
198  case value_t::array:
199  {
200  m_it.array_iterator = m_object->m_value.array->begin();
201  break;
202  }
203 
204  case value_t::null:
205  {
206  // set to end so begin()==end() is true: null is empty
208  break;
209  }
210 
211  case value_t::string:
212  case value_t::boolean:
216  case value_t::binary:
217  case value_t::discarded:
218  default:
219  {
221  break;
222  }
223  }
224  }
225 
230  void set_end() noexcept
231  {
232  JSON_ASSERT(m_object != nullptr);
233 
234  switch (m_object->m_type)
235  {
236  case value_t::object:
237  {
238  m_it.object_iterator = m_object->m_value.object->end();
239  break;
240  }
241 
242  case value_t::array:
243  {
244  m_it.array_iterator = m_object->m_value.array->end();
245  break;
246  }
247 
248  case value_t::null:
249  case value_t::string:
250  case value_t::boolean:
254  case value_t::binary:
255  case value_t::discarded:
256  default:
257  {
259  break;
260  }
261  }
262  }
263 
264  public:
270  {
271  JSON_ASSERT(m_object != nullptr);
272 
273  switch (m_object->m_type)
274  {
275  case value_t::object:
276  {
277  JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
278  return m_it.object_iterator->second;
279  }
280 
281  case value_t::array:
282  {
283  JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
284  return *m_it.array_iterator;
285  }
286 
287  case value_t::null:
288  JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object));
289 
290  case value_t::string:
291  case value_t::boolean:
295  case value_t::binary:
296  case value_t::discarded:
297  default:
298  {
299  if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
300  {
301  return *m_object;
302  }
303 
304  JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object));
305  }
306  }
307  }
308 
314  {
315  JSON_ASSERT(m_object != nullptr);
316 
317  switch (m_object->m_type)
318  {
319  case value_t::object:
320  {
321  JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
322  return &(m_it.object_iterator->second);
323  }
324 
325  case value_t::array:
326  {
327  JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
328  return &*m_it.array_iterator;
329  }
330 
331  case value_t::null:
332  case value_t::string:
333  case value_t::boolean:
337  case value_t::binary:
338  case value_t::discarded:
339  default:
340  {
341  if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
342  {
343  return m_object;
344  }
345 
346  JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object));
347  }
348  }
349  }
350 
355  iter_impl const operator++(int) // NOLINT(readability-const-return-type)
356  {
357  auto result = *this;
358  ++(*this);
359  return result;
360  }
361 
367  {
368  JSON_ASSERT(m_object != nullptr);
369 
370  switch (m_object->m_type)
371  {
372  case value_t::object:
373  {
374  std::advance(m_it.object_iterator, 1);
375  break;
376  }
377 
378  case value_t::array:
379  {
380  std::advance(m_it.array_iterator, 1);
381  break;
382  }
383 
384  case value_t::null:
385  case value_t::string:
386  case value_t::boolean:
390  case value_t::binary:
391  case value_t::discarded:
392  default:
393  {
395  break;
396  }
397  }
398 
399  return *this;
400  }
401 
406  iter_impl const operator--(int) // NOLINT(readability-const-return-type)
407  {
408  auto result = *this;
409  --(*this);
410  return result;
411  }
412 
418  {
419  JSON_ASSERT(m_object != nullptr);
420 
421  switch (m_object->m_type)
422  {
423  case value_t::object:
424  {
425  std::advance(m_it.object_iterator, -1);
426  break;
427  }
428 
429  case value_t::array:
430  {
431  std::advance(m_it.array_iterator, -1);
432  break;
433  }
434 
435  case value_t::null:
436  case value_t::string:
437  case value_t::boolean:
441  case value_t::binary:
442  case value_t::discarded:
443  default:
444  {
446  break;
447  }
448  }
449 
450  return *this;
451  }
452 
457  template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
458  bool operator==(const IterImpl& other) const
459  {
460  // if objects are not the same, the comparison is undefined
461  if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
462  {
463  JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object));
464  }
465 
466  JSON_ASSERT(m_object != nullptr);
467 
468  switch (m_object->m_type)
469  {
470  case value_t::object:
471  return (m_it.object_iterator == other.m_it.object_iterator);
472 
473  case value_t::array:
474  return (m_it.array_iterator == other.m_it.array_iterator);
475 
476  case value_t::null:
477  case value_t::string:
478  case value_t::boolean:
482  case value_t::binary:
483  case value_t::discarded:
484  default:
485  return (m_it.primitive_iterator == other.m_it.primitive_iterator);
486  }
487  }
488 
493  template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
494  bool operator!=(const IterImpl& other) const
495  {
496  return !operator==(other);
497  }
498 
503  bool operator<(const iter_impl& other) const
504  {
505  // if objects are not the same, the comparison is undefined
506  if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
507  {
508  JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object));
509  }
510 
511  JSON_ASSERT(m_object != nullptr);
512 
513  switch (m_object->m_type)
514  {
515  case value_t::object:
516  JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", *m_object));
517 
518  case value_t::array:
519  return (m_it.array_iterator < other.m_it.array_iterator);
520 
521  case value_t::null:
522  case value_t::string:
523  case value_t::boolean:
527  case value_t::binary:
528  case value_t::discarded:
529  default:
531  }
532  }
533 
538  bool operator<=(const iter_impl& other) const
539  {
540  return !other.operator < (*this);
541  }
542 
547  bool operator>(const iter_impl& other) const
548  {
549  return !operator<=(other);
550  }
551 
556  bool operator>=(const iter_impl& other) const
557  {
558  return !operator<(other);
559  }
560 
566  {
567  JSON_ASSERT(m_object != nullptr);
568 
569  switch (m_object->m_type)
570  {
571  case value_t::object:
572  JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object));
573 
574  case value_t::array:
575  {
576  std::advance(m_it.array_iterator, i);
577  break;
578  }
579 
580  case value_t::null:
581  case value_t::string:
582  case value_t::boolean:
586  case value_t::binary:
587  case value_t::discarded:
588  default:
589  {
591  break;
592  }
593  }
594 
595  return *this;
596  }
597 
603  {
604  return operator+=(-i);
605  }
606 
612  {
613  auto result = *this;
614  result += i;
615  return result;
616  }
617 
623  {
624  auto result = it;
625  result += i;
626  return result;
627  }
628 
634  {
635  auto result = *this;
636  result -= i;
637  return result;
638  }
639 
644  difference_type operator-(const iter_impl& other) const
645  {
646  JSON_ASSERT(m_object != nullptr);
647 
648  switch (m_object->m_type)
649  {
650  case value_t::object:
651  JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object));
652 
653  case value_t::array:
654  return m_it.array_iterator - other.m_it.array_iterator;
655 
656  case value_t::null:
657  case value_t::string:
658  case value_t::boolean:
662  case value_t::binary:
663  case value_t::discarded:
664  default:
666  }
667  }
668 
674  {
675  JSON_ASSERT(m_object != nullptr);
676 
677  switch (m_object->m_type)
678  {
679  case value_t::object:
680  JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", *m_object));
681 
682  case value_t::array:
683  return *std::next(m_it.array_iterator, n);
684 
685  case value_t::null:
686  JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object));
687 
688  case value_t::string:
689  case value_t::boolean:
693  case value_t::binary:
694  case value_t::discarded:
695  default:
696  {
697  if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
698  {
699  return *m_object;
700  }
701 
702  JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object));
703  }
704  }
705  }
706 
711  const typename object_t::key_type& key() const
712  {
713  JSON_ASSERT(m_object != nullptr);
714 
715  if (JSON_HEDLEY_LIKELY(m_object->is_object()))
716  {
717  return m_it.object_iterator->first;
718  }
719 
720  JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", *m_object));
721  }
722 
727  reference value() const
728  {
729  return operator*();
730  }
731 
732  JSON_PRIVATE_UNLESS_TESTED:
734  pointer m_object = nullptr;
737 };
738 } // namespace detail
739 } // namespace nlohmann
a template for a bidirectional iterator for the basic_json class This class implements a both iterato...
Definition: iter_impl.hpp:40
bool operator<(const iter_impl &other) const
comparison: smaller
Definition: iter_impl.hpp:503
iter_impl operator-(difference_type i) const
subtract from iterator
Definition: iter_impl.hpp:633
const object_t::key_type & key() const
return the key of an object iterator
Definition: iter_impl.hpp:711
bool operator!=(const IterImpl &other) const
comparison: not equal
Definition: iter_impl.hpp:494
iter_impl const operator--(int)
post-decrement (it–)
Definition: iter_impl.hpp:406
void set_end() noexcept
set the iterator past the last value
Definition: iter_impl.hpp:230
typename BasicJsonType::difference_type difference_type
a type to represent differences between iterators
Definition: iter_impl.hpp:67
iter_impl & operator+=(difference_type i)
add to iterator
Definition: iter_impl.hpp:565
difference_type operator-(const iter_impl &other) const
return difference
Definition: iter_impl.hpp:644
typename std::conditional< std::is_const< BasicJsonType >::value, typename BasicJsonType::const_reference, typename BasicJsonType::reference >::type reference
defines a reference to the type iterated over (value_type)
Definition: iter_impl.hpp:76
reference operator*() const
return a reference to the value pointed to by the iterator
Definition: iter_impl.hpp:269
bool operator>=(const iter_impl &other) const
comparison: greater than or equal
Definition: iter_impl.hpp:556
typename std::conditional< std::is_const< BasicJsonType >::value, typename BasicJsonType::const_pointer, typename BasicJsonType::pointer >::type pointer
defines a pointer to the type iterated over (value_type)
Definition: iter_impl.hpp:71
pointer operator->() const
dereference the iterator
Definition: iter_impl.hpp:313
iter_impl & operator=(const iter_impl< typename std::remove_const< BasicJsonType >::type > &other) noexcept
converting assignment
Definition: iter_impl.hpp:174
iter_impl(const iter_impl< const BasicJsonType > &other) noexcept
const copy constructor
Definition: iter_impl.hpp:139
iter_impl const operator++(int)
post-increment (it++)
Definition: iter_impl.hpp:355
iter_impl & operator--()
pre-decrement (–it)
Definition: iter_impl.hpp:417
iter_impl(const iter_impl< typename std::remove_const< BasicJsonType >::type > &other) noexcept
converting constructor
Definition: iter_impl.hpp:164
internal_iterator< typename std::remove_const< BasicJsonType >::type > m_it
the actual iterator of the associated instance
Definition: iter_impl.hpp:736
iter_impl operator+(difference_type i) const
add to iterator
Definition: iter_impl.hpp:611
friend iter_impl operator+(difference_type i, const iter_impl &it)
addition of distance and iterator
Definition: iter_impl.hpp:622
iter_impl & operator=(const iter_impl< const BasicJsonType > &other) noexcept
converting assignment
Definition: iter_impl.hpp:149
bool operator==(const IterImpl &other) const
comparison: equal
Definition: iter_impl.hpp:458
bool operator>(const iter_impl &other) const
comparison: greater than
Definition: iter_impl.hpp:547
typename BasicJsonType::value_type value_type
the type of the values when the iterator is dereferenced
Definition: iter_impl.hpp:65
reference value() const
return the value of an iterator
Definition: iter_impl.hpp:727
iter_impl & operator-=(difference_type i)
subtract from iterator
Definition: iter_impl.hpp:602
iter_impl & operator++()
pre-increment (++it)
Definition: iter_impl.hpp:366
reference operator[](difference_type n) const
access to successor
Definition: iter_impl.hpp:673
bool operator<=(const iter_impl &other) const
comparison: less than or equal
Definition: iter_impl.hpp:538
std::bidirectional_iterator_tag iterator_category
The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
Definition: iter_impl.hpp:62
Definition: iteration_proxy.hpp:24
proxy class for the items() function
Definition: iteration_proxy.hpp:122
Definition: primitive_iterator.hpp:22
constexpr bool is_begin() const noexcept
return whether the iterator can be dereferenced
Definition: primitive_iterator.hpp:51
void set_begin() noexcept
set iterator to a defined beginning
Definition: primitive_iterator.hpp:39
void set_end() noexcept
set iterator to a defined past the end
Definition: primitive_iterator.hpp:45
@ number_integer
number value (signed integer)
@ discarded
discarded by the parser callback function
@ binary
binary array (ordered collection of bytes)
@ object
object (unordered set of name/value pairs)
@ number_float
number value (floating-point)
@ number_unsigned
number value (unsigned integer)
@ array
array (ordered collection of values)
namespace for Niels Lohmann
Definition: adl_serializer.hpp:12
an iterator value
Definition: internal_iterator.hpp:16
primitive_iterator_t primitive_iterator
generic iterator for all other types
Definition: internal_iterator.hpp:22
BasicJsonType::array_t::iterator array_iterator
iterator for JSON arrays
Definition: internal_iterator.hpp:20
BasicJsonType::object_t::iterator object_iterator
iterator for JSON objects
Definition: internal_iterator.hpp:18
Definition: type_traits.hpp:42