Commit 96c76d55 authored by Tom Jackson's avatar Tom Jackson Committed by Sara Golemon

guard<Exception>()

Summary: For handling exceptions from downstream operations.

Test Plan: Unit tests

Reviewed By: marcelo.juchem@fb.com

FB internal diff: D874344
parent ca5621fa
...@@ -1675,11 +1675,11 @@ class RangeConcat : public Operator<RangeConcat> { ...@@ -1675,11 +1675,11 @@ class RangeConcat : public Operator<RangeConcat> {
public: public:
RangeConcat() { } RangeConcat() { }
template<class Source, template<class Range,
class Range, class Source,
class InnerValue = typename ValueTypeOfRange<Range>::RefType> class InnerValue = typename ValueTypeOfRange<Range>::RefType>
class Generator class Generator
: public GenImpl<InnerValue, Generator<Source, Range, InnerValue>> { : public GenImpl<InnerValue, Generator<Range, Source, InnerValue>> {
Source source_; Source source_;
public: public:
explicit Generator(Source source) explicit Generator(Source source)
...@@ -1709,19 +1709,89 @@ class RangeConcat : public Operator<RangeConcat> { ...@@ -1709,19 +1709,89 @@ class RangeConcat : public Operator<RangeConcat> {
template<class Value, template<class Value,
class Source, class Source,
class Gen = Generator<Source, Value>> class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const { Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self())); return Gen(std::move(source.self()));
} }
template<class Value, template<class Value,
class Source, class Source,
class Gen = Generator<Source, Value>> class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const { Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self()); 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>([](std::runtime_error& e,
* StringPiece sp) {
* LOG(ERROR) << sp << ": " << e.str();
* return true; // continue processing subsequent lines
* })
* | eachTo<int>()
* | as<vector>();
**/
template<class Exception,
class ErrorHandler>
class Guard : public Operator<Guard<Exception, ErrorHandler>> {
ErrorHandler handler_;
public:
Guard(ErrorHandler handler)
: handler_(std::move(handler)) {}
template<class Value,
class Source>
class Generator : public GenImpl<Value, Generator<Value, Source>> {
Source source_;
ErrorHandler handler_;
public:
explicit Generator(Source source,
ErrorHandler handler)
: source_(std::move(source)),
handler_(std::move(handler)) {}
template<class Handler>
bool apply(Handler&& handler) const {
return source_.apply([&](Value value) {
try {
handler(std::forward<Value>(value));
return true;
} catch (Exception& e) {
return handler_(e, std::forward<Value>(value));
}
});
}
static constexpr bool infinite = Source::infinite;
};
template<class Value,
class Source,
class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()), handler_);
}
template<class Value,
class Source,
class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self(), handler_);
}
};
} //::detail } //::detail
/** /**
......
...@@ -343,6 +343,10 @@ struct GeneratorBuilder; ...@@ -343,6 +343,10 @@ struct GeneratorBuilder;
template<class Needle> template<class Needle>
class Contains; class Contains;
template<class Exception,
class ErrorHandler>
class Guard;
} }
/** /**
...@@ -622,6 +626,14 @@ Contains contains(Needle&& needle) { ...@@ -622,6 +626,14 @@ Contains contains(Needle&& needle) {
return Contains(std::forward<Needle>(needle)); return Contains(std::forward<Needle>(needle));
} }
template<class Exception,
class ErrorHandler,
class Guard = detail::Guard<Exception,
typename std::decay<ErrorHandler>::type>>
Guard guard(ErrorHandler&& handler) {
return Guard(std::forward<ErrorHandler>(handler));
}
}} // folly::gen }} // folly::gen
#include "folly/experimental/Gen-inl.h" #include "folly/experimental/Gen-inl.h"
...@@ -1214,6 +1214,38 @@ INSTANTIATE_TEST_CASE_P( ...@@ -1214,6 +1214,38 @@ INSTANTIATE_TEST_CASE_P(
FileGenBufferedTest, FileGenBufferedTest,
::testing::Values(0, 1, 2, 4, 8, 64, 4096)); ::testing::Values(0, 1, 2, 4, 8, 64, 4096));
TEST(Gen, Guard) {
using std::runtime_error;
EXPECT_THROW(from({"1", "a", "3"})
| eachTo<int>()
| sum,
runtime_error);
EXPECT_EQ(4,
from({"1", "a", "3"})
| guard<runtime_error>([](runtime_error&, const char*) {
return true; // continue
})
| eachTo<int>()
| sum);
EXPECT_EQ(1,
from({"1", "a", "3"})
| guard<runtime_error>([](runtime_error&, const char*) {
return false; // break
})
| eachTo<int>()
| sum);
EXPECT_THROW(from({"1", "a", "3"})
| guard<runtime_error>([](runtime_error&, const char* v) {
if (v[0] == 'a') {
throw;
}
return true;
})
| eachTo<int>()
| sum,
runtime_error);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true); google::ParseCommandLineFlags(&argc, &argv, true);
......
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