Add Optional::value_type
[folly.git] / folly / gen / Base.h
index 06cc0e3c89e1f786e9987a67b17e8f1b6d25b3a7..38fba4f79c72207426feb01ea40799ce2af5f732 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/gen/Core.h"
+#include <folly/Conv.h>
+#include <folly/Optional.h>
+#include <folly/Range.h>
+#include <folly/gen/Core.h>
 
 /**
  * Generator-based Sequence Comprehensions in C++, akin to C#'s LINQ
 
 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,
@@ -136,6 +130,10 @@ class MemberFunction {
   Result operator()(Class& x) const {
     return (x.*member_)();
   }
+
+  Result operator()(Class* x) const {
+    return (x->*member_)();
+  }
 };
 
 template<class Class,
@@ -153,6 +151,10 @@ class ConstMemberFunction{
   Result operator()(const Class& x) const {
     return (x.*member_)();
   }
+
+  Result operator()(const Class* x) const {
+    return (x->*member_)();
+  }
 };
 
 template<class Class,
@@ -171,10 +173,18 @@ class Field {
     return x.*field_;
   }
 
+  const FieldType& operator()(const Class* x) const {
+    return x->*field_;
+  }
+
   FieldType& operator()(Class& x) const {
     return x.*field_;
   }
 
+  FieldType& operator()(Class* x) const {
+    return x->*field_;
+  }
+
   FieldType&& operator()(Class&& x) const {
     return std::move(x.*field_);
   }
@@ -198,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:
@@ -225,6 +259,9 @@ class To<StringPiece> {
   }
 };
 
+template<class Key, class Value>
+class Group;
+
 namespace detail {
 
 template<class Self>
@@ -235,13 +272,9 @@ struct FBounded;
  */
 template<class Container>
 struct ValueTypeOfRange {
- private:
-  static Container container_;
  public:
-  typedef decltype(*std::begin(container_))
-    RefType;
-  typedef typename std::decay<decltype(*std::begin(container_))>::type
-    StorageType;
+  using RefType = decltype(*std::begin(std::declval<Container&>()));
+  using StorageType = typename std::decay<RefType>::type;
 };
 
 
@@ -256,9 +289,24 @@ template<class Value,
          class Container = std::vector<typename std::decay<Value>::type>>
 class CopiedSource;
 
-template<class Value, bool endless = false, bool endInclusive = false>
+template<class Value, class SequenceImpl>
 class Sequence;
 
+template <class Value>
+class RangeImpl;
+
+template <class Value, class Distance>
+class RangeWithStepImpl;
+
+template <class Value>
+class SeqImpl;
+
+template <class Value, class Distance>
+class SeqWithStepImpl;
+
+template <class Value>
+class InfiniteImpl;
+
 template<class Value, class Source>
 class Yield;
 
@@ -266,7 +314,10 @@ template<class Value>
 class Empty;
 
 template<class Value>
-class Just;
+class SingleReference;
+
+template<class Value>
+class SingleCopy;
 
 /*
  * Operators
@@ -282,6 +333,8 @@ class Until;
 
 class Take;
 
+class Stride;
+
 template<class Rand>
 class Sample;
 
@@ -290,6 +343,9 @@ class Skip;
 template<class Selector, class Comparer = Less>
 class Order;
 
+template<class Selector>
+class GroupBy;
+
 template<class Selector>
 class Distinct;
 
@@ -303,12 +359,15 @@ class Concat;
 
 class RangeConcat;
 
+template <bool forever>
 class Cycle;
 
 class Batch;
 
 class Dereference;
 
+class Indirect;
+
 /*
  * Sinks
  */
@@ -318,10 +377,8 @@ class FoldLeft;
 
 class First;
 
-class Any;
-
-template<class Predicate>
-class All;
+template <bool result>
+class IsEmpty;
 
 template<class Reducer>
 class Reduce;
@@ -352,6 +409,11 @@ template<class Exception,
          class ErrorHandler>
 class GuardImpl;
 
+template <class T>
+class UnwrapOr;
+
+class Unwrap;
+
 }
 
 /**
@@ -396,21 +458,36 @@ From from(Container&& source) {
   return From(std::move(source));
 }
 
-template<class Value, class Gen = detail::Sequence<Value, false, false>>
+template<class Value, class Impl = detail::RangeImpl<Value>,
+         class Gen = detail::Sequence<Value, Impl>>
 Gen range(Value begin, Value end) {
-  return Gen(begin, end);
+  return Gen{std::move(begin), Impl{std::move(end)}};
 }
 
-template<class Value,
-         class Gen = detail::Sequence<Value, false, true>>
+template<class Value, class Distance,
+         class Impl = detail::RangeWithStepImpl<Value, Distance>,
+         class Gen = detail::Sequence<Value, Impl>>
+Gen range(Value begin, Value end, Distance step) {
+  return Gen{std::move(begin), Impl{std::move(end), std::move(step)}};
+}
+
+template<class Value, class Impl = detail::SeqImpl<Value>,
+         class Gen = detail::Sequence<Value, Impl>>
 Gen seq(Value first, Value last) {
-  return Gen(first, last);
+  return Gen{std::move(first), Impl{std::move(last)}};
 }
 
-template<class Value,
-         class Gen = detail::Sequence<Value, true>>
-Gen seq(Value begin) {
-  return Gen(begin);
+template<class Value, class Distance,
+         class Impl = detail::SeqWithStepImpl<Value, Distance>,
+         class Gen = detail::Sequence<Value, Impl>>
+Gen seq(Value first, Value last, Distance step) {
+  return Gen{std::move(first), Impl{std::move(last), std::move(step)}};
+}
+
+template<class Value, class Impl = detail::InfiniteImpl<Value>,
+         class Gen = detail::Sequence<Value, Impl>>
+Gen seq(Value first) {
+  return Gen{std::move(first), Impl{}};
 }
 
 template<class Value,
@@ -432,14 +509,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));
 }
 
 /*
@@ -489,12 +571,29 @@ enum MemberType {
   Mutable
 };
 
+/**
+ * These exist because MSVC has problems with expression SFINAE in templates
+ * assignment and comparisons don't work properly without being pulled out
+ * of the template declaration
+ */
+template <MemberType Constness> struct ExprIsConst {
+  enum {
+    value = Constness == Const
+  };
+};
+
+template <MemberType Constness> struct ExprIsMutable {
+  enum {
+    value = Constness == Mutable
+  };
+};
+
 template<MemberType Constness = Const,
          class Class,
          class Return,
          class Mem = ConstMemberFunction<Class, Return>,
          class Map = detail::Map<Mem>>
-typename std::enable_if<Constness == Const, Map>::type
+typename std::enable_if<ExprIsConst<Constness>::value, Map>::type
 member(Return (Class::*member)() const) {
   return Map(Mem(member));
 }
@@ -504,7 +603,7 @@ template<MemberType Constness = Mutable,
          class Return,
          class Mem = MemberFunction<Class, Return>,
          class Map = detail::Map<Mem>>
-typename std::enable_if<Constness == Mutable, Map>::type
+typename std::enable_if<ExprIsMutable<Constness>::value, Map>::type
 member(Return (Class::*member)()) {
   return Map(Mem(member));
 }
@@ -532,42 +631,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));
 }
 
@@ -599,6 +698,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>>
@@ -661,8 +817,14 @@ 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"
+#include <folly/gen/Base-inl.h>
 
 #endif // FOLLY_GEN_BASE_H