#ifndef _OPTIONAL_HPP_
#define _OPTIONAL_HPP_
#if (__cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L))
#include <optional>
using std::optional;
#else
#include <type_traits>
namespace datasketches {
template<typename T>
class optional {
public:
optional() noexcept: initialized_(false) {}
optional(const T& value) noexcept(std::is_nothrow_copy_constructible<T>::value) {
new (&value_) T(value);
initialized_ = true;
}
optional(T&& value) noexcept(std::is_nothrow_move_constructible<T>::value) {
new (&value_) T(std::move(value));
initialized_ = true;
}
template<typename TT>
optional(const optional<TT>& other) noexcept(std::is_nothrow_constructible<T, TT>::value): initialized_(false) {
if (other.initialized_) {
new (&value_) T(other.value_);
initialized_ = true;
}
}
optional(const optional& other) noexcept(std::is_nothrow_copy_constructible<T>::value): initialized_(false) {
if (other.initialized_) {
new (&value_) T(other.value_);
initialized_ = true;
}
}
optional(optional&& other) noexcept(std::is_nothrow_move_constructible<T>::value): initialized_(false) {
if (other.initialized_) {
new (&value_) T(std::move(other.value_));
initialized_ = true;
}
}
~optional() noexcept(std::is_nothrow_destructible<T>::value) {
if (initialized_) value_.~T();
}
explicit operator bool() const noexcept {
return initialized_;
}
optional& operator=(const optional& other)
noexcept(std::is_nothrow_copy_constructible<T>::value && std::is_nothrow_copy_assignable<T>::value) {
if (initialized_) {
if (other.initialized_) {
value_ = other.value_;
} else {
reset();
}
} else {
if (other.initialized_) {
new (&value_) T(other.value_);
initialized_ = true;
}
}
return *this;
}
optional& operator=(optional&& other)
noexcept(std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value) {
if (initialized_) {
if (other.initialized_) {
value_ = std::move(other.value_);
} else {
reset();
}
} else {
if (other.initialized_) {
new (&value_) T(std::move(other.value_));
initialized_ = true;
}
}
return *this;
}
template<typename... Args>
void emplace(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) {
new (&value_) T(args...);
initialized_ = true;
}
T& operator*() & noexcept { return value_; }
const T& operator*() const & noexcept { return value_; }
T&& operator*() && noexcept { return std::move(value_); }
const T&& operator*() const && noexcept { return std::move(value_); }
T* operator->() noexcept { return &value_; }
const T* operator->() const noexcept { return &value_; }
void reset() noexcept(std::is_nothrow_destructible<T>::value) {
if (initialized_) value_.~T();
initialized_ = false;
}
private:
union {
T value_;
};
bool initialized_;
template<typename TT> friend class optional;
};
}
#endif
#endif