#pragma once
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <new>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <folly/CPortability.h>
#include <folly/CppAttributes.h>
#include <folly/Likely.h>
#include <folly/Portability.h>
#include <folly/Preprocessor.h>
#include <folly/Traits.h>
#include <folly/Unit.h>
#include <folly/Utility.h>
#include <folly/lang/Exception.h>
#include <folly/lang/Hint.h>
#define FOLLY_EXPECTED_ID(X) …
#define FOLLY_REQUIRES_IMPL(...) …
#define FOLLY_REQUIRES_TRAILING …
#define FOLLY_REQUIRES …
namespace folly {
namespace expected_detail {
namespace expected_detail_ExpectedHelper {
struct ExpectedHelper;
}
ExpectedHelper;
}
template <class Error>
class FOLLY_NODISCARD Unexpected final { … };
template <
class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable<Error>::value)>
inline bool operator==(
const Unexpected<Error>& lhs, const Unexpected<Error>& rhs) { … }
template <
class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable<Error>::value)>
inline bool operator!=(
const Unexpected<Error>& lhs, const Unexpected<Error>& rhs) { … }
template <class Error>
constexpr Unexpected<typename std::decay<Error>::type> makeUnexpected(
Error&& err) { … }
template <class Error>
class FOLLY_EXPORT BadExpectedAccess;
template <>
class FOLLY_EXPORT BadExpectedAccess<void> : public std::exception { … };
template <class Error>
class FOLLY_EXPORT BadExpectedAccess : public BadExpectedAccess<void> { … };
template <class Value, class Error>
class Expected;
template <class Error, class Value>
FOLLY_NODISCARD constexpr Expected<typename std::decay<Value>::type, Error>
makeExpected(Value&&);
ExpectedValueType;
ExpectedErrorType;
namespace expected_detail {
template <typename Value, typename Error>
struct Promise;
template <typename Value, typename Error>
struct PromiseReturn;
StrictAllOf;
IsCopyable;
IsMovable;
IsNothrowCopyable;
IsNothrowMovable;
IsConvertible;
template <class T, class U>
auto doEmplaceAssign(int, T& t, U&& u)
-> decltype(void(t = static_cast<U&&>(u))) { … }
template <class T, class U>
auto doEmplaceAssign(long, T& t, U&& u)
-> decltype(void(T(static_cast<U&&>(u)))) { … }
template <class T, class... Us>
auto doEmplaceAssign(int, T& t, Us&&... us)
-> decltype(void(t = T(static_cast<Us&&>(us)...))) { … }
template <class T, class... Us>
auto doEmplaceAssign(long, T& t, Us&&... us)
-> decltype(void(T(static_cast<Us&&>(us)...))) { … }
struct EmptyTag { … };
struct ValueTag { … };
struct ErrorTag { … };
enum class Which : unsigned char { … };
enum class StorageType { … };
template <class Value, class Error>
constexpr StorageType getStorageType() { … }
template <
class Value,
class Error,
StorageType = expected_detail::getStorageType<Value, Error>()>
struct ExpectedStorage { … };
template <class Value, class Error>
struct ExpectedUnion { … };
template <class Derived, bool, bool Noexcept>
struct CopyConstructible { … };
CopyConstructible<Derived, false, Noexcept>;
template <class Derived, bool, bool Noexcept>
struct MoveConstructible { … };
MoveConstructible<Derived, false, Noexcept>;
template <class Derived, bool, bool Noexcept>
struct CopyAssignable { … };
CopyAssignable<Derived, false, Noexcept>;
template <class Derived, bool, bool Noexcept>
struct MoveAssignable { … };
MoveAssignable<Derived, false, Noexcept>;
ExpectedStorage<Value, Error, StorageType::eUnion>;
ExpectedStorage<Value, Error, StorageType::ePODStruct>;
namespace expected_detail_ExpectedHelper {
template <class T>
inline T&& operator,(T&& t, Unit) noexcept { … }
struct ExpectedHelper { … };
}
struct UnexpectedTag { … };
}
unexpected_t;
inline expected_detail::UnexpectedTag unexpected(
expected_detail::UnexpectedTag = { … }
namespace expected_detail {
}
template <class Value, class Error>
class Expected final : expected_detail::ExpectedStorage<Value, Error> { … };
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) { … }
template <
class Value,
class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable<Value>::value)>
inline bool operator!=(
const Expected<Value, Error>& lhs, const Expected<Value, Error>& rhs) { … }
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) { … }
template <
class Value,
class Error FOLLY_REQUIRES_TRAILING(IsLessThanComparable<Value>::value)>
inline bool operator<=(
const Expected<Value, Error>& lhs, const Expected<Value, Error>& rhs) { … }
template <
class Value,
class Error FOLLY_REQUIRES_TRAILING(IsLessThanComparable<Value>::value)>
inline bool operator>(
const Expected<Value, Error>& lhs, const Expected<Value, Error>& rhs) { … }
template <
class Value,
class Error FOLLY_REQUIRES_TRAILING(IsLessThanComparable<Value>::value)>
inline bool operator>=(
const Expected<Value, Error>& lhs, const Expected<Value, Error>& rhs) { … }
template <class Value, class Error>
void swap(Expected<Value, Error>& lhs, Expected<Value, Error>& rhs) noexcept(
std::is_nothrow_swappable_v<Value> && std::is_nothrow_swappable_v<Error>) { … }
template <class Value, class Error>
const Value* get_pointer(const Expected<Value, Error>& ex) noexcept { … }
template <class Value, class Error>
Value* get_pointer(Expected<Value, Error>& ex) noexcept { … }
template <class Error, class Value>
FOLLY_NODISCARD constexpr Expected<typename std::decay<Value>::type, Error>
makeExpected(Value&& val) { … }
template <class Value, class Error>
bool operator==(const Expected<Value, Error>&, const Value& other) = delete;
template <class Value, class Error>
bool operator!=(const Expected<Value, Error>&, const Value& other) = delete;
template <class Value, class Error>
bool operator<(const Expected<Value, Error>&, const Value& other) = delete;
template <class Value, class Error>
bool operator<=(const Expected<Value, Error>&, const Value& other) = delete;
template <class Value, class Error>
bool operator>=(const Expected<Value, Error>&, const Value& other) = delete;
template <class Value, class Error>
bool operator>(const Expected<Value, Error>&, const Value& other) = delete;
template <class Value, class Error>
bool operator==(const Value& other, const Expected<Value, Error>&) = delete;
template <class Value, class Error>
bool operator!=(const Value& other, const Expected<Value, Error>&) = delete;
template <class Value, class Error>
bool operator<(const Value& other, const Expected<Value, Error>&) = delete;
template <class Value, class Error>
bool operator<=(const Value& other, const Expected<Value, Error>&) = delete;
template <class Value, class Error>
bool operator>=(const Value& other, const Expected<Value, Error>&) = delete;
template <class Value, class Error>
bool operator>(const Value& other, const Expected<Value, Error>&) = delete;
}
#undef FOLLY_REQUIRES
#undef FOLLY_REQUIRES_TRAILING
#if FOLLY_HAS_COROUTINES
#include <folly/experimental/coro/Coroutine.h>
namespace folly {
namespace expected_detail {
template <typename Value, typename Error>
struct PromiseBase;
template <typename Value, typename Error>
struct PromiseReturn {
Expected<Value, Error> storage_{EmptyTag{}};
Expected<Value, Error>*& pointer_;
PromiseReturn(PromiseBase<Value, Error>& p) noexcept
: pointer_{p.value_} {
pointer_ = &storage_;
}
PromiseReturn(PromiseReturn const&) = delete;
~PromiseReturn() {}
operator Expected<Value, Error>() {
if (folly::coro::detect_promise_return_object_eager_conversion()) {
assert(storage_.which_ == expected_detail::Which::eEmpty);
return Expected<Value, Error>{EmptyTag{}, pointer_};
} else {
assert(storage_.which_ != expected_detail::Which::eEmpty);
return std::move(storage_);
}
}
};
template <typename Value, typename Error>
struct PromiseBase {
Expected<Value, Error>* value_ = nullptr;
PromiseBase() = default;
PromiseBase(PromiseBase const&) = delete;
void operator=(PromiseBase const&) = delete;
[[nodiscard]] coro::suspend_never initial_suspend() const noexcept {
return {};
}
[[nodiscard]] coro::suspend_never final_suspend() const noexcept {
return {};
}
[[noreturn]] void unhandled_exception() {
rethrow_current_exception();
}
PromiseReturn<Value, Error> get_return_object() noexcept { return *this; }
};
template <typename Value>
inline constexpr bool ReturnsVoid =
std::is_trivial_v<Value> && std::is_empty_v<Value>;
template <typename Value, typename Error>
struct PromiseReturnsValue : public PromiseBase<Value, Error> {
template <typename U = Value>
void return_value(U&& u) {
auto& v = *this->value_;
ExpectedHelper::assume_empty(v);
v = static_cast<U&&>(u);
}
};
template <typename Value, typename Error>
struct PromiseReturnsVoid : public PromiseBase<Value, Error> {
void return_void() { this->value_->emplace(Value{}); }
};
template <typename Value, typename Error>
struct Promise
: conditional_t<
ReturnsVoid<Value>,
PromiseReturnsVoid<Value, Error>,
PromiseReturnsValue<Value, Error>> {};
template <typename Error>
struct UnexpectedAwaitable {
Unexpected<Error> o_;
explicit UnexpectedAwaitable(Unexpected<Error> o) : o_(std::move(o)) {}
constexpr std::false_type await_ready() const noexcept { return {}; }
void await_resume() { compiler_may_unsafely_assume_unreachable(); }
template <typename U>
FOLLY_ALWAYS_INLINE void await_suspend(
coro::coroutine_handle<Promise<U, Error>> h) {
auto& v = *h.promise().value_;
ExpectedHelper::assume_empty(v);
v = std::move(o_);
h.destroy();
}
};
template <typename Value, typename Error>
struct ExpectedAwaitable {
Expected<Value, Error> o_;
explicit ExpectedAwaitable(Expected<Value, Error> o) : o_(std::move(o)) {}
bool await_ready() const noexcept { return o_.hasValue(); }
Value await_resume() { return std::move(o_.value()); }
template <typename U>
FOLLY_ALWAYS_INLINE void await_suspend(
coro::coroutine_handle<Promise<U, Error>> h) {
auto& v = *h.promise().value_;
ExpectedHelper::assume_empty(v);
v = makeUnexpected(std::move(o_.error()));
h.destroy();
}
};
}
template <typename Error>
expected_detail::UnexpectedAwaitable<Error>
operator co_await(Unexpected<Error> o) {
return expected_detail::UnexpectedAwaitable<Error>{std::move(o)};
}
template <typename Value, typename Error>
expected_detail::ExpectedAwaitable<Value, Error>
operator co_await(Expected<Value, Error> o) {
return expected_detail::ExpectedAwaitable<Value, Error>{std::move(o)};
}
}
#endif