X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FTry.h;h=d145806a058cbd0387451e4c68593e40d19f469c;hb=HEAD;hp=e6b6ebad3298450c5f4fa6f001fd751fd79c849b;hpb=347311500aa10d0524ac6db3987a94216e6d76ef;p=folly.git diff --git a/folly/Try.h b/folly/Try.h index e6b6ebad..d145806a 100644 --- a/folly/Try.h +++ b/folly/Try.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2014-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,46 +13,36 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #pragma once -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include +#include namespace folly { -class TryException : public std::exception { +class FOLLY_EXPORT TryException : public std::logic_error { public: - explicit TryException(std::string message_arg) noexcept - : message(std::move(message_arg)) {} - - const char* what() const noexcept override { - return message.c_str(); - } - - bool operator==(const TryException& other) const noexcept { - return other.message == this->message; - } - - bool operator!=(const TryException& other) const noexcept { - return !(*this == other); - } - - protected: - std::string message; + using std::logic_error::logic_error; }; -class UsingUninitializedTry : public TryException { +class FOLLY_EXPORT UsingUninitializedTry : public TryException { public: - UsingUninitializedTry() noexcept : TryException("Using unitialized try") {} + 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 @@ -96,6 +86,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 */ @@ -108,8 +103,7 @@ class Try { * @param e The exception_wrapper */ explicit Try(exception_wrapper e) - : contains_(Contains::EXCEPTION), - e_(folly::make_unique(std::move(e))) {} + : contains_(Contains::EXCEPTION), e_(std::move(e)) {} /* * DEPRECATED @@ -119,15 +113,8 @@ class Try { */ FOLLY_DEPRECATED("use Try(exception_wrapper)") explicit Try(std::exception_ptr ep) - : contains_(Contains::EXCEPTION) { - try { - std::rethrow_exception(ep); - } catch (const std::exception& e) { - e_ = folly::make_unique(std::current_exception(), e); - } catch (...) { - e_ = folly::make_unique(std::current_exception()); - } - } + : contains_(Contains::EXCEPTION), + e_(exception_wrapper::from_exception_ptr(ep)) {} // Move constructor Try(Try&& t) noexcept; @@ -147,21 +134,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. @@ -174,13 +168,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 @@ -210,21 +226,60 @@ class Try { */ template bool hasException() const { - return hasException() && e_->is_compatible_with(); + 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_; + 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 *e_; + 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; } /* @@ -235,11 +290,41 @@ class Try { * @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; + } + 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; } - return e_->with_exception(std::move(func)); + return e_.with_exception(std::move(func)); } template @@ -256,7 +341,7 @@ class Try { Contains contains_; union { T value_; - std::unique_ptr e_; + exception_wrapper e_; }; }; @@ -280,9 +365,7 @@ class Try { * * @param e The exception_wrapper */ - explicit Try(exception_wrapper e) - : hasValue_(false), - e_(folly::make_unique(std::move(e))) {} + explicit Try(exception_wrapper e) : hasValue_(false), e_(std::move(e)) {} /* * DEPRECATED @@ -291,22 +374,13 @@ 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_ = folly::make_unique(std::current_exception(), e); - } catch (...) { - e_ = folly::make_unique(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) { hasValue_ = t.hasValue_; - if (t.e_) { - e_ = folly::make_unique(*t.e_); - } + e_ = t.e_; return *this; } // Copy constructor @@ -330,7 +404,7 @@ class Try { // @returns True if the Try contains an exception of type Ex, false otherwise template bool hasException() const { - return hasException() && e_->is_compatible_with(); + return hasException() && e_.is_compatible_with(); } /* @@ -338,18 +412,57 @@ 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_; + 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 *e_; + 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; } /* @@ -360,11 +473,41 @@ class Try { * @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; + } + 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; } - return e_->with_exception(std::move(func)); + return e_.with_exception(std::move(func)); } template @@ -374,26 +517,9 @@ class Try { private: bool hasValue_; - std::unique_ptr e_{nullptr}; + 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) * @@ -418,9 +544,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