Commit 8d89ba5c authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

revise BadExpectedAccess following P0323R11

Summary:
* `BadExpectedAccess<void>` inherits `std::exception` and `BadExpectedAccess<E>` inherits `BadExpectedAccess<void>`.
* Copy-constructor, copy-assignment-operator.
* Member `error` returns a reference.

Paper: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r11.html.

Reviewed By: Gownta

Differential Revision: D33907293

fbshipit-source-id: 5002dfa548840431f957540bec23d95f34c9a68d
parent ee89ab55
...@@ -54,14 +54,6 @@ ...@@ -54,14 +54,6 @@
namespace folly { namespace folly {
/**
* An exception type thrown by Expected on catastrophic logic errors.
*/
class FOLLY_EXPORT BadExpectedAccess : public std::logic_error {
public:
BadExpectedAccess() : std::logic_error("bad Expected access") {}
};
namespace expected_detail { namespace expected_detail {
namespace expected_detail_ExpectedHelper { namespace expected_detail_ExpectedHelper {
struct ExpectedHelper; struct ExpectedHelper;
...@@ -82,25 +74,6 @@ class Unexpected final { ...@@ -82,25 +74,6 @@ class Unexpected final {
friend struct expected_detail::ExpectedHelper; friend struct expected_detail::ExpectedHelper;
public: public:
/**
* Unexpected::BadExpectedAccess - An exception type thrown by Expected
* when the user tries to access the nested value but the Expected object is
* actually storing an error code.
*/
class FOLLY_EXPORT BadExpectedAccess : public folly::BadExpectedAccess {
public:
explicit BadExpectedAccess(Error err)
: folly::BadExpectedAccess{}, error_(std::move(err)) {}
/**
* The error code that was held by the Expected object when the user
* erroneously requested the value.
*/
Error error() const { return error_; }
private:
Error error_;
};
/** /**
* Constructors * Constructors
*/ */
...@@ -136,13 +109,6 @@ class Unexpected final { ...@@ -136,13 +109,6 @@ class Unexpected final {
Error&& error() && { return std::move(error_); } Error&& error() && { return std::move(error_); }
private: private:
struct MakeBadExpectedAccess {
template <class E>
BadExpectedAccess operator()(E&& err) const {
return BadExpectedAccess(static_cast<E&&>(err));
}
};
Error error_; Error error_;
}; };
...@@ -179,6 +145,47 @@ constexpr Unexpected<typename std::decay<Error>::type> makeUnexpected( ...@@ -179,6 +145,47 @@ constexpr Unexpected<typename std::decay<Error>::type> makeUnexpected(
static_cast<Error&&>(err)}; static_cast<Error&&>(err)};
} }
template <class Error>
class FOLLY_EXPORT BadExpectedAccess;
/**
* A common base type for exceptions thrown by Expected when the caller
* erroneously requests a value.
*/
template <>
class FOLLY_EXPORT BadExpectedAccess<void> : public std::exception {
public:
explicit BadExpectedAccess() noexcept = default;
BadExpectedAccess(BadExpectedAccess const&) {}
BadExpectedAccess& operator=(BadExpectedAccess const&) { return *this; }
char const* what() const noexcept override { return "bad expected access"; }
};
/**
* An exception type thrown by Expected on catastrophic logic errors, i.e., when
* the caller tries to access the value within an Expected but when the Expected
* instead contains an error.
*/
template <class Error>
class FOLLY_EXPORT BadExpectedAccess : public BadExpectedAccess<void> {
public:
explicit BadExpectedAccess(Error error)
: error_{static_cast<Error&&>(error)} {}
/**
* The error code that was held by the Expected object when the caller
* erroneously requested the value.
*/
Error& error() & { return error_; }
Error const& error() const& { return error_; }
Error&& error() && { return static_cast<Error&&>(error_); }
Error const&& error() const&& { return static_cast<Error const&&>(error_); }
private:
Error error_;
};
/** /**
* Forward declarations * Forward declarations
*/ */
...@@ -687,8 +694,8 @@ struct ExpectedHelper { ...@@ -687,8 +694,8 @@ struct ExpectedHelper {
return Ret(static_cast<Yes&&>(yes)(static_cast<This&&>(ex).value())); return Ret(static_cast<Yes&&>(yes)(static_cast<This&&>(ex).value()));
} }
static_cast<No&&>(no)(ex.error()); static_cast<No&&>(no)(ex.error());
typename Unexpected<ExpectedErrorType<This>>::MakeBadExpectedAccess bad; throw_exception<BadExpectedAccess<ExpectedErrorType<This>>>(
throw_exception(bad(static_cast<This&&>(ex).error())); static_cast<This&&>(ex).error());
} }
FOLLY_POP_WARNING FOLLY_POP_WARNING
}; };
...@@ -812,12 +819,17 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -812,12 +819,17 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
friend struct expected_detail::ExpectedStorage; friend struct expected_detail::ExpectedStorage;
friend struct expected_detail::ExpectedHelper; friend struct expected_detail::ExpectedHelper;
using Base = expected_detail::ExpectedStorage<Value, Error>; using Base = expected_detail::ExpectedStorage<Value, Error>;
using MakeBadExpectedAccess =
typename Unexpected<Error>::MakeBadExpectedAccess;
Base& base() & { return *this; } Base& base() & { return *this; }
const Base& base() const& { return *this; } const Base& base() const& { return *this; }
Base&& base() && { return std::move(*this); } Base&& base() && { return std::move(*this); }
struct MakeBadExpectedAccess {
template <class E>
auto operator()(E&& e) {
return BadExpectedAccess<Error>(static_cast<E&&>(e));
}
};
public: public:
using value_type = Value; using value_type = Value;
using error_type = Error; using error_type = Error;
...@@ -982,7 +994,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -982,7 +994,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
void swap(Expected& that) noexcept( void swap(Expected& that) noexcept(
expected_detail::StrictAllOf<IsNothrowSwappable, Value, Error>::value) { expected_detail::StrictAllOf<IsNothrowSwappable, Value, Error>::value) {
if (this->uninitializedByException() || that.uninitializedByException()) { if (this->uninitializedByException() || that.uninitializedByException()) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
using std::swap; using std::swap;
if (*this) { if (*this) {
...@@ -1109,7 +1121,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1109,7 +1121,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
const& -> decltype(expected_detail::ExpectedHelper::then_( const& -> decltype(expected_detail::ExpectedHelper::then_(
std::declval<const Base&>(), std::declval<Fns>()...)) { std::declval<const Base&>(), std::declval<Fns>()...)) {
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
return expected_detail::ExpectedHelper::then_( return expected_detail::ExpectedHelper::then_(
base(), static_cast<Fns&&>(fns)...); base(), static_cast<Fns&&>(fns)...);
...@@ -1119,7 +1131,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1119,7 +1131,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
auto then(Fns&&... fns) & -> decltype(expected_detail::ExpectedHelper::then_( auto then(Fns&&... fns) & -> decltype(expected_detail::ExpectedHelper::then_(
std::declval<Base&>(), std::declval<Fns>()...)) { std::declval<Base&>(), std::declval<Fns>()...)) {
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
return expected_detail::ExpectedHelper::then_( return expected_detail::ExpectedHelper::then_(
base(), static_cast<Fns&&>(fns)...); base(), static_cast<Fns&&>(fns)...);
...@@ -1129,7 +1141,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1129,7 +1141,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
auto then(Fns&&... fns) && -> decltype(expected_detail::ExpectedHelper::then_( auto then(Fns&&... fns) && -> decltype(expected_detail::ExpectedHelper::then_(
std::declval<Base&&>(), std::declval<Fns>()...)) { std::declval<Base&&>(), std::declval<Fns>()...)) {
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
return expected_detail::ExpectedHelper::then_( return expected_detail::ExpectedHelper::then_(
std::move(base()), static_cast<Fns&&>(fns)...); std::move(base()), static_cast<Fns&&>(fns)...);
...@@ -1143,7 +1155,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1143,7 +1155,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
const& -> decltype(std::declval<Yes>()(std::declval<const Value&>())) { const& -> decltype(std::declval<Yes>()(std::declval<const Value&>())) {
using Ret = decltype(std::declval<Yes>()(std::declval<const Value&>())); using Ret = decltype(std::declval<Yes>()(std::declval<const Value&>()));
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
return Ret(expected_detail::ExpectedHelper::thenOrThrow_( return Ret(expected_detail::ExpectedHelper::thenOrThrow_(
base(), static_cast<Yes&&>(yes), static_cast<No&&>(no))); base(), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
...@@ -1154,7 +1166,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1154,7 +1166,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
std::declval<Value&>())) { std::declval<Value&>())) {
using Ret = decltype(std::declval<Yes>()(std::declval<Value&>())); using Ret = decltype(std::declval<Yes>()(std::declval<Value&>()));
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
return Ret(expected_detail::ExpectedHelper::thenOrThrow_( return Ret(expected_detail::ExpectedHelper::thenOrThrow_(
base(), static_cast<Yes&&>(yes), static_cast<No&&>(no))); base(), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
...@@ -1167,7 +1179,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1167,7 +1179,7 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
No{}) && -> decltype(std::declval<Yes>()(std::declval<Value&&>())) { No{}) && -> decltype(std::declval<Yes>()(std::declval<Value&&>())) {
using Ret = decltype(std::declval<Yes>()(std::declval<Value&&>())); using Ret = decltype(std::declval<Yes>()(std::declval<Value&&>()));
if (this->uninitializedByException()) { if (this->uninitializedByException()) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
return Ret(expected_detail::ExpectedHelper::thenOrThrow_( return Ret(expected_detail::ExpectedHelper::thenOrThrow_(
std::move(base()), static_cast<Yes&&>(yes), static_cast<No&&>(no))); std::move(base()), static_cast<Yes&&>(yes), static_cast<No&&>(no)));
...@@ -1177,16 +1189,15 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> { ...@@ -1177,16 +1189,15 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
void requireValue() const { void requireValue() const {
if (UNLIKELY(!hasValue())) { if (UNLIKELY(!hasValue())) {
if (LIKELY(hasError())) { if (LIKELY(hasError())) {
using Err = typename Unexpected<Error>::BadExpectedAccess; throw_exception<BadExpectedAccess<Error>>(this->error_);
throw_exception<Err>(this->error_);
} }
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
} }
void requireError() const { void requireError() const {
if (UNLIKELY(!hasError())) { if (UNLIKELY(!hasError())) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
} }
...@@ -1198,7 +1209,7 @@ inline typename std::enable_if<IsEqualityComparable<Value>::value, bool>::type ...@@ -1198,7 +1209,7 @@ inline typename std::enable_if<IsEqualityComparable<Value>::value, bool>::type
operator==( operator==(
const Expected<Value, Error>& lhs, const Expected<Value, Error>& rhs) { const Expected<Value, Error>& lhs, const Expected<Value, Error>& rhs) {
if (UNLIKELY(lhs.uninitializedByException())) { if (UNLIKELY(lhs.uninitializedByException())) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
if (UNLIKELY(lhs.which_ != rhs.which_)) { if (UNLIKELY(lhs.which_ != rhs.which_)) {
return false; return false;
...@@ -1223,7 +1234,7 @@ operator<( ...@@ -1223,7 +1234,7 @@ operator<(
const Expected<Value, Error>& lhs, const Expected<Value, Error>& rhs) { const Expected<Value, Error>& lhs, const Expected<Value, Error>& rhs) {
if (UNLIKELY( if (UNLIKELY(
lhs.uninitializedByException() || rhs.uninitializedByException())) { lhs.uninitializedByException() || rhs.uninitializedByException())) {
throw_exception<BadExpectedAccess>(); throw_exception<BadExpectedAccess<void>>();
} }
if (UNLIKELY(lhs.hasError())) { if (UNLIKELY(lhs.hasError())) {
return !rhs.hasError(); return !rhs.hasError();
......
...@@ -572,7 +572,7 @@ TEST(Expected, AssignmentContained) { ...@@ -572,7 +572,7 @@ TEST(Expected, AssignmentContained) {
TEST(Expected, Exceptions) { TEST(Expected, Exceptions) {
Expected<int, E> empty; Expected<int, E> empty;
EXPECT_THROW(empty.value(), Unexpected<E>::BadExpectedAccess); EXPECT_THROW(empty.value(), BadExpectedAccess<E>);
} }
struct ThrowingBadness { struct ThrowingBadness {
...@@ -763,7 +763,7 @@ TEST(Expected, ThenOrThrow) { ...@@ -763,7 +763,7 @@ TEST(Expected, ThenOrThrow) {
EXPECT_THROW( EXPECT_THROW(
(Expected<std::unique_ptr<int>, E>{unexpected, E::E1}.thenOrThrow( (Expected<std::unique_ptr<int>, E>{unexpected, E::E1}.thenOrThrow(
[](std::unique_ptr<int> p) { return *p; })), [](std::unique_ptr<int> p) { return *p; })),
Unexpected<E>::BadExpectedAccess); BadExpectedAccess<E>);
} }
{ {
...@@ -786,7 +786,7 @@ TEST(Expected, ThenOrThrow) { ...@@ -786,7 +786,7 @@ TEST(Expected, ThenOrThrow) {
EXPECT_THROW( EXPECT_THROW(
(Expected<std::unique_ptr<int>, E>{unexpected, E::E1}.thenOrThrow( (Expected<std::unique_ptr<int>, E>{unexpected, E::E1}.thenOrThrow(
[](std::unique_ptr<int> p) { return *p; }, [](E) {})), [](std::unique_ptr<int> p) { return *p; }, [](E) {})),
Unexpected<E>::BadExpectedAccess); BadExpectedAccess<E>);
} }
} }
......
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