recursive_iterator.hpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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 <iterator>
  10. #include <string>
  11. #include <tuple>
  12. #include <utility>
  13. #include "detail/traits.h"
  14. #include "end_aware_iterator.hpp"
  15. #include "facade.h"
  16. namespace iterator::recursive {
  17. // Helpers for condensing type deductions
  18. template <typename IterType>
  19. using value = decltype(std::begin(*std::declval<IterType>()));
  20. template <typename IterType>
  21. using mapped = decltype(std::begin(std::declval<IterType>()->second));
  22. // Type trait to identify value_type ~~ std::pair<K const, V>, which is
  23. // a safe bet towards 'this is an associative container type'
  24. template <typename T, typename = void>
  25. struct is_associative : std::false_type {};
  26. template <typename T>
  27. struct is_associative<T, std::enable_if_t<std::is_const<
  28. typename T::value_type::first_type>::value>>
  29. : std::true_type {};
  30. // Type deduction guides for constructing recursive iterators.
  31. enum class typeclass { TERMINAL, CONTAINER, ASSOCIATIVE_CONTAINER };
  32. template <typename T, typename = void> struct typeclass_t {
  33. static constexpr typeclass const value{typeclass::TERMINAL};
  34. };
  35. template <typename T> struct is_string_iterator : std::false_type {};
  36. template <>
  37. struct is_string_iterator<std::string::iterator> : std::true_type {};
  38. template <>
  39. struct is_string_iterator<std::string::const_iterator> : std::true_type {};
  40. template <typename T>
  41. struct typeclass_t<T,
  42. std::enable_if_t<!is_string_iterator<value<T>>::value>> {
  43. static constexpr typeclass const value{typeclass::CONTAINER};
  44. };
  45. template <typename T>
  46. struct typeclass_t<T, std::enable_if_t<is_string_iterator<value<T>>::value>> {
  47. static constexpr typeclass const value{typeclass::TERMINAL};
  48. };
  49. template <typename T> struct typeclass_t<T, detail::void_t<mapped<T>>> {
  50. static constexpr typeclass const value{typeclass::ASSOCIATIVE_CONTAINER};
  51. };
  52. }
  53. namespace iterator::recursive {
  54. template <size_t N, size_t I = 1> struct bounded {
  55. template <typename It>
  56. static constexpr typeclass const value =
  57. I == N ? typeclass::TERMINAL : typeclass_t<It>::value;
  58. using next = std::conditional_t<I == N, void, bounded<N, I + 1>>;
  59. static constexpr size_t size = N;
  60. };
  61. struct unbounded {
  62. template <typename It>
  63. static constexpr typeclass const value = typeclass_t<It>::value;
  64. using next = unbounded;
  65. static constexpr size_t size = std::numeric_limits<size_t>::max();
  66. };
  67. template <typename It, typename Bnd = unbounded,
  68. typeclass = Bnd::template value<It>>
  69. struct tuple;
  70. template <typename It, typename Bnd>
  71. struct tuple<It, Bnd, typeclass::TERMINAL> {
  72. using iter = std::tuple<end_aware_iterator<It>>;
  73. decltype(auto) get(It iter) const {
  74. if constexpr (is_associative<It>{}) {
  75. return std::tie(iter->first, iter->second);
  76. } else {
  77. return std::tie(*iter);
  78. }
  79. }
  80. };
  81. template <typename... Ts>
  82. using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));
  83. template <typename It, typename Bnd>
  84. struct tuple<It, Bnd, typeclass::CONTAINER> {
  85. using next = decltype(std::begin(*std::declval<It>()));
  86. using iter = tuple_cat_t<std::tuple<end_aware_iterator<It>>,
  87. typename tuple<next, typename Bnd::next>::iter>;
  88. auto get(It) const { return std::make_tuple(); }
  89. };
  90. template <typename It, typename Bnd>
  91. struct tuple<It, Bnd, typeclass::ASSOCIATIVE_CONTAINER> {
  92. using next = decltype(std::begin(std::declval<It>()->second));
  93. using iter = tuple_cat_t<std::tuple<end_aware_iterator<It>>,
  94. typename tuple<next, typename Bnd::next>::iter>;
  95. auto get(It iter) const { return std::tie(iter->first); };
  96. };
  97. template <typename It, typename Bnd = unbounded>
  98. class rimpl : public facade<rimpl<It, Bnd>> {
  99. private:
  100. typename tuple<It, Bnd>::iter impl_;
  101. public:
  102. static constexpr size_t size =
  103. std::min(std::tuple_size_v<typename tuple<It, Bnd>::iter>, Bnd::size);
  104. rimpl() = default;
  105. rimpl(end_aware_iterator<It> iter) { assign<0>(iter); }
  106. template <typename Ot>
  107. rimpl(end_aware_iterator<Ot> other)
  108. : rimpl(end_aware_iterator<It>(other)) {}
  109. template <typename Ot>
  110. rimpl(rimpl<Ot, Bnd> other) : rimpl(end_aware_iterator<Ot>(other)) {}
  111. template <typename T> operator end_aware_iterator<T>() const {
  112. return std::get<end_aware_iterator<T>>(impl_);
  113. }
  114. decltype(auto) dereference() const {
  115. // Special Case Handling for circumstances where at least everything up to
  116. // the deepest nested container is non-associative. In this case, we don't
  117. // want to transmute our single element/association into a tuple, since
  118. // there's no benefit from that.
  119. if constexpr (std::tuple_size_v<decltype(this->build_tuple())> == 1) {
  120. return *std::get<size - 1>(impl_);
  121. } else {
  122. return build_tuple();
  123. }
  124. }
  125. template <size_t I = size - 1> bool increment() {
  126. auto & iter = std::get<I>(impl_);
  127. if (iter.at_end()) { return false; } // Make sure we don't go OOB
  128. ++iter;
  129. if constexpr (I > 0) {
  130. while (iter.at_end() && increment<I - 1>()) {
  131. assign<I>(*std::get<I - 1>(impl_));
  132. }
  133. }
  134. return !iter.at_end();
  135. }
  136. bool at_end() const { return std::get<0>(impl_).at_end(); }
  137. bool equal_to(rimpl const & other) const { return impl_ == other.impl_; }
  138. // Used by std::get, don't use elsewhere...
  139. auto const & impl() const { return impl_; }
  140. private:
  141. template <size_t I = 0> decltype(auto) build_tuple() const {
  142. // In the case of a bounded recursive iterator, I need to ensure that the
  143. // effectively terminal iterator is treated as such even if there is still
  144. // iteration to be had.
  145. auto it = std::get<I>(impl_);
  146. if constexpr (I == size - 1) {
  147. return tuple<decltype(it), unbounded, typeclass::TERMINAL>{}.get(it);
  148. } else {
  149. // Implemented as a recursive function instead of a parameter-pack
  150. // because OSX has a compiler bug regarding certain forms of parameter
  151. // packs...
  152. return std::tuple_cat(tuple<decltype(it)>{}.get(it),
  153. build_tuple<I + 1>());
  154. }
  155. }
  156. template <size_t I, typename C> void assign(end_aware_iterator<C> it) {
  157. std::get<I>(impl_) = it;
  158. if constexpr (I < size - 1) {
  159. if (!it.at_end()) { assign<I + 1>(*it); }
  160. }
  161. }
  162. template <size_t I, typename C> void assign(C && collection) {
  163. assign<I>(make_end_aware_iterator(std::forward<C>(collection)));
  164. }
  165. template <size_t I, typename K, typename V>
  166. void assign(std::pair<K const, V> const & pair) {
  167. assign<I>(pair.second);
  168. }
  169. template <size_t I, typename K, typename V>
  170. void assign(std::pair<K const, V> & pair) {
  171. assign<I>(pair.second);
  172. }
  173. };
  174. }
  175. MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::recursive::rimpl);
  176. namespace iterator {
  177. /**
  178. * @brief An iterator type for nested collections, allowing you to treat it as
  179. * a single-layer collection.
  180. *
  181. * In order to provide a simple interface, if an associative container is used
  182. * in the chain, the type returned by operator*() is a tuple. If multiple
  183. * associative containers are nested, then the tuple will be of the form
  184. * std::tuple<key1, key2, ..., keyN, value>. To avoid copies, and allow
  185. * editting of underlying values, the tuple contains references.
  186. *
  187. * @tparam It The iterator type of the top-level collection.
  188. */
  189. template <typename It> using recursive_iterator = recursive::rimpl<It>;
  190. /**
  191. * @copydoc recursive_iterator
  192. * This object has bounded recursive depth, so that it can be used to get
  193. * sub-collections, which may be used in other functions.
  194. *
  195. * For Example:
  196. * @code
  197. * using map_type = std::map<std::string, std::map<std::string,
  198. * std::vector<Data> > >;
  199. * ...
  200. * recursive_iterator_n<map_type::iterator, 2> iter{ ... };
  201. * std::vector<Data> & data = std::get<2>(*iter);
  202. * reload_data_from_file( std::get<1>(*iter), data );
  203. * @endcode
  204. *
  205. * @tparam N The maximum depth to recurse into the object
  206. */
  207. template <typename It, std::size_t N>
  208. using recursive_iterator_n = recursive::rimpl<It, recursive::bounded<N>>;
  209. }
  210. namespace std {
  211. template <std::size_t I, typename It>
  212. auto get(::iterator::recursive_iterator<It> const & iter) {
  213. return ::std::get<I>(iter.impl());
  214. }
  215. template <std::size_t I, typename It, std::size_t N>
  216. auto get(::iterator::recursive_iterator_n<It, N> const & iter) {
  217. static_assert(I < N, "Cannot get past bounding level");
  218. return ::std::get<I>(iter.impl());
  219. }
  220. }
  221. template <typename C>
  222. auto make_recursive_iterator(C & collect)
  223. -> iterator::recursive_iterator<decltype(std::begin(collect))> {
  224. return iterator::recursive_iterator<decltype(std::begin(collect))>{
  225. make_end_aware_iterator(collect)};
  226. }
  227. template <typename C>
  228. auto make_recursive_iterator(C const & collect)
  229. -> iterator::recursive_iterator<decltype(std::begin(collect))> {
  230. return iterator::recursive_iterator<decltype(std::begin(collect))>{
  231. make_end_aware_iterator(collect)};
  232. }
  233. template <std::size_t Max, typename C>
  234. auto make_recursive_iterator(C & collect)
  235. -> iterator::recursive_iterator_n<decltype(std::begin(collect)), Max> {
  236. return iterator::recursive_iterator_n<decltype(std::begin(collect)), Max>{
  237. make_end_aware_iterator(collect)};
  238. }
  239. template <std::size_t Max, typename C>
  240. auto make_recursive_iterator(C const & collect)
  241. -> iterator::recursive_iterator_n<decltype(std::begin(collect)), Max> {
  242. return iterator::recursive_iterator_n<decltype(std::begin(collect)), Max>{
  243. make_end_aware_iterator(collect)};
  244. }