/*
- * 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,
Result operator()(Class& x) const {
return (x.*member_)();
}
+
+ Result operator()(Class* x) const {
+ return (x->*member_)();
+ }
};
template<class Class,
Result operator()(const Class& x) const {
return (x.*member_)();
}
+
+ Result operator()(const Class* x) const {
+ return (x->*member_)();
+ }
};
template<class Class,
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_);
}
}
};
+/**
+ * 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:
}
};
+template<class Key, class Value>
+class Group;
+
namespace detail {
template<class Self>
*/
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;
};
class Empty;
template<class Value>
-class Just;
+class SingleReference;
+
+template<class Value>
+class SingleCopy;
/*
* Operators
class Take;
+class Stride;
+
template<class Rand>
class Sample;
template<class Selector, class Comparer = Less>
class Order;
+template<class Selector>
+class GroupBy;
+
template<class Selector>
class Distinct;
class RangeConcat;
+template <bool forever>
class Cycle;
class Batch;
class Dereference;
+class Indirect;
+
/*
* Sinks
*/
class First;
-class Any;
-
-template<class Predicate>
-class All;
+template <bool result>
+class IsEmpty;
template<class Reducer>
class Reduce;
class ErrorHandler>
class GuardImpl;
+template <class T>
+class UnwrapOr;
+
+class Unwrap;
+
}
/**
/*
* 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));
}
/*
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));
}
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));
}
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));
}
/*
* 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>>
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