2 * Copyright 2013 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 #ifndef FOLLY_GEN_BASE_H
17 #define FOLLY_GEN_BASE_H
21 #include <type_traits>
26 #include <unordered_set>
28 #include "folly/Range.h"
29 #include "folly/Optional.h"
30 #include "folly/Conv.h"
31 #include "folly/gen/Core.h"
34 * Generator-based Sequence Comprehensions in C++, akin to C#'s LINQ
35 * @author Tom Jackson <tjackson@fb.com>
37 * This library makes it possible to write declarative comprehensions for
38 * processing sequences of values efficiently in C++. The operators should be
39 * familiar to those with experience in functional programming, and the
40 * performance will be virtually identical to the equivalent, boilerplate C++
43 * Generator objects may be created from either an stl-like container (anything
44 * supporting begin() and end()), from sequences of values, or from another
45 * generator (see below). To create a generator that pulls values from a vector,
46 * for example, one could write:
48 * vector<string> names { "Jack", "Jill", "Sara", "Tom" };
49 * auto gen = from(names);
51 * Generators are composed by building new generators out of old ones through
52 * the use of operators. These are reminicent of shell pipelines, and afford
53 * similar composition. Lambda functions are used liberally to describe how to
54 * handle individual values:
57 * | mapped([](const fbstring& name) { return name.size(); });
59 * Generators are lazy; they don't actually perform any work until they need to.
60 * As an example, the 'lengths' generator (above) won't actually invoke the
61 * provided lambda until values are needed:
63 * auto lengthVector = lengths | as<std::vector>();
64 * auto totalLength = lengths | sum;
66 * 'auto' is useful in here because the actual types of the generators objects
67 * are usually complicated and implementation-sensitive.
69 * If a simpler type is desired (for returning, as an example), VirtualGen<T>
70 * may be used to wrap the generator in a polymorphic wrapper:
72 * VirtualGen<float> powersOfE() {
73 * return seq(1) | mapped(&expf);
76 * To learn more about this library, including the use of infinite generators,
77 * see the examples in the comments, or the docs (coming soon).
80 namespace folly { namespace gen {
82 class EmptySequence : public std::exception {
84 virtual const char* what() const noexcept {
85 return "This operation cannot be called on an empty sequence";
93 auto operator()(const First& first, const Second& second) const ->
94 decltype(first < second) {
95 return first < second;
101 template<class First,
103 auto operator()(const First& first, const Second& second) const ->
104 decltype(first > second) {
105 return first > second;
112 template<class Value>
113 auto operator()(Value&& value) const ->
114 decltype(std::get<n>(std::forward<Value>(value))) {
115 return std::get<n>(std::forward<Value>(value));
119 template<class Class,
121 class MemberFunction {
123 typedef Result (Class::*MemberPtr)();
127 explicit MemberFunction(MemberPtr member)
131 Result operator()(Class&& x) const {
132 return (x.*member_)();
135 Result operator()(Class& x) const {
136 return (x.*member_)();
140 template<class Class,
142 class ConstMemberFunction{
144 typedef Result (Class::*MemberPtr)() const;
148 explicit ConstMemberFunction(MemberPtr member)
152 Result operator()(const Class& x) const {
153 return (x.*member_)();
157 template<class Class,
161 typedef FieldType (Class::*FieldPtr);
165 explicit Field(FieldPtr field)
169 const FieldType& operator()(const Class& x) const {
173 FieldType& operator()(Class& x) const {
177 FieldType&& operator()(Class&& x) const {
178 return std::move(x.*field_);
184 template<class Value>
185 auto operator()(Value&& value) const ->
186 decltype(std::move(std::forward<Value>(value))) {
187 return std::move(std::forward<Value>(value));
193 template<class Value>
194 auto operator()(Value&& value) const ->
195 decltype(std::forward<Value>(value)) {
196 return std::forward<Value>(value);
200 template <class Dest>
203 template <class Value>
204 Dest operator()(Value&& value) const {
205 return Dest(std::forward<Value>(value));
209 template <class Dest>
212 template <class Value>
213 Dest operator()(Value&& value) const {
214 return ::folly::to<Dest>(std::forward<Value>(value));
218 // Specialization to allow String->StringPiece conversion
220 class To<StringPiece> {
222 StringPiece operator()(StringPiece src) const {
235 template<class Container>
236 struct ValueTypeOfRange {
238 static Container container_;
240 typedef decltype(*std::begin(container_))
242 typedef typename std::decay<decltype(*std::begin(container_))>::type
250 template<class Container,
251 class Value = typename ValueTypeOfRange<Container>::RefType>
252 class ReferencedSource;
254 template<class Value,
255 class Container = std::vector<typename std::decay<Value>::type>>
258 template<class Value, bool endless = false, bool endInclusive = false>
261 template<class Value, class Source>
264 template<class Value>
271 template<class Predicate>
274 template<class Predicate>
277 template<class Predicate>
287 template<class Selector, class Comparer = Less>
290 template<class Selector>
293 template<class Expected>
317 template<class Predicate>
320 template<class Reducer>
325 template<class Selector,
329 template<class Container>
332 template<template<class, class> class Collection = std::vector,
333 template<class> class Allocator = std::allocator>
334 class CollectTemplate;
336 template<class Collection>
339 template<class Value>
340 struct GeneratorBuilder;
342 template<class Needle>
345 template<class Exception,
352 * Polymorphic wrapper
354 template<class Value>
360 template<class Container,
361 class From = detail::ReferencedSource<const Container>>
362 From fromConst(const Container& source) {
363 return From(&source);
366 template<class Container,
367 class From = detail::ReferencedSource<Container>>
368 From from(Container& source) {
369 return From(&source);
372 template<class Container,
374 typename detail::ValueTypeOfRange<Container>::StorageType,
375 class CopyOf = detail::CopiedSource<Value>>
376 CopyOf fromCopy(Container&& source) {
377 return CopyOf(std::forward<Container>(source));
380 template<class Value,
381 class From = detail::CopiedSource<Value>>
382 From from(std::initializer_list<Value> source) {
386 template<class Container,
387 class From = detail::CopiedSource<typename Container::value_type,
389 From from(Container&& source) {
390 return From(std::move(source));
393 template<class Value, class Gen = detail::Sequence<Value, false, false>>
394 Gen range(Value begin, Value end) {
395 return Gen(begin, end);
398 template<class Value,
399 class Gen = detail::Sequence<Value, false, true>>
400 Gen seq(Value first, Value last) {
401 return Gen(first, last);
404 template<class Value,
405 class Gen = detail::Sequence<Value, true>>
406 Gen seq(Value begin) {
410 template<class Value,
412 class Yield = detail::Yield<Value, Source>>
413 Yield generator(Source&& source) {
414 return Yield(std::forward<Source>(source));
418 * Create inline generator, used like:
420 * auto gen = GENERATOR(int) { yield(1); yield(2); };
422 #define GENERATOR(TYPE) \
423 ::folly::gen::detail::GeneratorBuilder<TYPE>() + \
424 [=](const std::function<void(TYPE)>& yield)
427 * empty() - for producing empty sequences.
429 template<class Value>
430 detail::Empty<Value> empty() {
437 template<class Predicate,
438 class Map = detail::Map<Predicate>>
439 Map mapped(Predicate pred = Predicate()) {
440 return Map(std::move(pred));
443 template<class Predicate,
444 class Map = detail::Map<Predicate>>
445 Map map(Predicate pred = Predicate()) {
446 return Map(std::move(pred));
450 * member(...) - For extracting a member from each value.
452 * vector<string> strings = ...;
453 * auto sizes = from(strings) | member(&string::size);
455 * If a member is const overridden (like 'front()'), pass template parameter
456 * 'Const' to select the const version, or 'Mutable' to select the non-const
459 * auto heads = from(strings) | member<Const>(&string::front);
466 template<MemberType Constness = Const,
469 class Mem = ConstMemberFunction<Class, Return>,
470 class Map = detail::Map<Mem>>
471 typename std::enable_if<Constness == Const, Map>::type
472 member(Return (Class::*member)() const) {
473 return Map(Mem(member));
476 template<MemberType Constness = Mutable,
479 class Mem = MemberFunction<Class, Return>,
480 class Map = detail::Map<Mem>>
481 typename std::enable_if<Constness == Mutable, Map>::type
482 member(Return (Class::*member)()) {
483 return Map(Mem(member));
487 * field(...) - For extracting a field from each value.
489 * vector<Item> items = ...;
490 * auto names = from(items) | field(&Item::name);
492 * Note that if the values of the generator are rvalues, any non-reference
493 * fields will be rvalues as well. As an example, the code below does not copy
494 * any strings, only moves them:
496 * auto namesVector = from(items)
498 * | field(&Item::name)
501 template<class Class,
503 class Field = Field<Class, FieldType>,
504 class Map = detail::Map<Field>>
505 Map field(FieldType Class::*field) {
506 return Map(Field(field));
509 template<class Predicate,
510 class Filter = detail::Filter<Predicate>>
511 Filter filter(Predicate pred = Predicate()) {
512 return Filter(std::move(pred));
515 template<class Predicate,
516 class All = detail::All<Predicate>>
517 All all(Predicate pred = Predicate()) {
518 return All(std::move(pred));
521 template<class Predicate,
522 class Until = detail::Until<Predicate>>
523 Until until(Predicate pred = Predicate()) {
524 return Until(std::move(pred));
527 template<class Selector,
528 class Comparer = Less,
529 class Order = detail::Order<Selector, Comparer>>
530 Order orderBy(Selector selector = Identity(),
531 Comparer comparer = Comparer()) {
532 return Order(std::move(selector),
533 std::move(comparer));
536 template<class Selector,
537 class Order = detail::Order<Selector, Greater>>
538 Order orderByDescending(Selector selector = Identity()) {
539 return Order(std::move(selector));
542 template<class Selector,
543 class Distinct = detail::Distinct<Selector>>
544 Distinct distinctBy(Selector selector = Identity()) {
545 return Distinct(std::move(selector));
549 class Get = detail::Map<Get<n>>>
554 // construct Dest from each value
555 template <class Dest,
556 class Cast = detail::Map<Cast<Dest>>>
561 // call folly::to on each value
562 template <class Dest,
563 class To = detail::Map<To<Dest>>>
568 template<class Value>
569 detail::TypeAssertion<Value> assert_type() {
578 class FoldLeft = detail::FoldLeft<Seed, Fold>>
579 FoldLeft foldl(Seed seed = Seed(),
580 Fold fold = Fold()) {
581 return FoldLeft(std::move(seed),
585 template<class Reducer,
586 class Reduce = detail::Reduce<Reducer>>
587 Reduce reduce(Reducer reducer = Reducer()) {
588 return Reduce(std::move(reducer));
591 template<class Selector = Identity,
592 class Min = detail::Min<Selector, Less>>
593 Min minBy(Selector selector = Selector()) {
594 return Min(std::move(selector));
597 template<class Selector,
598 class MaxBy = detail::Min<Selector, Greater>>
599 MaxBy maxBy(Selector selector = Selector()) {
600 return MaxBy(std::move(selector));
603 template<class Collection,
604 class Collect = detail::Collect<Collection>>
609 template<template<class, class> class Container = std::vector,
610 template<class> class Allocator = std::allocator,
611 class Collect = detail::CollectTemplate<Container, Allocator>>
616 template<class Collection,
617 class Append = detail::Append<Collection>>
618 Append appendTo(Collection& collection) {
619 return Append(&collection);
622 template<class Needle,
623 class Contains = detail::Contains<typename std::decay<Needle>::type>>
624 Contains contains(Needle&& needle) {
625 return Contains(std::forward<Needle>(needle));
628 template<class Exception,
633 typename std::decay<ErrorHandler>::type>>
634 GuardImpl guard(ErrorHandler&& handler) {
635 return GuardImpl(std::forward<ErrorHandler>(handler));
640 #include "folly/gen/Base-inl.h"
642 #endif // FOLLY_GEN_BASE_H