}
};
+template<class Value>
+class Empty : public GenImpl<Value, Empty<Value>> {
+ public:
+ template<class Handler>
+ bool apply(Handler&&) const { return true; }
+};
/*
* Operators
}
};
+/*
+ * TypeAssertion - For verifying the exact type of the value produced by a
+ * generator. Useful for testing and debugging, and acts as a no-op at runtime.
+ * Pass-through at runtime. Used through the 'assert_type<>()' factory method
+ * like so:
+ *
+ * auto c = from(vector) | assert_type<int&>() | sum;
+ *
+ */
+template<class Expected>
+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");
+ 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");
+ return std::move(source.self());
+ }
+};
+
/**
* Distinct - For filtering duplicates out of a sequence. A selector may be
* provided to generate a key to uniquify for each value.
}
};
+template<class Class,
+ class Result>
+class MemberFunction {
+ public:
+ typedef Result (Class::*MemberPtr)();
+ private:
+ MemberPtr member_;
+ public:
+ explicit MemberFunction(MemberPtr member)
+ : member_(member)
+ {}
+
+ Result operator()(Class&& x) const {
+ return (x.*member_)();
+ }
+
+ Result operator()(Class& x) const {
+ return (x.*member_)();
+ }
+};
+
+template<class Class,
+ class Result>
+class ConstMemberFunction{
+ public:
+ typedef Result (Class::*MemberPtr)() const;
+ private:
+ MemberPtr member_;
+ public:
+ explicit ConstMemberFunction(MemberPtr member)
+ : member_(member)
+ {}
+
+ Result operator()(const Class& x) const {
+ return (x.*member_)();
+ }
+};
+
+template<class Class,
+ class FieldType>
+class Field {
+ public:
+ typedef FieldType (Class::*FieldPtr);
+ private:
+ FieldPtr field_;
+ public:
+ explicit Field(FieldPtr field)
+ : field_(field)
+ {}
+
+ const FieldType& operator()(const Class& x) const {
+ return x.*field_;
+ }
+
+ FieldType& operator()(Class& x) const {
+ return x.*field_;
+ }
+
+ FieldType&& operator()(Class&& x) const {
+ return std::move(x.*field_);
+ }
+};
+
class Move {
public:
template<class Value>
template<class Value, class Source>
class Yield;
+template<class Value>
+class Empty;
+
+
/*
* Operators
*/
template<class First, class Second>
class Composed;
+template<class Expected>
+class TypeAssertion;
+
/*
* Sinks
*/
/*
* Create inline generator, used like:
*
- * auto gen = GENERATOR(int) { yield(1); yield(2); };
+ * auto gen = GENERATOR(int) { yield(1); yield(2); };
*/
#define GENERATOR(TYPE) \
::folly::gen::detail::GeneratorBuilder<TYPE>() + \
[=](const std::function<void(TYPE)>& yield)
+/*
+ * empty() - for producing empty sequences.
+ */
+template<class Value>
+detail::Empty<Value> empty() {
+ return {};
+}
+
/*
* Operator Factories
*/
return Map(std::move(pred));
}
+/*
+ * member(...) - For extracting a member from each value.
+ *
+ * vector<string> strings = ...;
+ * auto sizes = from(strings) | member(&string::size);
+ *
+ * If a member is const overridden (like 'front()'), pass template parameter
+ * 'Const' to select the const version, or 'Mutable' to select the non-const
+ * version:
+ *
+ * auto heads = from(strings) | member<Const>(&string::front);
+ */
+enum MemberType {
+ Const,
+ Mutable
+};
+
+template<MemberType Constness = Const,
+ class Class,
+ class Return,
+ class Mem = ConstMemberFunction<Class, Return>,
+ class Map = detail::Map<Mem>>
+typename std::enable_if<Constness == Const, Map>::type
+member(Return (Class::*member)() const) {
+ return Map(Mem(member));
+}
+
+template<MemberType Constness = Mutable,
+ class Class,
+ class Return,
+ class Mem = MemberFunction<Class, Return>,
+ class Map = detail::Map<Mem>>
+typename std::enable_if<Constness == Mutable, Map>::type
+member(Return (Class::*member)()) {
+ return Map(Mem(member));
+}
+
+/*
+ * field(...) - For extracting a field from each value.
+ *
+ * vector<Item> items = ...;
+ * auto names = from(items) | field(&Item::name);
+ *
+ * Note that if the values of the generator are rvalues, any non-reference
+ * fields will be rvalues as well. As an example, the code below does not copy
+ * any strings, only moves them:
+ *
+ * auto namesVector = from(items)
+ * | move
+ * | field(&Item::name)
+ * | as<vector>();
+ */
+template<class Class,
+ class FieldType,
+ class Field = Field<Class, FieldType>,
+ class Map = detail::Map<Field>>
+Map field(FieldType Class::*field) {
+ return Map(Field(field));
+}
+
template<class Predicate,
class Filter = detail::Filter<Predicate>>
Filter filter(Predicate pred = Predicate()) {
return To();
}
+template<class Value>
+detail::TypeAssertion<Value> assert_type() {
+ return {};
+}
+
/*
* Sink Factories
*/
return seq(1, i) | as<vector>();
})
| as<vector>();
+static vector<fbstring> strings =
+ from(testVector)
+ | eachTo<fbstring>()
+ | as<vector>();
auto square = [](int x) { return x * x; };
auto add = [](int a, int b) { return a + b; };
BENCHMARK_DRAW_LINE()
+BENCHMARK(Member, iters) {
+ int s = 0;
+ while(iters--) {
+ s += from(strings)
+ | member(&fbstring::size)
+ | sum;
+ }
+ folly::doNotOptimizeAway(s);
+}
+
+BENCHMARK_RELATIVE(MapMember, iters) {
+ int s = 0;
+ while(iters--) {
+ s += from(strings)
+ | map([](const fbstring& x) { return x.size(); })
+ | sum;
+ }
+ folly::doNotOptimizeAway(s);
+}
+
+BENCHMARK_DRAW_LINE()
+
BENCHMARK(Count_Vector_NoGen, iters) {
int s = 0;
while (iters--) {
EXPECT_EQ((vector<int>{4, 9}), gen | take(2) | as<vector>());
}
+TEST(Gen, Member) {
+ struct Counter {
+ Counter(int start = 0)
+ : c(start)
+ {}
+
+ int count() const { return c; }
+ int incr() { 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 * (2 + 11) / 2,
+ from(counters)
+ | member(&Counter::incr)
+ | sum);
+ EXPECT_EQ(10 * (2 + 11) / 2,
+ from(counters)
+ | member(&Counter::count)
+ | sum);
+
+ // type-verifications
+ auto m = empty<Counter&>();
+ auto c = empty<const Counter&>();
+ m | member(&Counter::incr) | assert_type<int&&>();
+ m | member(&Counter::count) | assert_type<int&&>();
+ m | member(&Counter::count) | assert_type<int&&>();
+ m | member<Const>(&Counter::ref) | assert_type<const int&>();
+ m | member<Mutable>(&Counter::ref) | assert_type<int&>();
+ c | member<Const>(&Counter::ref) | assert_type<const int&>();
+}
+
+TEST(Gen, Field) {
+ struct X {
+ X() : a(2), b(3), c(4), d(b) {}
+
+ const int a;
+ int b;
+ mutable int c;
+ int& d; // can't access this with a field pointer.
+ };
+
+ std::vector<X> xs(1);
+ EXPECT_EQ(2, from(xs)
+ | field(&X::a)
+ | first);
+ EXPECT_EQ(3, from(xs)
+ | field(&X::b)
+ | first);
+ EXPECT_EQ(4, from(xs)
+ | field(&X::c)
+ | first);
+ // type-verification
+ empty<X&>() | field(&X::a) | assert_type<const int&>();
+ empty<X&>() | field(&X::b) | assert_type<int&>();
+ empty<X&>() | field(&X::c) | assert_type<int&>();
+ empty<X&&>() | field(&X::a) | assert_type<const int&&>();
+ empty<X&&>() | field(&X::b) | assert_type<int&&>();
+ empty<X&&>() | field(&X::c) | assert_type<int&&>();
+ // references don't imply ownership so they're not moved
+ empty<const X&>() | field(&X::a) | assert_type<const int&>();
+ empty<const X&>() | field(&X::b) | assert_type<const int&>();
+ // 'mutable' has no effect on field pointers, by C++ spec
+ empty<const X&>() | field(&X::c) | assert_type<const int&>();
+
+ // can't form pointer-to-reference field: empty<X&>() | field(&X::d)
+}
+
TEST(Gen, Seq) {
// cover the fenceposts of the loop unrolling
for (int n = 1; n < 100; ++n) {
}
namespace {
+
class TestIntSeq : public GenImpl<int, TestIntSeq> {
public:
TestIntSeq() { }
TestIntSeq(const TestIntSeq&) = delete;
TestIntSeq& operator=(const TestIntSeq&) = delete;
};
+
} // namespace
TEST(Gen, NoGeneratorCopies) {