#pragma once #include #include #include namespace BAN { template class Optional { public: Optional(); Optional(const T&); Optional(T&&); template Optional(Args&&...); ~Optional(); Optional& operator=(const Optional&); Optional& operator=(Optional&&); template Optional& emplace(Args&&...); T* operator->(); const T* operator->() const; T& operator*(); const T& operator*() const; bool has_value() const; T&& release_value(); const T& value() const; T& value(); void clear(); private: alignas(T) uint8_t m_storage[sizeof(T)]; bool m_has_value { false }; }; template Optional::Optional() : m_has_value(false) {} template Optional::Optional(const T& value) : m_has_value(true) { new (m_storage) T(value); } template Optional::Optional(T&& value) : m_has_value(true) { new (m_storage) T(BAN::move(value)); } template template Optional::Optional(Args&&... args) : m_has_value(true) { new (m_storage) T(BAN::forward(args)...); } template Optional::~Optional() { clear(); } template Optional& Optional::operator=(const Optional& other) { clear(); if (other.has_value()) { m_has_value = true; new (m_storage) T(other.value()); } return *this; } template Optional& Optional::operator=(Optional&& other) { clear(); if (other.has_value()) { m_has_value = true; new (m_storage) T(BAN::move(other.release_value())); } return *this; } template template Optional& Optional::emplace(Args&&... args) { clear(); m_has_value = true; new (m_storage) T(BAN::forward(args)...); return *this; } template T* Optional::operator->() { ASSERT(has_value()); return &value(); } template const T* Optional::operator->() const { ASSERT(has_value()); return &value(); } template T& Optional::operator*() { ASSERT(has_value()); return value(); } template const T& Optional::operator*() const { ASSERT(has_value()); return value(); } template bool Optional::has_value() const { return m_has_value; } template T&& Optional::release_value() { ASSERT(has_value()); m_has_value = false; return BAN::move((T&)m_storage); } template const T& Optional::value() const { ASSERT(has_value()); return (const T&)m_storage; } template T& Optional::value() { ASSERT(has_value()); return (T&)m_storage; } template void Optional::clear() { if (m_has_value) value().~T(); m_has_value = false; } }