From 96c76d557b4de4489cba50c7f8d13d83a1710c71 Mon Sep 17 00:00:00 2001 From: Tom Jackson Date: Wed, 3 Jul 2013 11:38:32 -0700 Subject: [PATCH] guard() Summary: For handling exceptions from downstream operations. Test Plan: Unit tests Reviewed By: marcelo.juchem@fb.com FB internal diff: D874344 --- folly/experimental/Gen-inl.h | 80 +++++++++++++++++++++++++++-- folly/experimental/Gen.h | 12 +++++ folly/experimental/test/GenTest.cpp | 32 ++++++++++++ 3 files changed, 119 insertions(+), 5 deletions(-) diff --git a/folly/experimental/Gen-inl.h b/folly/experimental/Gen-inl.h index 8b0c4dc7..064bd6b5 100644 --- a/folly/experimental/Gen-inl.h +++ b/folly/experimental/Gen-inl.h @@ -1675,11 +1675,11 @@ class RangeConcat : public Operator { public: RangeConcat() { } - template::RefType> class Generator - : public GenImpl> { + : public GenImpl> { Source source_; public: explicit Generator(Source source) @@ -1709,19 +1709,89 @@ class RangeConcat : public Operator { template> + class Gen = Generator> Gen compose(GenImpl&& source) const { return Gen(std::move(source.self())); } template> + class Gen = Generator> Gen compose(const GenImpl& source) const { return Gen(source.self()); } }; + +/** + * Guard - For handling exceptions from downstream computation. Requires the + * type of exception to catch, and handler function to invoke in the event of + * the exception. Note that the handler may: + * 1) return true to continue processing the sequence + * 2) return false to end the sequence immediately + * 3) throw, to pass the exception to the next catch + * The handler must match the signature 'bool(Exception&, Value)'. + * + * This type is used through the `guard` helper, like so: + * + * auto indexes + * = byLine(STDIN_FILENO) + * | guard([](std::runtime_error& e, + * StringPiece sp) { + * LOG(ERROR) << sp << ": " << e.str(); + * return true; // continue processing subsequent lines + * }) + * | eachTo() + * | as(); + **/ +template +class Guard : public Operator> { + ErrorHandler handler_; + public: + Guard(ErrorHandler handler) + : handler_(std::move(handler)) {} + + template + class Generator : public GenImpl> { + Source source_; + ErrorHandler handler_; + public: + explicit Generator(Source source, + ErrorHandler handler) + : source_(std::move(source)), + handler_(std::move(handler)) {} + + template + bool apply(Handler&& handler) const { + return source_.apply([&](Value value) { + try { + handler(std::forward(value)); + return true; + } catch (Exception& e) { + return handler_(e, std::forward(value)); + } + }); + } + + static constexpr bool infinite = Source::infinite; + }; + + template> + Gen compose(GenImpl&& source) const { + return Gen(std::move(source.self()), handler_); + } + + template> + Gen compose(const GenImpl& source) const { + return Gen(source.self(), handler_); + } +}; } //::detail /** diff --git a/folly/experimental/Gen.h b/folly/experimental/Gen.h index 47fab197..12407fc7 100644 --- a/folly/experimental/Gen.h +++ b/folly/experimental/Gen.h @@ -343,6 +343,10 @@ struct GeneratorBuilder; template class Contains; +template +class Guard; + } /** @@ -622,6 +626,14 @@ Contains contains(Needle&& needle) { return Contains(std::forward(needle)); } +template::type>> +Guard guard(ErrorHandler&& handler) { + return Guard(std::forward(handler)); +} + }} // folly::gen #include "folly/experimental/Gen-inl.h" diff --git a/folly/experimental/test/GenTest.cpp b/folly/experimental/test/GenTest.cpp index ddb7bf8a..d2412af0 100644 --- a/folly/experimental/test/GenTest.cpp +++ b/folly/experimental/test/GenTest.cpp @@ -1214,6 +1214,38 @@ INSTANTIATE_TEST_CASE_P( FileGenBufferedTest, ::testing::Values(0, 1, 2, 4, 8, 64, 4096)); +TEST(Gen, Guard) { + using std::runtime_error; + EXPECT_THROW(from({"1", "a", "3"}) + | eachTo() + | sum, + runtime_error); + EXPECT_EQ(4, + from({"1", "a", "3"}) + | guard([](runtime_error&, const char*) { + return true; // continue + }) + | eachTo() + | sum); + EXPECT_EQ(1, + from({"1", "a", "3"}) + | guard([](runtime_error&, const char*) { + return false; // break + }) + | eachTo() + | sum); + EXPECT_THROW(from({"1", "a", "3"}) + | guard([](runtime_error&, const char* v) { + if (v[0] == 'a') { + throw; + } + return true; + }) + | eachTo() + | sum, + runtime_error); +} + int main(int argc, char *argv[]) { testing::InitGoogleTest(&argc, argv); google::ParseCommandLineFlags(&argc, &argv, true); -- 2.34.1