From ca7e6f1b2c1b52330b66ceaa2ddb1f97c4bd61cb Mon Sep 17 00:00:00 2001 From: Tom Jackson Date: Sun, 4 Aug 2013 14:30:06 -0700 Subject: [PATCH] dereference Summary: For dealing with sequences of pointers. Works with pointer wrappers, and filters out nullptrs, see tests. Test Plan: Unit tests Reviewed By: tulloch@fb.com FB internal diff: D914069 --- folly/experimental/Gen-inl.h | 61 ++++++++++++++++++++++++ folly/experimental/Gen.h | 2 + folly/experimental/test/GenTest.cpp | 73 +++++++++++++++++++++++++---- 3 files changed, 128 insertions(+), 8 deletions(-) diff --git a/folly/experimental/Gen-inl.h b/folly/experimental/Gen-inl.h index 1d975267..7a752d0f 100644 --- a/folly/experimental/Gen-inl.h +++ b/folly/experimental/Gen-inl.h @@ -1955,6 +1955,65 @@ class Cycle : public Operator { } }; +/** + * Dereference - For dereferencing a sequence of pointers while filtering out + * null pointers. + * + * This type is usually used through the 'dereference' static value, like: + * + * auto refs = from(ptrs) | dereference; + */ +class Dereference : public Operator { + public: + Dereference() {} + + template())> + class Generator : public GenImpl> { + Source source_; + public: + explicit Generator(Source source) + : source_(std::move(source)) {} + + template + void foreach(Body&& body) const { + source_.foreach([&](Value value) { + if (value) { + return body(*value); + } + }); + } + + template + bool apply(Handler&& handler) const { + return source_.apply([&](Value value) -> bool { + if (value) { + return handler(*value); + } + 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())); + } + + template> + Gen compose(const GenImpl& source) const { + return Gen(source.self()); + } +}; + } //::detail /** @@ -2067,6 +2126,8 @@ static const detail::RangeConcat rconcat; */ static const detail::Cycle cycle; +static const detail::Dereference dereference; + inline detail::Take take(size_t count) { return detail::Take(count); } diff --git a/folly/experimental/Gen.h b/folly/experimental/Gen.h index fa1ec1b2..e0f61f0b 100644 --- a/folly/experimental/Gen.h +++ b/folly/experimental/Gen.h @@ -312,6 +312,8 @@ class Cycle; class Batch; +class Dereference; + /* * Sinks */ diff --git a/folly/experimental/test/GenTest.cpp b/folly/experimental/test/GenTest.cpp index 9b41f0b7..499ab052 100644 --- a/folly/experimental/test/GenTest.cpp +++ b/folly/experimental/test/GenTest.cpp @@ -20,26 +20,29 @@ #include #include #include -#include "folly/experimental/Gen.h" -#include "folly/experimental/StringGen.h" -#include "folly/experimental/CombineGen.h" -#include "folly/experimental/FileGen.h" -#include "folly/experimental/TestUtil.h" + #include "folly/FBString.h" #include "folly/FBVector.h" #include "folly/Format.h" +#include "folly/MapUtil.h" +#include "folly/Memory.h" #include "folly/dynamic.h" +#include "folly/experimental/CombineGen.h" +#include "folly/experimental/FileGen.h" +#include "folly/experimental/Gen.h" +#include "folly/experimental/StringGen.h" +#include "folly/experimental/TestUtil.h" using namespace folly::gen; using namespace folly; +using std::make_tuple; using std::ostream; using std::pair; using std::set; -using std::unique_ptr; -using std::vector; using std::string; using std::tuple; -using std::make_tuple; +using std::unique_ptr; +using std::vector; #define EXPECT_SAME(A, B) \ static_assert(std::is_same::value, "Mismatched: " #A ", " #B) @@ -1038,6 +1041,60 @@ TEST(Gen, Cycle) { } } +TEST(Gen, Dereference) { + { + const int x = 4, y = 2; + auto s = from({&x, nullptr, &y}); + EXPECT_EQ(6, s | dereference | sum); + } + { + vector a { 1, 2 }; + vector b { 3, 4 }; + vector*> pv { &a, nullptr, &b }; + from(pv) + | dereference + | [&](vector& v) { + v.push_back(5); + }; + EXPECT_EQ(3, a.size()); + EXPECT_EQ(3, b.size()); + EXPECT_EQ(5, a.back()); + EXPECT_EQ(5, b.back()); + } + { + vector> maps { + { + { 2, 31 }, + { 3, 41 }, + }, + { + { 3, 52 }, + { 4, 62 }, + }, + { + { 4, 73 }, + { 5, 83 }, + }, + }; + EXPECT_EQ( + 93, + from(maps) + | map([](std::map& m) { + return get_ptr(m, 3); + }) + | dereference + | sum); + } + { + vector> ups; + ups.emplace_back(new int(3)); + ups.emplace_back(); + ups.emplace_back(new int(7)); + EXPECT_EQ(10, from(ups) | dereference | sum); + EXPECT_EQ(10, from(ups) | move | dereference | sum); + } +} + TEST(StringGen, Split) { auto collect = eachTo() | as(); { -- 2.34.1