#pragma once
|
|
#include <type_traits>
|
|
#include "gp_config.hpp"
|
|
#include "gp/exception.hpp"
|
|
#include "gp/memory.hpp"
|
|
|
|
namespace gp{
|
|
struct nullopt_t{};
|
|
|
|
constexpr nullopt_t nullopt;
|
|
|
|
template<typename T, bool B = std::is_final<T>::value || std::is_fundamental<T>::value>
|
|
class optional;
|
|
|
|
template<typename T>
|
|
class optional<T,true>{
|
|
bool ready = false;
|
|
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(std::move(value));
|
|
}
|
|
|
|
constexpr bool has_value()
|
|
{
|
|
return ready;
|
|
}
|
|
|
|
constexpr T& value()
|
|
{
|
|
if constexpr (gp_config::has_exceptions)
|
|
{
|
|
if(!ready)
|
|
{
|
|
throw bad_optional{};
|
|
}
|
|
}
|
|
return *reinterpret_cast<T*>(buffer);
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
class optional<T,false>{
|
|
bool ready = false;
|
|
void* ptr;
|
|
public:
|
|
constexpr optional()
|
|
: ready{false}
|
|
{}
|
|
|
|
constexpr optional(nullopt_t)
|
|
: ready{false}
|
|
{}
|
|
|
|
constexpr optional(T& value)
|
|
: ready{true}
|
|
{
|
|
ptr = (void*)new T(value);
|
|
}
|
|
|
|
constexpr optional(T&& value)
|
|
: ready{true}
|
|
{
|
|
ptr = (void*)new T(std::move(value));
|
|
}
|
|
|
|
constexpr bool has_value()
|
|
{
|
|
return ready;
|
|
}
|
|
|
|
constexpr T& value()
|
|
{
|
|
if constexpr (gp_config::has_exceptions)
|
|
{
|
|
if(!ready)
|
|
{
|
|
throw bad_optional{};
|
|
}
|
|
}
|
|
return *reinterpret_cast<T*>(ptr);
|
|
}
|
|
};
|
|
}
|