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 
22 /*!
23 @brief a template for a bidirectional iterator for the @ref basic_json class
24 This class implements a both iterators (iterator and const_iterator) for the
25 @ref basic_json class.
26 @note An iterator is called *initialized* when a pointer to a JSON value has
27       been set (e.g., by a constructor or a copy assignment). If the iterator is
28       default-constructed, it is *uninitialized* and most methods are undefined.
29       **The library uses assertions to detect calls on uninitialized iterators.**
30 @requirement The class satisfies the following concept requirements:
31 -
32 [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
33   The iterator that can be moved can be moved in both directions (i.e.
34   incremented and decremented).
35 @since version 1.0.0, simplified in version 2.0.9, change to bidirectional
36        iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
37 */
38 template<typename BasicJsonType>
39 class iter_impl
40 {
41     /// allow basic_json to access private members
42     friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
43     friend BasicJsonType;
44     friend iteration_proxy<iter_impl>;
45     friend iteration_proxy_value<iter_impl>;
46 
47     using object_t = typename BasicJsonType::object_t;
48     using array_t = typename BasicJsonType::array_t;
49     // make sure BasicJsonType is basic_json or const basic_json
50     static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
51                   "iter_impl only accepts (const) basic_json");
52 
53   public:
54 
55     /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
56     /// The C++ Standard has never required user-defined iterators to derive from std::iterator.
57     /// A user-defined iterator should provide publicly accessible typedefs named
58     /// iterator_category, value_type, difference_type, pointer, and reference.
59     /// Note that value_type is required to be non-const, even for constant iterators.
60     using iterator_category = std::bidirectional_iterator_tag;
61 
62     /// the type of the values when the iterator is dereferenced
63     using value_type = typename BasicJsonType::value_type;
64     /// a type to represent differences between iterators
65     using difference_type = typename BasicJsonType::difference_type;
66     /// defines a pointer to the type iterated over (value_type)
67     using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
68           typename BasicJsonType::const_pointer,
69           typename BasicJsonType::pointer>::type;
70     /// defines a reference to the type iterated over (value_type)
71     using reference =
72         typename std::conditional<std::is_const<BasicJsonType>::value,
73         typename BasicJsonType::const_reference,
74         typename BasicJsonType::reference>::type;
75 
76     /// default constructor
77     iter_impl() = default;
78 
79     /*!
80     @brief constructor for a given JSON instance
81     @param[in] object  pointer to a JSON object for this iterator
82     @pre object != nullptr
83     @post The iterator is initialized; i.e. `m_object != nullptr`.
84     */
iter_impl(pointer object)85     explicit iter_impl(pointer object) noexcept : m_object(object)
86     {
87         JSON_ASSERT(m_object != nullptr);
88 
89         switch (m_object->m_type)
90         {
91             case value_t::object:
92             {
93                 m_it.object_iterator = typename object_t::iterator();
94                 break;
95             }
96 
97             case value_t::array:
98             {
99                 m_it.array_iterator = typename array_t::iterator();
100                 break;
101             }
102 
103             default:
104             {
105                 m_it.primitive_iterator = primitive_iterator_t();
106                 break;
107             }
108         }
109     }
110 
111     /*!
112     @note The conventional copy constructor and copy assignment are implicitly
113           defined. Combined with the following converting constructor and
114           assignment, they support: (1) copy from iterator to iterator, (2)
115           copy from const iterator to const iterator, and (3) conversion from
116           iterator to const iterator. However conversion from const iterator
117           to iterator is not defined.
118     */
119 
120     /*!
121     @brief const copy constructor
122     @param[in] other const iterator to copy from
123     @note This copy constructor had to be defined explicitly to circumvent a bug
124           occurring on msvc v19.0 compiler (VS 2015) debug build. For more
125           information refer to: https://github.com/nlohmann/json/issues/1608
126     */
iter_impl(const iter_impl<const BasicJsonType> & other)127     iter_impl(const iter_impl<const BasicJsonType>& other) noexcept
128         : m_object(other.m_object), m_it(other.m_it)
129     {}
130 
131     /*!
132     @brief converting assignment
133     @param[in] other const iterator to copy from
134     @return const/non-const iterator
135     @note It is not checked whether @a other is initialized.
136     */
operator =(const iter_impl<const BasicJsonType> & other)137     iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept
138     {
139         m_object = other.m_object;
140         m_it = other.m_it;
141         return *this;
142     }
143 
144     /*!
145     @brief converting constructor
146     @param[in] other  non-const iterator to copy from
147     @note It is not checked whether @a other is initialized.
148     */
iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type> & other)149     iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
150         : m_object(other.m_object), m_it(other.m_it)
151     {}
152 
153     /*!
154     @brief converting assignment
155     @param[in] other  non-const iterator to copy from
156     @return const/non-const iterator
157     @note It is not checked whether @a other is initialized.
158     */
operator =(const iter_impl<typename std::remove_const<BasicJsonType>::type> & other)159     iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
160     {
161         m_object = other.m_object;
162         m_it = other.m_it;
163         return *this;
164     }
165 
166   private:
167     /*!
168     @brief set the iterator to the first value
169     @pre The iterator is initialized; i.e. `m_object != nullptr`.
170     */
set_begin()171     void set_begin() noexcept
172     {
173         JSON_ASSERT(m_object != nullptr);
174 
175         switch (m_object->m_type)
176         {
177             case value_t::object:
178             {
179                 m_it.object_iterator = m_object->m_value.object->begin();
180                 break;
181             }
182 
183             case value_t::array:
184             {
185                 m_it.array_iterator = m_object->m_value.array->begin();
186                 break;
187             }
188 
189             case value_t::null:
190             {
191                 // set to end so begin()==end() is true: null is empty
192                 m_it.primitive_iterator.set_end();
193                 break;
194             }
195 
196             default:
197             {
198                 m_it.primitive_iterator.set_begin();
199                 break;
200             }
201         }
202     }
203 
204     /*!
205     @brief set the iterator past the last value
206     @pre The iterator is initialized; i.e. `m_object != nullptr`.
207     */
set_end()208     void set_end() noexcept
209     {
210         JSON_ASSERT(m_object != nullptr);
211 
212         switch (m_object->m_type)
213         {
214             case value_t::object:
215             {
216                 m_it.object_iterator = m_object->m_value.object->end();
217                 break;
218             }
219 
220             case value_t::array:
221             {
222                 m_it.array_iterator = m_object->m_value.array->end();
223                 break;
224             }
225 
226             default:
227             {
228                 m_it.primitive_iterator.set_end();
229                 break;
230             }
231         }
232     }
233 
234   public:
235     /*!
236     @brief return a reference to the value pointed to by the iterator
237     @pre The iterator is initialized; i.e. `m_object != nullptr`.
238     */
operator *() const239     reference operator*() const
240     {
241         JSON_ASSERT(m_object != nullptr);
242 
243         switch (m_object->m_type)
244         {
245             case value_t::object:
246             {
247                 JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
248                 return m_it.object_iterator->second;
249             }
250 
251             case value_t::array:
252             {
253                 JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
254                 return *m_it.array_iterator;
255             }
256 
257             case value_t::null:
258                 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
259 
260             default:
261             {
262                 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
263                 {
264                     return *m_object;
265                 }
266 
267                 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
268             }
269         }
270     }
271 
272     /*!
273     @brief dereference the iterator
274     @pre The iterator is initialized; i.e. `m_object != nullptr`.
275     */
operator ->() const276     pointer operator->() const
277     {
278         JSON_ASSERT(m_object != nullptr);
279 
280         switch (m_object->m_type)
281         {
282             case value_t::object:
283             {
284                 JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
285                 return &(m_it.object_iterator->second);
286             }
287 
288             case value_t::array:
289             {
290                 JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
291                 return &*m_it.array_iterator;
292             }
293 
294             default:
295             {
296                 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
297                 {
298                     return m_object;
299                 }
300 
301                 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
302             }
303         }
304     }
305 
306     /*!
307     @brief post-increment (it++)
308     @pre The iterator is initialized; i.e. `m_object != nullptr`.
309     */
operator ++(int)310     iter_impl const operator++(int)
311     {
312         auto result = *this;
313         ++(*this);
314         return result;
315     }
316 
317     /*!
318     @brief pre-increment (++it)
319     @pre The iterator is initialized; i.e. `m_object != nullptr`.
320     */
operator ++()321     iter_impl& operator++()
322     {
323         JSON_ASSERT(m_object != nullptr);
324 
325         switch (m_object->m_type)
326         {
327             case value_t::object:
328             {
329                 std::advance(m_it.object_iterator, 1);
330                 break;
331             }
332 
333             case value_t::array:
334             {
335                 std::advance(m_it.array_iterator, 1);
336                 break;
337             }
338 
339             default:
340             {
341                 ++m_it.primitive_iterator;
342                 break;
343             }
344         }
345 
346         return *this;
347     }
348 
349     /*!
350     @brief post-decrement (it--)
351     @pre The iterator is initialized; i.e. `m_object != nullptr`.
352     */
operator --(int)353     iter_impl const operator--(int)
354     {
355         auto result = *this;
356         --(*this);
357         return result;
358     }
359 
360     /*!
361     @brief pre-decrement (--it)
362     @pre The iterator is initialized; i.e. `m_object != nullptr`.
363     */
operator --()364     iter_impl& operator--()
365     {
366         JSON_ASSERT(m_object != nullptr);
367 
368         switch (m_object->m_type)
369         {
370             case value_t::object:
371             {
372                 std::advance(m_it.object_iterator, -1);
373                 break;
374             }
375 
376             case value_t::array:
377             {
378                 std::advance(m_it.array_iterator, -1);
379                 break;
380             }
381 
382             default:
383             {
384                 --m_it.primitive_iterator;
385                 break;
386             }
387         }
388 
389         return *this;
390     }
391 
392     /*!
393     @brief  comparison: equal
394     @pre The iterator is initialized; i.e. `m_object != nullptr`.
395     */
operator ==(const iter_impl & other) const396     bool operator==(const iter_impl& other) const
397     {
398         // if objects are not the same, the comparison is undefined
399         if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
400         {
401             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
402         }
403 
404         JSON_ASSERT(m_object != nullptr);
405 
406         switch (m_object->m_type)
407         {
408             case value_t::object:
409                 return (m_it.object_iterator == other.m_it.object_iterator);
410 
411             case value_t::array:
412                 return (m_it.array_iterator == other.m_it.array_iterator);
413 
414             default:
415                 return (m_it.primitive_iterator == other.m_it.primitive_iterator);
416         }
417     }
418 
419     /*!
420     @brief  comparison: not equal
421     @pre The iterator is initialized; i.e. `m_object != nullptr`.
422     */
operator !=(const iter_impl & other) const423     bool operator!=(const iter_impl& other) const
424     {
425         return !operator==(other);
426     }
427 
428     /*!
429     @brief  comparison: smaller
430     @pre The iterator is initialized; i.e. `m_object != nullptr`.
431     */
operator <(const iter_impl & other) const432     bool operator<(const iter_impl& other) const
433     {
434         // if objects are not the same, the comparison is undefined
435         if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
436         {
437             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
438         }
439 
440         JSON_ASSERT(m_object != nullptr);
441 
442         switch (m_object->m_type)
443         {
444             case value_t::object:
445                 JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
446 
447             case value_t::array:
448                 return (m_it.array_iterator < other.m_it.array_iterator);
449 
450             default:
451                 return (m_it.primitive_iterator < other.m_it.primitive_iterator);
452         }
453     }
454 
455     /*!
456     @brief  comparison: less than or equal
457     @pre The iterator is initialized; i.e. `m_object != nullptr`.
458     */
operator <=(const iter_impl & other) const459     bool operator<=(const iter_impl& other) const
460     {
461         return !other.operator < (*this);
462     }
463 
464     /*!
465     @brief  comparison: greater than
466     @pre The iterator is initialized; i.e. `m_object != nullptr`.
467     */
operator >(const iter_impl & other) const468     bool operator>(const iter_impl& other) const
469     {
470         return !operator<=(other);
471     }
472 
473     /*!
474     @brief  comparison: greater than or equal
475     @pre The iterator is initialized; i.e. `m_object != nullptr`.
476     */
operator >=(const iter_impl & other) const477     bool operator>=(const iter_impl& other) const
478     {
479         return !operator<(other);
480     }
481 
482     /*!
483     @brief  add to iterator
484     @pre The iterator is initialized; i.e. `m_object != nullptr`.
485     */
operator +=(difference_type i)486     iter_impl& operator+=(difference_type i)
487     {
488         JSON_ASSERT(m_object != nullptr);
489 
490         switch (m_object->m_type)
491         {
492             case value_t::object:
493                 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
494 
495             case value_t::array:
496             {
497                 std::advance(m_it.array_iterator, i);
498                 break;
499             }
500 
501             default:
502             {
503                 m_it.primitive_iterator += i;
504                 break;
505             }
506         }
507 
508         return *this;
509     }
510 
511     /*!
512     @brief  subtract from iterator
513     @pre The iterator is initialized; i.e. `m_object != nullptr`.
514     */
operator -=(difference_type i)515     iter_impl& operator-=(difference_type i)
516     {
517         return operator+=(-i);
518     }
519 
520     /*!
521     @brief  add to iterator
522     @pre The iterator is initialized; i.e. `m_object != nullptr`.
523     */
operator +(difference_type i) const524     iter_impl operator+(difference_type i) const
525     {
526         auto result = *this;
527         result += i;
528         return result;
529     }
530 
531     /*!
532     @brief  addition of distance and iterator
533     @pre The iterator is initialized; i.e. `m_object != nullptr`.
534     */
operator +(difference_type i,const iter_impl & it)535     friend iter_impl operator+(difference_type i, const iter_impl& it)
536     {
537         auto result = it;
538         result += i;
539         return result;
540     }
541 
542     /*!
543     @brief  subtract from iterator
544     @pre The iterator is initialized; i.e. `m_object != nullptr`.
545     */
operator -(difference_type i) const546     iter_impl operator-(difference_type i) const
547     {
548         auto result = *this;
549         result -= i;
550         return result;
551     }
552 
553     /*!
554     @brief  return difference
555     @pre The iterator is initialized; i.e. `m_object != nullptr`.
556     */
operator -(const iter_impl & other) const557     difference_type operator-(const iter_impl& other) const
558     {
559         JSON_ASSERT(m_object != nullptr);
560 
561         switch (m_object->m_type)
562         {
563             case value_t::object:
564                 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
565 
566             case value_t::array:
567                 return m_it.array_iterator - other.m_it.array_iterator;
568 
569             default:
570                 return m_it.primitive_iterator - other.m_it.primitive_iterator;
571         }
572     }
573 
574     /*!
575     @brief  access to successor
576     @pre The iterator is initialized; i.e. `m_object != nullptr`.
577     */
operator [](difference_type n) const578     reference operator[](difference_type n) const
579     {
580         JSON_ASSERT(m_object != nullptr);
581 
582         switch (m_object->m_type)
583         {
584             case value_t::object:
585                 JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
586 
587             case value_t::array:
588                 return *std::next(m_it.array_iterator, n);
589 
590             case value_t::null:
591                 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
592 
593             default:
594             {
595                 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
596                 {
597                     return *m_object;
598                 }
599 
600                 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
601             }
602         }
603     }
604 
605     /*!
606     @brief  return the key of an object iterator
607     @pre The iterator is initialized; i.e. `m_object != nullptr`.
608     */
key() const609     const typename object_t::key_type& key() const
610     {
611         JSON_ASSERT(m_object != nullptr);
612 
613         if (JSON_HEDLEY_LIKELY(m_object->is_object()))
614         {
615             return m_it.object_iterator->first;
616         }
617 
618         JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators"));
619     }
620 
621     /*!
622     @brief  return the value of an iterator
623     @pre The iterator is initialized; i.e. `m_object != nullptr`.
624     */
value() const625     reference value() const
626     {
627         return operator*();
628     }
629 
630   private:
631     /// associated JSON instance
632     pointer m_object = nullptr;
633     /// the actual iterator of the associated instance
634     internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
635 };
636 } // namespace detail
637 } // namespace nlohmann
638