recursive_iterator.hpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. //
  2. // recursive_iterator.hpp
  3. // iterator
  4. //
  5. // Created by Sam Jaffe on 2/17/17.
  6. //
  7. #pragma once
  8. #include "iterator_fwd.hpp"
  9. #include <string>
  10. #include <tuple>
  11. #include <utility>
  12. #include "detail/recursive_traits.h"
  13. #include "end_aware_iterator.hpp"
  14. #include "facade.h"
  15. namespace iterator::recursive {
  16. template <size_t N, size_t I> struct bounded {
  17. template <typename It>
  18. static constexpr recursion_type const value =
  19. I == N ? recursion_type::END : typeclass_t<It>::value;
  20. using next = std::conditional_t<I == N, void, bounded<N, I + 1>>;
  21. static constexpr size_t size = N;
  22. };
  23. struct unbounded {
  24. template <typename It>
  25. static constexpr recursion_type const value = typeclass_t<It>::value;
  26. using next = unbounded;
  27. static constexpr size_t size = std::numeric_limits<size_t>::max();
  28. };
  29. template <typename It, typename Bnd = unbounded,
  30. recursion_type = Bnd::template value<It>>
  31. struct tuple;
  32. template <typename It, typename Bnd>
  33. struct tuple<It, Bnd, recursion_type::END> {
  34. using iter = std::tuple<end_aware_iterator<It>>;
  35. decltype(auto) get(It iter) const {
  36. if constexpr (is_associative<It>{}) {
  37. return std::tie(iter->first, iter->second);
  38. } else {
  39. return std::tie(*iter);
  40. }
  41. }
  42. };
  43. template <typename... Ts>
  44. using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));
  45. template <typename It, typename Bnd>
  46. struct tuple<It, Bnd, recursion_type::THRU> {
  47. using next = decltype(std::begin(*std::declval<It>()));
  48. using iter = tuple_cat_t<std::tuple<end_aware_iterator<It>>,
  49. typename tuple<next, typename Bnd::next>::iter>;
  50. auto get(It) const { return std::make_tuple(); }
  51. };
  52. template <typename It, typename Bnd>
  53. struct tuple<It, Bnd, recursion_type::ASSOC> {
  54. using next = decltype(std::begin(std::declval<It>()->second));
  55. using iter = tuple_cat_t<std::tuple<end_aware_iterator<It>>,
  56. typename tuple<next, typename Bnd::next>::iter>;
  57. auto get(It iter) const { return std::tie(iter->first); };
  58. };
  59. /**
  60. * @brief An iterator type for nested collections, allowing you to treat it as
  61. * a single-layer collection.
  62. *
  63. * In order to provide a simple interface, if an associative container is used
  64. * in the chain, the type returned by operator*() is a tuple. If multiple
  65. * associative containers are nested, then the tuple will be of the form
  66. * std::tuple<key1, key2, ..., keyN, value>. To avoid copies, and allow
  67. * editting of underlying values, the tuple contains references.
  68. *
  69. * @tparam It The iterator type of the top-level collection.
  70. * @tparam Bnd The bounding type, representing how many layers this iterator
  71. * is willing to delve in the parent object.
  72. */
  73. template <typename It, typename Bnd>
  74. class rimpl : public facade<rimpl<It, Bnd>> {
  75. private:
  76. typename tuple<It, Bnd>::iter impl_;
  77. public:
  78. static constexpr size_t size =
  79. std::min(std::tuple_size_v<typename tuple<It, Bnd>::iter>, Bnd::size);
  80. rimpl() = default;
  81. rimpl(end_aware_iterator<It> iter) { assign<0>(iter); }
  82. template <typename Ot>
  83. rimpl(end_aware_iterator<Ot> other)
  84. : rimpl(end_aware_iterator<It>(other)) {}
  85. template <typename Ot>
  86. rimpl(rimpl<Ot, Bnd> other) : rimpl(end_aware_iterator<Ot>(other)) {}
  87. template <typename T> operator end_aware_iterator<T>() const {
  88. return std::get<end_aware_iterator<T>>(impl_);
  89. }
  90. decltype(auto) dereference() const {
  91. // Special Case Handling for circumstances where at least everything up to
  92. // the deepest nested container is non-associative. In this case, we don't
  93. // want to transmute our single element/association into a tuple, since
  94. // there's no benefit from that.
  95. if constexpr (std::tuple_size_v<decltype(this->build_tuple())> == 1) {
  96. return *std::get<size - 1>(impl_);
  97. } else {
  98. return build_tuple();
  99. }
  100. }
  101. template <size_t I = size - 1> bool increment() {
  102. auto & iter = std::get<I>(impl_);
  103. if (iter.at_end()) { return false; } // Make sure we don't go OOB
  104. ++iter;
  105. if constexpr (I > 0) {
  106. while (iter.at_end() && increment<I - 1>()) {
  107. assign<I>(*std::get<I - 1>(impl_));
  108. }
  109. }
  110. return !iter.at_end();
  111. }
  112. bool at_end() const { return std::get<0>(impl_).at_end(); }
  113. bool equal_to(rimpl const & other) const { return impl_ == other.impl_; }
  114. // Used by std::get, don't use elsewhere...
  115. auto const & impl() const { return impl_; }
  116. private:
  117. template <size_t I = 0> decltype(auto) build_tuple() const {
  118. // In the case of a bounded recursive iterator, I need to ensure that the
  119. // effectively terminal iterator is treated as such even if there is still
  120. // iteration to be had.
  121. auto it = std::get<I>(impl_);
  122. if constexpr (I == size - 1) {
  123. return tuple<decltype(it), unbounded, recursion_type::END>{}.get(it);
  124. } else {
  125. // Implemented as a recursive function instead of a parameter-pack
  126. // because OSX has a compiler bug regarding certain forms of parameter
  127. // packs...
  128. return std::tuple_cat(tuple<decltype(it)>{}.get(it),
  129. build_tuple<I + 1>());
  130. }
  131. }
  132. template <size_t I, typename C> void assign(end_aware_iterator<C> it) {
  133. std::get<I>(impl_) = it;
  134. if constexpr (I < size - 1) {
  135. if (!it.at_end()) { assign<I + 1>(*it); }
  136. }
  137. }
  138. template <size_t I, typename C> void assign(C && collection) {
  139. assign<I>(make_end_aware_iterator(std::forward<C>(collection)));
  140. }
  141. template <size_t I, typename K, typename V>
  142. void assign(std::pair<K const, V> const & pair) {
  143. assign<I>(pair.second);
  144. }
  145. template <size_t I, typename K, typename V>
  146. void assign(std::pair<K const, V> & pair) {
  147. assign<I>(pair.second);
  148. }
  149. };
  150. }
  151. MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::recursive::rimpl);
  152. namespace std {
  153. template <std::size_t I, typename It>
  154. auto get(::iterator::recursive_iterator<It> const & iter) {
  155. return ::std::get<I>(iter.impl());
  156. }
  157. template <std::size_t I, typename It, std::size_t N>
  158. auto get(::iterator::recursive_iterator_n<It, N> const & iter) {
  159. static_assert(I < N, "Cannot get past bounding level");
  160. return ::std::get<I>(iter.impl());
  161. }
  162. }
  163. template <typename C>
  164. auto make_recursive_iterator(C & collect)
  165. -> iterator::recursive_iterator<decltype(std::begin(collect))> {
  166. return iterator::recursive_iterator<decltype(std::begin(collect))>{
  167. make_end_aware_iterator(collect)};
  168. }
  169. template <typename C>
  170. auto make_recursive_iterator(C const & collect)
  171. -> iterator::recursive_iterator<decltype(std::begin(collect))> {
  172. return iterator::recursive_iterator<decltype(std::begin(collect))>{
  173. make_end_aware_iterator(collect)};
  174. }
  175. template <std::size_t Max, typename C>
  176. auto make_recursive_iterator(C & collect)
  177. -> iterator::recursive_iterator_n<decltype(std::begin(collect)), Max> {
  178. return iterator::recursive_iterator_n<decltype(std::begin(collect)), Max>{
  179. make_end_aware_iterator(collect)};
  180. }
  181. template <std::size_t Max, typename C>
  182. auto make_recursive_iterator(C const & collect)
  183. -> iterator::recursive_iterator_n<decltype(std::begin(collect)), Max> {
  184. return iterator::recursive_iterator_n<decltype(std::begin(collect)), Max>{
  185. make_end_aware_iterator(collect)};
  186. }