X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;ds=sidebyside;f=folly%2FTry.h;h=7b97754c7d13a632220da91101c8ddd413bd1e68;hb=598926c4529b459ce535657ec76ac792f4ec010e;hp=fe963753b0f895642e44b3a203ca4360e4a78585;hpb=790b68acacebb628f9552b1c20fbafa4962aebb7;p=folly.git diff --git a/folly/Try.h b/folly/Try.h index fe963753..7b97754c 100644 --- a/folly/Try.h +++ b/folly/Try.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,11 @@ class UsingUninitializedTry : public TryException { UsingUninitializedTry() : TryException("Using uninitialized try") {} }; +namespace try_detail { +[[noreturn]] void throwTryDoesNotContainException(); +[[noreturn]] void throwUsingUninitializedTry(); +} // namespace try_detail + /* * Try is a wrapper that contains either an instance of T, an exception, or * nothing. Exceptions are stored as exception_wrappers so that the user can @@ -81,6 +87,11 @@ class Try { */ explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {} + template + explicit Try(in_place_t, Args&&... args) noexcept( + noexcept(::new (nullptr) T(std::declval()...))) + : contains_(Contains::VALUE), value_(std::forward(args)...) {} + /// Implicit conversion from Try to Try template /* implicit */ @@ -103,15 +114,8 @@ class Try { */ FOLLY_DEPRECATED("use Try(exception_wrapper)") explicit Try(std::exception_ptr ep) - : contains_(Contains::EXCEPTION) { - try { - std::rethrow_exception(ep); - } catch (std::exception& e) { - e_ = exception_wrapper(std::current_exception(), e); - } catch (...) { - e_ = exception_wrapper(std::current_exception()); - } - } + : contains_(Contains::EXCEPTION), + e_(exception_wrapper::from_exception_ptr(ep)) {} // Move constructor Try(Try&& t) noexcept; @@ -131,21 +135,28 @@ class Try { * * @returns mutable reference to the contained value */ - T& value()&; + T& value() &; /* * Get a rvalue reference to the contained value. If the Try contains an * exception it will be rethrown. * * @returns rvalue reference to the contained value */ - T&& value()&&; + T&& value() &&; /* * Get a const reference to the contained value. If the Try contains an * exception it will be rethrown. * * @returns const reference to the contained value */ - const T& value() const&; + const T& value() const &; + /* + * Get a const rvalue reference to the contained value. If the Try contains an + * exception it will be rethrown. + * + * @returns const rvalue reference to the contained value + */ + const T&& value() const &&; /* * If the Try contains an exception, rethrow it. Otherwise do nothing. @@ -158,13 +169,35 @@ class Try { * * @returns const reference to the contained value */ - const T& operator*() const { return value(); } + const T& operator*() const & { + return value(); + } /* * Dereference operator. If the Try contains an exception it will be rethrown. * * @returns mutable reference to the contained value */ - T& operator*() { return value(); } + T& operator*() & { + return value(); + } + /* + * Mutable rvalue dereference operator. If the Try contains an exception it + * will be rethrown. + * + * @returns rvalue reference to the contained value + */ + T&& operator*() && { + return std::move(value()); + } + /* + * Const rvalue dereference operator. If the Try contains an exception it + * will be rethrown. + * + * @returns rvalue reference to the contained value + */ + const T&& operator*() const && { + return std::move(value()); + } /* * Const arrow operator. If the Try contains an exception it will be @@ -197,20 +230,59 @@ class Try { return hasException() && e_.is_compatible_with(); } - exception_wrapper& exception() { - if (UNLIKELY(!hasException())) { - throw TryException("exception(): Try does not contain an exception"); + exception_wrapper& exception() & { + if (!hasException()) { + try_detail::throwTryDoesNotContainException(); } return e_; } - const exception_wrapper& exception() const { - if (UNLIKELY(!hasException())) { - throw TryException("exception(): Try does not contain an exception"); + exception_wrapper&& exception() && { + if (!hasException()) { + try_detail::throwTryDoesNotContainException(); + } + return std::move(e_); + } + + const exception_wrapper& exception() const & { + if (!hasException()) { + try_detail::throwTryDoesNotContainException(); } return e_; } + const exception_wrapper&& exception() const && { + if (!hasException()) { + try_detail::throwTryDoesNotContainException(); + } + return std::move(e_); + } + + /* + * @returns a pointer to the `std::exception` held by `*this`, if one is held; + * otherwise, returns `nullptr`. + */ + std::exception* tryGetExceptionObject() { + return hasException() ? e_.get_exception() : nullptr; + } + std::exception const* tryGetExceptionObject() const { + return hasException() ? e_.get_exception() : nullptr; + } + + /* + * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose + * type `From` permits `std::is_convertible`; otherwise, + * returns `nullptr`. + */ + template + E* tryGetExceptionObject() { + return hasException() ? e_.get_exception() : nullptr; + } + template + E const* tryGetExceptionObject() const { + return hasException() ? e_.get_exception() : nullptr; + } + /* * If the Try contains an exception and it is of type Ex, execute func(Ex) * @@ -223,9 +295,32 @@ class Try { if (!hasException()) { return false; } - return e_.with_exception(std::move(func)); + return e_.with_exception(std::move(func)); } template + bool withException(F func) const { + if (!hasException()) { + return false; + } + return e_.with_exception(std::move(func)); + } + + /* + * If the Try contains an exception and it is of type compatible with Ex as + * deduced from the first parameter of func, execute func(Ex) + * + * @param func a function that takes a single parameter of type const Ex& + * + * @returns True if the Try held an Ex and func was executed, false otherwise + */ + template + bool withException(F func) { + if (!hasException()) { + return false; + } + return e_.with_exception(std::move(func)); + } + template bool withException(F func) const { if (!hasException()) { return false; @@ -280,15 +375,8 @@ class Try { * @param ep The exception_pointer. Will be rethrown. */ FOLLY_DEPRECATED("use Try(exception_wrapper)") - explicit Try(std::exception_ptr ep) : hasValue_(false) { - try { - std::rethrow_exception(ep); - } catch (const std::exception& e) { - e_ = exception_wrapper(std::current_exception(), e); - } catch (...) { - e_ = exception_wrapper(std::current_exception()); - } - } + explicit Try(std::exception_ptr ep) + : hasValue_(false), e_(exception_wrapper::from_exception_ptr(ep)) {} // Copy assigner Try& operator=(const Try& t) { @@ -325,20 +413,59 @@ class Try { * * @returns mutable reference to the exception contained by this Try */ - exception_wrapper& exception() { - if (UNLIKELY(!hasException())) { - throw TryException("exception(): Try does not contain an exception"); + exception_wrapper& exception() & { + if (!hasException()) { + try_detail::throwTryDoesNotContainException(); } return e_; } - const exception_wrapper& exception() const { - if (UNLIKELY(!hasException())) { - throw TryException("exception(): Try does not contain an exception"); + exception_wrapper&& exception() && { + if (!hasException()) { + try_detail::throwTryDoesNotContainException(); + } + return std::move(e_); + } + + const exception_wrapper& exception() const & { + if (!hasException()) { + try_detail::throwTryDoesNotContainException(); } return e_; } + const exception_wrapper&& exception() const && { + if (!hasException()) { + try_detail::throwTryDoesNotContainException(); + } + return std::move(e_); + } + + /* + * @returns a pointer to the `std::exception` held by `*this`, if one is held; + * otherwise, returns `nullptr`. + */ + std::exception* tryGetExceptionObject() { + return hasException() ? e_.get_exception() : nullptr; + } + std::exception const* tryGetExceptionObject() const { + return hasException() ? e_.get_exception() : nullptr; + } + + /* + * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose + * type `From` permits `std::is_convertible`; otherwise, + * returns `nullptr`. + */ + template + E* tryGetExceptionObject() { + return hasException() ? e_.get_exception() : nullptr; + } + template + E const* tryGetExceptionObject() const { + return hasException() ? e_.get_exception() : nullptr; + } + /* * If the Try contains an exception and it is of type Ex, execute func(Ex) * @@ -351,9 +478,32 @@ class Try { if (!hasException()) { return false; } - return e_.with_exception(std::move(func)); + return e_.with_exception(std::move(func)); } template + bool withException(F func) const { + if (!hasException()) { + return false; + } + return e_.with_exception(std::move(func)); + } + + /* + * If the Try contains an exception and it is of type compatible with Ex as + * deduced from the first parameter of func, execute func(Ex) + * + * @param func a function that takes a single parameter of type const Ex& + * + * @returns True if the Try held an Ex and func was executed, false otherwise + */ + template + bool withException(F func) { + if (!hasException()) { + return false; + } + return e_.with_exception(std::move(func)); + } + template bool withException(F func) const { if (!hasException()) { return false; @@ -371,23 +521,6 @@ class Try { exception_wrapper e_; }; -/* - * Extracts value from try and returns it. Throws if try contained an exception. - * - * @param t Try to extract value from - * - * @returns value contained in t - */ -template -T moveFromTry(Try& t); - -/* - * Throws if try contained an exception. - * - * @param t Try to move from - */ -void moveFromTry(Try& t); - /* * @param f a function to execute and capture the result of (value or exception) * @@ -412,9 +545,15 @@ typename std::enable_if< Try>::type makeTryWith(F&& f); -template -std::tuple unwrapTryTuple(std::tuple...>&& ts); +/** + * Tuple...> -> std::tuple + * + * Unwraps a tuple-like type containing a sequence of Try instances to + * std::tuple + */ +template +auto unwrapTryTuple(Tuple&&); -} // folly +} // namespace folly #include