/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #define FOLLY_GEN_BASE_H_ #include #include #include #include #include #include #include #include #include #include #include #include /** * Generator-based Sequence Comprehensions in C++, akin to C#'s LINQ * @author Tom Jackson * * This library makes it possible to write declarative comprehensions for * processing sequences of values efficiently in C++. The operators should be * familiar to those with experience in functional programming, and the * performance will be virtually identical to the equivalent, boilerplate C++ * implementations. * * Generator objects may be created from either an stl-like container (anything * supporting begin() and end()), from sequences of values, or from another * generator (see below). To create a generator that pulls values from a vector, * for example, one could write: * * vector names { "Jack", "Jill", "Sara", "Tom" }; * auto gen = from(names); * * Generators are composed by building new generators out of old ones through * the use of operators. These are reminiscent of shell pipelines, and afford * similar composition. Lambda functions are used liberally to describe how to * handle individual values: * * auto lengths = gen * | mapped([](const fbstring& name) { return name.size(); }); * * Generators are lazy; they don't actually perform any work until they need to. * As an example, the 'lengths' generator (above) won't actually invoke the * provided lambda until values are needed: * * auto lengthVector = lengths | as(); * auto totalLength = lengths | sum; * * 'auto' is useful in here because the actual types of the generators objects * are usually complicated and implementation-sensitive. * * If a simpler type is desired (for returning, as an example), VirtualGen * may be used to wrap the generator in a polymorphic wrapper: * * VirtualGen powersOfE() { * return seq(1) | mapped(&expf); * } * * 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 Less { public: template auto operator()(const First& first, const Second& second) const -> decltype(first < second) { return first < second; } }; class Greater { public: template auto operator()(const First& first, const Second& second) const -> decltype(first > second) { return first > second; } }; template class Get { public: template auto operator()(Value&& value) const -> decltype(std::get(std::forward(value))) { return std::get(std::forward(value)); } }; template class MemberFunction { public: typedef Result (Class::*MemberPtr)(); private: MemberPtr member_; public: explicit MemberFunction(MemberPtr member) : member_(member) {} Result operator()(Class&& x) const { return (x.*member_)(); } Result operator()(Class& x) const { return (x.*member_)(); } Result operator()(Class* x) const { return (x->*member_)(); } }; template class ConstMemberFunction { public: typedef Result (Class::*MemberPtr)() const; private: MemberPtr member_; public: explicit ConstMemberFunction(MemberPtr member) : member_(member) {} Result operator()(const Class& x) const { return (x.*member_)(); } Result operator()(const Class* x) const { return (x->*member_)(); } }; template class Field { public: typedef FieldType Class::*FieldPtr; private: FieldPtr field_; public: explicit Field(FieldPtr field) : field_(field) {} const FieldType& operator()(const Class& x) const { 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 Move { public: template auto operator()(Value&& value) const -> decltype(std::move(std::forward(value))) { return std::move(std::forward(value)); } }; /** * Class and helper function for negating a boolean Predicate */ template class Negate { Predicate pred_; public: Negate() = default; explicit Negate(Predicate pred) : pred_(std::move(pred)) {} template bool operator()(Arg&& arg) const { return !pred_(std::forward(arg)); } }; template Negate negate(Predicate pred) { return Negate(std::move(pred)); } template class Cast { public: template Dest operator()(Value&& value) const { return Dest(std::forward(value)); } }; template class To { public: template Dest operator()(Value&& value) const { return ::folly::to(std::forward(value)); } }; template class TryTo { public: template Expected operator()(Value&& value) const { return ::folly::tryTo(std::forward(value)); } }; // Specialization to allow String->StringPiece conversion template <> class To { public: StringPiece operator()(StringPiece src) const { return src; } }; template class Group; namespace detail { template struct FBounded; /* * Type Traits */ template struct ValueTypeOfRange { public: using RefType = decltype(*std::begin(std::declval())); using StorageType = typename std::decay::type; }; /* * Sources */ template < class Container, class Value = typename ValueTypeOfRange::RefType> class ReferencedSource; template < class Value, class Container = std::vector::type>> class CopiedSource; template class Sequence; template class RangeImpl; template class RangeWithStepImpl; template class SeqImpl; template class SeqWithStepImpl; template class InfiniteImpl; template class Yield; template class Empty; template class SingleReference; template class SingleCopy; /* * Operators */ template class Map; template class Filter; template class Until; class Take; class Stride; template class Sample; class Skip; template class Visit; template class Order; template class GroupBy; template class GroupByAdjacent; template class Distinct; template class Composer; template class TypeAssertion; class Concat; class RangeConcat; template class Cycle; class Batch; class Window; class Dereference; class Indirect; /* * Sinks */ template class FoldLeft; class First; template class IsEmpty; template class Reduce; class Sum; template class Min; template class Collect; template < template class Collection = std::vector, template class Allocator = std::allocator> class CollectTemplate; template class Append; template struct GeneratorBuilder; template class Contains; template class GuardImpl; template class UnwrapOr; class Unwrap; } // namespace detail /** * Polymorphic wrapper **/ template class VirtualGen; /* * Source Factories */ template < class Container, class From = detail::ReferencedSource> From fromConst(const Container& source) { return From(&source); } template > From from(Container& source) { return From(&source); } template < class Container, class Value = typename detail::ValueTypeOfRange::StorageType, class CopyOf = detail::CopiedSource> CopyOf fromCopy(Container&& source) { return CopyOf(std::forward(source)); } template > From from(std::initializer_list source) { return From(source); } template < class Container, class From = detail::CopiedSource> From from(Container&& source) { return From(std::move(source)); } template < class Value, class Impl = detail::RangeImpl, class Gen = detail::Sequence> Gen range(Value begin, Value end) { return Gen{std::move(begin), Impl{std::move(end)}}; } template < class Value, class Distance, class Impl = detail::RangeWithStepImpl, class Gen = detail::Sequence> 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, class Gen = detail::Sequence> Gen seq(Value first, Value last) { return Gen{std::move(first), Impl{std::move(last)}}; } template < class Value, class Distance, class Impl = detail::SeqWithStepImpl, class Gen = detail::Sequence> 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, class Gen = detail::Sequence> Gen seq(Value first) { return Gen{std::move(first), Impl{}}; } template > Yield generator(Source&& source) { return Yield(std::forward(source)); } /* * Create inline generator, used like: * * auto gen = GENERATOR(int) { yield(1); yield(2); }; */ #define GENERATOR(TYPE) \ ::folly::gen::detail::GeneratorBuilder() + [=](auto&& yield) /* * empty() - for producing empty sequences. */ template detail::Empty empty() { return {}; } template < class Value, class Just = typename std::conditional< std::is_reference::value, detail::SingleReference::type>, detail::SingleCopy>::type> Just just(Value&& value) { return Just(std::forward(value)); } /* * Operator Factories */ template > Map mapped(Predicate pred = Predicate()) { return Map(std::move(pred)); } template > Map map(Predicate pred = Predicate()) { return Map(std::move(pred)); } /** * mapOp - Given a generator of generators, maps the application of the given * operator on to each inner gen. Especially useful in aggregating nested data * structures: * * chunked(samples, 256) * | mapOp(filter(sampleTest) | count) * | sum; */ template >> Map mapOp(Operator op) { return Map(detail::Composer(std::move(op))); } /* * member(...) - For extracting a member from each value. * * vector strings = ...; * auto sizes = from(strings) | member(&string::size); * * If a member is const overridden (like 'front()'), pass template parameter * 'Const' to select the const version, or 'Mutable' to select the non-const * version: * * auto heads = from(strings) | member(&string::front); */ enum MemberType { Const, 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 struct ExprIsConst { enum { value = Constness == Const, }; }; template struct ExprIsMutable { enum { value = Constness == Mutable, }; }; template < MemberType Constness = Const, class Class, class Return, class Mem = ConstMemberFunction, class Map = detail::Map> typename std::enable_if::value, Map>::type member( Return (Class::*member)() const) { return Map(Mem(member)); } template < MemberType Constness = Mutable, class Class, class Return, class Mem = MemberFunction, class Map = detail::Map> typename std::enable_if::value, Map>::type member( Return (Class::*member)()) { return Map(Mem(member)); } /* * field(...) - For extracting a field from each value. * * vector items = ...; * auto names = from(items) | field(&Item::name); * * Note that if the values of the generator are rvalues, any non-reference * fields will be rvalues as well. As an example, the code below does not copy * any strings, only moves them: * * auto namesVector = from(items) * | move * | field(&Item::name) * | as(); */ template < class Class, class FieldType, class Field = Field, class Map = detail::Map> Map field(FieldType Class::*field) { return Map(Field(field)); } template > Filter filter(Predicate pred = Predicate()) { return Filter(std::move(pred)); } template > Visit visit(Visitor visitor = Visitor()) { return Visit(std::move(visitor)); } template > Until until(Predicate pred = Predicate()) { return Until(std::move(pred)); } template < class Predicate = Identity, class TakeWhile = detail::Until>> TakeWhile takeWhile(Predicate pred = Predicate()) { return TakeWhile(Negate(std::move(pred))); } template < class Selector = Identity, class Comparer = Less, class Order = detail::Order> Order orderBy(Selector selector = Selector(), Comparer comparer = Comparer()) { return Order(std::move(selector), std::move(comparer)); } template < class Selector = Identity, class Order = detail::Order> Order orderByDescending(Selector selector = Selector()) { return Order(std::move(selector)); } template > GroupBy groupBy(Selector selector = Selector()) { return GroupBy(std::move(selector)); } template < class Selector = Identity, class GroupByAdjacent = detail::GroupByAdjacent> GroupByAdjacent groupByAdjacent(Selector selector = Selector()) { return GroupByAdjacent(std::move(selector)); } template < class Selector = Identity, class Distinct = detail::Distinct> Distinct distinctBy(Selector selector = Selector()) { return Distinct(std::move(selector)); } template >> Get get() { return Get(); } // construct Dest from each value template >> Cast eachAs() { return Cast(); } // call folly::to on each value template >> EachTo eachTo() { return EachTo(); } // call folly::tryTo on each value template >> EachTryTo eachTryTo() { return EachTryTo(); } template detail::TypeAssertion assert_type() { return {}; } /* * 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, class NotEmpty = detail::IsEmpty, class Composed = detail::Composed> 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>, class IsEmpty = detail::IsEmpty, class Composed = detail::Composed> Composed all(Predicate pred = Predicate()) { return Composed(Filter(std::move(negate(pred))), IsEmpty()); } template > FoldLeft foldl(Seed seed = Seed(), Fold fold = Fold()) { return FoldLeft(std::move(seed), std::move(fold)); } template > Reduce reduce(Reducer reducer = Reducer()) { return Reduce(std::move(reducer)); } template > Min minBy(Selector selector = Selector()) { return Min(std::move(selector)); } template > MaxBy maxBy(Selector selector = Selector()) { return MaxBy(std::move(selector)); } template > Collect as() { return Collect(); } template < template class Container = std::vector, template class Allocator = std::allocator, class Collect = detail::CollectTemplate> Collect as() { return Collect(); } template > Append appendTo(Collection& collection) { return Append(&collection); } template < class Needle, class Contains = detail::Contains::type>> Contains contains(Needle&& needle) { return Contains(std::forward(needle)); } template < class Exception, class ErrorHandler, class GuardImpl = detail::GuardImpl::type>> GuardImpl guard(ErrorHandler&& handler) { return GuardImpl(std::forward(handler)); } template < class Fallback, class UnwrapOr = detail::UnwrapOr::type>> UnwrapOr unwrapOr(Fallback&& fallback) { return UnwrapOr(std::forward(fallback)); } } // namespace gen } // namespace folly #include