Commit 2015ae71 authored by Tom Jackson's avatar Tom Jackson Committed by Tudor Bosman

stride()

Summary: thatwaseasy

Test Plan: iloveunittests

Reviewed By: lucian@fb.com

Subscribers: philipp

FB internal diff: D1419848

Tasks: 4636617
parent db66e2f4
...@@ -334,7 +334,7 @@ class Just : public GenImpl<const Value&, Just<Value>> { ...@@ -334,7 +334,7 @@ class Just : public GenImpl<const Value&, Just<Value>> {
"Just requires non-ref types"); "Just requires non-ref types");
const Value value_; const Value value_;
public: public:
Just(Value value) : value_(std::forward<Value>(value)) {} explicit Just(Value value) : value_(std::forward<Value>(value)) {}
template <class Handler> template <class Handler>
bool apply(Handler&& handler) const { bool apply(Handler&& handler) const {
...@@ -598,6 +598,69 @@ class Take : public Operator<Take> { ...@@ -598,6 +598,69 @@ class Take : public Operator<Take> {
} }
}; };
/**
* 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<Stride> {
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 Value, class Source>
class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
size_t stride_;
public:
Generator(Source source, size_t stride)
: source_(std::move(source)), stride_(stride) {}
template <class Handler>
bool apply(Handler&& handler) const {
size_t distance = stride_;
return source_.apply([&](Value value)->bool {
if (++distance >= stride_) {
if (!handler(std::forward<Value>(value))) {
return false;
}
distance = 0;
}
return true;
});
}
template <class Body>
void foreach(Body&& body) const {
size_t distance = stride_;
source_.foreach([&](Value value) {
if (++distance >= stride_) {
body(std::forward<Value>(value));
distance = 0;
}
});
}
};
template <class Source, class Value, class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), stride_);
}
template <class Source, class Value, class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), stride_);
}
};
/** /**
* Sample - For taking a random sample of N elements from a sequence * Sample - For taking a random sample of N elements from a sequence
* (without replacement). * (without replacement).
...@@ -1615,8 +1678,7 @@ template<class Exception, ...@@ -1615,8 +1678,7 @@ template<class Exception,
class GuardImpl : public Operator<GuardImpl<Exception, ErrorHandler>> { class GuardImpl : public Operator<GuardImpl<Exception, ErrorHandler>> {
ErrorHandler handler_; ErrorHandler handler_;
public: public:
GuardImpl(ErrorHandler handler) explicit GuardImpl(ErrorHandler handler) : handler_(std::move(handler)) {}
: handler_(std::move(handler)) {}
template<class Value, template<class Value,
class Source> class Source>
...@@ -1801,7 +1863,7 @@ template<class Value> ...@@ -1801,7 +1863,7 @@ template<class Value>
class VirtualGen : public GenImpl<Value, VirtualGen<Value>> { class VirtualGen : public GenImpl<Value, VirtualGen<Value>> {
class WrapperBase { class WrapperBase {
public: public:
virtual ~WrapperBase() {} virtual ~WrapperBase() noexcept {}
virtual bool apply(const std::function<bool(Value)>& handler) const = 0; virtual bool apply(const std::function<bool(Value)>& handler) const = 0;
virtual void foreach(const std::function<void(Value)>& body) const = 0; virtual void foreach(const std::function<void(Value)>& body) const = 0;
virtual std::unique_ptr<const WrapperBase> clone() const = 0; virtual std::unique_ptr<const WrapperBase> clone() const = 0;
...@@ -1831,25 +1893,22 @@ class VirtualGen : public GenImpl<Value, VirtualGen<Value>> { ...@@ -1831,25 +1893,22 @@ class VirtualGen : public GenImpl<Value, VirtualGen<Value>> {
std::unique_ptr<const WrapperBase> wrapper_; std::unique_ptr<const WrapperBase> wrapper_;
public: public:
template<class Self> template <class Self>
/* implicit */ VirtualGen(Self source) /* implicit */ VirtualGen(Self source)
: wrapper_(new WrapperImpl<Self>(std::move(source))) : wrapper_(new WrapperImpl<Self>(std::move(source))) {}
{ }
VirtualGen(VirtualGen&& source) VirtualGen(VirtualGen&& source) noexcept
: wrapper_(std::move(source.wrapper_)) : wrapper_(std::move(source.wrapper_)) {}
{ }
VirtualGen(const VirtualGen& source) VirtualGen(const VirtualGen& source)
: wrapper_(source.wrapper_->clone()) : wrapper_(source.wrapper_->clone()) {}
{ }
VirtualGen& operator=(const VirtualGen& source) { VirtualGen& operator=(const VirtualGen& source) {
wrapper_.reset(source.wrapper_->clone()); wrapper_.reset(source.wrapper_->clone());
return *this; return *this;
} }
VirtualGen& operator=(VirtualGen&& source) { VirtualGen& operator=(VirtualGen&& source) noexcept {
wrapper_= std::move(source.wrapper_); wrapper_= std::move(source.wrapper_);
return *this; return *this;
} }
...@@ -1910,6 +1969,10 @@ inline detail::Take take(size_t count) { ...@@ -1910,6 +1969,10 @@ inline detail::Take take(size_t count) {
return detail::Take(count); return detail::Take(count);
} }
inline detail::Stride stride(size_t s) {
return detail::Stride(s);
}
template<class Random = std::default_random_engine> template<class Random = std::default_random_engine>
inline detail::Sample<Random> sample(size_t count, Random rng = Random()) { inline detail::Sample<Random> sample(size_t count, Random rng = Random()) {
return detail::Sample<Random>(count, std::move(rng)); return detail::Sample<Random>(count, std::move(rng));
......
...@@ -313,6 +313,8 @@ class Until; ...@@ -313,6 +313,8 @@ class Until;
class Take; class Take;
class Stride;
template<class Rand> template<class Rand>
class Sample; class Sample;
......
...@@ -308,6 +308,47 @@ TEST(Gen, Take) { ...@@ -308,6 +308,47 @@ 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>>();
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{1, 3, 5, 7};
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>>();
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{1, 3, 5, 7, 9, 1, 4, 7, 10};
auto actual
= ((seq(1, 10) | stride(2)) +
(seq(1, 10) | stride(3)))
| as<vector<int>>();
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) { TEST(Gen, Sample) {
std::mt19937 rnd(42); std::mt19937 rnd(42);
...@@ -767,8 +808,8 @@ class TestIntSeq : public GenImpl<int, TestIntSeq> { ...@@ -767,8 +808,8 @@ class TestIntSeq : public GenImpl<int, TestIntSeq> {
return true; return true;
} }
TestIntSeq(TestIntSeq&&) = default; TestIntSeq(TestIntSeq&&) noexcept = default;
TestIntSeq& operator=(TestIntSeq&&) = default; TestIntSeq& operator=(TestIntSeq&&) noexcept = default;
TestIntSeq(const TestIntSeq&) = delete; TestIntSeq(const TestIntSeq&) = delete;
TestIntSeq& operator=(const TestIntSeq&) = delete; TestIntSeq& operator=(const TestIntSeq&) = delete;
}; };
...@@ -809,7 +850,7 @@ struct CopyCounter { ...@@ -809,7 +850,7 @@ struct CopyCounter {
++alive; ++alive;
} }
CopyCounter(CopyCounter&& source) { CopyCounter(CopyCounter&& source) noexcept {
*this = std::move(source); *this = std::move(source);
++alive; ++alive;
} }
......
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