// ===================================================================================================================== // fennec, a free and open source game engine // Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // ===================================================================================================================== /// /// \file optional.h /// \brief A header containing the definition for a container with an optionally present variable /// /// /// \details /// \author Medusa Slockbower /// /// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) /// /// #ifndef FENNEC_CONTAINERS_OPTIONAL_H #define FENNEC_CONTAINERS_OPTIONAL_H #include #include #include namespace fennec { struct nullopt_t {}; constexpr nullopt_t nullopt_v = {}; #define nullopt nullopt_v /// /// \brief Structure to hold an optional value. /// \tparam T template struct optional { // Definitions ========================================================================================================= public: using reference_t = T&; using pointer_t = T*; using const_reference_t = T&; using const_pointer_t = const T*; // Constructors ======================================================================================================== /// \name Constructors & Destructor /// @{ /// /// \brief Default Constructor constexpr optional() : _root(0) , _set(false) { } /// /// \brief Default Constructor constexpr optional(nullopt_t) : _root(0) , _set(false) { } /// /// \brief Type Copy Constructor /// \param val the value to initialize the underlying object with constexpr optional(const T& val) : _val(val) , _set(true) { } /// /// \brief Type Move Constructor /// \param val the value to initialize the underlying object with constexpr optional(T&& val) : _val(fennec::forward(val)) , _set(true) { } /// /// \brief Copy Constructor /// \param opt the optional to copy constexpr optional(const optional& opt) requires is_copy_assignable_v : optional() { _set = opt._set; if (_set) { _val = opt._val; } } /// /// \brief Move Constructor /// \param opt the optional to move constexpr optional(optional&& opt) noexcept requires is_move_assignable_v : optional() { _set = opt._set; if (_set) { _val = fennec::move(opt._val); } opt = nullopt; } template constexpr optional(ArgsT&&...args) : _val(fennec::forward(args)...) , _set(true) { } constexpr ~optional() { if constexpr(is_fundamental_v) { return; } if (_set) { fennec::destruct(&_val); } } /// @} // Properties ========================================================================================================== /// \name Properties /// @{ /// /// \brief Implicit Boolean Check, returns `true` when there is a value contained constexpr operator bool() const { return _set; } /// /// \returns `true` when there is no held value, `false` otherwise. constexpr bool empty() const { return not _set; } /// @} // Assignment Operators ================================================================================================ /// \name Assignment /// @{ /// /// \brief Fundamental Type Assignment /// \param val The value to set with constexpr optional& operator=(nullopt_t) { if constexpr(not is_fundamental_v) { if (_set) { fennec::destruct(&_val); } } _root = '\0'; _set = false; return *this; } /// /// \brief Type Copy Assignment /// \param val The value to set with constexpr optional& operator=(const T& val) requires is_copy_constructible_v and is_copy_assignable_v { if (_set) { _val = val; } else { fennec::construct(&_val, val); _set = true; } return *this; } /// /// \brief Type Move Assignment /// \param val The value to set with constexpr optional& operator=(T&& val) requires is_move_constructible_v and is_move_assignable_v { if (_set) { _val = fennec::forward(val); } else { fennec::construct(&_val, fennec::forward(val)); _set = true; } return *this; } /// /// \brief Copy Assignment /// \param opt The optional to copy constexpr optional& operator=(const optional& opt) requires is_copy_constructible_v and is_copy_assignable_v { if (_set != opt._set) { _set = opt._set; if (_set) { // Construct fennec::construct(&_val, opt._val); } else { // Destruct fennec::destruct(&_val); _root = 0; } } else if (_set) { // Copy Assignment _val = opt._val; } return *this; } /// /// \brief Move Assignment /// \param opt The optional to move constexpr optional& operator=(optional&& opt) noexcept requires is_move_constructible_v and is_move_assignable_v { if (_set != opt._set) { _set = opt._set; if (_set) { // Construct fennec::construct(&_val, fennec::move(opt._val)); } else { // Destruct fennec::destruct(&_val); _root = 0; } } else if (_set) { // Copy Assignment _val = fennec::move(opt._val); } return *this; } /// @} // Access ============================================================================================================== /// \name Access /// @{ /// /// \returns A pointer to the value, `nullptr` if there is no value constexpr pointer_t operator->() noexcept { return _set ? &_val : nullptr; } /// /// \returns A const-qualified pointer to the value, `nullptr` if there is no value constexpr const_pointer_t operator->() const noexcept { return _set ? &_val : nullptr; } /// /// \brief Dereference Operator /// \returns A reference to the value constexpr T& operator*() & noexcept { assertd(_set, "Attempted to reference the value of an unset optional"); return _val; } /// /// \brief Const Dereference Operator /// \returns A const-qualified reference to the value constexpr const T& operator*() const& noexcept { assertd(_set, "Attempted to reference the value of an unset optional"); return _val; } /// /// \brief Dereference Operator /// \returns A reference to the value constexpr T&& operator*() && noexcept { assertd(_set, "Attempted to reference the value of an unset optional"); return _val; } /// /// \brief Const Dereference Operator /// \returns A const-qualified reference to the value constexpr const T&& operator*() const&& noexcept { assertd(_set, "Attempted to reference the value of an unset optional"); return _val; } /// @} // Modifiers =========================================================================================================== /// \name Modifiers /// @{ /// /// \brief Emplace Assignment, Move overload /// \param val The object to take ownership of constexpr T& emplace(T&& val) { if (_set) { _val = fennec::forward(val); } else { fennec::construct(&_val, fennec::forward(val)); _set = true; } return _val; } /// /// \brief Emplace Assignment, Copy overload /// \param val The object to copy constexpr T& emplace(const T& val) { if (_set) { _val = val; } else { fennec::construct(&_val, val); _set = true; } return _val; } /// /// \brief Emplace Assignment /// \param args The arguments to construct with template constexpr T& emplace(ArgsT&&...args) { if (_set) { _val = T(fennec::forward(args)...); } else { fennec::construct(&_val, fennec::forward(args)...); _set = true; } return _val; } /// /// \brief Reset the Optional void reset() { this->operator=(nullopt); } /// @} private: union { char _root; T _val; }; bool _set; }; } #endif // FENNEC_CONTAINERS_OPTIONAL_H