Handle take(-1) better
[folly.git] / folly / gen / Base.h
index bbae117a505ddb822d442e4cfb96e079b90a96b7..6e661f16183d4019b38d6056b4dbb54c055859ae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2015 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #ifndef FOLLY_GEN_BASE_H
 #define FOLLY_GEN_BASE_H
 
+#include <algorithm>
 #include <functional>
 #include <memory>
+#include <random>
 #include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
 #include <utility>
-#include <algorithm>
-#include <random>
 #include <vector>
-#include <unordered_set>
 
-#include <folly/Range.h>
-#include <folly/Optional.h>
 #include <folly/Conv.h>
+#include <folly/Optional.h>
+#include <folly/Range.h>
 #include <folly/gen/Core.h>
 
 /**
 
 namespace folly { namespace gen {
 
-class EmptySequence : public std::exception {
-public:
-  virtual const char* what() const noexcept {
-    return "This operation cannot be called on an empty sequence";
-  }
-};
-
 class Less {
 public:
   template<class First,
@@ -214,6 +208,30 @@ public:
   }
 };
 
+/**
+ * Class and helper function for negating a boolean Predicate
+ */
+template <class Predicate>
+class Negate {
+  Predicate pred_;
+
+ public:
+  Negate() = default;
+
+  explicit Negate(Predicate pred)
+    : pred_(std::move(pred))
+  {}
+
+  template <class Arg>
+  bool operator()(Arg&& arg) const {
+    return !pred_(std::forward<Arg>(arg));
+  }
+};
+template <class Predicate>
+Negate<Predicate> negate(Predicate pred) {
+  return Negate<Predicate>(std::move(pred));
+}
+
 template <class Dest>
 class Cast {
  public:
@@ -241,6 +259,9 @@ class To<StringPiece> {
   }
 };
 
+template<class Key, class Value>
+class Group;
+
 namespace detail {
 
 template<class Self>
@@ -297,7 +318,10 @@ template<class Value>
 class Empty;
 
 template<class Value>
-class Just;
+class SingleReference;
+
+template<class Value>
+class SingleCopy;
 
 /*
  * Operators
@@ -323,6 +347,9 @@ class Skip;
 template<class Selector, class Comparer = Less>
 class Order;
 
+template<class Selector>
+class GroupBy;
+
 template<class Selector>
 class Distinct;
 
@@ -336,12 +363,15 @@ class Concat;
 
 class RangeConcat;
 
+template <bool forever>
 class Cycle;
 
 class Batch;
 
 class Dereference;
 
+class Indirect;
+
 /*
  * Sinks
  */
@@ -351,10 +381,8 @@ class FoldLeft;
 
 class First;
 
-class Any;
-
-template<class Predicate>
-class All;
+template <bool result>
+class IsEmpty;
 
 template<class Reducer>
 class Reduce;
@@ -385,6 +413,11 @@ template<class Exception,
          class ErrorHandler>
 class GuardImpl;
 
+template <class T>
+class UnwrapOr;
+
+class Unwrap;
+
 }
 
 /**
@@ -480,14 +513,19 @@ Yield generator(Source&& source) {
 /*
  * empty() - for producing empty sequences.
  */
-template<class Value>
+template <class Value>
 detail::Empty<Value> empty() {
   return {};
 }
 
-template<class Value>
-detail::Just<Value> just(Value value) {
-  return detail::Just<Value>(std::move(value));
+template <
+    class Value,
+    class Just = typename std::conditional<
+        std::is_reference<Value>::value,
+        detail::SingleReference<typename std::remove_reference<Value>::type>,
+        detail::SingleCopy<Value>>::type>
+Just just(Value&& value) {
+  return Just(std::forward<Value>(value));
 }
 
 /*
@@ -597,42 +635,42 @@ Map field(FieldType Class::*field) {
   return Map(Field(field));
 }
 
-template<class Predicate,
-         class Filter = detail::Filter<Predicate>>
+template <class Predicate = Identity,
+          class Filter = detail::Filter<Predicate>>
 Filter filter(Predicate pred = Predicate()) {
   return Filter(std::move(pred));
 }
 
-template<class Predicate,
-         class All = detail::All<Predicate>>
-All all(Predicate pred = Predicate()) {
-  return All(std::move(pred));
-}
-
 template<class Predicate,
          class Until = detail::Until<Predicate>>
 Until until(Predicate pred = Predicate()) {
   return Until(std::move(pred));
 }
 
-template<class Selector,
+template<class Selector = Identity,
          class Comparer = Less,
          class Order = detail::Order<Selector, Comparer>>
-Order orderBy(Selector selector = Identity(),
+Order orderBy(Selector selector = Selector(),
               Comparer comparer = Comparer()) {
   return Order(std::move(selector),
                std::move(comparer));
 }
 
-template<class Selector,
+template<class Selector = Identity,
          class Order = detail::Order<Selector, Greater>>
-Order orderByDescending(Selector selector = Identity()) {
+Order orderByDescending(Selector selector = Selector()) {
   return Order(std::move(selector));
 }
 
-template<class Selector,
+template <class Selector = Identity,
+          class GroupBy = detail::GroupBy<Selector>>
+GroupBy groupBy(Selector selector = Selector()) {
+  return GroupBy(std::move(selector));
+}
+
+template<class Selector = Identity,
          class Distinct = detail::Distinct<Selector>>
-Distinct distinctBy(Selector selector = Identity()) {
+Distinct distinctBy(Selector selector = Selector()) {
   return Distinct(std::move(selector));
 }
 
@@ -664,6 +702,63 @@ detail::TypeAssertion<Value> assert_type() {
 /*
  * Sink Factories
  */
+
+/**
+ * any() - For determining if any value in a sequence satisfies a predicate.
+ *
+ * The following is an example for checking if any computer is broken:
+ *
+ *   bool schrepIsMad = from(computers) | any(isBroken);
+ *
+ * (because everyone knows Schrep hates broken computers).
+ *
+ * Note that if no predicate is provided, 'any()' checks if any of the values
+ * are true when cased to bool. To check if any of the scores are nonZero:
+ *
+ *   bool somebodyScored = from(scores) | any();
+ *
+ * Note: Passing an empty sequence through 'any()' will always return false. In
+ * fact, 'any()' is equivilent to the composition of 'filter()' and 'notEmpty'.
+ *
+ *   from(source) | any(pred) == from(source) | filter(pred) | notEmpty
+ */
+
+template <class Predicate = Identity,
+          class Filter = detail::Filter<Predicate>,
+          class NotEmpty = detail::IsEmpty<false>,
+          class Composed = detail::Composed<Filter, NotEmpty>>
+Composed any(Predicate pred = Predicate()) {
+  return Composed(Filter(std::move(pred)), NotEmpty());
+}
+
+/**
+ * all() - For determining whether all values in a sequence satisfy a predicate.
+ *
+ * The following is an example for checking if all members of a team are cool:
+ *
+ *   bool isAwesomeTeam = from(team) | all(isCool);
+ *
+ * Note that if no predicate is provided, 'all()'' checks if all of the values
+ * are true when cased to bool.
+ * The following makes sure none of 'pointers' are nullptr:
+ *
+ *   bool allNonNull = from(pointers) | all();
+ *
+ * Note: Passing an empty sequence through 'all()' will always return true. In
+ * fact, 'all()' is equivilent to the composition of 'filter()' with the
+ * reversed predicate and 'isEmpty'.
+ *
+ *   from(source) | all(pred) == from(source) | filter(negate(pred)) | isEmpty
+ */
+
+template <class Predicate = Identity,
+          class Filter = detail::Filter<Negate<Predicate>>,
+          class IsEmpty = detail::IsEmpty<true>,
+          class Composed = detail::Composed<Filter, IsEmpty>>
+Composed all(Predicate pred = Predicate()) {
+  return Composed(Filter(std::move(negate(pred))), IsEmpty());
+}
+
 template<class Seed,
          class Fold,
          class FoldLeft = detail::FoldLeft<Seed, Fold>>
@@ -726,6 +821,12 @@ GuardImpl guard(ErrorHandler&& handler) {
   return GuardImpl(std::forward<ErrorHandler>(handler));
 }
 
+template<class Fallback,
+         class UnwrapOr = detail::UnwrapOr<typename std::decay<Fallback>::type>>
+UnwrapOr unwrapOr(Fallback&& fallback) {
+  return UnwrapOr(std::forward<Fallback>(fallback));
+}
+
 }} // folly::gen
 
 #include <folly/gen/Base-inl.h>