Commit 52479853 authored by Tom Jackson's avatar Tom Jackson Committed by Sara Golemon

Fixing Until, Take

Summary:
`apply()` returns false if and only if the handler it was //directly//
passed returned false. `Take` didn't do this right, and `Until` was just broken.

Test Plan: More thorough unit tests.

Reviewed By: kittipat@fb.com

FB internal diff: D913185
parent d82103b8
...@@ -159,11 +159,11 @@ class GenImpl : public FBounded<Self> { ...@@ -159,11 +159,11 @@ class GenImpl : public FBounded<Self> {
typedef typename std::decay<Value>::type StorageType; typedef typename std::decay<Value>::type StorageType;
/** /**
* apply() - Send all values produced by this generator to given * apply() - Send all values produced by this generator to given handler until
* handler until the handler returns false. Returns false if and only if the * the handler returns false. Returns false if and only if the handler passed
* handler returns false. Note: It should return true even if it completes * in returns false. Note: It should return true even if it completes (without
* (without the handler returning false), as 'Chain' uses the return value of * the handler returning false), as 'Chain' uses the return value of apply to
* apply to determine if it should process the second object in its chain. * determine if it should process the second object in its chain.
*/ */
template<class Handler> template<class Handler>
bool apply(Handler&& handler) const; bool apply(Handler&& handler) const;
...@@ -695,10 +695,8 @@ class Until : public Operator<Until<Predicate>> { ...@@ -695,10 +695,8 @@ class Until : public Operator<Until<Predicate>> {
{} {}
template<class Value, template<class Value,
class Source, class Source>
class Result = typename std::result_of<Predicate(Value)>::type> class Generator : public GenImpl<Value, Generator<Value, Source>> {
class Generator :
public GenImpl<Result, Generator<Value, Source, Result>> {
Source source_; Source source_;
Predicate pred_; Predicate pred_;
public: public:
...@@ -707,10 +705,18 @@ class Until : public Operator<Until<Predicate>> { ...@@ -707,10 +705,18 @@ class Until : public Operator<Until<Predicate>> {
template<class Handler> template<class Handler>
bool apply(Handler&& handler) const { bool apply(Handler&& handler) const {
return source_.apply([&](Value value) -> bool { bool cancelled = false;
return !pred_(std::forward<Value>(value)) source_.apply([&](Value value) -> bool {
&& handler(std::forward<Value>(value)); if (pred_(value)) { // un-forwarded to disable move
return false;
}
if (!handler(std::forward<Value>(value))) {
cancelled = true;
return false;
}
return true;
}); });
return !cancelled;
} }
}; };
...@@ -761,12 +767,15 @@ class Take : public Operator<Take> { ...@@ -761,12 +767,15 @@ class Take : public Operator<Take> {
bool apply(Handler&& handler) const { bool apply(Handler&& handler) const {
if (count_ == 0) { return false; } if (count_ == 0) { return false; }
size_t n = count_; size_t n = count_;
return source_.apply([&](Value value) -> bool { bool cancelled = false;
if (!handler(std::forward<Value>(value))) { source_.apply([&](Value value) -> bool {
return false; if (!handler(std::forward<Value>(value))) {
} cancelled = true;
return --n; return false;
}); }
return --n;
});
return !cancelled;
} }
}; };
...@@ -907,7 +916,7 @@ class Skip : public Operator<Skip> { ...@@ -907,7 +916,7 @@ class Skip : public Operator<Skip> {
template<class Handler> template<class Handler>
bool apply(Handler&& handler) const { bool apply(Handler&& handler) const {
if (count_ == 0) { if (count_ == 0) {
return source_.apply(handler); return source_.apply(std::forward<Handler>(handler));
} }
size_t n = 0; size_t n = 0;
return source_.apply([&](Value value) -> bool { return source_.apply([&](Value value) -> bool {
......
...@@ -241,13 +241,37 @@ TEST(Gen, Contains) { ...@@ -241,13 +241,37 @@ TEST(Gen, Contains) {
} }
TEST(Gen, Take) { TEST(Gen, Take) {
auto expected = vector<int>{1, 4, 9, 16}; {
auto actual = auto expected = vector<int>{1, 4, 9, 16};
auto actual =
seq(1, 1000) seq(1, 1000)
| mapped([](int x) { return x * x; }) | mapped([](int x) { return x * x; })
| take(4) | take(4)
| as<vector<int>>(); | as<vector<int>>();
EXPECT_EQ(expected, actual); EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{ 0, 1, 4, 5, 8 };
auto actual
= ((seq(0) | take(2)) +
(seq(4) | take(2)) +
(seq(8) | take(2)))
| take(5)
| as<vector>();
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{ 0, 1, 4, 5, 8 };
auto actual
= seq(0)
| mapped([](int i) {
return seq(i * 4) | take(2);
})
| concat
| take(5)
| as<vector>();
EXPECT_EQ(expected, actual);
}
} }
TEST(Gen, Sample) { TEST(Gen, Sample) {
...@@ -294,11 +318,39 @@ TEST(Gen, Skip) { ...@@ -294,11 +318,39 @@ TEST(Gen, Skip) {
} }
TEST(Gen, Until) { TEST(Gen, Until) {
auto gen = {
seq(1) //infinite auto expected = vector<int>{1, 4, 9, 16};
| mapped([](int x) { return x * x; }) auto actual
| until([](int x) { return x >= 1000; }); = seq(1, 1000)
EXPECT_EQ(31, gen | count); | mapped([](int x) { return x * x; })
| until([](int x) { return x > 20; })
| as<vector<int>>();
EXPECT_EQ(expected, actual);
}
{
auto expected = vector<int>{ 0, 1, 4, 5, 8 };
auto actual
= ((seq(0) | until([](int i) { return i > 1; })) +
(seq(4) | until([](int i) { return i > 5; })) +
(seq(8) | until([](int i) { return i > 9; })))
| until([](int i) { return i > 8; })
| as<vector<int>>();
EXPECT_EQ(expected, actual);
}
/*
{
auto expected = vector<int>{ 0, 1, 5, 6, 10 };
auto actual
= seq(0)
| mapped([](int i) {
return seq(i * 5) | until([=](int j) { return j > i * 5 + 1; });
})
| concat
| until([](int i) { return i > 10; })
| as<vector<int>>();
EXPECT_EQ(expected, actual);
}
*/
} }
auto even = [](int i) -> bool { return i % 2 == 0; }; auto even = [](int i) -> bool { return i % 2 == 0; };
......
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