From: Tom Jackson Date: Mon, 8 Jul 2013 19:41:11 +0000 (-0700) Subject: guard() (redo) X-Git-Tag: v0.22.0~927 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b5a0a9f7095fea0ed4c1074c60ec4a747a98fcc6;p=folly.git guard() (redo) Summary: For handling exceptions from downstream operations. Now with cleaner build. Test Plan: Unit tests, including those outside `folly`. Reviewed By: marcelo.juchem@fb.com FB internal diff: D877795 Blame Revision: https://phabricator.fb.com/D872581 --- diff --git a/folly/experimental/Gen-inl.h b/folly/experimental/Gen-inl.h index 8b0c4dc7..f553cc86 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,91 @@ 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()); } }; + +/** + * GuardImpl - 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(); + * + * TODO(tjackson): Rename this back to Guard. + **/ +template +class GuardImpl : public Operator> { + ErrorHandler handler_; + public: + GuardImpl(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) -> bool { + 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..342968b0 100644 --- a/folly/experimental/Gen.h +++ b/folly/experimental/Gen.h @@ -343,6 +343,10 @@ struct GeneratorBuilder; template class Contains; +template +class GuardImpl; + } /** @@ -622,6 +626,16 @@ Contains contains(Needle&& needle) { return Contains(std::forward(needle)); } +template::type>> +GuardImpl guard(ErrorHandler&& handler) { + return GuardImpl(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);