|
|
@@ -11,296 +11,10 @@
|
|
|
#include <tuple>
|
|
|
#include <utility>
|
|
|
|
|
|
-#include "end_aware_iterator.hpp"
|
|
|
+#include "detail/recursive_iterator_impl.hpp"
|
|
|
+#include "detail/recursive_iterator_traits.hpp"
|
|
|
#include "iterator_fwd.hpp"
|
|
|
|
|
|
-namespace iterator { namespace detail {
|
|
|
- template <typename> struct void_t { using type = void; };
|
|
|
-
|
|
|
- template <typename IterType>
|
|
|
- using value_iterator = decltype(std::begin(*std::declval<IterType>()));
|
|
|
-
|
|
|
- template <typename IterType>
|
|
|
- using mapped_iterator =
|
|
|
- decltype(std::begin(std::declval<IterType>()->second));
|
|
|
-
|
|
|
- struct terminal_layer_tag_t;
|
|
|
- struct continue_layer_tag_t;
|
|
|
-
|
|
|
- /**
|
|
|
- * @class recursive_iterator_base
|
|
|
- * @brief A thin wrapper around end_aware_iterator for the purposes of
|
|
|
- * template metaprogramming.
|
|
|
- */
|
|
|
- template <typename Iterator, typename = void>
|
|
|
- class recursive_iterator_base : public end_aware_iterator<Iterator> {
|
|
|
- public:
|
|
|
- using super = end_aware_iterator<Iterator>;
|
|
|
-
|
|
|
- protected:
|
|
|
- using recursive_category = terminal_layer_tag_t;
|
|
|
-
|
|
|
- public:
|
|
|
- using super::super;
|
|
|
- recursive_iterator_base(super const & iter) : super(iter) {}
|
|
|
- recursive_iterator_base(super && iter) : super(std::move(iter)) {}
|
|
|
- recursive_iterator_base() = default;
|
|
|
- operator super() const { return *this; }
|
|
|
-
|
|
|
- protected:
|
|
|
- typename super::reference get() const { return super::operator*(); }
|
|
|
- };
|
|
|
-
|
|
|
- /**
|
|
|
- * @class recursive_iterator_base
|
|
|
- * @brief An SFINAE specialization of recursive_iterator_base for associative
|
|
|
- * containers
|
|
|
- *
|
|
|
- * Because it is possible for recursive iterator to step over multiple layers
|
|
|
- * of associative containers, the return type is made into a tuple, so that
|
|
|
- * the caller does not need to write something like
|
|
|
- * `it->second.second.second'. Instead, the return type is a tuple of
|
|
|
- * references, so that the caller can write code like `std::get<3>(*it)'.
|
|
|
- *
|
|
|
- * For example, the ref type for std::map<int, std::map<float, double> >
|
|
|
- * with this would be std::tuple<int const&, float const&, double &>.
|
|
|
- */
|
|
|
- template <typename Iterator>
|
|
|
- class recursive_iterator_base<
|
|
|
- Iterator,
|
|
|
- typename std::enable_if<std::is_const<typename end_aware_iterator<
|
|
|
- Iterator>::value_type::first_type>::value>::type>
|
|
|
- : public end_aware_iterator<Iterator> {
|
|
|
- public:
|
|
|
- using super = end_aware_iterator<Iterator>;
|
|
|
- using first_type = decltype((std::declval<Iterator>()->first));
|
|
|
- using second_type = decltype((std::declval<Iterator>()->second));
|
|
|
-
|
|
|
- protected:
|
|
|
- using recursive_category = continue_layer_tag_t;
|
|
|
-
|
|
|
- public:
|
|
|
- using value_type = std::tuple<first_type, second_type>;
|
|
|
- using reference = std::tuple<first_type &, second_type &>;
|
|
|
-
|
|
|
- public:
|
|
|
- using super::super;
|
|
|
- recursive_iterator_base(super const & iter) : super(iter) {}
|
|
|
- recursive_iterator_base(super && iter) : super(std::move(iter)) {}
|
|
|
- recursive_iterator_base() = default;
|
|
|
- operator super() const { return *this; }
|
|
|
-
|
|
|
- protected:
|
|
|
- /**
|
|
|
- * An alternative function to operator*(), which allows single layer
|
|
|
- * recursive iterators (on associative containers) to return the
|
|
|
- * underlying value/reference type, and nested containers to propogate
|
|
|
- * a tuple or a pair as necessary.
|
|
|
- */
|
|
|
- reference get() const {
|
|
|
- auto & pair = super::operator*();
|
|
|
- return std::tie(pair.first, pair.second);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- /**
|
|
|
- * @class recursive_iterator_layer
|
|
|
- * @brief A single layer for recursing down a nested collection. Represents
|
|
|
- * non-associative containers.
|
|
|
- *
|
|
|
- * Provides dispatch/overloading for types and functions of recursive_iterator
|
|
|
- * chains to resolve ambiguous typedefs and operators.
|
|
|
- *
|
|
|
- * @see recursive_iterator_impl
|
|
|
- * @see bounded_recursive_iterator_impl
|
|
|
- * @tparam Iterator The underlying iterator type of the layer
|
|
|
- * @tparam RecursiveIterator_NextLayer The next layer, either a
|
|
|
- * recursive_iterator_impl, or a bounded_recursive_iterator_impl
|
|
|
- */
|
|
|
- template <typename Iterator, typename RecursiveIterator_NextLayer>
|
|
|
- class recursive_iterator_layer : public recursive_iterator_base<Iterator>,
|
|
|
- public RecursiveIterator_NextLayer {
|
|
|
- public:
|
|
|
- using super = RecursiveIterator_NextLayer;
|
|
|
- using layer = recursive_iterator_base<Iterator>;
|
|
|
-
|
|
|
- protected:
|
|
|
- using recursive_category = continue_layer_tag_t;
|
|
|
-
|
|
|
- public:
|
|
|
- using value_type = typename super::value_type;
|
|
|
- using reference = typename super::reference;
|
|
|
- using pointer = typename super::pointer;
|
|
|
- using difference_type = typename super::difference_type;
|
|
|
- using iterator_category = std::forward_iterator_tag;
|
|
|
-
|
|
|
- public:
|
|
|
- recursive_iterator_layer() = default;
|
|
|
- recursive_iterator_layer(layer v) : recursive_iterator_layer() {
|
|
|
- assign(v);
|
|
|
- update();
|
|
|
- }
|
|
|
- template <typename OIter, typename Rec>
|
|
|
- recursive_iterator_layer(recursive_iterator_layer<OIter, Rec> const & other)
|
|
|
- : layer(static_cast<recursive_iterator_base<OIter> const &>(other)),
|
|
|
- super(static_cast<Rec const &>(other)) {}
|
|
|
-
|
|
|
- reference operator*() const { return super::get(); }
|
|
|
-
|
|
|
- pointer operator->() const { return super::operator->(); }
|
|
|
-
|
|
|
- bool operator==(recursive_iterator_layer const & other) const {
|
|
|
- return layer::operator==(other) && super::operator==(other);
|
|
|
- }
|
|
|
-
|
|
|
- protected:
|
|
|
- reference get() const { return operator*(); }
|
|
|
-
|
|
|
- /**
|
|
|
- * Advance the iterator step. If the next layer has reached the end, then
|
|
|
- * we advance this iterator until it reaches either its own end, or a
|
|
|
- * non-empty subcollection to start iterating over.
|
|
|
- */
|
|
|
- void next() {
|
|
|
- super::next();
|
|
|
- update();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Update the underlying iterator and propogate updates down the chain so
|
|
|
- * that if there is data available, the iterator is in a dereferencable
|
|
|
- * state.
|
|
|
- */
|
|
|
- void assign(layer v) {
|
|
|
- static_cast<layer &>(*this) = v;
|
|
|
- if (!v.done()) { super::assign(make_end_aware_iterator(*v)); }
|
|
|
- }
|
|
|
-
|
|
|
- void update() {
|
|
|
- layer & self = static_cast<layer &>(*this);
|
|
|
- while (super::done() && !(++self).done()) {
|
|
|
- super::assign(make_end_aware_iterator(*self));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- bool done() const { return layer::done(); }
|
|
|
- };
|
|
|
-
|
|
|
- /**
|
|
|
- * @class next_layer_type
|
|
|
- * @breif A template metaprogramming type for unifying associative and
|
|
|
- * non-associative containers.
|
|
|
- */
|
|
|
- template <typename V, typename Tag> struct next_layer_type {
|
|
|
- using type = std::tuple<V>;
|
|
|
- };
|
|
|
- template <typename V> struct next_layer_type<V, continue_layer_tag_t> {
|
|
|
- using type = V;
|
|
|
- };
|
|
|
-
|
|
|
- /**
|
|
|
- * @class flatten_iterator_layer
|
|
|
- * @brief A single layer for recursing down a nested collection. Represents
|
|
|
- * associative containers.
|
|
|
- *
|
|
|
- * @copydoc recursive_iterator_layer
|
|
|
- */
|
|
|
- template <typename Iterator, typename RecursiveIterator_NextLayer>
|
|
|
- class flatten_iterator_layer : public recursive_iterator_base<Iterator>,
|
|
|
- public RecursiveIterator_NextLayer {
|
|
|
- public:
|
|
|
- using super = RecursiveIterator_NextLayer;
|
|
|
- using layer = recursive_iterator_base<Iterator>;
|
|
|
- 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<typename super::value_type,
|
|
|
- typename super::recursive_category>::type;
|
|
|
- using next_reference =
|
|
|
- typename next_layer_type<typename super::reference,
|
|
|
- typename super::recursive_category>::type;
|
|
|
-
|
|
|
- public:
|
|
|
- using value_type =
|
|
|
- decltype(std::tuple_cat(std::make_tuple(std::declval<key_type>()),
|
|
|
- std::declval<next_value_type>()));
|
|
|
- using reference = decltype(std::tuple_cat(
|
|
|
- std::tie(std::declval<key_type>()), std::declval<next_reference>()));
|
|
|
- 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 <typename OIter, typename Rec>
|
|
|
- flatten_iterator_layer(flatten_iterator_layer<OIter, Rec> const & other)
|
|
|
- : layer(static_cast<recursive_iterator_base<OIter> const &>(other)),
|
|
|
- super(static_cast<Rec const &>(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<K, std::vector<std::tuple<T1, T2, T3>>> would return a reference
|
|
|
- * of type std::tuple<K const &, std::tuple<T1, T2, T3>&>, 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<layer &>(*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<layer &>(*this) = v;
|
|
|
- if (!v.done()) { super::assign(make_end_aware_iterator(v->second)); }
|
|
|
- }
|
|
|
-
|
|
|
- bool done() const { return layer::done(); }
|
|
|
- };
|
|
|
-}}
|
|
|
-
|
|
|
-#include "recursive_iterator_meta.hpp"
|
|
|
-
|
|
|
namespace iterator {
|
|
|
/**
|
|
|
* @class recursive_iterator
|