Ver Fonte

Making operator*/-> const-correct.
Moving some recursive_iterator boilerplate into recursive_iterator_meta.hpp.
Adding recursive_iterator_accessors.t.h to test std::get and inplace construction.

Samuel Jaffe há 8 anos atrás
pai
commit
9d80954d44

+ 2 - 2
end_aware_iterator.hpp

@@ -49,8 +49,8 @@ namespace iterator {
       return tmp;
     }
     
-    reference operator*() { return *curr_; }
-    pointer operator->() { return std::addressof(*curr_); }
+    reference operator*() const { return *curr_; }
+    pointer operator->() const { return std::addressof(*curr_); }
     
     bool done() const { return curr_ == end_; }
     /**

+ 6 - 1
iterator.xcodeproj/project.pbxproj

@@ -29,6 +29,8 @@
 		CD21AE2C1E4A3EC100536178 /* join_iterator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = join_iterator.hpp; sourceTree = "<group>"; };
 		CD21AE2E1E4A3F8E00536178 /* end_aware_iterator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = end_aware_iterator.hpp; sourceTree = "<group>"; };
 		CD21AE2F1E4A428D00536178 /* end_aware_iterator.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = end_aware_iterator.t.h; sourceTree = "<group>"; };
+		CD679D721E5D127600F9F843 /* recursive_iterator_meta.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = recursive_iterator_meta.hpp; sourceTree = "<group>"; };
+		CD679D731E5D19B900F9F843 /* recursive_iterator_accessors.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = recursive_iterator_accessors.t.h; sourceTree = "<group>"; };
 		CD7172E91E57C6580048DFFF /* recursive_iterator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = recursive_iterator.hpp; sourceTree = "<group>"; };
 		CD7172EA1E57C91D0048DFFF /* recursive_iterator_one_dimension.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = recursive_iterator_one_dimension.t.h; sourceTree = "<group>"; };
 		CD7172EC1E5897B80048DFFF /* iterator_fwd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = iterator_fwd.hpp; sourceTree = "<group>"; };
@@ -72,6 +74,7 @@
 				CD7172EA1E57C91D0048DFFF /* recursive_iterator_one_dimension.t.h */,
 				CD7172ED1E58BC930048DFFF /* recursive_iterator_nested_map.t.h */,
 				CD7172EE1E58C9930048DFFF /* recursive_iterator_mixed_container.t.h */,
+				CD679D731E5D19B900F9F843 /* recursive_iterator_accessors.t.h */,
 				CD21AE291E4A3EB000536178 /* iterator_tc.cpp */,
 			);
 			name = test;
@@ -84,6 +87,7 @@
 				CD21AE2E1E4A3F8E00536178 /* end_aware_iterator.hpp */,
 				CD21AE2C1E4A3EC100536178 /* join_iterator.hpp */,
 				CD7172E91E57C6580048DFFF /* recursive_iterator.hpp */,
+				CD679D721E5D127600F9F843 /* recursive_iterator_meta.hpp */,
 			);
 			name = src;
 			sourceTree = "<group>";
@@ -152,13 +156,14 @@
 				"$(SRCROOT)/recursive_iterator_one_dimension.t.h",
 				"$(SRCROOT)/recursive_iterator_nested_map.t.h",
 				"$(SRCROOT)/recursive_iterator_mixed_container.t.h",
+				"$(SRCROOT)/recursive_iterator_accessors.t.h",
 			);
 			outputPaths = (
 				"$(SRCROOT)/iterator_tc.cpp",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "cxxtestgen --error-printer -o iterator_tc.cpp end_aware_iterator.t.h join_iterator.t.h recursive_iterator_one_dimension.t.h recursive_iterator_nested_map.t.h recursive_iterator_mixed_container.t.h";
+			shellScript = "cxxtestgen --error-printer -o iterator_tc.cpp end_aware_iterator.t.h join_iterator.t.h recursive_iterator_one_dimension.t.h recursive_iterator_nested_map.t.h recursive_iterator_mixed_container.t.h recursive_iterator_accessors.t.h";
 		};
 /* End PBXShellScriptBuildPhase section */
 

+ 2 - 2
join_iterator.hpp

@@ -54,8 +54,8 @@ namespace iterator {
       return tmp;
     }
     
-    reference operator*() { return iterator_.operator*(); }
-    pointer operator->() { return iterator_.operator->(); }
+    reference operator*() const { return iterator_.operator*(); }
+    pointer operator->() const { return iterator_.operator->(); }
     
     bool operator==(joining_iterator const & other) const {
       return joiner_ == other.joiner_ && iterator_ == other.iterator_;

+ 245 - 370
recursive_iterator.hpp

@@ -10,404 +10,267 @@
 #include "iterator_fwd.hpp"
 #include "end_aware_iterator.hpp"
 
-namespace iterator {
-  namespace detail {
-    struct terminal_layer_tag_t;
-    struct continue_layer_tag_t;
-    
+namespace iterator { namespace detail {
+  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> {
+  public:
+    using super = end_aware_iterator<Iterator>;
+  protected:
+    using recursive_category = terminal_layer_tag_t;
+  public:
+    using super::super;
+    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() = default;
+    operator super() const { return *this; }
+  protected:
     /**
-     * @class recursive_iterator_base
-     * @breif A thin wrapper around end_aware_iterator for the purposes of template metaprogramming.
+     * 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.
      */
-    template <typename Iterator, typename = void>
-    class recursive_iterator_base : public end_aware_iterator<Iterator> {
-    private:
-      using super = end_aware_iterator<Iterator>;
-    protected:
-      using recursive_category = terminal_layer_tag_t;
-    public:
-      using super::super;
-      recursive_iterator_base() = default;
-      operator super() const { return *this; }
-    protected:
-      typename super::reference get() { return super::operator*(); }
-    };
+    reference get() const {
+      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 >,
+  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 = typename super::iterator_category;
+  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)) {}
+    template <typename OIter, typename... Iterators>
+    recursive_iterator_layer(in_place_t, OIter it, Iterators && ...iter)
+    : layer(it), super(in_place, iter...) {
+      update();
+    }
     
-    /**
-     * @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:
-      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() = 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() {
-        auto & pair = super::operator*();
-        return std::tie(pair.first, pair.second);
-      }
-    };
+    reference operator*() const {
+      return super::get();
+    }
     
-    /**
-     * @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 >,
-    public RecursiveIterator_NextLayer {
-    private:
-      using next_layer = RecursiveIterator_NextLayer;
-      using layer = recursive_iterator_base< Iterator >;
-    protected:
-      using recursive_category = continue_layer_tag_t;
-    public:
-      using value_type = typename next_layer::value_type;
-      using reference = typename next_layer::reference;
-      using pointer = typename next_layer::pointer;
-      using difference_type = typename next_layer::difference_type;
-      using iterator_category = typename next_layer::iterator_category;
-    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)), next_layer(static_cast<Rec const&>(other)) {}
-      template <typename OIter, typename... Iterators>
-      recursive_iterator_layer(in_place_t, OIter it, Iterators && ...iter)
-      : layer(it), next_layer(in_place, iter...) {
-        update();
-      }
-
-      reference operator*() {
-        return next_layer::get();
-      }
-      
-      pointer operator->() {
-        return next_layer::operator->();
-      }
-      
-      bool operator==(recursive_iterator_layer const & other) const {
-        return layer::operator==(other) && next_layer::operator==(other);
-      }
-    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() {
-        next_layer::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()) {
-          next_layer::assign(make_end_aware_iterator(*v));
-        }
-      }
-      
-      void update() {
-        layer & self = static_cast<layer&>(*this);
-        while ( next_layer::done() && !(++self).done() ) {
-          next_layer::assign(make_end_aware_iterator(*self));
-        }
-      }
-      
-      bool done() const { return layer::done(); }
-    };
+    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*(); }
     
     /**
-     * @class next_layer_type
-     * @breif A template metaprogramming type for unifying associative and non-associative containers.
+     * 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.
      */
-    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; };
+    void next() {
+      super::next();
+      update();
+    }
     
     /**
-     * @class flatten_iterator_layer
-     * @breif A single layer for recursing down a nested collection. Represents associative containers.
-     *
-     * @copydoc recursive_iterator_layer
+     * Update the underlying iterator and propogate updates down the chain so
+     * that if there is data available, the iterator is in a dereferencable
+     * state.
      */
-    template <typename Iterator, typename RecursiveIterator_NextLayer>
-    class flatten_iterator_layer :
-    recursive_iterator_base< Iterator >,
-    RecursiveIterator_NextLayer {
-    private:
-      using next_layer = 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 next_layer::value_type, typename next_layer::recursive_category>::type;
-      using next_reference = typename next_layer_type<typename next_layer::reference, typename next_layer::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 next_layer::difference_type;
-      using iterator_category = typename next_layer::iterator_category;
-    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)), next_layer(static_cast<Rec const&>(other)) {}
-      template <typename OIter, typename... Iterators>
-      flatten_iterator_layer(in_place_t, OIter it, Iterators && ...iter)
-      : layer(it), next_layer(in_place, iter...) {
-        update();
-      }
-      
-      /**
-       * @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 {
-        return layer::operator==(other) && next_layer::operator==(other);
-      }
-    protected:
-      reference get() { return operator*(); }
-
-      /**
-       * @copydoc recursive_iterator_layer::next
-       */
-      void next() {
-        next_layer::next();
-        update();
-      }
-      
-      void update() {
-        layer & self = static_cast<layer&>(*this);
-        while ( next_layer::done() && !(++self).done() ) {
-          next_layer::assign(make_end_aware_iterator(self->second));
-        }
+    void assign(layer v) {
+      static_cast<layer&>(*this) = v;
+      if (!v.done()) {
+        super::assign(make_end_aware_iterator(*v));
       }
-      
-      /**
-       * @copydoc recursive_iterator_layer::assign
-       */
-      void assign(layer v) {
-        static_cast<layer&>(*this) = v;
-        if ( !v.done() ) {
-          next_layer::assign(make_end_aware_iterator(v->second));
-        }
+    }
+    
+    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(); }
-    };
+    }
+    
+    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 :
+  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 = typename super::iterator_category;
+  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)) {}
+    template <typename OIter, typename... Iterators>
+    flatten_iterator_layer(in_place_t, OIter it, Iterators && ...iter)
+    : layer(it), super(in_place, iter...) {
+      update();
+    }
     
     /**
-     * @class bounded_recursive_iterator_impl
-     * @brief The default (terminal) implementation of a recursive iterator up to Max levels deep.
+     * @breif Concatenate the key in this layer, with the dereferenced data from the next.
      *
-     * @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.
+     * 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.
      */
-    template <typename Iterator, std::size_t N, std::size_t Max, typename = void>
-    class bounded_recursive_iterator_impl :
-    public recursive_iterator_base< Iterator > {
-    private:
-      using super = recursive_iterator_base< Iterator >;
-    public:
-      using super::super;
-      bounded_recursive_iterator_impl() = default;
-      template <typename OIter>
-      bounded_recursive_iterator_impl(in_place_t, OIter iter) : super(iter) {}
-    protected:
-      void next() { super::operator++(); }
-      void assign(super eat) { static_cast<super&>(*this) = eat; }
-    };
+    reference operator*() const {
+      return std::tuple_cat(std::forward_as_tuple(std::get<0>(layer::get())),
+                            next_reference(super::get()));
+    }
     
     /**
-     * @class bounded_recursive_iterator_impl
-     * 
-     * An SFINAE specialization of bounded_recursive_iterator_impl for 
-     * non-associative container types.
-     * @see recursive_iterator_layer
+     * Unimplemented because we return an inline constructed type, and tuple
+     * can only be accessed through std::get anyway.
      */
-    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 > > {
-    private:
-      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;
-      bounded_recursive_iterator_impl() = default;
-      template <typename... Iterators>
-      bounded_recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
-    };
+    pointer operator->() const;
     
-    /**
-     * @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:
-      using super = recursive_iterator_base< Iterator >;
-    public:
-      using super::super;
-      recursive_iterator_impl() = default;
-      template <typename OIter>
-      recursive_iterator_impl(in_place_t, OIter iter) : super(iter) {}
-    protected:
-      void next() { super::operator++(); }
-      void assign(super eat) { static_cast<super&>(*this) = eat; }
-    };
+    bool operator==(flatten_iterator_layer const & other) const {
+      return layer::operator==(other) && super::operator==(other);
+    }
+  protected:
+    reference get() const { return operator*(); }
     
     /**
-     * @class recursive_iterator_impl
-     *
-     * An SFINAE specialization of bounded_recursive_iterator_impl for
-     * non-associative container types.
-     * @see recursive_iterator_layer
+     * @copydoc recursive_iterator_layer::next
      */
-    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> > > {
-    private:
-      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;
-      recursive_iterator_impl() = default;
-      template <typename... Iterators>
-      recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
-    };
+    void next() {
+      super::next();
+      update();
+    }
     
-    /**
-     * @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 > > {
-    private:
-      using next_layer = bounded_recursive_iterator_impl< mapped_iterator<Iterator>, N+1, Max >;
-      using super = flatten_iterator_layer< Iterator, next_layer >;
-    public:
-      using super::super;
-      bounded_recursive_iterator_impl() = default;
-      template <typename... Iterators>
-      bounded_recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
-    };
+    void update() {
+      layer & self = static_cast<layer&>(*this);
+      while ( super::done() && !(++self).done() ) {
+        super::assign(make_end_aware_iterator(self->second));
+      }
+    }
     
     /**
-     * @class recursive_iterator_impl
-     *
-     * An SFINAE specialization of bounded_recursive_iterator_impl for
-     * associative container types.
-     * @see flatten_iterator_layer
+     * @copydoc recursive_iterator_layer::assign
      */
-    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> > > {
-    private:
-      using next_layer = recursive_iterator_impl< mapped_iterator<Iterator> >;
-      using super = flatten_iterator_layer< Iterator, next_layer >;
-    public:
-      using super::super;
-      recursive_iterator_impl() = default;
-      template <typename... Iterators>
-      recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
-    };
-  }
-  
+    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
    * @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
@@ -418,7 +281,7 @@ namespace iterator {
    */
   template <typename Iterator>
   class recursive_iterator : public detail::recursive_iterator_impl< Iterator > {
-  private:
+  public:
     using super = detail::recursive_iterator_impl< Iterator >;
   public:
     using super::super;
@@ -459,7 +322,7 @@ namespace iterator {
    */
   template <typename Iterator, std::size_t N>
   class recursive_iterator_n : public detail::bounded_recursive_iterator_impl< Iterator, 1, N > {
-  private:
+  public:
     using super = detail::bounded_recursive_iterator_impl< Iterator, 1, N >;
   public:
     using super::super;
@@ -482,6 +345,18 @@ namespace iterator {
   };
 }
 
+namespace std {
+  template <std::size_t I, typename It>
+  auto get(::iterator::recursive_iterator<It> const & iter) -> typename ::iterator::detail::accessor<I, ::iterator::recursive_iterator<It>>::type {
+    return iter;
+  }
+}
+
+template <typename Iter0, typename... Iters>
+auto make_recursive_iterator(iterator::end_aware_iterator<Iter0> it, Iters &&... iters) -> iterator::recursive_iterator<Iter0> {
+  return { iterator::in_place, it, iters... };
+}
+
 template <typename C>
 auto make_recursive_iterator(C & collect) -> iterator::recursive_iterator<decltype(std::begin(collect))> {
   return { make_end_aware_iterator(collect)};

+ 55 - 0
recursive_iterator_accessors.t.h

@@ -0,0 +1,55 @@
+//
+//  recursive_iterator_accessors.t.h
+//  iterator
+//
+//  Created by Sam Jaffe on 2/21/17.
+//
+
+#pragma once
+
+#include <cxxtest/TestSuite.h>
+
+class recursive_iterator_accessors_TestSuite : public CxxTest::TestSuite {
+public:
+  void test_access_iterator_types() {
+    using layer1 = std::map<int, int>;
+    using layer2 = std::vector<layer1>;
+    using object_type = std::map<int, layer2>;
+    object_type const obj{{ 1, {{{1, 1}}, {{2, 2}}}}, {2, {{{3, 3}, {4, 4}}}}};
+    auto rit = make_recursive_iterator(obj);
+    TS_ASSERT_EQUALS(typeid(decltype(std::get<0>(rit))).name(),
+                     typeid(iterator::end_aware_iterator<object_type::const_iterator>).name());
+    TS_ASSERT_EQUALS(typeid(decltype(std::get<1>(rit))).name(),
+                     typeid(iterator::end_aware_iterator<layer2::const_iterator>).name());
+    TS_ASSERT_EQUALS(typeid(decltype(std::get<2>(rit))).name(),
+                     typeid(iterator::end_aware_iterator<layer1::const_iterator>).name());
+  }
+  
+  void test_construct_inplace_recursive_iterator() {
+    using layer1 = std::map<int, int>;
+    using layer2 = std::vector<layer1>;
+    using object_type = std::map<int, layer2>;
+    object_type const obj{{ 1, {{{1, 1}}, {{2, 2}}}}, {2, {{{3, 3}, {4, 4}}}}};
+    auto const it = make_end_aware_iterator(obj.begin(), obj.end());
+    auto const it_1 = ++make_end_aware_iterator(it->second);
+    auto const it_2 = make_end_aware_iterator(*it_1);
+    TS_ASSERT_THROWS_NOTHING(make_recursive_iterator(it, it_1, it_2));
+  }
+  
+  void test_access_iterator_values_match_inplace() {
+    using layer1 = std::map<int, int>;
+    using layer2 = std::vector<layer1>;
+    using object_type = std::map<int, layer2>;
+    object_type const obj{{ 1, {{{1, 1}}, {{2, 2}}}}, {2, {{{3, 3}, {4, 4}}}}};
+    auto const it = make_end_aware_iterator(obj.begin(), obj.end());
+    auto const it_1 = ++make_end_aware_iterator(it->second);
+    auto const it_2 = make_end_aware_iterator(*it_1);
+    iterator::recursive_iterator<object_type::const_iterator> rit{
+      iterator::in_place,
+      it, it_1, it_2
+    };
+    TS_ASSERT_EQUALS(std::get<0>(rit), it);
+    TS_ASSERT_EQUALS(std::get<1>(rit), it_1);
+    TS_ASSERT_EQUALS(std::get<2>(rit), it_2);
+  }
+};

+ 190 - 0
recursive_iterator_meta.hpp

@@ -0,0 +1,190 @@
+//
+//  recursive_iterator_meta.hpp
+//  iterator
+//
+//  Created by Sam Jaffe on 2/21/17.
+//
+
+#pragma once
+
+namespace iterator { namespace detail {
+  
+  /**
+   * @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 > {
+  public:
+    using super = recursive_iterator_base< Iterator >;
+  public:
+    using super::super;
+    recursive_iterator_impl() = default;
+    template <typename OIter>
+    recursive_iterator_impl(in_place_t, OIter iter) : super(iter) {}
+  protected:
+    void next() { super::operator++(); }
+    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> > > {
+  public:
+    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*() const -> decltype(*(next_layer&)(*this)) { return next_layer::operator*(); }
+    using super::super;
+    recursive_iterator_impl() = default;
+    template <typename... Iterators>
+    recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+  };
+  
+  /**
+   * @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> > > {
+  public:
+    using next_layer = recursive_iterator_impl< mapped_iterator<Iterator> >;
+    using super = flatten_iterator_layer< Iterator, next_layer >;
+  public:
+    using super::super;
+    recursive_iterator_impl() = default;
+    template <typename... Iterators>
+    recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+  };
+  
+  /**
+   * @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 > {
+  public:
+    using super = recursive_iterator_base< Iterator >;
+  public:
+    using super::super;
+    bounded_recursive_iterator_impl() = default;
+    template <typename OIter>
+    bounded_recursive_iterator_impl(in_place_t, OIter iter) : super(iter) {}
+  protected:
+    void next() { super::operator++(); }
+    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 > > {
+  public:
+    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*() const -> decltype(*(next_layer&)(*this)) { return next_layer::operator*(); }
+    using super::super;
+    bounded_recursive_iterator_impl() = default;
+    template <typename... Iterators>
+    bounded_recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+  };
+  
+  /**
+   * @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 > > {
+  public:
+    using next_layer = bounded_recursive_iterator_impl< mapped_iterator<Iterator>, N+1, Max >;
+    using super = flatten_iterator_layer< Iterator, next_layer >;
+  public:
+    using super::super;
+    bounded_recursive_iterator_impl() = default;
+    template <typename... Iterators>
+    bounded_recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+  };
+} }
+
+namespace iterator { namespace detail {
+  template <std::size_t I, typename It, typename = void>
+  struct accessor;
+  
+  template <typename It>
+  struct accessor<0, end_aware_iterator<It>> {
+    using type = end_aware_iterator<It>;
+  };
+  
+  template <typename It, typename Rec>
+  struct accessor<0, recursive_iterator_layer<It, Rec>> {
+    using type = end_aware_iterator<It>;
+  };
+    
+  template <typename It, typename Rec>
+  struct accessor<0, flatten_iterator_layer<It, Rec>> {
+    using type = end_aware_iterator<It>;
+  };
+
+  template <typename It>
+  struct accessor<0, It> {
+    using type = typename accessor<0, typename It::super>::type;
+  };
+  
+  template <std::size_t I, typename It>
+  struct accessor<I, It, typename std::enable_if<I != 0>::type> {
+    using type = typename accessor<I, typename It::super>::type;
+  };
+  
+  template <std::size_t I, typename It, typename Rec>
+  struct accessor<I, recursive_iterator_layer<It, Rec>, typename std::enable_if<I != 0>::type> {
+    using type = typename accessor<I-1, Rec>::type;
+  };
+  
+  template <std::size_t I, typename It, typename Rec>
+  struct accessor<I, flatten_iterator_layer<It, Rec>, typename std::enable_if<I != 0>::type> {
+    using type = typename accessor<I-1, Rec>::type;
+  };
+} }