Branch data Line data Source code
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 : :
15 : : namespace nlohmann
16 : : {
17 : : namespace detail
18 : 0 : {
19 : : // forward declare, to be able to friend it later on
20 : 0 : template<typename IteratorType> class iteration_proxy;
21 : : template<typename IteratorType> class iteration_proxy_value;
22 : 0 :
23 : : /*!
24 : : @brief a template for a bidirectional iterator for the @ref basic_json class
25 : : This 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 : : */
39 : : template<typename BasicJsonType>
40 : : class 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 : 0 : explicit iter_impl(pointer object) noexcept : m_object(object)
87 : : {
88 : 0 : assert(m_object != nullptr);
89 : :
90 : 0 : switch (m_object->m_type)
91 : : {
92 : : case value_t::object:
93 : : {
94 : 0 : m_it.object_iterator = typename object_t::iterator();
95 : 0 : break;
96 : : }
97 : :
98 : : case value_t::array:
99 : : {
100 : 0 : m_it.array_iterator = typename array_t::iterator();
101 : 0 : break;
102 : : }
103 : :
104 : : default:
105 : : {
106 : 0 : m_it.primitive_iterator = primitive_iterator_t();
107 : 0 : break;
108 : : }
109 : : }
110 : 0 : }
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 converting constructor
123 : : @param[in] other non-const iterator to copy from
124 : : @note It is not checked whether @a other is initialized.
125 : : */
126 : 0 : iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
127 : 0 : : m_object(other.m_object), m_it(other.m_it) {}
128 : :
129 : : /*!
130 : : @brief converting assignment
131 : : @param[in,out] other non-const iterator to copy from
132 : : @return const/non-const iterator
133 : : @note It is not checked whether @a other is initialized.
134 : : */
135 : : iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
136 : : {
137 : : m_object = other.m_object;
138 : : m_it = other.m_it;
139 : : return *this;
140 : : }
141 : :
142 : : private:
143 : : /*!
144 : : @brief set the iterator to the first value
145 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
146 : : */
147 : 0 : void set_begin() noexcept
148 : : {
149 : 0 : assert(m_object != nullptr);
150 : :
151 : 0 : switch (m_object->m_type)
152 : : {
153 : : case value_t::object:
154 : : {
155 : 0 : m_it.object_iterator = m_object->m_value.object->begin();
156 : 0 : break;
157 : : }
158 : :
159 : : case value_t::array:
160 : : {
161 : 0 : m_it.array_iterator = m_object->m_value.array->begin();
162 : 0 : break;
163 : : }
164 : :
165 : : case value_t::null:
166 : : {
167 : : // set to end so begin()==end() is true: null is empty
168 : 0 : m_it.primitive_iterator.set_end();
169 : 0 : break;
170 : : }
171 : :
172 : : default:
173 : : {
174 : 0 : m_it.primitive_iterator.set_begin();
175 : 0 : break;
176 : : }
177 : : }
178 : 0 : }
179 : :
180 : : /*!
181 : : @brief set the iterator past the last value
182 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
183 : : */
184 : 0 : void set_end() noexcept
185 : : {
186 : 0 : assert(m_object != nullptr);
187 : :
188 : 0 : switch (m_object->m_type)
189 : : {
190 : : case value_t::object:
191 : : {
192 : 0 : m_it.object_iterator = m_object->m_value.object->end();
193 : 0 : break;
194 : : }
195 : :
196 : : case value_t::array:
197 : : {
198 : 0 : m_it.array_iterator = m_object->m_value.array->end();
199 : 0 : break;
200 : : }
201 : :
202 : : default:
203 : : {
204 : 0 : m_it.primitive_iterator.set_end();
205 : 0 : break;
206 : : }
207 : : }
208 : 0 : }
209 : :
210 : : public:
211 : : /*!
212 : : @brief return a reference to the value pointed to by the iterator
213 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
214 : : */
215 : 0 : reference operator*() const
216 : : {
217 : 0 : assert(m_object != nullptr);
218 : :
219 : 0 : switch (m_object->m_type)
220 : : {
221 : : case value_t::object:
222 : : {
223 : 0 : assert(m_it.object_iterator != m_object->m_value.object->end());
224 : 0 : return m_it.object_iterator->second;
225 : : }
226 : :
227 : : case value_t::array:
228 : : {
229 : 0 : assert(m_it.array_iterator != m_object->m_value.array->end());
230 : 0 : return *m_it.array_iterator;
231 : : }
232 : :
233 : : case value_t::null:
234 : 0 : JSON_THROW(invalid_iterator::create(214, "cannot get value"));
235 : :
236 : : default:
237 : : {
238 : 0 : if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
239 : : {
240 : 0 : return *m_object;
241 : : }
242 : :
243 : 0 : JSON_THROW(invalid_iterator::create(214, "cannot get value"));
244 : : }
245 : : }
246 : 0 : }
247 : :
248 : : /*!
249 : : @brief dereference the iterator
250 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
251 : : */
252 : 0 : pointer operator->() const
253 : : {
254 : 0 : assert(m_object != nullptr);
255 : :
256 : 0 : switch (m_object->m_type)
257 : : {
258 : : case value_t::object:
259 : : {
260 : 0 : assert(m_it.object_iterator != m_object->m_value.object->end());
261 : 0 : return &(m_it.object_iterator->second);
262 : : }
263 : :
264 : : case value_t::array:
265 : : {
266 : 0 : assert(m_it.array_iterator != m_object->m_value.array->end());
267 : 0 : return &*m_it.array_iterator;
268 : : }
269 : :
270 : : default:
271 : : {
272 : 0 : if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
273 : : {
274 : 0 : return m_object;
275 : : }
276 : :
277 : 0 : JSON_THROW(invalid_iterator::create(214, "cannot get value"));
278 : : }
279 : : }
280 : 0 : }
281 : :
282 : : /*!
283 : : @brief post-increment (it++)
284 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
285 : : */
286 : : iter_impl const operator++(int)
287 : : {
288 : : auto result = *this;
289 : : ++(*this);
290 : : return result;
291 : : }
292 : :
293 : : /*!
294 : : @brief pre-increment (++it)
295 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
296 : : */
297 : 0 : iter_impl& operator++()
298 : : {
299 : 0 : assert(m_object != nullptr);
300 : :
301 : 0 : switch (m_object->m_type)
302 : : {
303 : : case value_t::object:
304 : : {
305 : 0 : std::advance(m_it.object_iterator, 1);
306 : 0 : break;
307 : : }
308 : :
309 : : case value_t::array:
310 : : {
311 : 0 : std::advance(m_it.array_iterator, 1);
312 : 0 : break;
313 : : }
314 : :
315 : : default:
316 : : {
317 : 0 : ++m_it.primitive_iterator;
318 : 0 : break;
319 : : }
320 : : }
321 : :
322 : 0 : return *this;
323 : : }
324 : :
325 : : /*!
326 : : @brief post-decrement (it--)
327 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
328 : : */
329 : : iter_impl const operator--(int)
330 : : {
331 : : auto result = *this;
332 : : --(*this);
333 : : return result;
334 : : }
335 : :
336 : : /*!
337 : : @brief pre-decrement (--it)
338 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
339 : : */
340 : : iter_impl& operator--()
341 : : {
342 : : assert(m_object != nullptr);
343 : :
344 : : switch (m_object->m_type)
345 : : {
346 : : case value_t::object:
347 : : {
348 : : std::advance(m_it.object_iterator, -1);
349 : : break;
350 : : }
351 : :
352 : : case value_t::array:
353 : : {
354 : : std::advance(m_it.array_iterator, -1);
355 : : break;
356 : : }
357 : :
358 : : default:
359 : : {
360 : : --m_it.primitive_iterator;
361 : : break;
362 : : }
363 : : }
364 : :
365 : : return *this;
366 : : }
367 : :
368 : : /*!
369 : : @brief comparison: equal
370 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
371 : : */
372 : 0 : bool operator==(const iter_impl& other) const
373 : : {
374 : : // if objects are not the same, the comparison is undefined
375 : 0 : if (JSON_UNLIKELY(m_object != other.m_object))
376 : : {
377 : 0 : JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
378 : : }
379 : :
380 : 0 : assert(m_object != nullptr);
381 : :
382 : 0 : switch (m_object->m_type)
383 : : {
384 : : case value_t::object:
385 : 0 : return (m_it.object_iterator == other.m_it.object_iterator);
386 : :
387 : : case value_t::array:
388 : 0 : return (m_it.array_iterator == other.m_it.array_iterator);
389 : :
390 : : default:
391 : 0 : return (m_it.primitive_iterator == other.m_it.primitive_iterator);
392 : : }
393 : 0 : }
394 : :
395 : : /*!
396 : : @brief comparison: not equal
397 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
398 : : */
399 : 0 : bool operator!=(const iter_impl& other) const
400 : : {
401 : 0 : return not operator==(other);
402 : : }
403 : :
404 : : /*!
405 : : @brief comparison: smaller
406 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
407 : : */
408 : : bool operator<(const iter_impl& other) const
409 : : {
410 : : // if objects are not the same, the comparison is undefined
411 : : if (JSON_UNLIKELY(m_object != other.m_object))
412 : : {
413 : : JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
414 : : }
415 : :
416 : : assert(m_object != nullptr);
417 : :
418 : : switch (m_object->m_type)
419 : : {
420 : : case value_t::object:
421 : : JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
422 : :
423 : : case value_t::array:
424 : : return (m_it.array_iterator < other.m_it.array_iterator);
425 : :
426 : : default:
427 : : return (m_it.primitive_iterator < other.m_it.primitive_iterator);
428 : : }
429 : : }
430 : :
431 : : /*!
432 : : @brief comparison: less than or equal
433 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
434 : : */
435 : : bool operator<=(const iter_impl& other) const
436 : : {
437 : : return not other.operator < (*this);
438 : : }
439 : :
440 : : /*!
441 : : @brief comparison: greater than
442 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
443 : : */
444 : : bool operator>(const iter_impl& other) const
445 : : {
446 : : return not operator<=(other);
447 : : }
448 : :
449 : : /*!
450 : : @brief comparison: greater than or equal
451 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
452 : : */
453 : : bool operator>=(const iter_impl& other) const
454 : : {
455 : : return not operator<(other);
456 : : }
457 : :
458 : : /*!
459 : : @brief add to iterator
460 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
461 : : */
462 : : iter_impl& operator+=(difference_type i)
463 : : {
464 : : assert(m_object != nullptr);
465 : :
466 : : switch (m_object->m_type)
467 : : {
468 : : case value_t::object:
469 : : JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
470 : :
471 : : case value_t::array:
472 : : {
473 : : std::advance(m_it.array_iterator, i);
474 : : break;
475 : : }
476 : :
477 : : default:
478 : : {
479 : : m_it.primitive_iterator += i;
480 : : break;
481 : : }
482 : : }
483 : :
484 : : return *this;
485 : : }
486 : :
487 : : /*!
488 : : @brief subtract from iterator
489 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
490 : : */
491 : : iter_impl& operator-=(difference_type i)
492 : : {
493 : : return operator+=(-i);
494 : : }
495 : :
496 : : /*!
497 : : @brief add to iterator
498 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
499 : : */
500 : : iter_impl operator+(difference_type i) const
501 : : {
502 : : auto result = *this;
503 : : result += i;
504 : : return result;
505 : : }
506 : :
507 : : /*!
508 : : @brief addition of distance and iterator
509 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
510 : : */
511 : : friend iter_impl operator+(difference_type i, const iter_impl& it)
512 : : {
513 : : auto result = it;
514 : : result += i;
515 : : return result;
516 : : }
517 : :
518 : : /*!
519 : : @brief subtract from iterator
520 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
521 : : */
522 : : iter_impl operator-(difference_type i) const
523 : : {
524 : : auto result = *this;
525 : : result -= i;
526 : : return result;
527 : : }
528 : :
529 : : /*!
530 : : @brief return difference
531 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
532 : : */
533 : : difference_type operator-(const iter_impl& other) const
534 : : {
535 : : assert(m_object != nullptr);
536 : :
537 : : switch (m_object->m_type)
538 : : {
539 : : case value_t::object:
540 : : JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
541 : :
542 : : case value_t::array:
543 : : return m_it.array_iterator - other.m_it.array_iterator;
544 : :
545 : : default:
546 : : return m_it.primitive_iterator - other.m_it.primitive_iterator;
547 : : }
548 : : }
549 : :
550 : : /*!
551 : : @brief access to successor
552 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
553 : : */
554 : : reference operator[](difference_type n) const
555 : : {
556 : : assert(m_object != nullptr);
557 : :
558 : : switch (m_object->m_type)
559 : : {
560 : : case value_t::object:
561 : : JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
562 : :
563 : : case value_t::array:
564 : : return *std::next(m_it.array_iterator, n);
565 : :
566 : : case value_t::null:
567 : : JSON_THROW(invalid_iterator::create(214, "cannot get value"));
568 : :
569 : : default:
570 : : {
571 : : if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n))
572 : : {
573 : : return *m_object;
574 : : }
575 : :
576 : : JSON_THROW(invalid_iterator::create(214, "cannot get value"));
577 : : }
578 : : }
579 : : }
580 : :
581 : : /*!
582 : : @brief return the key of an object iterator
583 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
584 : : */
585 : 0 : const typename object_t::key_type& key() const
586 : : {
587 : 0 : assert(m_object != nullptr);
588 : :
589 : 0 : if (JSON_LIKELY(m_object->is_object()))
590 : : {
591 : 0 : return m_it.object_iterator->first;
592 : : }
593 : :
594 : 0 : JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators"));
595 : 0 : }
596 : :
597 : : /*!
598 : : @brief return the value of an iterator
599 : : @pre The iterator is initialized; i.e. `m_object != nullptr`.
600 : : */
601 : 0 : reference value() const
602 : : {
603 : 0 : return operator*();
604 : : }
605 : :
606 : : private:
607 : : /// associated JSON instance
608 : : pointer m_object = nullptr;
609 : : /// the actual iterator of the associated instance
610 : 0 : internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
611 : : };
612 : : } // namespace detail
613 : : } // namespace nlohmann
|