T&& // int -> int&&
>::type> {};
+/**
+ * Group - The output objects from the GroupBy operator
+ */
template <class Key, class Value>
class Group : public GenImpl<Value&&, Group<Key, Value>> {
public:
return true;
}
+ // GroupBy only takes in finite generators, so we only have finite groups
+ static constexpr bool infinite = false;
+
private:
Key key_;
mutable VectorType values_;
namespace detail {
+// Classes used for the implementation of Sources, Operators, and Sinks
+
+/*
+ ******************************* Sources ***************************************
+ */
+
/*
* ReferencedSource - Generate values from an STL-like container using
* iterators from .begin() until .end(). Value type defaults to the type of
* string& longestName = from(names)
* | maxBy([](string& s) { return s.size() });
*/
-template<class Container,
- class Value>
-class ReferencedSource :
- public GenImpl<Value, ReferencedSource<Container, Value>> {
+template <class Container, class Value>
+class ReferencedSource
+ : public GenImpl<Value, ReferencedSource<Container, Value>> {
Container* container_;
-public:
- explicit ReferencedSource(Container* container)
- : container_(container) {}
- template<class Body>
+ public:
+ explicit ReferencedSource(Container* container) : container_(container) {}
+
+ template <class Body>
void foreach(Body&& body) const {
for (auto& value : *container_) {
body(std::forward<Value>(value));
}
}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
for (auto& value : *container_) {
if (!handler(std::forward<Value>(value))) {
}
return true;
}
+
+ // from takes in a normal stl structure, which are all finite
+ static constexpr bool infinite = false;
};
/**
*
* Though it is also used for the initializer_list specialization of from().
*/
-template<class StorageType,
- class Container>
-class CopiedSource :
- public GenImpl<const StorageType&,
- CopiedSource<StorageType, Container>> {
- static_assert(
- !std::is_reference<StorageType>::value, "StorageType must be decayed");
+template <class StorageType, class Container>
+class CopiedSource
+ : public GenImpl<const StorageType&, CopiedSource<StorageType, Container>> {
+ static_assert(!std::is_reference<StorageType>::value,
+ "StorageType must be decayed");
+
public:
// Generator objects are often copied during normal construction as they are
// encapsulated by downstream generators. It would be bad if this caused
// a copy of the entire container each time, and since we're only exposing a
// const reference to the value, it's safe to share it between multiple
// generators.
- static_assert(
- !std::is_reference<Container>::value,
- "Can't copy into a reference");
+ static_assert(!std::is_reference<Container>::value,
+ "Can't copy into a reference");
std::shared_ptr<const Container> copy_;
-public:
+
+ public:
typedef Container ContainerType;
- template<class SourceContainer>
+ template <class SourceContainer>
explicit CopiedSource(const SourceContainer& container)
- : copy_(new Container(begin(container), end(container))) {}
+ : copy_(new Container(begin(container), end(container))) {}
- explicit CopiedSource(Container&& container) :
- copy_(new Container(std::move(container))) {}
+ explicit CopiedSource(Container&& container)
+ : copy_(new Container(std::move(container))) {}
// To enable re-use of cached results.
CopiedSource(const CopiedSource<StorageType, Container>& source)
- : copy_(source.copy_) {}
+ : copy_(source.copy_) {}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
for (const auto& value : *copy_) {
body(value);
}
}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
// The collection may be reused by others, we can't allow it to be changed.
for (const auto& value : *copy_) {
}
return true;
}
+
+ // from takes in a normal stl structure, which are all finite
+ static constexpr bool infinite = false;
};
/**
*
* Reminder: Be careful not to invalidate iterators when using ranges like this.
*/
-template<class Iterator>
+template <class Iterator>
class RangeSource : public GenImpl<typename Range<Iterator>::reference,
RangeSource<Iterator>> {
Range<Iterator> range_;
+
public:
RangeSource() = default;
- explicit RangeSource(Range<Iterator> range)
- : range_(std::move(range))
- {}
+ explicit RangeSource(Range<Iterator> range) : range_(std::move(range)) {}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
for (auto& value : range_) {
if (!handler(value)) {
return true;
}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
for (auto& value : range_) {
body(value);
}
}
+
+ // folly::Range only supports finite ranges
+ static constexpr bool infinite = false;
};
/**
* auto indexes = range(0, 10);
* auto endless = seq(0); // 0, 1, 2, 3, ...
*/
-template<class Value, class SequenceImpl>
+template <class Value, class SequenceImpl>
class Sequence : public GenImpl<const Value&, Sequence<Value, SequenceImpl>> {
static_assert(!std::is_reference<Value>::value &&
- !std::is_const<Value>::value, "Value mustn't be const or ref.");
+ !std::is_const<Value>::value,
+ "Value mustn't be const or ref.");
Value start_;
SequenceImpl impl_;
-public:
+
+ public:
explicit Sequence(Value start, SequenceImpl impl)
- : start_(std::move(start)), impl_(std::move(impl)) { }
+ : start_(std::move(start)), impl_(std::move(impl)) {}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
for (Value current = start_; impl_.test(current); impl_.step(current)) {
if (!handler(current)) {
return true;
}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
for (Value current = start_; impl_.test(current); impl_.step(current)) {
body(current);
}
}
+
+ // Let the implementation say if we are infinite or not
+ static constexpr bool infinite = SequenceImpl::infinite;
};
/**
* Sequence implementations (range, sequence, infinite, with/without step)
**/
-template<class Value>
+template <class Value>
class RangeImpl {
Value end_;
+
public:
- explicit RangeImpl(Value end) : end_(std::move(end)) { }
+ explicit RangeImpl(Value end) : end_(std::move(end)) {}
bool test(const Value& current) const { return current < end_; }
void step(Value& current) const { ++current; }
+ static constexpr bool infinite = false;
};
-template<class Value, class Distance>
+template <class Value, class Distance>
class RangeWithStepImpl {
Value end_;
Distance step_;
+
public:
explicit RangeWithStepImpl(Value end, Distance step)
- : end_(std::move(end)), step_(std::move(step)) { }
+ : end_(std::move(end)), step_(std::move(step)) {}
bool test(const Value& current) const { return current < end_; }
void step(Value& current) const { current += step_; }
+ static constexpr bool infinite = false;
};
-template<class Value>
+template <class Value>
class SeqImpl {
Value end_;
+
public:
- explicit SeqImpl(Value end) : end_(std::move(end)) { }
+ explicit SeqImpl(Value end) : end_(std::move(end)) {}
bool test(const Value& current) const { return current <= end_; }
void step(Value& current) const { ++current; }
+ static constexpr bool infinite = false;
};
-template<class Value, class Distance>
+template <class Value, class Distance>
class SeqWithStepImpl {
Value end_;
Distance step_;
+
public:
explicit SeqWithStepImpl(Value end, Distance step)
- : end_(std::move(end)), step_(std::move(step)) { }
+ : end_(std::move(end)), step_(std::move(step)) {}
bool test(const Value& current) const { return current <= end_; }
void step(Value& current) const { current += step_; }
+ static constexpr bool infinite = false;
};
-template<class Value>
+template <class Value>
class InfiniteImpl {
public:
bool test(const Value& current) const { return true; }
void step(Value& current) const { ++current; }
+ static constexpr bool infinite = true;
};
/**
* GenratorBuilder - Helper for GENERTATOR macro.
**/
-template<class Value>
+template <class Value>
struct GeneratorBuilder {
- template<class Source,
- class Yield = detail::Yield<Value, Source>>
+ template <class Source,
+ class Yield = detail::Yield<Value, Source>>
Yield operator+(Source&& source) {
return Yield(std::forward<Source>(source));
}
* Yield - For producing values from a user-defined generator by way of a
* 'yield' function.
**/
-template<class Value, class Source>
+template <class Value, class Source>
class Yield : public GenImpl<Value, Yield<Value, Source>> {
Source source_;
+
public:
- explicit Yield(Source source)
- : source_(std::move(source)) {
- }
+ explicit Yield(Source source) : source_(std::move(source)) {}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
struct Break {};
auto body = [&](Value value) {
}
}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
source_(std::forward<Body>(body));
}
};
-template<class Value>
+template <class Value>
class Empty : public GenImpl<Value, Empty<Value>> {
public:
template <class Handler>
template <class Body>
void foreach(Body&&) const {}
+
+ // No values, so finite
+ static constexpr bool infinite = false;
};
template <class Value>
static_assert(!std::is_reference<Value>::value,
"SingleReference requires non-ref types");
Value* ptr_;
+
public:
explicit SingleReference(Value& ref) : ptr_(&ref) {}
void foreach(Body&& body) const {
body(*ptr_);
}
+
+ // One value, so finite
+ static constexpr bool infinite = false;
};
template <class Value>
static_assert(!std::is_reference<Value>::value,
"SingleCopy requires non-ref types");
Value value_;
+
public:
explicit SingleCopy(Value value) : value_(std::forward<Value>(value)) {}
void foreach(Body&& body) const {
body(value_);
}
+
+ // One value, so finite
+ static constexpr bool infinite = false;
};
/*
- * Operators
+ ***************************** Operators ***************************************
*/
/**
*
* auto squares = seq(1, 10) | map(square) | asVector;
*/
-template<class Predicate>
+template <class Predicate>
class Map : public Operator<Map<Predicate>> {
Predicate pred_;
+
public:
Map() = default;
- explicit Map(Predicate pred)
- : pred_(std::move(pred))
- { }
-
- template<class Value,
- class Source,
- class Result = typename ArgumentReference<
- typename std::result_of<Predicate(Value)>::type
- >::type>
- class Generator :
- public GenImpl<Result, Generator<Value, Source, Result>> {
+ explicit Map(Predicate pred) : pred_(std::move(pred)) {}
+
+ template <class Value,
+ class Source,
+ class Result = typename ArgumentReference<
+ typename std::result_of<Predicate(Value)>::type>::type>
+ class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
Source source_;
Predicate pred_;
- public:
+
+ public:
explicit Generator(Source source, const Predicate& pred)
- : source_(std::move(source)), pred_(pred) {}
+ : source_(std::move(source)), pred_(pred) {}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
- source_.foreach([&](Value value) {
- body(pred_(std::forward<Value>(value)));
- });
+ source_.foreach(
+ [&](Value value) { body(pred_(std::forward<Value>(value))); });
}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
return source_.apply([&](Value value) {
return handler(pred_(std::forward<Value>(value)));
static constexpr bool infinite = Source::infinite;
};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), pred_);
}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), pred_);
}
*
* will give a vector of all the pointers != nullptr.
*/
-template<class Predicate>
+template <class Predicate>
class Filter : public Operator<Filter<Predicate>> {
Predicate pred_;
+
public:
Filter() = default;
- explicit Filter(Predicate pred)
- : pred_(std::move(pred))
- { }
+ explicit Filter(Predicate pred) : pred_(std::move(pred)) {}
- template<class Value,
- class Source>
+ template <class Value, class Source>
class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
Predicate pred_;
- public:
+
+ public:
explicit Generator(Source source, const Predicate& pred)
- : source_(std::move(source)), pred_(pred) {}
+ : source_(std::move(source)), pred_(pred) {}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
source_.foreach([&](Value value) {
if (pred_(std::forward<Value>(value))) {
});
}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
return source_.apply([&](Value value) -> bool {
if (pred_(std::forward<Value>(value))) {
static constexpr bool infinite = Source::infinite;
};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), pred_);
}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), pred_);
}
* | until([](Item& item) { return item.score > 100; })
* | asVector;
*/
-template<class Predicate>
+template <class Predicate>
class Until : public Operator<Until<Predicate>> {
Predicate pred_;
+
public:
Until() = default;
- explicit Until(Predicate pred)
- : pred_(std::move(pred))
- {}
+ explicit Until(Predicate pred) : pred_(std::move(pred)) {}
- template<class Value,
- class Source>
+ template <class Value, class Source>
class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
Predicate pred_;
+
public:
explicit Generator(Source source, const Predicate& pred)
- : source_(std::move(source)), pred_(pred) {}
+ : source_(std::move(source)), pred_(pred) {}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
bool cancelled = false;
source_.apply([&](Value value) -> bool {
});
return !cancelled;
}
+
+ // Theoretically an 'until' might stop an infinite
+ static constexpr bool infinite = false;
};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), pred_);
}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), pred_);
}
-
- // Theoretically an 'until' might stop an infinite
- static constexpr bool infinite = false;
};
/**
*/
class Take : public Operator<Take> {
size_t count_;
+
public:
- explicit Take(size_t count)
- : count_(count) {}
+ explicit Take(size_t count) : count_(count) {}
- template<class Value,
- class Source>
- class Generator :
- public GenImpl<Value, Generator<Value, Source>> {
+ template <class Value, class Source>
+ class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
size_t count_;
- public:
+
+ public:
explicit Generator(Source source, size_t count)
- : source_(std::move(source)) , count_(count) {}
+ : source_(std::move(source)), count_(count) {}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
- if (count_ == 0) { return false; }
+ if (count_ == 0) {
+ return false;
+ }
size_t n = count_;
bool cancelled = false;
source_.apply([&](Value value) -> bool {
});
return !cancelled;
}
+
+ // take will stop an infinite generator
+ static constexpr bool infinite = false;
};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), count_);
}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), count_);
}
class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
size_t stride_;
- public:
- Generator(Source source, size_t stride)
- : source_(std::move(source)), stride_(stride) {}
-
- template <class Handler>
- bool apply(Handler&& handler) const {
- size_t distance = stride_;
- return source_.apply([&](Value value)->bool {
- if (++distance >= stride_) {
- if (!handler(std::forward<Value>(value))) {
- return false;
- }
- distance = 0;
- }
- return true;
- });
- }
-
- template <class Body>
- void foreach(Body&& body) const {
- size_t distance = stride_;
- source_.foreach([&](Value value) {
- if (++distance >= stride_) {
- body(std::forward<Value>(value));
- distance = 0;
- }
- });
- }
+
+ public:
+ explicit Generator(Source source, size_t stride)
+ : source_(std::move(source)), stride_(stride) {}
+
+ template <class Handler>
+ bool apply(Handler&& handler) const {
+ size_t distance = stride_;
+ return source_.apply([&](Value value) -> bool {
+ if (++distance >= stride_) {
+ if (!handler(std::forward<Value>(value))) {
+ return false;
+ }
+ distance = 0;
+ }
+ return true;
+ });
+ }
+
+ template <class Body>
+ void foreach(Body&& body) const {
+ size_t distance = stride_;
+ source_.foreach([&](Value value) {
+ if (++distance >= stride_) {
+ body(std::forward<Value>(value));
+ distance = 0;
+ }
+ });
+ }
+
+ // Taking every Nth of an infinite list is still infinte
+ static constexpr bool infinite = Source::infinite;
};
- template <class Source, class Value, class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), stride_);
}
- template <class Source, class Value, class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), stride_);
}
* Sample - For taking a random sample of N elements from a sequence
* (without replacement).
*/
-template<class Random>
+template <class Random>
class Sample : public Operator<Sample<Random>> {
size_t count_;
Random rng_;
+
public:
explicit Sample(size_t count, Random rng)
- : count_(count), rng_(std::move(rng)) {}
-
- template<class Value,
- class Source,
- class Rand,
- class StorageType = typename std::decay<Value>::type>
- class Generator :
- public GenImpl<StorageType&&,
- Generator<Value, Source, Rand, StorageType>> {
+ : count_(count), rng_(std::move(rng)) {}
+
+ template <class Value,
+ class Source,
+ class Rand,
+ class StorageType = typename std::decay<Value>::type>
+ class Generator
+ : public GenImpl<StorageType&&,
+ Generator<Value, Source, Rand, StorageType>> {
static_assert(!Source::infinite, "Cannot sample infinite source!");
// It's too easy to bite ourselves if random generator is only 16-bit
static_assert(Random::max() >= std::numeric_limits<int32_t>::max() - 1,
Source source_;
size_t count_;
mutable Rand rng_;
- public:
+
+ public:
explicit Generator(Source source, size_t count, Random rng)
- : source_(std::move(source)) , count_(count), rng_(std::move(rng)) {}
+ : source_(std::move(source)), count_(count), rng_(std::move(rng)) {}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
- if (count_ == 0) { return false; }
+ if (count_ == 0) {
+ return false;
+ }
std::vector<StorageType> v;
v.reserve(count_);
// use reservoir sampling to give each source value an equal chance
// of appearing in our output.
size_t n = 1;
source_.foreach([&](Value value) -> void {
- if (v.size() < count_) {
- v.push_back(std::forward<Value>(value));
- } else {
- // alternatively, we could create a std::uniform_int_distribution
- // instead of using modulus, but benchmarks show this has
- // substantial overhead.
- size_t index = rng_() % n;
- if (index < v.size()) {
- v[index] = std::forward<Value>(value);
- }
+ if (v.size() < count_) {
+ v.push_back(std::forward<Value>(value));
+ } else {
+ // alternatively, we could create a std::uniform_int_distribution
+ // instead of using modulus, but benchmarks show this has
+ // substantial overhead.
+ size_t index = rng_() % n;
+ if (index < v.size()) {
+ v[index] = std::forward<Value>(value);
}
- ++n;
- });
+ }
+ ++n;
+ });
// output is unsorted!
- for (auto& val: v) {
+ for (auto& val : v) {
if (!handler(std::move(val))) {
return false;
}
}
return true;
}
+
+ // Only takes N elements, so finite
+ static constexpr bool infinite = false;
};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source, Random>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source, Random>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), count_, rng_);
}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source, Random>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source, Random>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), count_, rng_);
}
*/
class Skip : public Operator<Skip> {
size_t count_;
+
public:
- explicit Skip(size_t count)
- : count_(count) {}
+ explicit Skip(size_t count) : count_(count) {}
- template<class Value,
- class Source>
- class Generator :
- public GenImpl<Value, Generator<Value, Source>> {
+ template <class Value, class Source>
+ class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
size_t count_;
+
public:
explicit Generator(Source source, size_t count)
- : source_(std::move(source)) , count_(count) {}
+ : source_(std::move(source)), count_(count) {}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
if (count_ == 0) {
source_.foreach(body);
}
size_t n = 0;
source_.foreach([&](Value value) {
- if (n < count_) {
- ++n;
- } else {
- body(std::forward<Value>(value));
- }
- });
+ if (n < count_) {
+ ++n;
+ } else {
+ body(std::forward<Value>(value));
+ }
+ });
}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
if (count_ == 0) {
return source_.apply(std::forward<Handler>(handler));
}
size_t n = 0;
return source_.apply([&](Value value) -> bool {
- if (n < count_) {
- ++n;
- return true;
- }
- return handler(std::forward<Value>(value));
- });
+ if (n < count_) {
+ ++n;
+ return true;
+ }
+ return handler(std::forward<Value>(value));
+ });
}
+ // Skipping N items of an infinite source is still infinite
static constexpr bool infinite = Source::infinite;
};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), count_);
}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), count_);
}
* })
* | take(10);
*/
-template<class Selector, class Comparer>
+template <class Selector, class Comparer>
class Order : public Operator<Order<Selector, Comparer>> {
Selector selector_;
Comparer comparer_;
+
public:
Order() = default;
- explicit Order(Selector selector)
- : selector_(std::move(selector))
- {}
-
- Order(Selector selector,
- Comparer comparer)
- : selector_(std::move(selector))
- , comparer_(std::move(comparer))
- {}
-
- template<class Value,
- class Source,
- class StorageType = typename std::decay<Value>::type,
- class Result = typename std::result_of<Selector(Value)>::type>
- class Generator :
- public GenImpl<StorageType&&,
- Generator<Value, Source, StorageType, Result>> {
+ explicit Order(Selector selector) : selector_(std::move(selector)) {}
+
+ Order(Selector selector, Comparer comparer)
+ : selector_(std::move(selector)), comparer_(std::move(comparer)) {}
+
+ template <class Value,
+ class Source,
+ class StorageType = typename std::decay<Value>::type,
+ class Result = typename std::result_of<Selector(Value)>::type>
+ class Generator
+ : public GenImpl<StorageType&&,
+ Generator<Value, Source, StorageType, Result>> {
static_assert(!Source::infinite, "Cannot sort infinite source!");
Source source_;
Selector selector_;
std::sort(vals.begin(), vals.end(), comparer);
return std::move(vals);
}
+
public:
- Generator(Source source,
- Selector selector,
- Comparer comparer)
- : source_(std::move(source)),
- selector_(std::move(selector)),
- comparer_(std::move(comparer)) {}
+ Generator(Source source, Selector selector, Comparer comparer)
+ : source_(std::move(source)),
+ selector_(std::move(selector)),
+ comparer_(std::move(comparer)) {}
VectorType operator|(const Collect<VectorType>&) const {
return asVector();
return asVector();
}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
for (auto& value : asVector()) {
body(std::move(value));
}
}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
auto comparer = [&](const StorageType& a, const StorageType& b) {
// swapped for minHeap
}
return true;
}
+
+ // Can only be run on and produce finite generators
+ static constexpr bool infinite = false;
};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), selector_, comparer_);
}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), selector_, comparer_);
}
}
return true;
}
+
+ // Can only be run on and produce finite generators
+ static constexpr bool infinite = false;
};
- template <class Source, class Value, class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), selector_);
}
- template <class Source, class Value, class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), selector_);
}
* auto c = from(vector) | assert_type<int&>() | sum;
*
*/
-template<class Expected>
+template <class Expected>
class TypeAssertion : public Operator<TypeAssertion<Expected>> {
public:
- template<class Source, class Value>
+ template <class Source, class Value>
const Source& compose(const GenImpl<Value, Source>& source) const {
static_assert(std::is_same<Expected, Value>::value,
"assert_type() check failed");
return source.self();
}
- template<class Source, class Value>
+ template <class Source, class Value>
Source&& compose(GenImpl<Value, Source>&& source) const {
static_assert(std::is_same<Expected, Value>::value,
"assert_type() check failed");
* })
* | take(10);
*/
-template<class Selector>
+template <class Selector>
class Distinct : public Operator<Distinct<Selector>> {
Selector selector_;
+
public:
Distinct() = default;
- explicit Distinct(Selector selector)
- : selector_(std::move(selector))
- {}
+ explicit Distinct(Selector selector) : selector_(std::move(selector)) {}
- template<class Value,
- class Source>
+ template <class Value, class Source>
class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
Selector selector_;
typedef typename std::decay<KeyType>::type KeyStorageType;
public:
- Generator(Source source,
- Selector selector)
- : source_(std::move(source)),
- selector_(std::move(selector)) {}
+ Generator(Source source, Selector selector)
+ : source_(std::move(source)), selector_(std::move(selector)) {}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
std::unordered_set<KeyStorageType> keysSeen;
source_.foreach([&](Value value) {
});
}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
std::unordered_set<KeyStorageType> keysSeen;
return source_.apply([&](Value value) -> bool {
return true;
});
}
+
+ // While running distinct on an infinite sequence might produce a
+ // conceptually finite sequence, it will take infinite time
+ static constexpr bool infinite = Source::infinite;
};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), selector_);
}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), selector_);
}
* Composer - Helper class for adapting pipelines into functors. Primarily used
* for 'mapOp'.
*/
-template<class Operators>
+template <class Operators>
class Composer {
Operators op_;
+
public:
- explicit Composer(Operators op)
- : op_(std::move(op)) {}
+ explicit Composer(Operators op) : op_(std::move(op)) {}
- template<class Source,
- class Ret = decltype(std::declval<Operators>()
- .compose(std::declval<Source>()))>
+ template <class Source,
+ class Ret = decltype(
+ std::declval<Operators>().compose(std::declval<Source>()))>
Ret operator()(Source&& source) const {
return op_.compose(std::forward<Source>(source));
}
*/
class Batch : public Operator<Batch> {
size_t batchSize_;
+
public:
- explicit Batch(size_t batchSize)
- : batchSize_(batchSize) {
+ explicit Batch(size_t batchSize) : batchSize_(batchSize) {
if (batchSize_ == 0) {
throw std::invalid_argument("Batch size must be non-zero!");
}
}
- template<class Value,
- class Source,
- class StorageType = typename std::decay<Value>::type,
- class VectorType = std::vector<StorageType>>
- class Generator :
- public GenImpl<VectorType&,
- Generator<Value, Source, StorageType, VectorType>> {
+ template <class Value,
+ class Source,
+ class StorageType = typename std::decay<Value>::type,
+ class VectorType = std::vector<StorageType>>
+ class Generator
+ : public GenImpl<VectorType&,
+ Generator<Value, Source, StorageType, VectorType>> {
Source source_;
size_t batchSize_;
- public:
+
+ public:
explicit Generator(Source source, size_t batchSize)
- : source_(std::move(source))
- , batchSize_(batchSize) {}
+ : source_(std::move(source)), batchSize_(batchSize) {}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
VectorType batch_;
batch_.reserve(batchSize_);
bool shouldContinue = source_.apply([&](Value value) -> bool {
- batch_.push_back(std::forward<Value>(value));
- if (batch_.size() == batchSize_) {
- bool needMore = handler(batch_);
- batch_.clear();
- return needMore;
- }
- // Always need more if the handler is not called.
- return true;
- });
+ batch_.push_back(std::forward<Value>(value));
+ if (batch_.size() == batchSize_) {
+ bool needMore = handler(batch_);
+ batch_.clear();
+ return needMore;
+ }
+ // Always need more if the handler is not called.
+ return true;
+ });
// Flush everything, if and only if `handler` hasn't returned false.
if (shouldContinue && !batch_.empty()) {
shouldContinue = handler(batch_);
return shouldContinue;
}
+ // Taking n-tuples of an infinite source is still infinite
static constexpr bool infinite = Source::infinite;
};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), batchSize_);
}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), batchSize_);
}
};
-/*
- * Sinks
- */
/**
- * FoldLeft - Left-associative functional fold. For producing an aggregate value
- * from a seed and a folder function. Useful for custom aggregators on a
- * sequence.
+ * Concat - For flattening generators of generators.
*
- * This type is primarily used through the 'foldl' helper method, like:
+ * This type is usually used through the 'concat' static value, like:
*
- * double movingAverage = from(values)
- * | foldl(0.0, [](double avg, double sample) {
- * return sample * 0.1 + avg * 0.9;
- * });
+ * auto edges =
+ * from(nodes)
+ * | map([](Node& x) {
+ * return from(x.neighbors)
+ * | map([&](Node& y) {
+ * return Edge(x, y);
+ * });
+ * })
+ * | concat
+ * | as<std::set>();
*/
-template<class Seed,
- class Fold>
-class FoldLeft : public Operator<FoldLeft<Seed, Fold>> {
- Seed seed_;
- Fold fold_;
+class Concat : public Operator<Concat> {
public:
- FoldLeft() = default;
- FoldLeft(Seed seed,
- Fold fold)
- : seed_(std::move(seed))
- , fold_(std::move(fold))
- {}
-
- template<class Source,
- class Value>
- Seed compose(const GenImpl<Value, Source>& source) const {
- static_assert(!Source::infinite, "Cannot foldl infinite source");
- Seed accum = seed_;
- source | [&](Value v) {
- accum = fold_(std::move(accum), std::forward<Value>(v));
- };
- return accum;
+ Concat() = default;
+
+ template <class Inner,
+ class Source,
+ class InnerValue = typename std::decay<Inner>::type::ValueType>
+ class Generator
+ : public GenImpl<InnerValue, Generator<Inner, Source, InnerValue>> {
+ Source source_;
+
+ public:
+ explicit Generator(Source source) : source_(std::move(source)) {}
+
+ template <class Handler>
+ bool apply(Handler&& handler) const {
+ return source_.apply([&](Inner inner) -> bool {
+ return inner.apply(std::forward<Handler>(handler));
+ });
+ }
+
+ template <class Body>
+ void foreach(Body&& body) const {
+ source_.foreach([&](Inner inner) {
+ inner.foreach(std::forward<Body>(body));
+ });
+ }
+
+ // Resulting concatination is only finite if both Source and Inner are also
+ // finite. In one sence, if dosn't make sence to call concat when the Inner
+ // generator is infinite (you could just call first), so we could also just
+ // static_assert if the inner is infinite. Taking the less restrictive
+ // approch for now.
+ static constexpr bool infinite =
+ Source::infinite || std::decay<Inner>::type::infinite;
+ };
+
+ template <class Value,
+ class Source,
+ class Gen = Generator<Value, Source>>
+ Gen compose(GenImpl<Value, Source>&& source) const {
+ return Gen(std::move(source.self()));
+ }
+
+ template <class Value,
+ class Source,
+ class Gen = Generator<Value, Source>>
+ Gen compose(const GenImpl<Value, Source>& source) const {
+ return Gen(source.self());
}
};
/**
- * First - For finding the first value in a sequence.
+ * RangeConcat - For flattening generators of iterables.
*
- * This type is primarily used through the 'first' static value, like:
+ * This type is usually used through the 'rconcat' static value, like:
*
- * int firstThreeDigitPrime = seq(100) | filter(isPrime) | first;
+ * map<int, vector<int>> adjacency;
+ * auto sinks =
+ * from(adjacency)
+ * | get<1>()
+ * | rconcat()
+ * | as<std::set>();
*/
-class First : public Operator<First> {
+class RangeConcat : public Operator<RangeConcat> {
public:
- First() = default;
-
- template<class Source,
- class Value,
- class StorageType = typename std::decay<Value>::type>
- StorageType compose(const GenImpl<Value, Source>& source) const {
- Optional<StorageType> accum;
- source | [&](Value v) -> bool {
- accum = std::forward<Value>(v);
- return false;
- };
- if (!accum.hasValue()) {
- throw EmptySequence();
- }
- return std::move(accum.value());
- }
-};
+ RangeConcat() = default;
-/**
- * IsEmpty - a helper class for isEmpty and notEmpty
- *
- * Essentially returns 'result' if the source is empty. Note that this cannot be
- * called on an infinite source, because then there is only one possible return
- * value.
- */
-template <bool emptyResult>
-class IsEmpty : public Operator<IsEmpty<emptyResult>> {
- public:
- IsEmpty() = default;
+ template <class Range,
+ class Source,
+ class InnerValue = typename ValueTypeOfRange<Range>::RefType>
+ class Generator
+ : public GenImpl<InnerValue, Generator<Range, Source, InnerValue>> {
+ Source source_;
- template<class Source,
- class Value>
- bool compose(const GenImpl<Value, Source>& source) const {
- static_assert(!Source::infinite,
- "Cannot call 'all', 'any', 'isEmpty', or 'notEmpty' on "
- "infinite source. 'all' and 'isEmpty' will either return "
- "false or hang. 'any' or 'notEmpty' will either return true "
- "or hang.");
- bool ans = emptyResult;
- source | [&](Value v) -> bool {
- ans = !emptyResult;
- return false;
- };
- return ans;
- }
-};
+ public:
+ explicit Generator(Source source) : source_(std::move(source)) {}
-/**
- * Reduce - Functional reduce, for recursively combining values from a source
- * using a reducer function until there is only one item left. Useful for
- * combining values when an empty sequence doesn't make sense.
- *
- * This type is primarily used through the 'reduce' helper method, like:
- *
- * sring longest = from(names)
- * | reduce([](string&& best, string& current) {
- * return best.size() >= current.size() ? best : current;
- * });
- */
-template<class Reducer>
-class Reduce : public Operator<Reduce<Reducer>> {
- Reducer reducer_;
- public:
- Reduce() = default;
- explicit Reduce(Reducer reducer)
- : reducer_(std::move(reducer))
- {}
+ template <class Body>
+ void foreach(Body&& body) const {
+ source_.foreach([&](Range range) {
+ for (auto& value : range) {
+ body(value);
+ }
+ });
+ }
- template<class Source,
- class Value,
- class StorageType = typename std::decay<Value>::type>
- StorageType compose(const GenImpl<Value, Source>& source) const {
- Optional<StorageType> accum;
- source | [&](Value v) {
- if (accum.hasValue()) {
- accum = reducer_(std::move(accum.value()), std::forward<Value>(v));
- } else {
- accum = std::forward<Value>(v);
- }
- };
- if (!accum.hasValue()) {
- throw EmptySequence();
+ template <class Handler>
+ bool apply(Handler&& handler) const {
+ return source_.apply([&](Range range) -> bool {
+ for (auto& value : range) {
+ if (!handler(value)) {
+ return false;
+ }
+ }
+ return true;
+ });
}
- return accum.value();
- }
-};
-/**
- * Count - for simply counting the items in a collection.
- *
- * This type is usually used through its singleton, 'count':
- *
- * auto shortPrimes = seq(1, 100) | filter(isPrime) | count;
- */
-class Count : public Operator<Count> {
- public:
- Count() = default;
+ // This is similar to concat, except that the inner iterables all are finite
+ // so the only thing that matters is that the source is infinite.
+ static constexpr bool infinite = Source::infinite;
+ };
- template<class Source,
- class Value>
- size_t compose(const GenImpl<Value, Source>& source) const {
- static_assert(!Source::infinite, "Cannot count infinite source");
- return foldl(size_t(0),
- [](size_t accum, Value v) {
- return accum + 1;
- }).compose(source);
+ template <class Value,
+ class Source,
+ class Gen = Generator<Value, Source>>
+ Gen compose(GenImpl<Value, Source>&& source) const {
+ return Gen(std::move(source.self()));
}
-};
-/**
- * Sum - For simply summing up all the values from a source.
- *
- * This type is usually used through its singleton, 'sum':
- *
- * auto gaussSum = seq(1, 100) | sum;
- */
-class Sum : public Operator<Sum> {
- public:
- Sum() = default;
-
- template<class Source,
- class Value,
- class StorageType = typename std::decay<Value>::type>
- StorageType compose(const GenImpl<Value, Source>& source) const {
- static_assert(!Source::infinite, "Cannot sum infinite source");
- return foldl(StorageType(0),
- [](StorageType&& accum, Value v) {
- return std::move(accum) + std::forward<Value>(v);
- }).compose(source);
+ template <class Value,
+ class Source,
+ class Gen = Generator<Value, Source>>
+ Gen compose(const GenImpl<Value, Source>& source) const {
+ return Gen(source.self());
}
};
/**
- * Contains - For testing whether a value matching the given value is contained
- * in a sequence.
- *
- * This type should be used through the 'contains' helper method, like:
+ * GuardImpl - For handling exceptions from downstream computation. Requires the
+ * type of exception to catch, and handler function to invoke in the event of
+ * the exception. Note that the handler may:
+ * 1) return true to continue processing the sequence
+ * 2) return false to end the sequence immediately
+ * 3) throw, to pass the exception to the next catch
+ * The handler must match the signature 'bool(Exception&, Value)'.
*
- * bool contained = seq(1, 10) | map(square) | contains(49);
- */
-template<class Needle>
-class Contains : public Operator<Contains<Needle>> {
- Needle needle_;
- public:
- explicit Contains(Needle needle)
- : needle_(std::move(needle))
- {}
-
- template<class Source,
- class Value,
- class StorageType = typename std::decay<Value>::type>
- bool compose(const GenImpl<Value, Source>& source) const {
- static_assert(!Source::infinite,
- "Calling contains on an infinite source might cause "
- "an infinite loop.");
- return !(source | [this](Value value) {
- return !(needle_ == std::forward<Value>(value));
- });
- }
-};
-
-/**
- * Min - For a value which minimizes a key, where the key is determined by a
- * given selector, and compared by given comparer.
+ * This type is used through the `guard` helper, like so:
*
- * This type is usually used through the singletone 'min' or through the helper
- * functions 'minBy' and 'maxBy'.
+ * auto indexes
+ * = byLine(STDIN_FILENO)
+ * | guard<std::runtime_error>([](std::runtime_error& e,
+ * StringPiece sp) {
+ * LOG(ERROR) << sp << ": " << e.str();
+ * return true; // continue processing subsequent lines
+ * })
+ * | eachTo<int>()
+ * | as<vector>();
*
- * auto oldest = from(people)
- * | minBy([](Person& p) {
- * return p.dateOfBirth;
- * });
- */
-template<class Selector,
- class Comparer>
-class Min : public Operator<Min<Selector, Comparer>> {
- Selector selector_;
- Comparer comparer_;
- public:
- Min() = default;
-
- explicit Min(Selector selector)
- : selector_(std::move(selector))
- {}
-
- Min(Selector selector,
- Comparer comparer)
- : selector_(std::move(selector))
- , comparer_(std::move(comparer))
- {}
-
- template<class Value,
- class Source,
- class StorageType = typename std::decay<Value>::type,
- class Key = typename std::decay<
- typename std::result_of<Selector(Value)>::type
- >::type>
- StorageType compose(const GenImpl<Value, Source>& source) const {
- Optional<StorageType> min;
- Optional<Key> minKey;
- source | [&](Value v) {
- Key key = selector_(std::forward<Value>(v));
- if (!minKey.hasValue() || comparer_(key, minKey.value())) {
- minKey = key;
- min = std::forward<Value>(v);
- }
- };
- if (!min.hasValue()) {
- throw EmptySequence();
- }
- return min.value();
- }
-};
+ * TODO(tjackson): Rename this back to Guard.
+ **/
+template <class Exception, class ErrorHandler>
+class GuardImpl : public Operator<GuardImpl<Exception, ErrorHandler>> {
+ ErrorHandler handler_;
-/**
- * Append - For collecting values from a source into a given output container
- * by appending.
- *
- * This type is usually used through the helper function 'appendTo', like:
- *
- * vector<int64_t> ids;
- * from(results) | map([](Person& p) { return p.id })
- * | appendTo(ids);
- */
-template<class Collection>
-class Append : public Operator<Append<Collection>> {
- Collection* collection_;
public:
- explicit Append(Collection* collection)
- : collection_(collection)
- {}
+ explicit GuardImpl(ErrorHandler handler) : handler_(std::move(handler)) {}
- template<class Value,
- class Source>
- Collection& compose(const GenImpl<Value, Source>& source) const {
- source | [&](Value v) {
- collection_->insert(collection_->end(), std::forward<Value>(v));
- };
- return *collection_;
- }
-};
+ template <class Value, class Source>
+ class Generator : public GenImpl<Value, Generator<Value, Source>> {
+ Source source_;
+ ErrorHandler handler_;
-/**
- * Collect - For collecting values from a source in a collection of the desired
- * type.
- *
- * This type is usually used through the helper function 'as', like:
- *
- * std::string upper = from(stringPiece)
- * | map(&toupper)
- * | as<std::string>();
- */
-template<class Collection>
-class Collect : public Operator<Collect<Collection>> {
- public:
- Collect() = default;
+ public:
+ explicit Generator(Source source, ErrorHandler handler)
+ : source_(std::move(source)), handler_(std::move(handler)) {}
- template<class Value,
- class Source,
- class StorageType = typename std::decay<Value>::type>
- Collection compose(const GenImpl<Value, Source>& source) const {
- Collection collection;
- source | [&](Value v) {
- collection.insert(collection.end(), std::forward<Value>(v));
- };
- return collection;
- }
-};
+ template <class Handler>
+ bool apply(Handler&& handler) const {
+ return source_.apply([&](Value value) -> bool {
+ try {
+ handler(std::forward<Value>(value));
+ return true;
+ } catch (Exception& e) {
+ return handler_(e, std::forward<Value>(value));
+ }
+ });
+ }
+ // Just passes value though, length unaffected
+ static constexpr bool infinite = Source::infinite;
+ };
-/**
- * CollectTemplate - For collecting values from a source in a collection
- * constructed using the specified template type. Given the type of values
- * produced by the given generator, the collection type will be:
- * Container<Value, Allocator<Value>>
- *
- * The allocator defaults to std::allocator, so this may be used for the STL
- * containers by simply using operators like 'as<set>', 'as<deque>',
- * 'as<vector>'. 'as', here is the helper method which is the usual means of
- * consturcting this operator.
- *
- * Example:
- *
- * set<string> uniqueNames = from(names) | as<set>();
- */
-template<template<class, class> class Container,
- template<class> class Allocator>
-class CollectTemplate : public Operator<CollectTemplate<Container, Allocator>> {
- public:
- CollectTemplate() = default;
+ template <class Value,
+ class Source,
+ class Gen = Generator<Value, Source>>
+ Gen compose(GenImpl<Value, Source>&& source) const {
+ return Gen(std::move(source.self()), handler_);
+ }
- template<class Value,
- class Source,
- class StorageType = typename std::decay<Value>::type,
- class Collection = Container<StorageType, Allocator<StorageType>>>
- Collection compose(const GenImpl<Value, Source>& source) const {
- Collection collection;
- source | [&](Value v) {
- collection.insert(collection.end(), std::forward<Value>(v));
- };
- return collection;
+ template <class Value,
+ class Source,
+ class Gen = Generator<Value, Source>>
+ Gen compose(const GenImpl<Value, Source>& source) const {
+ return Gen(source.self(), handler_);
}
};
/**
- * Concat - For flattening generators of generators.
+ * Dereference - For dereferencing a sequence of pointers while filtering out
+ * null pointers.
*
- * This type is usually used through the 'concat' static value, like:
+ * This type is usually used through the 'dereference' static value, like:
*
- * auto edges =
- * from(nodes)
- * | map([](Node& x) {
- * return from(x.neighbors)
- * | map([&](Node& y) {
- * return Edge(x, y);
- * });
- * })
- * | concat
- * | as<std::set>();
+ * auto refs = from(ptrs) | dereference;
*/
-class Concat : public Operator<Concat> {
+class Dereference : public Operator<Dereference> {
public:
- Concat() = default;
+ Dereference() = default;
- template<class Inner,
- class Source,
- class InnerValue = typename std::decay<Inner>::type::ValueType>
- class Generator :
- public GenImpl<InnerValue, Generator<Inner, Source, InnerValue>> {
+ template <class Value,
+ class Source,
+ class Result = decltype(*std::declval<Value>())>
+ class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
Source source_;
+
public:
- explicit Generator(Source source)
- : source_(std::move(source)) {}
+ explicit Generator(Source source) : source_(std::move(source)) {}
- template<class Handler>
- bool apply(Handler&& handler) const {
- return source_.apply([&](Inner inner) -> bool {
- return inner.apply(std::forward<Handler>(handler));
- });
+ template <class Body>
+ void foreach(Body&& body) const {
+ source_.foreach([&](Value value) {
+ if (value) {
+ return body(*value);
+ }
+ });
}
- template<class Body>
- void foreach(Body&& body) const {
- source_.foreach([&](Inner inner) {
- inner.foreach(std::forward<Body>(body));
- });
+ template <class Handler>
+ bool apply(Handler&& handler) const {
+ return source_.apply([&](Value value) -> bool {
+ if (value) {
+ return handler(*value);
+ }
+ return true;
+ });
}
+ // Just passes value though, length unaffected
static constexpr bool infinite = Source::infinite;
};
- template<class Value,
- class Source,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()));
}
- template<class Value,
- class Source,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self());
}
};
/**
- * RangeConcat - For flattening generators of iterables.
+ * Indirect - For producing a sequence of the addresses of the values in the
+ * input.
*
- * This type is usually used through the 'rconcat' static value, like:
+ * This type is usually used through the 'indirect' static value, like:
*
- * map<int, vector<int>> adjacency;
- * auto sinks =
- * from(adjacency)
- * | get<1>()
- * | rconcat()
- * | as<std::set>();
+ * auto ptrs = from(refs) | indirect;
*/
-class RangeConcat : public Operator<RangeConcat> {
+class Indirect : public Operator<Indirect> {
public:
- RangeConcat() = default;
+ Indirect() = default;
- template<class Range,
- class Source,
- class InnerValue = typename ValueTypeOfRange<Range>::RefType>
- class Generator
- : public GenImpl<InnerValue, Generator<Range, Source, InnerValue>> {
+ template <class Value,
+ class Source,
+ class Result = typename std::remove_reference<Value>::type*>
+ class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
Source source_;
+ static_assert(!std::is_rvalue_reference<Value>::value,
+ "Cannot use indirect on an rvalue");
+
public:
- explicit Generator(Source source)
- : source_(std::move(source)) {}
+ explicit Generator(Source source) : source_(std::move(source)) {}
- template<class Body>
+ template <class Body>
void foreach(Body&& body) const {
- source_.foreach([&](Range range) {
- for (auto& value : range) {
- body(value);
- }
- });
+ source_.foreach([&](Value value) {
+ return body(&value);
+ });
}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
- return source_.apply([&](Range range) -> bool {
- for (auto& value : range) {
- if (!handler(value)) {
- return false;
- }
- }
- return true;
- });
+ return source_.apply([&](Value value) -> bool {
+ return handler(&value);
+ });
}
+
+ // Just passes value though, length unaffected
+ static constexpr bool infinite = Source::infinite;
};
- template<class Value,
- class Source,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()));
}
- template<class Value,
- class Source,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self());
}
};
-
/**
- * GuardImpl - For handling exceptions from downstream computation. Requires the
- * type of exception to catch, and handler function to invoke in the event of
- * the exception. Note that the handler may:
- * 1) return true to continue processing the sequence
- * 2) return false to end the sequence immediately
- * 3) throw, to pass the exception to the next catch
- * The handler must match the signature 'bool(Exception&, Value)'.
+ * Cycle - For repeating a sequence forever.
*
- * This type is used through the `guard` helper, like so:
+ * This type is usually used through the 'cycle' static value, like:
*
- * auto indexes
- * = byLine(STDIN_FILENO)
- * | guard<std::runtime_error>([](std::runtime_error& e,
- * StringPiece sp) {
- * LOG(ERROR) << sp << ": " << e.str();
- * return true; // continue processing subsequent lines
- * })
- * | eachTo<int>()
- * | as<vector>();
+ * auto tests
+ * = from(samples)
+ * | cycle
+ * | take(100);
*
- * TODO(tjackson): Rename this back to Guard.
- **/
-template<class Exception,
- class ErrorHandler>
-class GuardImpl : public Operator<GuardImpl<Exception, ErrorHandler>> {
- ErrorHandler handler_;
+ * or in the finite case:
+ *
+ * auto thrice = g | cycle(3);
+ */
+template <bool forever>
+class Cycle : public Operator<Cycle<forever>> {
+ off_t limit_; // not used if forever == true
public:
- explicit GuardImpl(ErrorHandler handler) : handler_(std::move(handler)) {}
+ Cycle() = default;
+
+ explicit Cycle(off_t limit) : limit_(limit) {
+ static_assert(
+ !forever,
+ "Cycle limit consturctor should not be used when forever == true.");
+ }
- template<class Value,
- class Source>
+ template <class Value, class Source>
class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
- ErrorHandler handler_;
- public:
- explicit Generator(Source source,
- ErrorHandler handler)
- : source_(std::move(source)),
- handler_(std::move(handler)) {}
+ off_t limit_;
+
+ public:
+ explicit Generator(Source source, off_t limit)
+ : source_(std::move(source)), limit_(limit) {}
- template<class Handler>
+ template <class Handler>
bool apply(Handler&& handler) const {
- return source_.apply([&](Value value) -> bool {
- try {
- handler(std::forward<Value>(value));
- return true;
- } catch (Exception& e) {
- return handler_(e, std::forward<Value>(value));
+ bool cont;
+ auto handler2 = [&](Value value) {
+ cont = handler(std::forward<Value>(value));
+ return cont;
+ };
+ // Becomes an infinte loop if forever == true
+ for (off_t count = 0; (forever || count != limit_); ++count) {
+ cont = false;
+ source_.apply(handler2);
+ if (!cont) {
+ return false;
}
- });
+ }
+ return true;
}
- static constexpr bool infinite = Source::infinite;
+ // This is the hardest one to infer. If we are simply doing a finite cycle,
+ // then (gen | cycle(n)) is infinite if and only if gen is infinite.
+ // However, if we are doing an infinite cycle, (gen | cycle) is infinite
+ // unless gen is empty. However, we will always mark (gen | cycle) as
+ // infinite, because patterns such as (gen | cycle | count) can either take
+ // on exactly one value, or infinite loop.
+ static constexpr bool infinite = forever || Source::infinite;
};
- template<class Value,
- class Source,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
- return Gen(std::move(source.self()), handler_);
+ return Gen(std::move(source.self()), limit_);
}
- template<class Value,
- class Source,
- class Gen = Generator<Value, Source>>
+ template <class Source,
+ class Value,
+ class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
- return Gen(source.self(), handler_);
+ return Gen(source.self(), limit_);
+ }
+
+ /**
+ * Convenience function for finite cycles used like:
+ *
+ * auto tripled = gen | cycle(3);
+ */
+ Cycle<false> operator()(off_t limit) const { return Cycle<false>(limit); }
+};
+
+/*
+ ******************************* Sinks *****************************************
+ */
+
+/**
+ * FoldLeft - Left-associative functional fold. For producing an aggregate value
+ * from a seed and a folder function. Useful for custom aggregators on a
+ * sequence.
+ *
+ * This type is primarily used through the 'foldl' helper method, like:
+ *
+ * double movingAverage = from(values)
+ * | foldl(0.0, [](double avg, double sample) {
+ * return sample * 0.1 + avg * 0.9;
+ * });
+ */
+template <class Seed, class Fold>
+class FoldLeft : public Operator<FoldLeft<Seed, Fold>> {
+ Seed seed_;
+ Fold fold_;
+
+ public:
+ FoldLeft() = default;
+ FoldLeft(Seed seed, Fold fold)
+ : seed_(std::move(seed)), fold_(std::move(fold)) {}
+
+ template <class Source, class Value>
+ Seed compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite, "Cannot foldl infinite source");
+ Seed accum = seed_;
+ source | [&](Value v) {
+ accum = fold_(std::move(accum), std::forward<Value>(v));
+ };
+ return accum;
+ }
+};
+
+/**
+ * First - For finding the first value in a sequence.
+ *
+ * This type is primarily used through the 'first' static value, like:
+ *
+ * int firstThreeDigitPrime = seq(100) | filter(isPrime) | first;
+ */
+class First : public Operator<First> {
+ public:
+ First() = default;
+
+ template <class Source,
+ class Value,
+ class StorageType = typename std::decay<Value>::type>
+ StorageType compose(const GenImpl<Value, Source>& source) const {
+ Optional<StorageType> accum;
+ source | [&](Value v) -> bool {
+ accum = std::forward<Value>(v);
+ return false;
+ };
+ if (!accum.hasValue()) {
+ throw EmptySequence();
+ }
+ return std::move(accum.value());
+ }
+};
+
+/**
+ * IsEmpty - a helper class for isEmpty and notEmpty
+ *
+ * Essentially returns 'result' if the source is empty. Note that this cannot be
+ * called on an infinite source, because then there is only one possible return
+ * value.
+ *
+ *
+ * Used primarily through 'isEmpty' and 'notEmpty' static values
+ *
+ * bool hasPrimes = g | filter(prime) | notEmpty;
+ * bool lacksEvens = g | filter(even) | isEmpty;
+ *
+ * Also used in the implementation of 'any' and 'all'
+ */
+template <bool emptyResult>
+class IsEmpty : public Operator<IsEmpty<emptyResult>> {
+ public:
+ IsEmpty() = default;
+
+ template <class Source, class Value>
+ bool compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite,
+ "Cannot call 'all', 'any', 'isEmpty', or 'notEmpty' on "
+ "infinite source. 'all' and 'isEmpty' will either return "
+ "false or hang. 'any' or 'notEmpty' will either return true "
+ "or hang.");
+ bool ans = emptyResult;
+ source | [&](Value v) -> bool {
+ ans = !emptyResult;
+ return false;
+ };
+ return ans;
+ }
+};
+
+/**
+ * Reduce - Functional reduce, for recursively combining values from a source
+ * using a reducer function until there is only one item left. Useful for
+ * combining values when an empty sequence doesn't make sense.
+ *
+ * This type is primarily used through the 'reduce' helper method, like:
+ *
+ * sring longest = from(names)
+ * | reduce([](string&& best, string& current) {
+ * return best.size() >= current.size() ? best : current;
+ * });
+ */
+template <class Reducer>
+class Reduce : public Operator<Reduce<Reducer>> {
+ Reducer reducer_;
+
+ public:
+ Reduce() = default;
+ explicit Reduce(Reducer reducer) : reducer_(std::move(reducer)) {}
+
+ template <class Source,
+ class Value,
+ class StorageType = typename std::decay<Value>::type>
+ StorageType compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite, "Cannot reduce infinite source");
+ Optional<StorageType> accum;
+ source | [&](Value v) {
+ if (accum.hasValue()) {
+ accum = reducer_(std::move(accum.value()), std::forward<Value>(v));
+ } else {
+ accum = std::forward<Value>(v);
+ }
+ };
+ if (!accum.hasValue()) {
+ throw EmptySequence();
+ }
+ return accum.value();
+ }
+};
+
+/**
+ * Count - for simply counting the items in a collection.
+ *
+ * This type is usually used through its singleton, 'count':
+ *
+ * auto shortPrimes = seq(1, 100) | filter(isPrime) | count;
+ */
+class Count : public Operator<Count> {
+ public:
+ Count() = default;
+
+ template <class Source, class Value>
+ size_t compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite, "Cannot count infinite source");
+ return foldl(size_t(0),
+ [](size_t accum, Value v) {
+ return accum + 1;
+ }).compose(source);
}
};
/**
- * Cycle - For repeating a sequence forever.
- *
- * This type is usually used through the 'cycle' static value, like:
- *
- * auto tests
- * = from(samples)
- * | cycle
- * | take(100);
+ * Sum - For simply summing up all the values from a source.
*
- * or in the finite case:
+ * This type is usually used through its singleton, 'sum':
*
- * auto thrice = g | cycle(3);
+ * auto gaussSum = seq(1, 100) | sum;
*/
-template <bool forever>
-class Cycle : public Operator<Cycle<forever>> {
- off_t limit_; // not used if forever == true
+class Sum : public Operator<Sum> {
public:
- Cycle() = default;
-
- explicit Cycle(off_t limit)
- : limit_(limit) {
- static_assert(
- !forever,
- "Cycle limit consturctor should not be used when forever == true.");
- }
-
- template<class Value,
- class Source>
- class Generator : public GenImpl<Value, Generator<Value, Source>> {
- Source source_;
- off_t limit_;
- public:
- explicit Generator(Source source, off_t limit)
- : source_(std::move(source))
- , limit_(limit) {}
-
- template<class Handler>
- bool apply(Handler&& handler) const {
- bool cont;
- auto handler2 = [&](Value value) {
- cont = handler(std::forward<Value>(value));
- return cont;
- };
- // Becomes an infinte loop if forever == true
- for (off_t count = 0; (forever || count != limit_); ++count) {
- cont = false;
- source_.apply(handler2);
- if (!cont) {
- return false;
- }
- }
- return true;
- }
-
- // not actually infinite, since an empty generator will end the cycles.
- static constexpr bool infinite = Source::infinite;
- };
+ Sum() = default;
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
- Gen compose(GenImpl<Value, Source>&& source) const {
- return Gen(std::move(source.self()), limit_);
+ template <class Source,
+ class Value,
+ class StorageType = typename std::decay<Value>::type>
+ StorageType compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite, "Cannot sum infinite source");
+ return foldl(StorageType(0),
+ [](StorageType&& accum, Value v) {
+ return std::move(accum) + std::forward<Value>(v);
+ }).compose(source);
}
+};
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
- Gen compose(const GenImpl<Value, Source>& source) const {
- return Gen(source.self(), limit_);
- }
+/**
+ * Contains - For testing whether a value matching the given value is contained
+ * in a sequence.
+ *
+ * This type should be used through the 'contains' helper method, like:
+ *
+ * bool contained = seq(1, 10) | map(square) | contains(49);
+ */
+template <class Needle>
+class Contains : public Operator<Contains<Needle>> {
+ Needle needle_;
- /**
- * Convenience function for finite cycles used like:
- *
- * auto tripled = gen | cycle(3);
- */
- Cycle<false> operator()(off_t limit) const {
- return Cycle<false>(limit);
+ public:
+ explicit Contains(Needle needle) : needle_(std::move(needle)) {}
+
+ template <class Source,
+ class Value,
+ class StorageType = typename std::decay<Value>::type>
+ bool compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite,
+ "Calling contains on an infinite source might cause "
+ "an infinite loop.");
+ return !(source | [this](Value value) {
+ return !(needle_ == std::forward<Value>(value));
+ });
}
};
/**
- * Dereference - For dereferencing a sequence of pointers while filtering out
- * null pointers.
+ * Min - For a value which minimizes a key, where the key is determined by a
+ * given selector, and compared by given comparer.
*
- * This type is usually used through the 'dereference' static value, like:
+ * This type is usually used through the singletone 'min' or through the helper
+ * functions 'minBy' and 'maxBy'.
*
- * auto refs = from(ptrs) | dereference;
+ * auto oldest = from(people)
+ * | minBy([](Person& p) {
+ * return p.dateOfBirth;
+ * });
*/
-class Dereference : public Operator<Dereference> {
+template <class Selector, class Comparer>
+class Min : public Operator<Min<Selector, Comparer>> {
+ Selector selector_;
+ Comparer comparer_;
+
public:
- Dereference() = default;
+ Min() = default;
- template<class Value,
- class Source,
- class Result = decltype(*std::declval<Value>())>
- class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
- Source source_;
- public:
- explicit Generator(Source source)
- : source_(std::move(source)) {}
+ explicit Min(Selector selector) : selector_(std::move(selector)) {}
- template<class Body>
- void foreach(Body&& body) const {
- source_.foreach([&](Value value) {
- if (value) {
- return body(*value);
- }
- });
- }
+ Min(Selector selector, Comparer comparer)
+ : selector_(std::move(selector)), comparer_(std::move(comparer)) {}
- template<class Handler>
- bool apply(Handler&& handler) const {
- return source_.apply([&](Value value) -> bool {
- if (value) {
- return handler(*value);
- }
- return true;
- });
+ template <class Value,
+ class Source,
+ class StorageType = typename std::decay<Value>::type,
+ class Key = typename std::decay<
+ typename std::result_of<Selector(Value)>::type>::type>
+ StorageType compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite,
+ "Calling min or max on an infinite source will cause "
+ "an infinite loop.");
+ Optional<StorageType> min;
+ Optional<Key> minKey;
+ source | [&](Value v) {
+ Key key = selector_(std::forward<Value>(v));
+ if (!minKey.hasValue() || comparer_(key, minKey.value())) {
+ minKey = key;
+ min = std::forward<Value>(v);
+ }
+ };
+ if (!min.hasValue()) {
+ throw EmptySequence();
}
+ return min.value();
+ }
+};
- // not actually infinite, since an empty generator will end the cycles.
- static constexpr bool infinite = Source::infinite;
- };
+/**
+ * Append - For collecting values from a source into a given output container
+ * by appending.
+ *
+ * This type is usually used through the helper function 'appendTo', like:
+ *
+ * vector<int64_t> ids;
+ * from(results) | map([](Person& p) { return p.id })
+ * | appendTo(ids);
+ */
+template <class Collection>
+class Append : public Operator<Append<Collection>> {
+ Collection* collection_;
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
- Gen compose(GenImpl<Value, Source>&& source) const {
- return Gen(std::move(source.self()));
- }
+ public:
+ explicit Append(Collection* collection) : collection_(collection) {}
- template<class Source,
- class Value,
- class Gen = Generator<Value, Source>>
- Gen compose(const GenImpl<Value, Source>& source) const {
- return Gen(source.self());
+ template <class Value, class Source>
+ Collection& compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite, "Cannot appendTo with infinite source");
+ source | [&](Value v) {
+ collection_->insert(collection_->end(), std::forward<Value>(v));
+ };
+ return *collection_;
}
};
/**
- * Indirect - For producing a sequence of the addresses of the values in the
- * input.
+ * Collect - For collecting values from a source in a collection of the desired
+ * type.
*
- * This type is usually used through the 'indirect' static value, like:
+ * This type is usually used through the helper function 'as', like:
*
- * auto ptrs = from(refs) | indirect;
+ * std::string upper = from(stringPiece)
+ * | map(&toupper)
+ * | as<std::string>();
*/
-class Indirect : public Operator<Indirect> {
+template <class Collection>
+class Collect : public Operator<Collect<Collection>> {
public:
- Indirect() = default;
+ Collect() = default;
template <class Value,
class Source,
- class Result = typename std::remove_reference<Value>::type*>
- class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
- Source source_;
- static_assert(!std::is_rvalue_reference<Value>::value,
- "Cannot use indirect on an rvalue");
-
- public:
- explicit Generator(Source source) : source_(std::move(source)) {}
-
- template <class Body>
- void foreach(Body&& body) const {
- source_.foreach([&](Value value) {
- return body(&value);
- });
- }
-
- template <class Handler>
- bool apply(Handler&& handler) const {
- return source_.apply([&](Value value) -> bool {
- return handler(&value);
- });
- }
-
- // not actually infinite, since an empty generator will end the cycles.
- static constexpr bool infinite = Source::infinite;
- };
-
- template <class Source, class Value, class Gen = Generator<Value, Source>>
- Gen compose(GenImpl<Value, Source>&& source) const {
- return Gen(std::move(source.self()));
+ class StorageType = typename std::decay<Value>::type>
+ Collection compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite,
+ "Cannot convert infinite source to object with as.");
+ Collection collection;
+ source | [&](Value v) {
+ collection.insert(collection.end(), std::forward<Value>(v));
+ };
+ return collection;
}
+};
- template <class Source, class Value, class Gen = Generator<Value, Source>>
- Gen compose(const GenImpl<Value, Source>& source) const {
- return Gen(source.self());
+/**
+ * CollectTemplate - For collecting values from a source in a collection
+ * constructed using the specified template type. Given the type of values
+ * produced by the given generator, the collection type will be:
+ * Container<Value, Allocator<Value>>
+ *
+ * The allocator defaults to std::allocator, so this may be used for the STL
+ * containers by simply using operators like 'as<set>', 'as<deque>',
+ * 'as<vector>'. 'as', here is the helper method which is the usual means of
+ * consturcting this operator.
+ *
+ * Example:
+ *
+ * set<string> uniqueNames = from(names) | as<set>();
+ */
+template <template <class, class> class Container,
+ template <class> class Allocator>
+class CollectTemplate : public Operator<CollectTemplate<Container, Allocator>> {
+ public:
+ CollectTemplate() = default;
+
+ template <class Value,
+ class Source,
+ class StorageType = typename std::decay<Value>::type,
+ class Collection = Container<StorageType, Allocator<StorageType>>>
+ Collection compose(const GenImpl<Value, Source>& source) const {
+ static_assert(!Source::infinite,
+ "Cannot convert infinite source to object with as.");
+ Collection collection;
+ source | [&](Value v) {
+ collection.insert(collection.end(), std::forward<Value>(v));
+ };
+ return collection;
}
};
/**
* VirtualGen<T> - For wrapping template types in simple polymorphic wrapper.
**/
-template<class Value>
+template <class Value>
class VirtualGen : public GenImpl<Value, VirtualGen<Value>> {
class WrapperBase {
public:
virtual std::unique_ptr<const WrapperBase> clone() const = 0;
};
- template<class Wrapped>
+ template <class Wrapped>
class WrapperImpl : public WrapperBase {
Wrapped wrapped_;
+
public:
- explicit WrapperImpl(Wrapped wrapped)
- : wrapped_(std::move(wrapped)) {
- }
+ explicit WrapperImpl(Wrapped wrapped) : wrapped_(std::move(wrapped)) {}
virtual bool apply(const std::function<bool(Value)>& handler) const {
return wrapped_.apply(handler);
VirtualGen(VirtualGen&& source) noexcept
: wrapper_(std::move(source.wrapper_)) {}
- VirtualGen(const VirtualGen& source)
- : wrapper_(source.wrapper_->clone()) {}
+ VirtualGen(const VirtualGen& source) : wrapper_(source.wrapper_->clone()) {}
VirtualGen& operator=(const VirtualGen& source) {
wrapper_.reset(source.wrapper_->clone());
}
VirtualGen& operator=(VirtualGen&& source) noexcept {
- wrapper_= std::move(source.wrapper_);
+ wrapper_ = std::move(source.wrapper_);
return *this;
}
constexpr detail::First first{};
-/**
- * Use 'isEmpty' and 'notEmpty' for detecting if there are any values or not.
- *
- * bool hasPrimes = g | filter(prime) | notEmpty;
- * bool lacksEvens = g | filter(even) | isEmpty;
- */
constexpr detail::IsEmpty<true> isEmpty{};
constexpr detail::IsEmpty<false> notEmpty{};
constexpr detail::Indirect indirect{};
-inline detail::Take take(size_t count) {
- return detail::Take(count);
-}
+inline detail::Take take(size_t count) { return detail::Take(count); }
-inline detail::Stride stride(size_t s) {
- return detail::Stride(s);
-}
+inline detail::Stride stride(size_t s) { return detail::Stride(s); }
-template<class Random = std::default_random_engine>
+template <class Random = std::default_random_engine>
inline detail::Sample<Random> sample(size_t count, Random rng = Random()) {
return detail::Sample<Random>(count, std::move(rng));
}
-inline detail::Skip skip(size_t count) {
- return detail::Skip(count);
-}
+inline detail::Skip skip(size_t count) { return detail::Skip(count); }
inline detail::Batch batch(size_t batchSize) {
return detail::Batch(batchSize);
}
-}} //folly::gen
+}} // folly::gen
#pragma GCC diagnostic pop