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.
17 // Ignore shadowing warnings within this file, so includers can use -Wshadow.
18 #pragma GCC diagnostic push
19 #pragma GCC diagnostic ignored "-Wshadow"
21 namespace folly { namespace gen {
24 * IsCompatibleSignature - Trait type for testing whether a given Functor
25 * matches an expected signature.
28 * IsCompatibleSignature<FunctorType, bool(int, float)>::value
30 template<class Candidate, class Expected>
31 class IsCompatibleSignature {
32 static constexpr bool value = false;
35 template<class Candidate,
38 class IsCompatibleSignature<Candidate, ExpectedReturn(ArgTypes...)> {
41 decltype(std::declval<F>()(std::declval<ArgTypes>()...)),
42 bool good = std::is_same<ExpectedReturn, ActualReturn>::value>
43 static constexpr bool testArgs(int* p) {
48 static constexpr bool testArgs(...) {
52 static constexpr bool value = testArgs<Candidate>(nullptr);
56 * ArgumentReference - For determining ideal argument type to receive a value.
59 struct ArgumentReference :
60 public std::conditional<std::is_reference<T>::value,
61 T, // T& -> T&, T&& -> T&&, const T& -> const T&
62 typename std::conditional<
63 std::is_const<T>::value,
64 T&, // const int -> const int&
69 * FBounded - Helper type for the curiously recurring template pattern, used
70 * heavily here to enable inlining and obviate virtual functions
74 const Self& self() const {
75 return *static_cast<const Self*>(this);
79 return *static_cast<Self*>(this);
84 * Operator - Core abstraction of an operation which may be applied to a
85 * generator. All operators implement a method compose(), which takes a
86 * generator and produces an output generator.
89 class Operator : public FBounded<Self> {
92 * compose() - Must be implemented by child class to compose a new Generator
93 * out of a given generator. This function left intentionally unimplemented.
95 template<class Source,
97 class ResultGen = void>
98 ResultGen compose(const GenImpl<Value, Source>& source) const;
101 Operator() = default;
102 Operator(const Operator&) = default;
103 Operator(Operator&&) = default;
107 * operator|() - For composing two operators without binding it to a
108 * particular generator.
112 class Composed = detail::Composed<Left, Right>>
113 Composed operator|(const Operator<Left>& left,
114 const Operator<Right>& right) {
115 return Composed(left.self(), right.self());
120 class Composed = detail::Composed<Left, Right>>
121 Composed operator|(const Operator<Left>& left,
122 Operator<Right>&& right) {
123 return Composed(left.self(), std::move(right.self()));
128 class Composed = detail::Composed<Left, Right>>
129 Composed operator|(Operator<Left>&& left,
130 const Operator<Right>& right) {
131 return Composed(std::move(left.self()), right.self());
136 class Composed = detail::Composed<Left, Right>>
137 Composed operator|(Operator<Left>&& left,
138 Operator<Right>&& right) {
139 return Composed(std::move(left.self()), std::move(right.self()));
143 * GenImpl - Core abstraction of a generator, an object which produces values by
144 * passing them to a given handler lambda. All generator implementations must
145 * implement apply(). foreach() may also be implemented to special case the
146 * condition where the entire sequence is consumed.
148 template<class Value,
150 class GenImpl : public FBounded<Self> {
152 // To prevent slicing
154 GenImpl(const GenImpl&) = default;
155 GenImpl(GenImpl&&) = default;
158 typedef Value ValueType;
159 typedef typename std::decay<Value>::type StorageType;
162 * apply() - Send all values produced by this generator to given handler until
163 * the handler returns false. Returns false if and only if the handler passed
164 * in returns false. Note: It should return true even if it completes (without
165 * the handler returning false), as 'Chain' uses the return value of apply to
166 * determine if it should process the second object in its chain.
168 template<class Handler>
169 bool apply(Handler&& handler) const;
172 * foreach() - Send all values produced by this generator to given lambda.
175 void foreach(Body&& body) const {
176 this->self().apply([&](Value value) -> bool {
177 static_assert(!infinite, "Cannot call foreach on infinite GenImpl");
178 body(std::forward<Value>(value));
183 // Child classes should override if the sequence generated is *definitely*
184 // infinite. 'infinite' may be false_type for some infinite sequences
185 // (due the the Halting Problem).
186 static constexpr bool infinite = false;
189 template<class LeftValue,
193 class Chain = detail::Chain<LeftValue, Left, Right>>
194 Chain operator+(const GenImpl<LeftValue, Left>& left,
195 const GenImpl<RightValue, Right>& right) {
197 std::is_same<LeftValue, RightValue>::value,
198 "Generators may ony be combined if Values are the exact same type.");
199 return Chain(left.self(), right.self());
202 template<class LeftValue,
206 class Chain = detail::Chain<LeftValue, Left, Right>>
207 Chain operator+(const GenImpl<LeftValue, Left>& left,
208 GenImpl<RightValue, Right>&& right) {
210 std::is_same<LeftValue, RightValue>::value,
211 "Generators may ony be combined if Values are the exact same type.");
212 return Chain(left.self(), std::move(right.self()));
215 template<class LeftValue,
219 class Chain = detail::Chain<LeftValue, Left, Right>>
220 Chain operator+(GenImpl<LeftValue, Left>&& left,
221 const GenImpl<RightValue, Right>& right) {
223 std::is_same<LeftValue, RightValue>::value,
224 "Generators may ony be combined if Values are the exact same type.");
225 return Chain(std::move(left.self()), right.self());
228 template<class LeftValue,
232 class Chain = detail::Chain<LeftValue, Left, Right>>
233 Chain operator+(GenImpl<LeftValue, Left>&& left,
234 GenImpl<RightValue, Right>&& right) {
236 std::is_same<LeftValue, RightValue>::value,
237 "Generators may ony be combined if Values are the exact same type.");
238 return Chain(std::move(left.self()), std::move(right.self()));
242 * operator|() which enables foreach-like usage:
243 * gen | [](Value v) -> void {...};
245 template<class Value,
248 typename std::enable_if<
249 IsCompatibleSignature<Handler, void(Value)>::value>::type
250 operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
251 static_assert(!Gen::infinite,
252 "Cannot pull all values from an infinite sequence.");
253 gen.self().foreach(std::forward<Handler>(handler));
257 * operator|() which enables foreach-like usage with 'break' support:
258 * gen | [](Value v) -> bool { return shouldContinue(); };
260 template<class Value,
263 typename std::enable_if<
264 IsCompatibleSignature<Handler, bool(Value)>::value, bool>::type
265 operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
266 return gen.self().apply(std::forward<Handler>(handler));
270 * operator|() for composing generators with operators, similar to boosts' range
272 * gen | map(square) | sum
274 template<class Value,
277 auto operator|(const GenImpl<Value, Gen>& gen, const Operator<Op>& op) ->
278 decltype(op.self().compose(gen.self())) {
279 return op.self().compose(gen.self());
282 template<class Value,
285 auto operator|(GenImpl<Value, Gen>&& gen, const Operator<Op>& op) ->
286 decltype(op.self().compose(std::move(gen.self()))) {
287 return op.self().compose(std::move(gen.self()));
293 * ReferencedSource - Generate values from an STL-like container using
294 * iterators from .begin() until .end(). Value type defaults to the type of
295 * *container->begin(). For std::vector<int>, this would be int&. Note that the
296 * value here is a reference, so the values in the vector will be passed by
297 * reference to downstream operators.
299 * This type is primarily used through the 'from' helper method, like:
301 * string& longestName = from(names)
302 * | maxBy([](string& s) { return s.size() });
304 template<class Container,
306 class ReferencedSource :
307 public GenImpl<Value, ReferencedSource<Container, Value>> {
308 Container* container_;
310 explicit ReferencedSource(Container* container)
311 : container_(container) {}
314 void foreach(Body&& body) const {
315 for (auto& value : *container_) {
316 body(std::forward<Value>(value));
320 template<class Handler>
321 bool apply(Handler&& handler) const {
322 for (auto& value : *container_) {
323 if (!handler(std::forward<Value>(value))) {
332 * CopiedSource - For producing values from eagerly from a sequence of values
333 * whose storage is owned by this class. Useful for preparing a generator for
334 * use after a source collection will no longer be available, or for when the
335 * values are specified literally with an initializer list.
337 * This type is primarily used through the 'fromCopy' function, like:
339 * auto sourceCopy = fromCopy(makeAVector());
340 * auto sum = sourceCopy | sum;
341 * auto max = sourceCopy | max;
343 * Though it is also used for the initializer_list specialization of from().
345 template<class StorageType,
348 public GenImpl<const StorageType&,
349 CopiedSource<StorageType, Container>> {
351 !std::is_reference<StorageType>::value, "StorageType must be decayed");
353 // Generator objects are often copied during normal construction as they are
354 // encapsulated by downstream generators. It would be bad if this caused
355 // a copy of the entire container each time, and since we're only exposing a
356 // const reference to the value, it's safe to share it between multiple
359 !std::is_reference<Container>::value,
360 "Can't copy into a reference");
361 std::shared_ptr<const Container> copy_;
363 typedef Container ContainerType;
365 template<class SourceContainer>
366 explicit CopiedSource(const SourceContainer& container)
367 : copy_(new Container(begin(container), end(container))) {}
369 explicit CopiedSource(Container&& container) :
370 copy_(new Container(std::move(container))) {}
372 // To enable re-use of cached results.
373 CopiedSource(const CopiedSource<StorageType, Container>& source)
374 : copy_(source.copy_) {}
377 void foreach(Body&& body) const {
378 for (const auto& value : *copy_) {
383 template<class Handler>
384 bool apply(Handler&& handler) const {
385 // The collection may be reused by others, we can't allow it to be changed.
386 for (const auto& value : *copy_) {
387 if (!handler(value)) {
396 * Sequence - For generating values from beginning value, incremented along the
397 * way with the ++ and += operators. Iteration may continue indefinitely by
398 * setting the 'endless' template parameter to true. If set to false, iteration
399 * will stop when value reaches 'end', either inclusively or exclusively,
400 * depending on the template parameter 'endInclusive'. Value type specified
403 * This type is primarily used through the 'seq' and 'range' function, like:
405 * int total = seq(1, 10) | sum;
406 * auto indexes = range(0, 10);
408 template<class Value,
411 class Sequence : public GenImpl<const Value&,
412 Sequence<Value, endless, endInclusive>> {
413 static_assert(!std::is_reference<Value>::value &&
414 !std::is_const<Value>::value, "Value mustn't be const or ref.");
415 Value bounds_[endless ? 1 : 2];
417 explicit Sequence(Value begin)
418 : bounds_{std::move(begin)} {
419 static_assert(endless, "Must supply 'end'");
422 Sequence(Value begin,
424 : bounds_{std::move(begin), std::move(end)} {}
426 template<class Handler>
427 bool apply(Handler&& handler) const {
428 Value value = bounds_[0];
429 for (;endless || value < bounds_[1]; ++value) {
430 const Value& arg = value;
435 if (endInclusive && value == bounds_[1]) {
436 const Value& arg = value;
445 void foreach(Body&& body) const {
446 Value value = bounds_[0];
447 for (;endless || value < bounds_[1]; ++value) {
448 const Value& arg = value;
451 if (endInclusive && value == bounds_[1]) {
452 const Value& arg = value;
457 static constexpr bool infinite = endless;
461 * Chain - For concatenating the values produced by two Generators.
463 * This type is primarily used through using '+' to combine generators, like:
465 * auto nums = seq(1, 10) + seq(20, 30);
466 * int total = nums | sum;
468 template<class Value, class First, class Second>
469 class Chain : public GenImpl<Value,
470 Chain<Value, First, Second>> {
474 explicit Chain(First first, Second second)
475 : first_(std::move(first))
476 , second_(std::move(second)) {}
478 template<class Handler>
479 bool apply(Handler&& handler) const {
480 return first_.apply(std::forward<Handler>(handler))
481 && second_.apply(std::forward<Handler>(handler));
485 void foreach(Body&& body) const {
486 first_.foreach(std::forward<Body>(body));
487 second_.foreach(std::forward<Body>(body));
490 static constexpr bool infinite = First::infinite || Second::infinite;
494 * GenratorBuilder - Helper for GENERTATOR macro.
496 template<class Value>
497 struct GeneratorBuilder {
498 template<class Source,
499 class Yield = detail::Yield<Value, Source>>
500 Yield operator+(Source&& source) {
501 return Yield(std::forward<Source>(source));
506 * Yield - For producing values from a user-defined generator by way of a
509 template<class Value, class Source>
510 class Yield : public GenImpl<Value, Yield<Value, Source>> {
513 explicit Yield(Source source)
514 : source_(std::move(source)) {
517 template<class Handler>
518 bool apply(Handler&& handler) const {
520 auto body = [&](Value value) {
521 if (!handler(std::forward<Value>(value))) {
534 void foreach(Body&& body) const {
535 source_(std::forward<Body>(body));
539 template<class Value>
540 class Empty : public GenImpl<Value, Empty<Value>> {
542 template<class Handler>
543 bool apply(Handler&&) const { return true; }
551 * Map - For producing a sequence of values by passing each value from a source
552 * collection through a predicate.
554 * This type is usually used through the 'map' or 'mapped' helper function:
556 * auto squares = seq(1, 10) | map(square) | asVector;
558 template<class Predicate>
559 class Map : public Operator<Map<Predicate>> {
564 explicit Map(Predicate pred)
565 : pred_(std::move(pred))
568 template<class Value,
570 class Result = typename ArgumentReference<
571 typename std::result_of<Predicate(Value)>::type
574 public GenImpl<Result, Generator<Value, Source, Result>> {
578 explicit Generator(Source source, const Predicate& pred)
579 : source_(std::move(source)), pred_(pred) {}
582 void foreach(Body&& body) const {
583 source_.foreach([&](Value value) {
584 body(pred_(std::forward<Value>(value)));
588 template<class Handler>
589 bool apply(Handler&& handler) const {
590 return source_.apply([&](Value value) {
591 return handler(pred_(std::forward<Value>(value)));
595 static constexpr bool infinite = Source::infinite;
598 template<class Source,
600 class Gen = Generator<Value, Source>>
601 Gen compose(GenImpl<Value, Source>&& source) const {
602 return Gen(std::move(source.self()), pred_);
605 template<class Source,
607 class Gen = Generator<Value, Source>>
608 Gen compose(const GenImpl<Value, Source>& source) const {
609 return Gen(source.self(), pred_);
615 * Filter - For filtering values from a source sequence by a predicate.
617 * This type is usually used through the 'filter' helper function, like:
619 * auto nonEmpty = from(strings)
620 * | filter([](const string& str) -> bool {
621 * return !str.empty();
624 template<class Predicate>
625 class Filter : public Operator<Filter<Predicate>> {
629 explicit Filter(Predicate pred)
630 : pred_(std::move(pred))
633 template<class Value,
635 class Generator : public GenImpl<Value, Generator<Value, Source>> {
639 explicit Generator(Source source, const Predicate& pred)
640 : source_(std::move(source)), pred_(pred) {}
643 void foreach(Body&& body) const {
644 source_.foreach([&](Value value) {
645 if (pred_(std::forward<Value>(value))) {
646 body(std::forward<Value>(value));
651 template<class Handler>
652 bool apply(Handler&& handler) const {
653 return source_.apply([&](Value value) -> bool {
654 if (pred_(std::forward<Value>(value))) {
655 return handler(std::forward<Value>(value));
661 static constexpr bool infinite = Source::infinite;
664 template<class Source,
666 class Gen = Generator<Value, Source>>
667 Gen compose(GenImpl<Value, Source>&& source) const {
668 return Gen(std::move(source.self()), pred_);
671 template<class Source,
673 class Gen = Generator<Value, Source>>
674 Gen compose(const GenImpl<Value, Source>& source) const {
675 return Gen(source.self(), pred_);
680 * Until - For producing values from a source until a predicate is satisfied.
682 * This type is usually used through the 'until' helper function, like:
684 * auto best = from(sortedItems)
685 * | until([](Item& item) { return item.score > 100; })
688 template<class Predicate>
689 class Until : public Operator<Until<Predicate>> {
693 explicit Until(Predicate pred)
694 : pred_(std::move(pred))
697 template<class Value,
699 class Generator : public GenImpl<Value, Generator<Value, Source>> {
703 explicit Generator(Source source, const Predicate& pred)
704 : source_(std::move(source)), pred_(pred) {}
706 template<class Handler>
707 bool apply(Handler&& handler) const {
708 bool cancelled = false;
709 source_.apply([&](Value value) -> bool {
710 if (pred_(value)) { // un-forwarded to disable move
713 if (!handler(std::forward<Value>(value))) {
723 template<class Source,
725 class Gen = Generator<Value, Source>>
726 Gen compose(GenImpl<Value, Source>&& source) const {
727 return Gen(std::move(source.self()), pred_);
730 template<class Source,
732 class Gen = Generator<Value, Source>>
733 Gen compose(const GenImpl<Value, Source>& source) const {
734 return Gen(source.self(), pred_);
737 // Theoretically an 'until' might stop an infinite
738 static constexpr bool infinite = false;
742 * Take - For producing up to N values from a source.
744 * This type is usually used through the 'take' helper function, like:
746 * auto best = from(docs)
747 * | orderByDescending(scoreDoc)
750 class Take : public Operator<Take> {
753 explicit Take(size_t count)
756 template<class Value,
759 public GenImpl<Value, Generator<Value, Source>> {
763 explicit Generator(Source source, size_t count)
764 : source_(std::move(source)) , count_(count) {}
766 template<class Handler>
767 bool apply(Handler&& handler) const {
768 if (count_ == 0) { return false; }
770 bool cancelled = false;
771 source_.apply([&](Value value) -> bool {
772 if (!handler(std::forward<Value>(value))) {
782 template<class Source,
784 class Gen = Generator<Value, Source>>
785 Gen compose(GenImpl<Value, Source>&& source) const {
786 return Gen(std::move(source.self()), count_);
789 template<class Source,
791 class Gen = Generator<Value, Source>>
792 Gen compose(const GenImpl<Value, Source>& source) const {
793 return Gen(source.self(), count_);
798 * Sample - For taking a random sample of N elements from a sequence
799 * (without replacement).
801 template<class Random>
802 class Sample : public Operator<Sample<Random>> {
806 explicit Sample(size_t count, Random rng)
807 : count_(count), rng_(std::move(rng)) {}
809 template<class Value,
812 class StorageType = typename std::decay<Value>::type>
814 public GenImpl<StorageType&&,
815 Generator<Value, Source, Rand, StorageType>> {
816 static_assert(!Source::infinite, "Cannot sample infinite source!");
817 // It's too easy to bite ourselves if random generator is only 16-bit
818 static_assert(Random::max() >= std::numeric_limits<int32_t>::max() - 1,
819 "Random number generator must support big values");
824 explicit Generator(Source source, size_t count, Random rng)
825 : source_(std::move(source)) , count_(count), rng_(std::move(rng)) {}
827 template<class Handler>
828 bool apply(Handler&& handler) const {
829 if (count_ == 0) { return false; }
830 std::vector<StorageType> v;
832 // use reservoir sampling to give each source value an equal chance
833 // of appearing in our output.
835 source_.foreach([&](Value value) -> void {
836 if (v.size() < count_) {
837 v.push_back(std::forward<Value>(value));
839 // alternatively, we could create a std::uniform_int_distribution
840 // instead of using modulus, but benchmarks show this has
841 // substantial overhead.
842 size_t index = rng_() % n;
843 if (index < v.size()) {
844 v[index] = std::forward<Value>(value);
850 // output is unsorted!
852 if (!handler(std::move(val))) {
860 template<class Source,
862 class Gen = Generator<Value, Source, Random>>
863 Gen compose(GenImpl<Value, Source>&& source) const {
864 return Gen(std::move(source.self()), count_, rng_);
867 template<class Source,
869 class Gen = Generator<Value, Source, Random>>
870 Gen compose(const GenImpl<Value, Source>& source) const {
871 return Gen(source.self(), count_, rng_);
876 * Skip - For skipping N items from the beginning of a source generator.
878 * This type is usually used through the 'skip' helper function, like:
880 * auto page = from(results)
881 * | skip(pageSize * startPage)
884 class Skip : public Operator<Skip> {
887 explicit Skip(size_t count)
890 template<class Value,
893 public GenImpl<Value, Generator<Value, Source>> {
897 explicit Generator(Source source, size_t count)
898 : source_(std::move(source)) , count_(count) {}
901 void foreach(Body&& body) const {
903 source_.foreach(body);
907 source_.foreach([&](Value value) {
911 body(std::forward<Value>(value));
916 template<class Handler>
917 bool apply(Handler&& handler) const {
919 return source_.apply(std::forward<Handler>(handler));
922 return source_.apply([&](Value value) -> bool {
927 return handler(std::forward<Value>(value));
931 static constexpr bool infinite = Source::infinite;
934 template<class Source,
936 class Gen = Generator<Value, Source>>
937 Gen compose(GenImpl<Value, Source>&& source) const {
938 return Gen(std::move(source.self()), count_);
941 template<class Source,
943 class Gen = Generator<Value, Source>>
944 Gen compose(const GenImpl<Value, Source>& source) const {
945 return Gen(source.self(), count_);
950 * Order - For ordering a sequence of values from a source by key.
951 * The key is extracted by the given selector functor, and this key is then
952 * compared using the specified comparator.
954 * This type is usually used through the 'order' helper function, like:
956 * auto closest = from(places)
957 * | orderBy([](Place& p) {
958 * return -distance(p.location, here);
962 template<class Selector, class Comparer>
963 class Order : public Operator<Order<Selector, Comparer>> {
969 explicit Order(Selector selector)
970 : selector_(std::move(selector))
973 Order(Selector selector,
975 : selector_(std::move(selector))
976 , comparer_(std::move(comparer))
979 template<class Value,
981 class StorageType = typename std::decay<Value>::type,
982 class Result = typename std::result_of<Selector(Value)>::type>
984 public GenImpl<StorageType&&,
985 Generator<Value, Source, StorageType, Result>> {
986 static_assert(!Source::infinite, "Cannot sort infinite source!");
991 typedef std::vector<StorageType> VectorType;
993 VectorType asVector() const {
994 auto comparer = [&](const StorageType& a, const StorageType& b) {
995 return comparer_(selector_(a), selector_(b));
997 auto vals = source_ | as<VectorType>();
998 std::sort(vals.begin(), vals.end(), comparer);
999 return std::move(vals);
1002 Generator(Source source,
1005 : source_(std::move(source)),
1006 selector_(std::move(selector)),
1007 comparer_(std::move(comparer)) {}
1009 VectorType operator|(const Collect<VectorType>&) const {
1013 VectorType operator|(const CollectTemplate<std::vector>&) const {
1017 template<class Body>
1018 void foreach(Body&& body) const {
1019 for (auto& value : asVector()) {
1020 body(std::move(value));
1024 template<class Handler>
1025 bool apply(Handler&& handler) const {
1026 auto comparer = [&](const StorageType& a, const StorageType& b) {
1027 // swapped for minHeap
1028 return comparer_(selector_(b), selector_(a));
1030 auto heap = source_ | as<VectorType>();
1031 std::make_heap(heap.begin(), heap.end(), comparer);
1032 while (!heap.empty()) {
1033 std::pop_heap(heap.begin(), heap.end(), comparer);
1034 if (!handler(std::move(heap.back()))) {
1043 template<class Source,
1045 class Gen = Generator<Value, Source>>
1046 Gen compose(GenImpl<Value, Source>&& source) const {
1047 return Gen(std::move(source.self()), selector_, comparer_);
1050 template<class Source,
1052 class Gen = Generator<Value, Source>>
1053 Gen compose(const GenImpl<Value, Source>& source) const {
1054 return Gen(source.self(), selector_, comparer_);
1059 * TypeAssertion - For verifying the exact type of the value produced by a
1060 * generator. Useful for testing and debugging, and acts as a no-op at runtime.
1061 * Pass-through at runtime. Used through the 'assert_type<>()' factory method
1064 * auto c = from(vector) | assert_type<int&>() | sum;
1067 template<class Expected>
1068 class TypeAssertion : public Operator<TypeAssertion<Expected>> {
1070 template<class Source, class Value>
1071 const Source& compose(const GenImpl<Value, Source>& source) const {
1072 static_assert(std::is_same<Expected, Value>::value,
1073 "assert_type() check failed");
1074 return source.self();
1077 template<class Source, class Value>
1078 Source&& compose(GenImpl<Value, Source>&& source) const {
1079 static_assert(std::is_same<Expected, Value>::value,
1080 "assert_type() check failed");
1081 return std::move(source.self());
1086 * Distinct - For filtering duplicates out of a sequence. A selector may be
1087 * provided to generate a key to uniquify for each value.
1089 * This type is usually used through the 'distinct' helper function, like:
1091 * auto closest = from(results)
1092 * | distinctBy([](Item& i) {
1097 template<class Selector>
1098 class Distinct : public Operator<Distinct<Selector>> {
1103 explicit Distinct(Selector selector)
1104 : selector_(std::move(selector))
1107 template<class Value,
1109 class Generator : public GenImpl<Value, Generator<Value, Source>> {
1113 typedef typename std::decay<Value>::type StorageType;
1115 // selector_ cannot be passed an rvalue or it would end up passing the husk
1116 // of a value to the downstream operators.
1117 typedef const StorageType& ParamType;
1119 typedef typename std::result_of<Selector(ParamType)>::type KeyType;
1120 typedef typename std::decay<KeyType>::type KeyStorageType;
1123 Generator(Source source,
1125 : source_(std::move(source)),
1126 selector_(std::move(selector)) {}
1128 template<class Body>
1129 void foreach(Body&& body) const {
1130 std::unordered_set<KeyStorageType> keysSeen;
1131 source_.foreach([&](Value value) {
1132 if (keysSeen.insert(selector_(ParamType(value))).second) {
1133 body(std::forward<Value>(value));
1138 template<class Handler>
1139 bool apply(Handler&& handler) const {
1140 std::unordered_set<KeyStorageType> keysSeen;
1141 return source_.apply([&](Value value) -> bool {
1142 if (keysSeen.insert(selector_(ParamType(value))).second) {
1143 return handler(std::forward<Value>(value));
1150 template<class Source,
1152 class Gen = Generator<Value, Source>>
1153 Gen compose(GenImpl<Value, Source>&& source) const {
1154 return Gen(std::move(source.self()), selector_);
1157 template<class Source,
1159 class Gen = Generator<Value, Source>>
1160 Gen compose(const GenImpl<Value, Source>& source) const {
1161 return Gen(source.self(), selector_);
1166 * Batch - For producing fixed-size batches of each value from a source.
1168 * This type is usually used through the 'batch' helper function:
1173 * | map([](const std::vector<int>& batch) {
1174 * return from(batch) | sum;
1178 class Batch : public Operator<Batch> {
1181 explicit Batch(size_t batchSize)
1182 : batchSize_(batchSize) {
1183 if (batchSize_ == 0) {
1184 throw std::invalid_argument("Batch size must be non-zero!");
1188 template<class Value,
1190 class StorageType = typename std::decay<Value>::type,
1191 class VectorType = std::vector<StorageType>>
1193 public GenImpl<VectorType&,
1194 Generator<Value, Source, StorageType, VectorType>> {
1198 explicit Generator(Source source, size_t batchSize)
1199 : source_(std::move(source))
1200 , batchSize_(batchSize) {}
1202 template<class Handler>
1203 bool apply(Handler&& handler) const {
1205 batch_.reserve(batchSize_);
1206 bool shouldContinue = source_.apply([&](Value value) -> bool {
1207 batch_.push_back(std::forward<Value>(value));
1208 if (batch_.size() == batchSize_) {
1209 bool needMore = handler(batch_);
1213 // Always need more if the handler is not called.
1216 // Flush everything, if and only if `handler` hasn't returned false.
1217 if (shouldContinue && !batch_.empty()) {
1218 shouldContinue = handler(batch_);
1221 return shouldContinue;
1224 static constexpr bool infinite = Source::infinite;
1227 template<class Source,
1229 class Gen = Generator<Value, Source>>
1230 Gen compose(GenImpl<Value, Source>&& source) const {
1231 return Gen(std::move(source.self()), batchSize_);
1234 template<class Source,
1236 class Gen = Generator<Value, Source>>
1237 Gen compose(const GenImpl<Value, Source>& source) const {
1238 return Gen(source.self(), batchSize_);
1243 * Composed - For building up a pipeline of operations to perform, absent any
1244 * particular source generator. Useful for building up custom pipelines.
1246 * This type is usually used by just piping two operators together:
1248 * auto valuesOf = filter([](Optional<int>& o) { return o.hasValue(); })
1249 * | map([](Optional<int>& o) -> int& { return o.value(); });
1251 * auto valuesIncluded = from(optionals) | valuesOf | as<vector>();
1253 template<class First,
1255 class Composed : public Operator<Composed<First, Second>> {
1261 Composed(First first, Second second)
1262 : first_(std::move(first))
1263 , second_(std::move(second)) {}
1265 template<class Source,
1267 class FirstRet = decltype(std::declval<First>()
1268 .compose(std::declval<Source>())),
1269 class SecondRet = decltype(std::declval<Second>()
1270 .compose(std::declval<FirstRet>()))>
1271 SecondRet compose(const GenImpl<Value, Source>& source) const {
1272 return second_.compose(first_.compose(source.self()));
1275 template<class Source,
1277 class FirstRet = decltype(std::declval<First>()
1278 .compose(std::declval<Source>())),
1279 class SecondRet = decltype(std::declval<Second>()
1280 .compose(std::declval<FirstRet>()))>
1281 SecondRet compose(GenImpl<Value, Source>&& source) const {
1282 return second_.compose(first_.compose(std::move(source.self())));
1291 * FoldLeft - Left-associative functional fold. For producing an aggregate value
1292 * from a seed and a folder function. Useful for custom aggregators on a
1295 * This type is primarily used through the 'foldl' helper method, like:
1297 * double movingAverage = from(values)
1298 * | foldl(0.0, [](double avg, double sample) {
1299 * return sample * 0.1 + avg * 0.9;
1302 template<class Seed,
1304 class FoldLeft : public Operator<FoldLeft<Seed, Fold>> {
1311 : seed_(std::move(seed))
1312 , fold_(std::move(fold))
1315 template<class Source,
1317 Seed compose(const GenImpl<Value, Source>& source) const {
1318 static_assert(!Source::infinite, "Cannot foldl infinite source");
1320 source | [&](Value v) {
1321 accum = fold_(std::move(accum), std::forward<Value>(v));
1328 * First - For finding the first value in a sequence.
1330 * This type is primarily used through the 'first' static value, like:
1332 * int firstThreeDigitPrime = seq(100) | filter(isPrime) | first;
1334 class First : public Operator<First> {
1338 template<class Source,
1340 class StorageType = typename std::decay<Value>::type>
1341 StorageType compose(const GenImpl<Value, Source>& source) const {
1342 Optional<StorageType> accum;
1343 source | [&](Value v) -> bool {
1344 accum = std::forward<Value>(v);
1347 if (!accum.hasValue()) {
1348 throw EmptySequence();
1350 return std::move(accum.value());
1356 * Any - For determining whether any values in a sequence satisfy a predicate.
1358 * This type is primarily used through the 'any' static value, like:
1360 * bool any20xPrimes = seq(200, 210) | filter(isPrime) | any;
1362 * Note that it may also be used like so:
1364 * bool any20xPrimes = seq(200, 210) | any(isPrime);
1367 class Any : public Operator<Any> {
1371 template<class Source,
1373 bool compose(const GenImpl<Value, Source>& source) const {
1375 source | [&](Value v) -> bool {
1383 * Convenience function for use like:
1385 * bool found = gen | any([](int i) { return i * i > 100; });
1387 template<class Predicate,
1388 class Filter = Filter<Predicate>,
1389 class Composed = Composed<Filter, Any>>
1390 Composed operator()(Predicate pred) const {
1391 return Composed(Filter(std::move(pred)), Any());
1396 * All - For determining whether all values in a sequence satisfy a predicate.
1398 * This type is primarily used through the 'any' static value, like:
1400 * bool valid = from(input) | all(validate);
1402 * Note: Passing an empty sequence through 'all()' will always return true.
1404 template<class Predicate>
1405 class All : public Operator<All<Predicate>> {
1409 explicit All(Predicate pred)
1410 : pred_(std::move(pred))
1413 template<class Source,
1415 bool compose(const GenImpl<Value, Source>& source) const {
1416 static_assert(!Source::infinite, "Cannot call 'all' on infinite source");
1418 source | [&](Value v) -> bool {
1419 if (!pred_(std::forward<Value>(v))) {
1430 * Reduce - Functional reduce, for recursively combining values from a source
1431 * using a reducer function until there is only one item left. Useful for
1432 * combining values when an empty sequence doesn't make sense.
1434 * This type is primarily used through the 'reduce' helper method, like:
1436 * sring longest = from(names)
1437 * | reduce([](string&& best, string& current) {
1438 * return best.size() >= current.size() ? best : current;
1441 template<class Reducer>
1442 class Reduce : public Operator<Reduce<Reducer>> {
1446 explicit Reduce(Reducer reducer)
1447 : reducer_(std::move(reducer))
1450 template<class Source,
1452 class StorageType = typename std::decay<Value>::type>
1453 StorageType compose(const GenImpl<Value, Source>& source) const {
1454 Optional<StorageType> accum;
1455 source | [&](Value v) {
1456 if (accum.hasValue()) {
1457 accum = reducer_(std::move(accum.value()), std::forward<Value>(v));
1459 accum = std::forward<Value>(v);
1462 if (!accum.hasValue()) {
1463 throw EmptySequence();
1465 return accum.value();
1470 * Count - for simply counting the items in a collection.
1472 * This type is usually used through its singleton, 'count':
1474 * auto shortPrimes = seq(1, 100) | filter(isPrime) | count;
1476 class Count : public Operator<Count> {
1480 template<class Source,
1482 size_t compose(const GenImpl<Value, Source>& source) const {
1483 static_assert(!Source::infinite, "Cannot count infinite source");
1484 return foldl(size_t(0),
1485 [](size_t accum, Value v) {
1492 * Sum - For simply summing up all the values from a source.
1494 * This type is usually used through its singleton, 'sum':
1496 * auto gaussSum = seq(1, 100) | sum;
1498 class Sum : public Operator<Sum> {
1500 Sum() : Operator<Sum>() {}
1502 template<class Source,
1504 class StorageType = typename std::decay<Value>::type>
1505 StorageType compose(const GenImpl<Value, Source>& source) const {
1506 static_assert(!Source::infinite, "Cannot sum infinite source");
1507 return foldl(StorageType(0),
1508 [](StorageType&& accum, Value v) {
1509 return std::move(accum) + std::forward<Value>(v);
1515 * Contains - For testing whether a value matching the given value is contained
1518 * This type should be used through the 'contains' helper method, like:
1520 * bool contained = seq(1, 10) | map(square) | contains(49);
1522 template<class Needle>
1523 class Contains : public Operator<Contains<Needle>> {
1526 explicit Contains(Needle needle)
1527 : needle_(std::move(needle))
1530 template<class Source,
1532 class StorageType = typename std::decay<Value>::type>
1533 bool compose(const GenImpl<Value, Source>& source) const {
1534 static_assert(!Source::infinite,
1535 "Calling contains on an infinite source might cause "
1536 "an infinite loop.");
1537 return !(source | [this](Value value) {
1538 return !(needle_ == std::forward<Value>(value));
1544 * Min - For a value which minimizes a key, where the key is determined by a
1545 * given selector, and compared by given comparer.
1547 * This type is usually used through the singletone 'min' or through the helper
1548 * functions 'minBy' and 'maxBy'.
1550 * auto oldest = from(people)
1551 * | minBy([](Person& p) {
1552 * return p.dateOfBirth;
1555 template<class Selector,
1557 class Min : public Operator<Min<Selector, Comparer>> {
1563 explicit Min(Selector selector)
1564 : selector_(std::move(selector))
1567 Min(Selector selector,
1569 : selector_(std::move(selector))
1570 , comparer_(std::move(comparer))
1573 template<class Value,
1575 class StorageType = typename std::decay<Value>::type,
1576 class Key = typename std::decay<
1577 typename std::result_of<Selector(Value)>::type
1579 StorageType compose(const GenImpl<Value, Source>& source) const {
1580 Optional<StorageType> min;
1581 Optional<Key> minKey;
1582 source | [&](Value v) {
1583 Key key = selector_(std::forward<Value>(v));
1584 if (!minKey.hasValue() || comparer_(key, minKey.value())) {
1586 min = std::forward<Value>(v);
1589 if (!min.hasValue()) {
1590 throw EmptySequence();
1597 * Append - For collecting values from a source into a given output container
1600 * This type is usually used through the helper function 'appendTo', like:
1602 * vector<int64_t> ids;
1603 * from(results) | map([](Person& p) { return p.id })
1606 template<class Collection>
1607 class Append : public Operator<Append<Collection>> {
1608 Collection* collection_;
1610 explicit Append(Collection* collection)
1611 : collection_(collection)
1614 template<class Value,
1616 Collection& compose(const GenImpl<Value, Source>& source) const {
1617 source | [&](Value v) {
1618 collection_->insert(collection_->end(), std::forward<Value>(v));
1620 return *collection_;
1625 * Collect - For collecting values from a source in a collection of the desired
1628 * This type is usually used through the helper function 'as', like:
1630 * std::string upper = from(stringPiece)
1632 * | as<std::string>();
1634 template<class Collection>
1635 class Collect : public Operator<Collect<Collection>> {
1639 template<class Value,
1641 class StorageType = typename std::decay<Value>::type>
1642 Collection compose(const GenImpl<Value, Source>& source) const {
1643 Collection collection;
1644 source | [&](Value v) {
1645 collection.insert(collection.end(), std::forward<Value>(v));
1653 * CollectTemplate - For collecting values from a source in a collection
1654 * constructed using the specified template type. Given the type of values
1655 * produced by the given generator, the collection type will be:
1656 * Container<Value, Allocator<Value>>
1658 * The allocator defaults to std::allocator, so this may be used for the STL
1659 * containers by simply using operators like 'as<set>', 'as<deque>',
1660 * 'as<vector>'. 'as', here is the helper method which is the usual means of
1661 * consturcting this operator.
1665 * set<string> uniqueNames = from(names) | as<set>();
1667 template<template<class, class> class Container,
1668 template<class> class Allocator>
1669 class CollectTemplate : public Operator<CollectTemplate<Container, Allocator>> {
1671 CollectTemplate() { }
1673 template<class Value,
1675 class StorageType = typename std::decay<Value>::type,
1676 class Collection = Container<StorageType, Allocator<StorageType>>>
1677 Collection compose(const GenImpl<Value, Source>& source) const {
1678 Collection collection;
1679 source | [&](Value v) {
1680 collection.insert(collection.end(), std::forward<Value>(v));
1687 * Concat - For flattening generators of generators.
1689 * This type is usually used through the 'concat' static value, like:
1693 * | map([](Node& x) {
1694 * return from(x.neighbors)
1695 * | map([&](Node& y) {
1696 * return Edge(x, y);
1702 class Concat : public Operator<Concat> {
1706 template<class Inner,
1708 class InnerValue = typename std::decay<Inner>::type::ValueType>
1710 public GenImpl<InnerValue, Generator<Inner, Source, InnerValue>> {
1713 explicit Generator(Source source)
1714 : source_(std::move(source)) {}
1716 template<class Handler>
1717 bool apply(Handler&& handler) const {
1718 return source_.apply([&](Inner inner) -> bool {
1719 return inner.apply(std::forward<Handler>(handler));
1723 template<class Body>
1724 void foreach(Body&& body) const {
1725 source_.foreach([&](Inner inner) {
1726 inner.foreach(std::forward<Body>(body));
1730 static constexpr bool infinite = Source::infinite;
1733 template<class Value,
1735 class Gen = Generator<Value, Source>>
1736 Gen compose(GenImpl<Value, Source>&& source) const {
1737 return Gen(std::move(source.self()));
1740 template<class Value,
1742 class Gen = Generator<Value, Source>>
1743 Gen compose(const GenImpl<Value, Source>& source) const {
1744 return Gen(source.self());
1749 * RangeConcat - For flattening generators of iterables.
1751 * This type is usually used through the 'rconcat' static value, like:
1753 * map<int, vector<int>> adjacency;
1760 class RangeConcat : public Operator<RangeConcat> {
1764 template<class Range,
1766 class InnerValue = typename ValueTypeOfRange<Range>::RefType>
1768 : public GenImpl<InnerValue, Generator<Range, Source, InnerValue>> {
1771 explicit Generator(Source source)
1772 : source_(std::move(source)) {}
1774 template<class Body>
1775 void foreach(Body&& body) const {
1776 source_.foreach([&](Range range) {
1777 for (auto& value : range) {
1783 template<class Handler>
1784 bool apply(Handler&& handler) const {
1785 return source_.apply([&](Range range) -> bool {
1786 for (auto& value : range) {
1787 if (!handler(value)) {
1796 template<class Value,
1798 class Gen = Generator<Value, Source>>
1799 Gen compose(GenImpl<Value, Source>&& source) const {
1800 return Gen(std::move(source.self()));
1803 template<class Value,
1805 class Gen = Generator<Value, Source>>
1806 Gen compose(const GenImpl<Value, Source>& source) const {
1807 return Gen(source.self());
1813 * GuardImpl - For handling exceptions from downstream computation. Requires the
1814 * type of exception to catch, and handler function to invoke in the event of
1815 * the exception. Note that the handler may:
1816 * 1) return true to continue processing the sequence
1817 * 2) return false to end the sequence immediately
1818 * 3) throw, to pass the exception to the next catch
1819 * The handler must match the signature 'bool(Exception&, Value)'.
1821 * This type is used through the `guard` helper, like so:
1824 * = byLine(STDIN_FILENO)
1825 * | guard<std::runtime_error>([](std::runtime_error& e,
1827 * LOG(ERROR) << sp << ": " << e.str();
1828 * return true; // continue processing subsequent lines
1833 * TODO(tjackson): Rename this back to Guard.
1835 template<class Exception,
1837 class GuardImpl : public Operator<GuardImpl<Exception, ErrorHandler>> {
1838 ErrorHandler handler_;
1840 GuardImpl(ErrorHandler handler)
1841 : handler_(std::move(handler)) {}
1843 template<class Value,
1845 class Generator : public GenImpl<Value, Generator<Value, Source>> {
1847 ErrorHandler handler_;
1849 explicit Generator(Source source,
1850 ErrorHandler handler)
1851 : source_(std::move(source)),
1852 handler_(std::move(handler)) {}
1854 template<class Handler>
1855 bool apply(Handler&& handler) const {
1856 return source_.apply([&](Value value) -> bool {
1858 handler(std::forward<Value>(value));
1860 } catch (Exception& e) {
1861 return handler_(e, std::forward<Value>(value));
1866 static constexpr bool infinite = Source::infinite;
1869 template<class Value,
1871 class Gen = Generator<Value, Source>>
1872 Gen compose(GenImpl<Value, Source>&& source) const {
1873 return Gen(std::move(source.self()), handler_);
1876 template<class Value,
1878 class Gen = Generator<Value, Source>>
1879 Gen compose(const GenImpl<Value, Source>& source) const {
1880 return Gen(source.self(), handler_);
1885 * Cycle - For repeating a sequence forever.
1887 * This type is usually used through the 'cycle' static value, like:
1894 class Cycle : public Operator<Cycle> {
1895 off_t limit_; // -1 for infinite
1900 explicit Cycle(off_t limit)
1903 template<class Value,
1905 class Generator : public GenImpl<Value, Generator<Value, Source>> {
1907 off_t limit_; // -1 for infinite
1909 explicit Generator(Source source, off_t limit)
1910 : source_(std::move(source))
1913 template<class Handler>
1914 bool apply(Handler&& handler) const {
1916 auto handler2 = [&](Value value) {
1917 cont = handler(std::forward<Value>(value));
1920 for (off_t count = 0; count != limit_; ++count) {
1922 source_.apply(handler2);
1930 // not actually infinite, since an empty generator will end the cycles.
1931 static constexpr bool infinite = Source::infinite;
1934 template<class Source,
1936 class Gen = Generator<Value, Source>>
1937 Gen compose(GenImpl<Value, Source>&& source) const {
1938 return Gen(std::move(source.self()), limit_);
1941 template<class Source,
1943 class Gen = Generator<Value, Source>>
1944 Gen compose(const GenImpl<Value, Source>& source) const {
1945 return Gen(source.self(), limit_);
1949 * Convenience function for use like:
1951 * auto tripled = gen | cycle(3);
1953 Cycle operator()(off_t limit) const {
1954 return Cycle(limit);
1959 * Dereference - For dereferencing a sequence of pointers while filtering out
1962 * This type is usually used through the 'dereference' static value, like:
1964 * auto refs = from(ptrs) | dereference;
1966 class Dereference : public Operator<Dereference> {
1970 template<class Value,
1972 class Result = decltype(*std::declval<Value>())>
1973 class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
1976 explicit Generator(Source source)
1977 : source_(std::move(source)) {}
1979 template<class Body>
1980 void foreach(Body&& body) const {
1981 source_.foreach([&](Value value) {
1983 return body(*value);
1988 template<class Handler>
1989 bool apply(Handler&& handler) const {
1990 return source_.apply([&](Value value) -> bool {
1992 return handler(*value);
1998 // not actually infinite, since an empty generator will end the cycles.
1999 static constexpr bool infinite = Source::infinite;
2002 template<class Source,
2004 class Gen = Generator<Value, Source>>
2005 Gen compose(GenImpl<Value, Source>&& source) const {
2006 return Gen(std::move(source.self()));
2009 template<class Source,
2011 class Gen = Generator<Value, Source>>
2012 Gen compose(const GenImpl<Value, Source>& source) const {
2013 return Gen(source.self());
2020 * VirtualGen<T> - For wrapping template types in simple polymorphic wrapper.
2022 template<class Value>
2023 class VirtualGen : public GenImpl<Value, VirtualGen<Value>> {
2026 virtual ~WrapperBase() {}
2027 virtual bool apply(const std::function<bool(Value)>& handler) const = 0;
2028 virtual void foreach(const std::function<void(Value)>& body) const = 0;
2029 virtual std::unique_ptr<const WrapperBase> clone() const = 0;
2032 template<class Wrapped>
2033 class WrapperImpl : public WrapperBase {
2036 explicit WrapperImpl(Wrapped wrapped)
2037 : wrapped_(std::move(wrapped)) {
2040 virtual bool apply(const std::function<bool(Value)>& handler) const {
2041 return wrapped_.apply(handler);
2044 virtual void foreach(const std::function<void(Value)>& body) const {
2045 wrapped_.foreach(body);
2048 virtual std::unique_ptr<const WrapperBase> clone() const {
2049 return std::unique_ptr<const WrapperBase>(new WrapperImpl(wrapped_));
2053 std::unique_ptr<const WrapperBase> wrapper_;
2056 template<class Self>
2057 /* implicit */ VirtualGen(Self source)
2058 : wrapper_(new WrapperImpl<Self>(std::move(source)))
2061 VirtualGen(VirtualGen&& source)
2062 : wrapper_(std::move(source.wrapper_))
2065 VirtualGen(const VirtualGen& source)
2066 : wrapper_(source.wrapper_->clone())
2069 VirtualGen& operator=(const VirtualGen& source) {
2070 wrapper_.reset(source.wrapper_->clone());
2074 VirtualGen& operator=(VirtualGen&& source) {
2075 wrapper_= std::move(source.wrapper_);
2079 bool apply(const std::function<bool(Value)>& handler) const {
2080 return wrapper_->apply(handler);
2083 void foreach(const std::function<void(Value)>& body) const {
2084 wrapper_->foreach(body);
2089 * non-template operators, statically defined to avoid the need for anything but
2092 static const detail::Sum sum;
2094 static const detail::Count count;
2096 static const detail::First first;
2099 * Use directly for detecting any values, or as a function to detect values
2100 * which pass a predicate:
2102 * auto nonempty = g | any;
2103 * auto evens = g | any(even);
2105 static const detail::Any any;
2107 static const detail::Min<Identity, Less> min;
2109 static const detail::Min<Identity, Greater> max;
2111 static const detail::Order<Identity> order;
2113 static const detail::Distinct<Identity> distinct;
2115 static const detail::Map<Move> move;
2117 static const detail::Concat concat;
2119 static const detail::RangeConcat rconcat;
2122 * Use directly for infinite sequences, or as a function to limit cycle count.
2124 * auto forever = g | cycle;
2125 * auto thrice = g | cycle(3);
2127 static const detail::Cycle cycle;
2129 static const detail::Dereference dereference;
2131 inline detail::Take take(size_t count) {
2132 return detail::Take(count);
2135 template<class Random = std::default_random_engine>
2136 inline detail::Sample<Random> sample(size_t count, Random rng = Random()) {
2137 return detail::Sample<Random>(count, std::move(rng));
2140 inline detail::Skip skip(size_t count) {
2141 return detail::Skip(count);
2144 inline detail::Batch batch(size_t batchSize) {
2145 return detail::Batch(batchSize);
2150 #pragma GCC diagnostic pop