2 * Copyright 2015 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.
17 #ifndef FOLLY_GEN_BASE_H
18 #error This file may only be included from folly/gen/Base.h
21 // Ignore shadowing warnings within this file, so includers can use -Wshadow.
22 #pragma GCC diagnostic push
23 #pragma GCC diagnostic ignored "-Wshadow"
25 namespace folly { namespace gen {
28 * ArgumentReference - For determining ideal argument type to receive a value.
31 struct ArgumentReference
32 : public std::conditional<
33 std::is_reference<T>::value,
34 T, // T& -> T&, T&& -> T&&, const T& -> const T&
35 typename std::conditional<std::is_const<T>::value,
36 T&, // const int -> const int&
40 template <class Key, class Value>
41 class Group : public GenImpl<Value&&, Group<Key, Value>> {
43 static_assert(!std::is_reference<Key>::value &&
44 !std::is_reference<Value>::value,
45 "Key and Value must be decayed types");
47 typedef std::vector<Value> VectorType;
49 typedef Value ValueType;
51 Group(Key key, VectorType values)
52 : key_(std::move(key)), values_(std::move(values)) {}
54 const Key& key() const { return key_; }
56 size_t size() const { return values_.size(); }
57 const VectorType& values() const { return values_; }
58 VectorType& values() { return values_; }
60 VectorType operator|(const detail::Collect<VectorType>&) const {
64 VectorType operator|(const detail::CollectTemplate<std::vector>&) const {
69 void foreach(Body&& body) const {
70 for (auto& value : values_) {
71 body(std::move(value));
75 template <class Handler>
76 bool apply(Handler&& handler) const {
77 for (auto& value : values_) {
78 if (!handler(std::move(value))) {
87 mutable VectorType values_;
93 * ReferencedSource - Generate values from an STL-like container using
94 * iterators from .begin() until .end(). Value type defaults to the type of
95 * *container->begin(). For std::vector<int>, this would be int&. Note that the
96 * value here is a reference, so the values in the vector will be passed by
97 * reference to downstream operators.
99 * This type is primarily used through the 'from' helper method, like:
101 * string& longestName = from(names)
102 * | maxBy([](string& s) { return s.size() });
104 template<class Container,
106 class ReferencedSource :
107 public GenImpl<Value, ReferencedSource<Container, Value>> {
108 Container* container_;
110 explicit ReferencedSource(Container* container)
111 : container_(container) {}
114 void foreach(Body&& body) const {
115 for (auto& value : *container_) {
116 body(std::forward<Value>(value));
120 template<class Handler>
121 bool apply(Handler&& handler) const {
122 for (auto& value : *container_) {
123 if (!handler(std::forward<Value>(value))) {
132 * CopiedSource - For producing values from eagerly from a sequence of values
133 * whose storage is owned by this class. Useful for preparing a generator for
134 * use after a source collection will no longer be available, or for when the
135 * values are specified literally with an initializer list.
137 * This type is primarily used through the 'fromCopy' function, like:
139 * auto sourceCopy = fromCopy(makeAVector());
140 * auto sum = sourceCopy | sum;
141 * auto max = sourceCopy | max;
143 * Though it is also used for the initializer_list specialization of from().
145 template<class StorageType,
148 public GenImpl<const StorageType&,
149 CopiedSource<StorageType, Container>> {
151 !std::is_reference<StorageType>::value, "StorageType must be decayed");
153 // Generator objects are often copied during normal construction as they are
154 // encapsulated by downstream generators. It would be bad if this caused
155 // a copy of the entire container each time, and since we're only exposing a
156 // const reference to the value, it's safe to share it between multiple
159 !std::is_reference<Container>::value,
160 "Can't copy into a reference");
161 std::shared_ptr<const Container> copy_;
163 typedef Container ContainerType;
165 template<class SourceContainer>
166 explicit CopiedSource(const SourceContainer& container)
167 : copy_(new Container(begin(container), end(container))) {}
169 explicit CopiedSource(Container&& container) :
170 copy_(new Container(std::move(container))) {}
172 // To enable re-use of cached results.
173 CopiedSource(const CopiedSource<StorageType, Container>& source)
174 : copy_(source.copy_) {}
177 void foreach(Body&& body) const {
178 for (const auto& value : *copy_) {
183 template<class Handler>
184 bool apply(Handler&& handler) const {
185 // The collection may be reused by others, we can't allow it to be changed.
186 for (const auto& value : *copy_) {
187 if (!handler(value)) {
196 * RangeSource - For producing values from a folly::Range. Useful for referring
197 * to a slice of some container.
199 * This type is primarily used through the 'from' function, like:
201 * auto rangeSource = from(folly::range(v.begin(), v.end()));
202 * auto sum = rangeSource | sum;
204 * Reminder: Be careful not to invalidate iterators when using ranges like this.
206 template<class Iterator>
207 class RangeSource : public GenImpl<typename Range<Iterator>::reference,
208 RangeSource<Iterator>> {
209 Range<Iterator> range_;
211 RangeSource() = default;
212 explicit RangeSource(Range<Iterator> range)
213 : range_(std::move(range))
216 template<class Handler>
217 bool apply(Handler&& handler) const {
218 for (auto& value : range_) {
219 if (!handler(value)) {
227 void foreach(Body&& body) const {
228 for (auto& value : range_) {
235 * Sequence - For generating values from beginning value, incremented along the
236 * way with the ++ and += operators. Iteration may continue indefinitely.
237 * Value type specified explicitly.
239 * This type is primarily used through the 'seq' and 'range' function, like:
241 * int total = seq(1, 10) | sum;
242 * auto indexes = range(0, 10);
243 * auto endless = seq(0); // 0, 1, 2, 3, ...
245 template<class Value, class SequenceImpl>
246 class Sequence : public GenImpl<const Value&, Sequence<Value, SequenceImpl>> {
247 static_assert(!std::is_reference<Value>::value &&
248 !std::is_const<Value>::value, "Value mustn't be const or ref.");
252 explicit Sequence(Value start, SequenceImpl impl)
253 : start_(std::move(start)), impl_(std::move(impl)) { }
255 template<class Handler>
256 bool apply(Handler&& handler) const {
257 for (Value current = start_; impl_.test(current); impl_.step(current)) {
258 if (!handler(current)) {
266 void foreach(Body&& body) const {
267 for (Value current = start_; impl_.test(current); impl_.step(current)) {
274 * Sequence implementations (range, sequence, infinite, with/without step)
276 template<class Value>
280 explicit RangeImpl(Value end) : end_(std::move(end)) { }
281 bool test(const Value& current) const { return current < end_; }
282 void step(Value& current) const { ++current; }
285 template<class Value, class Distance>
286 class RangeWithStepImpl {
290 explicit RangeWithStepImpl(Value end, Distance step)
291 : end_(std::move(end)), step_(std::move(step)) { }
292 bool test(const Value& current) const { return current < end_; }
293 void step(Value& current) const { current += step_; }
296 template<class Value>
300 explicit SeqImpl(Value end) : end_(std::move(end)) { }
301 bool test(const Value& current) const { return current <= end_; }
302 void step(Value& current) const { ++current; }
305 template<class Value, class Distance>
306 class SeqWithStepImpl {
310 explicit SeqWithStepImpl(Value end, Distance step)
311 : end_(std::move(end)), step_(std::move(step)) { }
312 bool test(const Value& current) const { return current <= end_; }
313 void step(Value& current) const { current += step_; }
316 template<class Value>
319 bool test(const Value& current) const { return true; }
320 void step(Value& current) const { ++current; }
324 * GenratorBuilder - Helper for GENERTATOR macro.
326 template<class Value>
327 struct GeneratorBuilder {
328 template<class Source,
329 class Yield = detail::Yield<Value, Source>>
330 Yield operator+(Source&& source) {
331 return Yield(std::forward<Source>(source));
336 * Yield - For producing values from a user-defined generator by way of a
339 template<class Value, class Source>
340 class Yield : public GenImpl<Value, Yield<Value, Source>> {
343 explicit Yield(Source source)
344 : source_(std::move(source)) {
347 template<class Handler>
348 bool apply(Handler&& handler) const {
350 auto body = [&](Value value) {
351 if (!handler(std::forward<Value>(value))) {
364 void foreach(Body&& body) const {
365 source_(std::forward<Body>(body));
369 template<class Value>
370 class Empty : public GenImpl<Value, Empty<Value>> {
372 template <class Handler>
373 bool apply(Handler&&) const {
377 template <class Body>
378 void foreach(Body&&) const {}
381 template <class Value>
382 class SingleReference : public GenImpl<Value&, SingleReference<Value>> {
383 static_assert(!std::is_reference<Value>::value,
384 "SingleReference requires non-ref types");
387 explicit SingleReference(Value& ref) : ptr_(&ref) {}
389 template <class Handler>
390 bool apply(Handler&& handler) const {
391 return handler(*ptr_);
394 template <class Body>
395 void foreach(Body&& body) const {
400 template <class Value>
401 class SingleCopy : public GenImpl<const Value&, SingleCopy<Value>> {
402 static_assert(!std::is_reference<Value>::value,
403 "SingleCopy requires non-ref types");
406 explicit SingleCopy(Value value) : value_(std::forward<Value>(value)) {}
408 template <class Handler>
409 bool apply(Handler&& handler) const {
410 return handler(value_);
413 template <class Body>
414 void foreach(Body&& body) const {
424 * Map - For producing a sequence of values by passing each value from a source
425 * collection through a predicate.
427 * This type is usually used through the 'map' or 'mapped' helper function:
429 * auto squares = seq(1, 10) | map(square) | asVector;
431 template<class Predicate>
432 class Map : public Operator<Map<Predicate>> {
437 explicit Map(Predicate pred)
438 : pred_(std::move(pred))
441 template<class Value,
443 class Result = typename ArgumentReference<
444 typename std::result_of<Predicate(Value)>::type
447 public GenImpl<Result, Generator<Value, Source, Result>> {
451 explicit Generator(Source source, const Predicate& pred)
452 : source_(std::move(source)), pred_(pred) {}
455 void foreach(Body&& body) const {
456 source_.foreach([&](Value value) {
457 body(pred_(std::forward<Value>(value)));
461 template<class Handler>
462 bool apply(Handler&& handler) const {
463 return source_.apply([&](Value value) {
464 return handler(pred_(std::forward<Value>(value)));
468 static constexpr bool infinite = Source::infinite;
471 template<class Source,
473 class Gen = Generator<Value, Source>>
474 Gen compose(GenImpl<Value, Source>&& source) const {
475 return Gen(std::move(source.self()), pred_);
478 template<class Source,
480 class Gen = Generator<Value, Source>>
481 Gen compose(const GenImpl<Value, Source>& source) const {
482 return Gen(source.self(), pred_);
487 * Filter - For filtering values from a source sequence by a predicate.
489 * This type is usually used through the 'filter' helper function, like:
491 * auto nonEmpty = from(strings)
492 * | filter([](const string& str) -> bool {
493 * return !str.empty();
496 * Note that if no predicate is provided, the values are casted to bool and
497 * filtered based on that. So if pointers is a vector of pointers,
499 * auto nonNull = from(pointers) | filter();
501 * will give a vector of all the pointers != nullptr.
503 template<class Predicate>
504 class Filter : public Operator<Filter<Predicate>> {
508 explicit Filter(Predicate pred)
509 : pred_(std::move(pred))
512 template<class Value,
514 class Generator : public GenImpl<Value, Generator<Value, Source>> {
518 explicit Generator(Source source, const Predicate& pred)
519 : source_(std::move(source)), pred_(pred) {}
522 void foreach(Body&& body) const {
523 source_.foreach([&](Value value) {
524 if (pred_(std::forward<Value>(value))) {
525 body(std::forward<Value>(value));
530 template<class Handler>
531 bool apply(Handler&& handler) const {
532 return source_.apply([&](Value value) -> bool {
533 if (pred_(std::forward<Value>(value))) {
534 return handler(std::forward<Value>(value));
540 static constexpr bool infinite = Source::infinite;
543 template<class Source,
545 class Gen = Generator<Value, Source>>
546 Gen compose(GenImpl<Value, Source>&& source) const {
547 return Gen(std::move(source.self()), pred_);
550 template<class Source,
552 class Gen = Generator<Value, Source>>
553 Gen compose(const GenImpl<Value, Source>& source) const {
554 return Gen(source.self(), pred_);
559 * Until - For producing values from a source until a predicate is satisfied.
561 * This type is usually used through the 'until' helper function, like:
563 * auto best = from(sortedItems)
564 * | until([](Item& item) { return item.score > 100; })
567 template<class Predicate>
568 class Until : public Operator<Until<Predicate>> {
572 explicit Until(Predicate pred)
573 : pred_(std::move(pred))
576 template<class Value,
578 class Generator : public GenImpl<Value, Generator<Value, Source>> {
582 explicit Generator(Source source, const Predicate& pred)
583 : source_(std::move(source)), pred_(pred) {}
585 template<class Handler>
586 bool apply(Handler&& handler) const {
587 bool cancelled = false;
588 source_.apply([&](Value value) -> bool {
589 if (pred_(value)) { // un-forwarded to disable move
592 if (!handler(std::forward<Value>(value))) {
602 template<class Source,
604 class Gen = Generator<Value, Source>>
605 Gen compose(GenImpl<Value, Source>&& source) const {
606 return Gen(std::move(source.self()), pred_);
609 template<class Source,
611 class Gen = Generator<Value, Source>>
612 Gen compose(const GenImpl<Value, Source>& source) const {
613 return Gen(source.self(), pred_);
616 // Theoretically an 'until' might stop an infinite
617 static constexpr bool infinite = false;
621 * Take - For producing up to N values from a source.
623 * This type is usually used through the 'take' helper function, like:
625 * auto best = from(docs)
626 * | orderByDescending(scoreDoc)
629 class Take : public Operator<Take> {
632 explicit Take(size_t count)
635 template<class Value,
638 public GenImpl<Value, Generator<Value, Source>> {
642 explicit Generator(Source source, size_t count)
643 : source_(std::move(source)) , count_(count) {}
645 template<class Handler>
646 bool apply(Handler&& handler) const {
647 if (count_ == 0) { return false; }
649 bool cancelled = false;
650 source_.apply([&](Value value) -> bool {
651 if (!handler(std::forward<Value>(value))) {
661 template<class Source,
663 class Gen = Generator<Value, Source>>
664 Gen compose(GenImpl<Value, Source>&& source) const {
665 return Gen(std::move(source.self()), count_);
668 template<class Source,
670 class Gen = Generator<Value, Source>>
671 Gen compose(const GenImpl<Value, Source>& source) const {
672 return Gen(source.self(), count_);
677 * Stride - For producing every Nth value from a source.
679 * This type is usually used through the 'stride' helper function, like:
681 * auto half = from(samples)
684 class Stride : public Operator<Stride> {
688 explicit Stride(size_t stride) : stride_(stride) {
690 throw std::invalid_argument("stride must not be 0");
694 template <class Value, class Source>
695 class Generator : public GenImpl<Value, Generator<Value, Source>> {
699 Generator(Source source, size_t stride)
700 : source_(std::move(source)), stride_(stride) {}
702 template <class Handler>
703 bool apply(Handler&& handler) const {
704 size_t distance = stride_;
705 return source_.apply([&](Value value)->bool {
706 if (++distance >= stride_) {
707 if (!handler(std::forward<Value>(value))) {
716 template <class Body>
717 void foreach(Body&& body) const {
718 size_t distance = stride_;
719 source_.foreach([&](Value value) {
720 if (++distance >= stride_) {
721 body(std::forward<Value>(value));
728 template <class Source, class Value, class Gen = Generator<Value, Source>>
729 Gen compose(GenImpl<Value, Source>&& source) const {
730 return Gen(std::move(source.self()), stride_);
733 template <class Source, class Value, class Gen = Generator<Value, Source>>
734 Gen compose(const GenImpl<Value, Source>& source) const {
735 return Gen(source.self(), stride_);
740 * Sample - For taking a random sample of N elements from a sequence
741 * (without replacement).
743 template<class Random>
744 class Sample : public Operator<Sample<Random>> {
748 explicit Sample(size_t count, Random rng)
749 : count_(count), rng_(std::move(rng)) {}
751 template<class Value,
754 class StorageType = typename std::decay<Value>::type>
756 public GenImpl<StorageType&&,
757 Generator<Value, Source, Rand, StorageType>> {
758 static_assert(!Source::infinite, "Cannot sample infinite source!");
759 // It's too easy to bite ourselves if random generator is only 16-bit
760 static_assert(Random::max() >= std::numeric_limits<int32_t>::max() - 1,
761 "Random number generator must support big values");
766 explicit Generator(Source source, size_t count, Random rng)
767 : source_(std::move(source)) , count_(count), rng_(std::move(rng)) {}
769 template<class Handler>
770 bool apply(Handler&& handler) const {
771 if (count_ == 0) { return false; }
772 std::vector<StorageType> v;
774 // use reservoir sampling to give each source value an equal chance
775 // of appearing in our output.
777 source_.foreach([&](Value value) -> void {
778 if (v.size() < count_) {
779 v.push_back(std::forward<Value>(value));
781 // alternatively, we could create a std::uniform_int_distribution
782 // instead of using modulus, but benchmarks show this has
783 // substantial overhead.
784 size_t index = rng_() % n;
785 if (index < v.size()) {
786 v[index] = std::forward<Value>(value);
792 // output is unsorted!
794 if (!handler(std::move(val))) {
802 template<class Source,
804 class Gen = Generator<Value, Source, Random>>
805 Gen compose(GenImpl<Value, Source>&& source) const {
806 return Gen(std::move(source.self()), count_, rng_);
809 template<class Source,
811 class Gen = Generator<Value, Source, Random>>
812 Gen compose(const GenImpl<Value, Source>& source) const {
813 return Gen(source.self(), count_, rng_);
818 * Skip - For skipping N items from the beginning of a source generator.
820 * This type is usually used through the 'skip' helper function, like:
822 * auto page = from(results)
823 * | skip(pageSize * startPage)
826 class Skip : public Operator<Skip> {
829 explicit Skip(size_t count)
832 template<class Value,
835 public GenImpl<Value, Generator<Value, Source>> {
839 explicit Generator(Source source, size_t count)
840 : source_(std::move(source)) , count_(count) {}
843 void foreach(Body&& body) const {
845 source_.foreach(body);
849 source_.foreach([&](Value value) {
853 body(std::forward<Value>(value));
858 template<class Handler>
859 bool apply(Handler&& handler) const {
861 return source_.apply(std::forward<Handler>(handler));
864 return source_.apply([&](Value value) -> bool {
869 return handler(std::forward<Value>(value));
873 static constexpr bool infinite = Source::infinite;
876 template<class Source,
878 class Gen = Generator<Value, Source>>
879 Gen compose(GenImpl<Value, Source>&& source) const {
880 return Gen(std::move(source.self()), count_);
883 template<class Source,
885 class Gen = Generator<Value, Source>>
886 Gen compose(const GenImpl<Value, Source>& source) const {
887 return Gen(source.self(), count_);
892 * Order - For ordering a sequence of values from a source by key.
893 * The key is extracted by the given selector functor, and this key is then
894 * compared using the specified comparator.
896 * This type is usually used through the 'order' helper function, like:
898 * auto closest = from(places)
899 * | orderBy([](Place& p) {
900 * return -distance(p.location, here);
904 template<class Selector, class Comparer>
905 class Order : public Operator<Order<Selector, Comparer>> {
911 explicit Order(Selector selector)
912 : selector_(std::move(selector))
915 Order(Selector selector,
917 : selector_(std::move(selector))
918 , comparer_(std::move(comparer))
921 template<class Value,
923 class StorageType = typename std::decay<Value>::type,
924 class Result = typename std::result_of<Selector(Value)>::type>
926 public GenImpl<StorageType&&,
927 Generator<Value, Source, StorageType, Result>> {
928 static_assert(!Source::infinite, "Cannot sort infinite source!");
933 typedef std::vector<StorageType> VectorType;
935 VectorType asVector() const {
936 auto comparer = [&](const StorageType& a, const StorageType& b) {
937 return comparer_(selector_(a), selector_(b));
939 auto vals = source_ | as<VectorType>();
940 std::sort(vals.begin(), vals.end(), comparer);
941 return std::move(vals);
944 Generator(Source source,
947 : source_(std::move(source)),
948 selector_(std::move(selector)),
949 comparer_(std::move(comparer)) {}
951 VectorType operator|(const Collect<VectorType>&) const {
955 VectorType operator|(const CollectTemplate<std::vector>&) const {
960 void foreach(Body&& body) const {
961 for (auto& value : asVector()) {
962 body(std::move(value));
966 template<class Handler>
967 bool apply(Handler&& handler) const {
968 auto comparer = [&](const StorageType& a, const StorageType& b) {
969 // swapped for minHeap
970 return comparer_(selector_(b), selector_(a));
972 auto heap = source_ | as<VectorType>();
973 std::make_heap(heap.begin(), heap.end(), comparer);
974 while (!heap.empty()) {
975 std::pop_heap(heap.begin(), heap.end(), comparer);
976 if (!handler(std::move(heap.back()))) {
985 template<class Source,
987 class Gen = Generator<Value, Source>>
988 Gen compose(GenImpl<Value, Source>&& source) const {
989 return Gen(std::move(source.self()), selector_, comparer_);
992 template<class Source,
994 class Gen = Generator<Value, Source>>
995 Gen compose(const GenImpl<Value, Source>& source) const {
996 return Gen(source.self(), selector_, comparer_);
1001 * GroupBy - Group values by a given key selector, producing a sequence of
1004 * This type is usually used through the 'groupBy' helper function, like:
1008 * | groupBy([](const Place& p) {
1011 * | [](Group<std::string, Place>&& g) {
1012 * cout << g.key() << ": " << (g | first).description;
1015 template <class Selector>
1016 class GroupBy : public Operator<GroupBy<Selector>> {
1022 explicit GroupBy(Selector selector) : selector_(std::move(selector)) {}
1024 template <class Value,
1026 class ValueDecayed = typename std::decay<Value>::type,
1027 class Key = typename std::result_of<Selector(Value)>::type,
1028 class KeyDecayed = typename std::decay<Key>::type>
1031 Group<KeyDecayed, ValueDecayed>&&,
1032 Generator<Value, Source, ValueDecayed, Key, KeyDecayed>> {
1033 static_assert(!Source::infinite, "Cannot group infinite source!");
1038 Generator(Source source, Selector selector)
1039 : source_(std::move(source)), selector_(std::move(selector)) {}
1041 typedef Group<KeyDecayed, ValueDecayed> GroupType;
1043 template <class Handler>
1044 bool apply(Handler&& handler) const {
1045 std::unordered_map<KeyDecayed, typename GroupType::VectorType> groups;
1046 source_ | [&](Value value) {
1047 const Value& cv = value;
1048 auto& group = groups[selector_(cv)];
1049 group.push_back(std::forward<Value>(value));
1051 for (auto& kg : groups) {
1052 GroupType group(kg.first, std::move(kg.second));
1053 if (!handler(std::move(group))) {
1062 template <class Source, class Value, class Gen = Generator<Value, Source>>
1063 Gen compose(GenImpl<Value, Source>&& source) const {
1064 return Gen(std::move(source.self()), selector_);
1067 template <class Source, class Value, class Gen = Generator<Value, Source>>
1068 Gen compose(const GenImpl<Value, Source>& source) const {
1069 return Gen(source.self(), selector_);
1074 * TypeAssertion - For verifying the exact type of the value produced by a
1075 * generator. Useful for testing and debugging, and acts as a no-op at runtime.
1076 * Pass-through at runtime. Used through the 'assert_type<>()' factory method
1079 * auto c = from(vector) | assert_type<int&>() | sum;
1082 template<class Expected>
1083 class TypeAssertion : public Operator<TypeAssertion<Expected>> {
1085 template<class Source, class Value>
1086 const Source& compose(const GenImpl<Value, Source>& source) const {
1087 static_assert(std::is_same<Expected, Value>::value,
1088 "assert_type() check failed");
1089 return source.self();
1092 template<class Source, class Value>
1093 Source&& compose(GenImpl<Value, Source>&& source) const {
1094 static_assert(std::is_same<Expected, Value>::value,
1095 "assert_type() check failed");
1096 return std::move(source.self());
1101 * Distinct - For filtering duplicates out of a sequence. A selector may be
1102 * provided to generate a key to uniquify for each value.
1104 * This type is usually used through the 'distinct' helper function, like:
1106 * auto closest = from(results)
1107 * | distinctBy([](Item& i) {
1112 template<class Selector>
1113 class Distinct : public Operator<Distinct<Selector>> {
1116 Distinct() = default;
1118 explicit Distinct(Selector selector)
1119 : selector_(std::move(selector))
1122 template<class Value,
1124 class Generator : public GenImpl<Value, Generator<Value, Source>> {
1128 typedef typename std::decay<Value>::type StorageType;
1130 // selector_ cannot be passed an rvalue or it would end up passing the husk
1131 // of a value to the downstream operators.
1132 typedef const StorageType& ParamType;
1134 typedef typename std::result_of<Selector(ParamType)>::type KeyType;
1135 typedef typename std::decay<KeyType>::type KeyStorageType;
1138 Generator(Source source,
1140 : source_(std::move(source)),
1141 selector_(std::move(selector)) {}
1143 template<class Body>
1144 void foreach(Body&& body) const {
1145 std::unordered_set<KeyStorageType> keysSeen;
1146 source_.foreach([&](Value value) {
1147 if (keysSeen.insert(selector_(ParamType(value))).second) {
1148 body(std::forward<Value>(value));
1153 template<class Handler>
1154 bool apply(Handler&& handler) const {
1155 std::unordered_set<KeyStorageType> keysSeen;
1156 return source_.apply([&](Value value) -> bool {
1157 if (keysSeen.insert(selector_(ParamType(value))).second) {
1158 return handler(std::forward<Value>(value));
1165 template<class Source,
1167 class Gen = Generator<Value, Source>>
1168 Gen compose(GenImpl<Value, Source>&& source) const {
1169 return Gen(std::move(source.self()), selector_);
1172 template<class Source,
1174 class Gen = Generator<Value, Source>>
1175 Gen compose(const GenImpl<Value, Source>& source) const {
1176 return Gen(source.self(), selector_);
1181 * Composer - Helper class for adapting pipelines into functors. Primarily used
1184 template<class Operators>
1188 explicit Composer(Operators op)
1189 : op_(std::move(op)) {}
1191 template<class Source,
1192 class Ret = decltype(std::declval<Operators>()
1193 .compose(std::declval<Source>()))>
1194 Ret operator()(Source&& source) const {
1195 return op_.compose(std::forward<Source>(source));
1200 * Batch - For producing fixed-size batches of each value from a source.
1202 * This type is usually used through the 'batch' helper function:
1207 * | map([](const std::vector<int>& batch) {
1208 * return from(batch) | sum;
1212 class Batch : public Operator<Batch> {
1215 explicit Batch(size_t batchSize)
1216 : batchSize_(batchSize) {
1217 if (batchSize_ == 0) {
1218 throw std::invalid_argument("Batch size must be non-zero!");
1222 template<class Value,
1224 class StorageType = typename std::decay<Value>::type,
1225 class VectorType = std::vector<StorageType>>
1227 public GenImpl<VectorType&,
1228 Generator<Value, Source, StorageType, VectorType>> {
1232 explicit Generator(Source source, size_t batchSize)
1233 : source_(std::move(source))
1234 , batchSize_(batchSize) {}
1236 template<class Handler>
1237 bool apply(Handler&& handler) const {
1239 batch_.reserve(batchSize_);
1240 bool shouldContinue = source_.apply([&](Value value) -> bool {
1241 batch_.push_back(std::forward<Value>(value));
1242 if (batch_.size() == batchSize_) {
1243 bool needMore = handler(batch_);
1247 // Always need more if the handler is not called.
1250 // Flush everything, if and only if `handler` hasn't returned false.
1251 if (shouldContinue && !batch_.empty()) {
1252 shouldContinue = handler(batch_);
1255 return shouldContinue;
1258 static constexpr bool infinite = Source::infinite;
1261 template<class Source,
1263 class Gen = Generator<Value, Source>>
1264 Gen compose(GenImpl<Value, Source>&& source) const {
1265 return Gen(std::move(source.self()), batchSize_);
1268 template<class Source,
1270 class Gen = Generator<Value, Source>>
1271 Gen compose(const GenImpl<Value, Source>& source) const {
1272 return Gen(source.self(), batchSize_);
1280 * FoldLeft - Left-associative functional fold. For producing an aggregate value
1281 * from a seed and a folder function. Useful for custom aggregators on a
1284 * This type is primarily used through the 'foldl' helper method, like:
1286 * double movingAverage = from(values)
1287 * | foldl(0.0, [](double avg, double sample) {
1288 * return sample * 0.1 + avg * 0.9;
1291 template<class Seed,
1293 class FoldLeft : public Operator<FoldLeft<Seed, Fold>> {
1297 FoldLeft() = default;
1300 : seed_(std::move(seed))
1301 , fold_(std::move(fold))
1304 template<class Source,
1306 Seed compose(const GenImpl<Value, Source>& source) const {
1307 static_assert(!Source::infinite, "Cannot foldl infinite source");
1309 source | [&](Value v) {
1310 accum = fold_(std::move(accum), std::forward<Value>(v));
1317 * First - For finding the first value in a sequence.
1319 * This type is primarily used through the 'first' static value, like:
1321 * int firstThreeDigitPrime = seq(100) | filter(isPrime) | first;
1323 class First : public Operator<First> {
1327 template<class Source,
1329 class StorageType = typename std::decay<Value>::type>
1330 StorageType compose(const GenImpl<Value, Source>& source) const {
1331 Optional<StorageType> accum;
1332 source | [&](Value v) -> bool {
1333 accum = std::forward<Value>(v);
1336 if (!accum.hasValue()) {
1337 throw EmptySequence();
1339 return std::move(accum.value());
1345 * Any - For determining whether any values in a sequence satisfy a predicate.
1347 * This type is primarily used through the 'any' static value, like:
1349 * bool any20xPrimes = seq(200, 210) | filter(isPrime) | any;
1351 * Note that it may also be used like so:
1353 * bool any20xPrimes = seq(200, 210) | any(isPrime);
1356 class Any : public Operator<Any> {
1360 template<class Source,
1362 bool compose(const GenImpl<Value, Source>& source) const {
1364 source | [&](Value v) -> bool {
1372 * Convenience function for use like:
1374 * bool found = gen | any([](int i) { return i * i > 100; });
1376 template<class Predicate,
1377 class Filter = Filter<Predicate>,
1378 class Composed = Composed<Filter, Any>>
1379 Composed operator()(Predicate pred) const {
1380 return Composed(Filter(std::move(pred)), Any());
1385 * All - For determining whether all values in a sequence satisfy a predicate.
1387 * This type is primarily used through the 'any' static value, like:
1389 * bool valid = from(input) | all(validate);
1391 * Note: Passing an empty sequence through 'all()' will always return true.
1393 template<class Predicate>
1394 class All : public Operator<All<Predicate>> {
1398 explicit All(Predicate pred)
1399 : pred_(std::move(pred))
1402 template<class Source,
1404 bool compose(const GenImpl<Value, Source>& source) const {
1405 static_assert(!Source::infinite, "Cannot call 'all' on infinite source");
1407 source | [&](Value v) -> bool {
1408 if (!pred_(std::forward<Value>(v))) {
1419 * Reduce - Functional reduce, for recursively combining values from a source
1420 * using a reducer function until there is only one item left. Useful for
1421 * combining values when an empty sequence doesn't make sense.
1423 * This type is primarily used through the 'reduce' helper method, like:
1425 * sring longest = from(names)
1426 * | reduce([](string&& best, string& current) {
1427 * return best.size() >= current.size() ? best : current;
1430 template<class Reducer>
1431 class Reduce : public Operator<Reduce<Reducer>> {
1435 explicit Reduce(Reducer reducer)
1436 : reducer_(std::move(reducer))
1439 template<class Source,
1441 class StorageType = typename std::decay<Value>::type>
1442 StorageType compose(const GenImpl<Value, Source>& source) const {
1443 Optional<StorageType> accum;
1444 source | [&](Value v) {
1445 if (accum.hasValue()) {
1446 accum = reducer_(std::move(accum.value()), std::forward<Value>(v));
1448 accum = std::forward<Value>(v);
1451 if (!accum.hasValue()) {
1452 throw EmptySequence();
1454 return accum.value();
1459 * Count - for simply counting the items in a collection.
1461 * This type is usually used through its singleton, 'count':
1463 * auto shortPrimes = seq(1, 100) | filter(isPrime) | count;
1465 class Count : public Operator<Count> {
1469 template<class Source,
1471 size_t compose(const GenImpl<Value, Source>& source) const {
1472 static_assert(!Source::infinite, "Cannot count infinite source");
1473 return foldl(size_t(0),
1474 [](size_t accum, Value v) {
1481 * Sum - For simply summing up all the values from a source.
1483 * This type is usually used through its singleton, 'sum':
1485 * auto gaussSum = seq(1, 100) | sum;
1487 class Sum : public Operator<Sum> {
1489 Sum() : Operator<Sum>() {}
1491 template<class Source,
1493 class StorageType = typename std::decay<Value>::type>
1494 StorageType compose(const GenImpl<Value, Source>& source) const {
1495 static_assert(!Source::infinite, "Cannot sum infinite source");
1496 return foldl(StorageType(0),
1497 [](StorageType&& accum, Value v) {
1498 return std::move(accum) + std::forward<Value>(v);
1504 * Contains - For testing whether a value matching the given value is contained
1507 * This type should be used through the 'contains' helper method, like:
1509 * bool contained = seq(1, 10) | map(square) | contains(49);
1511 template<class Needle>
1512 class Contains : public Operator<Contains<Needle>> {
1515 explicit Contains(Needle needle)
1516 : needle_(std::move(needle))
1519 template<class Source,
1521 class StorageType = typename std::decay<Value>::type>
1522 bool compose(const GenImpl<Value, Source>& source) const {
1523 static_assert(!Source::infinite,
1524 "Calling contains on an infinite source might cause "
1525 "an infinite loop.");
1526 return !(source | [this](Value value) {
1527 return !(needle_ == std::forward<Value>(value));
1533 * Min - For a value which minimizes a key, where the key is determined by a
1534 * given selector, and compared by given comparer.
1536 * This type is usually used through the singletone 'min' or through the helper
1537 * functions 'minBy' and 'maxBy'.
1539 * auto oldest = from(people)
1540 * | minBy([](Person& p) {
1541 * return p.dateOfBirth;
1544 template<class Selector,
1546 class Min : public Operator<Min<Selector, Comparer>> {
1552 explicit Min(Selector selector)
1553 : selector_(std::move(selector))
1556 Min(Selector selector,
1558 : selector_(std::move(selector))
1559 , comparer_(std::move(comparer))
1562 template<class Value,
1564 class StorageType = typename std::decay<Value>::type,
1565 class Key = typename std::decay<
1566 typename std::result_of<Selector(Value)>::type
1568 StorageType compose(const GenImpl<Value, Source>& source) const {
1569 Optional<StorageType> min;
1570 Optional<Key> minKey;
1571 source | [&](Value v) {
1572 Key key = selector_(std::forward<Value>(v));
1573 if (!minKey.hasValue() || comparer_(key, minKey.value())) {
1575 min = std::forward<Value>(v);
1578 if (!min.hasValue()) {
1579 throw EmptySequence();
1586 * Append - For collecting values from a source into a given output container
1589 * This type is usually used through the helper function 'appendTo', like:
1591 * vector<int64_t> ids;
1592 * from(results) | map([](Person& p) { return p.id })
1595 template<class Collection>
1596 class Append : public Operator<Append<Collection>> {
1597 Collection* collection_;
1599 explicit Append(Collection* collection)
1600 : collection_(collection)
1603 template<class Value,
1605 Collection& compose(const GenImpl<Value, Source>& source) const {
1606 source | [&](Value v) {
1607 collection_->insert(collection_->end(), std::forward<Value>(v));
1609 return *collection_;
1614 * Collect - For collecting values from a source in a collection of the desired
1617 * This type is usually used through the helper function 'as', like:
1619 * std::string upper = from(stringPiece)
1621 * | as<std::string>();
1623 template<class Collection>
1624 class Collect : public Operator<Collect<Collection>> {
1626 Collect() = default;
1628 template<class Value,
1630 class StorageType = typename std::decay<Value>::type>
1631 Collection compose(const GenImpl<Value, Source>& source) const {
1632 Collection collection;
1633 source | [&](Value v) {
1634 collection.insert(collection.end(), std::forward<Value>(v));
1642 * CollectTemplate - For collecting values from a source in a collection
1643 * constructed using the specified template type. Given the type of values
1644 * produced by the given generator, the collection type will be:
1645 * Container<Value, Allocator<Value>>
1647 * The allocator defaults to std::allocator, so this may be used for the STL
1648 * containers by simply using operators like 'as<set>', 'as<deque>',
1649 * 'as<vector>'. 'as', here is the helper method which is the usual means of
1650 * consturcting this operator.
1654 * set<string> uniqueNames = from(names) | as<set>();
1656 template<template<class, class> class Container,
1657 template<class> class Allocator>
1658 class CollectTemplate : public Operator<CollectTemplate<Container, Allocator>> {
1660 CollectTemplate() = default;
1662 template<class Value,
1664 class StorageType = typename std::decay<Value>::type,
1665 class Collection = Container<StorageType, Allocator<StorageType>>>
1666 Collection compose(const GenImpl<Value, Source>& source) const {
1667 Collection collection;
1668 source | [&](Value v) {
1669 collection.insert(collection.end(), std::forward<Value>(v));
1676 * Concat - For flattening generators of generators.
1678 * This type is usually used through the 'concat' static value, like:
1682 * | map([](Node& x) {
1683 * return from(x.neighbors)
1684 * | map([&](Node& y) {
1685 * return Edge(x, y);
1691 class Concat : public Operator<Concat> {
1695 template<class Inner,
1697 class InnerValue = typename std::decay<Inner>::type::ValueType>
1699 public GenImpl<InnerValue, Generator<Inner, Source, InnerValue>> {
1702 explicit Generator(Source source)
1703 : source_(std::move(source)) {}
1705 template<class Handler>
1706 bool apply(Handler&& handler) const {
1707 return source_.apply([&](Inner inner) -> bool {
1708 return inner.apply(std::forward<Handler>(handler));
1712 template<class Body>
1713 void foreach(Body&& body) const {
1714 source_.foreach([&](Inner inner) {
1715 inner.foreach(std::forward<Body>(body));
1719 static constexpr bool infinite = Source::infinite;
1722 template<class Value,
1724 class Gen = Generator<Value, Source>>
1725 Gen compose(GenImpl<Value, Source>&& source) const {
1726 return Gen(std::move(source.self()));
1729 template<class Value,
1731 class Gen = Generator<Value, Source>>
1732 Gen compose(const GenImpl<Value, Source>& source) const {
1733 return Gen(source.self());
1738 * RangeConcat - For flattening generators of iterables.
1740 * This type is usually used through the 'rconcat' static value, like:
1742 * map<int, vector<int>> adjacency;
1749 class RangeConcat : public Operator<RangeConcat> {
1751 RangeConcat() = default;
1753 template<class Range,
1755 class InnerValue = typename ValueTypeOfRange<Range>::RefType>
1757 : public GenImpl<InnerValue, Generator<Range, Source, InnerValue>> {
1760 explicit Generator(Source source)
1761 : source_(std::move(source)) {}
1763 template<class Body>
1764 void foreach(Body&& body) const {
1765 source_.foreach([&](Range range) {
1766 for (auto& value : range) {
1772 template<class Handler>
1773 bool apply(Handler&& handler) const {
1774 return source_.apply([&](Range range) -> bool {
1775 for (auto& value : range) {
1776 if (!handler(value)) {
1785 template<class Value,
1787 class Gen = Generator<Value, Source>>
1788 Gen compose(GenImpl<Value, Source>&& source) const {
1789 return Gen(std::move(source.self()));
1792 template<class Value,
1794 class Gen = Generator<Value, Source>>
1795 Gen compose(const GenImpl<Value, Source>& source) const {
1796 return Gen(source.self());
1802 * GuardImpl - For handling exceptions from downstream computation. Requires the
1803 * type of exception to catch, and handler function to invoke in the event of
1804 * the exception. Note that the handler may:
1805 * 1) return true to continue processing the sequence
1806 * 2) return false to end the sequence immediately
1807 * 3) throw, to pass the exception to the next catch
1808 * The handler must match the signature 'bool(Exception&, Value)'.
1810 * This type is used through the `guard` helper, like so:
1813 * = byLine(STDIN_FILENO)
1814 * | guard<std::runtime_error>([](std::runtime_error& e,
1816 * LOG(ERROR) << sp << ": " << e.str();
1817 * return true; // continue processing subsequent lines
1822 * TODO(tjackson): Rename this back to Guard.
1824 template<class Exception,
1826 class GuardImpl : public Operator<GuardImpl<Exception, ErrorHandler>> {
1827 ErrorHandler handler_;
1829 explicit GuardImpl(ErrorHandler handler) : handler_(std::move(handler)) {}
1831 template<class Value,
1833 class Generator : public GenImpl<Value, Generator<Value, Source>> {
1835 ErrorHandler handler_;
1837 explicit Generator(Source source,
1838 ErrorHandler handler)
1839 : source_(std::move(source)),
1840 handler_(std::move(handler)) {}
1842 template<class Handler>
1843 bool apply(Handler&& handler) const {
1844 return source_.apply([&](Value value) -> bool {
1846 handler(std::forward<Value>(value));
1848 } catch (Exception& e) {
1849 return handler_(e, std::forward<Value>(value));
1854 static constexpr bool infinite = Source::infinite;
1857 template<class Value,
1859 class Gen = Generator<Value, Source>>
1860 Gen compose(GenImpl<Value, Source>&& source) const {
1861 return Gen(std::move(source.self()), handler_);
1864 template<class Value,
1866 class Gen = Generator<Value, Source>>
1867 Gen compose(const GenImpl<Value, Source>& source) const {
1868 return Gen(source.self(), handler_);
1873 * Cycle - For repeating a sequence forever.
1875 * This type is usually used through the 'cycle' static value, like:
1882 class Cycle : public Operator<Cycle> {
1883 off_t limit_; // -1 for infinite
1888 explicit Cycle(off_t limit)
1891 template<class Value,
1893 class Generator : public GenImpl<Value, Generator<Value, Source>> {
1895 off_t limit_; // -1 for infinite
1897 explicit Generator(Source source, off_t limit)
1898 : source_(std::move(source))
1901 template<class Handler>
1902 bool apply(Handler&& handler) const {
1904 auto handler2 = [&](Value value) {
1905 cont = handler(std::forward<Value>(value));
1908 for (off_t count = 0; count != limit_; ++count) {
1910 source_.apply(handler2);
1918 // not actually infinite, since an empty generator will end the cycles.
1919 static constexpr bool infinite = Source::infinite;
1922 template<class Source,
1924 class Gen = Generator<Value, Source>>
1925 Gen compose(GenImpl<Value, Source>&& source) const {
1926 return Gen(std::move(source.self()), limit_);
1929 template<class Source,
1931 class Gen = Generator<Value, Source>>
1932 Gen compose(const GenImpl<Value, Source>& source) const {
1933 return Gen(source.self(), limit_);
1937 * Convenience function for use like:
1939 * auto tripled = gen | cycle(3);
1941 Cycle operator()(off_t limit) const {
1942 return Cycle(limit);
1947 * Dereference - For dereferencing a sequence of pointers while filtering out
1950 * This type is usually used through the 'dereference' static value, like:
1952 * auto refs = from(ptrs) | dereference;
1954 class Dereference : public Operator<Dereference> {
1956 Dereference() = default;
1958 template<class Value,
1960 class Result = decltype(*std::declval<Value>())>
1961 class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
1964 explicit Generator(Source source)
1965 : source_(std::move(source)) {}
1967 template<class Body>
1968 void foreach(Body&& body) const {
1969 source_.foreach([&](Value value) {
1971 return body(*value);
1976 template<class Handler>
1977 bool apply(Handler&& handler) const {
1978 return source_.apply([&](Value value) -> bool {
1980 return handler(*value);
1986 // not actually infinite, since an empty generator will end the cycles.
1987 static constexpr bool infinite = Source::infinite;
1990 template<class Source,
1992 class Gen = Generator<Value, Source>>
1993 Gen compose(GenImpl<Value, Source>&& source) const {
1994 return Gen(std::move(source.self()));
1997 template<class Source,
1999 class Gen = Generator<Value, Source>>
2000 Gen compose(const GenImpl<Value, Source>& source) const {
2001 return Gen(source.self());
2006 * Indirect - For producing a sequence of the addresses of the values in the
2009 * This type is usually used through the 'indirect' static value, like:
2011 * auto ptrs = from(refs) | indirect;
2013 class Indirect : public Operator<Indirect> {
2015 Indirect() = default;
2017 template <class Value,
2019 class Result = typename std::remove_reference<Value>::type*>
2020 class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
2022 static_assert(!std::is_rvalue_reference<Value>::value,
2023 "Cannot use indirect on an rvalue");
2026 explicit Generator(Source source) : source_(std::move(source)) {}
2028 template <class Body>
2029 void foreach(Body&& body) const {
2030 source_.foreach([&](Value value) {
2031 return body(&value);
2035 template <class Handler>
2036 bool apply(Handler&& handler) const {
2037 return source_.apply([&](Value value) -> bool {
2038 return handler(&value);
2042 // not actually infinite, since an empty generator will end the cycles.
2043 static constexpr bool infinite = Source::infinite;
2046 template <class Source, class Value, class Gen = Generator<Value, Source>>
2047 Gen compose(GenImpl<Value, Source>&& source) const {
2048 return Gen(std::move(source.self()));
2051 template <class Source, class Value, class Gen = Generator<Value, Source>>
2052 Gen compose(const GenImpl<Value, Source>& source) const {
2053 return Gen(source.self());
2060 * VirtualGen<T> - For wrapping template types in simple polymorphic wrapper.
2062 template<class Value>
2063 class VirtualGen : public GenImpl<Value, VirtualGen<Value>> {
2066 virtual ~WrapperBase() noexcept {}
2067 virtual bool apply(const std::function<bool(Value)>& handler) const = 0;
2068 virtual void foreach(const std::function<void(Value)>& body) const = 0;
2069 virtual std::unique_ptr<const WrapperBase> clone() const = 0;
2072 template<class Wrapped>
2073 class WrapperImpl : public WrapperBase {
2076 explicit WrapperImpl(Wrapped wrapped)
2077 : wrapped_(std::move(wrapped)) {
2080 virtual bool apply(const std::function<bool(Value)>& handler) const {
2081 return wrapped_.apply(handler);
2084 virtual void foreach(const std::function<void(Value)>& body) const {
2085 wrapped_.foreach(body);
2088 virtual std::unique_ptr<const WrapperBase> clone() const {
2089 return std::unique_ptr<const WrapperBase>(new WrapperImpl(wrapped_));
2093 std::unique_ptr<const WrapperBase> wrapper_;
2096 template <class Self>
2097 /* implicit */ VirtualGen(Self source)
2098 : wrapper_(new WrapperImpl<Self>(std::move(source))) {}
2100 VirtualGen(VirtualGen&& source) noexcept
2101 : wrapper_(std::move(source.wrapper_)) {}
2103 VirtualGen(const VirtualGen& source)
2104 : wrapper_(source.wrapper_->clone()) {}
2106 VirtualGen& operator=(const VirtualGen& source) {
2107 wrapper_.reset(source.wrapper_->clone());
2111 VirtualGen& operator=(VirtualGen&& source) noexcept {
2112 wrapper_= std::move(source.wrapper_);
2116 bool apply(const std::function<bool(Value)>& handler) const {
2117 return wrapper_->apply(handler);
2120 void foreach(const std::function<void(Value)>& body) const {
2121 wrapper_->foreach(body);
2126 * non-template operators, statically defined to avoid the need for anything but
2129 static const detail::Sum sum{};
2131 static const detail::Count count{};
2133 static const detail::First first{};
2136 * Use directly for detecting any values, or as a function to detect values
2137 * which pass a predicate:
2139 * auto nonempty = g | any;
2140 * auto evens = g | any(even);
2142 static const detail::Any any{};
2144 static const detail::Min<Identity, Less> min{};
2146 static const detail::Min<Identity, Greater> max{};
2148 static const detail::Order<Identity> order{};
2150 static const detail::Distinct<Identity> distinct{};
2152 static const detail::Map<Move> move{};
2154 static const detail::Concat concat{};
2156 static const detail::RangeConcat rconcat{};
2159 * Use directly for infinite sequences, or as a function to limit cycle count.
2161 * auto forever = g | cycle;
2162 * auto thrice = g | cycle(3);
2164 static const detail::Cycle cycle{};
2166 static const detail::Dereference dereference{};
2168 static const detail::Indirect indirect{};
2170 inline detail::Take take(size_t count) {
2171 return detail::Take(count);
2174 inline detail::Stride stride(size_t s) {
2175 return detail::Stride(s);
2178 template<class Random = std::default_random_engine>
2179 inline detail::Sample<Random> sample(size_t count, Random rng = Random()) {
2180 return detail::Sample<Random>(count, std::move(rng));
2183 inline detail::Skip skip(size_t count) {
2184 return detail::Skip(count);
2187 inline detail::Batch batch(size_t batchSize) {
2188 return detail::Batch(batchSize);
2193 #pragma GCC diagnostic pop