|
|
@ -2,6 +2,7 @@ |
|
|
|
#include <type_traits>
|
|
|
|
#include "gp_config.hpp"
|
|
|
|
#include "gp/exception.hpp"
|
|
|
|
#include "gp/algorithm/move.hpp"
|
|
|
|
#include "gp/memory.hpp"
|
|
|
|
|
|
|
|
namespace gp{ |
|
|
@ -9,6 +10,7 @@ namespace gp{ |
|
|
|
|
|
|
|
constexpr nullopt_t nullopt; |
|
|
|
|
|
|
|
// TODO: Add allocators to the template
|
|
|
|
template<typename T, bool B = std::is_final<T>::value || std::is_fundamental<T>::value> |
|
|
|
class optional; |
|
|
|
|
|
|
@ -34,9 +36,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; |
|
|
@ -50,11 +81,14 @@ namespace gp{ |
|
|
|
{ |
|
|
|
throw bad_optional{}; |
|
|
|
} |
|
|
|
} else { |
|
|
|
gp_config::assertion(ready, "bad optional access"); |
|
|
|
} |
|
|
|
return *reinterpret_cast<T*>(buffer); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// TODO: Add allocators to the template
|
|
|
|
template<typename T> |
|
|
|
class optional<T,false>{ |
|
|
|
bool ready = false; |
|
|
@ -68,16 +102,48 @@ namespace gp{ |
|
|
|
: ready{false} |
|
|
|
{} |
|
|
|
|
|
|
|
// TODO: Add typesafe generic assignment
|
|
|
|
constexpr optional(T& value) |
|
|
|
: ready{true} |
|
|
|
{ |
|
|
|
ptr = (void*)new T(value); |
|
|
|
ptr = (void*)new T(value); // TODO: Use allocators
|
|
|
|
} |
|
|
|
|
|
|
|
// TODO: Add typesafe generic assignment
|
|
|
|
constexpr optional(T&& value) |
|
|
|
: ready{true} |
|
|
|
{ |
|
|
|
ptr = (void*)new T(std::move(value)); |
|
|
|
ptr = (void*)new T(gp::move(value)); // TODO: Use allocators
|
|
|
|
} |
|
|
|
|
|
|
|
optional operator=(nullopt_t) { |
|
|
|
if(ready) { |
|
|
|
delete (T*)ptr; |
|
|
|
ready = false; |
|
|
|
} |
|
|
|
return *this; |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: Add typesafe generic assignment
|
|
|
|
optional operator=(T& value) { |
|
|
|
if(ready) { |
|
|
|
*(T*)ptr = value; |
|
|
|
} else { |
|
|
|
ready = true; |
|
|
|
ptr = (void*)new T(value); // TODO: Use allocators
|
|
|
|
} |
|
|
|
return *this; |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: Add typesafe generic assignment
|
|
|
|
optional operator=(T&& value) { |
|
|
|
if(ready) { |
|
|
|
*(T*)ptr = gp::move(value); |
|
|
|
} else { |
|
|
|
ready = true; |
|
|
|
ptr = (void*)new T(gp::move(value)); // TODO: Use allocators
|
|
|
|
} |
|
|
|
return *this; |
|
|
|
} |
|
|
|
|
|
|
|
constexpr bool has_value() |
|
|
@ -93,6 +159,8 @@ namespace gp{ |
|
|
|
{ |
|
|
|
throw bad_optional{}; |
|
|
|
} |
|
|
|
} else { |
|
|
|
gp_config::assertion(ready, "bad optional access"); |
|
|
|
} |
|
|
|
return *reinterpret_cast<T*>(ptr); |
|
|
|
} |
|
|
|