Commit e1868ae2 authored by Max Katsev's avatar Max Katsev Committed by Facebook GitHub Bot

pass by rvalue in folly::gen::zip and interleave

Summary: Both operators use their own copy of the container (eg line 104), so mutating it should be ok

Reviewed By: ot

Differential Revision: D19170228

fbshipit-source-id: a53094bdbd3fb7b5028cf7ed4e0b073dd919b2d7
parent a7584380
...@@ -36,7 +36,7 @@ namespace detail { ...@@ -36,7 +36,7 @@ namespace detail {
template <class Container> template <class Container>
class Interleave : public Operator<Interleave<Container>> { class Interleave : public Operator<Interleave<Container>> {
// see comment about copies in CopiedSource // see comment about copies in CopiedSource
const std::shared_ptr<const Container> container_; const std::shared_ptr<Container> container_;
public: public:
explicit Interleave(Container container) explicit Interleave(Container container)
...@@ -45,30 +45,25 @@ class Interleave : public Operator<Interleave<Container>> { ...@@ -45,30 +45,25 @@ class Interleave : public Operator<Interleave<Container>> {
template <class Value, class Source> template <class Value, class Source>
class Generator : public GenImpl<Value, Generator<Value, Source>> { class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_; Source source_;
const std::shared_ptr<const Container> container_; const std::shared_ptr<Container> container_;
typedef const typename Container::value_type& ConstRefType;
static_assert(
std::is_same<const Value&, ConstRefType>::value,
"Only matching types may be interleaved");
public: public:
explicit Generator( explicit Generator(
Source source, Source source,
const std::shared_ptr<const Container> container) const std::shared_ptr<Container> container)
: source_(std::move(source)), container_(container) {} : source_(std::move(source)), container_(container) {}
template <class Handler> template <class Handler>
bool apply(Handler&& handler) const { bool apply(Handler&& handler) const {
auto iter = container_->begin(); auto iter = container_->begin();
return source_.apply([&](const Value& value) -> bool { return source_.apply([&](Value value) -> bool {
if (iter == container_->end()) { if (iter == container_->end()) {
return false; return false;
} }
if (!handler(value)) { if (!handler(std::forward<Value>(value))) {
return false; return false;
} }
if (!handler(*iter)) { if (!handler(std::move(*iter))) {
return false; return false;
} }
iter++; iter++;
...@@ -98,38 +93,37 @@ class Interleave : public Operator<Interleave<Container>> { ...@@ -98,38 +93,37 @@ class Interleave : public Operator<Interleave<Container>> {
template <class Container> template <class Container>
class Zip : public Operator<Zip<Container>> { class Zip : public Operator<Zip<Container>> {
// see comment about copies in CopiedSource // see comment about copies in CopiedSource
const std::shared_ptr<const Container> container_; const std::shared_ptr<Container> container_;
public: public:
explicit Zip(Container container) explicit Zip(Container container)
: container_(new Container(std::move(container))) {} : container_(new Container(std::move(container))) {}
template < template <
class Value1, class Value,
class Source, class Source,
class Value2 = decltype(*std::begin(*container_)),
class Result = std::tuple< class Result = std::tuple<
typename std::decay<Value1>::type, typename std::decay<Value>::type,
typename std::decay<Value2>::type>> typename std::decay<typename Container::value_type>::type>>
class Generator class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
: public GenImpl<Result, Generator<Value1, Source, Value2, Result>> {
Source source_; Source source_;
const std::shared_ptr<const Container> container_; const std::shared_ptr<Container> container_;
public: public:
explicit Generator( explicit Generator(
Source source, Source source,
const std::shared_ptr<const Container> container) const std::shared_ptr<Container> container)
: source_(std::move(source)), container_(container) {} : source_(std::move(source)), container_(container) {}
template <class Handler> template <class Handler>
bool apply(Handler&& handler) const { bool apply(Handler&& handler) const {
auto iter = container_->begin(); auto iter = container_->begin();
return (source_.apply([&](Value1 value) -> bool { return (source_.apply([&](Value value) -> bool {
if (iter == container_->end()) { if (iter == container_->end()) {
return false; return false;
} }
if (!handler(std::make_tuple(std::forward<Value1>(value), *iter))) { if (!handler(std::make_tuple(
std::forward<Value>(value), std::move(*iter)))) {
return false; return false;
} }
++iter; ++iter;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
#include <memory>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
...@@ -37,6 +38,13 @@ const folly::gen::detail::Map<folly::gen::detail::MergeTuples> gTupleFlatten{}; ...@@ -37,6 +38,13 @@ const folly::gen::detail::Map<folly::gen::detail::MergeTuples> gTupleFlatten{};
auto even = [](int i) -> bool { return i % 2 == 0; }; auto even = [](int i) -> bool { return i % 2 == 0; };
auto odd = [](int i) -> bool { return i % 2 == 1; }; auto odd = [](int i) -> bool { return i % 2 == 1; };
auto initVectorUniquePtr(int value) {
std::vector<std::unique_ptr<int>> v;
v.push_back(std::make_unique<int>(value));
v.push_back(std::make_unique<int>(value));
v.push_back(std::make_unique<int>(value));
return v;
}
TEST(CombineGen, Interleave) { TEST(CombineGen, Interleave) {
{ // large (infinite) base, small container { // large (infinite) base, small container
...@@ -53,6 +61,20 @@ TEST(CombineGen, Interleave) { ...@@ -53,6 +61,20 @@ TEST(CombineGen, Interleave) {
} }
} }
TEST(CombineGen, InterleaveMoveOnly) {
auto base = initVectorUniquePtr(1);
auto toInterleave = initVectorUniquePtr(2);
const auto interleaved =
from(base) | move | interleave(std::move(toInterleave)) | as<vector>();
ASSERT_EQ(interleaved.size(), 6);
EXPECT_EQ(*interleaved[0], 1);
EXPECT_EQ(*interleaved[1], 2);
EXPECT_EQ(*interleaved[2], 1);
EXPECT_EQ(*interleaved[3], 2);
EXPECT_EQ(*interleaved[4], 1);
EXPECT_EQ(*interleaved[5], 2);
}
TEST(CombineGen, Zip) { TEST(CombineGen, Zip) {
auto base0 = seq(1); auto base0 = seq(1);
// We rely on std::move(fbvector) emptying the source vector // We rely on std::move(fbvector) emptying the source vector
...@@ -87,6 +109,20 @@ TEST(CombineGen, Zip) { ...@@ -87,6 +109,20 @@ TEST(CombineGen, Zip) {
} }
} }
TEST(CombineGen, ZipMoveOnly) {
auto base = initVectorUniquePtr(1);
auto zippee = initVectorUniquePtr(2);
const auto combined =
from(base) | move | zip(std::move(zippee)) | as<vector>();
ASSERT_EQ(combined.size(), 3);
EXPECT_EQ(*std::get<0>(combined[0]), 1);
EXPECT_EQ(*std::get<1>(combined[0]), 2);
EXPECT_EQ(*std::get<0>(combined[1]), 1);
EXPECT_EQ(*std::get<1>(combined[1]), 2);
EXPECT_EQ(*std::get<0>(combined[2]), 1);
EXPECT_EQ(*std::get<1>(combined[2]), 2);
}
TEST(CombineGen, TupleFlatten) { TEST(CombineGen, TupleFlatten) {
vector<tuple<int, string>> intStringTupleVec{ vector<tuple<int, string>> intStringTupleVec{
tuple<int, string>{1, "1"}, tuple<int, string>{1, "1"},
......
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