diff --git a/include/gp/optional.hpp b/include/gp/optional.hpp index 552e436..8864d29 100644 --- a/include/gp/optional.hpp +++ b/include/gp/optional.hpp @@ -2,12 +2,14 @@ #include #include "gp_config.hpp" #include "gp/exception.hpp" +#include "gp/algorithm/move.hpp" namespace gp{ struct nullopt_t{}; constexpr nullopt_t nullopt; + // TODO: Add allocators to the template template::value || std::is_fundamental::value> class optional; @@ -33,9 +35,38 @@ namespace gp{ constexpr optional(T&& value) : ready{true} { - new(buffer) T(std::move(value)); + new(buffer) T(gp::move(value)); } + optional& operator=(nullopt_t) { + if(ready) { + ((T*)buffer)->~T(); + ready = false; + } + return *this; + } + + optional& operator=(T& value) { + if(ready) { + *(T*)buffer = value; + } else { + ready = true; + new(buffer) T(value); + } + return *this; + } + + optional& operator=(T&& value) { + if(ready) { + *(T*)buffer = gp::move(value); + } else { + ready = true; + new(buffer) T(gp::move(value)); + } + return *this; + } + + constexpr bool has_value() { return ready; @@ -49,15 +80,18 @@ namespace gp{ { throw bad_optional{}; } + } else { + gp_config::assertion(ready, "bad optional access"); } return *reinterpret_cast(buffer); } }; + // TODO: Add allocators to the template template class optional{ bool ready = false; - void* ptr; + T* ptr; public: constexpr optional() : ready{false} @@ -67,16 +101,90 @@ namespace gp{ : ready{false} {} - constexpr optional(T& value) + template + constexpr optional(U& value) : ready{true} { - ptr = (void*)new T(value); + ptr = new U(value); // TODO: Use allocators } - constexpr optional(T&& value) + template + constexpr optional(U&& value) : ready{true} { - ptr = (void*)new T(std::move(value)); + ptr = new U(gp::move(value)); // TODO: Use allocators + } + + optional& operator=(nullopt_t) { + if(ready) { + delete ptr; + ready = false; + } + return *this; + } + + template + optional& operator=(U& value) { + if(ready) { + if constexpr (std::is_same_v) { + *ptr = value; + } else { + delete ptr; // TODO: Use allocators + ptr = new U(value); // TODO: Use allocators + } + } else { + ready = true; + ptr = new U(value); // TODO: Use allocators + } + return *this; + } + + template + optional& operator=(U&& value) { + if(ready) { + if constexpr (std::is_same_v) { + *ptr = gp::move(value); + } else { + delete ptr; // TODO: Use allocators + ptr = new U(gp::move(value)); // TODO: Use allocators + } + } else { + ready = true; + ptr = new U(gp::move(value)); // TODO: Use allocators + } + return *this; + } + + template<> + optional& operator=(optional& value) { + if(ready) { + *ptr = value; + } else { + ready = true; + ptr = new optional(value.value()); // TODO: Use allocators + } + return *this; + } + + template<> + optional& operator=(optional&& value){ + if(ready) { + delete ptr; // TODO: Use allocators + } + if(value.ready) { + ptr = value.ptr; + value.ready = false; + ready = true; + return *this; + } else { + ready = false; + return *this; + } + } + + operator T&() { + gp_config::assertion(ready, "bad optional access"); + return *ptr; } constexpr bool has_value() @@ -92,8 +200,16 @@ namespace gp{ { throw bad_optional{}; } + } else { + gp_config::assertion(ready, "bad optional access"); + } + return *ptr; + } + + ~optional() { + if(ready) { + delete ptr; // TODO: Use allocators } - return *reinterpret_cast(ptr); } }; } \ No newline at end of file