From dd7b8eba9c8a01fc05daeb96d560b0fe8f19d9fb Mon Sep 17 00:00:00 2001 From: Jeremy <51220084+jeremy-rifkin@users.noreply.github.com> Date: Mon, 11 Sep 2023 09:37:11 -0400 Subject: [PATCH] basic optional implementation --- src/platform/common.hpp | 133 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/src/platform/common.hpp b/src/platform/common.hpp index 3733f2c..d5739bc 100644 --- a/src/platform/common.hpp +++ b/src/platform/common.hpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #define IS_WINDOWS 0 #define IS_LINUX 0 @@ -270,4 +272,135 @@ class file_error : std::exception { #pragma warning(pop) #endif +struct nullopt_t {}; + +static constexpr nullopt_t nullopt; + +template::type, void>::value, int>::type = 0> +class optional { + bool holds_value = false; + + union { + T uvalue; + }; + +public: + optional() {} + + optional(nullopt_t) {} + + ~optional() { + reset(); + } + + optional(const optional& other) : holds_value(other.holds_value) { + if(holds_value) { + new (static_cast(std::addressof(uvalue))) T(other.uvalue); + } + } + + optional(optional&& other) : holds_value(other.holds_value) { + if(holds_value) { + new (static_cast(std::addressof(uvalue))) T(std::move(other.uvalue)); + } + } + + optional& operator=(const optional& other) { + optional copy(other); + swap(*this, copy); + return *this; + } + + optional& operator=(optional&& other) { + reset(); + if(other.holds_value) { + new (static_cast(std::addressof(uvalue))) T(std::move(other.uvalue)); + holds_value = true; + } + return *this; + } + + template::type, optional>::value, int>::type = 0> + optional(U&& value) : holds_value(true) { + new (static_cast(std::addressof(uvalue))) T(std::forward(value)); + } + + template::type, optional>::value, int>::type = 0> + optional& operator=(U&& value) { + if(holds_value) { + uvalue = std::forward(value); + } else { + new (static_cast(std::addressof(uvalue))) T(std::forward(value)); + holds_value = true; + } + return *this; + } + + void swap(optional& other) { + if(holds_value && other.holds_value) { + std::swap(uvalue, other.uvalue); + } else if(holds_value && !other.holds_value) { + new (&other.uvalue) T(std::move(uvalue)); + uvalue.~T(); + } else if(!holds_value && other.holds_value) { + new (static_cast(std::addressof(uvalue))) T(std::move(other.uvalue)); + other.uvalue.~T(); + } + std::swap(holds_value, other.holds_value); + } + + bool has_value() const { + return holds_value; + } + + operator bool() const { + return holds_value; + } + + void reset() { + if(holds_value) { + uvalue.~T(); + } + holds_value = false; + } + + T& value() & { + if(!holds_value) { + throw std::runtime_error{"Optional does not contain a value"}; + } + return uvalue; + } + + const T& value() const & { + if(!holds_value) { + throw std::runtime_error{"Optional does not contain a value"}; + } + return uvalue; + } + + T&& value() && { + if(!holds_value) { + throw std::runtime_error{"Optional does not contain a value"}; + } + return std::move(uvalue); + } + + const T&& value() const && { + if(!holds_value) { + throw std::runtime_error{"Optional does not contain a value"}; + } + return std::move(uvalue); + } + + template + T value_or(U&& default_value) const & { + return holds_value ? uvalue : static_cast(std::forward(default_value)); + } + + template + T value_or(U&& default_value) && { + return holds_value ? std::move(uvalue) : static_cast(std::forward(default_value)); + } +}; + #endif