#pragma once #include "../detail/arrow_proxy.h" #include "base.hpp" #include "traits.hpp" namespace iterator::recursive { /** * @class flatten_iterator_layer * @brief A single layer for recursing down a nested collection. Represents * associative containers. * * @copydoc recursive_iterator_layer */ template class flatten_layer : public base, public Next { protected: using recursive_category = continue_layer_tag_t; public: flatten_layer() = default; explicit flatten_layer(base v) : flatten_layer() { assign(v); update(); } template flatten_layer(flatten_layer const & other) : base(static_cast const &>(other)), Next(static_cast(other)) {} /** * @brief Concatenate the key in this layer, with the dereferenced data from * the next. * * Due to the use of the next_layer_type metaprogramming, a type such as * std::map>> would return a reference * of type std::tuple&>, preserving * sub-aggregates of pair/tuple type. Similarly, forward_as_tuple means * even a key-type of pair/tuple will not be unwrapped. */ decltype(auto) operator*() const { using next_t = typename next_layer_type::type; return std::tuple_cat( std::forward_as_tuple(std::get<0>(base::get())), next_t(Next::get())); } /** * Unimplemented because we return an inline constructed type, and tuple * can only be accessed through std::get anyway. */ // auto operator->() const { return detail::arrow_proxy(**this); } void operator->() const; bool operator==(flatten_layer const & other) const { return (static_cast const &>(*this) == other) && (static_cast(*this) == other); } protected: decltype(auto) get() const { return **this; } /** * @copydoc recursive_iterator_layer::next */ void next() { Next::next(); update(); } void update() { base & self = static_cast &>(*this); while (Next::at_end() && !(++self).at_end()) { Next::assign(make_end_aware_iterator(self->second)); } } /** * @copydoc recursive_iterator_layer::assign */ void assign(base v) { static_cast &>(*this) = v; if (!v.at_end()) { Next::assign(make_end_aware_iterator(v->second)); } } using base::at_end; }; }