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.
21 #include <type_traits>
25 #include "folly/Range.h"
26 #include "folly/Optional.h"
27 #include "folly/Conv.h"
30 * Generator-based Sequence Comprehensions in C++, akin to C#'s LINQ
31 * @author Tom Jackson <tjackson@fb.com>
33 * This library makes it possible to write declarative comprehensions for
34 * processing sequences of values efficiently in C++. The operators should be
35 * familiar to those with experience in functional programming, and the
36 * performance will be virtually identical to the equivalent, boilerplate C++
39 * Generator objects may be created from either an stl-like container (anything
40 * supporting begin() and end()), from sequences of values, or from another
41 * generator (see below). To create a generator that pulls values from a vector,
42 * for example, one could write:
44 * vector<string> names { "Jack", "Jill", "Sara", "Tom" };
45 * auto gen = from(names);
47 * Generators are composed by building new generators out of old ones through
48 * the use of operators. These are reminicent of shell pipelines, and afford
49 * similar composition. Lambda functions are used liberally to describe how to
50 * handle individual values:
53 * | mapped([](const fbstring& name) { return name.size(); });
55 * Generators are lazy; they don't actually perform any work until they need to.
56 * As an example, the 'lengths' generator (above) won't actually invoke the
57 * provided lambda until values are needed:
59 * auto lengthVector = lengths | as<std::vector>();
60 * auto totalLength = lengths | sum;
62 * 'auto' is useful in here because the actual types of the generators objects
63 * are usually complicated and implementation-sensitive.
65 * If a simpler type is desired (for returning, as an example), VirtualGen<T>
66 * may be used to wrap the generator in a polymorphic wrapper:
68 * VirtualGen<float> powersOfE() {
69 * return seq(1) | mapped(&expf);
72 * To learn more about this library, including the use of infinite generators,
73 * see the examples in the comments, or the docs (coming soon).
76 namespace folly { namespace gen {
78 template<class Value, class Self>
84 class EmptySequence : public std::exception {
86 virtual const char* what() const noexcept {
87 return "This operation cannot be called on an empty sequence";
95 auto operator()(const First& first, const Second& second) const ->
96 decltype(first < second) {
97 return first < second;
103 template<class First,
105 auto operator()(const First& first, const Second& second) const ->
106 decltype(first > second) {
107 return first > second;
114 template<class Value>
115 auto operator()(Value&& value) const ->
116 decltype(std::get<n>(std::forward<Value>(value))) {
117 return std::get<n>(std::forward<Value>(value));
123 template<class Value>
124 auto operator()(Value&& value) const ->
125 decltype(std::move(std::forward<Value>(value))) {
126 return std::move(std::forward<Value>(value));
132 template<class Value>
133 auto operator()(Value&& value) const ->
134 decltype(std::forward<Value>(value)) {
135 return std::forward<Value>(value);
139 template <class Dest>
142 template <class Value>
143 Dest operator()(Value&& value) const {
144 return Dest(std::forward<Value>(value));
148 template <class Dest>
151 template <class Value>
152 Dest operator()(Value&& value) const {
153 return ::folly::to<Dest>(std::forward<Value>(value));
165 template<class Container>
166 struct ValueTypeOfRange {
168 static Container container_;
170 typedef decltype(*std::begin(container_))
172 typedef typename std::decay<decltype(*std::begin(container_))>::type
180 template<class Container,
181 class Value = typename ValueTypeOfRange<Container>::RefType>
182 class ReferencedSource;
184 template<class Value,
185 class Container = std::vector<typename std::decay<Value>::type>>
188 template<class Value, bool endless = false, bool endInclusive = false>
191 template<class Value, class First, class Second>
194 template<class Value, class Source>
200 template<class Predicate>
203 template<class Predicate>
206 template<class Predicate>
213 template<class Selector, class Comparer = Less>
216 template<class First, class Second>
230 template<class Predicate>
233 template<class Reducer>
238 template<class Selector,
242 template<class Container>
245 template<template<class, class> class Collection = std::vector,
246 template<class> class Allocator = std::allocator>
247 class CollectTemplate;
249 template<class Collection>
252 template<class Value>
253 class GeneratorBuilder;
255 template<class Needle>
261 * Polymorphic wrapper
263 template<class Value>
269 template<class Container,
270 class From = detail::ReferencedSource<const Container>>
271 From fromConst(const Container& source) {
272 return From(&source);
275 template<class Container,
276 class From = detail::ReferencedSource<Container>>
277 From from(Container& source) {
278 return From(&source);
281 template<class Container,
283 typename detail::ValueTypeOfRange<Container>::StorageType,
284 class CopyOf = detail::CopiedSource<Value>>
285 CopyOf fromCopy(Container&& source) {
286 return CopyOf(std::forward<Container>(source));
289 template<class Value,
290 class From = detail::CopiedSource<Value>>
291 From from(std::initializer_list<Value> source) {
295 template<class Container,
296 class From = detail::CopiedSource<typename Container::value_type,
298 From from(Container&& source) {
299 return From(std::move(source));
302 template<class Value, class Gen = detail::Sequence<Value, false, false>>
303 Gen range(Value begin, Value end) {
304 return Gen(begin, end);
307 template<class Value,
308 class Gen = detail::Sequence<Value, false, true>>
309 Gen seq(Value first, Value last) {
310 return Gen(first, last);
313 template<class Value,
314 class Gen = detail::Sequence<Value, true>>
315 Gen seq(Value begin) {
319 template<class Value,
321 class Yield = detail::Yield<Value, Source>>
322 Yield generator(Source&& source) {
323 return Yield(std::forward<Source>(source));
327 * Create inline generator, used like:
329 * auto gen = GENERATOR(int) { yield(1); yield(2); };
331 #define GENERATOR(TYPE) \
332 ::folly::gen::detail::GeneratorBuilder<TYPE>() + \
333 [=](const std::function<void(TYPE)>& yield)
338 template<class Predicate,
339 class Map = detail::Map<Predicate>>
340 Map mapped(Predicate pred = Predicate()) {
341 return Map(std::move(pred));
344 template<class Predicate,
345 class Map = detail::Map<Predicate>>
346 Map map(Predicate pred = Predicate()) {
347 return Map(std::move(pred));
350 template<class Predicate,
351 class Filter = detail::Filter<Predicate>>
352 Filter filter(Predicate pred = Predicate()) {
353 return Filter(std::move(pred));
356 template<class Predicate,
357 class All = detail::All<Predicate>>
358 All all(Predicate pred = Predicate()) {
359 return All(std::move(pred));
362 template<class Predicate,
363 class Until = detail::Until<Predicate>>
364 Until until(Predicate pred = Predicate()) {
365 return Until(std::move(pred));
368 template<class Selector,
369 class Comparer = Less,
370 class Order = detail::Order<Selector, Comparer>>
371 Order orderBy(Selector selector = Identity(),
372 Comparer comparer = Comparer()) {
373 return Order(std::move(selector),
374 std::move(comparer));
377 template<class Selector,
378 class Order = detail::Order<Selector, Greater>>
379 Order orderByDescending(Selector selector = Identity()) {
380 return Order(std::move(selector));
384 class Get = detail::Map<Get<n>>>
389 // construct Dest from each value
390 template <class Dest,
391 class Cast = detail::Map<Cast<Dest>>>
396 // call folly::to on each value
397 template <class Dest,
398 class To = detail::Map<To<Dest>>>
408 class FoldLeft = detail::FoldLeft<Seed, Fold>>
409 FoldLeft foldl(Seed seed = Seed(),
410 Fold fold = Fold()) {
411 return FoldLeft(std::move(seed),
415 template<class Reducer,
416 class Reduce = detail::Reduce<Reducer>>
417 Reduce reduce(Reducer reducer = Reducer()) {
418 return Reduce(std::move(reducer));
421 template<class Selector = Identity,
422 class Min = detail::Min<Selector, Less>>
423 Min minBy(Selector selector = Selector()) {
424 return Min(std::move(selector));
427 template<class Selector,
428 class MaxBy = detail::Min<Selector, Greater>>
429 MaxBy maxBy(Selector selector = Selector()) {
430 return MaxBy(std::move(selector));
433 template<class Collection,
434 class Collect = detail::Collect<Collection>>
439 template<template<class, class> class Container = std::vector,
440 template<class> class Allocator = std::allocator,
441 class Collect = detail::CollectTemplate<Container, Allocator>>
446 template<class Collection,
447 class Append = detail::Append<Collection>>
448 Append appendTo(Collection& collection) {
449 return Append(&collection);
452 template<class Needle,
453 class Contains = detail::Contains<typename std::decay<Needle>::type>>
454 Contains contains(Needle&& needle) {
455 return Contains(std::forward<Needle>(needle));
460 #include "folly/experimental/Gen-inl.h"