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