iteration_proxy.hpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #pragma once
  2. #include <cstddef> // size_t
  3. #include <string> // string, to_string
  4. #include <iterator> // input_iterator_tag
  5. #include <nlohmann/detail/value_t.hpp>
  6. namespace nlohmann
  7. {
  8. namespace detail
  9. {
  10. /// proxy class for the items() function
  11. template<typename IteratorType> class iteration_proxy
  12. {
  13. private:
  14. /// helper class for iteration
  15. class iteration_proxy_internal
  16. {
  17. public:
  18. using difference_type = std::ptrdiff_t;
  19. using value_type = iteration_proxy_internal;
  20. using pointer = iteration_proxy_internal*;
  21. using reference = iteration_proxy_internal&;
  22. using iterator_category = std::input_iterator_tag;
  23. private:
  24. /// the iterator
  25. IteratorType anchor;
  26. /// an index for arrays (used to create key names)
  27. std::size_t array_index = 0;
  28. /// last stringified array index
  29. mutable std::size_t array_index_last = 0;
  30. /// a string representation of the array index
  31. mutable std::string array_index_str = "0";
  32. /// an empty string (to return a reference for primitive values)
  33. const std::string empty_str = "";
  34. public:
  35. explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {}
  36. iteration_proxy_internal(const iteration_proxy_internal&) = default;
  37. iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default;
  38. /// dereference operator (needed for range-based for)
  39. iteration_proxy_internal& operator*()
  40. {
  41. return *this;
  42. }
  43. /// increment operator (needed for range-based for)
  44. iteration_proxy_internal& operator++()
  45. {
  46. ++anchor;
  47. ++array_index;
  48. return *this;
  49. }
  50. /// equality operator (needed for InputIterator)
  51. bool operator==(const iteration_proxy_internal& o) const noexcept
  52. {
  53. return anchor == o.anchor;
  54. }
  55. /// inequality operator (needed for range-based for)
  56. bool operator!=(const iteration_proxy_internal& o) const noexcept
  57. {
  58. return anchor != o.anchor;
  59. }
  60. /// return key of the iterator
  61. const std::string& key() const
  62. {
  63. assert(anchor.m_object != nullptr);
  64. switch (anchor.m_object->type())
  65. {
  66. // use integer array index as key
  67. case value_t::array:
  68. {
  69. if (array_index != array_index_last)
  70. {
  71. array_index_str = std::to_string(array_index);
  72. array_index_last = array_index;
  73. }
  74. return array_index_str;
  75. }
  76. // use key from the object
  77. case value_t::object:
  78. return anchor.key();
  79. // use an empty key for all primitive types
  80. default:
  81. return empty_str;
  82. }
  83. }
  84. /// return value of the iterator
  85. typename IteratorType::reference value() const
  86. {
  87. return anchor.value();
  88. }
  89. };
  90. /// the container to iterate
  91. typename IteratorType::reference container;
  92. public:
  93. /// construct iteration proxy from a container
  94. explicit iteration_proxy(typename IteratorType::reference cont) noexcept
  95. : container(cont) {}
  96. /// return iterator begin (needed for range-based for)
  97. iteration_proxy_internal begin() noexcept
  98. {
  99. return iteration_proxy_internal(container.begin());
  100. }
  101. /// return iterator end (needed for range-based for)
  102. iteration_proxy_internal end() noexcept
  103. {
  104. return iteration_proxy_internal(container.end());
  105. }
  106. };
  107. }
  108. }