|
|
- #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);
- }
- };
- }
|