/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#ifndef FOLLY_GEN_BASE_H
-#define FOLLY_GEN_BASE_H
+#pragma once
+#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/Utility.h>
#include <folly/gen/Core.h>
/**
*
* To learn more about this library, including the use of infinite generators,
* see the examples in the comments, or the docs (coming soon).
-*/
-
-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";
- }
-};
+namespace folly {
+namespace gen {
class Less {
-public:
- template<class First,
- class Second>
+ public:
+ template <class First, class Second>
auto operator()(const First& first, const Second& second) const ->
decltype(first < second) {
return first < second;
};
class Greater {
-public:
- template<class First,
- class Second>
+ public:
+ template <class First, class Second>
auto operator()(const First& first, const Second& second) const ->
decltype(first > second) {
return first > second;
}
};
-template<int n>
+template <int n>
class Get {
-public:
- template<class Value>
+ public:
+ template <class Value>
auto operator()(Value&& value) const ->
decltype(std::get<n>(std::forward<Value>(value))) {
return std::get<n>(std::forward<Value>(value));
}
};
-template<class Class,
- class Result>
+template <class Class, class Result>
class MemberFunction {
public:
typedef Result (Class::*MemberPtr)();
}
};
-template<class Class,
- class Result>
+template <class Class, class Result>
class ConstMemberFunction{
public:
typedef Result (Class::*MemberPtr)() const;
}
};
-template<class Class,
- class FieldType>
+template <class Class, class FieldType>
class Field {
public:
typedef FieldType (Class::*FieldPtr);
};
class Move {
-public:
- template<class Value>
+ public:
+ template <class Value>
auto operator()(Value&& value) const ->
decltype(std::move(std::forward<Value>(value))) {
return std::move(std::forward<Value>(value));
}
};
-class Identity {
-public:
- template<class Value>
- auto operator()(Value&& value) const ->
- decltype(std::forward<Value>(value)) {
- return std::forward<Value>(value);
+/**
+ * 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 {
}
};
+template <class Key, class Value>
+class Group;
+
namespace detail {
-template<class Self>
+template <class Self>
struct FBounded;
/*
* Type Traits
*/
-template<class Container>
+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;
};
/*
* Sources
*/
-template<class Container,
- class Value = typename ValueTypeOfRange<Container>::RefType>
+template <
+ class Container,
+ class Value = typename ValueTypeOfRange<Container>::RefType>
class ReferencedSource;
-template<class Value,
- class Container = std::vector<typename std::decay<Value>::type>>
+template <
+ class Value,
+ class Container = std::vector<typename std::decay<Value>::type>>
class CopiedSource;
-template<class Value, class SequenceImpl>
+template <class Value, class SequenceImpl>
class Sequence;
template <class Value>
template <class Value>
class InfiniteImpl;
-template<class Value, class Source>
+template <class Value, class Source>
class Yield;
-template<class Value>
+template <class Value>
class Empty;
-template<class Value>
+template <class Value>
class SingleReference;
-template<class Value>
+template <class Value>
class SingleCopy;
/*
* Operators
*/
-template<class Predicate>
+template <class Predicate>
class Map;
-template<class Predicate>
+template <class Predicate>
class Filter;
-template<class Predicate>
+template <class Predicate>
class Until;
class Take;
class Stride;
-template<class Rand>
+template <class Rand>
class Sample;
class Skip;
-template<class Selector, class Comparer = Less>
+template <class Visitor>
+class Visit;
+
+template <class Selector, class Comparer = Less>
class Order;
-template<class Selector>
+template <class Selector>
+class GroupBy;
+
+template <class Selector>
class Distinct;
-template<class Operators>
+template <class Operators>
class Composer;
-template<class Expected>
+template <class Expected>
class TypeAssertion;
class Concat;
class RangeConcat;
+template <bool forever>
class Cycle;
class Batch;
+class Window;
+
class Dereference;
class Indirect;
/*
* Sinks
*/
-template<class Seed,
- class Fold>
+template <class Seed, class Fold>
class FoldLeft;
class First;
-class Any;
-
-template<class Predicate>
-class All;
+template <bool result>
+class IsEmpty;
-template<class Reducer>
+template <class Reducer>
class Reduce;
class Sum;
-template<class Selector,
- class Comparer>
+template <class Selector, class Comparer>
class Min;
-template<class Container>
+template <class Container>
class Collect;
-template<template<class, class> class Collection = std::vector,
- template<class> class Allocator = std::allocator>
+template <
+ template <class, class> class Collection = std::vector,
+ template <class> class Allocator = std::allocator>
class CollectTemplate;
-template<class Collection>
+template <class Collection>
class Append;
-template<class Value>
+template <class Value>
struct GeneratorBuilder;
-template<class Needle>
+template <class Needle>
class Contains;
-template<class Exception,
- class ErrorHandler>
+template <class Exception, class ErrorHandler>
class GuardImpl;
-}
+template <class T>
+class UnwrapOr;
+
+class Unwrap;
+
+} // namespace detail
/**
* Polymorphic wrapper
**/
-template<class Value>
+template <class Value>
class VirtualGen;
/*
* Source Factories
*/
-template<class Container,
- class From = detail::ReferencedSource<const Container>>
+template <
+ class Container,
+ class From = detail::ReferencedSource<const Container>>
From fromConst(const Container& source) {
return From(&source);
}
-template<class Container,
- class From = detail::ReferencedSource<Container>>
+template <class Container, class From = detail::ReferencedSource<Container>>
From from(Container& source) {
return From(&source);
}
-template<class Container,
- class Value =
- typename detail::ValueTypeOfRange<Container>::StorageType,
- class CopyOf = detail::CopiedSource<Value>>
+template <
+ class Container,
+ class Value = typename detail::ValueTypeOfRange<Container>::StorageType,
+ class CopyOf = detail::CopiedSource<Value>>
CopyOf fromCopy(Container&& source) {
return CopyOf(std::forward<Container>(source));
}
-template<class Value,
- class From = detail::CopiedSource<Value>>
+template <class Value, class From = detail::CopiedSource<Value>>
From from(std::initializer_list<Value> source) {
return From(source);
}
-template<class Container,
- class From = detail::CopiedSource<typename Container::value_type,
- Container>>
+template <
+ class Container,
+ class From =
+ detail::CopiedSource<typename Container::value_type, Container>>
From from(Container&& source) {
return From(std::move(source));
}
-template<class Value, class Impl = detail::RangeImpl<Value>,
- class Gen = detail::Sequence<Value, Impl>>
+template <
+ class Value,
+ class Impl = detail::RangeImpl<Value>,
+ class Gen = detail::Sequence<Value, Impl>>
Gen range(Value begin, Value end) {
return Gen{std::move(begin), Impl{std::move(end)}};
}
-template<class Value, class Distance,
- class Impl = detail::RangeWithStepImpl<Value, Distance>,
- class Gen = detail::Sequence<Value, Impl>>
+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>>
+template <
+ class Value,
+ class Impl = detail::SeqImpl<Value>,
+ class Gen = detail::Sequence<Value, Impl>>
Gen seq(Value first, Value last) {
return Gen{std::move(first), Impl{std::move(last)}};
}
-template<class Value, class Distance,
- class Impl = detail::SeqWithStepImpl<Value, Distance>,
- class Gen = detail::Sequence<Value, Impl>>
+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>>
+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,
- class Source,
- class Yield = detail::Yield<Value, Source>>
+template <class Value, class Source, class Yield = detail::Yield<Value, Source>>
Yield generator(Source&& source) {
return Yield(std::forward<Source>(source));
}
*
* auto gen = GENERATOR(int) { yield(1); yield(2); };
*/
-#define GENERATOR(TYPE) \
- ::folly::gen::detail::GeneratorBuilder<TYPE>() + \
- [=](const std::function<void(TYPE)>& yield)
+#define GENERATOR(TYPE) \
+ ::folly::gen::detail::GeneratorBuilder<TYPE>() + [=](auto&& yield)
/*
* empty() - for producing empty sequences.
/*
* Operator Factories
*/
-template<class Predicate,
- class Map = detail::Map<Predicate>>
+template <class Predicate, class Map = detail::Map<Predicate>>
Map mapped(Predicate pred = Predicate()) {
return Map(std::move(pred));
}
-template<class Predicate,
- class Map = detail::Map<Predicate>>
+template <class Predicate, class Map = detail::Map<Predicate>>
Map map(Predicate pred = Predicate()) {
return Map(std::move(pred));
}
* | mapOp(filter(sampleTest) | count)
* | sum;
*/
-template<class Operator,
- class Map = detail::Map<detail::Composer<Operator>>>
+template <class Operator, class Map = detail::Map<detail::Composer<Operator>>>
Map mapOp(Operator op) {
return Map(detail::Composer<Operator>(std::move(op)));
}
* assignment and comparisons don't work properly without being pulled out
* of the template declaration
*/
-template <MemberType Constness> struct ExprIsConst {
+template <MemberType Constness>
+struct ExprIsConst {
enum {
value = Constness == Const
};
};
-template <MemberType Constness> struct ExprIsMutable {
+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>>
+template <
+ MemberType Constness = Const,
+ class Class,
+ class Return,
+ class Mem = ConstMemberFunction<Class, Return>,
+ class Map = detail::Map<Mem>>
typename std::enable_if<ExprIsConst<Constness>::value, Map>::type
member(Return (Class::*member)() const) {
return Map(Mem(member));
}
-template<MemberType Constness = Mutable,
- class Class,
- class Return,
- class Mem = MemberFunction<Class, Return>,
- class Map = detail::Map<Mem>>
+template <
+ MemberType Constness = Mutable,
+ class Class,
+ class Return,
+ class Mem = MemberFunction<Class, Return>,
+ class Map = detail::Map<Mem>>
typename std::enable_if<ExprIsMutable<Constness>::value, Map>::type
member(Return (Class::*member)()) {
return Map(Mem(member));
* | field(&Item::name)
* | as<vector>();
*/
-template<class Class,
- class FieldType,
- class Field = Field<Class, FieldType>,
- class Map = detail::Map<Field>>
+template <
+ class Class,
+ class FieldType,
+ class Field = Field<Class, FieldType>,
+ class Map = detail::Map<Field>>
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 Visitor = Ignore, class Visit = detail::Visit<Visitor>>
+Visit visit(Visitor visitor = Visitor()) {
+ return Visit(std::move(visitor));
}
-template<class Predicate,
- class Until = detail::Until<Predicate>>
+template <class Predicate, class Until = detail::Until<Predicate>>
Until until(Predicate pred = Predicate()) {
return Until(std::move(pred));
}
-template<class Selector,
- class Comparer = Less,
- class Order = detail::Order<Selector, Comparer>>
-Order orderBy(Selector selector = Identity(),
+template <
+ class Selector = Identity,
+ class Comparer = Less,
+ class Order = detail::Order<Selector, Comparer>>
+Order orderBy(Selector selector = Selector(),
Comparer comparer = Comparer()) {
return Order(std::move(selector),
std::move(comparer));
}
-template<class Selector,
- class Order = detail::Order<Selector, Greater>>
-Order orderByDescending(Selector selector = Identity()) {
+template <
+ class Selector = Identity,
+ class Order = detail::Order<Selector, Greater>>
+Order orderByDescending(Selector selector = Selector()) {
return Order(std::move(selector));
}
-template<class Selector,
- class Distinct = detail::Distinct<Selector>>
-Distinct distinctBy(Selector selector = Identity()) {
+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 = Selector()) {
return Distinct(std::move(selector));
}
-template<int n,
- class Get = detail::Map<Get<n>>>
+template <int n, class Get = detail::Map<Get<n>>>
Get get() {
return Get();
}
// construct Dest from each value
-template <class Dest,
- class Cast = detail::Map<Cast<Dest>>>
+template <class Dest, class Cast = detail::Map<Cast<Dest>>>
Cast eachAs() {
return Cast();
}
// call folly::to on each value
-template <class Dest,
- class To = detail::Map<To<Dest>>>
+template <class Dest, class To = detail::Map<To<Dest>>>
To eachTo() {
return To();
}
-template<class Value>
+template <class Value>
detail::TypeAssertion<Value> assert_type() {
return {};
}
/*
* Sink Factories
*/
-template<class Seed,
- class Fold,
- class FoldLeft = detail::FoldLeft<Seed, Fold>>
+
+/**
+ * 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>>
FoldLeft foldl(Seed seed = Seed(),
Fold fold = Fold()) {
return FoldLeft(std::move(seed),
std::move(fold));
}
-template<class Reducer,
- class Reduce = detail::Reduce<Reducer>>
+template <class Reducer, class Reduce = detail::Reduce<Reducer>>
Reduce reduce(Reducer reducer = Reducer()) {
return Reduce(std::move(reducer));
}
-template<class Selector = Identity,
- class Min = detail::Min<Selector, Less>>
+template <class Selector = Identity, class Min = detail::Min<Selector, Less>>
Min minBy(Selector selector = Selector()) {
return Min(std::move(selector));
}
-template<class Selector,
- class MaxBy = detail::Min<Selector, Greater>>
+template <class Selector, class MaxBy = detail::Min<Selector, Greater>>
MaxBy maxBy(Selector selector = Selector()) {
return MaxBy(std::move(selector));
}
-template<class Collection,
- class Collect = detail::Collect<Collection>>
+template <class Collection, class Collect = detail::Collect<Collection>>
Collect as() {
return Collect();
}
-template<template<class, class> class Container = std::vector,
- template<class> class Allocator = std::allocator,
- class Collect = detail::CollectTemplate<Container, Allocator>>
+template <
+ template <class, class> class Container = std::vector,
+ template <class> class Allocator = std::allocator,
+ class Collect = detail::CollectTemplate<Container, Allocator>>
Collect as() {
return Collect();
}
-template<class Collection,
- class Append = detail::Append<Collection>>
+template <class Collection, class Append = detail::Append<Collection>>
Append appendTo(Collection& collection) {
return Append(&collection);
}
-template<class Needle,
- class Contains = detail::Contains<typename std::decay<Needle>::type>>
+template <
+ class Needle,
+ class Contains = detail::Contains<typename std::decay<Needle>::type>>
Contains contains(Needle&& needle) {
return Contains(std::forward<Needle>(needle));
}
-template<class Exception,
- class ErrorHandler,
- class GuardImpl =
- detail::GuardImpl<
- Exception,
- typename std::decay<ErrorHandler>::type>>
+template <
+ class Exception,
+ class ErrorHandler,
+ class GuardImpl =
+ detail::GuardImpl<Exception, typename std::decay<ErrorHandler>::type>>
GuardImpl guard(ErrorHandler&& handler) {
return GuardImpl(std::forward<ErrorHandler>(handler));
}
-}} // folly::gen
+template <
+ class Fallback,
+ class UnwrapOr = detail::UnwrapOr<typename std::decay<Fallback>::type>>
+UnwrapOr unwrapOr(Fallback&& fallback) {
+ return UnwrapOr(std::forward<Fallback>(fallback));
+}
+
+} // namespace gen
+} // namespace folly
#include <folly/gen/Base-inl.h>
-
-#endif // FOLLY_GEN_BASE_H