/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// Details...
namespace expected_detail {
+#ifdef _MSC_VER
+// MSVC 2015 can't handle the StrictConjunction, so we have
+// to use std::conjunction instead.
+template <template <class...> class Trait, class... Ts>
+using StrictAllOf = std::conjunction<Trait<Ts>...>;
+#else
template <template <class...> class Trait, class... Ts>
using StrictAllOf = StrictConjunction<Trait<Ts>...>;
+#endif
template <class T>
using IsCopyable = StrictConjunction<
};
Which which_;
- template <class E = Error, class = decltype(E())>
- constexpr ExpectedStorage() noexcept(noexcept(E()))
- : error_(), which_(Which::eError) {}
+ template <class E = Error, class = decltype(E{})>
+ constexpr ExpectedStorage() noexcept(noexcept(E{}))
+ : error_{}, which_(Which::eError) {}
explicit constexpr ExpectedStorage(EmptyTag) noexcept
- : ch_(), which_(Which::eEmpty) {}
+ : ch_{}, which_(Which::eEmpty) {}
template <class... Vs>
explicit constexpr ExpectedStorage(ValueTag, Vs&&... vs) noexcept(
noexcept(Value(static_cast<Vs&&>(vs)...)))
union {
Value value_;
Error error_;
- char ch_;
+ char ch_{};
};
- Which which_;
+ Which which_ = Which::eEmpty;
- explicit constexpr ExpectedUnion(EmptyTag = {}) noexcept
- : ch_(), which_(Which::eEmpty) {}
+ explicit constexpr ExpectedUnion(EmptyTag) noexcept {}
template <class... Vs>
explicit constexpr ExpectedUnion(ValueTag, Vs&&... vs) noexcept(
noexcept(Value(static_cast<Vs&&>(vs)...)))
template <class Derived, bool, bool Noexcept>
struct CopyConstructible {
- CopyConstructible() = default;
+ constexpr CopyConstructible() = default;
CopyConstructible(const CopyConstructible& that) noexcept(Noexcept) {
static_cast<Derived*>(this)->assign(static_cast<const Derived&>(that));
}
- CopyConstructible(CopyConstructible&&) = default;
+ constexpr CopyConstructible(CopyConstructible&&) = default;
CopyConstructible& operator=(const CopyConstructible&) = default;
CopyConstructible& operator=(CopyConstructible&&) = default;
};
template <class Derived, bool Noexcept>
struct CopyConstructible<Derived, false, Noexcept> {
- CopyConstructible() = default;
+ constexpr CopyConstructible() = default;
CopyConstructible(const CopyConstructible&) = delete;
- CopyConstructible(CopyConstructible&&) = default;
+ constexpr CopyConstructible(CopyConstructible&&) = default;
CopyConstructible& operator=(const CopyConstructible&) = default;
CopyConstructible& operator=(CopyConstructible&&) = default;
};
template <class Derived, bool, bool Noexcept>
struct MoveConstructible {
- MoveConstructible() = default;
- MoveConstructible(const MoveConstructible&) = default;
+ constexpr MoveConstructible() = default;
+ constexpr MoveConstructible(const MoveConstructible&) = default;
MoveConstructible(MoveConstructible&& that) noexcept(Noexcept) {
static_cast<Derived*>(this)->assign(std::move(static_cast<Derived&>(that)));
}
template <class Derived, bool Noexcept>
struct MoveConstructible<Derived, false, Noexcept> {
- MoveConstructible() = default;
- MoveConstructible(const MoveConstructible&) = default;
+ constexpr MoveConstructible() = default;
+ constexpr MoveConstructible(const MoveConstructible&) = default;
MoveConstructible(MoveConstructible&&) = delete;
MoveConstructible& operator=(const MoveConstructible&) = default;
MoveConstructible& operator=(MoveConstructible&&) = default;
template <class Derived, bool, bool Noexcept>
struct CopyAssignable {
- CopyAssignable() = default;
- CopyAssignable(const CopyAssignable&) = default;
- CopyAssignable(CopyAssignable&&) = default;
+ constexpr CopyAssignable() = default;
+ constexpr CopyAssignable(const CopyAssignable&) = default;
+ constexpr CopyAssignable(CopyAssignable&&) = default;
CopyAssignable& operator=(const CopyAssignable& that) noexcept(Noexcept) {
static_cast<Derived*>(this)->assign(static_cast<const Derived&>(that));
return *this;
template <class Derived, bool Noexcept>
struct CopyAssignable<Derived, false, Noexcept> {
- CopyAssignable() = default;
- CopyAssignable(const CopyAssignable&) = default;
- CopyAssignable(CopyAssignable&&) = default;
+ constexpr CopyAssignable() = default;
+ constexpr CopyAssignable(const CopyAssignable&) = default;
+ constexpr CopyAssignable(CopyAssignable&&) = default;
CopyAssignable& operator=(const CopyAssignable&) = delete;
CopyAssignable& operator=(CopyAssignable&&) = default;
};
template <class Derived, bool, bool Noexcept>
struct MoveAssignable {
- MoveAssignable() = default;
- MoveAssignable(const MoveAssignable&) = default;
- MoveAssignable(MoveAssignable&&) = default;
+ constexpr MoveAssignable() = default;
+ constexpr MoveAssignable(const MoveAssignable&) = default;
+ constexpr MoveAssignable(MoveAssignable&&) = default;
MoveAssignable& operator=(const MoveAssignable&) = default;
MoveAssignable& operator=(MoveAssignable&& that) noexcept(Noexcept) {
static_cast<Derived*>(this)->assign(std::move(static_cast<Derived&>(that)));
template <class Derived, bool Noexcept>
struct MoveAssignable<Derived, false, Noexcept> {
- MoveAssignable() = default;
- MoveAssignable(const MoveAssignable&) = default;
- MoveAssignable(MoveAssignable&&) = default;
+ constexpr MoveAssignable() = default;
+ constexpr MoveAssignable(const MoveAssignable&) = default;
+ constexpr MoveAssignable(MoveAssignable&&) = default;
MoveAssignable& operator=(const MoveAssignable&) = default;
MoveAssignable& operator=(MoveAssignable&& that) = delete;
};
using value_type = Value;
using error_type = Error;
using Base = ExpectedUnion<Value, Error>;
- template <class E = Error, class = decltype(E())>
- constexpr ExpectedStorage() noexcept(noexcept(E())) : Base{ErrorTag{}} {}
+ template <class E = Error, class = decltype(E{})>
+ constexpr ExpectedStorage() noexcept(noexcept(E{})) : Base{ErrorTag{}} {}
ExpectedStorage(const ExpectedStorage&) = default;
ExpectedStorage(ExpectedStorage&&) = default;
ExpectedStorage& operator=(const ExpectedStorage&) = default;
this->which_ = Which::eError;
}
}
- bool isThis(const ExpectedStorage* that) const {
+ bool isSelfAssign(const ExpectedStorage* that) const {
return this == that;
}
constexpr bool isSelfAssign(const void*) const {
Value value_;
constexpr ExpectedStorage() noexcept
- : which_(Which::eError), error_(), value_() {}
+ : which_(Which::eError), error_{}, value_{} {}
explicit constexpr ExpectedStorage(EmptyTag) noexcept
- : which_(Which::eEmpty), error_(), value_() {}
+ : which_(Which::eEmpty), error_{}, value_{} {}
template <class... Vs>
explicit constexpr ExpectedStorage(ValueTag, Vs&&... vs) noexcept(
noexcept(Value(static_cast<Vs&&>(vs)...)))
- : which_(Which::eValue), error_(), value_(static_cast<Vs&&>(vs)...) {}
+ : which_(Which::eValue), error_{}, value_(static_cast<Vs&&>(vs)...) {}
template <class... Es>
explicit constexpr ExpectedStorage(ErrorTag, Es&&... es) noexcept(
noexcept(Error(static_cast<Es&&>(es)...)))
- : which_(Which::eError), error_(static_cast<Es&&>(es)...), value_() {}
+ : which_(Which::eError), error_(static_cast<Es&&>(es)...), value_{} {}
void clear() noexcept {}
constexpr static bool uninitializedByException() noexcept {
return false;
return static_cast<This&&>(ex);
}
+ FOLLY_PUSH_WARNING
+ // Don't warn about not using the overloaded comma operator.
+ FOLLY_MSVC_DISABLE_WARNING(4913)
template <
class This,
class Fn,
throw typename Unexpected<ExpectedErrorType<This>>::MakeBadExpectedAccess()(
static_cast<This&&>(ex).error());
}
+ FOLLY_POP_WARNING
};
}
/* using override */ using expected_detail_ExpectedHelper::ExpectedHelper;
class BadExpectedAccess : public folly::BadExpectedAccess {
public:
explicit BadExpectedAccess(Error err)
- : folly::BadExpectedAccess(), error_(std::move(err)) {}
+ : folly::BadExpectedAccess{}, error_(std::move(err)) {}
/**
* The error code that was held by the Expected object when the user
* erroneously requested the value.
return std::move(error_);
}
- /**
- * Relational operators
- */
- FOLLY_REQUIRES(IsEqualityComparable<Error>::value)
- friend bool operator==(const Unexpected& lhs, const Unexpected& rhs) {
- return lhs.error() == rhs.error();
- }
- FOLLY_REQUIRES(IsEqualityComparable<Error>::value)
- friend bool operator!=(const Unexpected& lhs, const Unexpected& rhs) {
- return !(lhs == rhs);
- }
-
private:
struct MakeBadExpectedAccess {
template <class E>
Error error_;
};
+template <
+ class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable<Error>::value)>
+inline bool operator==(
+ const Unexpected<Error>& lhs,
+ const Unexpected<Error>& rhs) {
+ return lhs.error() == rhs.error();
+}
+
+template <
+ class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable<Error>::value)>
+inline bool operator!=(
+ const Unexpected<Error>& lhs,
+ const Unexpected<Error>& rhs) {
+ return !(lhs == rhs);
+}
+
/**
* For constructing an Unexpected object from an error code. Unexpected objects
* are implicitly convertible to Expected object in the error state. Usage is
* Constructors
*/
template <class B = Base, class = decltype(B{})>
- Expected() noexcept(noexcept(B{})) : Base() {}
+ Expected() noexcept(noexcept(B{})) : Base{} {}
Expected(const Expected& that) = default;
Expected(Expected&& that) = default;
/**
* Relational Operators
*/
- FOLLY_REQUIRES(IsEqualityComparable<Value>::value)
- friend bool operator==(const Expected& lhs, const Expected& rhs) {
- if (UNLIKELY(lhs.which_ != rhs.which_))
- return UNLIKELY(lhs.uninitializedByException())
- ? false
- : throw BadExpectedAccess();
- if (UNLIKELY(lhs.uninitializedByException()))
- throw BadExpectedAccess();
- if (UNLIKELY(lhs.hasError()))
- return true; // All error states are considered equal
- return lhs.value_ == rhs.value_;
- }
-
- FOLLY_REQUIRES(IsEqualityComparable<Value>::value)
- friend bool operator!=(const Expected& lhs, const Expected& rhs) {
- return !(lhs == rhs);
- }
-
- FOLLY_REQUIRES(IsLessThanComparable<Value>::value)
- friend bool operator<(const Expected& lhs, const Expected& rhs) {
- if (UNLIKELY(
- lhs.uninitializedByException() || rhs.uninitializedByException()))
- throw BadExpectedAccess();
- if (UNLIKELY(lhs.hasError()))
- return !rhs.hasError();
- if (UNLIKELY(rhs.hasError()))
- return false;
- return lhs.value_ < rhs.value_;
- }
-
- FOLLY_REQUIRES(IsLessThanComparable<Value>::value)
- friend bool operator<=(const Expected& lhs, const Expected& rhs) {
- return !(rhs < lhs);
- }
-
- FOLLY_REQUIRES(IsLessThanComparable<Value>::value)
- friend bool operator>(const Expected& lhs, const Expected& rhs) {
- return rhs < lhs;
- }
-
- FOLLY_REQUIRES(IsLessThanComparable<Value>::value)
- friend bool operator>=(const Expected& lhs, const Expected& rhs) {
- return !(lhs < rhs);
- }
+ template <class Val, class Err>
+ friend typename std::enable_if<IsEqualityComparable<Val>::value, bool>::type
+ operator==(const Expected<Val, Err>& lhs, const Expected<Val, Err>& rhs);
+ template <class Val, class Err>
+ friend typename std::enable_if<IsLessThanComparable<Val>::value, bool>::type
+ operator<(const Expected<Val, Err>& lhs, const Expected<Val, Err>& rhs);
/*
* Accessors
* thenOrThrow
*/
template <class Yes, class No = MakeBadExpectedAccess>
- auto thenOrThrow(Yes&& yes, No&& no = No()) const& -> decltype(
+ auto thenOrThrow(Yes&& yes, No&& no = No{}) const& -> decltype(
std::declval<Yes>()(std::declval<const Value&>())) {
using Ret = decltype(std::declval<Yes>()(std::declval<const Value&>()));
if (this->uninitializedByException())
}
template <class Yes, class No = MakeBadExpectedAccess>
- auto thenOrThrow(Yes&& yes, No&& no = No()) & -> decltype(
+ auto thenOrThrow(Yes&& yes, No&& no = No{}) & -> decltype(
std::declval<Yes>()(std::declval<Value&>())) {
using Ret = decltype(std::declval<Yes>()(std::declval<Value&>()));
if (this->uninitializedByException())
}
template <class Yes, class No = MakeBadExpectedAccess>
- auto thenOrThrow(Yes&& yes, No&& no = No()) && -> decltype(
+ auto thenOrThrow(Yes&& yes, No&& no = No{}) && -> decltype(
std::declval<Yes>()(std::declval<Value&&>())) {
using Ret = decltype(std::declval<Yes>()(std::declval<Value&&>()));
if (this->uninitializedByException())
}
};
+template <class Value, class Error>
+inline typename std::enable_if<IsEqualityComparable<Value>::value, bool>::type
+operator==(
+ const Expected<Value, Error>& lhs,
+ const Expected<Value, Error>& rhs) {
+ if (UNLIKELY(lhs.which_ != rhs.which_))
+ return UNLIKELY(lhs.uninitializedByException()) ? false
+ : throw BadExpectedAccess();
+ if (UNLIKELY(lhs.uninitializedByException()))
+ throw BadExpectedAccess();
+ if (UNLIKELY(lhs.hasError()))
+ return true; // All error states are considered equal
+ return lhs.value_ == rhs.value_;
+}
+
+template <
+ class Value,
+ class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable<Value>::value)>
+inline bool operator!=(
+ const Expected<Value, Error>& lhs,
+ const Expected<Value, Error>& rhs) {
+ return !(rhs == lhs);
+}
+
+template <class Value, class Error>
+inline typename std::enable_if<IsLessThanComparable<Value>::value, bool>::type
+operator<(
+ const Expected<Value, Error>& lhs,
+ const Expected<Value, Error>& rhs) {
+ if (UNLIKELY(
+ lhs.uninitializedByException() || rhs.uninitializedByException()))
+ throw BadExpectedAccess();
+ if (UNLIKELY(lhs.hasError()))
+ return !rhs.hasError();
+ if (UNLIKELY(rhs.hasError()))
+ return false;
+ return lhs.value_ < rhs.value_;
+}
+
+template <
+ class Value,
+ class Error FOLLY_REQUIRES_TRAILING(IsLessThanComparable<Value>::value)>
+inline bool operator<=(
+ const Expected<Value, Error>& lhs,
+ const Expected<Value, Error>& rhs) {
+ return !(rhs < lhs);
+}
+
+template <
+ class Value,
+ class Error FOLLY_REQUIRES_TRAILING(IsLessThanComparable<Value>::value)>
+inline bool operator>(
+ const Expected<Value, Error>& lhs,
+ const Expected<Value, Error>& rhs) {
+ return rhs < lhs;
+}
+
+template <
+ class Value,
+ class Error FOLLY_REQUIRES_TRAILING(IsLessThanComparable<Value>::value)>
+inline bool operator>=(
+ const Expected<Value, Error>& lhs,
+ const Expected<Value, Error>& rhs) {
+ return !(lhs < rhs);
+}
+
/**
* swap Expected values
*/