diff --git a/AK/Optional.h b/AK/Optional.h new file mode 100644 index 0000000000..7399b2ee4b --- /dev/null +++ b/AK/Optional.h @@ -0,0 +1,102 @@ +#pragma once + +#include + +template +class alignas(T) Optional { +public: + Optional() {} + + Optional(T&& value) + : m_has_value(true) + { + new (&m_storage) T(move(value)); + } + + template + Optional(U&& value) + : m_has_value(true) + { + new (&m_storage) T(move(value)); + } + + Optional(Optional&& other) + : m_has_value(other.m_has_value) + { + if (m_has_value) { + new (&m_storage) T(move(other.value())); + other.m_has_value = false; + } + } + + Optional(const Optional& other) + : m_has_value(other.m_has_value) + { + if (m_has_value) { + new (&m_storage) T(other.value()); + } + } + + Optional& operator=(const Optional& other) + { + if (this != &other) { + clear(); + m_has_value = other.m_has_value; + if (m_has_value) { + new (&m_storage) T(other.value()); + } + } + return *this; + } + + Optional& operator=(Optional&& other) + { + if (this != &other) { + clear(); + m_has_value = other.m_has_value; + if (m_has_value) { + new (&m_storage) T(other.release_value()); + } + } + return *this; + } + + ~Optional() + { + clear(); + } + + void clear() + { + if (m_has_value) { + value().~T(); + m_has_value = false; + } + } + + bool has_value() const { return m_has_value; } + + T& value() + { + ASSERT(m_has_value); + return *reinterpret_cast(&m_storage); + } + + const T& value() const + { + ASSERT(m_has_value); + return *reinterpret_cast(&m_storage); + } + + T release_value() + { + ASSERT(m_has_value); + T released_value = move(value()); + value().~T(); + return released_value; + } + +private: + char m_storage[sizeof(T)] __attribute__((aligned(sizeof(T)))); + bool m_has_value { false }; +};