iter_impl.hpp 17 KB

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