diff --git a/flow/Arena.h b/flow/Arena.h index 2e1cc36801..d752baedf0 100644 --- a/flow/Arena.h +++ b/flow/Arena.h @@ -237,12 +237,12 @@ public: } template - Optional map(std::function f) const { - if (present()) { - return Optional(f(get())); - } else { - return Optional(); - } + Optional map(std::function f) const& { + return present() ? Optional(f(get())) : Optional(); + } + template + Optional map(std::function f) && { + return present() ? Optional(f(std::move(*this).get())) : Optional(); } 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 + T orDefault(U&& defaultValue) const& { + return impl.value_or(std::forward(defaultValue)); + } + template + T orDefault(U&& defaultValue) && { + return std::move(impl).value_or(std::forward(defaultValue)); + } // Spaceship operator. Treats not-present as less-than present. int compare(Optional const& rhs) const { diff --git a/flow/flow.h b/flow/flow.h index 6c5f380b52..b598f82987 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -133,22 +133,21 @@ class Never {}; template class ErrorOr : public ComposedIdentifier { + std::variant value; + public: ErrorOr() : ErrorOr(default_error_or()) {} - ErrorOr(Error const& error) : error(error) { memset(&value, 0, sizeof(value)); } - ErrorOr(const ErrorOr& o) : error(o.error) { - if (present()) - new (&value) T(o.get()); - } + ErrorOr(Error const& error) : value(std::in_place_type, error) {} template - ErrorOr(const U& t) : error() { - new (&value) T(t); - } + ErrorOr(U const& t) : value(std::in_place_type, t) {} - ErrorOr(Arena& a, const ErrorOr& o) : error(o.error) { - if (present()) - new (&value) T(a, o.get()); + ErrorOr(Arena& a, ErrorOr const& o) { + if (o.present()) { + value = std::variant(std::in_place_type, a, o.get()); + } else { + value = std::variant(std::in_place_type, o.getError()); + } } int expectedSize() const { return present() ? get().expectedSize() : 0; } @@ -158,69 +157,67 @@ public: } template - ErrorOr map(std::function f) const { - if (present()) { - return ErrorOr(f(get())); - } else { - return ErrorOr(error); - } + ErrorOr map(std::function f) const& { + return present() ? ErrorOr(f(get())) : ErrorOr(getError()); + } + template + ErrorOr map(std::function f) && { + return present() ? ErrorOr(f(std::move(*this).get())) : ErrorOr(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(value); } + T& get() & { UNSTOPPABLE_ASSERT(present()); - return *(T*)&value; + return std::get(value); } - T const& get() const { + T const& get() const& { UNSTOPPABLE_ASSERT(present()); - return *(T const*)&value; + return std::get(value); } - T orDefault(T const& default_value) const { - if (present()) - return get(); - else - return default_value; + T&& get() && { + UNSTOPPABLE_ASSERT(present()); + return std::get(std::move(value)); + } + template + T orDefault(U&& defaultValue) const& { + return present() ? get() : std::forward(defaultValue); + } + template + T orDefault(U&& defaultValue) && { + return present() ? std::move(*this).get() : std::forward(defaultValue); } - template - 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(value); } + bool isError(int code) const { return isError() && getError().code() == code; } + Error const& getError() const { ASSERT(isError()); - return error; + return std::get(value); } - -private: - typename std::aligned_storage::type value; - Error error; }; +template +void load(Archive& ar, ErrorOr& value) { + Error error; + ar >> error; + if (error.code() != invalid_error_code) { + T t; + ar >> t; + value = ErrorOr(t); + } else { + value = ErrorOr(error); + } +} + +template +void save(Archive& ar, ErrorOr const& value) { + if (value.present()) { + ar << Error{}; // invalid error code + ar << value.get(); + } else { + ar << value.getError(); + } +} + template struct union_like_traits> : std::true_type { using Member = ErrorOr;