From e65fe1b93684f9517599be695eb40aa4537fc6c7 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Sun, 5 Jan 2025 18:53:16 +0100 Subject: Add status_or --- asl/status_or.hpp | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 asl/status_or.hpp (limited to 'asl/status_or.hpp') diff --git a/asl/status_or.hpp b/asl/status_or.hpp new file mode 100644 index 0000000..04fcc4a --- /dev/null +++ b/asl/status_or.hpp @@ -0,0 +1,170 @@ +#pragma once + +#include "asl/status.hpp" +#include "asl/maybe_uninit.hpp" + +namespace asl +{ + +template +class status_or +{ + status m_status; + maybe_uninit m_value{}; + +public: + // @Todo Convert copy + // @Todo Convert move + + constexpr status_or(const status_or& other) + requires copy_constructible + : m_status{other.m_status} + { + if (other.ok()) + { + m_value.construct_unsafe(other.m_value.as_init_unsafe()); + } + } + + constexpr status_or(status_or&& other) + requires move_constructible + : m_status{ASL_MOVE(other.m_status)} + { + if (other.ok()) + { + m_value.construct_unsafe(ASL_MOVE(other.m_value.as_init_unsafe())); + } + } + + constexpr status_or& operator=(const status_or& other) + requires copyable + { + if (&other != this) + { + if (ok()) + { + if (other.ok()) + { + m_value.assign_unsafe(other.m_value.as_init_unsafe()); + } + else + { + m_value.destroy_unsafe(); + } + } + else if (other.ok()) + { + m_value.construct_unsafe(other.m_value.as_init_unsafe()); + } + m_status = other.m_status; + } + return *this; + } + + constexpr status_or& operator=(status_or&& other) + requires moveable + { + if (&other != this) + { + if (ok()) + { + if (other.ok()) + { + m_value.assign_unsafe(ASL_MOVE(other.m_value.as_init_unsafe())); + } + else + { + m_value.destroy_unsafe(); + } + } + else if (other.ok()) + { + m_value.construct_unsafe(ASL_MOVE(other.m_value.as_init_unsafe())); + } + m_status = ASL_MOVE(other.m_status); + } + return *this; + } + + constexpr ~status_or() + { + if (m_status.ok()) + { + m_value.destroy_unsafe(); + } + } + + // NOLINTNEXTLINE(*-explicit-conversions) + constexpr status_or(const status& status) : m_status{status} + { + ASL_ASSERT_RELEASE(!m_status.ok()); + } + + // NOLINTNEXTLINE(*-explicit-conversions) + constexpr status_or(status&& status) : m_status{ASL_MOVE(status)} + { + ASL_ASSERT_RELEASE(!m_status.ok()); + } + + status_or& operator=(status status) = delete; + + template + constexpr explicit (!convertible_from) + status_or(U&& value) + requires ( + constructible_from && + !same_as, status_or> && + !same_as, status> + ) + : m_status{status_code::ok} + , m_value{in_place, ASL_FWD(value)} + {} + + constexpr bool ok() const { return m_status.ok(); } + + // NOLINTNEXTLINE(*-explicit-conversions) + constexpr operator bool() const { return m_status; } + + constexpr status_code code() const { return m_status.code(); } + + constexpr string_view message() const { return m_status.message(); } + + // @Todo(C++23) Deducing this + constexpr const T& value() const& + { + ASL_ASSERT_RELEASE(ok()); + return m_value.as_init_unsafe(); + } + + constexpr T& value() & + { + ASL_ASSERT_RELEASE(ok()); + return m_value.as_init_unsafe(); + } + + constexpr T&& value() && + { + ASL_ASSERT_RELEASE(ok()); + return ASL_MOVE(m_value.as_init_unsafe()); + } + + template + constexpr T value_or(U&& other_value) const& + requires copy_constructible && convertible_from + { + return ok() ? value() : static_cast(ASL_FWD(other_value)); + } + + template + constexpr T value_or(U&& other_value) && + requires move_constructible && convertible_from + { + return ok() ? ASL_MOVE(value()) : static_cast(ASL_FWD(other_value)); + } +}; + +template +status_or(T) -> status_or; + +} // namespace asl + -- cgit