Created
May 14, 2020 16:02
-
-
Save cdhowie/4985d7a461e1cf61ee0cfb29cf9e3dc2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef OPTIONAL_HPP | |
#define OPTIONAL_HPP | |
#include <utility> | |
namespace gamesolver { | |
template <typename T> | |
class optional { | |
public: | |
optional() noexcept; | |
~optional(); | |
optional(T const &); | |
optional(T &&); | |
optional(optional const &); | |
optional(optional &&); | |
optional & operator=(T const &); | |
optional & operator=(T &&); | |
optional & operator=(optional const &); | |
optional & operator=(optional &&); | |
void swap(optional &) noexcept; | |
bool has_value() const noexcept; | |
explicit operator bool() const noexcept; | |
T & operator*() noexcept; | |
T const & operator*() const noexcept; | |
T * get() noexcept; | |
T const * get() const noexcept; | |
T * operator->() noexcept; | |
T const * operator->() const noexcept; | |
void clear(); | |
template <typename... Args> | |
void emplace(Args && ...); | |
private: | |
char mem[sizeof(T)]; | |
T * target; | |
}; | |
template <typename T> | |
optional<T>::optional() noexcept : target{nullptr} { } | |
template <typename T> | |
optional<T>::~optional() { | |
clear(); | |
} | |
template <typename T> | |
optional<T>::optional(optional const & other) : optional{} { | |
*this = other; | |
} | |
template <typename T> | |
optional<T>::optional(optional && other) : optional{} { | |
*this = std::move(other); | |
} | |
template <typename T> | |
optional<T>::optional(T const & other) : | |
target{new (mem) T{other}} { } | |
template <typename T> | |
optional<T>::optional(T && other) : | |
target{new (mem) T{std::move(other)}} { } | |
template <typename T> | |
optional<T> & optional<T>::operator=(optional const & other) { | |
if (!other.has_value()) { | |
clear(); | |
} else if (has_value()) { | |
*target = *other; | |
} else { | |
target = new (mem) T{*other}; | |
} | |
return *this; | |
} | |
template <typename T> | |
optional<T> & optional<T>::operator=(optional && other) { | |
if (!other.has_value()) { | |
clear(); | |
} else if (has_value()) { | |
*target = std::move(*other); | |
other.clear(); | |
} else { | |
target = new (mem) T{std::move(*other)}; | |
other.clear(); | |
} | |
return *this; | |
} | |
template <typename T> | |
optional<T> & optional<T>::operator=(T const & other) { | |
if (has_value()) { | |
*target = other; | |
} else { | |
target = new (mem) T{other}; | |
} | |
return *this; | |
} | |
template <typename T> | |
optional<T> & optional<T>::operator=(T && other) { | |
if (has_value()) { | |
*target = std::move(other); | |
} else { | |
target = new (mem) T{std::move(other)}; | |
} | |
return *this; | |
} | |
template <typename T> | |
template <typename... Args> | |
void optional<T>::emplace(Args && ... args) { | |
clear(); | |
target = new (mem) T{std::forward<Args>(args)...}; | |
} | |
template <typename T> | |
bool optional<T>::has_value() const noexcept { | |
return target != nullptr; | |
} | |
template <typename T> | |
optional<T>::operator bool() const noexcept { | |
return has_value(); | |
} | |
template <typename T> | |
void optional<T>::swap(optional & other) noexcept { | |
std::swap(mem, other.mem); | |
std::swap(target, other.target); | |
} | |
template <typename T> | |
T * optional<T>::get() noexcept { | |
return target; | |
} | |
template <typename T> | |
T const * optional<T>::get() const noexcept { | |
return target; | |
} | |
template <typename T> | |
T * optional<T>::operator->() noexcept { | |
return get(); | |
} | |
template <typename T> | |
T const * optional<T>::operator->() const noexcept { | |
return get(); | |
} | |
template <typename T> | |
T & optional<T>::operator*() noexcept { | |
return *get(); | |
} | |
template <typename T> | |
T const & optional<T>::operator*() const noexcept { | |
return *get(); | |
} | |
template <typename T> | |
void optional<T>::clear() { | |
if (target != nullptr) { | |
target->~T(); | |
target = nullptr; | |
} | |
} | |
template <typename T> | |
void swap(optional<T> & a, optional<T> & b) { | |
a.swap(b); | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment