basic optional implementation

This commit is contained in:
Jeremy 2023-09-11 09:37:11 -04:00
parent 95ee2a815c
commit dd7b8eba9c
No known key found for this signature in database
GPG Key ID: 3E11861CB34E158C

View File

@ -23,6 +23,8 @@
#include <type_traits>
#include <utility>
#include <vector>
#include <memory>
#include <new>
#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<typename T, typename std::enable_if<!std::is_same<typename std::decay<T>::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<void*>(std::addressof(uvalue))) T(other.uvalue);
}
}
optional(optional&& other) : holds_value(other.holds_value) {
if(holds_value) {
new (static_cast<void*>(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<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
holds_value = true;
}
return *this;
}
template<class U = T, typename std::enable_if<!std::is_same<typename std::decay<U>::type, optional<T>>::value, int>::type = 0>
optional(U&& value) : holds_value(true) {
new (static_cast<void*>(std::addressof(uvalue))) T(std::forward<U>(value));
}
template<typename U = T, typename std::enable_if<!std::is_same<typename std::decay<U>::type, optional<T>>::value, int>::type = 0>
optional& operator=(U&& value) {
if(holds_value) {
uvalue = std::forward<U>(value);
} else {
new (static_cast<void*>(std::addressof(uvalue))) T(std::forward<U>(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<void*>(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<typename U>
T value_or(U&& default_value) const & {
return holds_value ? uvalue : static_cast<T>(std::forward<U>(default_value));
}
template<typename U>
T value_or(U&& default_value) && {
return holds_value ? std::move(uvalue) : static_cast<T>(std::forward<U>(default_value));
}
};
#endif