Actually denote when we have infinite generators
authorJoe Richey <jrichey@fb.com>
Tue, 14 Jul 2015 20:50:31 +0000 (13:50 -0700)
committerSara Golemon <sgolemon@fb.com>
Wed, 15 Jul 2015 20:25:11 +0000 (13:25 -0700)
Summary: Before we didn't do anything at all with the ::infinite value for our
generators, now all the sources operators and sinks are properly notated. The
one signifcant change regarding what is allowed concerns 'cycle' which now (when
called with no arguments) always produces an infinite generator. This is fine
for all but the weirdest of generators fed into cycle.

Reviewed By: @ddrcoder

Differential Revision: D2240328

folly/gen/Base-inl.h
folly/gen/Core-inl.h
folly/gen/test/BaseTest.cpp

index 7a26fedeb512be83c4c094936e8b438149492304..fe3a78f45c479075cedf8e2638f5cfe2ab4b4b8a 100644 (file)
@@ -37,6 +37,9 @@ struct ArgumentReference
                                     T&& // int -> int&&
                                     >::type> {};
 
+/**
+ * Group - The output objects from the GroupBy operator
+ */
 template <class Key, class Value>
 class Group : public GenImpl<Value&&, Group<Key, Value>> {
  public:
@@ -82,6 +85,9 @@ class Group : public GenImpl<Value&&, Group<Key, Value>> {
     return true;
   }
 
+  // GroupBy only takes in finite generators, so we only have finite groups
+  static constexpr bool infinite = false;
+
  private:
   Key key_;
   mutable VectorType values_;
@@ -89,6 +95,12 @@ class Group : public GenImpl<Value&&, Group<Key, Value>> {
 
 namespace detail {
 
+// Classes used for the implementation of Sources, Operators, and Sinks
+
+/*
+ ******************************* Sources ***************************************
+ */
+
 /*
  * ReferencedSource - Generate values from an STL-like container using
  * iterators from .begin() until .end(). Value type defaults to the type of
@@ -101,23 +113,22 @@ namespace detail {
  *   string& longestName = from(names)
  *                       | maxBy([](string& s) { return s.size() });
  */
-template<class Container,
-         class Value>
-class ReferencedSource :
-    public GenImpl<Value, ReferencedSource<Container, Value>> {
+template <class Container, class Value>
+class ReferencedSource
+    : public GenImpl<Value, ReferencedSource<Container, Value>> {
   Container* container_;
-public:
-  explicit ReferencedSource(Container* container)
-    : container_(container) {}
 
-  template<class Body>
+ public:
+  explicit ReferencedSource(Container* container) : container_(container) {}
+
+  template <class Body>
   void foreach(Body&& body) const {
     for (auto& value : *container_) {
       body(std::forward<Value>(value));
     }
   }
 
-  template<class Handler>
+  template <class Handler>
   bool apply(Handler&& handler) const {
     for (auto& value : *container_) {
       if (!handler(std::forward<Value>(value))) {
@@ -126,6 +137,9 @@ public:
     }
     return true;
   }
+
+  // from takes in a normal stl structure, which are all finite
+  static constexpr bool infinite = false;
 };
 
 /**
@@ -142,45 +156,44 @@ public:
  *
  * Though it is also used for the initializer_list specialization of from().
  */
-template<class StorageType,
-         class Container>
-class CopiedSource :
-  public GenImpl<const StorageType&,
-                 CopiedSource<StorageType, Container>> {
-  static_assert(
-    !std::is_reference<StorageType>::value, "StorageType must be decayed");
+template <class StorageType, class Container>
+class CopiedSource
+    : public GenImpl<const StorageType&, CopiedSource<StorageType, Container>> {
+  static_assert(!std::is_reference<StorageType>::value,
+                "StorageType must be decayed");
+
  public:
   // Generator objects are often copied during normal construction as they are
   // encapsulated by downstream generators. It would be bad if this caused
   // a copy of the entire container each time, and since we're only exposing a
   // const reference to the value, it's safe to share it between multiple
   // generators.
-  static_assert(
-    !std::is_reference<Container>::value,
-    "Can't copy into a reference");
+  static_assert(!std::is_reference<Container>::value,
+                "Can't copy into a reference");
   std::shared_ptr<const Container> copy_;
-public:
+
+ public:
   typedef Container ContainerType;
 
-  template<class SourceContainer>
+  template <class SourceContainer>
   explicit CopiedSource(const SourceContainer& container)
-    : copy_(new Container(begin(container), end(container))) {}
+      : copy_(new Container(begin(container), end(container))) {}
 
-  explicit CopiedSource(Container&& container) :
-    copy_(new Container(std::move(container))) {}
+  explicit CopiedSource(Container&& container)
+      : copy_(new Container(std::move(container))) {}
 
   // To enable re-use of cached results.
   CopiedSource(const CopiedSource<StorageType, Container>& source)
-    : copy_(source.copy_) {}
+      : copy_(source.copy_) {}
 
-  template<class Body>
+  template <class Body>
   void foreach(Body&& body) const {
     for (const auto& value : *copy_) {
       body(value);
     }
   }
 
-  template<class Handler>
+  template <class Handler>
   bool apply(Handler&& handler) const {
     // The collection may be reused by others, we can't allow it to be changed.
     for (const auto& value : *copy_) {
@@ -190,6 +203,9 @@ public:
     }
     return true;
   }
+
+  // from takes in a normal stl structure, which are all finite
+  static constexpr bool infinite = false;
 };
 
 /**
@@ -203,17 +219,16 @@ public:
  *
  * Reminder: Be careful not to invalidate iterators when using ranges like this.
  */
-template<class Iterator>
+template <class Iterator>
 class RangeSource : public GenImpl<typename Range<Iterator>::reference,
                                    RangeSource<Iterator>> {
   Range<Iterator> range_;
+
  public:
   RangeSource() = default;
-  explicit RangeSource(Range<Iterator> range)
-    : range_(std::move(range))
-  {}
+  explicit RangeSource(Range<Iterator> range) : range_(std::move(range)) {}
 
-  template<class Handler>
+  template <class Handler>
   bool apply(Handler&& handler) const {
     for (auto& value : range_) {
       if (!handler(value)) {
@@ -223,12 +238,15 @@ class RangeSource : public GenImpl<typename Range<Iterator>::reference,
     return true;
   }
 
-  template<class Body>
+  template <class Body>
   void foreach(Body&& body) const {
     for (auto& value : range_) {
       body(value);
     }
   }
+
+  // folly::Range only supports finite ranges
+  static constexpr bool infinite = false;
 };
 
 /**
@@ -242,17 +260,19 @@ class RangeSource : public GenImpl<typename Range<Iterator>::reference,
  *   auto indexes = range(0, 10);
  *   auto endless = seq(0); // 0, 1, 2, 3, ...
  */
-template<class Value, class SequenceImpl>
+template <class Value, class SequenceImpl>
 class Sequence : public GenImpl<const Value&, Sequence<Value, SequenceImpl>> {
   static_assert(!std::is_reference<Value>::value &&
-                !std::is_const<Value>::value, "Value mustn't be const or ref.");
+                    !std::is_const<Value>::value,
+                "Value mustn't be const or ref.");
   Value start_;
   SequenceImpl impl_;
-public:
+
+ public:
   explicit Sequence(Value start, SequenceImpl impl)
-      : start_(std::move(start)), impl_(std::move(impl)) { }
+      : start_(std::move(start)), impl_(std::move(impl)) {}
 
-  template<class Handler>
+  template <class Handler>
   bool apply(Handler&& handler) const {
     for (Value current = start_; impl_.test(current); impl_.step(current)) {
       if (!handler(current)) {
@@ -262,71 +282,83 @@ public:
     return true;
   }
 
-  template<class Body>
+  template <class Body>
   void foreach(Body&& body) const {
     for (Value current = start_; impl_.test(current); impl_.step(current)) {
       body(current);
     }
   }
+
+  // Let the implementation say if we are infinite or not
+  static constexpr bool infinite = SequenceImpl::infinite;
 };
 
 /**
  * Sequence implementations (range, sequence, infinite, with/without step)
  **/
-template<class Value>
+template <class Value>
 class RangeImpl {
   Value end_;
+
  public:
-  explicit RangeImpl(Value end) : end_(std::move(end)) { }
+  explicit RangeImpl(Value end) : end_(std::move(end)) {}
   bool test(const Value& current) const { return current < end_; }
   void step(Value& current) const { ++current; }
+  static constexpr bool infinite = false;
 };
 
-template<class Value, class Distance>
+template <class Value, class Distance>
 class RangeWithStepImpl {
   Value end_;
   Distance step_;
+
  public:
   explicit RangeWithStepImpl(Value end, Distance step)
-    : end_(std::move(end)), step_(std::move(step)) { }
+      : end_(std::move(end)), step_(std::move(step)) {}
   bool test(const Value& current) const { return current < end_; }
   void step(Value& current) const { current += step_; }
+  static constexpr bool infinite = false;
 };
 
-template<class Value>
+template <class Value>
 class SeqImpl {
   Value end_;
+
  public:
-  explicit SeqImpl(Value end) : end_(std::move(end)) { }
+  explicit SeqImpl(Value end) : end_(std::move(end)) {}
   bool test(const Value& current) const { return current <= end_; }
   void step(Value& current) const { ++current; }
+  static constexpr bool infinite = false;
 };
 
-template<class Value, class Distance>
+template <class Value, class Distance>
 class SeqWithStepImpl {
   Value end_;
   Distance step_;
+
  public:
   explicit SeqWithStepImpl(Value end, Distance step)
-    : end_(std::move(end)), step_(std::move(step)) { }
+      : end_(std::move(end)), step_(std::move(step)) {}
   bool test(const Value& current) const { return current <= end_; }
   void step(Value& current) const { current += step_; }
+  static constexpr bool infinite = false;
 };
 
-template<class Value>
+template <class Value>
 class InfiniteImpl {
  public:
   bool test(const Value& current) const { return true; }
   void step(Value& current) const { ++current; }
+  static constexpr bool infinite = true;
 };
 
 /**
  * GenratorBuilder - Helper for GENERTATOR macro.
  **/
-template<class Value>
+template <class Value>
 struct GeneratorBuilder {
-  template<class Source,
-           class Yield = detail::Yield<Value, Source>>
+  template <class Source,
+            class Yield = detail::Yield<Value, Source>>
   Yield operator+(Source&& source) {
     return Yield(std::forward<Source>(source));
   }
@@ -336,15 +368,14 @@ struct GeneratorBuilder {
  * Yield - For producing values from a user-defined generator by way of a
  * 'yield' function.
  **/
-template<class Value, class Source>
+template <class Value, class Source>
 class Yield : public GenImpl<Value, Yield<Value, Source>> {
   Source source_;
+
  public:
-  explicit Yield(Source source)
-    : source_(std::move(source)) {
-  }
+  explicit Yield(Source source) : source_(std::move(source)) {}
 
-  template<class Handler>
+  template <class Handler>
   bool apply(Handler&& handler) const {
     struct Break {};
     auto body = [&](Value value) {
@@ -360,13 +391,13 @@ class Yield : public GenImpl<Value, Yield<Value, Source>> {
     }
   }
 
-  template<class Body>
+  template <class Body>
   void foreach(Body&& body) const {
     source_(std::forward<Body>(body));
   }
 };
 
-template<class Value>
+template <class Value>
 class Empty : public GenImpl<Value, Empty<Value>> {
  public:
   template <class Handler>
@@ -376,6 +407,9 @@ class Empty : public GenImpl<Value, Empty<Value>> {
 
   template <class Body>
   void foreach(Body&&) const {}
+
+  // No values, so finite
+  static constexpr bool infinite = false;
 };
 
 template <class Value>
@@ -383,6 +417,7 @@ class SingleReference : public GenImpl<Value&, SingleReference<Value>> {
   static_assert(!std::is_reference<Value>::value,
                 "SingleReference requires non-ref types");
   Value* ptr_;
+
  public:
   explicit SingleReference(Value& ref) : ptr_(&ref) {}
 
@@ -395,6 +430,9 @@ class SingleReference : public GenImpl<Value&, SingleReference<Value>> {
   void foreach(Body&& body) const {
     body(*ptr_);
   }
+
+  // One value, so finite
+  static constexpr bool infinite = false;
 };
 
 template <class Value>
@@ -402,6 +440,7 @@ class SingleCopy : public GenImpl<const Value&, SingleCopy<Value>> {
   static_assert(!std::is_reference<Value>::value,
                 "SingleCopy requires non-ref types");
   Value value_;
+
  public:
   explicit SingleCopy(Value value) : value_(std::forward<Value>(value)) {}
 
@@ -414,10 +453,13 @@ class SingleCopy : public GenImpl<const Value&, SingleCopy<Value>> {
   void foreach(Body&& body) const {
     body(value_);
   }
+
+  // One value, so finite
+  static constexpr bool infinite = false;
 };
 
 /*
- * Operators
+ ***************************** Operators ***************************************
  */
 
 /**
@@ -428,37 +470,34 @@ class SingleCopy : public GenImpl<const Value&, SingleCopy<Value>> {
  *
  *   auto squares = seq(1, 10) | map(square) | asVector;
  */
-template<class Predicate>
+template <class Predicate>
 class Map : public Operator<Map<Predicate>> {
   Predicate pred_;
+
  public:
   Map() = default;
 
-  explicit Map(Predicate pred)
-    : pred_(std::move(pred))
-  { }
-
-  template<class Value,
-           class Source,
-           class Result = typename ArgumentReference<
-                            typename std::result_of<Predicate(Value)>::type
-                          >::type>
-  class Generator :
-      public GenImpl<Result, Generator<Value, Source, Result>> {
+  explicit Map(Predicate pred) : pred_(std::move(pred)) {}
+
+  template <class Value,
+            class Source,
+            class Result = typename ArgumentReference<
+                typename std::result_of<Predicate(Value)>::type>::type>
+  class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
     Source source_;
     Predicate pred_;
-  public:
+
+   public:
     explicit Generator(Source source, const Predicate& pred)
-      : source_(std::move(source)), pred_(pred) {}
+        : source_(std::move(source)), pred_(pred) {}
 
-    template<class Body>
+    template <class Body>
     void foreach(Body&& body) const {
-      source_.foreach([&](Value value) {
-        body(pred_(std::forward<Value>(value)));
-      });
+      source_.foreach(
+          [&](Value value) { body(pred_(std::forward<Value>(value))); });
     }
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
       return source_.apply([&](Value value) {
         return handler(pred_(std::forward<Value>(value)));
@@ -468,16 +507,16 @@ class Map : public Operator<Map<Predicate>> {
     static constexpr bool infinite = Source::infinite;
   };
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), pred_);
   }
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), pred_);
   }
@@ -500,25 +539,24 @@ class Map : public Operator<Map<Predicate>> {
  *
  * will give a vector of all the pointers != nullptr.
  */
-template<class Predicate>
+template <class Predicate>
 class Filter : public Operator<Filter<Predicate>> {
   Predicate pred_;
+
  public:
   Filter() = default;
-  explicit Filter(Predicate pred)
-    : pred_(std::move(pred))
-  { }
+  explicit Filter(Predicate pred) : pred_(std::move(pred)) {}
 
-  template<class Value,
-           class Source>
+  template <class Value, class Source>
   class Generator : public GenImpl<Value, Generator<Value, Source>> {
     Source source_;
     Predicate pred_;
-  public:
+
+   public:
     explicit Generator(Source source, const Predicate& pred)
-      : source_(std::move(source)), pred_(pred) {}
+        : source_(std::move(source)), pred_(pred) {}
 
-    template<class Body>
+    template <class Body>
     void foreach(Body&& body) const {
       source_.foreach([&](Value value) {
         if (pred_(std::forward<Value>(value))) {
@@ -527,7 +565,7 @@ class Filter : public Operator<Filter<Predicate>> {
       });
     }
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
       return source_.apply([&](Value value) -> bool {
         if (pred_(std::forward<Value>(value))) {
@@ -540,16 +578,16 @@ class Filter : public Operator<Filter<Predicate>> {
     static constexpr bool infinite = Source::infinite;
   };
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), pred_);
   }
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), pred_);
   }
@@ -564,25 +602,24 @@ class Filter : public Operator<Filter<Predicate>> {
  *             | until([](Item& item) { return item.score > 100; })
  *             | asVector;
  */
-template<class Predicate>
+template <class Predicate>
 class Until : public Operator<Until<Predicate>> {
   Predicate pred_;
+
  public:
   Until() = default;
-  explicit Until(Predicate pred)
-    : pred_(std::move(pred))
-  {}
+  explicit Until(Predicate pred) : pred_(std::move(pred)) {}
 
-  template<class Value,
-           class Source>
+  template <class Value, class Source>
   class Generator : public GenImpl<Value, Generator<Value, Source>> {
     Source source_;
     Predicate pred_;
+
    public:
     explicit Generator(Source source, const Predicate& pred)
-      : source_(std::move(source)), pred_(pred) {}
+        : source_(std::move(source)), pred_(pred) {}
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
       bool cancelled = false;
       source_.apply([&](Value value) -> bool {
@@ -597,24 +634,24 @@ class Until : public Operator<Until<Predicate>> {
       });
       return !cancelled;
     }
+
+    // Theoretically an 'until' might stop an infinite
+    static constexpr bool infinite = false;
   };
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), pred_);
   }
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), pred_);
   }
-
-  // Theoretically an 'until' might stop an infinite
-  static constexpr bool infinite = false;
 };
 
 /**
@@ -628,23 +665,24 @@ class Until : public Operator<Until<Predicate>> {
  */
 class Take : public Operator<Take> {
   size_t count_;
+
  public:
-  explicit Take(size_t count)
-    : count_(count) {}
+  explicit Take(size_t count) : count_(count) {}
 
-  template<class Value,
-           class Source>
-  class Generator :
-      public GenImpl<Value, Generator<Value, Source>> {
+  template <class Value, class Source>
+  class Generator : public GenImpl<Value, Generator<Value, Source>> {
     Source source_;
     size_t count_;
-  public:
+
+   public:
     explicit Generator(Source source, size_t count)
-      : source_(std::move(source)) , count_(count) {}
+        : source_(std::move(source)), count_(count) {}
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
-      if (count_ == 0) { return false; }
+      if (count_ == 0) {
+        return false;
+      }
       size_t n = count_;
       bool cancelled = false;
       source_.apply([&](Value value) -> bool {
@@ -656,18 +694,21 @@ class Take : public Operator<Take> {
       });
       return !cancelled;
     }
+
+    // take will stop an infinite generator
+    static constexpr bool infinite = false;
   };
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), count_);
   }
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), count_);
   }
@@ -695,42 +736,50 @@ class Stride : public Operator<Stride> {
   class Generator : public GenImpl<Value, Generator<Value, Source>> {
     Source source_;
     size_t stride_;
-  public:
-   Generator(Source source, size_t stride)
-       : source_(std::move(source)), stride_(stride) {}
-
-   template <class Handler>
-   bool apply(Handler&& handler) const {
-     size_t distance = stride_;
-     return source_.apply([&](Value value)->bool {
-       if (++distance >= stride_) {
-         if (!handler(std::forward<Value>(value))) {
-           return false;
-         }
-         distance = 0;
-       }
-       return true;
-     });
-   }
-
-   template <class Body>
-   void foreach(Body&& body) const {
-     size_t distance = stride_;
-     source_.foreach([&](Value value) {
-       if (++distance >= stride_) {
-         body(std::forward<Value>(value));
-         distance = 0;
-       }
-     });
-   }
+
+   public:
+    explicit Generator(Source source, size_t stride)
+        : source_(std::move(source)), stride_(stride) {}
+
+    template <class Handler>
+    bool apply(Handler&& handler) const {
+      size_t distance = stride_;
+      return source_.apply([&](Value value) -> bool {
+        if (++distance >= stride_) {
+          if (!handler(std::forward<Value>(value))) {
+            return false;
+          }
+          distance = 0;
+        }
+        return true;
+      });
+    }
+
+    template <class Body>
+    void foreach(Body&& body) const {
+      size_t distance = stride_;
+      source_.foreach([&](Value value) {
+        if (++distance >= stride_) {
+          body(std::forward<Value>(value));
+          distance = 0;
+        }
+      });
+    }
+
+    // Taking every Nth of an infinite list is still infinte
+    static constexpr bool infinite = Source::infinite;
   };
 
-  template <class Source, class Value, class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), stride_);
   }
 
-  template <class Source, class Value, class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), stride_);
   }
@@ -740,21 +789,22 @@ class Stride : public Operator<Stride> {
  * Sample - For taking a random sample of N elements from a sequence
  * (without replacement).
  */
-template<class Random>
+template <class Random>
 class Sample : public Operator<Sample<Random>> {
   size_t count_;
   Random rng_;
+
  public:
   explicit Sample(size_t count, Random rng)
-    : count_(count), rng_(std::move(rng)) {}
-
-  template<class Value,
-           class Source,
-           class Rand,
-           class StorageType = typename std::decay<Value>::type>
-  class Generator :
-          public GenImpl<StorageType&&,
-                         Generator<Value, Source, Rand, StorageType>> {
+      : count_(count), rng_(std::move(rng)) {}
+
+  template <class Value,
+            class Source,
+            class Rand,
+            class StorageType = typename std::decay<Value>::type>
+  class Generator
+      : public GenImpl<StorageType&&,
+                       Generator<Value, Source, Rand, StorageType>> {
     static_assert(!Source::infinite, "Cannot sample infinite source!");
     // It's too easy to bite ourselves if random generator is only 16-bit
     static_assert(Random::max() >= std::numeric_limits<int32_t>::max() - 1,
@@ -762,53 +812,59 @@ class Sample : public Operator<Sample<Random>> {
     Source source_;
     size_t count_;
     mutable Rand rng_;
-  public:
+
+   public:
     explicit Generator(Source source, size_t count, Random rng)
-      : source_(std::move(source)) , count_(count), rng_(std::move(rng)) {}
+        : source_(std::move(source)), count_(count), rng_(std::move(rng)) {}
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
-      if (count_ == 0) { return false; }
+      if (count_ == 0) {
+        return false;
+      }
       std::vector<StorageType> v;
       v.reserve(count_);
       // use reservoir sampling to give each source value an equal chance
       // of appearing in our output.
       size_t n = 1;
       source_.foreach([&](Value value) -> void {
-          if (v.size() < count_) {
-            v.push_back(std::forward<Value>(value));
-          } else {
-            // alternatively, we could create a std::uniform_int_distribution
-            // instead of using modulus, but benchmarks show this has
-            // substantial overhead.
-            size_t index = rng_() % n;
-            if (index < v.size()) {
-              v[index] = std::forward<Value>(value);
-            }
+        if (v.size() < count_) {
+          v.push_back(std::forward<Value>(value));
+        } else {
+          // alternatively, we could create a std::uniform_int_distribution
+          // instead of using modulus, but benchmarks show this has
+          // substantial overhead.
+          size_t index = rng_() % n;
+          if (index < v.size()) {
+            v[index] = std::forward<Value>(value);
           }
-          ++n;
-        });
+        }
+        ++n;
+      });
 
       // output is unsorted!
-      for (auto& val: v) {
+      for (auto& val : v) {
         if (!handler(std::move(val))) {
           return false;
         }
       }
       return true;
     }
+
+    // Only takes N elements, so finite
+    static constexpr bool infinite = false;
   };
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source, Random>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source, Random>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), count_, rng_);
   }
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source, Random>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source, Random>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), count_, rng_);
   }
@@ -825,21 +881,20 @@ class Sample : public Operator<Sample<Random>> {
  */
 class Skip : public Operator<Skip> {
   size_t count_;
+
  public:
-  explicit Skip(size_t count)
-    : count_(count) {}
+  explicit Skip(size_t count) : count_(count) {}
 
-  template<class Value,
-           class Source>
-  class Generator :
-      public GenImpl<Value, Generator<Value, Source>> {
+  template <class Value, class Source>
+  class Generator : public GenImpl<Value, Generator<Value, Source>> {
     Source source_;
     size_t count_;
+
    public:
     explicit Generator(Source source, size_t count)
-      : source_(std::move(source)) , count_(count) {}
+        : source_(std::move(source)), count_(count) {}
 
-    template<class Body>
+    template <class Body>
     void foreach(Body&& body) const {
       if (count_ == 0) {
         source_.foreach(body);
@@ -847,42 +902,43 @@ class Skip : public Operator<Skip> {
       }
       size_t n = 0;
       source_.foreach([&](Value value) {
-          if (n < count_) {
-            ++n;
-          } else {
-            body(std::forward<Value>(value));
-          }
-        });
+        if (n < count_) {
+          ++n;
+        } else {
+          body(std::forward<Value>(value));
+        }
+      });
     }
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
       if (count_ == 0) {
         return source_.apply(std::forward<Handler>(handler));
       }
       size_t n = 0;
       return source_.apply([&](Value value) -> bool {
-          if (n < count_) {
-            ++n;
-            return true;
-          }
-          return handler(std::forward<Value>(value));
-        });
+        if (n < count_) {
+          ++n;
+          return true;
+        }
+        return handler(std::forward<Value>(value));
+      });
     }
 
+    // Skipping N items of an infinite source is still infinite
     static constexpr bool infinite = Source::infinite;
   };
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), count_);
   }
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), count_);
   }
@@ -901,30 +957,26 @@ class Skip : public Operator<Skip> {
  *                  })
  *                | take(10);
  */
-template<class Selector, class Comparer>
+template <class Selector, class Comparer>
 class Order : public Operator<Order<Selector, Comparer>> {
   Selector selector_;
   Comparer comparer_;
+
  public:
   Order() = default;
 
-  explicit Order(Selector selector)
-    : selector_(std::move(selector))
-  {}
-
-  Order(Selector selector,
-        Comparer comparer)
-    : selector_(std::move(selector))
-    , comparer_(std::move(comparer))
-  {}
-
-  template<class Value,
-           class Source,
-           class StorageType = typename std::decay<Value>::type,
-           class Result = typename std::result_of<Selector(Value)>::type>
-  class Generator :
-    public GenImpl<StorageType&&,
-                   Generator<Value, Source, StorageType, Result>> {
+  explicit Order(Selector selector) : selector_(std::move(selector)) {}
+
+  Order(Selector selector, Comparer comparer)
+      : selector_(std::move(selector)), comparer_(std::move(comparer)) {}
+
+  template <class Value,
+            class Source,
+            class StorageType = typename std::decay<Value>::type,
+            class Result = typename std::result_of<Selector(Value)>::type>
+  class Generator
+      : public GenImpl<StorageType&&,
+                       Generator<Value, Source, StorageType, Result>> {
     static_assert(!Source::infinite, "Cannot sort infinite source!");
     Source source_;
     Selector selector_;
@@ -940,13 +992,12 @@ class Order : public Operator<Order<Selector, Comparer>> {
       std::sort(vals.begin(), vals.end(), comparer);
       return std::move(vals);
     }
+
    public:
-    Generator(Source source,
-              Selector selector,
-              Comparer comparer)
-      : source_(std::move(source)),
-        selector_(std::move(selector)),
-        comparer_(std::move(comparer)) {}
+    Generator(Source source, Selector selector, Comparer comparer)
+        : source_(std::move(source)),
+          selector_(std::move(selector)),
+          comparer_(std::move(comparer)) {}
 
     VectorType operator|(const Collect<VectorType>&) const {
       return asVector();
@@ -956,14 +1007,14 @@ class Order : public Operator<Order<Selector, Comparer>> {
       return asVector();
     }
 
-    template<class Body>
+    template <class Body>
     void foreach(Body&& body) const {
       for (auto& value : asVector()) {
         body(std::move(value));
       }
     }
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
       auto comparer = [&](const StorageType& a, const StorageType& b) {
         // swapped for minHeap
@@ -980,18 +1031,21 @@ class Order : public Operator<Order<Selector, Comparer>> {
       }
       return true;
     }
+
+    // Can only be run on and produce finite generators
+    static constexpr bool infinite = false;
   };
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), selector_, comparer_);
   }
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), selector_, comparer_);
   }
@@ -1057,14 +1111,21 @@ class GroupBy : public Operator<GroupBy<Selector>> {
       }
       return true;
     }
+
+    // Can only be run on and produce finite generators
+    static constexpr bool infinite = false;
   };
 
-  template <class Source, class Value, class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), selector_);
   }
 
-  template <class Source, class Value, class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), selector_);
   }
@@ -1079,17 +1140,17 @@ class GroupBy : public Operator<GroupBy<Selector>> {
  *   auto c =  from(vector) | assert_type<int&>() | sum;
  *
  */
-template<class Expected>
+template <class Expected>
 class TypeAssertion : public Operator<TypeAssertion<Expected>> {
  public:
-  template<class Source, class Value>
+  template <class Source, class Value>
   const Source& compose(const GenImpl<Value, Source>& source) const {
     static_assert(std::is_same<Expected, Value>::value,
                   "assert_type() check failed");
     return source.self();
   }
 
-  template<class Source, class Value>
+  template <class Source, class Value>
   Source&& compose(GenImpl<Value, Source>&& source) const {
     static_assert(std::is_same<Expected, Value>::value,
                   "assert_type() check failed");
@@ -1109,18 +1170,16 @@ class TypeAssertion : public Operator<TypeAssertion<Expected>> {
  *                  })
  *                | take(10);
  */
-template<class Selector>
+template <class Selector>
 class Distinct : public Operator<Distinct<Selector>> {
   Selector selector_;
+
  public:
   Distinct() = default;
 
-  explicit Distinct(Selector selector)
-    : selector_(std::move(selector))
-  {}
+  explicit Distinct(Selector selector) : selector_(std::move(selector)) {}
 
-  template<class Value,
-           class Source>
+  template <class Value, class Source>
   class Generator : public GenImpl<Value, Generator<Value, Source>> {
     Source source_;
     Selector selector_;
@@ -1135,12 +1194,10 @@ class Distinct : public Operator<Distinct<Selector>> {
     typedef typename std::decay<KeyType>::type KeyStorageType;
 
    public:
-    Generator(Source source,
-              Selector selector)
-      : source_(std::move(source)),
-        selector_(std::move(selector)) {}
+    Generator(Source source, Selector selector)
+        : source_(std::move(source)), selector_(std::move(selector)) {}
 
-    template<class Body>
+    template <class Body>
     void foreach(Body&& body) const {
       std::unordered_set<KeyStorageType> keysSeen;
       source_.foreach([&](Value value) {
@@ -1150,7 +1207,7 @@ class Distinct : public Operator<Distinct<Selector>> {
       });
     }
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
       std::unordered_set<KeyStorageType> keysSeen;
       return source_.apply([&](Value value) -> bool {
@@ -1160,18 +1217,22 @@ class Distinct : public Operator<Distinct<Selector>> {
         return true;
       });
     }
+
+    // While running distinct on an infinite sequence might produce a
+    // conceptually finite sequence, it will take infinite time
+    static constexpr bool infinite = Source::infinite;
   };
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), selector_);
   }
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), selector_);
   }
@@ -1181,16 +1242,16 @@ class Distinct : public Operator<Distinct<Selector>> {
  * Composer - Helper class for adapting pipelines into functors. Primarily used
  * for 'mapOp'.
  */
-template<class Operators>
+template <class Operators>
 class Composer {
   Operators op_;
+
  public:
-  explicit Composer(Operators op)
-    : op_(std::move(op)) {}
+  explicit Composer(Operators op) : op_(std::move(op)) {}
 
-  template<class Source,
-           class Ret = decltype(std::declval<Operators>()
-                                  .compose(std::declval<Source>()))>
+  template <class Source,
+            class Ret = decltype(
+                std::declval<Operators>().compose(std::declval<Source>()))>
   Ret operator()(Source&& source) const {
     return op_.compose(std::forward<Source>(source));
   }
@@ -1211,42 +1272,42 @@ class Composer {
  */
 class Batch : public Operator<Batch> {
   size_t batchSize_;
+
  public:
-  explicit Batch(size_t batchSize)
-    : batchSize_(batchSize) {
+  explicit Batch(size_t batchSize) : batchSize_(batchSize) {
     if (batchSize_ == 0) {
       throw std::invalid_argument("Batch size must be non-zero!");
     }
   }
 
-  template<class Value,
-           class Source,
-           class StorageType = typename std::decay<Value>::type,
-           class VectorType = std::vector<StorageType>>
-  class Generator :
-      public GenImpl<VectorType&,
-                     Generator<Value, Source, StorageType, VectorType>> {
+  template <class Value,
+            class Source,
+            class StorageType = typename std::decay<Value>::type,
+            class VectorType = std::vector<StorageType>>
+  class Generator
+      public GenImpl<VectorType&,
+                       Generator<Value, Source, StorageType, VectorType>> {
     Source source_;
     size_t batchSize_;
-  public:
+
+   public:
     explicit Generator(Source source, size_t batchSize)
-      : source_(std::move(source))
-      , batchSize_(batchSize) {}
+        : source_(std::move(source)), batchSize_(batchSize) {}
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
       VectorType batch_;
       batch_.reserve(batchSize_);
       bool shouldContinue = source_.apply([&](Value value) -> bool {
-          batch_.push_back(std::forward<Value>(value));
-          if (batch_.size() == batchSize_) {
-            bool needMore = handler(batch_);
-            batch_.clear();
-            return needMore;
-          }
-          // Always need more if the handler is not called.
-          return true;
-        });
+        batch_.push_back(std::forward<Value>(value));
+        if (batch_.size() == batchSize_) {
+          bool needMore = handler(batch_);
+          batch_.clear();
+          return needMore;
+        }
+        // Always need more if the handler is not called.
+        return true;
+      });
       // Flush everything, if and only if `handler` hasn't returned false.
       if (shouldContinue && !batch_.empty()) {
         shouldContinue = handler(batch_);
@@ -1255,765 +1316,780 @@ class Batch : public Operator<Batch> {
       return shouldContinue;
     }
 
+    // Taking n-tuples of an infinite source is still infinite
     static constexpr bool infinite = Source::infinite;
   };
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()), batchSize_);
   }
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self(), batchSize_);
   }
 };
-/*
- * Sinks
- */
 
 /**
- * FoldLeft - Left-associative functional fold. For producing an aggregate value
- * from a seed and a folder function. Useful for custom aggregators on a
- * sequence.
+ * Concat - For flattening generators of generators.
  *
- * This type is primarily used through the 'foldl' helper method, like:
+ * This type is usually used through the 'concat' static value, like:
  *
- *   double movingAverage = from(values)
- *                        | foldl(0.0, [](double avg, double sample) {
- *                            return sample * 0.1 + avg * 0.9;
- *                          });
+ *   auto edges =
+ *       from(nodes)
+ *     | map([](Node& x) {
+ *           return from(x.neighbors)
+ *                | map([&](Node& y) {
+ *                    return Edge(x, y);
+ *                  });
+ *         })
+ *     | concat
+ *     | as<std::set>();
  */
-template<class Seed,
-         class Fold>
-class FoldLeft : public Operator<FoldLeft<Seed, Fold>> {
-  Seed seed_;
-  Fold fold_;
+class Concat : public Operator<Concat> {
  public:
-  FoldLeft() = default;
-  FoldLeft(Seed seed,
-           Fold fold)
-    : seed_(std::move(seed))
-    , fold_(std::move(fold))
-  {}
-
-  template<class Source,
-           class Value>
-  Seed compose(const GenImpl<Value, Source>& source) const {
-    static_assert(!Source::infinite, "Cannot foldl infinite source");
-    Seed accum = seed_;
-    source | [&](Value v) {
-      accum = fold_(std::move(accum), std::forward<Value>(v));
-    };
-    return accum;
+  Concat() = default;
+
+  template <class Inner,
+            class Source,
+            class InnerValue = typename std::decay<Inner>::type::ValueType>
+  class Generator
+      : public GenImpl<InnerValue, Generator<Inner, Source, InnerValue>> {
+    Source source_;
+
+   public:
+    explicit Generator(Source source) : source_(std::move(source)) {}
+
+    template <class Handler>
+    bool apply(Handler&& handler) const {
+      return source_.apply([&](Inner inner) -> bool {
+        return inner.apply(std::forward<Handler>(handler));
+      });
+    }
+
+    template <class Body>
+    void foreach(Body&& body) const {
+      source_.foreach([&](Inner inner) {
+        inner.foreach(std::forward<Body>(body));
+      });
+    }
+
+    // Resulting concatination is only finite if both Source and Inner are also
+    // finite. In one sence, if dosn't make sence to call concat when the Inner
+    // generator is infinite (you could just call first), so we could also just
+    // static_assert if the inner is infinite. Taking the less restrictive
+    // approch for now.
+    static constexpr bool infinite =
+        Source::infinite || std::decay<Inner>::type::infinite;
+  };
+
+  template <class Value,
+            class Source,
+            class Gen = Generator<Value, Source>>
+  Gen compose(GenImpl<Value, Source>&& source) const {
+    return Gen(std::move(source.self()));
+  }
+
+  template <class Value,
+            class Source,
+            class Gen = Generator<Value, Source>>
+  Gen compose(const GenImpl<Value, Source>& source) const {
+    return Gen(source.self());
   }
 };
 
 /**
- * First - For finding the first value in a sequence.
+ * RangeConcat - For flattening generators of iterables.
  *
- * This type is primarily used through the 'first' static value, like:
+ * This type is usually used through the 'rconcat' static value, like:
  *
- *   int firstThreeDigitPrime = seq(100) | filter(isPrime) | first;
+ *   map<int, vector<int>> adjacency;
+ *   auto sinks =
+ *       from(adjacency)
+ *     | get<1>()
+ *     | rconcat()
+ *     | as<std::set>();
  */
-class First : public Operator<First> {
+class RangeConcat : public Operator<RangeConcat> {
  public:
-  First() = default;
-
-  template<class Source,
-           class Value,
-           class StorageType = typename std::decay<Value>::type>
-  StorageType compose(const GenImpl<Value, Source>& source) const {
-    Optional<StorageType> accum;
-    source | [&](Value v) -> bool {
-      accum = std::forward<Value>(v);
-      return false;
-    };
-    if (!accum.hasValue()) {
-      throw EmptySequence();
-    }
-    return std::move(accum.value());
-  }
-};
+  RangeConcat() = default;
 
-/**
- * IsEmpty - a helper class for isEmpty and notEmpty
- *
- * Essentially returns 'result' if the source is empty. Note that this cannot be
- * called on an infinite source, because then there is only one possible return
- * value.
- */
-template <bool emptyResult>
-class IsEmpty : public Operator<IsEmpty<emptyResult>> {
- public:
-  IsEmpty() = default;
+  template <class Range,
+            class Source,
+            class InnerValue = typename ValueTypeOfRange<Range>::RefType>
+  class Generator
+      : public GenImpl<InnerValue, Generator<Range, Source, InnerValue>> {
+    Source source_;
 
-  template<class Source,
-           class Value>
-  bool compose(const GenImpl<Value, Source>& source) const {
-    static_assert(!Source::infinite,
-                  "Cannot call 'all', 'any', 'isEmpty', or 'notEmpty' on "
-                  "infinite source. 'all' and 'isEmpty' will either return "
-                  "false or hang. 'any' or 'notEmpty' will either return true "
-                  "or hang.");
-    bool ans = emptyResult;
-    source | [&](Value v) -> bool {
-      ans = !emptyResult;
-      return false;
-    };
-    return ans;
-  }
-};
+   public:
+    explicit Generator(Source source) : source_(std::move(source)) {}
 
-/**
- * Reduce - Functional reduce, for recursively combining values from a source
- * using a reducer function until there is only one item left. Useful for
- * combining values when an empty sequence doesn't make sense.
- *
- * This type is primarily used through the 'reduce' helper method, like:
- *
- *   sring longest = from(names)
- *                 | reduce([](string&& best, string& current) {
- *                     return best.size() >= current.size() ? best : current;
- *                   });
- */
-template<class Reducer>
-class Reduce : public Operator<Reduce<Reducer>> {
-  Reducer reducer_;
- public:
-  Reduce() = default;
-  explicit Reduce(Reducer reducer)
-    : reducer_(std::move(reducer))
-  {}
+    template <class Body>
+    void foreach(Body&& body) const {
+      source_.foreach([&](Range range) {
+        for (auto& value : range) {
+          body(value);
+        }
+      });
+    }
 
-  template<class Source,
-           class Value,
-           class StorageType = typename std::decay<Value>::type>
-  StorageType compose(const GenImpl<Value, Source>& source) const {
-    Optional<StorageType> accum;
-    source | [&](Value v) {
-      if (accum.hasValue()) {
-        accum = reducer_(std::move(accum.value()), std::forward<Value>(v));
-      } else {
-        accum = std::forward<Value>(v);
-      }
-    };
-    if (!accum.hasValue()) {
-      throw EmptySequence();
+    template <class Handler>
+    bool apply(Handler&& handler) const {
+      return source_.apply([&](Range range) -> bool {
+        for (auto& value : range) {
+          if (!handler(value)) {
+            return false;
+          }
+        }
+        return true;
+      });
     }
-    return accum.value();
-  }
-};
 
-/**
- * Count - for simply counting the items in a collection.
- *
- * This type is usually used through its singleton, 'count':
- *
- *   auto shortPrimes = seq(1, 100) | filter(isPrime) | count;
- */
-class Count : public Operator<Count> {
- public:
-  Count() = default;
+    // This is similar to concat, except that the inner iterables all are finite
+    // so the only thing that matters is that the source is infinite.
+    static constexpr bool infinite = Source::infinite;
+  };
 
-  template<class Source,
-           class Value>
-  size_t compose(const GenImpl<Value, Source>& source) const {
-    static_assert(!Source::infinite, "Cannot count infinite source");
-    return foldl(size_t(0),
-                 [](size_t accum, Value v) {
-                   return accum + 1;
-                 }).compose(source);
+  template <class Value,
+            class Source,
+            class Gen = Generator<Value, Source>>
+  Gen compose(GenImpl<Value, Source>&& source) const {
+    return Gen(std::move(source.self()));
   }
-};
 
-/**
- * Sum - For simply summing up all the values from a source.
- *
- * This type is usually used through its singleton, 'sum':
- *
- *   auto gaussSum = seq(1, 100) | sum;
- */
-class Sum : public Operator<Sum> {
- public:
-  Sum() = default;
-
-  template<class Source,
-           class Value,
-           class StorageType = typename std::decay<Value>::type>
-  StorageType compose(const GenImpl<Value, Source>& source) const {
-    static_assert(!Source::infinite, "Cannot sum infinite source");
-    return foldl(StorageType(0),
-                 [](StorageType&& accum, Value v) {
-                   return std::move(accum) + std::forward<Value>(v);
-                 }).compose(source);
+  template <class Value,
+            class Source,
+            class Gen = Generator<Value, Source>>
+  Gen compose(const GenImpl<Value, Source>& source) const {
+    return Gen(source.self());
   }
 };
 
 /**
- * Contains - For testing whether a value matching the given value is contained
- * in a sequence.
- *
- * This type should be used through the 'contains' helper method, like:
+ * GuardImpl - For handling exceptions from downstream computation. Requires the
+ * type of exception to catch, and handler function to invoke in the event of
+ * the exception. Note that the handler may:
+ *   1) return true to continue processing the sequence
+ *   2) return false to end the sequence immediately
+ *   3) throw, to pass the exception to the next catch
+ * The handler must match the signature 'bool(Exception&, Value)'.
  *
- *   bool contained = seq(1, 10) | map(square) | contains(49);
- */
-template<class Needle>
-class Contains : public Operator<Contains<Needle>> {
-  Needle needle_;
- public:
-  explicit Contains(Needle needle)
-    : needle_(std::move(needle))
-  {}
-
-  template<class Source,
-           class Value,
-           class StorageType = typename std::decay<Value>::type>
-  bool compose(const GenImpl<Value, Source>& source) const {
-    static_assert(!Source::infinite,
-                  "Calling contains on an infinite source might cause "
-                  "an infinite loop.");
-    return !(source | [this](Value value) {
-        return !(needle_ == std::forward<Value>(value));
-      });
-  }
-};
-
-/**
- * Min - For a value which minimizes a key, where the key is determined by a
- * given selector, and compared by given comparer.
+ * This type is used through the `guard` helper, like so:
  *
- * This type is usually used through the singletone 'min' or through the helper
- * functions 'minBy' and 'maxBy'.
+ *  auto indexes
+ *    = byLine(STDIN_FILENO)
+ *    | guard<std::runtime_error>([](std::runtime_error& e,
+ *                                   StringPiece sp) {
+ *        LOG(ERROR) << sp << ": " << e.str();
+ *        return true; // continue processing subsequent lines
+ *      })
+ *    | eachTo<int>()
+ *    | as<vector>();
  *
- *   auto oldest = from(people)
- *               | minBy([](Person& p) {
- *                   return p.dateOfBirth;
- *                 });
- */
-template<class Selector,
-         class Comparer>
-class Min : public Operator<Min<Selector, Comparer>> {
-  Selector selector_;
-  Comparer comparer_;
- public:
-  Min() = default;
-
-  explicit Min(Selector selector)
-    : selector_(std::move(selector))
-  {}
-
-  Min(Selector selector,
-        Comparer comparer)
-    : selector_(std::move(selector))
-    , comparer_(std::move(comparer))
-  {}
-
-  template<class Value,
-           class Source,
-           class StorageType = typename std::decay<Value>::type,
-           class Key = typename std::decay<
-               typename std::result_of<Selector(Value)>::type
-             >::type>
-  StorageType compose(const GenImpl<Value, Source>& source) const {
-    Optional<StorageType> min;
-    Optional<Key> minKey;
-    source | [&](Value v) {
-      Key key = selector_(std::forward<Value>(v));
-      if (!minKey.hasValue() || comparer_(key, minKey.value())) {
-        minKey = key;
-        min = std::forward<Value>(v);
-      }
-    };
-    if (!min.hasValue()) {
-      throw EmptySequence();
-    }
-    return min.value();
-  }
-};
+ *  TODO(tjackson): Rename this back to Guard.
+ **/
+template <class Exception, class ErrorHandler>
+class GuardImpl : public Operator<GuardImpl<Exception, ErrorHandler>> {
+  ErrorHandler handler_;
 
-/**
- * Append - For collecting values from a source into a given output container
- * by appending.
- *
- * This type is usually used through the helper function 'appendTo', like:
- *
- *   vector<int64_t> ids;
- *   from(results) | map([](Person& p) { return p.id })
- *                 | appendTo(ids);
- */
-template<class Collection>
-class Append : public Operator<Append<Collection>> {
-  Collection* collection_;
  public:
-  explicit Append(Collection* collection)
-    : collection_(collection)
-  {}
+  explicit GuardImpl(ErrorHandler handler) : handler_(std::move(handler)) {}
 
-  template<class Value,
-           class Source>
-  Collection& compose(const GenImpl<Value, Source>& source) const {
-    source | [&](Value v) {
-      collection_->insert(collection_->end(), std::forward<Value>(v));
-    };
-    return *collection_;
-  }
-};
+  template <class Value, class Source>
+  class Generator : public GenImpl<Value, Generator<Value, Source>> {
+    Source source_;
+    ErrorHandler handler_;
 
-/**
- * Collect - For collecting values from a source in a collection of the desired
- * type.
- *
- * This type is usually used through the helper function 'as', like:
- *
- *   std::string upper = from(stringPiece)
- *                     | map(&toupper)
- *                     | as<std::string>();
- */
-template<class Collection>
-class Collect : public Operator<Collect<Collection>> {
- public:
-  Collect() = default;
+   public:
+    explicit Generator(Source source, ErrorHandler handler)
+        : source_(std::move(source)), handler_(std::move(handler)) {}
 
-  template<class Value,
-           class Source,
-           class StorageType = typename std::decay<Value>::type>
-  Collection compose(const GenImpl<Value, Source>& source) const {
-    Collection collection;
-    source | [&](Value v) {
-      collection.insert(collection.end(), std::forward<Value>(v));
-    };
-    return collection;
-  }
-};
+    template <class Handler>
+    bool apply(Handler&& handler) const {
+      return source_.apply([&](Value value) -> bool {
+        try {
+          handler(std::forward<Value>(value));
+          return true;
+        } catch (Exception& e) {
+          return handler_(e, std::forward<Value>(value));
+        }
+      });
+    }
 
+    // Just passes value though, length unaffected
+    static constexpr bool infinite = Source::infinite;
+  };
 
-/**
- * CollectTemplate - For collecting values from a source in a collection
- * constructed using the specified template type. Given the type of values
- * produced by the given generator, the collection type will be:
- *   Container<Value, Allocator<Value>>
- *
- * The allocator defaults to std::allocator, so this may be used for the STL
- * containers by simply using operators like 'as<set>', 'as<deque>',
- * 'as<vector>'. 'as', here is the helper method which is the usual means of
- * consturcting this operator.
- *
- * Example:
- *
- *   set<string> uniqueNames = from(names) | as<set>();
- */
-template<template<class, class> class Container,
-         template<class> class Allocator>
-class CollectTemplate : public Operator<CollectTemplate<Container, Allocator>> {
- public:
-  CollectTemplate() = default;
+  template <class Value,
+            class Source,
+            class Gen = Generator<Value, Source>>
+  Gen compose(GenImpl<Value, Source>&& source) const {
+    return Gen(std::move(source.self()), handler_);
+  }
 
-  template<class Value,
-           class Source,
-           class StorageType = typename std::decay<Value>::type,
-           class Collection = Container<StorageType, Allocator<StorageType>>>
-  Collection compose(const GenImpl<Value, Source>& source) const {
-    Collection collection;
-    source | [&](Value v) {
-      collection.insert(collection.end(), std::forward<Value>(v));
-    };
-    return collection;
+  template <class Value,
+            class Source,
+            class Gen = Generator<Value, Source>>
+  Gen compose(const GenImpl<Value, Source>& source) const {
+    return Gen(source.self(), handler_);
   }
 };
 
 /**
- * Concat - For flattening generators of generators.
+ * Dereference - For dereferencing a sequence of pointers while filtering out
+ * null pointers.
  *
- * This type is usually used through the 'concat' static value, like:
+ * This type is usually used through the 'dereference' static value, like:
  *
- *   auto edges =
- *       from(nodes)
- *     | map([](Node& x) {
- *           return from(x.neighbors)
- *                | map([&](Node& y) {
- *                    return Edge(x, y);
- *                  });
- *         })
- *     | concat
- *     | as<std::set>();
+ *   auto refs = from(ptrs) | dereference;
  */
-class Concat : public Operator<Concat> {
+class Dereference : public Operator<Dereference> {
  public:
-  Concat() = default;
+  Dereference() = default;
 
-  template<class Inner,
-           class Source,
-           class InnerValue = typename std::decay<Inner>::type::ValueType>
-  class Generator :
-      public GenImpl<InnerValue, Generator<Inner, Source, InnerValue>> {
+  template <class Value,
+            class Source,
+            class Result = decltype(*std::declval<Value>())>
+  class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
     Source source_;
+
    public:
-    explicit Generator(Source source)
-      : source_(std::move(source)) {}
+    explicit Generator(Source source) : source_(std::move(source)) {}
 
-    template<class Handler>
-    bool apply(Handler&& handler) const {
-      return source_.apply([&](Inner inner) -> bool {
-          return inner.apply(std::forward<Handler>(handler));
-        });
+    template <class Body>
+    void foreach(Body&& body) const {
+      source_.foreach([&](Value value) {
+        if (value) {
+          return body(*value);
+        }
+      });
     }
 
-    template<class Body>
-    void foreach(Body&& body) const {
-      source_.foreach([&](Inner inner) {
-          inner.foreach(std::forward<Body>(body));
-        });
+    template <class Handler>
+    bool apply(Handler&& handler) const {
+      return source_.apply([&](Value value) -> bool {
+        if (value) {
+          return handler(*value);
+        }
+        return true;
+      });
     }
 
+    // Just passes value though, length unaffected
     static constexpr bool infinite = Source::infinite;
   };
 
-  template<class Value,
-           class Source,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()));
   }
 
-  template<class Value,
-           class Source,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self());
   }
 };
 
 /**
- * RangeConcat - For flattening generators of iterables.
+ * Indirect - For producing a sequence of the addresses of the values in the
+ * input.
  *
- * This type is usually used through the 'rconcat' static value, like:
+ * This type is usually used through the 'indirect' static value, like:
  *
- *   map<int, vector<int>> adjacency;
- *   auto sinks =
- *       from(adjacency)
- *     | get<1>()
- *     | rconcat()
- *     | as<std::set>();
+ *   auto ptrs = from(refs) | indirect;
  */
-class RangeConcat : public Operator<RangeConcat> {
+class Indirect : public Operator<Indirect> {
  public:
-  RangeConcat() = default;
+  Indirect() = default;
 
-  template<class Range,
-           class Source,
-           class InnerValue = typename ValueTypeOfRange<Range>::RefType>
-  class Generator
-    : public GenImpl<InnerValue, Generator<Range, Source, InnerValue>> {
+  template <class Value,
+            class Source,
+            class Result = typename std::remove_reference<Value>::type*>
+  class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
     Source source_;
+    static_assert(!std::is_rvalue_reference<Value>::value,
+                  "Cannot use indirect on an rvalue");
+
    public:
-    explicit Generator(Source source)
-      : source_(std::move(source)) {}
+    explicit Generator(Source source) : source_(std::move(source)) {}
 
-    template<class Body>
+    template <class Body>
     void foreach(Body&& body) const {
-      source_.foreach([&](Range range) {
-          for (auto& value : range) {
-            body(value);
-          }
-        });
+      source_.foreach([&](Value value) {
+        return body(&value);
+      });
     }
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
-      return source_.apply([&](Range range) -> bool {
-          for (auto& value : range) {
-            if (!handler(value)) {
-              return false;
-            }
-          }
-          return true;
-        });
+      return source_.apply([&](Value value) -> bool {
+        return handler(&value);
+      });
     }
+
+    // Just passes value though, length unaffected
+    static constexpr bool infinite = Source::infinite;
   };
 
-  template<class Value,
-           class Source,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
     return Gen(std::move(source.self()));
   }
 
-  template<class Value,
-           class Source,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
     return Gen(source.self());
   }
 };
 
-
 /**
- * GuardImpl - For handling exceptions from downstream computation. Requires the
- * type of exception to catch, and handler function to invoke in the event of
- * the exception. Note that the handler may:
- *   1) return true to continue processing the sequence
- *   2) return false to end the sequence immediately
- *   3) throw, to pass the exception to the next catch
- * The handler must match the signature 'bool(Exception&, Value)'.
+ * Cycle - For repeating a sequence forever.
  *
- * This type is used through the `guard` helper, like so:
+ * This type is usually used through the 'cycle' static value, like:
  *
- *  auto indexes
- *    = byLine(STDIN_FILENO)
- *    | guard<std::runtime_error>([](std::runtime_error& e,
- *                                   StringPiece sp) {
- *        LOG(ERROR) << sp << ": " << e.str();
- *        return true; // continue processing subsequent lines
- *      })
- *    | eachTo<int>()
- *    | as<vector>();
+ *   auto tests
+ *     = from(samples)
+ *     | cycle
+ *     | take(100);
  *
- *  TODO(tjackson): Rename this back to Guard.
- **/
-template<class Exception,
-         class ErrorHandler>
-class GuardImpl : public Operator<GuardImpl<Exception, ErrorHandler>> {
-  ErrorHandler handler_;
+ * or in the finite case:
+ *
+ *   auto thrice = g | cycle(3);
+ */
+template <bool forever>
+class Cycle : public Operator<Cycle<forever>> {
+  off_t limit_; // not used if forever == true
  public:
-  explicit GuardImpl(ErrorHandler handler) : handler_(std::move(handler)) {}
+  Cycle() = default;
+
+  explicit Cycle(off_t limit) : limit_(limit) {
+    static_assert(
+        !forever,
+        "Cycle limit consturctor should not be used when forever == true.");
+  }
 
-  template<class Value,
-           class Source>
+  template <class Value, class Source>
   class Generator : public GenImpl<Value, Generator<Value, Source>> {
     Source source_;
-    ErrorHandler handler_;
-  public:
-    explicit Generator(Source source,
-                       ErrorHandler handler)
-      : source_(std::move(source)),
-        handler_(std::move(handler)) {}
+    off_t limit_;
+
+   public:
+    explicit Generator(Source source, off_t limit)
+        : source_(std::move(source)), limit_(limit) {}
 
-    template<class Handler>
+    template <class Handler>
     bool apply(Handler&& handler) const {
-      return source_.apply([&](Value value) -> bool {
-        try {
-          handler(std::forward<Value>(value));
-          return true;
-        } catch (Exception& e) {
-          return handler_(e, std::forward<Value>(value));
+      bool cont;
+      auto handler2 = [&](Value value) {
+        cont = handler(std::forward<Value>(value));
+        return cont;
+      };
+      // Becomes an infinte loop if forever == true
+      for (off_t count = 0; (forever || count != limit_); ++count) {
+        cont = false;
+        source_.apply(handler2);
+        if (!cont) {
+          return false;
         }
-      });
+      }
+      return true;
     }
 
-    static constexpr bool infinite = Source::infinite;
+    // This is the hardest one to infer. If we are simply doing a finite cycle,
+    // then (gen | cycle(n)) is infinite if and only if gen is infinite.
+    // However, if we are doing an infinite cycle, (gen | cycle) is infinite
+    // unless gen is empty. However, we will always mark (gen | cycle) as
+    // infinite, because patterns such as (gen | cycle | count) can either take
+    // on exactly one value, or infinite loop.
+    static constexpr bool infinite = forever || Source::infinite;
   };
 
-  template<class Value,
-           class Source,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(GenImpl<Value, Source>&& source) const {
-    return Gen(std::move(source.self()), handler_);
+    return Gen(std::move(source.self()), limit_);
   }
 
-  template<class Value,
-           class Source,
-           class Gen = Generator<Value, Source>>
+  template <class Source,
+            class Value,
+            class Gen = Generator<Value, Source>>
   Gen compose(const GenImpl<Value, Source>& source) const {
-    return Gen(source.self(), handler_);
+    return Gen(source.self(), limit_);
+  }
+
+  /**
+   * Convenience function for finite cycles used like:
+   *
+   *  auto tripled = gen | cycle(3);
+   */
+  Cycle<false> operator()(off_t limit) const { return Cycle<false>(limit); }
+};
+
+/*
+ ******************************* Sinks *****************************************
+ */
+
+/**
+ * FoldLeft - Left-associative functional fold. For producing an aggregate value
+ * from a seed and a folder function. Useful for custom aggregators on a
+ * sequence.
+ *
+ * This type is primarily used through the 'foldl' helper method, like:
+ *
+ *   double movingAverage = from(values)
+ *                        | foldl(0.0, [](double avg, double sample) {
+ *                            return sample * 0.1 + avg * 0.9;
+ *                          });
+ */
+template <class Seed, class Fold>
+class FoldLeft : public Operator<FoldLeft<Seed, Fold>> {
+  Seed seed_;
+  Fold fold_;
+
+ public:
+  FoldLeft() = default;
+  FoldLeft(Seed seed, Fold fold)
+      : seed_(std::move(seed)), fold_(std::move(fold)) {}
+
+  template <class Source, class Value>
+  Seed compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite, "Cannot foldl infinite source");
+    Seed accum = seed_;
+    source | [&](Value v) {
+      accum = fold_(std::move(accum), std::forward<Value>(v));
+    };
+    return accum;
+  }
+};
+
+/**
+ * First - For finding the first value in a sequence.
+ *
+ * This type is primarily used through the 'first' static value, like:
+ *
+ *   int firstThreeDigitPrime = seq(100) | filter(isPrime) | first;
+ */
+class First : public Operator<First> {
+ public:
+  First() = default;
+
+  template <class Source,
+            class Value,
+            class StorageType = typename std::decay<Value>::type>
+  StorageType compose(const GenImpl<Value, Source>& source) const {
+    Optional<StorageType> accum;
+    source | [&](Value v) -> bool {
+      accum = std::forward<Value>(v);
+      return false;
+    };
+    if (!accum.hasValue()) {
+      throw EmptySequence();
+    }
+    return std::move(accum.value());
+  }
+};
+
+/**
+ * IsEmpty - a helper class for isEmpty and notEmpty
+ *
+ * Essentially returns 'result' if the source is empty. Note that this cannot be
+ * called on an infinite source, because then there is only one possible return
+ * value.
+ *
+ *
+ *  Used primarily through 'isEmpty' and 'notEmpty' static values
+ *
+ *  bool hasPrimes = g | filter(prime) | notEmpty;
+ *  bool lacksEvens = g | filter(even) | isEmpty;
+ *
+ *  Also used in the implementation of 'any' and 'all'
+ */
+template <bool emptyResult>
+class IsEmpty : public Operator<IsEmpty<emptyResult>> {
+ public:
+  IsEmpty() = default;
+
+  template <class Source, class Value>
+  bool compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite,
+                  "Cannot call 'all', 'any', 'isEmpty', or 'notEmpty' on "
+                  "infinite source. 'all' and 'isEmpty' will either return "
+                  "false or hang. 'any' or 'notEmpty' will either return true "
+                  "or hang.");
+    bool ans = emptyResult;
+    source | [&](Value v) -> bool {
+      ans = !emptyResult;
+      return false;
+    };
+    return ans;
+  }
+};
+
+/**
+ * Reduce - Functional reduce, for recursively combining values from a source
+ * using a reducer function until there is only one item left. Useful for
+ * combining values when an empty sequence doesn't make sense.
+ *
+ * This type is primarily used through the 'reduce' helper method, like:
+ *
+ *   sring longest = from(names)
+ *                 | reduce([](string&& best, string& current) {
+ *                     return best.size() >= current.size() ? best : current;
+ *                   });
+ */
+template <class Reducer>
+class Reduce : public Operator<Reduce<Reducer>> {
+  Reducer reducer_;
+
+ public:
+  Reduce() = default;
+  explicit Reduce(Reducer reducer) : reducer_(std::move(reducer)) {}
+
+  template <class Source,
+            class Value,
+            class StorageType = typename std::decay<Value>::type>
+  StorageType compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite, "Cannot reduce infinite source");
+    Optional<StorageType> accum;
+    source | [&](Value v) {
+      if (accum.hasValue()) {
+        accum = reducer_(std::move(accum.value()), std::forward<Value>(v));
+      } else {
+        accum = std::forward<Value>(v);
+      }
+    };
+    if (!accum.hasValue()) {
+      throw EmptySequence();
+    }
+    return accum.value();
+  }
+};
+
+/**
+ * Count - for simply counting the items in a collection.
+ *
+ * This type is usually used through its singleton, 'count':
+ *
+ *   auto shortPrimes = seq(1, 100) | filter(isPrime) | count;
+ */
+class Count : public Operator<Count> {
+ public:
+  Count() = default;
+
+  template <class Source, class Value>
+  size_t compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite, "Cannot count infinite source");
+    return foldl(size_t(0),
+                 [](size_t accum, Value v) {
+                   return accum + 1;
+                 }).compose(source);
   }
 };
 
 /**
- * Cycle - For repeating a sequence forever.
- *
- * This type is usually used through the 'cycle' static value, like:
- *
- *   auto tests
- *     = from(samples)
- *     | cycle
- *     | take(100);
+ * Sum - For simply summing up all the values from a source.
  *
- * or in the finite case:
+ * This type is usually used through its singleton, 'sum':
  *
- *   auto thrice = g | cycle(3);
+ *   auto gaussSum = seq(1, 100) | sum;
  */
-template <bool forever>
-class Cycle : public Operator<Cycle<forever>> {
-  off_t limit_; // not used if forever == true
+class Sum : public Operator<Sum> {
  public:
-  Cycle() = default;
-
-  explicit Cycle(off_t limit)
-    : limit_(limit) {
-      static_assert(
-          !forever,
-          "Cycle limit consturctor should not be used when forever == true.");
-    }
-
-  template<class Value,
-           class Source>
-  class Generator : public GenImpl<Value, Generator<Value, Source>> {
-    Source source_;
-    off_t limit_;
-  public:
-    explicit Generator(Source source, off_t limit)
-      : source_(std::move(source))
-      , limit_(limit) {}
-
-    template<class Handler>
-    bool apply(Handler&& handler) const {
-      bool cont;
-      auto handler2 = [&](Value value) {
-        cont = handler(std::forward<Value>(value));
-        return cont;
-      };
-      // Becomes an infinte loop if forever == true
-      for (off_t count = 0; (forever || count != limit_); ++count) {
-        cont = false;
-        source_.apply(handler2);
-        if (!cont) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    // not actually infinite, since an empty generator will end the cycles.
-    static constexpr bool infinite = Source::infinite;
-  };
+  Sum() = default;
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
-  Gen compose(GenImpl<Value, Source>&& source) const {
-    return Gen(std::move(source.self()), limit_);
+  template <class Source,
+            class Value,
+            class StorageType = typename std::decay<Value>::type>
+  StorageType compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite, "Cannot sum infinite source");
+    return foldl(StorageType(0),
+                 [](StorageType&& accum, Value v) {
+                   return std::move(accum) + std::forward<Value>(v);
+                 }).compose(source);
   }
+};
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
-  Gen compose(const GenImpl<Value, Source>& source) const {
-    return Gen(source.self(), limit_);
-  }
+/**
+ * Contains - For testing whether a value matching the given value is contained
+ * in a sequence.
+ *
+ * This type should be used through the 'contains' helper method, like:
+ *
+ *   bool contained = seq(1, 10) | map(square) | contains(49);
+ */
+template <class Needle>
+class Contains : public Operator<Contains<Needle>> {
+  Needle needle_;
 
-  /**
-   * Convenience function for finite cycles used like:
-   *
-   *  auto tripled = gen | cycle(3);
-   */
-  Cycle<false> operator()(off_t limit) const {
-    return Cycle<false>(limit);
+ public:
+  explicit Contains(Needle needle) : needle_(std::move(needle)) {}
+
+  template <class Source,
+            class Value,
+            class StorageType = typename std::decay<Value>::type>
+  bool compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite,
+                  "Calling contains on an infinite source might cause "
+                  "an infinite loop.");
+    return !(source | [this](Value value) {
+      return !(needle_ == std::forward<Value>(value));
+    });
   }
 };
 
 /**
- * Dereference - For dereferencing a sequence of pointers while filtering out
- * null pointers.
+ * Min - For a value which minimizes a key, where the key is determined by a
+ * given selector, and compared by given comparer.
  *
- * This type is usually used through the 'dereference' static value, like:
+ * This type is usually used through the singletone 'min' or through the helper
+ * functions 'minBy' and 'maxBy'.
  *
- *   auto refs = from(ptrs) | dereference;
+ *   auto oldest = from(people)
+ *               | minBy([](Person& p) {
+ *                   return p.dateOfBirth;
+ *                 });
  */
-class Dereference : public Operator<Dereference> {
+template <class Selector, class Comparer>
+class Min : public Operator<Min<Selector, Comparer>> {
+  Selector selector_;
+  Comparer comparer_;
+
  public:
-  Dereference() = default;
+  Min() = default;
 
-  template<class Value,
-           class Source,
-           class Result = decltype(*std::declval<Value>())>
-  class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
-    Source source_;
-  public:
-    explicit Generator(Source source)
-      : source_(std::move(source)) {}
+  explicit Min(Selector selector) : selector_(std::move(selector)) {}
 
-    template<class Body>
-    void foreach(Body&& body) const {
-      source_.foreach([&](Value value) {
-        if (value) {
-          return body(*value);
-        }
-      });
-    }
+  Min(Selector selector, Comparer comparer)
+      : selector_(std::move(selector)), comparer_(std::move(comparer)) {}
 
-    template<class Handler>
-    bool apply(Handler&& handler) const {
-      return source_.apply([&](Value value) -> bool {
-        if (value) {
-          return handler(*value);
-        }
-        return true;
-      });
+  template <class Value,
+            class Source,
+            class StorageType = typename std::decay<Value>::type,
+            class Key = typename std::decay<
+                typename std::result_of<Selector(Value)>::type>::type>
+  StorageType compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite,
+                  "Calling min or max on an infinite source will cause "
+                  "an infinite loop.");
+    Optional<StorageType> min;
+    Optional<Key> minKey;
+    source | [&](Value v) {
+      Key key = selector_(std::forward<Value>(v));
+      if (!minKey.hasValue() || comparer_(key, minKey.value())) {
+        minKey = key;
+        min = std::forward<Value>(v);
+      }
+    };
+    if (!min.hasValue()) {
+      throw EmptySequence();
     }
+    return min.value();
+  }
+};
 
-    // not actually infinite, since an empty generator will end the cycles.
-    static constexpr bool infinite = Source::infinite;
-  };
+/**
+ * Append - For collecting values from a source into a given output container
+ * by appending.
+ *
+ * This type is usually used through the helper function 'appendTo', like:
+ *
+ *   vector<int64_t> ids;
+ *   from(results) | map([](Person& p) { return p.id })
+ *                 | appendTo(ids);
+ */
+template <class Collection>
+class Append : public Operator<Append<Collection>> {
+  Collection* collection_;
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
-  Gen compose(GenImpl<Value, Source>&& source) const {
-    return Gen(std::move(source.self()));
-  }
+ public:
+  explicit Append(Collection* collection) : collection_(collection) {}
 
-  template<class Source,
-           class Value,
-           class Gen = Generator<Value, Source>>
-  Gen compose(const GenImpl<Value, Source>& source) const {
-    return Gen(source.self());
+  template <class Value, class Source>
+  Collection& compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite, "Cannot appendTo with infinite source");
+    source | [&](Value v) {
+      collection_->insert(collection_->end(), std::forward<Value>(v));
+    };
+    return *collection_;
   }
 };
 
 /**
- * Indirect - For producing a sequence of the addresses of the values in the
- * input.
+ * Collect - For collecting values from a source in a collection of the desired
+ * type.
  *
- * This type is usually used through the 'indirect' static value, like:
+ * This type is usually used through the helper function 'as', like:
  *
- *   auto ptrs = from(refs) | indirect;
+ *   std::string upper = from(stringPiece)
+ *                     | map(&toupper)
+ *                     | as<std::string>();
  */
-class Indirect : public Operator<Indirect> {
+template <class Collection>
+class Collect : public Operator<Collect<Collection>> {
  public:
-  Indirect() = default;
+  Collect() = default;
 
   template <class Value,
             class Source,
-            class Result = typename std::remove_reference<Value>::type*>
-  class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
-    Source source_;
-    static_assert(!std::is_rvalue_reference<Value>::value,
-                  "Cannot use indirect on an rvalue");
-
-   public:
-    explicit Generator(Source source) : source_(std::move(source)) {}
-
-    template <class Body>
-    void foreach(Body&& body) const {
-      source_.foreach([&](Value value) {
-        return body(&value);
-      });
-    }
-
-    template <class Handler>
-    bool apply(Handler&& handler) const {
-      return source_.apply([&](Value value) -> bool {
-        return handler(&value);
-      });
-    }
-
-    // not actually infinite, since an empty generator will end the cycles.
-    static constexpr bool infinite = Source::infinite;
-  };
-
-  template <class Source, class Value, class Gen = Generator<Value, Source>>
-  Gen compose(GenImpl<Value, Source>&& source) const {
-    return Gen(std::move(source.self()));
+            class StorageType = typename std::decay<Value>::type>
+  Collection compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite,
+                  "Cannot convert infinite source to object with as.");
+    Collection collection;
+    source | [&](Value v) {
+      collection.insert(collection.end(), std::forward<Value>(v));
+    };
+    return collection;
   }
+};
 
-  template <class Source, class Value, class Gen = Generator<Value, Source>>
-  Gen compose(const GenImpl<Value, Source>& source) const {
-    return Gen(source.self());
+/**
+ * CollectTemplate - For collecting values from a source in a collection
+ * constructed using the specified template type. Given the type of values
+ * produced by the given generator, the collection type will be:
+ *   Container<Value, Allocator<Value>>
+ *
+ * The allocator defaults to std::allocator, so this may be used for the STL
+ * containers by simply using operators like 'as<set>', 'as<deque>',
+ * 'as<vector>'. 'as', here is the helper method which is the usual means of
+ * consturcting this operator.
+ *
+ * Example:
+ *
+ *   set<string> uniqueNames = from(names) | as<set>();
+ */
+template <template <class, class> class Container,
+          template <class> class Allocator>
+class CollectTemplate : public Operator<CollectTemplate<Container, Allocator>> {
+ public:
+  CollectTemplate() = default;
+
+  template <class Value,
+            class Source,
+            class StorageType = typename std::decay<Value>::type,
+            class Collection = Container<StorageType, Allocator<StorageType>>>
+  Collection compose(const GenImpl<Value, Source>& source) const {
+    static_assert(!Source::infinite,
+                  "Cannot convert infinite source to object with as.");
+    Collection collection;
+    source | [&](Value v) {
+      collection.insert(collection.end(), std::forward<Value>(v));
+    };
+    return collection;
   }
 };
 
@@ -2022,7 +2098,7 @@ class Indirect : public Operator<Indirect> {
 /**
  * VirtualGen<T> - For wrapping template types in simple polymorphic wrapper.
  **/
-template<class Value>
+template <class Value>
 class VirtualGen : public GenImpl<Value, VirtualGen<Value>> {
   class WrapperBase {
    public:
@@ -2032,13 +2108,12 @@ class VirtualGen : public GenImpl<Value, VirtualGen<Value>> {
     virtual std::unique_ptr<const WrapperBase> clone() const = 0;
   };
 
-  template<class Wrapped>
+  template <class Wrapped>
   class WrapperImpl : public WrapperBase {
     Wrapped wrapped_;
+
    public:
-    explicit WrapperImpl(Wrapped wrapped)
-     : wrapped_(std::move(wrapped)) {
-    }
+    explicit WrapperImpl(Wrapped wrapped) : wrapped_(std::move(wrapped)) {}
 
     virtual bool apply(const std::function<bool(Value)>& handler) const {
       return wrapped_.apply(handler);
@@ -2063,8 +2138,7 @@ class VirtualGen : public GenImpl<Value, VirtualGen<Value>> {
   VirtualGen(VirtualGen&& source) noexcept
       : wrapper_(std::move(source.wrapper_)) {}
 
-  VirtualGen(const VirtualGen& source)
-      : wrapper_(source.wrapper_->clone()) {}
+  VirtualGen(const VirtualGen& source) : wrapper_(source.wrapper_->clone()) {}
 
   VirtualGen& operator=(const VirtualGen& source) {
     wrapper_.reset(source.wrapper_->clone());
@@ -2072,7 +2146,7 @@ class VirtualGen : public GenImpl<Value, VirtualGen<Value>> {
   }
 
   VirtualGen& operator=(VirtualGen&& source) noexcept {
-    wrapper_= std::move(source.wrapper_);
+    wrapper_ = std::move(source.wrapper_);
     return *this;
   }
 
@@ -2095,12 +2169,6 @@ constexpr detail::Count count{};
 
 constexpr detail::First first{};
 
-/**
- * Use 'isEmpty' and 'notEmpty' for detecting if there are any values or not.
- *
- *  bool hasPrimes = g | filter(prime) | notEmpty;
- *  bool lacksEvens = g | filter(even) | isEmpty;
- */
 constexpr detail::IsEmpty<true> isEmpty{};
 
 constexpr detail::IsEmpty<false> notEmpty{};
@@ -2125,27 +2193,21 @@ constexpr detail::Dereference dereference{};
 
 constexpr detail::Indirect indirect{};
 
-inline detail::Take take(size_t count) {
-  return detail::Take(count);
-}
+inline detail::Take take(size_t count) { return detail::Take(count); }
 
-inline detail::Stride stride(size_t s) {
-  return detail::Stride(s);
-}
+inline detail::Stride stride(size_t s) { return detail::Stride(s); }
 
-template<class Random = std::default_random_engine>
+template <class Random = std::default_random_engine>
 inline detail::Sample<Random> sample(size_t count, Random rng = Random()) {
   return detail::Sample<Random>(count, std::move(rng));
 }
 
-inline detail::Skip skip(size_t count) {
-  return detail::Skip(count);
-}
+inline detail::Skip skip(size_t count) { return detail::Skip(count); }
 
 inline detail::Batch batch(size_t batchSize) {
   return detail::Batch(batchSize);
 }
 
-}} //folly::gen
+}} // folly::gen
 
 #pragma GCC diagnostic pop
index 33aff6b44cbddb651a421c9477e308773d648370..f260a55f8853a3aaaa1d571c88255781e326150c 100644 (file)
@@ -181,6 +181,13 @@ class GenImpl : public FBounded<Self> {
   // Child classes should override if the sequence generated is *definitely*
   // infinite. 'infinite' may be false_type for some infinite sequences
   // (due the the Halting Problem).
+  //
+  // In general, almost all sources are finite (only seq(n) produces an infinite
+  // source), almost all operators keep the finiteness of the source (only cycle
+  // makes an infinite generator from a finite one, only until and take make a
+  // finite generator from an infinite one, and concat needs both the inner and
+  // outer generators to be finite to make a finite one), and most sinks
+  // cannot accept and infinite generators (first being the expection).
   static constexpr bool infinite = false;
 };
 
index 6973def211a12d9156723e6bb2e3c04c0bc1f933..06acd00dc37e82fe958ae4f0e668d088c856c304 100644 (file)
@@ -577,6 +577,37 @@ TEST(Gen, DistinctMove) {   //  0  1  4  9  6  5  6  9  4  1  0
   EXPECT_EQ(expected, actual);
 }
 
+TEST(Gen, DistinctInfinite) {
+  // distinct should be able to handle an infinite sequence, provided that, of
+  // of cource, is it eventually made finite before returning the result.
+  auto expected = seq(0) | take(5) | as<vector>(); // 0 1 2 3 4
+
+  auto actual =
+      seq(0)                              // 0 1 2 3 4 5 6 7 ...
+    | mapped([](int i) { return i / 2; }) // 0 0 1 1 2 2 3 3 ...
+    | distinct                            // 0 1 2 3 4 5 6 7 ...
+    | take(5)                             // 0 1 2 3 4
+    | as<vector>();
+
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(Gen, DistinctByInfinite) {
+  // Similarly to the DistinctInfinite test case, distinct by should be able to
+  // handle infinite sequences. Note that depending on how many values we take()
+  // at the end, the sequence may infinite loop. This is fine becasue we cannot
+  // solve the halting problem.
+  auto expected = vector<int>{1, 2};
+  auto actual =
+      seq(1)                                    // 1 2 3 4 5 6 7 8 ...
+    | distinctBy([](int i) { return i % 2; })   // 1 2 (but might by infinite)
+    | take(2)                                   // 1 2
+    | as<vector>();
+  // Note that if we had take(3), this would infinite loop
+
+  EXPECT_EQ(expected, actual);
+}
+
 TEST(Gen, MinBy) {
   EXPECT_EQ(7, seq(1, 10)
              | minBy([](int i) -> double {
@@ -743,21 +774,17 @@ TEST(Gen, Get) {
 }
 
 TEST(Gen, notEmpty) {
-  EXPECT_TRUE(seq(0) | notEmpty);
   EXPECT_TRUE(seq(0, 1) | notEmpty);
   EXPECT_TRUE(just(1) | notEmpty);
   EXPECT_FALSE(gen::range(0, 0) | notEmpty);
   EXPECT_FALSE(from({1}) | take(0) | notEmpty);
-  EXPECT_TRUE(seq(1, 3) | cycle | notEmpty);
 }
 
 TEST(Gen, isEmpty) {
-  EXPECT_FALSE(seq(0) | isEmpty);
   EXPECT_FALSE(seq(0, 1) | isEmpty);
   EXPECT_FALSE(just(1) | isEmpty);
   EXPECT_TRUE(gen::range(0, 0) | isEmpty);
   EXPECT_TRUE(from({1}) | take(0) | isEmpty);
-  EXPECT_FALSE(seq(1, 3) | cycle | isEmpty);
 }
 
 TEST(Gen, Any) {
@@ -1018,7 +1045,8 @@ TEST(Gen, Cycle) {
     };
     auto s = countdown;
     EXPECT_EQ((vector<int> { 1, 2, 3, 1, 2, 1}),
-              s | cycle | as<vector>());
+              s | cycle | take(7) | as<vector>());
+    // take necessary as cycle returns an infinite generator
   }
 }