#pragma once #include "recursive_iterator_base.hpp" #include "recursive_iterator_traits.hpp" namespace iterator { namespace detail { /** * @class flatten_iterator_layer * @brief A single layer for recursing down a nested collection. Represents * associative containers. * * @copydoc recursive_iterator_layer */ template class flatten_iterator_layer : public recursive_iterator_base, public RecursiveIterator_NextLayer { public: using super = RecursiveIterator_NextLayer; using layer = recursive_iterator_base; using key_type = typename std::tuple_element<0, typename layer::value_type>::type; protected: using recursive_category = continue_layer_tag_t; using next_value_type = typename next_layer_type::type; using next_reference = typename next_layer_type::type; public: using value_type = decltype(std::tuple_cat(std::make_tuple(std::declval()), std::declval())); using reference = decltype(std::tuple_cat( std::tie(std::declval()), std::declval())); using pointer = void; using difference_type = typename super::difference_type; using iterator_category = std::forward_iterator_tag; public: flatten_iterator_layer() = default; flatten_iterator_layer(layer v) : flatten_iterator_layer() { assign(v); update(); } template flatten_iterator_layer(flatten_iterator_layer const & other) : layer(static_cast const &>(other)), super(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. */ reference operator*() const { return std::tuple_cat(std::forward_as_tuple(std::get<0>(layer::get())), next_reference(super::get())); } /** * Unimplemented because we return an inline constructed type, and tuple * can only be accessed through std::get anyway. */ pointer operator->() const; bool operator==(flatten_iterator_layer const & other) const { return layer::operator==(other) && super::operator==(other); } protected: reference get() const { return operator*(); } /** * @copydoc recursive_iterator_layer::next */ void next() { super::next(); update(); } void update() { layer & self = static_cast(*this); while (super::done() && !(++self).done()) { super::assign(make_end_aware_iterator(self->second)); } } /** * @copydoc recursive_iterator_layer::assign */ void assign(layer v) { static_cast(*this) = v; if (!v.done()) { super::assign(make_end_aware_iterator(v->second)); } } bool done() const { return layer::done(); } }; }}