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