iteration_proxy.hpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #pragma once
  2. #include <cstddef> // size_t
  3. #include <iterator> // input_iterator_tag
  4. #include <string> // string, to_string
  5. #include <tuple> // tuple_size, get, tuple_element
  6. #include <nlohmann/detail/meta/type_traits.hpp>
  7. #include <nlohmann/detail/value_t.hpp>
  8. namespace nlohmann
  9. {
  10. namespace detail
  11. {
  12. template<typename string_type>
  13. void int_to_string( string_type& target, std::size_t value )
  14. {
  15. target = std::to_string(value);
  16. }
  17. template <typename IteratorType> class iteration_proxy_value
  18. {
  19. public:
  20. using difference_type = std::ptrdiff_t;
  21. using value_type = iteration_proxy_value;
  22. using pointer = value_type * ;
  23. using reference = value_type & ;
  24. using iterator_category = std::input_iterator_tag;
  25. using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
  26. private:
  27. /// the iterator
  28. IteratorType anchor;
  29. /// an index for arrays (used to create key names)
  30. std::size_t array_index = 0;
  31. /// last stringified array index
  32. mutable std::size_t array_index_last = 0;
  33. /// a string representation of the array index
  34. mutable string_type array_index_str = "0";
  35. /// an empty string (to return a reference for primitive values)
  36. const string_type empty_str = "";
  37. public:
  38. explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}
  39. /// dereference operator (needed for range-based for)
  40. iteration_proxy_value& operator*()
  41. {
  42. return *this;
  43. }
  44. /// increment operator (needed for range-based for)
  45. iteration_proxy_value& operator++()
  46. {
  47. ++anchor;
  48. ++array_index;
  49. return *this;
  50. }
  51. /// equality operator (needed for InputIterator)
  52. bool operator==(const iteration_proxy_value& o) const
  53. {
  54. return anchor == o.anchor;
  55. }
  56. /// inequality operator (needed for range-based for)
  57. bool operator!=(const iteration_proxy_value& o) const
  58. {
  59. return anchor != o.anchor;
  60. }
  61. /// return key of the iterator
  62. const string_type& key() const
  63. {
  64. assert(anchor.m_object != nullptr);
  65. switch (anchor.m_object->type())
  66. {
  67. // use integer array index as key
  68. case value_t::array:
  69. {
  70. if (array_index != array_index_last)
  71. {
  72. int_to_string( array_index_str, array_index );
  73. array_index_last = array_index;
  74. }
  75. return array_index_str;
  76. }
  77. // use key from the object
  78. case value_t::object:
  79. return anchor.key();
  80. // use an empty key for all primitive types
  81. default:
  82. return empty_str;
  83. }
  84. }
  85. /// return value of the iterator
  86. typename IteratorType::reference value() const
  87. {
  88. return anchor.value();
  89. }
  90. };
  91. /// proxy class for the items() function
  92. template<typename IteratorType> class iteration_proxy
  93. {
  94. private:
  95. /// the container to iterate
  96. typename IteratorType::reference container;
  97. public:
  98. /// construct iteration proxy from a container
  99. explicit iteration_proxy(typename IteratorType::reference cont) noexcept
  100. : container(cont) {}
  101. /// return iterator begin (needed for range-based for)
  102. iteration_proxy_value<IteratorType> begin() noexcept
  103. {
  104. return iteration_proxy_value<IteratorType>(container.begin());
  105. }
  106. /// return iterator end (needed for range-based for)
  107. iteration_proxy_value<IteratorType> end() noexcept
  108. {
  109. return iteration_proxy_value<IteratorType>(container.end());
  110. }
  111. };
  112. // Structured Bindings Support
  113. // For further reference see https://blog.tartanllama.xyz/structured-bindings/
  114. // And see https://github.com/nlohmann/json/pull/1391
  115. template <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
  116. auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
  117. {
  118. return i.key();
  119. }
  120. // Structured Bindings Support
  121. // For further reference see https://blog.tartanllama.xyz/structured-bindings/
  122. // And see https://github.com/nlohmann/json/pull/1391
  123. template <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
  124. auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
  125. {
  126. return i.value();
  127. }
  128. } // namespace detail
  129. } // namespace nlohmann
  130. // The Addition to the STD Namespace is required to add
  131. // Structured Bindings Support to the iteration_proxy_value class
  132. // For further reference see https://blog.tartanllama.xyz/structured-bindings/
  133. // And see https://github.com/nlohmann/json/pull/1391
  134. namespace std
  135. {
  136. #if defined(__clang__)
  137. // Fix: https://github.com/nlohmann/json/issues/1401
  138. #pragma clang diagnostic push
  139. #pragma clang diagnostic ignored "-Wmismatched-tags"
  140. #endif
  141. template <typename IteratorType>
  142. class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
  143. : public std::integral_constant<std::size_t, 2> {};
  144. template <std::size_t N, typename IteratorType>
  145. class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
  146. {
  147. public:
  148. using type = decltype(
  149. get<N>(std::declval <
  150. ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
  151. };
  152. #if defined(__clang__)
  153. #pragma clang diagnostic pop
  154. #endif
  155. } // namespace std