Ver Fonte

Adding forward declarations of end_aware_iterator, joining_iterator, recursive_iterator, and recursive_iterator_n.
Adding doxygen-compatible documentation.

Samuel Jaffe há 9 anos atrás
pai
commit
ff84098870
3 ficheiros alterados com 180 adições e 0 exclusões
  1. 16 0
      end_aware_iterator.hpp
  2. 5 0
      iterator_fwd.hpp
  3. 159 0
      recursive_iterator.hpp

+ 16 - 0
end_aware_iterator.hpp

@@ -12,6 +12,12 @@
 #include <iterator>
 
 namespace iterator {
+  /**
+   * @class end_aware_iterator
+   * @breif An iterator that keeps track of the relative end of the range.
+   *
+   * @param Iterator The underlying iterator type
+   */
   template <typename Iterator>
   class end_aware_iterator {
   public:
@@ -47,6 +53,16 @@ namespace iterator {
     pointer operator->() { return std::addressof(*curr_); }
     
     bool done() const { return curr_ == end_; }
+    /**
+     * When comparing iterators that do not point to the same collection/range, 
+     * the result is not specified by the standard. Therefore, as a matter of
+     * convenience, even if the underlying data is different, all end-aware
+     * iterators in the done() state are considered equal.
+     *
+     * @see done
+     * @return true if both iterators are done, or if the underlying iterators 
+     * are logically equal
+     */
     bool operator==(end_aware_iterator const & other) const {
       return (done() && other.done()) || (curr_ == other.curr_ && end_ == other.end_);
     }

+ 5 - 0
iterator_fwd.hpp

@@ -17,4 +17,9 @@ namespace iterator {
     template <typename IterType>
     using mapped_iterator = decltype(std::begin(std::declval<IterType>()->second));
   }
+  
+  template <typename Iterator> class end_aware_iterator;
+  template <typename MetaIterator> class joining_iterator;
+  template <typename Iterator> class recursive_iterator;
+  template <typename Iterator, std::size_t MaxDepth> class recursive_iterator_n;
 }

+ 159 - 0
recursive_iterator.hpp

@@ -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: