// // recursive_iterator.h // iterator // // Created by Sam Jaffe on 2/17/17. // #pragma once #include #include #include #include #include #include #include #include #include #include namespace iterator { template class recursive_iterator_base; template class recursive_iterator_base, std::index_sequence> : public std::tuple { public: static constexpr size_t LastIndex = sizeof...(It) - 1; template using iterator_type = std::tuple_element_t>; template using value_type = std::iter_value_t>; public: template operator end_aware_iterator() const { return std::get>(*this); } decltype(auto) dereference() const { auto rval = std::tuple_cat(get()...); // Special Case Handling for circumstances where at least everything up to // the deepest nested container is non-associative. In this case, we don't // want to transmute our single element/association into a tuple, since // there's no benefit from that. if constexpr (std::tuple_size_v == 1) { return std::get<0>(rval); // May be a reference } else { return rval; // Tuple-of-references } } void increment() { increment<>(); } bool at_end() const { return std::get<0>(*this).at_end(); } bool equal_to(recursive_iterator_base const & other) const { return *this == other; } protected: recursive_iterator_base() = default; recursive_iterator_base(iterator_type<0> iter) { assign<0>(iter); } private: template bool increment() { auto & iter = std::get(*this); if (iter.at_end()) { return false; } // Make sure we don't go OOB ++iter; if constexpr (I > 0) { while (iter.at_end() && increment()) { assign(*std::get(*this)); } } return !iter.at_end(); } template decltype(auto) get() const { auto iter = std::get(*this); if constexpr (I + 1 == sizeof...(It)) { if constexpr (Assoc>) { return std::tie(iter->first, iter->second); } else { return std::tie(*iter); } } else if constexpr (Assoc>) { return std::tie(iter->first); } else { return std::make_tuple(); } } template void assign(end_aware_iterator it) { std::get(*this) = it; if constexpr (I < LastIndex) { if (!it.at_end()) { assign(*it); } } } template void assign(T && value) { if constexpr (Range) { assign(end_aware_iterator(std::forward(value))); } else { assign(value.second); } } }; template > struct recursive_iterator_helper { static typename detail::ProjectionExpander::type const & _projs; using Projections = decltype(detail::Projections(_projs)); using iterator_tuple = typename detail::RecursiveExpander::type; static constexpr auto extent = std::tuple_size_v; using indices = decltype(std::make_index_sequence()); using type = recursive_iterator_base; }; /** * @brief An iterator type for nested collections, allowing you to treat it as * a single-layer collection. * * In order to provide a simple interface, if an associative container is used * in the chain, the type returned by operator*() is a tuple. If multiple * associative containers are nested, then the tuple will be of the form * std::tuple. To avoid copies, and allow * editting of underlying values, the tuple contains references. * * @tparam It The iterator type of the top-level collection. * @tparam MaxDepth The bounding type, representing how many layers this * iterator is willing to delve in the parent object. */ template class recursive_iterator : public recursive_iterator_helper::type, public facade> { public: using sentinel_type = sentinel_t; public: recursive_iterator() = default; explicit recursive_iterator(Range auto & range, MaxDepth = {}) : recursive_iterator(end_aware_iterator(range)) {} explicit recursive_iterator(end_aware_iterator iter, MaxDepth = {}) : recursive_iterator::recursive_iterator_base(iter) {} template explicit recursive_iterator(end_aware_iterator other, MaxDepth = {}) : recursive_iterator(end_aware_iterator(other)) {} template explicit recursive_iterator(recursive_iterator other) : recursive_iterator(end_aware_iterator(other)) {} }; template recursive_iterator(Range &, MaxDepth) -> recursive_iterator, MaxDepth>; template recursive_iterator(Range &) -> recursive_iterator, unbounded>; } namespace std { template auto get(::iterator::recursive_iterator const & iter) { using return_type = std::decay_t::template iterator_type; return static_cast(iter); } } namespace iterator::views { template struct recursive_n_fn : std::ranges::range_adaptor_closure> { template auto operator()(Rng && rng) const { auto begin = recursive_iterator(std::forward(rng), bounded{}); return std::ranges::subrange(begin, decltype(begin)()); } }; struct recursive_fn : std::ranges::range_adaptor_closure { template auto operator()(Rng && rng) const { auto begin = recursive_iterator(std::forward(rng)); return std::ranges::subrange(begin, decltype(begin)()); } }; template constexpr recursive_n_fn recursive_n{}; constexpr recursive_fn recursive; } #include