General Purpose library for Freestanding C++ and POSIX systems
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

158 lines
2.5 KiB

#pragma once
#include "gp_config.hpp"
#include "gp/functional/bind_front.hpp"
#include "gp/functional/monostates.hpp"
#include "gp/algorithms/move.hpp"
#include "gp/exception.hpp"
#include <type_traits>
#include <new>
namespace gp{
template<typename T>
class optional final{
bool ready = false;
alignas(T) char buffer[sizeof(T)];
public:
constexpr optional()
: ready{false}
{}
constexpr optional(nullopt_t)
: ready{false}
{}
constexpr optional(T& value)
: ready{true}
{
new(buffer) T(value);
}
constexpr optional(T&& value)
: ready{true}
{
new(buffer) T(gp::move(value));
}
constexpr optional(const optional& oth)
: ready{oth.ready}
{
if(ready) {
new(buffer) T(oth.value());
}
}
constexpr optional(optional&& oth)
: ready{oth.ready}
{
if(ready) {
new(buffer) T(gp::move(oth.value()));
}
}
~optional() {
if(ready) {
((T*)buffer)->~T();
}
}
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;
}
optional& operator=(const optional& oth) {
if(oth.ready) {
if(ready) {
*(T*)buffer = oth.value();
} else {
ready = true;
new(buffer) T(oth.value());
}
} else {
if(ready) {
((T*)buffer)->~T();
ready = false;
}
}
return *this;
}
optional& operator=(optional&& oth) {
if(oth.ready) {
if(ready) {
*(T*)buffer = gp::move(oth.value());
} else {
ready = true;
new(buffer) T(gp::move(oth.value()));
}
} else {
if(ready) {
((T*)buffer)->~T();
ready = false;
}
}
return *this;
}
constexpr bool has_value() const
{
return ready;
}
constexpr T& value()
{
if constexpr (gp_config::has_exceptions)
{
if(!ready)
{
throw bad_optional{};
}
} else {
gp_config::assertion(ready, "bad optional access");
}
return *reinterpret_cast<T*>(buffer);
}
constexpr const T& value() const
{
if constexpr (gp_config::has_exceptions)
{
if(!ready)
{
throw bad_optional{};
}
} else {
gp_config::assertion(ready, "bad optional access");
}
return *reinterpret_cast<const T*>(buffer);
}
};
}