#pragma once
|
|
|
|
#include <type_traits>
|
|
#include <assert.h>
|
|
#include <stdexcept>
|
|
|
|
struct in_place_t
|
|
{
|
|
explicit in_place_t() = default;
|
|
};
|
|
|
|
template<typename BaseType> class optional
|
|
{
|
|
using Storage = typename std::aligned_storage<sizeof(BaseType), std::alignment_of<BaseType>::value>::type;
|
|
|
|
Storage m_storage;
|
|
bool m_valid = false;
|
|
|
|
public:
|
|
typedef optional<BaseType> self_type;
|
|
|
|
optional() = default;
|
|
|
|
~optional()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
optional(const optional& src) : m_valid(src.m_valid)
|
|
{
|
|
if (src.m_valid)
|
|
{
|
|
new(&m_storage) BaseType(*src);
|
|
}
|
|
}
|
|
|
|
optional(optional&& src) : m_valid(src.m_valid)
|
|
{
|
|
if (src.m_valid)
|
|
{
|
|
new(&m_storage) BaseType(std::move(*src));
|
|
}
|
|
}
|
|
|
|
template<typename U = BaseType, typename =
|
|
typename std::enable_if<
|
|
std::is_constructible<BaseType, U&&>::value &&
|
|
!(std::is_same<typename std::decay<U>::type, self_type>::value)
|
|
>::type
|
|
>
|
|
optional(U&& value) : m_valid(true)
|
|
{
|
|
new(&m_storage) BaseType(std::forward<U>(value));
|
|
}
|
|
|
|
template<typename... Args, typename = typename std::enable_if<std::is_constructible<BaseType, Args...>::value>::type>
|
|
explicit optional(in_place_t tag, Args&&... args) : m_valid(true)
|
|
{
|
|
new(&m_storage) BaseType(std::forward<Args>(args)...);
|
|
}
|
|
|
|
optional& operator = (optional&& src) noexcept
|
|
{
|
|
if (src.m_valid)
|
|
{
|
|
if (m_valid)
|
|
{
|
|
**this = std::move(*src);
|
|
}
|
|
else
|
|
{
|
|
new(&m_storage) BaseType(std::move(*src));
|
|
m_valid = true;
|
|
}
|
|
}
|
|
else if (m_valid)
|
|
{
|
|
reinterpret_cast<BaseType*>(&m_storage)->~BaseType();
|
|
m_valid = false;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
optional& operator = (const optional& src)
|
|
{
|
|
if (src.m_valid)
|
|
{
|
|
if (m_valid)
|
|
{
|
|
**this = *src;
|
|
}
|
|
else
|
|
{
|
|
new(&m_storage) BaseType(*src);
|
|
m_valid = true;
|
|
}
|
|
}
|
|
else if (m_valid)
|
|
{
|
|
reinterpret_cast<BaseType*>(&m_storage)->~BaseType();
|
|
m_valid = false;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<typename U = BaseType, typename =
|
|
typename std::enable_if<
|
|
!std::is_same<typename std::decay<U>::type, self_type>::value &&
|
|
std::is_constructible<BaseType, U>::value &&
|
|
std::is_assignable<BaseType&, U>::value
|
|
>::type>
|
|
optional& operator = (U&& value)
|
|
{
|
|
if (m_valid)
|
|
{
|
|
**this = std::forward<U>(value);
|
|
}
|
|
else
|
|
{
|
|
new(&m_storage) BaseType(std::forward<U>(value));
|
|
m_valid = true;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
if (m_valid)
|
|
{
|
|
(**this).BaseType::~BaseType();
|
|
m_valid = false;
|
|
}
|
|
}
|
|
|
|
constexpr explicit operator bool() const
|
|
{
|
|
return m_valid;
|
|
}
|
|
|
|
constexpr bool has_value() const
|
|
{
|
|
return m_valid;
|
|
}
|
|
|
|
constexpr bool valid() const
|
|
{
|
|
return has_value();
|
|
}
|
|
|
|
BaseType& operator * () &
|
|
{
|
|
assert(m_valid);
|
|
return *reinterpret_cast<BaseType*>(&m_storage);
|
|
}
|
|
|
|
const BaseType& operator * () const &
|
|
{
|
|
assert(m_valid);
|
|
return *reinterpret_cast<const BaseType*>(&m_storage);
|
|
}
|
|
|
|
BaseType&& operator * () &&
|
|
{
|
|
assert(m_valid);
|
|
return std::move(*reinterpret_cast<BaseType*>(&m_storage));
|
|
}
|
|
|
|
const BaseType&& operator * () const &&
|
|
{
|
|
assert(m_valid);
|
|
return std::move(*reinterpret_cast<BaseType*>(&m_storage));
|
|
}
|
|
|
|
BaseType* operator -> ()
|
|
{
|
|
assert(m_valid);
|
|
return reinterpret_cast<BaseType*>(&m_storage);
|
|
}
|
|
|
|
const BaseType* operator -> () const
|
|
{
|
|
assert(m_valid);
|
|
return reinterpret_cast<const BaseType*>(&m_storage);
|
|
}
|
|
|
|
BaseType& value()
|
|
{
|
|
if (!has_value())
|
|
{
|
|
throw std::logic_error("bad_optional_access");
|
|
}
|
|
|
|
return **this;
|
|
}
|
|
|
|
const BaseType& value() const
|
|
{
|
|
if (!has_value())
|
|
{
|
|
throw std::logic_error("bad_optional_access");
|
|
}
|
|
|
|
return **this;
|
|
}
|
|
|
|
template<typename U> BaseType value_or(U&& default_value) &&
|
|
{
|
|
return has_value() ? std::move(**this) : static_cast<BaseType>(std::forward<U>(default_value));
|
|
}
|
|
|
|
template<typename U> const BaseType value_or(U&& default_value) const &
|
|
{
|
|
return has_value() ? **this : static_cast<BaseType>(std::forward<U>(default_value));
|
|
}
|
|
|
|
template<typename... Args> BaseType& emplace(Args&&... args)
|
|
{
|
|
reset();
|
|
|
|
new(&m_storage) BaseType(std::forward<Args>(args)...);
|
|
m_valid = true;
|
|
|
|
return **this;
|
|
}
|
|
};
|
|
|
|
template<typename T> optional<typename std::decay<T>::type> make_optional(T&& val)
|
|
{
|
|
return optional<typename std::decay<T>::type>(std::forward<T>(val));
|
|
}
|
|
|
|
template<typename T, typename... Args> optional<T> make_optional(Args&&... args)
|
|
{
|
|
return optional<T>(in_place_t{}, std::forward<Args>(args)...);
|
|
}
|