Commit 062bb26d authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Apply clang-format to folly/gen/

Summary: [Folly] Apply `clang-format` to `folly/gen/`.

Reviewed By: Orvid

Differential Revision: D9671968

fbshipit-source-id: 1164cf0d236914b5fd7ed35d5d41c785935e876b
parent d98241e2
......@@ -32,11 +32,11 @@ namespace gen {
* ArgumentReference - For determining ideal argument type to receive a value.
*/
template <class T>
struct ArgumentReference
: public std::conditional<
struct ArgumentReference : public std::conditional<
std::is_reference<T>::value,
T, // T& -> T&, T&& -> T&&, const T& -> const T&
typename std::conditional<std::is_const<T>::value,
typename std::conditional<
std::is_const<T>::value,
T&, // const int -> const int&
T&& // int -> int&&
>::type> {};
......@@ -47,8 +47,8 @@ struct ArgumentReference
template <class Key, class Value>
class Group : public GenImpl<Value&&, Group<Key, Value>> {
public:
static_assert(!std::is_reference<Key>::value &&
!std::is_reference<Value>::value,
static_assert(
!std::is_reference<Key>::value && !std::is_reference<Value>::value,
"Key and Value must be decayed types");
typedef std::vector<Value> VectorType;
......@@ -58,11 +58,19 @@ class Group : public GenImpl<Value&&, Group<Key, Value>> {
Group(Key key, VectorType values)
: key_(std::move(key)), values_(std::move(values)) {}
const Key& key() const { return key_; }
const Key& key() const {
return key_;
}
size_t size() const { return values_.size(); }
const VectorType& values() const { return values_; }
VectorType& values() { return values_; }
size_t size() const {
return values_.size();
}
const VectorType& values() const {
return values_;
}
VectorType& values() {
return values_;
}
VectorType operator|(const detail::Collect<VectorType>&) const {
return values();
......@@ -163,7 +171,8 @@ class ReferencedSource
template <class StorageType, class Container>
class CopiedSource
: public GenImpl<const StorageType&, CopiedSource<StorageType, Container>> {
static_assert(!std::is_reference<StorageType>::value,
static_assert(
!std::is_reference<StorageType>::value,
"StorageType must be decayed");
public:
......@@ -172,7 +181,8 @@ class CopiedSource
// 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,
static_assert(
!std::is_reference<Container>::value,
"Can't copy into a reference");
std::shared_ptr<const Container> copy_;
......@@ -224,7 +234,8 @@ class CopiedSource
* Reminder: Be careful not to invalidate iterators when using ranges like this.
*/
template <class Iterator>
class RangeSource : public GenImpl<typename Range<Iterator>::reference,
class RangeSource : public GenImpl<
typename Range<Iterator>::reference,
RangeSource<Iterator>> {
Range<Iterator> range_;
......@@ -266,8 +277,8 @@ class RangeSource : public GenImpl<typename Range<Iterator>::reference,
*/
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,
static_assert(
!std::is_reference<Value>::value && !std::is_const<Value>::value,
"Value mustn't be const or ref.");
Value start_;
SequenceImpl impl_;
......@@ -306,8 +317,12 @@ class RangeImpl {
public:
explicit RangeImpl(Value end) : end_(std::move(end)) {}
bool test(const Value& current) const { return current < end_; }
void step(Value& current) const { ++current; }
bool test(const Value& current) const {
return current < end_;
}
void step(Value& current) const {
++current;
}
static constexpr bool infinite = false;
};
......@@ -319,8 +334,12 @@ class RangeWithStepImpl {
public:
explicit RangeWithStepImpl(Value end, Distance 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_; }
bool test(const Value& current) const {
return current < end_;
}
void step(Value& current) const {
current += step_;
}
static constexpr bool infinite = false;
};
......@@ -330,8 +349,12 @@ class SeqImpl {
public:
explicit SeqImpl(Value end) : end_(std::move(end)) {}
bool test(const Value& current) const { return current <= end_; }
void step(Value& current) const { ++current; }
bool test(const Value& current) const {
return current <= end_;
}
void step(Value& current) const {
++current;
}
static constexpr bool infinite = false;
};
......@@ -343,16 +366,24 @@ class SeqWithStepImpl {
public:
explicit SeqWithStepImpl(Value end, Distance 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_; }
bool test(const Value& current) const {
return current <= end_;
}
void step(Value& current) const {
current += step_;
}
static constexpr bool infinite = false;
};
template <class Value>
class InfiniteImpl {
public:
bool test(const Value& /* current */) const { return true; }
void step(Value& current) const { ++current; }
bool test(const Value& /* current */) const {
return true;
}
void step(Value& current) const {
++current;
}
static constexpr bool infinite = true;
};
......@@ -417,7 +448,8 @@ class Empty : public GenImpl<Value, Empty<Value>> {
template <class Value>
class SingleReference : public GenImpl<Value&, SingleReference<Value>> {
static_assert(!std::is_reference<Value>::value,
static_assert(
!std::is_reference<Value>::value,
"SingleReference requires non-ref types");
Value* ptr_;
......@@ -440,7 +472,8 @@ class SingleReference : public GenImpl<Value&, SingleReference<Value>> {
template <class Value>
class SingleCopy : public GenImpl<const Value&, SingleCopy<Value>> {
static_assert(!std::is_reference<Value>::value,
static_assert(
!std::is_reference<Value>::value,
"SingleCopy requires non-ref types");
Value value_;
......@@ -848,12 +881,13 @@ class Sample : public Operator<Sample<Random>> {
class Source,
class Rand,
class StorageType = typename std::decay<Value>::type>
class Generator
: public GenImpl<StorageType&&,
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,
static_assert(
Random::max() >= std::numeric_limits<int32_t>::max() - 1,
"Random number generator must support big values");
Source source_;
size_t count_;
......@@ -1284,15 +1318,15 @@ class TypeAssertion : public Operator<TypeAssertion<Expected>> {
public:
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");
static_assert(
std::is_same<Expected, Value>::value, "assert_type() check failed");
return source.self();
}
template <class Source, class Value>
Source&& compose(GenImpl<Value, Source>&& source) const {
static_assert(std::is_same<Expected, Value>::value,
"assert_type() check failed");
static_assert(
std::is_same<Expected, Value>::value, "assert_type() check failed");
return std::move(source.self());
}
};
......@@ -1421,8 +1455,8 @@ class Batch : public Operator<Batch> {
class Source,
class StorageType = typename std::decay<Value>::type,
class VectorType = std::vector<StorageType>>
class Generator
: public GenImpl<VectorType&,
class Generator : public GenImpl<
VectorType&,
Generator<Value, Source, StorageType, VectorType>> {
Source source_;
size_t batchSize_;
......@@ -1605,9 +1639,8 @@ class Concat : public Operator<Concat> {
template <class Body>
void foreach(Body&& body) const {
source_.foreach([&](Inner inner) {
inner.foreach(std::forward<Body>(body));
});
source_.foreach(
[&](Inner inner) { inner.foreach(std::forward<Body>(body)); });
}
// Resulting concatination is only finite if both Source and Inner are also
......@@ -1834,7 +1867,8 @@ class Indirect : public Operator<Indirect> {
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,
static_assert(
!std::is_rvalue_reference<Value>::value,
"Cannot use indirect on an rvalue");
public:
......@@ -1842,9 +1876,8 @@ class Indirect : public Operator<Indirect> {
template <class Body>
void foreach(Body&& body) const {
source_.foreach([&](Value value) {
return body(&std::forward<Value>(value));
});
source_.foreach(
[&](Value value) { return body(&std::forward<Value>(value)); });
}
template <class Handler>
......@@ -1946,7 +1979,9 @@ class Cycle : public Operator<Cycle<forever>> {
*
* auto tripled = gen | cycle(3);
*/
Cycle<false> operator()(off_t limit) const { return Cycle<false>(limit); }
Cycle<false> operator()(off_t limit) const {
return Cycle<false>(limit);
}
};
/*
......@@ -2033,14 +2068,14 @@ class IsEmpty : public Operator<IsEmpty<emptyResult>> {
template <class Source, class Value>
bool compose(const GenImpl<Value, Source>& source) const {
static_assert(!Source::infinite,
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 {
source | [&](Value /* v */) -> bool {
ans = !emptyResult;
return false;
};
......@@ -2100,8 +2135,8 @@ class Count : public Operator<Count> {
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; })
return foldl(
size_t(0), [](size_t accum, Value /* v */) { return accum + 1; })
.compose(source);
}
};
......@@ -2123,10 +2158,12 @@ class Sum : public Operator<Sum> {
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),
return foldl(
StorageType(0),
[](StorageType&& accum, Value v) {
return std::move(accum) + std::forward<Value>(v);
}).compose(source);
})
.compose(source);
}
};
......@@ -2150,7 +2187,8 @@ class Contains : public Operator<Contains<Needle>> {
class Value,
class StorageType = typename std::decay<Value>::type>
bool compose(const GenImpl<Value, Source>& source) const {
static_assert(!Source::infinite,
static_assert(
!Source::infinite,
"Calling contains on an infinite source might cause "
"an infinite loop.");
return !(source | [this](Value value) {
......@@ -2195,7 +2233,8 @@ class Min : public Operator<Min<Selector, Comparer>> {
class StorageType = typename std::decay<Value>::type,
class Key = typename std::decay<invoke_result_t<Selector, Value>>::type>
Optional<StorageType> compose(const GenImpl<Value, Source>& source) const {
static_assert(!Source::infinite,
static_assert(
!Source::infinite,
"Calling min or max on an infinite source will cause "
"an infinite loop.");
Optional<StorageType> min;
......@@ -2261,8 +2300,8 @@ class Collect : public Operator<Collect<Collection>> {
class Source,
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.");
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));
......@@ -2299,8 +2338,8 @@ class CollectTemplate : public Operator<CollectTemplate<Container, Allocator>> {
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.");
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));
......@@ -2326,8 +2365,12 @@ class UnwrapOr {
explicit UnwrapOr(T&& value) : value_(std::move(value)) {}
explicit UnwrapOr(const T& value) : value_(value) {}
T& value() { return value_; }
const T& value() const { return value_; }
T& value() {
return value_;
}
const T& value() const {
return value_;
}
private:
T value_;
......@@ -2543,14 +2586,18 @@ inline detail::Take take(Number count) {
return detail::Take(static_cast<size_t>(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>
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);
......
......@@ -86,8 +86,8 @@ namespace gen {
class Less {
public:
template <class First, class Second>
auto operator()(const First& first, const Second& second) const ->
decltype(first < second) {
auto operator()(const First& first, const Second& second) const
-> decltype(first < second) {
return first < second;
}
};
......@@ -95,8 +95,8 @@ class Less {
class Greater {
public:
template <class First, class Second>
auto operator()(const First& first, const Second& second) const ->
decltype(first > second) {
auto operator()(const First& first, const Second& second) const
-> decltype(first > second) {
return first > second;
}
};
......@@ -105,8 +105,8 @@ template <int n>
class Get {
public:
template <class Value>
auto operator()(Value&& value) const ->
decltype(std::get<n>(std::forward<Value>(value))) {
auto operator()(Value&& value) const
-> decltype(std::get<n>(std::forward<Value>(value))) {
return std::get<n>(std::forward<Value>(value));
}
};
......@@ -115,12 +115,12 @@ template <class Class, class Result>
class MemberFunction {
public:
typedef Result (Class::*MemberPtr)();
private:
MemberPtr member_;
public:
explicit MemberFunction(MemberPtr member)
: member_(member)
{}
explicit MemberFunction(MemberPtr member) : member_(member) {}
Result operator()(Class&& x) const {
return (x.*member_)();
......@@ -136,15 +136,15 @@ class MemberFunction {
};
template <class Class, class Result>
class ConstMemberFunction{
class ConstMemberFunction {
public:
typedef Result (Class::*MemberPtr)() const;
private:
MemberPtr member_;
public:
explicit ConstMemberFunction(MemberPtr member)
: member_(member)
{}
explicit ConstMemberFunction(MemberPtr member) : member_(member) {}
Result operator()(const Class& x) const {
return (x.*member_)();
......@@ -158,13 +158,13 @@ class ConstMemberFunction{
template <class Class, class FieldType>
class Field {
public:
typedef FieldType (Class::*FieldPtr);
typedef FieldType(Class::*FieldPtr);
private:
FieldPtr field_;
public:
explicit Field(FieldPtr field)
: field_(field)
{}
explicit Field(FieldPtr field) : field_(field) {}
const FieldType& operator()(const Class& x) const {
return x.*field_;
......@@ -190,8 +190,8 @@ class Field {
class Move {
public:
template <class Value>
auto operator()(Value&& value) const ->
decltype(std::move(std::forward<Value>(value))) {
auto operator()(Value&& value) const
-> decltype(std::move(std::forward<Value>(value))) {
return std::move(std::forward<Value>(value));
}
};
......@@ -206,9 +206,7 @@ class Negate {
public:
Negate() = default;
explicit Negate(Predicate pred)
: pred_(std::move(pred))
{}
explicit Negate(Predicate pred) : pred_(std::move(pred)) {}
template <class Arg>
bool operator()(Arg&& arg) const {
......@@ -274,7 +272,6 @@ struct ValueTypeOfRange {
using StorageType = typename std::decay<RefType>::type;
};
/*
* Sources
*/
......@@ -577,7 +574,7 @@ Map mapOp(Operator op) {
*/
enum MemberType {
Const,
Mutable
Mutable,
};
/**
......@@ -588,14 +585,14 @@ enum MemberType {
template <MemberType Constness>
struct ExprIsConst {
enum {
value = Constness == Const
value = Constness == Const,
};
};
template <MemberType Constness>
struct ExprIsMutable {
enum {
value = Constness == Mutable
value = Constness == Mutable,
};
};
......@@ -605,8 +602,8 @@ template <
class Return,
class Mem = ConstMemberFunction<Class, Return>,
class Map = detail::Map<Mem>>
typename std::enable_if<ExprIsConst<Constness>::value, Map>::type
member(Return (Class::*member)() const) {
typename std::enable_if<ExprIsConst<Constness>::value, Map>::type member(
Return (Class::*member)() const) {
return Map(Mem(member));
}
......@@ -616,8 +613,8 @@ template <
class Return,
class Mem = MemberFunction<Class, Return>,
class Map = detail::Map<Mem>>
typename std::enable_if<ExprIsMutable<Constness>::value, Map>::type
member(Return (Class::*member)()) {
typename std::enable_if<ExprIsMutable<Constness>::value, Map>::type member(
Return (Class::*member)()) {
return Map(Mem(member));
}
......@@ -671,10 +668,8 @@ template <
class Selector = Identity,
class Comparer = Less,
class Order = detail::Order<Selector, Comparer>>
Order orderBy(Selector selector = Selector(),
Comparer comparer = Comparer()) {
return Order(std::move(selector),
std::move(comparer));
Order orderBy(Selector selector = Selector(), Comparer comparer = Comparer()) {
return Order(std::move(selector), std::move(comparer));
}
template <
......@@ -793,10 +788,8 @@ Composed all(Predicate pred = Predicate()) {
}
template <class Seed, class Fold, class FoldLeft = detail::FoldLeft<Seed, Fold>>
FoldLeft foldl(Seed seed = Seed(),
Fold fold = Fold()) {
return FoldLeft(std::move(seed),
std::move(fold));
FoldLeft foldl(Seed seed = Seed(), Fold fold = Fold()) {
return FoldLeft(std::move(seed), std::move(fold));
}
template <class Reducer, class Reduce = detail::Reduce<Reducer>>
......
......@@ -37,6 +37,7 @@ template <class Container>
class Interleave : public Operator<Interleave<Container>> {
// see comment about copies in CopiedSource
const std::shared_ptr<const Container> container_;
public:
explicit Interleave(Container container)
: container_(new Container(std::move(container))) {}
......@@ -47,14 +48,15 @@ class Interleave : public Operator<Interleave<Container>> {
const std::shared_ptr<const Container> container_;
typedef const typename Container::value_type& ConstRefType;
static_assert(std::is_same<const Value&, ConstRefType>::value,
static_assert(
std::is_same<const Value&, ConstRefType>::value,
"Only matching types may be interleaved");
public:
explicit Generator(Source source,
explicit Generator(
Source source,
const std::shared_ptr<const Container> container)
: source_(std::move(source)),
container_(container) { }
: source_(std::move(source)), container_(container) {}
template <class Handler>
bool apply(Handler&& handler) const {
......@@ -97,6 +99,7 @@ template <class Container>
class Zip : public Operator<Zip<Container>> {
// see comment about copies in CopiedSource
const std::shared_ptr<const Container> container_;
public:
explicit Zip(Container container)
: container_(new Container(std::move(container))) {}
......@@ -108,16 +111,16 @@ class Zip : public Operator<Zip<Container>> {
class Result = std::tuple<
typename std::decay<Value1>::type,
typename std::decay<Value2>::type>>
class Generator : public GenImpl<Result,
Generator<Value1,Source,Value2,Result>> {
class Generator
: public GenImpl<Result, Generator<Value1, Source, Value2, Result>> {
Source source_;
const std::shared_ptr<const Container> container_;
public:
explicit Generator(Source source,
explicit Generator(
Source source,
const std::shared_ptr<const Container> container)
: source_(std::move(source)),
container_(container) { }
: source_(std::move(source)), container_(container) {}
template <class Handler>
bool apply(Handler&& handler) const {
......@@ -147,47 +150,44 @@ class Zip : public Operator<Zip<Container>> {
};
template <class... Types1, class... Types2>
auto add_to_tuple(std::tuple<Types1...> t1, std::tuple<Types2...> t2) ->
std::tuple<Types1..., Types2...> {
auto add_to_tuple(std::tuple<Types1...> t1, std::tuple<Types2...> t2)
-> std::tuple<Types1..., Types2...> {
return std::tuple_cat(std::move(t1), std::move(t2));
}
template <class... Types1, class Type2>
auto add_to_tuple(std::tuple<Types1...> t1, Type2&& t2) ->
decltype(std::tuple_cat(std::move(t1),
std::make_tuple(std::forward<Type2>(t2)))) {
return std::tuple_cat(std::move(t1),
std::make_tuple(std::forward<Type2>(t2)));
auto add_to_tuple(std::tuple<Types1...> t1, Type2&& t2) -> decltype(
std::tuple_cat(std::move(t1), std::make_tuple(std::forward<Type2>(t2)))) {
return std::tuple_cat(
std::move(t1), std::make_tuple(std::forward<Type2>(t2)));
}
template <class Type1, class... Types2>
auto add_to_tuple(Type1&& t1, std::tuple<Types2...> t2) ->
decltype(std::tuple_cat(std::make_tuple(std::forward<Type1>(t1)),
std::move(t2))) {
return std::tuple_cat(std::make_tuple(std::forward<Type1>(t1)),
std::move(t2));
auto add_to_tuple(Type1&& t1, std::tuple<Types2...> t2) -> decltype(
std::tuple_cat(std::make_tuple(std::forward<Type1>(t1)), std::move(t2))) {
return std::tuple_cat(
std::make_tuple(std::forward<Type1>(t1)), std::move(t2));
}
template <class Type1, class Type2>
auto add_to_tuple(Type1&& t1, Type2&& t2) ->
decltype(std::make_tuple(std::forward<Type1>(t1),
std::forward<Type2>(t2))) {
return std::make_tuple(std::forward<Type1>(t1),
std::forward<Type2>(t2));
auto add_to_tuple(Type1&& t1, Type2&& t2) -> decltype(
std::make_tuple(std::forward<Type1>(t1), std::forward<Type2>(t2))) {
return std::make_tuple(std::forward<Type1>(t1), std::forward<Type2>(t2));
}
// Merges a 2-tuple into a single tuple (get<0> could already be a tuple)
class MergeTuples {
public:
template <class Tuple>
auto operator()(Tuple&& value) const ->
decltype(add_to_tuple(std::get<0>(std::forward<Tuple>(value)),
auto operator()(Tuple&& value) const -> decltype(add_to_tuple(
std::get<0>(std::forward<Tuple>(value)),
std::get<1>(std::forward<Tuple>(value)))) {
static_assert(std::tuple_size<
typename std::remove_reference<Tuple>::type
>::value == 2,
static_assert(
std::tuple_size<typename std::remove_reference<Tuple>::type>::value ==
2,
"Can only merge tuples of size 2");
return add_to_tuple(std::get<0>(std::forward<Tuple>(value)),
return add_to_tuple(
std::get<0>(std::forward<Tuple>(value)),
std::get<1>(std::forward<Tuple>(value)));
}
};
......
......@@ -108,8 +108,7 @@ template <
class Left,
class Right,
class Composed = detail::Composed<Left, Right>>
Composed operator|(const Operator<Left>& left,
const Operator<Right>& right) {
Composed operator|(const Operator<Left>& left, const Operator<Right>& right) {
return Composed(left.self(), right.self());
}
......@@ -117,8 +116,7 @@ template <
class Left,
class Right,
class Composed = detail::Composed<Left, Right>>
Composed operator|(const Operator<Left>& left,
Operator<Right>&& right) {
Composed operator|(const Operator<Left>& left, Operator<Right>&& right) {
return Composed(left.self(), std::move(right.self()));
}
......@@ -126,8 +124,7 @@ template <
class Left,
class Right,
class Composed = detail::Composed<Left, Right>>
Composed operator|(Operator<Left>&& left,
const Operator<Right>& right) {
Composed operator|(Operator<Left>&& left, const Operator<Right>& right) {
return Composed(std::move(left.self()), right.self());
}
......@@ -135,8 +132,7 @@ template <
class Left,
class Right,
class Composed = detail::Composed<Left, Right>>
Composed operator|(Operator<Left>&& left,
Operator<Right>&& right) {
Composed operator|(Operator<Left>&& left, Operator<Right>&& right) {
return Composed(std::move(left.self()), std::move(right.self()));
}
......@@ -201,7 +197,8 @@ template <
class RightValue,
class Right,
class Chain = detail::Chain<LeftValue, Left, Right>>
Chain operator+(const GenImpl<LeftValue, Left>& left,
Chain operator+(
const GenImpl<LeftValue, Left>& left,
const GenImpl<RightValue, Right>& right) {
static_assert(
std::is_same<LeftValue, RightValue>::value,
......@@ -215,7 +212,8 @@ template <
class RightValue,
class Right,
class Chain = detail::Chain<LeftValue, Left, Right>>
Chain operator+(const GenImpl<LeftValue, Left>& left,
Chain operator+(
const GenImpl<LeftValue, Left>& left,
GenImpl<RightValue, Right>&& right) {
static_assert(
std::is_same<LeftValue, RightValue>::value,
......@@ -229,7 +227,8 @@ template <
class RightValue,
class Right,
class Chain = detail::Chain<LeftValue, Left, Right>>
Chain operator+(GenImpl<LeftValue, Left>&& left,
Chain operator+(
GenImpl<LeftValue, Left>&& left,
const GenImpl<RightValue, Right>& right) {
static_assert(
std::is_same<LeftValue, RightValue>::value,
......@@ -243,7 +242,8 @@ template <
class RightValue,
class Right,
class Chain = detail::Chain<LeftValue, Left, Right>>
Chain operator+(GenImpl<LeftValue, Left>&& left,
Chain operator+(
GenImpl<LeftValue, Left>&& left,
GenImpl<RightValue, Right>&& right) {
static_assert(
std::is_same<LeftValue, RightValue>::value,
......@@ -259,8 +259,8 @@ template <class Value, class Gen, class Handler>
typename std::enable_if<
IsCompatibleSignature<Handler, void(Value)>::value>::type
operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
static_assert(!Gen::infinite,
"Cannot pull all values from an infinite sequence.");
static_assert(
!Gen::infinite, "Cannot pull all values from an infinite sequence.");
gen.self().foreach(std::forward<Handler>(handler));
}
......@@ -269,9 +269,9 @@ operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
* gen | [](Value v) -> bool { return shouldContinue(); };
*/
template <class Value, class Gen, class Handler>
typename std::enable_if<
IsCompatibleSignature<Handler, bool(Value)>::value, bool>::type
operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
typename std::
enable_if<IsCompatibleSignature<Handler, bool(Value)>::value, bool>::type
operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
return gen.self().apply(std::forward<Handler>(handler));
}
......@@ -281,14 +281,14 @@ operator|(const GenImpl<Value, Gen>& gen, Handler&& handler) {
* gen | map(square) | sum
*/
template <class Value, class Gen, class Op>
auto operator|(const GenImpl<Value, Gen>& gen, const Operator<Op>& op) ->
decltype(op.self().compose(gen.self())) {
auto operator|(const GenImpl<Value, Gen>& gen, const Operator<Op>& op)
-> decltype(op.self().compose(gen.self())) {
return op.self().compose(gen.self());
}
template <class Value, class Gen, class Op>
auto operator|(GenImpl<Value, Gen>&& gen, const Operator<Op>& op) ->
decltype(op.self().compose(std::move(gen.self()))) {
auto operator|(GenImpl<Value, Gen>&& gen, const Operator<Op>& op)
-> decltype(op.self().compose(std::move(gen.self()))) {
return op.self().compose(std::move(gen.self()));
}
......@@ -309,12 +309,12 @@ template <class First, class Second>
class Composed : public Operator<Composed<First, Second>> {
First first_;
Second second_;
public:
Composed() = default;
Composed(First first, Second second)
: first_(std::move(first))
, second_(std::move(second)) {}
: first_(std::move(first)), second_(std::move(second)) {}
template <
class Source,
......@@ -348,20 +348,18 @@ class Composed : public Operator<Composed<First, Second>> {
* int total = nums | sum;
*/
template <class Value, class First, class Second>
class Chain : public GenImpl<Value,
Chain<Value, First, Second>> {
class Chain : public GenImpl<Value, Chain<Value, First, Second>> {
First first_;
Second second_;
public:
explicit Chain(First first, Second second)
: first_(std::move(first))
, second_(std::move(second)) {}
: first_(std::move(first)), second_(std::move(second)) {}
template <class Handler>
bool apply(Handler&& handler) const {
return first_.apply(std::forward<Handler>(handler))
&& second_.apply(std::forward<Handler>(handler));
return first_.apply(std::forward<Handler>(handler)) &&
second_.apply(std::forward<Handler>(handler));
}
template <class Body>
......
......@@ -29,8 +29,7 @@ namespace detail {
class FileReader : public GenImpl<ByteRange, FileReader> {
public:
FileReader(File file, std::unique_ptr<IOBuf> buffer)
: file_(std::move(file)),
buffer_(std::move(buffer)) {
: file_(std::move(file)), buffer_(std::move(buffer)) {
buffer_->clear();
}
......@@ -65,8 +64,7 @@ class FileReader : public GenImpl<ByteRange, FileReader> {
class FileWriter : public Operator<FileWriter> {
public:
FileWriter(File file, std::unique_ptr<IOBuf> buffer)
: file_(std::move(file)),
buffer_(std::move(buffer)) {
: file_(std::move(file)), buffer_(std::move(buffer)) {
if (buffer_) {
buffer_->clear();
}
......@@ -102,8 +100,8 @@ class FileWriter : public Operator<FileWriter> {
n = ::write(file_.fd(), v.data(), v.size());
} while (n == -1 && errno == EINTR);
if (n == -1) {
throw std::system_error(errno, std::system_category(),
"write() failed");
throw std::system_error(
errno, std::system_category(), "write() failed");
}
v.advance(size_t(n));
}
......@@ -121,9 +119,11 @@ class FileWriter : public Operator<FileWriter> {
};
inline auto byLineImpl(File file, char delim, bool keepDelimiter) {
// clang-format off
return fromFile(std::move(file))
| eachAs<StringPiece>()
| resplit(delim, keepDelimiter);
// clang-format on
}
} // namespace detail
......
......@@ -35,7 +35,7 @@ class FileWriter;
* to hold each value).
*/
template <class S = detail::FileReader>
S fromFile(File file, size_t bufferSize=4096) {
S fromFile(File file, size_t bufferSize = 4096) {
return S(std::move(file), IOBuf::create(bufferSize));
}
......@@ -52,7 +52,7 @@ S fromFile(File file, std::unique_ptr<IOBuf> buffer) {
* If bufferSize is 0, writes will be unbuffered.
*/
template <class S = detail::FileWriter>
S toFile(File file, size_t bufferSize=4096) {
S toFile(File file, size_t bufferSize = 4096) {
return S(std::move(file), bufferSize ? nullptr : IOBuf::create(bufferSize));
}
......
......@@ -45,8 +45,12 @@ class ClosableMPMCQueue {
CHECK(!consumers());
}
void openProducer() { ++producers_; }
void openConsumer() { ++consumers_; }
void openProducer() {
++producers_;
}
void openConsumer() {
++consumers_;
}
void closeInputProducer() {
size_t producers = producers_--;
......@@ -159,8 +163,10 @@ class Parallel : public Operator<Parallel<Ops>> {
decltype(std::declval<Ops>().compose(Empty<InputDecayed&&>())),
class Output = typename Composed::ValueType,
class OutputDecayed = typename std::decay<Output>::type>
class Generator : public GenImpl<OutputDecayed&&,
Generator<Input,
class Generator : public GenImpl<
OutputDecayed&&,
Generator<
Input,
Source,
InputDecayed,
Composed,
......@@ -269,9 +275,13 @@ class Parallel : public Operator<Parallel<Ops>> {
CHECK(!outQueue_.producers());
}
void closeInputProducer() { inQueue_.closeInputProducer(); }
void closeInputProducer() {
inQueue_.closeInputProducer();
}
void closeOutputConsumer() { outQueue_.closeOutputConsumer(); }
void closeOutputConsumer() {
outQueue_.closeOutputConsumer();
}
bool writeUnlessClosed(Input&& input) {
return inQueue_.writeUnlessClosed(std::forward<Input>(input));
......
......@@ -58,7 +58,6 @@ Chunked chunked(Container& container, int chunkSize = 256) {
return Chunked(chunkSize, folly::range(container.begin(), container.end()));
}
/**
* parallel - A parallelization operator.
*
......
......@@ -47,12 +47,12 @@ template <class Predicate>
class PMap : public Operator<PMap<Predicate>> {
Predicate pred_;
size_t nThreads_;
public:
PMap() = default;
PMap(Predicate pred, size_t nThreads)
: pred_(std::move(pred)),
nThreads_(nThreads) { }
: pred_(std::move(pred)), nThreads_(nThreads) {}
template <
class Value,
......@@ -75,8 +75,7 @@ class PMap : public Operator<PMap<Predicate>> {
public:
ExecutionPipeline(const Predicate& pred, size_t nThreads)
: pred_(pred),
pipeline_(nThreads, nThreads) {
: pred_(pred), pipeline_(nThreads, nThreads) {
workers_.reserve(nThreads);
for (size_t i = 0; i < nThreads; i++) {
workers_.push_back(std::thread([this] { this->predApplier(); }));
......@@ -86,7 +85,9 @@ class PMap : public Operator<PMap<Predicate>> {
~ExecutionPipeline() {
assert(pipeline_.sizeGuess() == 0);
assert(done_.load());
for (auto& w : workers_) { w.join(); }
for (auto& w : workers_) {
w.join();
}
}
void stop() {
......@@ -131,8 +132,7 @@ class PMap : public Operator<PMap<Predicate>> {
if (pipeline_.template readStage<0>(ticket, in)) {
wake_.cancelWait();
Output out = pred_(std::move(in));
pipeline_.template blockingWriteStage<0>(ticket,
std::move(out));
pipeline_.template blockingWriteStage<0>(ticket, std::move(out));
continue;
}
......@@ -151,8 +151,7 @@ class PMap : public Operator<PMap<Predicate>> {
Generator(Source source, const Predicate& pred, size_t nThreads)
: source_(std::move(source)),
pred_(pred),
nThreads_(nThreads ? nThreads : sysconf(_SC_NPROCESSORS_ONLN)) {
}
nThreads_(nThreads ? nThreads : sysconf(_SC_NPROCESSORS_ONLN)) {}
template <class Body>
void foreach(Body&& body) const {
......
......@@ -39,7 +39,7 @@ class PMap;
* caller thread.
*/
template <class Predicate, class PMap = detail::PMap<Predicate>>
PMap pmap(Predicate pred = Predicate(), size_t nThreads = 0) {
PMap pmap(Predicate pred = Predicate(), size_t nThreads = 0) {
return PMap(std::move(pred), nThreads);
}
} // namespace gen
......
......@@ -34,9 +34,8 @@ namespace detail {
* Returns the number of trailing bytes of "prefix" that make up the
* delimiter, or 0 if the delimiter was not found.
*/
inline size_t splitPrefix(StringPiece& in,
StringPiece& prefix,
char delimiter) {
inline size_t
splitPrefix(StringPiece& in, StringPiece& prefix, char delimiter) {
size_t found = in.find(delimiter);
if (found != StringPiece::npos) {
++found;
......@@ -51,9 +50,8 @@ inline size_t splitPrefix(StringPiece& in,
/**
* As above, but supports multibyte delimiters.
*/
inline size_t splitPrefix(StringPiece& in,
StringPiece& prefix,
StringPiece delimiter) {
inline size_t
splitPrefix(StringPiece& in, StringPiece& prefix, StringPiece delimiter) {
auto found = in.find(delimiter);
if (found != StringPiece::npos) {
found += delimiter.size();
......@@ -68,9 +66,7 @@ inline size_t splitPrefix(StringPiece& in,
/**
* As above, but splits by any of the EOL terms: \r, \n, or \r\n.
*/
inline size_t splitPrefix(StringPiece& in,
StringPiece& prefix,
MixedNewlines) {
inline size_t splitPrefix(StringPiece& in, StringPiece& prefix, MixedNewlines) {
const auto kCRLF = "\r\n";
const size_t kLenCRLF = 2;
......@@ -274,11 +270,10 @@ class SplitStringSource
: public GenImpl<StringPiece, SplitStringSource<DelimiterType>> {
StringPiece source_;
DelimiterType delimiter_;
public:
SplitStringSource(const StringPiece source,
DelimiterType delimiter)
: source_(source)
, delimiter_(std::move(delimiter)) { }
SplitStringSource(const StringPiece source, DelimiterType delimiter)
: source_(source), delimiter_(std::move(delimiter)) {}
template <class Body>
bool apply(Body&& body) const {
......@@ -308,10 +303,9 @@ class SplitStringSource
template <class Delimiter, class Output>
class Unsplit : public Operator<Unsplit<Delimiter, Output>> {
Delimiter delimiter_;
public:
explicit Unsplit(const Delimiter& delimiter)
: delimiter_(delimiter) {
}
explicit Unsplit(const Delimiter& delimiter) : delimiter_(delimiter) {}
template <class Source, class Value>
Output compose(const GenImpl<Value, Source>& source) const {
......@@ -332,10 +326,10 @@ template <class Delimiter, class OutputBuffer>
class UnsplitBuffer : public Operator<UnsplitBuffer<Delimiter, OutputBuffer>> {
Delimiter delimiter_;
OutputBuffer* outputBuffer_;
public:
UnsplitBuffer(const Delimiter& delimiter, OutputBuffer* outputBuffer)
: delimiter_(delimiter)
, outputBuffer_(outputBuffer) {
: delimiter_(delimiter), outputBuffer_(outputBuffer) {
CHECK(outputBuffer);
}
......@@ -355,12 +349,13 @@ class UnsplitBuffer : public Operator<UnsplitBuffer<Delimiter, OutputBuffer>> {
}
};
/**
* Hack for static for-like constructs
*/
template <class Target, class = void>
inline Target passthrough(Target target) { return target; }
inline Target passthrough(Target target) {
return target;
}
FOLLY_PUSH_WARNING
#ifdef __clang__
......@@ -381,9 +376,9 @@ FOLLY_PUSH_WARNING
template <class TargetContainer, class Delimiter, class... Targets>
class SplitTo {
Delimiter delimiter_;
public:
explicit SplitTo(Delimiter delimiter)
: delimiter_(delimiter) {}
explicit SplitTo(Delimiter delimiter) : delimiter_(delimiter) {}
TargetContainer operator()(StringPiece line) const {
int i = 0;
......@@ -391,7 +386,8 @@ class SplitTo {
// HACK(tjackson): Used for referencing fields[] corresponding to variadic
// template parameters.
auto eatField = [&]() -> StringPiece& { return fields[i++]; };
if (!split(delimiter_,
if (!split(
delimiter_,
line,
detail::passthrough<StringPiece&, Targets>(eatField())...)) {
throw std::runtime_error("field count mismatch");
......
......@@ -92,7 +92,6 @@ S lines(StringPiece source) {
* assert(result == "a b c");
*/
// NOTE: The template arguments are reversed to allow the user to cleanly
// specify the output type while still inferring the type of the delimiter.
template <
......@@ -142,8 +141,7 @@ UnsplitBuffer unsplit(const char* delimiter, OutputBuffer* outputBuffer) {
template <class... Targets>
detail::Map<detail::SplitTo<std::tuple<Targets...>, char, Targets...>>
eachToTuple(char delim) {
return detail::Map<
detail::SplitTo<std::tuple<Targets...>, char, Targets...>>(
return detail::Map<detail::SplitTo<std::tuple<Targets...>, char, Targets...>>(
detail::SplitTo<std::tuple<Targets...>, char, Targets...>(delim));
}
......@@ -196,9 +194,9 @@ eachToPair(StringPiece delim) {
*/
template <class Callback>
class StreamSplitter {
public:
StreamSplitter(char delimiter,
StreamSplitter(
char delimiter,
Callback&& pieceCb,
uint64_t maxLength = 0,
uint64_t initialCapacity = 0)
......@@ -237,9 +235,8 @@ class StreamSplitter {
};
template <class Callback> // Helper to enable template deduction
StreamSplitter<Callback> streamSplitter(char delimiter,
Callback&& pieceCb,
uint64_t capacity = 0) {
StreamSplitter<Callback>
streamSplitter(char delimiter, Callback&& pieceCb, uint64_t capacity = 0) {
return StreamSplitter<Callback>(delimiter, std::move(pieceCb), capacity);
}
......
......@@ -25,10 +25,11 @@ using namespace folly::gen;
using folly::fbstring;
using std::pair;
using std::set;
using std::vector;
using std::tuple;
using std::vector;
static std::atomic<int> testSize(1000);
// clang-format off
static vector<int> testVector =
seq(1, testSize.load())
| mapped([](int) { return rand(); })
......@@ -44,6 +45,7 @@ static vector<fbstring> strings =
from(testVector)
| eachTo<fbstring>()
| as<vector>();
// clang-format on
auto square = [](int x) { return x * x; };
......@@ -91,20 +93,24 @@ BENCHMARK_DRAW_LINE();
BENCHMARK(Member, iters) {
int s = 0;
while(iters--) {
while (iters--) {
// clang-format off
s += from(strings)
| member(&fbstring::size)
| sum;
// clang-format on
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(MapMember, iters) {
int s = 0;
while(iters--) {
while (iters--) {
// clang-format off
s += from(strings)
| map([](const fbstring& x) { return x.size(); })
| sum;
// clang-format on
}
folly::doNotOptimizeAway(s);
}
......@@ -126,11 +132,13 @@ BENCHMARK(Count_Vector_NoGen, iters) {
BENCHMARK_RELATIVE(Count_Vector_Gen, iters) {
int s = 0;
while (iters--) {
// clang-format off
s += from(testVector)
| filter([](int i) {
return i * 2 < rand();
})
| count;
// clang-format on
}
folly::doNotOptimizeAway(s);
}
......@@ -356,7 +364,7 @@ BENCHMARK(Sample, iters) {
// Sample 176.48ms 5.67
// ============================================================================
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
folly::runBenchmarks();
return 0;
......
......@@ -108,41 +108,35 @@ TEST(Gen, Map) {
TEST(Gen, Member) {
struct Counter {
Counter(int start = 0)
: c(start)
{}
Counter(int start = 0) : c(start) {}
int count() const { return c; }
int incr() { return ++c; }
int count() const {
return c;
}
int incr() {
return ++c;
}
int& ref() {
return c;
}
const int& ref() const {
return c;
}
int& ref() { return c; }
const int& ref() const { return c; }
private:
int c;
};
auto counters = seq(1, 10) | eachAs<Counter>() | as<vector>();
EXPECT_EQ(10 * (1 + 10) / 2,
from(counters)
| member(&Counter::count)
| sum);
EXPECT_EQ(10 * (1 + 10) / 2,
from(counters)
| indirect
| member(&Counter::count)
| sum);
EXPECT_EQ(10 * (2 + 11) / 2,
from(counters)
| member(&Counter::incr)
| sum);
EXPECT_EQ(10 * (3 + 12) / 2,
from(counters)
| indirect
| member(&Counter::incr)
| sum);
EXPECT_EQ(10 * (3 + 12) / 2,
from(counters)
| member(&Counter::count)
| sum);
EXPECT_EQ(10 * (1 + 10) / 2, from(counters) | member(&Counter::count) | sum);
EXPECT_EQ(
10 * (1 + 10) / 2,
from(counters) | indirect | member(&Counter::count) | sum);
EXPECT_EQ(10 * (2 + 11) / 2, from(counters) | member(&Counter::incr) | sum);
EXPECT_EQ(
10 * (3 + 12) / 2,
from(counters) | indirect | member(&Counter::incr) | sum);
EXPECT_EQ(10 * (3 + 12) / 2, from(counters) | member(&Counter::count) | sum);
// type-verifications
auto m = empty<Counter&>();
......@@ -166,18 +160,10 @@ TEST(Gen, Field) {
};
std::vector<X> xs(1);
EXPECT_EQ(2, from(xs)
| field(&X::a)
| sum);
EXPECT_EQ(3, from(xs)
| field(&X::b)
| sum);
EXPECT_EQ(4, from(xs)
| field(&X::c)
| sum);
EXPECT_EQ(2, seq(&xs[0], &xs[0])
| field(&X::a)
| sum);
EXPECT_EQ(2, from(xs) | field(&X::a) | sum);
EXPECT_EQ(3, from(xs) | field(&X::b) | sum);
EXPECT_EQ(4, from(xs) | field(&X::c) | sum);
EXPECT_EQ(2, seq(&xs[0], &xs[0]) | field(&X::a) | sum);
// type-verification
empty<X&>() | field(&X::a) | assert_type<const int&>();
empty<X*>() | field(&X::a) | assert_type<const int&>();
......@@ -216,9 +202,8 @@ TEST(Gen, SeqWithStep) {
TEST(Gen, SeqWithStepArray) {
const std::array<int, 6> arr{{1, 2, 3, 4, 5, 6}};
EXPECT_EQ(9, seq(&arr[0], &arr[5], 2)
| map([](const int *i) { return *i; })
| sum);
EXPECT_EQ(
9, seq(&arr[0], &arr[5], 2) | map([](const int* i) { return *i; }) | sum);
}
TEST(Gen, Range) {
......@@ -233,28 +218,30 @@ TEST(Gen, RangeWithStep) {
}
TEST(Gen, FromIterators) {
vector<int> source {2, 3, 5, 7, 11};
vector<int> source{2, 3, 5, 7, 11};
auto gen = from(folly::range(source.begin() + 1, source.end() - 1));
EXPECT_EQ(3 * 5 * 7, gen | product);
}
TEST(Gen, FromMap) {
auto source = seq(0, 10)
// clang-format off
auto source
= seq(0, 10)
| map([](int i) { return std::make_pair(i, i * i); })
| as<std::map<int, int>>();
auto gen = fromConst(source)
auto gen
= fromConst(source)
| map([&](const std::pair<const int, int>& p) {
return p.second - p.first;
});
// clang-format on
EXPECT_EQ(330, gen | sum);
}
TEST(Gen, Filter) {
const auto expected = vector<int>{1, 2, 4, 5, 7, 8};
auto actual =
seq(1, 9)
| filter([](int x) { return x % 3; })
| as<vector<int>>();
seq(1, 9) | filter([](int x) { return x % 3; }) | as<vector<int>>();
EXPECT_EQ(expected, actual);
}
......@@ -262,10 +249,7 @@ TEST(Gen, FilterDefault) {
{
// Default filter should remove 0s
const auto expected = vector<int>{1, 1, 2, 3};
auto actual =
from({0, 1, 1, 0, 2, 3, 0})
| filter()
| as<vector>();
auto actual = from({0, 1, 1, 0, 2, 3, 0}) | filter() | as<vector>();
EXPECT_EQ(expected, actual);
}
{
......@@ -274,46 +258,46 @@ TEST(Gen, FilterDefault) {
int b = 3;
int c = 0;
const auto expected = vector<int*>{&a, &b, &c};
auto actual =
from({(int*)nullptr, &a, &b, &c, (int*)nullptr})
// clang-format off
auto actual = from({(int*)nullptr, &a, &b, &c, (int*)nullptr})
| filter()
| as<vector>();
// clang-format on
EXPECT_EQ(expected, actual);
}
{
// Default filter on Optionals should remove folly::null
const auto expected =
vector<Optional<int>>{Optional<int>(5), Optional<int>(0)};
const auto actual =
from({Optional<int>(5), Optional<int>(), Optional<int>(0)})
// clang-format off
const auto actual = from(
{Optional<int>(5), Optional<int>(), Optional<int>(0)})
| filter()
| as<vector>();
// clang-format on
EXPECT_EQ(expected, actual);
}
}
TEST(Gen, FilterSink) {
auto actual
= seq(1, 2)
// clang-format off
auto actual = seq(1, 2)
| map([](int x) { return vector<int>{x}; })
| filter([](vector<int> v) { return !v.empty(); })
| as<vector>();
// clang-format on
EXPECT_FALSE(from(actual) | rconcat | isEmpty);
}
TEST(Gen, Contains) {
{
auto gen =
seq(1, 9)
| map(square);
auto gen = seq(1, 9) | map(square);
EXPECT_TRUE(gen | contains(49));
EXPECT_FALSE(gen | contains(50));
}
{
auto gen =
seq(1) // infinite, to prove laziness
| map(square)
| eachTo<std::string>();
// infinite, to prove laziness
auto gen = seq(1) | map(square) | eachTo<std::string>();
// std::string gen, const char* needle
EXPECT_TRUE(gen | take(9999) | contains("49"));
......@@ -323,25 +307,30 @@ TEST(Gen, Contains) {
TEST(Gen, Take) {
{
auto expected = vector<int>{1, 4, 9, 16};
// clang-format off
auto actual =
seq(1, 1000)
| mapped([](int x) { return x * x; })
| take(4)
| as<vector<int>>();
// clang-format on
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{ 0, 1, 4, 5, 8 };
auto expected = vector<int>{0, 1, 4, 5, 8};
// clang-format off
auto actual
= ((seq(0) | take(2)) +
(seq(4) | take(2)) +
(seq(8) | take(2)))
| take(5)
| as<vector>();
// clang-format on
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{ 0, 1, 4, 5, 8 };
auto expected = vector<int>{0, 1, 4, 5, 8};
// clang-format off
auto actual
= seq(0)
| mapped([](int i) {
......@@ -350,6 +339,7 @@ TEST(Gen, Take) {
| concat
| take(5)
| as<vector>();
// clang-format on
EXPECT_EQ(expected, actual);
}
{
......@@ -359,41 +349,31 @@ TEST(Gen, Take) {
}
}
TEST(Gen, Stride) {
{
EXPECT_THROW(stride(0), std::invalid_argument);
}
{
auto expected = vector<int>{1, 2, 3, 4};
auto actual
= seq(1, 4)
| stride(1)
| as<vector<int>>();
auto actual = seq(1, 4) | stride(1) | as<vector<int>>();
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{1, 3, 5, 7};
auto actual
= seq(1, 8)
| stride(2)
| as<vector<int>>();
auto actual = seq(1, 8) | stride(2) | as<vector<int>>();
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{1, 4, 7, 10};
auto actual
= seq(1, 12)
| stride(3)
| as<vector<int>>();
auto actual = seq(1, 12) | stride(3) | as<vector<int>>();
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{1, 3, 5, 7, 9, 1, 4, 7, 10};
// clang-format off
auto actual
= ((seq(1, 10) | stride(2)) +
(seq(1, 10) | stride(3)))
| as<vector<int>>();
// clang-format on
EXPECT_EQ(expected, actual);
}
EXPECT_EQ(500, seq(1) | take(1000) | stride(2) | count);
......@@ -403,17 +383,15 @@ TEST(Gen, Stride) {
TEST(Gen, Sample) {
std::mt19937 rnd(42);
auto sampler =
seq(1, 100)
| sample(50, rnd);
std::unordered_map<int,int> hits;
auto sampler = seq(1, 100) | sample(50, rnd);
std::unordered_map<int, int> hits;
const int kNumIters = 80;
for (int i = 0; i < kNumIters; i++) {
auto vec = sampler | as<vector<int>>();
EXPECT_EQ(vec.size(), 50);
auto uniq = fromConst(vec) | as<set<int>>();
EXPECT_EQ(uniq.size(), vec.size()); // sampling without replacement
for (auto v: vec) {
for (auto v : vec) {
++hits[v];
}
}
......@@ -422,50 +400,50 @@ TEST(Gen, Sample) {
// at least once and no value all 80 times. (The odds of either of those
// events is 1/2^80).
EXPECT_EQ(hits.size(), 100);
for (auto hit: hits) {
for (auto hit : hits) {
EXPECT_GT(hit.second, 0);
EXPECT_LT(hit.second, kNumIters);
}
auto small =
seq(1, 5)
| sample(10);
auto small = seq(1, 5) | sample(10);
EXPECT_EQ((small | sum), 15);
EXPECT_EQ((small | take(3) | count), 3);
}
TEST(Gen, Skip) {
auto gen =
seq(1, 1000)
| mapped([](int x) { return x * x; })
| skip(4)
| take(4);
seq(1, 1000) | mapped([](int x) { return x * x; }) | skip(4) | take(4);
EXPECT_EQ((vector<int>{25, 36, 49, 64}), gen | as<vector>());
}
TEST(Gen, Until) {
{
auto expected = vector<int>{1, 4, 9, 16};
// clang-format off
auto actual
= seq(1, 1000)
| mapped([](int x) { return x * x; })
| until([](int x) { return x > 20; })
| as<vector<int>>();
// clang-format on
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{ 0, 1, 4, 5, 8 };
auto expected = vector<int>{0, 1, 4, 5, 8};
// clang-format off
auto actual
= ((seq(0) | until([](int i) { return i > 1; })) +
(seq(4) | until([](int i) { return i > 5; })) +
(seq(8) | until([](int i) { return i > 9; })))
| until([](int i) { return i > 8; })
| as<vector<int>>();
// clang-format on
EXPECT_EQ(expected, actual);
}
/*
{
auto expected = vector<int>{ 0, 1, 5, 6, 10 };
// clang-format off
auto actual
= seq(0)
| mapped([](int i) {
......@@ -474,6 +452,7 @@ TEST(Gen, Until) {
| concat
| until([](int i) { return i > 10; })
| as<vector<int>>();
// clang-format on
EXPECT_EQ(expected, actual);
}
*/
......@@ -509,12 +488,12 @@ TEST(Gen, Visit) {
TEST(Gen, Composed) {
// Operator, Operator
auto valuesOf =
filter([](Optional<int>& o) { return o.hasValue(); })
// clang-format off
auto valuesOf
= filter([](Optional<int>& o) { return o.hasValue(); })
| map([](Optional<int>& o) -> int& { return o.value(); });
std::vector<Optional<int>> opts {
none, 4, none, 6, none
};
// clang-format on
std::vector<Optional<int>> opts{none, 4, none, 6, none};
EXPECT_EQ(4 * 4 + 6 * 6, from(opts) | valuesOf | map(square) | sum);
// Operator, Sink
auto sumOpt = valuesOf | sum;
......@@ -522,8 +501,8 @@ TEST(Gen, Composed) {
}
TEST(Gen, Chain) {
std::vector<int> nums {2, 3, 5, 7};
std::map<int, int> mappings { { 3, 9}, {5, 25} };
std::vector<int> nums{2, 3, 5, 7};
std::map<int, int> mappings{{3, 9}, {5, 25}};
auto gen = from(nums) + (from(mappings) | get<1>());
EXPECT_EQ(51, gen | sum);
EXPECT_EQ(5, gen | take(2) | sum);
......@@ -531,75 +510,72 @@ TEST(Gen, Chain) {
}
TEST(Gen, Concat) {
std::vector<std::vector<int>> nums {{2, 3}, {5, 7}};
std::vector<std::vector<int>> nums{{2, 3}, {5, 7}};
auto gen = from(nums) | rconcat;
EXPECT_EQ(17, gen | sum);
EXPECT_EQ(10, gen | take(3) | sum);
}
TEST(Gen, ConcatGen) {
auto gen = seq(1, 10)
| map([](int i) { return seq(1, i); })
| concat;
auto gen = seq(1, 10) | map([](int i) { return seq(1, i); }) | concat;
EXPECT_EQ(220, gen | sum);
EXPECT_EQ(10, gen | take(6) | sum);
}
TEST(Gen, ConcatAlt) {
std::vector<std::vector<int>> nums {{2, 3}, {5, 7}};
auto actual = from(nums)
std::vector<std::vector<int>> nums{{2, 3}, {5, 7}};
// clang-format off
auto actual
= from(nums)
| map([](std::vector<int>& v) { return from(v); })
| concat
| sum;
// clang-format on
auto expected = 17;
EXPECT_EQ(expected, actual);
}
TEST(Gen, Order) {
auto expected = vector<int>{0, 3, 5, 6, 7, 8, 9};
auto actual =
from({8, 6, 7, 5, 3, 0, 9})
| order
| as<vector>();
auto actual = from({8, 6, 7, 5, 3, 0, 9}) | order | as<vector>();
EXPECT_EQ(expected, actual);
}
TEST(Gen, OrderMoved) {
auto expected = vector<int>{0, 9, 25, 36, 49, 64, 81};
auto actual =
from({8, 6, 7, 5, 3, 0, 9})
// clang-format off
auto actual
= from({8, 6, 7, 5, 3, 0, 9})
| move
| order
| map(square)
| as<vector>();
// clang-format on
EXPECT_EQ(expected, actual);
}
TEST(Gen, OrderTake) {
auto expected = vector<int>{9, 8, 7};
auto actual =
from({8, 6, 7, 5, 3, 0, 9})
// clang-format off
auto actual
= from({8, 6, 7, 5, 3, 0, 9})
| orderByDescending(square)
| take(3)
| as<vector>();
// clang-format on
EXPECT_EQ(expected, actual);
}
TEST(Gen, Distinct) {
auto expected = vector<int>{3, 1, 2};
auto actual =
from({3, 1, 3, 2, 1, 2, 3})
| distinct
| as<vector>();
auto actual = from({3, 1, 3, 2, 1, 2, 3}) | distinct | as<vector>();
EXPECT_EQ(expected, actual);
}
TEST(Gen, DistinctBy) { // 0 1 4 9 6 5 6 9 4 1 0
auto expected = vector<int>{0, 1, 2, 3, 4, 5};
auto actual =
seq(0, 100)
| distinctBy([](int i) { return i * i % 10; })
| as<vector>();
seq(0, 100) | distinctBy([](int i) { return i * i % 10; }) | as<vector>();
EXPECT_EQ(expected, actual);
}
......@@ -627,8 +603,7 @@ TEST(Gen, DistinctInfinite) {
// of cource, is it eventually made finite before returning the result.
auto expected = seq(0) | take(5) | as<vector>(); // 0 1 2 3 4
auto actual =
seq(0) // 0 1 2 3 4 5 6 7 ...
auto actual = seq(0) // 0 1 2 3 4 5 6 7 ...
| mapped([](int i) { return i / 2; }) // 0 0 1 1 2 2 3 3 ...
| distinct // 0 1 2 3 4 5 6 7 ...
| take(5) // 0 1 2 3 4
......@@ -643,8 +618,7 @@ TEST(Gen, DistinctByInfinite) {
// at the end, the sequence may infinite loop. This is fine becasue we cannot
// solve the halting problem.
auto expected = vector<int>{1, 2};
auto actual =
seq(1) // 1 2 3 4 5 6 7 8 ...
auto actual = seq(1) // 1 2 3 4 5 6 7 8 ...
| distinctBy([](int i) { return i % 2; }) // 1 2 (but might by infinite)
| take(2) // 1 2
| as<vector>();
......@@ -654,12 +628,16 @@ TEST(Gen, DistinctByInfinite) {
}
TEST(Gen, MinBy) {
EXPECT_EQ(7, seq(1, 10)
// clang-format off
EXPECT_EQ(
7,
seq(1, 10)
| minBy([](int i) -> double {
double d = i - 6.8;
return d * d;
})
| unwrap);
// clang-format on
}
TEST(Gen, MaxBy) {
......@@ -669,13 +647,13 @@ TEST(Gen, MaxBy) {
}
TEST(Gen, Min) {
auto odds = seq(2,10) | filter([](int i){ return i % 2; });
auto odds = seq(2, 10) | filter([](int i) { return i % 2; });
EXPECT_EQ(3, odds | min);
}
TEST(Gen, Max) {
auto odds = seq(2,10) | filter([](int i){ return i % 2; });
auto odds = seq(2, 10) | filter([](int i) { return i % 2; });
EXPECT_EQ(9, odds | max);
}
......@@ -721,33 +699,35 @@ TEST(Gen, FromRValue) {
}
}
{
auto q = from(set<int>{1,2,3,2,1});
auto q = from(set<int>{1, 2, 3, 2, 1});
EXPECT_EQ(q | sum, 6);
}
}
TEST(Gen, OrderBy) {
auto expected = vector<int>{5, 6, 4, 7, 3, 8, 2, 9, 1, 10};
auto actual =
seq(1, 10)
// clang-format off
auto actual
= seq(1, 10)
| orderBy([](int x) { return (5.1 - x) * (5.1 - x); })
| as<vector>();
// clang-format on
EXPECT_EQ(expected, actual);
expected = seq(1, 10) | as<vector>();
actual =
from(expected)
// clang-format off
actual
= from(expected)
| map([] (int x) { return 11 - x; })
| orderBy()
| as<vector>();
// clang-format on
EXPECT_EQ(expected, actual);
}
TEST(Gen, Foldl) {
int expected = 2 * 3 * 4 * 5;
auto actual =
seq(2, 5)
| foldl(1, multiply);
auto actual = seq(2, 5) | foldl(1, multiply);
EXPECT_EQ(expected, actual);
}
......@@ -778,7 +758,7 @@ TEST(Gen, First) {
}
TEST(Gen, FromCopy) {
vector<int> v {3, 5};
vector<int> v{3, 5};
auto src = from(v);
auto copy = fromCopy(v);
EXPECT_EQ(8, src | sum);
......@@ -789,7 +769,7 @@ TEST(Gen, FromCopy) {
}
TEST(Gen, Get) {
std::map<int, int> pairs {
std::map<int, int> pairs{
{1, 1},
{2, 4},
{3, 9},
......@@ -805,7 +785,7 @@ TEST(Gen, Get) {
EXPECT_EQ(15, keys | sum);
EXPECT_EQ(55, values | sum);
vector<tuple<int, int, int>> tuples {
vector<tuple<int, int, int>> tuples{
make_tuple(1, 1, 1),
make_tuple(2, 4, 8),
make_tuple(3, 9, 27),
......@@ -848,33 +828,31 @@ TEST(Gen, Yielders) {
yield(i);
}
yield(7);
for (int i = 3; ; ++i) {
for (int i = 3;; ++i) {
yield(i * i);
}
};
vector<int> expected {
1, 2, 3, 4, 5, 7, 9, 16, 25
};
vector<int> expected{1, 2, 3, 4, 5, 7, 9, 16, 25};
EXPECT_EQ(expected, gen | take(9) | as<vector>());
}
TEST(Gen, NestedYield) {
auto nums = GENERATOR(int) {
for (int i = 1; ; ++i) {
for (int i = 1;; ++i) {
yield(i);
}
};
auto gen = GENERATOR(int) {
nums | take(10) | yield;
seq(1, 5) | [&](int i) {
yield(i);
};
seq(1, 5) | [&](int i) { yield(i); };
};
EXPECT_EQ(70, gen | sum);
}
TEST(Gen, MapYielders) {
auto gen = seq(1, 5)
// clang-format off
auto gen
= seq(1, 5)
| map([](int n) {
return GENERATOR(int) {
int i;
......@@ -894,6 +872,7 @@ TEST(Gen, MapYielders) {
1, 2, 3, 4, 3, 2, 1,
1, 2, 3, 4, 5, 4, 3, 2, 1,
};
// clang-format on
EXPECT_EQ(expected, gen | as<vector>());
}
......@@ -907,13 +886,11 @@ TEST(Gen, VirtualGen) {
EXPECT_EQ(30, v | take(4) | sum);
}
TEST(Gen, CustomType) {
struct Foo{
struct Foo {
int y;
};
auto gen = from({Foo{2}, Foo{3}})
| map([](const Foo& f) { return f.y; });
auto gen = from({Foo{2}, Foo{3}}) | map([](const Foo& f) { return f.y; });
EXPECT_EQ(5, gen | sum);
}
......@@ -930,7 +907,7 @@ namespace {
class TestIntSeq : public GenImpl<int, TestIntSeq> {
public:
TestIntSeq() { }
TestIntSeq() {}
template <class Body>
bool apply(Body&& body) const {
......@@ -963,15 +940,13 @@ TEST(Gen, FromArray) {
}
TEST(Gen, FromStdArray) {
std::array<int,4> source {{2, 3, 5, 7}};
std::array<int, 4> source{{2, 3, 5, 7}};
auto gen = from(source);
EXPECT_EQ(2 * 3 * 5 * 7, gen | product);
}
TEST(Gen, StringConcat) {
auto gen = seq(1, 10)
| eachTo<string>()
| rconcat;
auto gen = seq(1, 10) | eachTo<string>() | rconcat;
EXPECT_EQ("12345678910", gen | as<string>());
}
......@@ -1055,27 +1030,24 @@ TEST(Gen, Collect) {
EXPECT_EQ(s.size(), 5);
}
TEST(Gen, Cycle) {
{
auto s = from({1, 2});
EXPECT_EQ((vector<int> { 1, 2, 1, 2, 1 }),
s | cycle | take(5) | as<vector>());
EXPECT_EQ((vector<int>{1, 2, 1, 2, 1}), s | cycle | take(5) | as<vector>());
}
{
auto s = from({1, 2});
EXPECT_EQ((vector<int> { 1, 2, 1, 2 }),
s | cycle(2) | as<vector>());
EXPECT_EQ((vector<int>{1, 2, 1, 2}), s | cycle(2) | as<vector>());
}
{
auto s = from({1, 2, 3});
EXPECT_EQ((vector<int> { 1, 2, 1, 2, 1 }),
EXPECT_EQ(
(vector<int>{1, 2, 1, 2, 1}),
s | take(2) | cycle | take(5) | as<vector>());
}
{
auto s = empty<int>();
EXPECT_EQ((vector<int> { }),
s | cycle | take(4) | as<vector>());
EXPECT_EQ((vector<int>{}), s | cycle | take(4) | as<vector>());
}
{
int c = 3;
......@@ -1089,8 +1061,8 @@ TEST(Gen, Cycle) {
--*pcount;
};
auto s = countdown;
EXPECT_EQ((vector<int> { 1, 2, 3, 1, 2, 1}),
s | cycle | take(7) | as<vector>());
EXPECT_EQ(
(vector<int>{1, 2, 3, 1, 2, 1}), s | cycle | take(7) | as<vector>());
// take necessary as cycle returns an infinite generator
}
}
......@@ -1102,34 +1074,31 @@ TEST(Gen, Dereference) {
EXPECT_EQ(6, s | dereference | sum);
}
{
vector<int> a { 1, 2 };
vector<int> b { 3, 4 };
vector<vector<int>*> pv { &a, nullptr, &b };
from(pv)
| dereference
| [&](vector<int>& v) {
v.push_back(5);
};
vector<int> a{1, 2};
vector<int> b{3, 4};
vector<vector<int>*> pv{&a, nullptr, &b};
from(pv) | dereference | [&](vector<int>& v) { v.push_back(5); };
EXPECT_EQ(3, a.size());
EXPECT_EQ(3, b.size());
EXPECT_EQ(5, a.back());
EXPECT_EQ(5, b.back());
}
{
vector<std::map<int, int>> maps {
vector<std::map<int, int>> maps{
{
{ 2, 31 },
{ 3, 41 },
{2, 31},
{3, 41},
},
{
{ 3, 52 },
{ 4, 62 },
{3, 52},
{4, 62},
},
{
{ 4, 73 },
{ 5, 83 },
{4, 73},
{5, 83},
},
};
// clang-format off
EXPECT_EQ(
93,
from(maps)
......@@ -1138,6 +1107,7 @@ TEST(Gen, Dereference) {
})
| dereference
| sum);
// clang-format on
}
{
vector<unique_ptr<int>> ups;
......@@ -1195,25 +1165,30 @@ TEST(Gen, Indirect) {
TEST(Gen, Guard) {
using std::runtime_error;
EXPECT_THROW(from({"1", "a", "3"})
// clang-format off
EXPECT_THROW(
from({"1", "a", "3"})
| eachTo<int>()
| sum,
runtime_error);
EXPECT_EQ(4,
EXPECT_EQ(
4,
from({"1", "a", "3"})
| guard<runtime_error>([](runtime_error&, const char*) {
return true; // continue
})
| eachTo<int>()
| sum);
EXPECT_EQ(1,
EXPECT_EQ(
1,
from({"1", "a", "3"})
| guard<runtime_error>([](runtime_error&, const char*) {
return false; // break
})
| eachTo<int>()
| sum);
EXPECT_THROW(from({"1", "a", "3"})
EXPECT_THROW(
from({"1", "a", "3"})
| guard<runtime_error>([](runtime_error&, const char* v) {
if (v[0] == 'a') {
throw;
......@@ -1223,34 +1198,38 @@ TEST(Gen, Guard) {
| eachTo<int>()
| sum,
runtime_error);
// clang-format on
}
TEST(Gen, eachTryTo) {
using std::runtime_error;
EXPECT_EQ(4,
// clang-format off
EXPECT_EQ(
4,
from({"1", "a", "3"})
| eachTryTo<int>()
| dereference
| sum);
EXPECT_EQ(1,
EXPECT_EQ(
1,
from({"1", "a", "3"})
| eachTryTo<int>()
| takeWhile()
| dereference
| sum);
// clang-format on
}
TEST(Gen, Batch) {
EXPECT_EQ((vector<vector<int>> { {1} }),
seq(1, 1) | batch(5) | as<vector>());
EXPECT_EQ((vector<vector<int>> { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11} }),
EXPECT_EQ((vector<vector<int>>{{1}}), seq(1, 1) | batch(5) | as<vector>());
EXPECT_EQ(
(vector<vector<int>>{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11}}),
seq(1, 11) | batch(3) | as<vector>());
EXPECT_THROW(seq(1, 1) | batch(0) | as<vector>(),
std::invalid_argument);
EXPECT_THROW(seq(1, 1) | batch(0) | as<vector>(), std::invalid_argument);
}
TEST(Gen, BatchMove) {
auto expected = vector<vector<int>>{ {0, 1}, {2, 3}, {4} };
auto expected = vector<vector<int>>{{0, 1}, {2, 3}, {4}};
auto actual = seq(0, 4) |
mapped([](int i) { return std::make_unique<int>(i); }) | batch(2) |
mapped([](std::vector<std::unique_ptr<int>>& pVector) {
......@@ -1315,8 +1294,18 @@ TEST(Gen, Just) {
}
TEST(Gen, GroupBy) {
vector<string> strs{"zero", "one", "two", "three", "four",
"five", "six", "seven", "eight", "nine"};
vector<string> strs{
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
};
auto gb = from(strs) | groupBy([](const string& str) { return str.size(); });
......@@ -1324,16 +1313,24 @@ TEST(Gen, GroupBy) {
EXPECT_EQ(3, gb | count);
vector<string> mode{"zero", "four", "five", "nine"};
EXPECT_EQ(mode,
gb | maxBy([](const Group<size_t, string>& g) { return g.size(); })
// clang-format off
EXPECT_EQ(
mode,
gb
| maxBy([](const Group<size_t, string>& g) { return g.size(); })
| unwrap
| as<vector>());
// clang-format on
vector<string> largest{"three", "seven", "eight"};
EXPECT_EQ(largest,
gb | maxBy([](const Group<size_t, string>& g) { return g.key(); })
// clang-format off
EXPECT_EQ(
largest,
gb
| maxBy([](const Group<size_t, string>& g) { return g.key(); })
| unwrap
| as<vector>());
// clang-format on
}
TEST(Gen, GroupByAdjacent) {
......@@ -1454,7 +1451,7 @@ TEST(Gen, Unwrap) {
}
}
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
gflags::ParseCommandLineFlags(&argc, &argv, true);
return RUN_ALL_TESTS();
......
......@@ -19,14 +19,17 @@
#include <folly/Benchmark.h>
#define BENCH_GEN_IMPL(gen, prefix) \
static bool FB_ANONYMOUS_VARIABLE(benchGen) = ( \
::folly::addBenchmark(__FILE__, prefix FB_STRINGIZE(gen), \
[](unsigned iters){ \
static bool FB_ANONYMOUS_VARIABLE(benchGen) = \
(::folly::addBenchmark( \
__FILE__, \
prefix FB_STRINGIZE(gen), \
[](unsigned iters) { \
const unsigned num = iters; \
while (iters--) { \
folly::doNotOptimizeAway(gen); \
} \
return num; \
}), true)
}), \
true)
#define BENCH_GEN(gen) BENCH_GEN_IMPL(gen, "")
#define BENCH_GEN_REL(gen) BENCH_GEN_IMPL(gen, "%")
......@@ -26,11 +26,10 @@
using namespace folly::gen;
using namespace folly;
using std::string;
using std::vector;
using std::tuple;
using std::vector;
const folly::gen::detail::Map<
folly::gen::detail::MergeTuples> gTupleFlatten{};
const folly::gen::detail::Map<folly::gen::detail::MergeTuples> gTupleFlatten{};
auto even = [](int i) -> bool { return i % 2 == 0; };
auto odd = [](int i) -> bool { return i % 2 == 1; };
......@@ -46,8 +45,7 @@ TEST(CombineGen, Interleave) {
auto base = seq(1) | filter(odd) | take(3);
auto toInterleave = seq(1) | filter(even) | take(50);
auto interleaved = base | interleave(toInterleave | as<vector>());
EXPECT_EQ(interleaved | as<vector>(),
vector<int>({1, 2, 3, 4, 5, 6}));
EXPECT_EQ(interleaved | as<vector>(), vector<int>({1, 2, 3, 4, 5, 6}));
}
}
......@@ -56,9 +54,7 @@ TEST(CombineGen, Zip) {
// We rely on std::move(fbvector) emptying the source vector
auto zippee = fbvector<string>{"one", "two", "three"};
{
auto combined = base0
| zip(zippee)
| as<vector>();
auto combined = base0 | zip(zippee) | as<vector>();
ASSERT_EQ(combined.size(), 3);
EXPECT_EQ(std::get<0>(combined[0]), 1);
EXPECT_EQ(std::get<1>(combined[0]), "one");
......@@ -71,9 +67,7 @@ TEST(CombineGen, Zip) {
}
{ // same as top, but using std::move.
auto combined = base0
| zip(std::move(zippee))
| as<vector>();
auto combined = base0 | zip(std::move(zippee)) | as<vector>();
ASSERT_EQ(combined.size(), 3);
EXPECT_EQ(std::get<0>(combined[0]), 1);
EXPECT_TRUE(zippee.empty());
......@@ -81,9 +75,8 @@ TEST(CombineGen, Zip) {
{ // same as top, but base is truncated
auto baseFinite = seq(1) | take(1);
auto combined = baseFinite
| zip(vector<string>{"one", "two", "three"})
| as<vector>();
auto combined =
baseFinite | zip(vector<string>{"one", "two", "three"}) | as<vector>();
ASSERT_EQ(combined.size(), 1);
EXPECT_EQ(std::get<0>(combined[0]), 1);
EXPECT_EQ(std::get<1>(combined[0]), "one");
......@@ -91,10 +84,10 @@ TEST(CombineGen, Zip) {
}
TEST(CombineGen, TupleFlatten) {
vector<tuple<int,string>> intStringTupleVec{
tuple<int,string>{1, "1"},
tuple<int,string>{2, "2"},
tuple<int,string>{3, "3"},
vector<tuple<int, string>> intStringTupleVec{
tuple<int, string>{1, "1"},
tuple<int, string>{2, "2"},
tuple<int, string>{3, "3"},
};
vector<tuple<char>> charTupleVec{
......@@ -112,45 +105,56 @@ TEST(CombineGen, TupleFlatten) {
25.0,
};
// clang-format off
auto zipped1 = from(intStringTupleVec)
| zip(charTupleVec)
| assert_type<tuple<tuple<int, string>, tuple<char>>>()
| as<vector>();
// clang-format on
EXPECT_EQ(std::get<0>(zipped1[0]), std::make_tuple(1, "1"));
EXPECT_EQ(std::get<1>(zipped1[0]), std::make_tuple('A'));
// clang-format off
auto zipped2 = from(zipped1)
| gTupleFlatten
| assert_type<tuple<int, string, char>&&>()
| as<vector>();
// clang-format on
ASSERT_EQ(zipped2.size(), 3);
EXPECT_EQ(zipped2[0], std::make_tuple(1, "1", 'A'));
// clang-format off
auto zipped3 = from(charTupleVec)
| zip(intStringTupleVec)
| gTupleFlatten
| assert_type<tuple<char, int, string>&&>()
| as<vector>();
// clang-format on
ASSERT_EQ(zipped3.size(), 3);
EXPECT_EQ(zipped3[0], std::make_tuple('A', 1, "1"));
// clang-format off
auto zipped4 = from(intStringTupleVec)
| zip(doubleVec)
| gTupleFlatten
| assert_type<tuple<int, string, double>&&>()
| as<vector>();
// clang-format on
ASSERT_EQ(zipped4.size(), 3);
EXPECT_EQ(zipped4[0], std::make_tuple(1, "1", 1.0));
// clang-format off
auto zipped5 = from(doubleVec)
| zip(doubleVec)
| assert_type<tuple<double, double>>()
| gTupleFlatten // essentially a no-op
| assert_type<tuple<double, double>&&>()
| as<vector>();
// clang-format on
ASSERT_EQ(zipped5.size(), 5);
EXPECT_EQ(zipped5[0], std::make_tuple(1.0, 1.0));
// clang-format off
auto zipped6 = from(intStringTupleVec)
| zip(charTupleVec)
| gTupleFlatten
......@@ -158,11 +162,12 @@ TEST(CombineGen, TupleFlatten) {
| gTupleFlatten
| assert_type<tuple<int, string, char, double>&&>()
| as<vector>();
// clang-format on
ASSERT_EQ(zipped6.size(), 3);
EXPECT_EQ(zipped6[0], std::make_tuple(1, "1", 'A', 1.0));
}
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
gflags::ParseCommandLineFlags(&argc, &argv, true);
return RUN_ALL_TESTS();
......
......@@ -66,7 +66,7 @@ BENCHMARK(ByLine_Pipes, iters) {
// ByLine_Pipes 148.63ns 6.73M
// ============================================================================
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
folly::runBenchmarks();
return 0;
......
......@@ -58,7 +58,7 @@ TEST(FileGen, ByLine) {
}
TEST(FileGen, ByLineFull) {
auto cases = std::vector<std::string> {
auto cases = std::vector<std::string>{
stripLeftMargin(R"(
Hello world
This is the second line
......@@ -71,7 +71,8 @@ TEST(FileGen, ByLineFull) {
"\n",
""};
"",
};
for (auto& lines : cases) {
test::TemporaryFile file("ByLineFull");
......@@ -113,7 +114,8 @@ TEST(FileGenBufferedTest, FileWriterSimple) {
auto squares = seq(1, 100) | map([](int x) { return x * x; });
squares | map(toLine) | eachAs<StringPiece>() | toFile(File(file.fd()));
EXPECT_EQ(squares | sum,
EXPECT_EQ(
squares | sum,
byLine(File(file.path().string().c_str())) | eachTo<int>() | sum);
}
......
......@@ -25,17 +25,18 @@
#include <folly/gen/Parallel.h>
#include <folly/gen/test/Bench.h>
DEFINE_int32(threads,
std::max(1, (int32_t) sysconf(_SC_NPROCESSORS_CONF) / 2),
DEFINE_int32(
threads,
std::max(1, (int32_t)sysconf(_SC_NPROCESSORS_CONF) / 2),
"Num threads.");
using namespace folly::gen;
using std::vector;
constexpr int kFib = 28; // unit of work
size_t fib(int n) { return n <= 1 ? 1 : fib(n - 1) + fib(n - 2); }
size_t fib(int n) {
return n <= 1 ? 1 : fib(n - 1) + fib(n - 2);
}
static auto isPrimeSlow = [](int n) {
if (n < 2) {
......@@ -50,8 +51,7 @@ static auto isPrimeSlow = [](int n) {
return true;
};
static auto primes =
seq(1, 1 << 20) | filter(isPrimeSlow) | as<vector>();
static auto primes = seq(1, 1 << 20) | filter(isPrimeSlow) | as<vector>();
static auto stopc(int n) {
return [=](int d) { return d * d > n; };
......@@ -78,9 +78,7 @@ static auto sleepyWork = [](int i) {
return i;
};
static auto sleepAndWork = [](int i) {
return factorsSlow(i) + sleepyWork(i);
};
static auto sleepAndWork = [](int i) { return factorsSlow(i) + sleepyWork(i); };
auto start = 1 << 20;
auto v = seq(start) | take(1 << 20) | as<vector>();
......@@ -116,19 +114,26 @@ BENCHMARK_DRAW_LINE();
const int fibs = 1000;
BENCH_GEN(seq(1, fibs) | map([](int) { return fib(kFib); }) | sum);
BENCH_GEN_REL(seq(1, fibs) |
parallel(map([](int) { return fib(kFib); }) | sub(sum)) | sum);
// clang-format off
BENCH_GEN_REL(
seq(1, fibs)
| parallel(map([](int) { return fib(kFib); }) | sub(sum))
| sum);
// clang-format on
BENCH_GEN_REL([] {
// clang-format off
auto threads = seq(1, int(FLAGS_threads))
| map([](int i) {
return std::thread([=] {
return range((i + 0) * fibs / FLAGS_threads,
(i + 1) * fibs / FLAGS_threads) |
map([](int) { return fib(kFib); }) | sum;
return range(
(i + 0) * fibs / FLAGS_threads, (i + 1) * fibs / FLAGS_threads)
| map([](int) { return fib(kFib); })
| sum;
});
})
| as<vector>();
from(threads) | [](std::thread &thread) { thread.join(); };
// clang-format on
return 1;
}());
BENCHMARK_DRAW_LINE();
......@@ -160,7 +165,7 @@ seq(1, fibs) | parallel(map([](int) { return fi 1698.07% 87.96ms 11.37
----------------------------------------------------------------------------
============================================================================
#endif
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
folly::runBenchmarks();
return 0;
......
......@@ -26,18 +26,18 @@
using namespace folly::gen;
DEFINE_int32(threads,
std::max(1, (int32_t) sysconf(_SC_NPROCESSORS_CONF) / 2),
DEFINE_int32(
threads,
std::max(1, (int32_t)sysconf(_SC_NPROCESSORS_CONF) / 2),
"Num threads.");
constexpr int kFib = 35; // unit of work
size_t fib(int n) { return n <= 1 ? 1 : fib(n-1) * fib(n-2); }
size_t fib(int n) {
return n <= 1 ? 1 : fib(n - 1) * fib(n - 2);
}
BENCHMARK(FibSumMap, n) {
auto result =
seq(1, (int) n)
| map([](int) { return fib(kFib); })
| sum;
auto result = seq(1, (int)n) | map([](int) { return fib(kFib); }) | sum;
folly::doNotOptimizeAway(result);
}
......@@ -45,10 +45,12 @@ BENCHMARK_RELATIVE(FibSumPmap, n) {
// Schedule more work: enough so that each worker thread does the
// same amount as one FibSumMap.
const size_t kNumThreads = FLAGS_threads;
// clang-format off
auto result =
seq(1, (int) (n * kNumThreads))
seq(1, (int)(n * kNumThreads))
| pmap([](int) { return fib(kFib); }, kNumThreads)
| sum;
// clang-format on
folly::doNotOptimizeAway(result);
}
......@@ -58,16 +60,15 @@ BENCHMARK_RELATIVE(FibSumThreads, n) {
std::vector<std::thread> workers;
workers.reserve(kNumThreads);
auto fn = [n] {
auto result =
seq(1, (int) n)
| map([](int) { return fib(kFib); })
| sum;
auto result = seq(1, (int)n) | map([](int) { return fib(kFib); }) | sum;
folly::doNotOptimizeAway(result);
};
for (size_t i = 0; i < kNumThreads; i++) {
workers.push_back(std::thread(fn));
}
for (auto& w : workers) { w.join(); }
for (auto& w : workers) {
w.join();
}
}
/*
......@@ -84,7 +85,7 @@ BENCHMARK_RELATIVE(FibSumThreads, n) {
sys0m0.016s
*/
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
folly::runBenchmarks();
return 0;
......
......@@ -29,6 +29,7 @@ using namespace folly::gen;
TEST(Pmap, InfiniteEquivalent) {
// apply
{
// clang-format off
auto mapResult
= seq(1)
| map([](int x) { return x * x; })
......@@ -40,12 +41,14 @@ TEST(Pmap, InfiniteEquivalent) {
| pmap([](int x) { return x * x; }, 4)
| until([](int x) { return x > 1000 * 1000; })
| as<std::vector<int>>();
// clang-format on
EXPECT_EQ(pmapResult, mapResult);
}
// foreach
{
// clang-format off
auto mapResult
= seq(1, 10)
| map([](int x) { return x * x; })
......@@ -55,6 +58,7 @@ TEST(Pmap, InfiniteEquivalent) {
= seq(1, 10)
| pmap([](int x) { return x * x; }, 4)
| as<std::vector<int>>();
// clang-format on
EXPECT_EQ(pmapResult, mapResult);
}
......@@ -63,6 +67,7 @@ TEST(Pmap, InfiniteEquivalent) {
TEST(Pmap, Empty) {
// apply
{
// clang-format off
auto mapResult
= seq(1)
| map([](int x) { return x * x; })
......@@ -74,6 +79,7 @@ TEST(Pmap, Empty) {
| pmap([](int x) { return x * x; }, 4)
| until([](int) { return true; })
| as<std::vector<int>>();
// clang-format on
EXPECT_EQ(mapResult.size(), 0);
EXPECT_EQ(pmapResult, mapResult);
......@@ -81,6 +87,7 @@ TEST(Pmap, Empty) {
// foreach
{
// clang-format off
auto mapResult
= empty<int>()
| map([](int x) { return x * x; })
......@@ -90,6 +97,7 @@ TEST(Pmap, Empty) {
= empty<int>()
| pmap([](int x) { return x * x; }, 4)
| as<std::vector<int>>();
// clang-format on
EXPECT_EQ(mapResult.size(), 0);
EXPECT_EQ(pmapResult, mapResult);
......@@ -99,6 +107,7 @@ TEST(Pmap, Empty) {
TEST(Pmap, Rvalues) {
// apply
{
// clang-format off
auto mapResult
= seq(1)
| map([](int x) { return std::make_unique<int>(x); })
......@@ -116,12 +125,14 @@ TEST(Pmap, Rvalues) {
| pmap([](std::unique_ptr<int> x) { return *x; })
| take(1000)
| sum;
// clang-format on
EXPECT_EQ(pmapResult, mapResult);
}
// foreach
{
// clang-format off
auto mapResult
= seq(1, 1000)
| map([](int x) { return std::make_unique<int>(x); })
......@@ -137,12 +148,13 @@ TEST(Pmap, Rvalues) {
return std::make_unique<int>(*x * *x); })
| pmap([](std::unique_ptr<int> x) { return *x; })
| sum;
// clang-format on
EXPECT_EQ(pmapResult, mapResult);
}
}
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
gflags::ParseCommandLineFlags(&argc, &argv, true);
return RUN_ALL_TESTS();
......
......@@ -57,55 +57,55 @@ struct {
}
} makeUnique;
static auto primes = seq(1, 1 << 14)
| filter(isPrime)
| as<vector<size_t>>();
static auto primes = seq(1, 1 << 14) | filter(isPrime) | as<vector<size_t>>();
static auto primeFactors = [](int n) {
return from(primes)
| filter([&](int d) { return 0 == n % d; })
| count;
return from(primes) | filter([&](int d) { return 0 == n % d; }) | count;
};
TEST(ParallelTest, Serial) {
EXPECT_EQ(
seq(1,10) | map(square) | filter(even) | sum,
seq(1,10) | parallel(map(square) | filter(even)) | sum);
seq(1, 10) | map(square) | filter(even) | sum,
seq(1, 10) | parallel(map(square) | filter(even)) | sum);
}
auto heavyWork = map(primeFactors);
TEST(ParallelTest, ComputeBound64) {
int length = 1 << 10;
EXPECT_EQ(seq<size_t>(1, length) | heavyWork | sum,
EXPECT_EQ(
seq<size_t>(1, length) | heavyWork | sum,
seq<size_t>(1, length) | parallel(heavyWork) | sum);
}
TEST(ParallelTest, Take) {
int length = 1 << 18;
int limit = 1 << 14;
EXPECT_EQ(seq(1, length) | take(limit) | count,
EXPECT_EQ(
seq(1, length) | take(limit) | count,
seq(1, length) | parallel(heavyWork) | take(limit) | count);
}
TEST(ParallelTest, Unique) {
auto uniqued = from(primes) | map(makeUnique) | as<vector>();
EXPECT_EQ(primes.size(),
EXPECT_EQ(
primes.size(),
from(primes) | parallel(map(makeUnique)) |
parallel(dereference | map(makeUnique)) | dereference | count);
EXPECT_EQ(2,
EXPECT_EQ(
2,
from(primes) | parallel(map(makeUnique)) |
parallel(dereference | map(makeUnique)) | dereference |
take(2) | count);
parallel(dereference | map(makeUnique)) | dereference | take(2) |
count);
}
TEST(ParallelTest, PSum) {
EXPECT_EQ(from(primes) | map(sleepyWork) | sum,
EXPECT_EQ(
from(primes) | map(sleepyWork) | sum,
from(primes) | parallel(map(sleepyWork) | sub(sum)) | sum);
}
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
gflags::ParseCommandLineFlags(&argc, &argv, true);
return RUN_ALL_TESTS();
......
......@@ -28,16 +28,14 @@ using namespace folly;
using namespace folly::gen;
using std::pair;
using std::set;
using std::vector;
using std::tuple;
using std::vector;
namespace {
static std::atomic<int> testSize(1000);
static vector<fbstring> testStrVector
= seq(1, testSize.load())
| eachTo<fbstring>()
| as<vector>();
static vector<fbstring> testStrVector =
seq(1, testSize.load()) | eachTo<fbstring>() | as<vector>();
static auto testFileContent = from(testStrVector) | unsplit('\n');
const char* const kLine = "The quick brown fox jumped over the lazy dog.\n";
......@@ -61,7 +59,9 @@ void initStringResplitterBenchmark() {
}
}
size_t len(folly::StringPiece s) { return s.size(); }
size_t len(folly::StringPiece s) {
return s.size();
}
} // namespace
......@@ -94,7 +94,6 @@ BENCHMARK(StringSplit_Old, iters) {
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(StringSplit_Gen_Vector, iters) {
size_t s = 0;
StringPiece line(kLine);
......@@ -196,9 +195,7 @@ BENCHMARK_DRAW_LINE();
void StringUnsplit_Gen(size_t iters, size_t joinSize) {
std::vector<fbstring> v;
BENCHMARK_SUSPEND {
FOR_EACH_RANGE (i, 0, joinSize) {
v.push_back(to<fbstring>(rand()));
}
FOR_EACH_RANGE (i, 0, joinSize) { v.push_back(to<fbstring>(rand())); }
}
size_t s = 0;
fbstring buffer;
......@@ -231,20 +228,23 @@ BENCHMARK_RELATIVE_PARAM(Lines_Gen, 3e3)
BENCHMARK_DRAW_LINE();
fbstring records
= seq<size_t>(1, 1000)
// clang-format off
fbstring records = seq<size_t>(1, 1000)
| mapped([](size_t i) {
return folly::to<fbstring>(i, ' ', i * i, ' ', i * i * i);
})
| unsplit('\n');
// clang-format o
BENCHMARK(Records_EachToTuple, iters) {
size_t s = 0;
for (size_t i = 0; i < iters; i += 1000) {
// clang-format off
s += split(records, '\n')
| eachToTuple<int, size_t, StringPiece>(' ')
| get<1>()
| sum;
// clang-format on
}
folly::doNotOptimizeAway(s);
}
......@@ -253,6 +253,7 @@ BENCHMARK_RELATIVE(Records_VectorStringPieceReused, iters) {
size_t s = 0;
std::vector<StringPiece> fields;
for (size_t i = 0; i < iters; i += 1000) {
// clang-format off
s += split(records, '\n')
| mapped([&](StringPiece line) {
fields.clear();
......@@ -265,6 +266,7 @@ BENCHMARK_RELATIVE(Records_VectorStringPieceReused, iters) {
})
| get<1>()
| sum;
// clang-format on
}
folly::doNotOptimizeAway(s);
}
......@@ -272,6 +274,7 @@ BENCHMARK_RELATIVE(Records_VectorStringPieceReused, iters) {
BENCHMARK_RELATIVE(Records_VectorStringPiece, iters) {
size_t s = 0;
for (size_t i = 0; i < iters; i += 1000) {
// clang-format off
s += split(records, '\n')
| mapped([](StringPiece line) {
std::vector<StringPiece> fields;
......@@ -284,6 +287,7 @@ BENCHMARK_RELATIVE(Records_VectorStringPiece, iters) {
})
| get<1>()
| sum;
// clang-format on
}
folly::doNotOptimizeAway(s);
}
......@@ -291,6 +295,7 @@ BENCHMARK_RELATIVE(Records_VectorStringPiece, iters) {
BENCHMARK_RELATIVE(Records_VectorString, iters) {
size_t s = 0;
for (size_t i = 0; i < iters; i += 1000) {
// clang-format off
s += split(records, '\n')
| mapped([](StringPiece line) {
std::vector<std::string> fields;
......@@ -303,6 +308,7 @@ BENCHMARK_RELATIVE(Records_VectorString, iters) {
})
| get<1>()
| sum;
// clang-format on
}
folly::doNotOptimizeAway(s);
}
......@@ -338,7 +344,7 @@ BENCHMARK_RELATIVE(Records_VectorString, iters) {
// Records_VectorString 16.70% 607.47us 1.65K
// ============================================================================
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
initStringResplitterBenchmark();
runBenchmarks();
......
......@@ -149,11 +149,13 @@ TEST(StringGen, ResplitKeepDelimiter) {
TEST(StringGen, EachToTuple) {
{
auto lines = "2:1.414:yo 3:1.732:hi";
// clang-format off
auto actual
= split(lines, ' ')
| eachToTuple<int, double, std::string>(':')
| as<vector>();
vector<tuple<int, double, std::string>> expected {
// clang-format on
vector<tuple<int, double, std::string>> expected{
make_tuple(2, 1.414, "yo"),
make_tuple(3, 1.732, "hi"),
};
......@@ -161,11 +163,13 @@ TEST(StringGen, EachToTuple) {
}
{
auto lines = "2 3";
// clang-format off
auto actual
= split(lines, ' ')
| eachToTuple<int>(',')
| as<vector>();
vector<tuple<int>> expected {
// clang-format on
vector<tuple<int>> expected{
make_tuple(2),
make_tuple(3),
};
......@@ -174,11 +178,13 @@ TEST(StringGen, EachToTuple) {
{
// StringPiece target
auto lines = "1:cat 2:dog";
// clang-format off
auto actual
= split(lines, ' ')
| eachToTuple<int, StringPiece>(':')
| as<vector>();
vector<tuple<int, StringPiece>> expected {
// clang-format on
vector<tuple<int, StringPiece>> expected{
make_tuple(1, "cat"),
make_tuple(2, "dog"),
};
......@@ -187,11 +193,13 @@ TEST(StringGen, EachToTuple) {
{
// Empty field
auto lines = "2:tjackson:4 3::5";
// clang-format off
auto actual
= split(lines, ' ')
| eachToTuple<int, fbstring, int>(':')
| as<vector>();
vector<tuple<int, fbstring, int>> expected {
// clang-format on
vector<tuple<int, fbstring, int>> expected{
make_tuple(2, "tjackson", 4),
make_tuple(3, "", 5),
};
......@@ -200,18 +208,24 @@ TEST(StringGen, EachToTuple) {
{
// Excess fields
auto lines = "1:2 3:4:5";
EXPECT_THROW((split(lines, ' ')
// clang-format off
EXPECT_THROW(
(split(lines, ' ')
| eachToTuple<int, int>(':')
| as<vector>()),
std::runtime_error);
// clang-format on
}
{
// Missing fields
auto lines = "1:2:3 4:5";
EXPECT_THROW((split(lines, ' ')
// clang-format off
EXPECT_THROW(
(split(lines, ' ')
| eachToTuple<int, int, int>(':')
| as<vector>()),
std::runtime_error);
// clang-format on
}
}
......@@ -219,40 +233,48 @@ TEST(StringGen, EachToPair) {
{
// char delimiters
auto lines = "2:1.414 3:1.732";
// clang-format off
auto actual
= split(lines, ' ')
| eachToPair<int, double>(':')
| as<std::map<int, double>>();
std::map<int, double> expected {
{ 3, 1.732 },
{ 2, 1.414 },
// clang-format on
std::map<int, double> expected{
{3, 1.732},
{2, 1.414},
};
EXPECT_EQ(expected, actual);
}
{
// string delimiters
auto lines = "ab=>cd ef=>gh";
// clang-format off
auto actual
= split(lines, ' ')
| eachToPair<string, string>("=>")
| as<std::map<string, string>>();
std::map<string, string> expected {
{ "ab", "cd" },
{ "ef", "gh" },
// clang-format on
std::map<string, string> expected{
{"ab", "cd"},
{"ef", "gh"},
};
EXPECT_EQ(expected, actual);
}
}
void checkResplitMaxLength(vector<string> ins,
void checkResplitMaxLength(
vector<string> ins,
char delim,
uint64_t maxLength,
vector<string> outs) {
vector<std::string> pieces;
auto splitter = streamSplitter(delim, [&pieces](StringPiece s) {
auto splitter = streamSplitter(
delim,
[&pieces](StringPiece s) {
pieces.push_back(string(s.begin(), s.end()));
return true;
}, maxLength);
},
maxLength);
for (const auto& in : ins) {
splitter(in);
}
......@@ -270,22 +292,21 @@ void checkResplitMaxLength(vector<string> ins,
}
TEST(StringGen, ResplitMaxLength) {
// clang-format off
checkResplitMaxLength(
{"hel", "lo,", ", world", ", goodbye, m", "ew"}, ',', 5,
{"hello", ",", ",", " worl", "d,", " good", "bye,", " mew"}
);
{"hello", ",", ",", " worl", "d,", " good", "bye,", " mew"});
// " meow" cannot be "end of stream", since it's maxLength long
checkResplitMaxLength(
{"hel", "lo,", ", world", ", goodbye, m", "eow"}, ',', 5,
{"hello", ",", ",", " worl", "d,", " good", "bye,", " meow", ""}
);
{"hello", ",", ",", " worl", "d,", " good", "bye,", " meow", ""});
checkResplitMaxLength(
{"||", "", "", "", "|a|b", "cdefghijklmn", "|opqrst",
"uvwx|y|||", "z", "0123456789", "|", ""}, '|', 2,
{"|", "|", "|", "a|", "bc", "de", "fg", "hi", "jk", "lm", "n|", "op", "qr",
"st", "uv", "wx", "|", "y|", "|", "|", "z0", "12", "34", "56", "78", "9|",
""}
);
{"|", "|", "|", "a|", "bc", "de", "fg", "hi", "jk", "lm", "n|", "op",
"qr", "st", "uv", "wx", "|", "y|", "|", "|", "z0", "12", "34", "56",
"78", "9|", ""});
// clang-format on
}
template <typename F>
......@@ -299,7 +320,6 @@ void runUnsplitSuite(F fn) {
}
TEST(StringGen, Unsplit) {
auto basicFn = [](StringPiece s) {
EXPECT_EQ(split(s, ',') | unsplit(','), s);
};
......@@ -307,8 +327,7 @@ TEST(StringGen, Unsplit) {
auto existingBuffer = [](StringPiece s) {
folly::fbstring buffer("asdf");
split(s, ',') | unsplit(',', &buffer);
auto expected = folly::to<folly::fbstring>(
"asdf", s.empty() ? "" : ",", s);
auto expected = folly::to<folly::fbstring>("asdf", s.empty() ? "" : ",", s);
EXPECT_EQ(expected, buffer);
};
......@@ -334,16 +353,21 @@ TEST(StringGen, Unsplit) {
TEST(StringGen, Batch) {
std::vector<std::string> chunks{
"on", "e\nt", "w", "o", "\nthr", "ee\nfo", "ur\n",
};
std::vector<std::string> lines{
"one", "two", "three", "four",
};
"on", "e\nt", "w", "o", "\nthr", "ee\nfo", "ur\n"};
std::vector<std::string> lines{"one", "two", "three", "four"};
EXPECT_EQ(4, from(chunks) | resplit('\n') | count);
EXPECT_EQ(4, from(chunks) | resplit('\n') | batch(2) | rconcat | count);
EXPECT_EQ(4, from(chunks) | resplit('\n') | batch(3) | rconcat | count);
EXPECT_EQ(lines, from(chunks) | resplit('\n') | eachTo<std::string>() |
batch(3) | rconcat | as<vector>());
// clang-format off
EXPECT_EQ(
lines,
from(chunks)
| resplit('\n')
| eachTo<std::string>()
| batch(3)
| rconcat
| as<vector>());
// clang-format on
}
TEST(StringGen, UncurryTuple) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment