|
|
- #pragma once
-
- #include "gp_config.hpp"
-
- #include "gp/functional/bind_front.hpp"
- #include "gp/algorithms/move.hpp"
- #include "gp/exception.hpp"
-
- #include <type_traits>
- #include <new>
-
- namespace gp{
- struct nullopt_t final{};
-
- constexpr nullopt_t nullopt;
-
- 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::forward<T>(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::forward<T>(value);
- } else {
- ready = true;
- new(buffer) T(gp::forward<T>(value));
- }
- 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);
- }
- };
- }
|