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