#pragma once #include "arrow_proxy.h" #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 = detail::arrow_proxy; using difference_type = std::ptrdiff_t; using iterator_category = std::forward_iterator_tag; public: flatten_iterator_layer() = default; explicit 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. */ decltype(auto) 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. */ // auto operator->() const { return detail::arrow_proxy(**this); } void operator->() const; bool operator==(flatten_iterator_layer const & other) const { return (static_cast(*this) == other) && (static_cast(*this) == other); } protected: decltype(auto) get() const { return **this; } /** * @copydoc recursive_iterator_layer::next */ void next() { super::next(); update(); } void update() { layer & self = static_cast(*this); while (super::at_end() && !(++self).at_end()) { super::assign(make_end_aware_iterator(self->second)); } } /** * @copydoc recursive_iterator_layer::assign */ void assign(layer v) { static_cast(*this) = v; if (!v.at_end()) { super::assign(make_end_aware_iterator(v->second)); } } using layer::at_end; }; }}