• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //     __ _____ _____ _____
2 //  __|  |   __|     |   | |  JSON for Modern C++
3 // |  |  |__   |  |  | | | |  version 3.11.2
4 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8 
9 #pragma once
10 
11 #include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
12 #include <type_traits> // conditional, is_const, remove_const
13 
14 #include <nlohmann/detail/exceptions.hpp>
15 #include <nlohmann/detail/iterators/internal_iterator.hpp>
16 #include <nlohmann/detail/iterators/primitive_iterator.hpp>
17 #include <nlohmann/detail/macro_scope.hpp>
18 #include <nlohmann/detail/meta/cpp_future.hpp>
19 #include <nlohmann/detail/meta/type_traits.hpp>
20 #include <nlohmann/detail/value_t.hpp>
21 
22 NLOHMANN_JSON_NAMESPACE_BEGIN
23 namespace detail
24 {
25 
26 // forward declare, to be able to friend it later on
27 template<typename IteratorType> class iteration_proxy;
28 template<typename IteratorType> class iteration_proxy_value;
29 
30 /*!
31 @brief a template for a bidirectional iterator for the @ref basic_json class
32 This class implements a both iterators (iterator and const_iterator) for the
33 @ref basic_json class.
34 @note An iterator is called *initialized* when a pointer to a JSON value has
35       been set (e.g., by a constructor or a copy assignment). If the iterator is
36       default-constructed, it is *uninitialized* and most methods are undefined.
37       **The library uses assertions to detect calls on uninitialized iterators.**
38 @requirement The class satisfies the following concept requirements:
39 -
40 [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
41   The iterator that can be moved can be moved in both directions (i.e.
42   incremented and decremented).
43 @since version 1.0.0, simplified in version 2.0.9, change to bidirectional
44        iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
45 */
46 template<typename BasicJsonType>
47 class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
48 {
49     /// the iterator with BasicJsonType of different const-ness
50     using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
51     /// allow basic_json to access private members
52     friend other_iter_impl;
53     friend BasicJsonType;
54     friend iteration_proxy<iter_impl>;
55     friend iteration_proxy_value<iter_impl>;
56 
57     using object_t = typename BasicJsonType::object_t;
58     using array_t = typename BasicJsonType::array_t;
59     // make sure BasicJsonType is basic_json or const basic_json
60     static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
61                   "iter_impl only accepts (const) basic_json");
62     // superficial check for the LegacyBidirectionalIterator named requirement
63     static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
64                   &&  std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
65                   "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
66 
67   public:
68     /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
69     /// The C++ Standard has never required user-defined iterators to derive from std::iterator.
70     /// A user-defined iterator should provide publicly accessible typedefs named
71     /// iterator_category, value_type, difference_type, pointer, and reference.
72     /// Note that value_type is required to be non-const, even for constant iterators.
73     using iterator_category = std::bidirectional_iterator_tag;
74 
75     /// the type of the values when the iterator is dereferenced
76     using value_type = typename BasicJsonType::value_type;
77     /// a type to represent differences between iterators
78     using difference_type = typename BasicJsonType::difference_type;
79     /// defines a pointer to the type iterated over (value_type)
80     using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
81           typename BasicJsonType::const_pointer,
82           typename BasicJsonType::pointer>::type;
83     /// defines a reference to the type iterated over (value_type)
84     using reference =
85         typename std::conditional<std::is_const<BasicJsonType>::value,
86         typename BasicJsonType::const_reference,
87         typename BasicJsonType::reference>::type;
88 
89     iter_impl() = default;
90     ~iter_impl() = default;
91     iter_impl(iter_impl&&) noexcept = default;
92     iter_impl& operator=(iter_impl&&) noexcept = default;
93 
94     /*!
95     @brief constructor for a given JSON instance
96     @param[in] object  pointer to a JSON object for this iterator
97     @pre object != nullptr
98     @post The iterator is initialized; i.e. `m_object != nullptr`.
99     */
iter_impl(pointer object)100     explicit iter_impl(pointer object) noexcept : m_object(object)
101     {
102         JSON_ASSERT(m_object != nullptr);
103 
104         switch (m_object->m_type)
105         {
106             case value_t::object:
107             {
108                 m_it.object_iterator = typename object_t::iterator();
109                 break;
110             }
111 
112             case value_t::array:
113             {
114                 m_it.array_iterator = typename array_t::iterator();
115                 break;
116             }
117 
118             case value_t::null:
119             case value_t::string:
120             case value_t::boolean:
121             case value_t::number_integer:
122             case value_t::number_unsigned:
123             case value_t::number_float:
124             case value_t::binary:
125             case value_t::discarded:
126             default:
127             {
128                 m_it.primitive_iterator = primitive_iterator_t();
129                 break;
130             }
131         }
132     }
133 
134     /*!
135     @note The conventional copy constructor and copy assignment are implicitly
136           defined. Combined with the following converting constructor and
137           assignment, they support: (1) copy from iterator to iterator, (2)
138           copy from const iterator to const iterator, and (3) conversion from
139           iterator to const iterator. However conversion from const iterator
140           to iterator is not defined.
141     */
142 
143     /*!
144     @brief const copy constructor
145     @param[in] other const iterator to copy from
146     @note This copy constructor had to be defined explicitly to circumvent a bug
147           occurring on msvc v19.0 compiler (VS 2015) debug build. For more
148           information refer to: https://github.com/nlohmann/json/issues/1608
149     */
iter_impl(const iter_impl<const BasicJsonType> & other)150     iter_impl(const iter_impl<const BasicJsonType>& other) noexcept
151         : m_object(other.m_object), m_it(other.m_it)
152     {}
153 
154     /*!
155     @brief converting assignment
156     @param[in] other const iterator to copy from
157     @return const/non-const iterator
158     @note It is not checked whether @a other is initialized.
159     */
operator =(const iter_impl<const BasicJsonType> & other)160     iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept
161     {
162         if (&other != this)
163         {
164             m_object = other.m_object;
165             m_it = other.m_it;
166         }
167         return *this;
168     }
169 
170     /*!
171     @brief converting constructor
172     @param[in] other  non-const iterator to copy from
173     @note It is not checked whether @a other is initialized.
174     */
iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type> & other)175     iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
176         : m_object(other.m_object), m_it(other.m_it)
177     {}
178 
179     /*!
180     @brief converting assignment
181     @param[in] other  non-const iterator to copy from
182     @return const/non-const iterator
183     @note It is not checked whether @a other is initialized.
184     */
operator =(const iter_impl<typename std::remove_const<BasicJsonType>::type> & other)185     iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)
186     {
187         m_object = other.m_object;
188         m_it = other.m_it;
189         return *this;
190     }
191 
192   JSON_PRIVATE_UNLESS_TESTED:
193     /*!
194     @brief set the iterator to the first value
195     @pre The iterator is initialized; i.e. `m_object != nullptr`.
196     */
197     void set_begin() noexcept
198     {
199         JSON_ASSERT(m_object != nullptr);
200 
201         switch (m_object->m_type)
202         {
203             case value_t::object:
204             {
205                 m_it.object_iterator = m_object->m_value.object->begin();
206                 break;
207             }
208 
209             case value_t::array:
210             {
211                 m_it.array_iterator = m_object->m_value.array->begin();
212                 break;
213             }
214 
215             case value_t::null:
216             {
217                 // set to end so begin()==end() is true: null is empty
218                 m_it.primitive_iterator.set_end();
219                 break;
220             }
221 
222             case value_t::string:
223             case value_t::boolean:
224             case value_t::number_integer:
225             case value_t::number_unsigned:
226             case value_t::number_float:
227             case value_t::binary:
228             case value_t::discarded:
229             default:
230             {
231                 m_it.primitive_iterator.set_begin();
232                 break;
233             }
234         }
235     }
236 
237     /*!
238     @brief set the iterator past the last value
239     @pre The iterator is initialized; i.e. `m_object != nullptr`.
240     */
set_end()241     void set_end() noexcept
242     {
243         JSON_ASSERT(m_object != nullptr);
244 
245         switch (m_object->m_type)
246         {
247             case value_t::object:
248             {
249                 m_it.object_iterator = m_object->m_value.object->end();
250                 break;
251             }
252 
253             case value_t::array:
254             {
255                 m_it.array_iterator = m_object->m_value.array->end();
256                 break;
257             }
258 
259             case value_t::null:
260             case value_t::string:
261             case value_t::boolean:
262             case value_t::number_integer:
263             case value_t::number_unsigned:
264             case value_t::number_float:
265             case value_t::binary:
266             case value_t::discarded:
267             default:
268             {
269                 m_it.primitive_iterator.set_end();
270                 break;
271             }
272         }
273     }
274 
275   public:
276     /*!
277     @brief return a reference to the value pointed to by the iterator
278     @pre The iterator is initialized; i.e. `m_object != nullptr`.
279     */
operator *() const280     reference operator*() const
281     {
282         JSON_ASSERT(m_object != nullptr);
283 
284         switch (m_object->m_type)
285         {
286             case value_t::object:
287             {
288                 JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
289                 return m_it.object_iterator->second;
290             }
291 
292             case value_t::array:
293             {
294                 JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
295                 return *m_it.array_iterator;
296             }
297 
298             case value_t::null:
299                 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
300 
301             case value_t::string:
302             case value_t::boolean:
303             case value_t::number_integer:
304             case value_t::number_unsigned:
305             case value_t::number_float:
306             case value_t::binary:
307             case value_t::discarded:
308             default:
309             {
310                 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
311                 {
312                     return *m_object;
313                 }
314 
315                 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
316             }
317         }
318     }
319 
320     /*!
321     @brief dereference the iterator
322     @pre The iterator is initialized; i.e. `m_object != nullptr`.
323     */
operator ->() const324     pointer operator->() const
325     {
326         JSON_ASSERT(m_object != nullptr);
327 
328         switch (m_object->m_type)
329         {
330             case value_t::object:
331             {
332                 JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
333                 return &(m_it.object_iterator->second);
334             }
335 
336             case value_t::array:
337             {
338                 JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
339                 return &*m_it.array_iterator;
340             }
341 
342             case value_t::null:
343             case value_t::string:
344             case value_t::boolean:
345             case value_t::number_integer:
346             case value_t::number_unsigned:
347             case value_t::number_float:
348             case value_t::binary:
349             case value_t::discarded:
350             default:
351             {
352                 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
353                 {
354                     return m_object;
355                 }
356 
357                 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
358             }
359         }
360     }
361 
362     /*!
363     @brief post-increment (it++)
364     @pre The iterator is initialized; i.e. `m_object != nullptr`.
365     */
operator ++(int)366     iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp)
367     {
368         auto result = *this;
369         ++(*this);
370         return result;
371     }
372 
373     /*!
374     @brief pre-increment (++it)
375     @pre The iterator is initialized; i.e. `m_object != nullptr`.
376     */
operator ++()377     iter_impl& operator++()
378     {
379         JSON_ASSERT(m_object != nullptr);
380 
381         switch (m_object->m_type)
382         {
383             case value_t::object:
384             {
385                 std::advance(m_it.object_iterator, 1);
386                 break;
387             }
388 
389             case value_t::array:
390             {
391                 std::advance(m_it.array_iterator, 1);
392                 break;
393             }
394 
395             case value_t::null:
396             case value_t::string:
397             case value_t::boolean:
398             case value_t::number_integer:
399             case value_t::number_unsigned:
400             case value_t::number_float:
401             case value_t::binary:
402             case value_t::discarded:
403             default:
404             {
405                 ++m_it.primitive_iterator;
406                 break;
407             }
408         }
409 
410         return *this;
411     }
412 
413     /*!
414     @brief post-decrement (it--)
415     @pre The iterator is initialized; i.e. `m_object != nullptr`.
416     */
operator --(int)417     iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp)
418     {
419         auto result = *this;
420         --(*this);
421         return result;
422     }
423 
424     /*!
425     @brief pre-decrement (--it)
426     @pre The iterator is initialized; i.e. `m_object != nullptr`.
427     */
operator --()428     iter_impl& operator--()
429     {
430         JSON_ASSERT(m_object != nullptr);
431 
432         switch (m_object->m_type)
433         {
434             case value_t::object:
435             {
436                 std::advance(m_it.object_iterator, -1);
437                 break;
438             }
439 
440             case value_t::array:
441             {
442                 std::advance(m_it.array_iterator, -1);
443                 break;
444             }
445 
446             case value_t::null:
447             case value_t::string:
448             case value_t::boolean:
449             case value_t::number_integer:
450             case value_t::number_unsigned:
451             case value_t::number_float:
452             case value_t::binary:
453             case value_t::discarded:
454             default:
455             {
456                 --m_it.primitive_iterator;
457                 break;
458             }
459         }
460 
461         return *this;
462     }
463 
464     /*!
465     @brief comparison: equal
466     @pre The iterator is initialized; i.e. `m_object != nullptr`.
467     */
468     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 >
operator ==(const IterImpl & other) const469     bool operator==(const IterImpl& other) const
470     {
471         // if objects are not the same, the comparison is undefined
472         if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
473         {
474             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
475         }
476 
477         JSON_ASSERT(m_object != nullptr);
478 
479         switch (m_object->m_type)
480         {
481             case value_t::object:
482                 return (m_it.object_iterator == other.m_it.object_iterator);
483 
484             case value_t::array:
485                 return (m_it.array_iterator == other.m_it.array_iterator);
486 
487             case value_t::null:
488             case value_t::string:
489             case value_t::boolean:
490             case value_t::number_integer:
491             case value_t::number_unsigned:
492             case value_t::number_float:
493             case value_t::binary:
494             case value_t::discarded:
495             default:
496                 return (m_it.primitive_iterator == other.m_it.primitive_iterator);
497         }
498     }
499 
500     /*!
501     @brief comparison: not equal
502     @pre The iterator is initialized; i.e. `m_object != nullptr`.
503     */
504     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 >
operator !=(const IterImpl & other) const505     bool operator!=(const IterImpl& other) const
506     {
507         return !operator==(other);
508     }
509 
510     /*!
511     @brief comparison: smaller
512     @pre The iterator is initialized; i.e. `m_object != nullptr`.
513     */
operator <(const iter_impl & other) const514     bool operator<(const iter_impl& other) const
515     {
516         // if objects are not the same, the comparison is undefined
517         if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
518         {
519             JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
520         }
521 
522         JSON_ASSERT(m_object != nullptr);
523 
524         switch (m_object->m_type)
525         {
526             case value_t::object:
527                 JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object));
528 
529             case value_t::array:
530                 return (m_it.array_iterator < other.m_it.array_iterator);
531 
532             case value_t::null:
533             case value_t::string:
534             case value_t::boolean:
535             case value_t::number_integer:
536             case value_t::number_unsigned:
537             case value_t::number_float:
538             case value_t::binary:
539             case value_t::discarded:
540             default:
541                 return (m_it.primitive_iterator < other.m_it.primitive_iterator);
542         }
543     }
544 
545     /*!
546     @brief comparison: less than or equal
547     @pre The iterator is initialized; i.e. `m_object != nullptr`.
548     */
operator <=(const iter_impl & other) const549     bool operator<=(const iter_impl& other) const
550     {
551         return !other.operator < (*this);
552     }
553 
554     /*!
555     @brief comparison: greater than
556     @pre The iterator is initialized; i.e. `m_object != nullptr`.
557     */
operator >(const iter_impl & other) const558     bool operator>(const iter_impl& other) const
559     {
560         return !operator<=(other);
561     }
562 
563     /*!
564     @brief comparison: greater than or equal
565     @pre The iterator is initialized; i.e. `m_object != nullptr`.
566     */
operator >=(const iter_impl & other) const567     bool operator>=(const iter_impl& other) const
568     {
569         return !operator<(other);
570     }
571 
572     /*!
573     @brief add to iterator
574     @pre The iterator is initialized; i.e. `m_object != nullptr`.
575     */
operator +=(difference_type i)576     iter_impl& operator+=(difference_type i)
577     {
578         JSON_ASSERT(m_object != nullptr);
579 
580         switch (m_object->m_type)
581         {
582             case value_t::object:
583                 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
584 
585             case value_t::array:
586             {
587                 std::advance(m_it.array_iterator, i);
588                 break;
589             }
590 
591             case value_t::null:
592             case value_t::string:
593             case value_t::boolean:
594             case value_t::number_integer:
595             case value_t::number_unsigned:
596             case value_t::number_float:
597             case value_t::binary:
598             case value_t::discarded:
599             default:
600             {
601                 m_it.primitive_iterator += i;
602                 break;
603             }
604         }
605 
606         return *this;
607     }
608 
609     /*!
610     @brief subtract from iterator
611     @pre The iterator is initialized; i.e. `m_object != nullptr`.
612     */
operator -=(difference_type i)613     iter_impl& operator-=(difference_type i)
614     {
615         return operator+=(-i);
616     }
617 
618     /*!
619     @brief add to iterator
620     @pre The iterator is initialized; i.e. `m_object != nullptr`.
621     */
operator +(difference_type i) const622     iter_impl operator+(difference_type i) const
623     {
624         auto result = *this;
625         result += i;
626         return result;
627     }
628 
629     /*!
630     @brief addition of distance and iterator
631     @pre The iterator is initialized; i.e. `m_object != nullptr`.
632     */
operator +(difference_type i,const iter_impl & it)633     friend iter_impl operator+(difference_type i, const iter_impl& it)
634     {
635         auto result = it;
636         result += i;
637         return result;
638     }
639 
640     /*!
641     @brief subtract from iterator
642     @pre The iterator is initialized; i.e. `m_object != nullptr`.
643     */
operator -(difference_type i) const644     iter_impl operator-(difference_type i) const
645     {
646         auto result = *this;
647         result -= i;
648         return result;
649     }
650 
651     /*!
652     @brief return difference
653     @pre The iterator is initialized; i.e. `m_object != nullptr`.
654     */
operator -(const iter_impl & other) const655     difference_type operator-(const iter_impl& other) const
656     {
657         JSON_ASSERT(m_object != nullptr);
658 
659         switch (m_object->m_type)
660         {
661             case value_t::object:
662                 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
663 
664             case value_t::array:
665                 return m_it.array_iterator - other.m_it.array_iterator;
666 
667             case value_t::null:
668             case value_t::string:
669             case value_t::boolean:
670             case value_t::number_integer:
671             case value_t::number_unsigned:
672             case value_t::number_float:
673             case value_t::binary:
674             case value_t::discarded:
675             default:
676                 return m_it.primitive_iterator - other.m_it.primitive_iterator;
677         }
678     }
679 
680     /*!
681     @brief access to successor
682     @pre The iterator is initialized; i.e. `m_object != nullptr`.
683     */
operator [](difference_type n) const684     reference operator[](difference_type n) const
685     {
686         JSON_ASSERT(m_object != nullptr);
687 
688         switch (m_object->m_type)
689         {
690             case value_t::object:
691                 JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object));
692 
693             case value_t::array:
694                 return *std::next(m_it.array_iterator, n);
695 
696             case value_t::null:
697                 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
698 
699             case value_t::string:
700             case value_t::boolean:
701             case value_t::number_integer:
702             case value_t::number_unsigned:
703             case value_t::number_float:
704             case value_t::binary:
705             case value_t::discarded:
706             default:
707             {
708                 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
709                 {
710                     return *m_object;
711                 }
712 
713                 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
714             }
715         }
716     }
717 
718     /*!
719     @brief return the key of an object iterator
720     @pre The iterator is initialized; i.e. `m_object != nullptr`.
721     */
key() const722     const typename object_t::key_type& key() const
723     {
724         JSON_ASSERT(m_object != nullptr);
725 
726         if (JSON_HEDLEY_LIKELY(m_object->is_object()))
727         {
728             return m_it.object_iterator->first;
729         }
730 
731         JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object));
732     }
733 
734     /*!
735     @brief return the value of an iterator
736     @pre The iterator is initialized; i.e. `m_object != nullptr`.
737     */
value() const738     reference value() const
739     {
740         return operator*();
741     }
742 
743   JSON_PRIVATE_UNLESS_TESTED:
744     /// associated JSON instance
745     pointer m_object = nullptr;
746     /// the actual iterator of the associated instance
747     internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
748 };
749 
750 }  // namespace detail
751 NLOHMANN_JSON_NAMESPACE_END
752