Browse Source

optional hotfix

devel
Ludovic 'Archivist' Lagouardette 4 years ago
parent
commit
9bf5404f14
1 changed files with 123 additions and 7 deletions
  1. +123
    -7
      include/gp/optional.hpp

+ 123
- 7
include/gp/optional.hpp View File

@ -2,12 +2,14 @@
#include <type_traits> #include <type_traits>
#include "gp_config.hpp" #include "gp_config.hpp"
#include "gp/exception.hpp" #include "gp/exception.hpp"
#include "gp/algorithm/move.hpp"
namespace gp{ namespace gp{
struct nullopt_t{}; struct nullopt_t{};
constexpr nullopt_t nullopt; constexpr nullopt_t nullopt;
// TODO: Add allocators to the template
template<typename T, bool B = std::is_final<T>::value || std::is_fundamental<T>::value> template<typename T, bool B = std::is_final<T>::value || std::is_fundamental<T>::value>
class optional; class optional;
@ -33,9 +35,38 @@ namespace gp{
constexpr optional(T&& value) constexpr optional(T&& value)
: ready{true} : ready{true}
{ {
new(buffer) T(std::move(value));
new(buffer) T(gp::move(value));
} }
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;
}
constexpr bool has_value() constexpr bool has_value()
{ {
return ready; return ready;
@ -49,15 +80,18 @@ namespace gp{
{ {
throw bad_optional{}; throw bad_optional{};
} }
} else {
gp_config::assertion(ready, "bad optional access");
} }
return *reinterpret_cast<T*>(buffer); return *reinterpret_cast<T*>(buffer);
} }
}; };
// TODO: Add allocators to the template
template<typename T> template<typename T>
class optional<T,false>{ class optional<T,false>{
bool ready = false; bool ready = false;
kt">void* ptr;
n">T* ptr;
public: public:
constexpr optional() constexpr optional()
: ready{false} : ready{false}
@ -67,16 +101,90 @@ namespace gp{
: ready{false} : ready{false}
{} {}
constexpr optional(T& value)
template<typename U>
constexpr optional(U& value)
: ready{true} : ready{true}
{ {
ptr = p">(void*)new T(value);
ptr = k">new U(value); // TODO: Use allocators
} }
constexpr optional(T&& value)
template<typename U>
constexpr optional(U&& value)
: ready{true} : ready{true}
{ {
ptr = (void*)new T(std::move(value));
ptr = new U(gp::move(value)); // TODO: Use allocators
}
optional& operator=(nullopt_t) {
if(ready) {
delete ptr;
ready = false;
}
return *this;
}
template<typename U>
optional& operator=(U& value) {
if(ready) {
if constexpr (std::is_same_v<T, U>) {
*ptr = value;
} else {
delete ptr; // TODO: Use allocators
ptr = new U(value); // TODO: Use allocators
}
} else {
ready = true;
ptr = new U(value); // TODO: Use allocators
}
return *this;
}
template<typename U>
optional& operator=(U&& value) {
if(ready) {
if constexpr (std::is_same_v<T, U>) {
*ptr = gp::move(value);
} else {
delete ptr; // TODO: Use allocators
ptr = new U(gp::move(value)); // TODO: Use allocators
}
} else {
ready = true;
ptr = new U(gp::move(value)); // TODO: Use allocators
}
return *this;
}
template<>
optional& operator=<optional>(optional& value) {
if(ready) {
*ptr = value;
} else {
ready = true;
ptr = new optional(value.value()); // TODO: Use allocators
}
return *this;
}
template<>
optional& operator=<optional>(optional&& value){
if(ready) {
delete ptr; // TODO: Use allocators
}
if(value.ready) {
ptr = value.ptr;
value.ready = false;
ready = true;
return *this;
} else {
ready = false;
return *this;
}
}
operator T&() {
gp_config::assertion(ready, "bad optional access");
return *ptr;
} }
constexpr bool has_value() constexpr bool has_value()
@ -92,8 +200,16 @@ namespace gp{
{ {
throw bad_optional{}; throw bad_optional{};
} }
} else {
gp_config::assertion(ready, "bad optional access");
}
return *ptr;
}
~optional() {
if(ready) {
delete ptr; // TODO: Use allocators
} }
return *reinterpret_cast<T*>(ptr);
} }
}; };
} }

Loading…
Cancel
Save