// // recursive_iterator.h // iterator // // Created by Sam Jaffe on 2/17/17. // #pragma once #include #include #include #include #include #include #include #include #include namespace iterator { template class RecursiveBase; template class RecursiveBase, detail::Projections, std::index_sequence> : public std::tuple, private detail::Projections { 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 EndAwareIterator() 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(RecursiveBase const & other) const { return *this == other; } protected: RecursiveBase() = default; RecursiveBase(iterator_type<0> iter, Projs... projs) : detail::Projections(projs...) { 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)) { auto && rval = (*this)(*iter, std::integral_constant{}); if constexpr (Assoc>) { // Needed for tuple-cat to preserve references return std::tie(rval.first, rval.second); } else { return std::tie(rval); // Cannot wrap tie(pair) and expect it to work } } else if constexpr (Assoc>) { return std::tie(iter->first); } else { return std::make_tuple(); } } template void assign(EndAwareIterator it) { std::get(*this) = it; if constexpr (I < LastIndex) { if (!it.at_end()) { assign((*this)(*it, std::integral_constant{})); } } } template void assign(T && value) { if constexpr (Range) { assign(EndAwareIterator(std::forward(value))); } else { assign(std::get<1>(value)); } } }; template > struct RecursiveHelper { 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 = RecursiveBase; }; /** * @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 RecursiveIterator : public RecursiveHelper::type, public Facade> { public: using sentinel_type = sentinel_t; public: RecursiveIterator() = default; explicit RecursiveIterator(Range auto & range, MaxDepth = {}) : RecursiveIterator(EndAwareIterator(range)) {} explicit RecursiveIterator(EndAwareIterator iter, MaxDepth = {}) : RecursiveIterator::RecursiveBase(iter) {} template explicit RecursiveIterator(EndAwareIterator other, MaxDepth = {}) : RecursiveIterator(EndAwareIterator(other)) {} template explicit RecursiveIterator(RecursiveIterator other) : RecursiveIterator(EndAwareIterator(other)) {} }; template RecursiveIterator(Range &, MaxDepth) -> RecursiveIterator, MaxDepth>; template RecursiveIterator(Range &) -> RecursiveIterator, unbounded>; } // namespace iterator namespace std { template auto get(::iterator::RecursiveIterator const & iter) { using return_type = std::decay_t::template iterator_type; return static_cast(iter); } } // namespace std namespace iterator::views { template struct recursive_n_fn : std::ranges::range_adaptor_closure> { template auto operator()(Rng && rng) const { auto begin = RecursiveIterator(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 = RecursiveIterator(std::forward(rng)); return std::ranges::subrange(begin, decltype(begin)()); } }; template constexpr recursive_n_fn recursive_n{}; constexpr recursive_fn recursive; } // namespace iterator::views