From 2015ae71620e2d8cddce9b7103af407616308a89 Mon Sep 17 00:00:00 2001 From: Tom Jackson Date: Thu, 3 Jul 2014 15:28:27 -0700 Subject: [PATCH 1/1] stride() Summary: thatwaseasy Test Plan: iloveunittests Reviewed By: lucian@fb.com Subscribers: philipp FB internal diff: D1419848 Tasks: 4636617 --- folly/gen/Base-inl.h | 89 +++++++++++++++++++++++++++++++------ folly/gen/Base.h | 2 + folly/gen/test/BaseTest.cpp | 47 ++++++++++++++++++-- 3 files changed, 122 insertions(+), 16 deletions(-) diff --git a/folly/gen/Base-inl.h b/folly/gen/Base-inl.h index a805b08e..faaa92ac 100644 --- a/folly/gen/Base-inl.h +++ b/folly/gen/Base-inl.h @@ -334,7 +334,7 @@ class Just : public GenImpl> { "Just requires non-ref types"); const Value value_; public: - Just(Value value) : value_(std::forward(value)) {} + explicit Just(Value value) : value_(std::forward(value)) {} template bool apply(Handler&& handler) const { @@ -598,6 +598,69 @@ class Take : public Operator { } }; +/** + * Stride - For producing every Nth value from a source. + * + * This type is usually used through the 'stride' helper function, like: + * + * auto half = from(samples) + * | stride(2); + */ +class Stride : public Operator { + size_t stride_; + + public: + explicit Stride(size_t stride) : stride_(stride) { + if (stride == 0) { + throw std::invalid_argument("stride must not be 0"); + } + } + + template + class Generator : public GenImpl> { + Source source_; + size_t stride_; + public: + Generator(Source source, size_t stride) + : source_(std::move(source)), stride_(stride) {} + + template + bool apply(Handler&& handler) const { + size_t distance = stride_; + return source_.apply([&](Value value)->bool { + if (++distance >= stride_) { + if (!handler(std::forward(value))) { + return false; + } + distance = 0; + } + return true; + }); + } + + template + void foreach(Body&& body) const { + size_t distance = stride_; + source_.foreach([&](Value value) { + if (++distance >= stride_) { + body(std::forward(value)); + distance = 0; + } + }); + } + }; + + template > + Gen compose(GenImpl&& source) const { + return Gen(std::move(source.self()), stride_); + } + + template > + Gen compose(const GenImpl& source) const { + return Gen(source.self(), stride_); + } +}; + /** * Sample - For taking a random sample of N elements from a sequence * (without replacement). @@ -1615,8 +1678,7 @@ template> { ErrorHandler handler_; public: - GuardImpl(ErrorHandler handler) - : handler_(std::move(handler)) {} + explicit GuardImpl(ErrorHandler handler) : handler_(std::move(handler)) {} template @@ -1801,7 +1863,7 @@ template class VirtualGen : public GenImpl> { class WrapperBase { public: - virtual ~WrapperBase() {} + virtual ~WrapperBase() noexcept {} virtual bool apply(const std::function& handler) const = 0; virtual void foreach(const std::function& body) const = 0; virtual std::unique_ptr clone() const = 0; @@ -1831,25 +1893,22 @@ class VirtualGen : public GenImpl> { std::unique_ptr wrapper_; public: - template + template /* implicit */ VirtualGen(Self source) - : wrapper_(new WrapperImpl(std::move(source))) - { } + : wrapper_(new WrapperImpl(std::move(source))) {} - VirtualGen(VirtualGen&& source) - : wrapper_(std::move(source.wrapper_)) - { } + VirtualGen(VirtualGen&& source) noexcept + : wrapper_(std::move(source.wrapper_)) {} VirtualGen(const VirtualGen& source) - : wrapper_(source.wrapper_->clone()) - { } + : wrapper_(source.wrapper_->clone()) {} VirtualGen& operator=(const VirtualGen& source) { wrapper_.reset(source.wrapper_->clone()); return *this; } - VirtualGen& operator=(VirtualGen&& source) { + VirtualGen& operator=(VirtualGen&& source) noexcept { wrapper_= std::move(source.wrapper_); return *this; } @@ -1910,6 +1969,10 @@ inline detail::Take take(size_t count) { return detail::Take(count); } +inline detail::Stride stride(size_t s) { + return detail::Stride(s); +} + template inline detail::Sample sample(size_t count, Random rng = Random()) { return detail::Sample(count, std::move(rng)); diff --git a/folly/gen/Base.h b/folly/gen/Base.h index 047de1e9..2c8c2635 100644 --- a/folly/gen/Base.h +++ b/folly/gen/Base.h @@ -313,6 +313,8 @@ class Until; class Take; +class Stride; + template class Sample; diff --git a/folly/gen/test/BaseTest.cpp b/folly/gen/test/BaseTest.cpp index 7d34a21d..2ff11c83 100644 --- a/folly/gen/test/BaseTest.cpp +++ b/folly/gen/test/BaseTest.cpp @@ -308,6 +308,47 @@ TEST(Gen, Take) { } } + +TEST(Gen, Stride) { + { + EXPECT_THROW(stride(0), std::invalid_argument); + } + { + auto expected = vector{1, 2, 3, 4}; + auto actual + = seq(1, 4) + | stride(1) + | as>(); + EXPECT_EQ(expected, actual); + } + { + auto expected = vector{1, 3, 5, 7}; + auto actual + = seq(1, 8) + | stride(2) + | as>(); + EXPECT_EQ(expected, actual); + } + { + auto expected = vector{1, 4, 7, 10}; + auto actual + = seq(1, 12) + | stride(3) + | as>(); + EXPECT_EQ(expected, actual); + } + { + auto expected = vector{1, 3, 5, 7, 9, 1, 4, 7, 10}; + auto actual + = ((seq(1, 10) | stride(2)) + + (seq(1, 10) | stride(3))) + | as>(); + EXPECT_EQ(expected, actual); + } + EXPECT_EQ(500, seq(1) | take(1000) | stride(2) | count); + EXPECT_EQ(10, seq(1) | take(1000) | stride(2) | take(10) | count); +} + TEST(Gen, Sample) { std::mt19937 rnd(42); @@ -767,8 +808,8 @@ class TestIntSeq : public GenImpl { return true; } - TestIntSeq(TestIntSeq&&) = default; - TestIntSeq& operator=(TestIntSeq&&) = default; + TestIntSeq(TestIntSeq&&) noexcept = default; + TestIntSeq& operator=(TestIntSeq&&) noexcept = default; TestIntSeq(const TestIntSeq&) = delete; TestIntSeq& operator=(const TestIntSeq&) = delete; }; @@ -809,7 +850,7 @@ struct CopyCounter { ++alive; } - CopyCounter(CopyCounter&& source) { + CopyCounter(CopyCounter&& source) noexcept { *this = std::move(source); ++alive; } -- 2.34.1