فهرست منبع

Merge branch 'improve_type_system'

* improve_type_system:
  Add tests for pre-post increment.
  Improve test structuring. Fix handling of string-is-terminal
  Do some cleanup.
  Remove unneeded functions.
  Improve type system, add overrides that mark std::string as terminal in all cases.
  Add an is_associative trait.
  Re-arrange files more sensibly.
  Remove inplace_t entirely
Sam Jaffe 5 سال پیش
والد
کامیت
fc43c04e1e

+ 107 - 0
include/iterator/detail/flatten_iterator_layer.hpp

@@ -0,0 +1,107 @@
+#pragma once
+
+#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 <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(); }
+  };
+}}

+ 81 - 0
include/iterator/detail/recursive_iterator_base.hpp

@@ -0,0 +1,81 @@
+#pragma once
+
+#include "../end_aware_iterator.hpp"
+#include "recursive_iterator_traits.hpp"
+
+namespace iterator { namespace detail {
+
+  template <typename Iterator, typename = void> class recursive_iterator_base;
+
+  /**
+   * @class recursive_iterator_base
+   * @brief A thin wrapper around end_aware_iterator for the purposes of
+   * template metaprogramming.
+   */
+  template <typename Iterator, typename>
+  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;
+
+  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, is_associative_t<Iterator>>
+      : 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;
+
+  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);
+    }
+  };
+
+}}

+ 25 - 73
include/iterator/recursive_iterator_meta.hpp

@@ -7,7 +7,22 @@
 
 #pragma once
 
+#include "flatten_iterator_layer.hpp"
+#include "recursive_iterator_base.hpp"
+#include "recursive_iterator_layer.hpp"
+#include "recursive_iterator_traits.hpp"
+
 namespace iterator { namespace detail {
+  template <typename Iterator, typeclass = typeclass_t<Iterator>::value>
+  class recursive_iterator_impl;
+
+  /**
+   * A bounded_recursive_iterator_impl where N == Max is always a terminal node.
+   */
+  template <typename Iterator, std::size_t N, std::size_t Max,
+            typeclass = std::conditional_t<N == Max, typeclass_t<void>,
+                                           typeclass_t<Iterator>>::value>
+  class bounded_recursive_iterator_impl;
 
   /**
    * @class recursive_iterator_impl
@@ -18,17 +33,15 @@ namespace iterator { namespace detail {
    * @tparam 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> {
+  template <typename Iterator>
+  class recursive_iterator_impl<Iterator, typeclass::TERMINAL>
+      : 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(std::forward<OIter>(iter)) {}
 
   protected:
     void next() { super::operator++(); }
@@ -43,8 +56,7 @@ namespace iterator { namespace detail {
    * @see recursive_iterator_layer
    */
   template <typename Iterator>
-  class recursive_iterator_impl<Iterator,
-                                typename void_t<value_iterator<Iterator>>::type>
+  class recursive_iterator_impl<Iterator, typeclass::CONTAINER>
       : public recursive_iterator_layer<
             Iterator, recursive_iterator_impl<value_iterator<Iterator>>> {
   public:
@@ -63,9 +75,6 @@ namespace iterator { namespace detail {
     }
     using super::super;
     recursive_iterator_impl() = default;
-    //    template <typename... Iterators>
-    //    recursive_iterator_impl(in_place_t, Iterators &&... iter)
-    //        : super(in_place, std::forward<Iterators>(iter)...) {}
   };
 
   /**
@@ -76,8 +85,7 @@ namespace iterator { namespace detail {
    * @see flatten_iterator_layer
    */
   template <typename Iterator>
-  class recursive_iterator_impl<
-      Iterator, typename void_t<mapped_iterator<Iterator>>::type>
+  class recursive_iterator_impl<Iterator, typeclass::ASSOCIATIVE_CONTAINER>
       : public flatten_iterator_layer<
             Iterator, recursive_iterator_impl<mapped_iterator<Iterator>>> {
   public:
@@ -87,9 +95,6 @@ namespace iterator { namespace detail {
   public:
     using super::super;
     recursive_iterator_impl() = default;
-    //    template <typename... Iterators>
-    //    recursive_iterator_impl(in_place_t, Iterators &&... iter)
-    //        : super(in_place, std::forward<Iterators>(iter)...) {}
   };
 
   /**
@@ -104,8 +109,8 @@ namespace iterator { namespace detail {
    * @tparam 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
+  template <typename Iterator, std::size_t N, std::size_t Max>
+  class bounded_recursive_iterator_impl<Iterator, N, Max, typeclass::TERMINAL>
       : public recursive_iterator_base<Iterator> {
   public:
     using super = recursive_iterator_base<Iterator>;
@@ -113,9 +118,6 @@ namespace iterator { namespace detail {
   public:
     using super::super;
     bounded_recursive_iterator_impl() = default;
-    //    template <typename OIter>
-    //    bounded_recursive_iterator_impl(in_place_t, OIter && iter)
-    //        : super(std::forward<OIter>(iter)) {}
 
   protected:
     void next() { super::operator++(); }
@@ -130,10 +132,7 @@ namespace iterator { namespace detail {
    * @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>
+  class bounded_recursive_iterator_impl<Iterator, N, Max, typeclass::CONTAINER>
       : public recursive_iterator_layer<
             Iterator, bounded_recursive_iterator_impl<value_iterator<Iterator>,
                                                       N + 1, Max>> {
@@ -154,9 +153,6 @@ namespace iterator { namespace detail {
     }
     using super::super;
     bounded_recursive_iterator_impl() = default;
-    //    template <typename... Iterators>
-    //    bounded_recursive_iterator_impl(in_place_t, Iterators &&... iter)
-    //        : super(in_place, std::forward<Iterators>(iter)...) {}
   };
 
   /**
@@ -167,10 +163,8 @@ namespace iterator { namespace detail {
    * @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>
+  class bounded_recursive_iterator_impl<Iterator, N, Max,
+                                        typeclass::ASSOCIATIVE_CONTAINER>
       : public flatten_iterator_layer<
             Iterator, bounded_recursive_iterator_impl<mapped_iterator<Iterator>,
                                                       N + 1, Max>> {
@@ -182,47 +176,5 @@ namespace iterator { namespace detail {
   public:
     using super::super;
     bounded_recursive_iterator_impl() = default;
-    //    template <typename... Iterators>
-    //    bounded_recursive_iterator_impl(in_place_t, Iterators &&... iter)
-    //        : super(in_place, std::forward<Iterators>(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;
   };
 }}

+ 89 - 0
include/iterator/detail/recursive_iterator_layer.hpp

@@ -0,0 +1,89 @@
+#pragma once
+
+#include "recursive_iterator_base.hpp"
+#include "recursive_iterator_traits.hpp"
+
+namespace iterator { namespace detail {
+  /**
+   * @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(); }
+  };
+}}

+ 120 - 0
include/iterator/detail/recursive_iterator_traits.hpp

@@ -0,0 +1,120 @@
+#pragma once
+
+#include <iterator>
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "../iterator_fwd.hpp"
+
+namespace iterator { namespace detail {
+  template <typename Iterator, typename RecursiveIterator_NextLayer>
+  class flatten_iterator_layer;
+  template <typename Iterator, typename RecursiveIterator_NextLayer>
+  class recursive_iterator_layer;
+
+  // Helper struct for dealing with merging output from associative and
+  // non-associative containers.
+  // TODO: This seems unnecessarily verbose t.b.h.
+  struct terminal_layer_tag_t;
+  struct continue_layer_tag_t;
+
+  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;
+  };
+
+  // Helpers for condensing type deductions
+  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));
+
+  // Type trait to identify value_type ~~ std::pair<K const, V>, which is
+  // a safe bet towards 'this is an associative container type'
+  template <typename T, typename = void>
+  struct is_associative : std::false_type {};
+  template <typename T>
+  struct is_associative<T, std::enable_if_t<std::is_const<
+                               typename T::value_type::first_type>::value>>
+      : std::true_type {};
+
+  template <typename T>
+  using is_associative_t = std::enable_if_t<is_associative<T>::value>;
+
+  // Type deduction guides for constructing recursive iterators.
+  enum class typeclass { TERMINAL, CONTAINER, ASSOCIATIVE_CONTAINER };
+
+  template <typename> struct void_t { using type = void; };
+
+  template <typename T, typename = void> struct typeclass_t {
+    static constexpr typeclass const value{typeclass::TERMINAL};
+  };
+
+  template <typename T> struct is_string_iterator : std::false_type {};
+  template <>
+  struct is_string_iterator<std::string::iterator> : std::true_type {};
+  template <>
+  struct is_string_iterator<std::string::const_iterator> : std::true_type {};
+
+  template <typename T>
+  struct typeclass_t<
+      T, std::enable_if_t<!is_string_iterator<value_iterator<T>>::value>> {
+    static constexpr typeclass const value{typeclass::CONTAINER};
+  };
+
+  template <typename T>
+  struct typeclass_t<
+      T, std::enable_if_t<is_string_iterator<value_iterator<T>>::value>> {
+    static constexpr typeclass const value{typeclass::TERMINAL};
+  };
+
+  template <typename T>
+  struct typeclass_t<T, typename void_t<mapped_iterator<T>>::type> {
+    static constexpr typeclass const value{typeclass::ASSOCIATIVE_CONTAINER};
+  };
+
+  // Accessor templates for invoking std::get
+  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;
+  };
+
+}}

+ 0 - 4
include/iterator/iterator_fwd.hpp

@@ -10,10 +10,6 @@
 #include <cstdlib>
 
 namespace iterator {
-  struct {
-  } in_place;
-  using in_place_t = decltype(in_place);
-
   template <typename Iterator> class end_aware_iterator;
   template <typename MetaIterator> class joining_iterator;
   template <typename Iterator> class recursive_iterator;

+ 2 - 316
include/iterator/recursive_iterator.hpp

@@ -7,313 +7,12 @@
 
 #pragma once
 
-#include <iterator>
 #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)) {}
-    //    template <typename OIter, typename... Iterators>
-    //    recursive_iterator_layer(in_place_t, OIter && it, Iterators &&...
-    //    iter)
-    //        : layer(std::forward<OIter>(it)),
-    //          super(in_place, std::forward<Iterators>(iter)...) {
-    //      update();
-    //    }
-
-    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)) {}
-    //    template <typename OIter, typename... Iterators>
-    //    flatten_iterator_layer(in_place_t, OIter && it, Iterators &&... iter)
-    //        : layer(std::forward<OIter>(it)),
-    //          super(in_place, std::forward<Iterators>(iter)...) {
-    //      update();
-    //    }
-
-    /**
-     * @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
@@ -336,9 +35,6 @@ namespace iterator {
   public:
     using super::super;
     recursive_iterator() = default;
-    //    template <typename... Iterators>
-    //    recursive_iterator(in_place_t, Iterators &&... iter)
-    //        : super(in_place, std::forward<Iterators>(iter)...) {}
 
     recursive_iterator & operator++() {
       (void)super::next();
@@ -383,9 +79,6 @@ namespace iterator {
   public:
     using super::super;
     recursive_iterator_n() = default;
-    //    template <typename... Iterators>
-    //    recursive_iterator_n(in_place_t, Iterators &&... iter)
-    //        : super(in_place, std::forward<Iterators>(iter)...) {}
 
     recursive_iterator_n & operator++() {
       (void)super::next();
@@ -421,13 +114,6 @@ namespace std {
   }
 }
 
-// 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, std::move(it), std::forward<Iters>(iters)...};
-//}
-
 template <typename C>
 auto make_recursive_iterator(C & collect)
     -> iterator::recursive_iterator<decltype(std::begin(collect))> {

+ 4 - 0
iterator.xcodeproj/project.pbxproj

@@ -17,6 +17,7 @@
 		CDCB3BDC24E1D5320029B771 /* filter_iterator_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BD324E1D5320029B771 /* filter_iterator_test.cxx */; };
 		CDCB3BDD24E1D5320029B771 /* indexed_iterator_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BD424E1D5320029B771 /* indexed_iterator_test.cxx */; };
 		CDCB3BDE24E1D5320029B771 /* recursive_iterator_map_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BD524E1D5320029B771 /* recursive_iterator_map_test.cxx */; };
+		CDCB3BFC24E327CF0029B771 /* recursive_iterator_single_level_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BFB24E327CF0029B771 /* recursive_iterator_single_level_test.cxx */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -83,6 +84,7 @@
 		CDCB3BD324E1D5320029B771 /* filter_iterator_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filter_iterator_test.cxx; sourceTree = "<group>"; };
 		CDCB3BD424E1D5320029B771 /* indexed_iterator_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = indexed_iterator_test.cxx; sourceTree = "<group>"; };
 		CDCB3BD524E1D5320029B771 /* recursive_iterator_map_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = recursive_iterator_map_test.cxx; sourceTree = "<group>"; };
+		CDCB3BFB24E327CF0029B771 /* recursive_iterator_single_level_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = recursive_iterator_single_level_test.cxx; sourceTree = "<group>"; };
 		CDEC1E01235167920091D9F2 /* GoogleMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GoogleMock.xcodeproj; path = "../../../gmock-xcode-master/GoogleMock.xcodeproj"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -137,6 +139,7 @@
 				CDCB3BD124E1D5320029B771 /* recursive_iterator_mixed_container_test.cxx */,
 				CDCB3BD524E1D5320029B771 /* recursive_iterator_map_test.cxx */,
 				CDCB3BCF24E1D5320029B771 /* recursive_iterator_vector_test.cxx */,
+				CDCB3BFB24E327CF0029B771 /* recursive_iterator_single_level_test.cxx */,
 				CDCB3BCE24E1D5320029B771 /* unkeyed_iterator_test.cxx */,
 			);
 			path = test;
@@ -338,6 +341,7 @@
 				CDCB3BD724E1D5320029B771 /* unkeyed_iterator_test.cxx in Sources */,
 				CDCB3BDA24E1D5320029B771 /* recursive_iterator_mixed_container_test.cxx in Sources */,
 				CDCB3BD924E1D5320029B771 /* recursive_iterator_accessors_test.cxx in Sources */,
+				CDCB3BFC24E327CF0029B771 /* recursive_iterator_single_level_test.cxx in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 30 - 47
test/recursive_iterator_accessors_test.cxx

@@ -1,11 +1,18 @@
 #include "iterator/recursive_iterator.hpp"
 
 #include <map>
+#include <string>
+#include <tuple>
 #include <vector>
 
 #include <gmock/gmock.h>
 
-// TODO: std::string should not be unwrapped
+TEST(RecursiveIteratorTest, DoesNotUnwrapString) {
+  std::vector<std::string> obj{"A", "B", "C", "D"};
+  auto rit = make_recursive_iterator(obj);
+  testing::StaticAssertTypeEq<decltype(rit.operator->()), std::string *>();
+}
+
 TEST(RecursiveIteratorTest, CanArrowMultiVector) {
   std::vector<std::vector<int>> obj{{{0, 1}}, {{2, 3}}};
   auto rit = make_recursive_iterator(obj);
@@ -22,14 +29,14 @@ TEST(RecursiveIteratorTest, CannotArrowMap) {
 TEST(RecursiveIteratorTest, CanAccessOuterterator) {
   std::map<int, std::vector<int>> obj{{1, {{0, 1}}}, {2, {{2, 3}}}};
   auto rit = make_recursive_iterator(obj);
-  auto inner = iterator::end_aware_iterator<decltype(obj)::iterator>(rit);
+  iterator::end_aware_iterator<decltype(obj)::iterator> inner = rit;
   EXPECT_THAT(&std::get<0>(*rit), &(inner->first));
 }
 
 TEST(RecursiveIteratorTest, CanAccessInnerIterator) {
   std::map<int, std::vector<int>> obj{{1, {{0, 1}}}, {2, {{2, 3}}}};
   auto rit = make_recursive_iterator(obj);
-  auto inner = iterator::end_aware_iterator<std::vector<int>::iterator>(rit);
+  iterator::end_aware_iterator<std::vector<int>::iterator> inner = rit;
   EXPECT_THAT(&std::get<1>(*rit), &*inner);
 }
 
@@ -39,17 +46,17 @@ TEST(RecursiveIteratorTest, CanStdGetToAllLayersOfInternalIteration) {
       {2, {{{3, 3}, {4, 4}}}}    // 1 2-element map
   };
   auto rit = make_recursive_iterator(obj);
-  testing::StaticAssertTypeEq<
-      decltype(std::get<0>(rit)),
-      iterator::end_aware_iterator<decltype(obj)::iterator>>();
+  using mvm_iterator = std::map<int, std::vector<std::map<int, int>>>::iterator;
+  testing::StaticAssertTypeEq<decltype(std::get<0>(rit)),
+                              iterator::end_aware_iterator<mvm_iterator>>();
+  using vm_iterator = std::vector<std::map<int, int>>::iterator;
   testing::StaticAssertTypeEq<decltype(std::get<1>(rit)),
-                              iterator::end_aware_iterator<
-                                  std::vector<std::map<int, int>>::iterator>>();
-  testing::StaticAssertTypeEq<
-      decltype(std::get<2>(rit)),
-      iterator::end_aware_iterator<std::map<int, int>::iterator>>();
-  testing::StaticAssertTypeEq<decltype(*rit),
-                              std::tuple<int const &, int const &, int &>>();
+                              iterator::end_aware_iterator<vm_iterator>>();
+  using m_iterator = std::map<int, int>::iterator;
+  testing::StaticAssertTypeEq<decltype(std::get<2>(rit)),
+                              iterator::end_aware_iterator<m_iterator>>();
+  using tup_i_i_i = std::tuple<int const &, int const &, int &>;
+  testing::StaticAssertTypeEq<decltype(*rit), tup_i_i_i>();
 }
 
 TEST(RecursiveIteratorTest, CanAccessInternalIteratorsWithGet) {
@@ -91,14 +98,14 @@ TEST(BoundedRecursiveIteratorTest, CanStdGetToNLayersOfInternalIteration) {
       {2, {{{3, 3}, {4, 4}}}}    // 1 2-element map
   };
   auto rit = make_recursive_iterator<2>(obj);
-  testing::StaticAssertTypeEq<
-      decltype(std::get<0>(rit)),
-      iterator::end_aware_iterator<decltype(obj)::iterator>>();
+  using mvm_iterator = std::map<int, std::vector<std::map<int, int>>>::iterator;
+  testing::StaticAssertTypeEq<decltype(std::get<0>(rit)),
+                              iterator::end_aware_iterator<mvm_iterator>>();
+  using vm_iterator = std::vector<std::map<int, int>>::iterator;
   testing::StaticAssertTypeEq<decltype(std::get<1>(rit)),
-                              iterator::end_aware_iterator<
-                                  std::vector<std::map<int, int>>::iterator>>();
-  testing::StaticAssertTypeEq<decltype(*rit),
-                              std::tuple<int const &, std::map<int, int> &>>();
+                              iterator::end_aware_iterator<vm_iterator>>();
+  using tup_i_mii = std::tuple<int const &, std::map<int, int> &>;
+  testing::StaticAssertTypeEq<decltype(*rit), tup_i_mii>();
 }
 
 TEST(BoundedRecursiveIteratorTest, CanAccessInternalIteratorsWithGet) {
@@ -126,10 +133,10 @@ TEST(BoundedRecursiveIteratorTest, EmptyCtorIsEnd) {
       {1, {{{1, 1}}, {{2, 2}}}}, // 2 1-element maps
       {2, {{{3, 3}, {4, 4}}}}    // 1 2-element map
   };
-  auto rit = make_recursive_iterator<2>(obj);
+  auto rit = make_recursive_iterator<3>(obj);
   EXPECT_THAT(rit, testing::Ne(decltype(rit)()));
-  EXPECT_THAT(std::distance(rit, decltype(rit)()), 3);
-  std::advance(rit, 3);
+  EXPECT_THAT(std::distance(rit, decltype(rit)()), 4);
+  std::advance(rit, 4);
   EXPECT_THAT(rit, decltype(rit)());
 }
 
@@ -141,27 +148,3 @@ TEST(BoundedRecursiveIteratorTest, CanFetchInnerCollections) {
   auto rit = make_recursive_iterator<2>(obj);
   EXPECT_THAT(*rit, obj[0][0]);
 }
-
-// TEST(RecursiveIteratorTest, CanConstructInPlaceFromIterators) {
-//  std::map<int, std::vector<std::map<int, int>>> 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);
-//  // Note that this carries the weakness of non bounds-checking that our
-//  // iterators are all sitting on the same hierarchy...
-//  EXPECT_NO_THROW(make_recursive_iterator(it, it_1, it_2));
-//}
-//
-// TEST(RecursiveIteratorTest, InternalIteratorsFromStdGetMatchCtorArgs) {
-//  std::map<int, std::vector<std::map<int, int>>> 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<decltype(obj.cbegin())> rit{iterator::in_place,
-//                                                           it, it_1, it_2};
-//  EXPECT_THAT(std::get<0>(rit), it);
-//  EXPECT_THAT(std::get<1>(rit), it_1);
-//  EXPECT_THAT(std::get<2>(rit), it_2);
-//}

+ 65 - 37
test/recursive_iterator_map_test.cxx

@@ -6,64 +6,92 @@
 
 #include <gmock/gmock.h>
 
-TEST(RecursiveIteratorSingleMapTest, IterDistanceIsContainerSize) {
-  std::map<int, int> const map{{1, 1}, {2, 2}, {3, 3}};
+TEST(RecursiveIteratorMapTest, PreIncrementAdvancesIterator) {
+  std::map<int, std::map<int, std::map<int, int>>> const map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
   auto rit = make_recursive_iterator(map);
-  decltype(rit) end{};
-  EXPECT_THAT(std::distance(rit, end), map.size());
-}
-
-TEST(RecursiveIteratorSingleMapTest, DataMatchesContainerIterator) {
-  std::map<int, int> const map{{1, 1}, {2, 2}, {3, 3}};
-  auto rit = make_recursive_iterator(map);
-  decltype(map) result(rit, decltype(rit)());
-  EXPECT_THAT(result, map);
+  EXPECT_THAT(std::get<3>(*rit), 1);
+  EXPECT_THAT(std::get<3>(*++rit), 2);
+  EXPECT_THAT(std::get<3>(*rit), 2);
 }
 
-TEST(RecursiveIteratorSingleMapTest, CanMutatePointedToData) {
-  std::map<int, int> map{{1, 1}, {2, 2}, {3, 3}};
+TEST(RecursiveIteratorMapTest, PostIncrementReturnsCopyOfPrev) {
+  std::map<int, std::map<int, std::map<int, int>>> const map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
   auto rit = make_recursive_iterator(map);
-  std::get<1>(*rit) = 4;
-  EXPECT_THAT(map[1], 4);
+  EXPECT_THAT(std::get<3>(*rit), 1);
+  EXPECT_THAT(std::get<3>(*rit++), 1);
+  EXPECT_THAT(std::get<3>(*rit), 2);
 }
 
-TEST(RecursiveIteratorMapMapTest, IterDistanceIsSumOfInnerContainerSizes) {
-  std::map<int, std::map<int, int>> const map{{1, {{1, 1}}},
-                                              {2, {{2, 2}, {3, 3}}}};
+TEST(RecursiveIteratorMapTest, IterDistanceIsSumOfInnerContainerSizes) {
+  std::map<int, std::map<int, std::map<int, int>>> const map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
   auto rit = make_recursive_iterator(map);
   decltype(rit) end{};
   // TODO: Actually perform the summation?
-  EXPECT_THAT(std::distance(rit, end), 3);
+  EXPECT_THAT(std::distance(rit, end), 4);
 }
 
-TEST(RecursiveIteratorMapMapTest, ElementsAreUnwrappedAsATuple) {
-  std::map<int, std::map<int, int>> const map{{1, {{1, 1}}},
-                                              {2, {{2, 2}, {3, 3}}}};
-  std::vector<std::tuple<int, int, int>> const expected{
-      {1, 1, 1}, {2, 2, 2}, {2, 3, 3}};
+TEST(RecursiveIteratorMapTest, ElementsAreUnwrappedAsATuple) {
+  std::map<int, std::map<int, std::map<int, int>>> const map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
+  std::vector<std::tuple<int, int, int, int>> const expected{
+      {1, 1, 1, 1}, {2, 2, 2, 2}, {2, 3, 3, 3}, {2, 3, 4, 4}};
   auto rit = make_recursive_iterator(map);
   decltype(expected) result(rit, decltype(rit)());
   EXPECT_THAT(result, expected);
 }
 
-TEST(RecursiveIteratorMapMapTest, CanMutatePointedToData) {
-  std::map<int, std::map<int, int>> map{{1, {{1, 1}}}, {2, {{2, 2}, {3, 3}}}};
+TEST(RecursiveIteratorMapTest, CanMutatePointedToData) {
+  std::map<int, std::map<int, std::map<int, int>>> map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
   auto rit = make_recursive_iterator(map);
-  std::get<2>(*rit) = 4;
-  EXPECT_THAT(map[1][1], 4);
+  std::get<3>(*rit) = 4;
+  EXPECT_THAT(map[1][1][1], 4);
+}
+
+TEST(BoundRecursiveIteratorMapTest, PreIncrementAdvancesIterator) {
+  std::map<int, std::map<int, std::map<int, int>>> map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
+  auto rit = make_recursive_iterator<2>(map);
+  EXPECT_THAT(std::get<2>(*rit), map[1][1]);
+  EXPECT_THAT(std::get<2>(*++rit), map[2][2]);
+  EXPECT_THAT(std::get<2>(*rit), map[2][2]);
 }
 
-TEST(BoundRecursiveIteratorMapMapTest, IterDistanceSumOnNLayersSize) {
-  std::map<int, std::map<int, int>> map{{1, {{1, 1}}}, {2, {{2, 2}, {3, 3}}}};
-  auto rit = make_recursive_iterator<1>(map);
+TEST(BoundRecursiveIteratorMapTest, PostIncrementReturnsCopyOfPrev) {
+  std::map<int, std::map<int, std::map<int, int>>> map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
+  auto rit = make_recursive_iterator<2>(map);
+  EXPECT_THAT(std::get<2>(*rit), map[1][1]);
+  EXPECT_THAT(std::get<2>(*rit++), map[1][1]);
+  EXPECT_THAT(std::get<2>(*rit), map[2][2]);
+}
+
+TEST(BoundRecursiveIteratorMapTest, IterDistanceSumOnNLayersSize) {
+  std::map<int, std::map<int, std::map<int, int>>> const map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
+  auto rit = make_recursive_iterator<2>(map);
   decltype(rit) end{};
 
-  EXPECT_THAT(std::distance(rit, end), map.size());
+  EXPECT_THAT(std::distance(rit, end), 3);
+}
+
+TEST(BoundRecursiveIteratorMapTest, ElementsAreUnwrappedAsATuple) {
+  std::map<int, std::map<int, std::map<int, int>>> const map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
+  std::vector<std::tuple<int, int, std::map<int, int>>> const expected{
+      {1, 1, {{1, 1}}}, {2, 2, {{2, 2}}}, {2, 3, {{3, 3}, {4, 4}}}};
+  auto rit = make_recursive_iterator<2>(map);
+  decltype(expected) result(rit, decltype(rit)());
+  EXPECT_THAT(result, expected);
 }
 
-TEST(BoundRecursiveIteratorMapMapTest, ElementsAreUnwrappedAsATuple) {
-  std::map<int, std::map<int, int>> map{{1, {{1, 1}}}, {2, {{2, 2}, {3, 3}}}};
-  auto rit = make_recursive_iterator<1>(map);
-  decltype(map) result(rit, decltype(rit)());
-  EXPECT_THAT(result, map);
+TEST(BoundedRecursiveIteratorMapTest, CanMutatePointedToData) {
+  std::map<int, std::map<int, std::map<int, int>>> map{
+      {1, {{1, {{1, 1}}}}}, {2, {{2, {{2, 2}}}, {3, {{3, 3}, {4, 4}}}}}};
+  auto rit = make_recursive_iterator<2>(map);
+  std::get<2>(*rit).clear();
+  EXPECT_THAT(map[1][1], testing::IsEmpty());
 }

+ 56 - 0
test/recursive_iterator_single_level_test.cxx

@@ -0,0 +1,56 @@
+//
+//  recursive_iterator_single_level_test.cxx
+//  iterator-test
+//
+//  Created by Sam Jaffe on 8/11/20.
+//  Copyright © 2020 Sam Jaffe. All rights reserved.
+//
+
+#include "iterator/recursive_iterator.hpp"
+
+#include <map>
+#include <vector>
+
+#include <gmock/gmock.h>
+
+TEST(RecursiveIteratorSingleVectorTest, IterDistanceIsContainerSize) {
+  std::vector<int> const vec{1, 2, 3, 4, 5};
+  auto rit = make_recursive_iterator(vec);
+  decltype(rit) end{};
+  EXPECT_THAT(std::distance(rit, end), vec.size());
+}
+
+TEST(RecursiveIteratorSingleVectorTest, DataMatchesContainerIterator) {
+  std::vector<int> const vec{1, 2, 3, 4, 5};
+  auto rit = make_recursive_iterator(vec);
+  decltype(vec) result(rit, decltype(rit)());
+  EXPECT_THAT(result, vec);
+}
+
+TEST(RecursiveIteratorSingleVectorTest, CanMutatePointedToData) {
+  std::vector<int> vec{1, 2, 3, 4, 5};
+  auto rit = make_recursive_iterator(vec);
+  *rit = 6;
+  EXPECT_THAT(vec[0], 6);
+}
+
+TEST(RecursiveIteratorSingleMapTest, IterDistanceIsContainerSize) {
+  std::map<int, int> const map{{1, 1}, {2, 2}, {3, 3}};
+  auto rit = make_recursive_iterator(map);
+  decltype(rit) end{};
+  EXPECT_THAT(std::distance(rit, end), map.size());
+}
+
+TEST(RecursiveIteratorSingleMapTest, DataMatchesContainerIterator) {
+  std::map<int, int> const map{{1, 1}, {2, 2}, {3, 3}};
+  auto rit = make_recursive_iterator(map);
+  decltype(map) result(rit, decltype(rit)());
+  EXPECT_THAT(result, map);
+}
+
+TEST(RecursiveIteratorSingleMapTest, CanMutatePointedToData) {
+  std::map<int, int> map{{1, 1}, {2, 2}, {3, 3}};
+  auto rit = make_recursive_iterator(map);
+  std::get<1>(*rit) = 4;
+  EXPECT_THAT(map[1], 4);
+}

+ 50 - 32
test/recursive_iterator_vector_test.cxx

@@ -4,30 +4,24 @@
 
 #include <gmock/gmock.h>
 
-TEST(RecursiveIteratorSingleVectorTest, IterDistanceIsContainerSize) {
-  std::vector<int> const vec{1, 2, 3, 4, 5};
+TEST(RecursiveIteratorVecTest, PreIncrementAdvancesIterator) {
+  std::vector<std::vector<std::vector<int>>> const vec{{{1, 2}}, {{3}, {4, 5}}};
   auto rit = make_recursive_iterator(vec);
-  decltype(rit) end{};
-  EXPECT_THAT(std::distance(rit, end), vec.size());
+  EXPECT_THAT(*rit, 1);
+  EXPECT_THAT(*++rit, 2);
+  EXPECT_THAT(*rit, 2);
 }
 
-TEST(RecursiveIteratorSingleVectorTest, ElementsAreUnwrappedAsATuple) {
-  std::vector<int> const vec{1, 2, 3, 4, 5};
+TEST(RecursiveIteratorVecTest, PostIncrementReturnsCopyOfPrev) {
+  std::vector<std::vector<std::vector<int>>> const vec{{{1, 2}}, {{3}, {4, 5}}};
   auto rit = make_recursive_iterator(vec);
-  decltype(vec) result(rit, decltype(rit)());
-  EXPECT_THAT(result, vec);
+  EXPECT_THAT(*rit, 1);
+  EXPECT_THAT(*rit++, 1);
+  EXPECT_THAT(*rit, 2);
 }
 
-TEST(RecursiveIteratorSingleVectorTest, CanMutatePointedToData) {
-  std::vector<int> vec{1, 2, 3, 4, 5};
-  auto rit = make_recursive_iterator(vec);
-  *rit = 6;
-  EXPECT_THAT(vec[0], 6);
-}
-
-TEST(RecursiveIteratorVectorVectorTest,
-     IterDistanceIsSumOfInnerContainerSizes) {
-  std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
+TEST(RecursiveIteratorVecTest, IterDistanceIsSumOfInnerContainerSizes) {
+  std::vector<std::vector<std::vector<int>>> const vec{{{1, 2}}, {{3}, {4, 5}}};
   auto rit = make_recursive_iterator(vec);
   decltype(rit) end{};
 
@@ -35,32 +29,56 @@ TEST(RecursiveIteratorVectorVectorTest,
   EXPECT_THAT(std::distance(rit, end), 5);
 }
 
-TEST(RecursiveIteratorVectorVectorTest, ElementsAreUnwrappedAsATuple) {
-  std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
+TEST(RecursiveIteratorVecTest, FlattensVectorDataLikeJoinIterator) {
+  std::vector<std::vector<std::vector<int>>> const vec{{{1, 2}}, {{3}, {4, 5}}};
   std::vector<int> const expected{1, 2, 3, 4, 5};
   auto rit = make_recursive_iterator(vec);
   decltype(expected) result(rit, decltype(rit)());
   EXPECT_THAT(result, expected);
 }
 
-TEST(RecursiveIteratorVectorVectorTest, CanMutatePointedToData) {
-  std::vector<std::vector<int>> vec{{1, 2}, {3, 4, 5}};
+TEST(RecursiveIteratorVecTest, CanMutatePointedToData) {
+  std::vector<std::vector<std::vector<int>>> vec{{{1, 2}}, {{3}, {4, 5}}};
   auto rit = make_recursive_iterator(vec);
   *rit = 6;
-  EXPECT_THAT(vec[0][0], 6);
+  EXPECT_THAT(vec[0][0][0], 6);
+}
+
+TEST(BoundedRecursiveIteratorVecTest, PreIncrementAdvancesIterator) {
+  std::vector<std::vector<std::vector<int>>> const vec{{{1, 2}}, {{3}, {4, 5}}};
+  auto rit = make_recursive_iterator<2>(vec);
+  EXPECT_THAT(*rit, vec[0][0]);
+  EXPECT_THAT(*++rit, vec[1][0]);
+  EXPECT_THAT(*rit, vec[1][0]);
 }
 
-TEST(BoundedRecursiveIteratorVectorVectorTest, IterDistanceSumOnNLayersSize) {
-  std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
-  auto rit = make_recursive_iterator<1>(vec);
+TEST(BoundedRecursiveIteratorVecTest, PostIncrementReturnsCopyOfPrev) {
+  std::vector<std::vector<std::vector<int>>> const vec{{{1, 2}}, {{3}, {4, 5}}};
+  auto rit = make_recursive_iterator<2>(vec);
+  EXPECT_THAT(*rit, vec[0][0]);
+  EXPECT_THAT(*rit++, vec[0][0]);
+  EXPECT_THAT(*rit, vec[1][0]);
+}
+
+TEST(BoundedRecursiveIteratorVecTest, IterDistanceSumOnNLayersSize) {
+  std::vector<std::vector<std::vector<int>>> const vec{{{1, 2}}, {{3}, {4, 5}}};
+  auto rit = make_recursive_iterator<2>(vec);
   decltype(rit) end{};
 
-  EXPECT_THAT(std::distance(rit, end), vec.size());
+  EXPECT_THAT(std::distance(rit, end), 3);
+}
+
+TEST(BoundedRecursiveIteratorVecTest, ElementsAreUnwrappedAsATuple) {
+  std::vector<std::vector<std::vector<int>>> const vec{{{1, 2}}, {{3}, {4, 5}}};
+  std::vector<std::vector<int>> const expected{{1, 2}, {3}, {4, 5}};
+  auto rit = make_recursive_iterator<2>(vec);
+  decltype(expected) result(rit, decltype(rit)());
+  EXPECT_THAT(result, expected);
 }
 
-TEST(BoundedRecursiveIteratorVectorVectorTest, ElementsAreUnwrappedAsATuple) {
-  std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
-  auto rit = make_recursive_iterator<1>(vec);
-  decltype(vec) result(rit, decltype(rit)());
-  EXPECT_THAT(result, vec);
+TEST(BoundedRecursiveIteratorVecTest, CanMutatePointedToData) {
+  std::vector<std::vector<std::vector<int>>> vec{{{1, 2}}, {{3}, {4, 5}}};
+  auto rit = make_recursive_iterator<2>(vec);
+  rit->clear();
+  EXPECT_THAT(vec[0][0], testing::IsEmpty());
 }