}
};
-
/**
- * Any - For determining whether any values in a sequence satisfy a predicate.
- *
- * This type is primarily used through the 'any' static value, like:
- *
- * bool any20xPrimes = seq(200, 210) | filter(isPrime) | any;
- *
- * Note that it may also be used like so:
- *
- * bool any20xPrimes = seq(200, 210) | any(isPrime);
+ * IsEmpty - a helper class for isEmpty and notEmpty
*
+ * Essentially returns 'result' if the source is empty. Note that this cannot be
+ * called on an infinite source, because then there is only one possible return
+ * value.
*/
-class Any : public Operator<Any> {
+template <bool emptyResult>
+class IsEmpty : public Operator<IsEmpty<emptyResult>> {
public:
- Any() = default;
+ IsEmpty() = default;
template<class Source,
class Value>
bool compose(const GenImpl<Value, Source>& source) const {
- bool any = false;
+ 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 {
- any = true;
+ ans = !emptyResult;
return false;
};
- return any;
- }
-
- /**
- * Convenience function for use like:
- *
- * bool found = gen | any([](int i) { return i * i > 100; });
- */
- template<class Predicate,
- class Filter = Filter<Predicate>,
- class Composed = Composed<Filter, Any>>
- Composed operator()(Predicate pred) const {
- return Composed(Filter(std::move(pred)), Any());
- }
-};
-
-/**
- * All - For determining whether all values in a sequence satisfy a predicate.
- *
- * This type is primarily used through the 'any' static value, like:
- *
- * bool valid = from(input) | all(validate);
- *
- * Note: Passing an empty sequence through 'all()' will always return true.
- */
-template<class Predicate>
-class All : public Operator<All<Predicate>> {
- Predicate pred_;
- public:
- All() = default;
- explicit All(Predicate pred)
- : pred_(std::move(pred))
- { }
-
- template<class Source,
- class Value>
- bool compose(const GenImpl<Value, Source>& source) const {
- static_assert(!Source::infinite, "Cannot call 'all' on infinite source");
- bool all = true;
- source | [&](Value v) -> bool {
- if (!pred_(std::forward<Value>(v))) {
- all = false;
- return false;
- }
- return true;
- };
- return all;
+ return ans;
}
};
*/
class Sum : public Operator<Sum> {
public:
- Sum() : Operator<Sum>() {}
+ Sum() = default;
template<class Source,
class Value,
* = from(samples)
* | cycle
* | take(100);
+ *
+ * or in the finite case:
+ *
+ * auto thrice = g | cycle(3);
*/
-class Cycle : public Operator<Cycle> {
- off_t limit_; // -1 for infinite
+template <bool forever>
+class Cycle : public Operator<Cycle<forever>> {
+ off_t limit_; // not used if forever == true
public:
- Cycle()
- : limit_(-1) { }
+ Cycle() = default;
explicit Cycle(off_t limit)
- : limit_(limit) { }
+ : limit_(limit) {
+ static_assert(
+ !forever,
+ "Cycle limit consturctor should not be used when forever == true.");
+ }
template<class Value,
class Source>
class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
- off_t limit_; // -1 for infinite
+ off_t limit_;
public:
explicit Generator(Source source, off_t limit)
: source_(std::move(source))
cont = handler(std::forward<Value>(value));
return cont;
};
- for (off_t count = 0; count != limit_; ++count) {
+ // Becomes an infinte loop if forever == true
+ for (off_t count = 0; (forever || count != limit_); ++count) {
cont = false;
source_.apply(handler2);
if (!cont) {
}
/**
- * Convenience function for use like:
+ * Convenience function for finite cycles used like:
*
* auto tripled = gen | cycle(3);
*/
- Cycle operator()(off_t limit) const {
- return Cycle(limit);
+ Cycle<false> operator()(off_t limit) const {
+ return Cycle<false>(limit);
}
};
* non-template operators, statically defined to avoid the need for anything but
* the header.
*/
-static const detail::Sum sum{};
+constexpr detail::Sum sum{};
-static const detail::Count count{};
+constexpr detail::Count count{};
-static const detail::First first{};
+constexpr detail::First first{};
/**
- * Use directly for detecting any values, or as a function to detect values
- * which pass a predicate:
+ * Use 'isEmpty' and 'notEmpty' for detecting if there are any values or not.
*
- * auto nonempty = g | any;
- * auto evens = g | any(even);
+ * bool hasPrimes = g | filter(prime) | notEmpty;
+ * bool lacksEvens = g | filter(even) | isEmpty;
*/
-static const detail::Any any{};
+constexpr detail::IsEmpty<true> isEmpty{};
-static const detail::Min<Identity, Less> min{};
+constexpr detail::IsEmpty<false> notEmpty{};
-static const detail::Min<Identity, Greater> max{};
+constexpr detail::Min<Identity, Less> min{};
-static const detail::Order<Identity> order{};
+constexpr detail::Min<Identity, Greater> max{};
-static const detail::Distinct<Identity> distinct{};
+constexpr detail::Order<Identity> order{};
-static const detail::Map<Move> move{};
+constexpr detail::Distinct<Identity> distinct{};
-static const detail::Concat concat{};
+constexpr detail::Map<Move> move{};
-static const detail::RangeConcat rconcat{};
+constexpr detail::Concat concat{};
-/**
- * Use directly for infinite sequences, or as a function to limit cycle count.
- *
- * auto forever = g | cycle;
- * auto thrice = g | cycle(3);
- */
-static const detail::Cycle cycle{};
+constexpr detail::RangeConcat rconcat{};
+
+constexpr detail::Cycle<true> cycle{};
-static const detail::Dereference dereference{};
+constexpr detail::Dereference dereference{};
-static const detail::Indirect indirect{};
+constexpr detail::Indirect indirect{};
inline detail::Take take(size_t count) {
return detail::Take(count);
}
};
+/**
+ * Class and helper function for negating a boolean Predicate
+ */
+template <class Predicate>
+class Negate {
+ Predicate pred_;
+
+ public:
+ Negate() = default;
+
+ explicit Negate(Predicate pred)
+ : pred_(std::move(pred))
+ {}
+
+ template <class Arg>
+ bool operator()(Arg&& arg) const {
+ return !pred_(std::forward<Arg>(arg));
+ }
+};
+template <class Predicate>
+Negate<Predicate> negate(Predicate pred) {
+ return Negate<Predicate>(std::move(pred));
+}
+
template <class Dest>
class Cast {
public:
class RangeConcat;
+template <bool forever>
class Cycle;
class Batch;
class First;
-class Any;
-
-template<class Predicate>
-class All;
+template <bool result>
+class IsEmpty;
template<class Reducer>
class Reduce;
return Filter(std::move(pred));
}
-template<class Predicate,
- class All = detail::All<Predicate>>
-All all(Predicate pred = Predicate()) {
- return All(std::move(pred));
-}
-
template<class Predicate,
class Until = detail::Until<Predicate>>
Until until(Predicate pred = Predicate()) {
return Order(std::move(selector));
}
-template<class Selector,
- class GroupBy = detail::GroupBy<Selector>>
-GroupBy groupBy(Selector selector = Identity()) {
+template <class Selector = Identity,
+ class GroupBy = detail::GroupBy<Selector>>
+GroupBy groupBy(Selector selector = Selector()) {
return GroupBy(std::move(selector));
}
/*
* Sink Factories
*/
+
+/**
+ * any() - For determining if any value in a sequence satisfies a predicate.
+ *
+ * The following is an example for checking if any computer is broken:
+ *
+ * bool schrepIsMad = from(computers) | any(isBroken);
+ *
+ * (because everyone knows Schrep hates broken computers).
+ *
+ * Note that if no predicate is provided, 'any()' checks if any of the values
+ * are true when cased to bool. To check if any of the scores are nonZero:
+ *
+ * bool somebodyScored = from(scores) | any();
+ *
+ * Note: Passing an empty sequence through 'any()' will always return false. In
+ * fact, 'any()' is equivilent to the composition of 'filter()' and 'notEmpty'.
+ *
+ * from(source) | any(pred) == from(source) | filter(pred) | notEmpty
+ */
+
+template <class Predicate = Identity,
+ class Filter = detail::Filter<Predicate>,
+ class NotEmpty = detail::IsEmpty<false>,
+ class Composed = detail::Composed<Filter, NotEmpty>>
+Composed any(Predicate pred = Predicate()) {
+ return Composed(Filter(std::move(pred)), NotEmpty());
+}
+
+/**
+ * all() - For determining whether all values in a sequence satisfy a predicate.
+ *
+ * The following is an example for checking if all members of a team are cool:
+ *
+ * bool isAwesomeTeam = from(team) | all(isCool);
+ *
+ * Note that if no predicate is provided, 'all()'' checks if all of the values
+ * are true when cased to bool.
+ * The following makes sure none of 'pointers' are nullptr:
+ *
+ * bool allNonNull = from(pointers) | all();
+ *
+ * Note: Passing an empty sequence through 'all()' will always return true. In
+ * fact, 'all()' is equivilent to the composition of 'filter()' with the
+ * reversed predicate and 'isEmpty'.
+ *
+ * from(source) | all(pred) == from(source) | filter(negate(pred)) | isEmpty
+ */
+
+template <class Predicate = Identity,
+ class Filter = detail::Filter<Negate<Predicate>>,
+ class IsEmpty = detail::IsEmpty<true>,
+ class Composed = detail::Composed<Filter, IsEmpty>>
+Composed all(Predicate pred = Predicate()) {
+ return Composed(Filter(std::move(negate(pred))), IsEmpty());
+}
+
template<class Seed,
class Fold,
class FoldLeft = detail::FoldLeft<Seed, Fold>>
EXPECT_EQ("eleven", gen | maxBy(&strlen));
}
+TEST(Gen, Min) {
+ 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; });
+
+ EXPECT_EQ(9, odds | max);
+}
+
TEST(Gen, Append) {
string expected = "facebook";
string actual = "face";
EXPECT_EQ(36, from(tuples) | get<2>() | sum);
}
+TEST(Gen, notEmpty) {
+ EXPECT_TRUE(seq(0) | notEmpty);
+ EXPECT_TRUE(seq(0, 1) | notEmpty);
+ EXPECT_TRUE(just(1) | notEmpty);
+ EXPECT_FALSE(gen::range(0, 0) | notEmpty);
+ EXPECT_FALSE(from({1}) | take(0) | notEmpty);
+ EXPECT_TRUE(seq(1, 3) | cycle | notEmpty);
+}
+
+TEST(Gen, isEmpty) {
+ EXPECT_FALSE(seq(0) | isEmpty);
+ EXPECT_FALSE(seq(0, 1) | isEmpty);
+ EXPECT_FALSE(just(1) | isEmpty);
+ EXPECT_TRUE(gen::range(0, 0) | isEmpty);
+ EXPECT_TRUE(from({1}) | take(0) | isEmpty);
+ EXPECT_FALSE(seq(1, 3) | cycle | isEmpty);
+}
+
TEST(Gen, Any) {
- EXPECT_TRUE(seq(0) | any);
- EXPECT_TRUE(seq(0, 1) | any);
EXPECT_TRUE(seq(0, 10) | any([](int i) { return i == 7; }));
EXPECT_FALSE(seq(0, 10) | any([](int i) { return i == 11; }));
-
- EXPECT_TRUE(from({1}) | any);
- EXPECT_FALSE(gen::range(0, 0) | any);
- EXPECT_FALSE(from({1}) | take(0) | any);
}
TEST(Gen, All) {