Merge pull request #5158 from sfc-gh-tclinkenbeard/use-variant-for-erroror

Use std::variant for ErrorOr implementation
This commit is contained in:
Markus Pilman 2021-07-12 15:35:19 -06:00 committed by GitHub
commit ba5c2b647c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 69 deletions

View File

@ -237,12 +237,12 @@ public:
}
template <class R>
Optional<R> map(std::function<R(T)> f) const {
if (present()) {
return Optional<R>(f(get()));
} else {
return Optional<R>();
}
Optional<R> map(std::function<R(T)> f) const& {
return present() ? Optional<R>(f(get())) : Optional<R>();
}
template <class R>
Optional<R> map(std::function<R(T)> f) && {
return present() ? Optional<R>(f(std::move(*this).get())) : Optional<R>();
}
bool present() const { return impl.has_value(); }
@ -258,7 +258,14 @@ public:
UNSTOPPABLE_ASSERT(impl.has_value());
return std::move(impl.value());
}
T orDefault(T const& default_value) const { return impl.value_or(default_value); }
template <class U>
T orDefault(U&& defaultValue) const& {
return impl.value_or(std::forward<U>(defaultValue));
}
template <class U>
T orDefault(U&& defaultValue) && {
return std::move(impl).value_or(std::forward<U>(defaultValue));
}
// Spaceship operator. Treats not-present as less-than present.
int compare(Optional const& rhs) const {

View File

@ -133,22 +133,21 @@ class Never {};
template <class T>
class ErrorOr : public ComposedIdentifier<T, 2> {
std::variant<Error, T> value;
public:
ErrorOr() : ErrorOr(default_error_or()) {}
ErrorOr(Error const& error) : error(error) { memset(&value, 0, sizeof(value)); }
ErrorOr(const ErrorOr<T>& o) : error(o.error) {
if (present())
new (&value) T(o.get());
}
ErrorOr(Error const& error) : value(std::in_place_type<Error>, error) {}
template <class U>
ErrorOr(const U& t) : error() {
new (&value) T(t);
}
ErrorOr(U const& t) : value(std::in_place_type<T>, t) {}
ErrorOr(Arena& a, const ErrorOr<T>& o) : error(o.error) {
if (present())
new (&value) T(a, o.get());
ErrorOr(Arena& a, ErrorOr<T> const& o) {
if (o.present()) {
value = std::variant<Error, T>(std::in_place_type<T>, a, o.get());
} else {
value = std::variant<Error, T>(std::in_place_type<Error>, o.getError());
}
}
int expectedSize() const { return present() ? get().expectedSize() : 0; }
@ -158,69 +157,67 @@ public:
}
template <class R>
ErrorOr<R> map(std::function<R(T)> f) const {
if (present()) {
return ErrorOr<R>(f(get()));
} else {
return ErrorOr<R>(error);
}
ErrorOr<R> map(std::function<R(T)> f) const& {
return present() ? ErrorOr<R>(f(get())) : ErrorOr<R>(getError());
}
template <class R>
ErrorOr<R> map(std::function<R(T)> f) && {
return present() ? ErrorOr<R>(f(std::move(*this).get())) : ErrorOr<R>(getError());
}
~ErrorOr() {
if (present())
((T*)&value)->~T();
}
ErrorOr& operator=(ErrorOr const& o) {
if (present()) {
((T*)&value)->~T();
}
if (o.present()) {
new (&value) T(o.get());
}
error = o.error;
return *this;
}
bool present() const { return error.code() == invalid_error_code; }
T& get() {
bool present() const { return std::holds_alternative<T>(value); }
T& get() & {
UNSTOPPABLE_ASSERT(present());
return *(T*)&value;
return std::get<T>(value);
}
T const& get() const {
T const& get() const& {
UNSTOPPABLE_ASSERT(present());
return *(T const*)&value;
return std::get<T>(value);
}
T orDefault(T const& default_value) const {
if (present())
return get();
else
return default_value;
T&& get() && {
UNSTOPPABLE_ASSERT(present());
return std::get<T>(std::move(value));
}
template <class U>
T orDefault(U&& defaultValue) const& {
return present() ? get() : std::forward<U>(defaultValue);
}
template <class U>
T orDefault(U&& defaultValue) && {
return present() ? std::move(*this).get() : std::forward<U>(defaultValue);
}
template <class Ar>
void serialize(Ar& ar) {
// SOMEDAY: specialize for space efficiency?
serializer(ar, error);
if (present()) {
if (Ar::isDeserializing)
new (&value) T();
serializer(ar, *(T*)&value);
}
}
bool isError() const { return error.code() != invalid_error_code; }
bool isError(int code) const { return error.code() == code; }
const Error& getError() const {
bool isError() const { return std::holds_alternative<Error>(value); }
bool isError(int code) const { return isError() && getError().code() == code; }
Error const& getError() const {
ASSERT(isError());
return error;
return std::get<Error>(value);
}
private:
typename std::aligned_storage<sizeof(T), __alignof(T)>::type value;
Error error;
};
template <class Archive, class T>
void load(Archive& ar, ErrorOr<T>& value) {
Error error;
ar >> error;
if (error.code() != invalid_error_code) {
T t;
ar >> t;
value = ErrorOr<T>(t);
} else {
value = ErrorOr<T>(error);
}
}
template <class Archive, class T>
void save(Archive& ar, ErrorOr<T> const& value) {
if (value.present()) {
ar << Error{}; // invalid error code
ar << value.get();
} else {
ar << value.getError();
}
}
template <class T>
struct union_like_traits<ErrorOr<T>> : std::true_type {
using Member = ErrorOr<T>;