mirror of
https://github.com/ksherlock/wdc-utils.git
synced 2024-11-15 12:06:57 +00:00
172 lines
3.6 KiB
C++
172 lines
3.6 KiB
C++
#ifndef __optional_h__
|
|
#define __optional_h__
|
|
|
|
#include <type_traits>
|
|
#include <stdexcept>
|
|
|
|
class bad_optional_access : public std::exception {
|
|
public:
|
|
virtual const char* what() const noexcept {
|
|
return "bad optional access";
|
|
}
|
|
};
|
|
|
|
template<class T>
|
|
class optional {
|
|
public:
|
|
typedef T value_type;
|
|
|
|
optional() = default;
|
|
|
|
optional( const optional& other ) {
|
|
if (other._engaged) {
|
|
new (std::addressof(_data)) T(*other);
|
|
_engaged = true;
|
|
}
|
|
}
|
|
|
|
optional( const optional&& other ) {
|
|
if (other._engaged) {
|
|
new (std::addressof(_data)) T(std::move(*other));
|
|
_engaged = true;
|
|
}
|
|
}
|
|
|
|
template < class U >
|
|
optional( const optional<U>& other ) {
|
|
if (other._engaged) {
|
|
new (std::addressof(_data)) T(*other);
|
|
_engaged = true;
|
|
}
|
|
}
|
|
|
|
template < class U >
|
|
optional( optional<U>&& other ) {
|
|
if (other._engaged) {
|
|
new (std::addressof(_data)) T(std::move(*other));
|
|
_engaged = true;
|
|
}
|
|
}
|
|
|
|
|
|
template<class U = T>
|
|
optional(U &&value) {
|
|
new(std::addressof(_data)) T(std::forward<U>(value));
|
|
_engaged = true;
|
|
}
|
|
|
|
|
|
~optional() {
|
|
reset();
|
|
}
|
|
|
|
|
|
template< class U = T >
|
|
optional& operator=( U&& value ) {
|
|
if (_engaged) {
|
|
auto &self = *reinterpret_cast<T*>(std::addressof(_data));
|
|
self = std::forward<U>(value);
|
|
}
|
|
else {
|
|
new(std::addressof(_data)) T(std::forward<U>(value));
|
|
_engaged = true;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
optional& operator=(optional &&rhs) {
|
|
if (rhs._engaged) this->operator=(std::forward<T>(*rhs));
|
|
else reset();
|
|
return *this;
|
|
}
|
|
|
|
optional& operator=(const optional &rhs) {
|
|
if (rhs._engaged) this->operator=(*rhs);
|
|
else reset();
|
|
return *this;
|
|
}
|
|
|
|
template< class... Args >
|
|
void emplace( Args&&... args ) {
|
|
reset();
|
|
new(std::addressof(_data)) T(std::forward<Args>(args)...);
|
|
_engaged = true;
|
|
}
|
|
|
|
|
|
constexpr explicit operator bool() const {
|
|
return _engaged;
|
|
}
|
|
|
|
constexpr bool has_value() const {
|
|
return _engaged;
|
|
}
|
|
|
|
/* these should throw ... */
|
|
constexpr T& value() & {
|
|
if (!_engaged) throw bad_optional_access();
|
|
return *reinterpret_cast<T*>(std::addressof(_data));
|
|
}
|
|
|
|
constexpr const T & value() const & {
|
|
if (!_engaged) throw bad_optional_access();
|
|
return *reinterpret_cast<const T*>(std::addressof(_data));
|
|
}
|
|
|
|
constexpr T&& value() && {
|
|
if (!_engaged) throw bad_optional_access();
|
|
return *reinterpret_cast<T*>(std::addressof(_data));
|
|
}
|
|
|
|
constexpr const T&& value() const && {
|
|
if (!_engaged) throw bad_optional_access();
|
|
return *reinterpret_cast<const T*>(std::addressof(_data));
|
|
}
|
|
|
|
|
|
template< class U >
|
|
constexpr T value_or( U&& default_value ) const& {
|
|
return bool(*this) ? **this : static_cast<T>(std::forward<U>(default_value));
|
|
}
|
|
|
|
template< class U >
|
|
constexpr T value_or( U&& default_value ) && {
|
|
return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(default_value));
|
|
}
|
|
|
|
constexpr const T* operator->() const {
|
|
return reinterpret_cast<const T*>(std::addressof(_data));
|
|
}
|
|
constexpr T* operator->() {
|
|
return reinterpret_cast<T*>(std::addressof(_data));
|
|
}
|
|
|
|
constexpr const T& operator*() const& {
|
|
return *reinterpret_cast<const T*>(std::addressof(_data));
|
|
}
|
|
constexpr T& operator*() & {
|
|
return *reinterpret_cast<T*>(std::addressof(_data));
|
|
}
|
|
constexpr const T&& operator*() const&& {
|
|
return *reinterpret_cast<const T*>(std::addressof(_data));
|
|
}
|
|
constexpr T&& operator*() && {
|
|
return *reinterpret_cast<T*>(std::addressof(_data));
|
|
}
|
|
|
|
|
|
void reset() {
|
|
if (_engaged) {
|
|
reinterpret_cast<const T*>(std::addressof(_data))->~T();
|
|
_engaged = false;
|
|
}
|
|
}
|
|
|
|
private:
|
|
bool _engaged = false;
|
|
typename std::aligned_storage<sizeof(T), alignof(T)>::type _data;
|
|
};
|
|
|
|
#endif
|
|
|