#ifndef Optional_h
#define Optional_h
#include <type_traits>
#include <wtf/Assertions.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
enum InPlaceTag { InPlace };
enum NulloptTag { Nullopt };
template<typename T>
class Optional {
public:
Optional()
: m_isEngaged(false)
{
}
Optional(NulloptTag)
: m_isEngaged(false)
{
}
Optional(const T& value)
: m_isEngaged(true)
, m_value(value)
{
}
Optional(const Optional& other)
: m_isEngaged(other.m_isEngaged)
{
if (m_isEngaged)
new (NotNull, std::addressof(m_value)) T(other.m_value);
}
Optional(Optional&& other)
: m_isEngaged(other.m_isEngaged)
{
if (m_isEngaged)
new (NotNull, std::addressof(m_value)) T(WTF::move(other.m_value));
}
Optional(T&& value)
: m_isEngaged(true)
, m_value(WTF::move(value))
{
}
template<typename... Args>
Optional(InPlaceTag, Args&&... args)
: m_isEngaged(true)
, m_value(std::forward<Args>(args)...)
{
}
~Optional()
{
if (m_isEngaged)
m_value.~T();
}
Optional& operator=(NulloptTag)
{
if (m_isEngaged) {
m_value.~T();
m_isEngaged = false;
}
return *this;
}
Optional& operator=(const Optional& other)
{
if (m_isEngaged == other.m_isEngaged) {
if (m_isEngaged)
m_value = other.m_value;
return *this;
}
if (m_isEngaged)
m_value.~T();
else
new (NotNull, std::addressof(m_value)) T(other.m_value);
m_isEngaged = other.m_isEngaged;
return *this;
}
Optional& operator=(Optional&& other)
{
if (m_isEngaged == other.m_isEngaged) {
if (m_isEngaged)
m_value = WTF::move(other.m_value);
return *this;
}
if (m_isEngaged)
m_value.~T();
else
new (NotNull, std::addressof(m_value)) T(WTF::move(other.m_value));
m_isEngaged = other.m_isEngaged;
return *this;
}
template<typename U>
Optional& operator=(U&& u)
{
if (m_isEngaged) {
m_value = std::forward<U>(u);
return *this;
}
new (NotNull, std::addressof(m_value)) T(std::forward<U>(u));
m_isEngaged = true;
return *this;
}
explicit operator bool() const { return m_isEngaged; }
T& value()
{
ASSERT(m_isEngaged);
return m_value;
}
const T& value() const
{
ASSERT(m_isEngaged);
return m_value;
}
template<typename U>
T valueOr(U&& value) const
{
if (m_isEngaged)
return m_value;
return std::forward<U>(value);
}
private:
bool m_isEngaged;
union {
T m_value;
};
};
}
using WTF::InPlace;
using WTF::Nullopt;
using WTF::Optional;
#endif // Optional_h