From: Tom Jackson Date: Thu, 1 Aug 2013 20:54:24 +0000 (-0700) Subject: Cycle X-Git-Tag: v0.22.0~916 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=206a03724cc06f9856c11a454c07dd61299ac6d1;p=folly.git Cycle Summary: For repeating a generator's values endlessly. Test Plan: Unit tests Reviewed By: kittipat@fb.com FB internal diff: D911178 --- diff --git a/folly/experimental/Gen-inl.h b/folly/experimental/Gen-inl.h index f553cc86..9a7d568f 100644 --- a/folly/experimental/Gen-inl.h +++ b/folly/experimental/Gen-inl.h @@ -1794,6 +1794,81 @@ class GuardImpl : public Operator> { return Gen(source.self(), handler_); } }; + +/** + * Cycle - For repeating a sequence forever. + * + * This type is usually used through the 'cycle' static value, like: + * + * auto tests + * = from(samples) + * | cycle + * | take(100); + */ +class Cycle : public Operator { + off_t limit_; // -1 for infinite + public: + Cycle() + : limit_(-1) { } + + explicit Cycle(off_t limit) + : limit_(limit) { } + + template + class Generator : public GenImpl> { + Source source_; + off_t limit_; // -1 for infinite + public: + explicit Generator(Source source, off_t limit) + : source_(std::move(source)) + , limit_(limit) {} + + template + bool apply(Handler&& handler) const { + bool cont; + auto handler2 = [&](Value value) { + cont = handler(std::forward(value)); + return cont; + }; + for (off_t count = 0; count != limit_; ++count) { + cont = false; + source_.apply(handler2); + if (!cont) { + return false; + } + } + return true; + } + + // not actually infinite, since an empty generator will end the cycles. + static constexpr bool infinite = Source::infinite; + }; + + template> + Gen compose(GenImpl&& source) const { + return Gen(std::move(source.self()), limit_); + } + + template> + Gen compose(const GenImpl& source) const { + return Gen(source.self(), limit_); + } + + /** + * Convenience function for use like: + * + * auto tripled = gen | cycle(3); + */ + Cycle operator()(off_t limit) const { + return Cycle(limit); + } +}; + } //::detail /** @@ -1875,6 +1950,13 @@ static const detail::Count count; static const detail::First first; +/** + * Use directly for detecting any values, or as a function to detect values + * which pass a predicate: + * + * auto nonempty = g | any; + * auto evens = g | any(even); + */ static const detail::Any any; static const detail::Min min; @@ -1891,6 +1973,14 @@ static const detail::Concat concat; static const detail::RangeConcat rconcat; +/** + * 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; + inline detail::Take take(size_t count) { return detail::Take(count); } diff --git a/folly/experimental/Gen.h b/folly/experimental/Gen.h index 342968b0..31c1cedc 100644 --- a/folly/experimental/Gen.h +++ b/folly/experimental/Gen.h @@ -304,6 +304,12 @@ class Composed; template class TypeAssertion; +class Concat; + +class RangeConcat; + +class Cycle; + /* * Sinks */ diff --git a/folly/experimental/test/GenTest.cpp b/folly/experimental/test/GenTest.cpp index d2412af0..9ab1aa57 100644 --- a/folly/experimental/test/GenTest.cpp +++ b/folly/experimental/test/GenTest.cpp @@ -948,6 +948,44 @@ TEST(StringGen, EmptySplit) { } } +TEST(Gen, Cycle) { + { + auto s = from({1, 2}); + EXPECT_EQ((vector { 1, 2, 1, 2, 1 }), + s | cycle | take(5) | as()); + } + { + auto s = from({1, 2}); + EXPECT_EQ((vector { 1, 2, 1, 2 }), + s | cycle(2) | as()); + } + { + auto s = from({1, 2, 3}); + EXPECT_EQ((vector { 1, 2, 1, 2, 1 }), + s | take(2) | cycle | take(5) | as()); + } + { + auto s = empty(); + EXPECT_EQ((vector { }), + s | cycle | take(4) | as()); + } + { + int count = 3; + int* pcount = &count; + auto countdown = GENERATOR(int) { + ASSERT_GE(*pcount, 0) + << "Cycle should have stopped when it didnt' get values!"; + for (int i = 1; i <= *pcount; ++i) { + yield(i); + } + --*pcount; + }; + auto s = countdown; + EXPECT_EQ((vector { 1, 2, 3, 1, 2, 1}), + s | cycle | as()); + } +} + TEST(StringGen, Split) { auto collect = eachTo() | as(); { @@ -1099,7 +1137,6 @@ TEST(StringGen, EachToPair) { } } - TEST(StringGen, Resplit) { auto collect = eachTo() | as(); {