|
|
@@ -14,6 +14,10 @@ namespace iterator {
|
|
|
struct terminal_layer_tag_t;
|
|
|
struct continue_layer_tag_t;
|
|
|
|
|
|
+ /**
|
|
|
+ * @class recursive_iterator_base
|
|
|
+ * @breif 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> {
|
|
|
private:
|
|
|
@@ -26,6 +30,19 @@ namespace iterator {
|
|
|
typename super::reference get() { 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> {
|
|
|
private:
|
|
|
@@ -40,12 +57,30 @@ namespace iterator {
|
|
|
public:
|
|
|
using super::super;
|
|
|
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() {
|
|
|
auto & pair = super::operator*();
|
|
|
return std::tie(pair.first, pair.second);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * @class recursive_iterator_layer
|
|
|
+ * @breif 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
|
|
|
+ * @param Iterator The underlying iterator type of the layer
|
|
|
+ * @param 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 >,
|
|
|
@@ -81,6 +116,11 @@ namespace iterator {
|
|
|
protected:
|
|
|
reference get() { 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() {
|
|
|
layer & self = static_cast<layer&>(*this);
|
|
|
next_layer::next();
|
|
|
@@ -89,6 +129,11 @@ namespace iterator {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 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()) {
|
|
|
@@ -99,11 +144,21 @@ namespace iterator {
|
|
|
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
|
|
|
+ * @breif 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 :
|
|
|
recursive_iterator_base< Iterator >,
|
|
|
@@ -130,11 +185,24 @@ namespace iterator {
|
|
|
assign(v);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @breif 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*() {
|
|
|
return std::tuple_cat(std::forward_as_tuple(std::get<0>(layer::get())),
|
|
|
next_reference(next_layer::get()));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Unimplemented because we return an inline constructed type, and tuple
|
|
|
+ * can only be accessed through std::get anyway.
|
|
|
+ */
|
|
|
pointer operator->();
|
|
|
|
|
|
bool operator==(flatten_iterator_layer const & other) const {
|
|
|
@@ -143,6 +211,9 @@ namespace iterator {
|
|
|
protected:
|
|
|
reference get() { return operator*(); }
|
|
|
|
|
|
+ /**
|
|
|
+ * @copydoc recursive_iterator_layer::next
|
|
|
+ */
|
|
|
void next() {
|
|
|
layer & self = static_cast<layer&>(*this);
|
|
|
next_layer::next();
|
|
|
@@ -151,6 +222,9 @@ namespace iterator {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @copydoc recursive_iterator_layer::assign
|
|
|
+ */
|
|
|
void assign(layer v) {
|
|
|
static_cast<layer&>(*this) = v;
|
|
|
if ( !v.done() ) {
|
|
|
@@ -161,6 +235,15 @@ namespace iterator {
|
|
|
bool done() const { return layer::done(); }
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * @class bounded_recursive_iterator_impl
|
|
|
+ * @brief The default (terminal) implementation of a recursive iterator up to Max levels deep.
|
|
|
+ *
|
|
|
+ * @see recursive_iterator_base
|
|
|
+ * @param Iterator The iterator type being processed, such as std::vector<int>::iterator
|
|
|
+ * @param N The current layer of depth, starts at 1.
|
|
|
+ * @param Max The maximum recursive depth to dive down, in case you need to process some sub-collection in a specific manner.
|
|
|
+ */
|
|
|
template <typename Iterator, std::size_t N, std::size_t Max, typename = void>
|
|
|
class bounded_recursive_iterator_impl :
|
|
|
public recursive_iterator_base< Iterator > {
|
|
|
@@ -173,6 +256,13 @@ namespace iterator {
|
|
|
void assign(super eat) { static_cast<super&>(*this) = eat; }
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * @class bounded_recursive_iterator_impl
|
|
|
+ *
|
|
|
+ * An SFINAE specialization of bounded_recursive_iterator_impl for
|
|
|
+ * non-associative container types.
|
|
|
+ * @see recursive_iterator_layer
|
|
|
+ */
|
|
|
template <typename Iterator, std::size_t N, std::size_t Max>
|
|
|
class bounded_recursive_iterator_impl< Iterator, N, Max, typename std::enable_if<N < Max, typename void_t<value_iterator<Iterator>>::type>::type > :
|
|
|
public recursive_iterator_layer< Iterator , bounded_recursive_iterator_impl< value_iterator<Iterator>, N+1, Max > > {
|
|
|
@@ -180,10 +270,23 @@ namespace iterator {
|
|
|
using next_layer = bounded_recursive_iterator_impl< value_iterator<Iterator>, N+1, Max >;
|
|
|
using super = recursive_iterator_layer< Iterator, next_layer >;
|
|
|
public:
|
|
|
+ /**
|
|
|
+ * A special override of operator* that allows collections like
|
|
|
+ * std::vector<std::vector<std::map<K, V>>> still use the value/reference
|
|
|
+ * type of the map. Works only for nested collections with one associative
|
|
|
+ * container at the bottom/Max level.
|
|
|
+ */
|
|
|
auto operator*() -> decltype(*(next_layer&)(*this)) { return next_layer::operator*(); }
|
|
|
using super::super;
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * @class recursive_iterator_impl
|
|
|
+ * @brief The default (terminal) implementation of an unbounded recursive iterator.
|
|
|
+ *
|
|
|
+ * @see recursive_iterator_base
|
|
|
+ * @param Iterator The iterator type being processed, such as std::vector<int>::iterator
|
|
|
+ */
|
|
|
template <typename Iterator, typename = void>
|
|
|
class recursive_iterator_impl : public recursive_iterator_base< Iterator > {
|
|
|
private:
|
|
|
@@ -195,6 +298,13 @@ namespace iterator {
|
|
|
void assign(super eat) { static_cast<super&>(*this) = eat; }
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * @class recursive_iterator_impl
|
|
|
+ *
|
|
|
+ * An SFINAE specialization of bounded_recursive_iterator_impl for
|
|
|
+ * non-associative container types.
|
|
|
+ * @see recursive_iterator_layer
|
|
|
+ */
|
|
|
template <typename Iterator>
|
|
|
class recursive_iterator_impl< Iterator, typename void_t<value_iterator<Iterator>>::type > :
|
|
|
public recursive_iterator_layer< Iterator, recursive_iterator_impl< value_iterator<Iterator> > > {
|
|
|
@@ -202,10 +312,23 @@ namespace iterator {
|
|
|
using next_layer = recursive_iterator_impl< value_iterator<Iterator> >;
|
|
|
using super = recursive_iterator_layer< Iterator, next_layer >;
|
|
|
public:
|
|
|
+ /**
|
|
|
+ * A special override of operator* that allows collections like
|
|
|
+ * std::vector<std::vector<std::map<K, V>>> still use the value/reference
|
|
|
+ * type of the map. Works only for nested collections with one associative
|
|
|
+ * container at the bottom level.
|
|
|
+ */
|
|
|
auto operator*() -> decltype(*(next_layer&)(*this)) { return next_layer::operator*(); }
|
|
|
using super::super;
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * @class bounded_recursive_iterator_impl
|
|
|
+ *
|
|
|
+ * An SFINAE specialization of bounded_recursive_iterator_impl for
|
|
|
+ * associative container types.
|
|
|
+ * @see flatten_iterator_layer
|
|
|
+ */
|
|
|
template <typename Iterator, std::size_t N, std::size_t Max>
|
|
|
class bounded_recursive_iterator_impl< Iterator, N, Max, typename std::enable_if<N < Max, typename void_t<mapped_iterator<Iterator>>::type>::type > :
|
|
|
public flatten_iterator_layer< Iterator , bounded_recursive_iterator_impl< mapped_iterator<Iterator>, N+1, Max > > {
|
|
|
@@ -216,6 +339,13 @@ namespace iterator {
|
|
|
using super::super;
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * @class recursive_iterator_impl
|
|
|
+ *
|
|
|
+ * An SFINAE specialization of bounded_recursive_iterator_impl for
|
|
|
+ * associative container types.
|
|
|
+ * @see flatten_iterator_layer
|
|
|
+ */
|
|
|
template <typename Iterator>
|
|
|
class recursive_iterator_impl< Iterator, typename void_t<mapped_iterator<Iterator>>::type > :
|
|
|
public flatten_iterator_layer< Iterator, recursive_iterator_impl< mapped_iterator<Iterator> > > {
|
|
|
@@ -227,6 +357,18 @@ namespace iterator {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @class recursive_iterator
|
|
|
+ * @breif 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<key1, key2, ..., keyN, value>. To avoid copies, and allow
|
|
|
+ * editting of underlying values, the tuple contains references.
|
|
|
+ *
|
|
|
+ * @param Iterator The iterator type of the top-level collection.
|
|
|
+ */
|
|
|
template <typename Iterator>
|
|
|
class recursive_iterator : public detail::recursive_iterator_impl< Iterator > {
|
|
|
private:
|
|
|
@@ -248,6 +390,23 @@ namespace iterator {
|
|
|
bool operator!=(recursive_iterator const & other) { return !(super::operator==(other)); }
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * @class recursive_iterator_n
|
|
|
+ * @copydoc recursive_iterator
|
|
|
+ * This object has bounded recursive depth, so that it can be used to get
|
|
|
+ * sub-collections, which may be used in other functions.
|
|
|
+ *
|
|
|
+ * For Example:
|
|
|
+ * @code
|
|
|
+ * using map_type = std::map<std::string, std::map<std::string, std::vector<Data> > >;
|
|
|
+ * ...
|
|
|
+ * recursive_iterator_n<map_type::iterator, 2> iter{ ... };
|
|
|
+ * std::vector<Data> & data = std::get<2>(*iter);
|
|
|
+ * reload_data_from_file( std::get<1>(*iter), data );
|
|
|
+ * @endcode
|
|
|
+ *
|
|
|
+ * @param N The maximum depth to recurse into the object
|
|
|
+ */
|
|
|
template <typename Iterator, std::size_t N>
|
|
|
class recursive_iterator_n : public detail::bounded_recursive_iterator_impl< Iterator, 1, N > {
|
|
|
private:
|