#pragma once #include #include "basis/seadTypes.h" namespace sead { struct InitializeTag { }; struct ZeroInitializeTag { }; /// Provides suitably aligned uninitialized storage for a type T. /// Use this as a std::aligned_storage replacement that is easier to use and less error prone for /// common cases (std::aligned_storage_t). template class StorageFor { public: constexpr StorageFor() = default; explicit StorageFor(InitializeTag) { constructDefault(); } template explicit StorageFor(InitializeTag, Args&&... args) { construct(std::forward(args)...); } explicit StorageFor(ZeroInitializeTag) : mStorage{} { constructDefault(); } template explicit StorageFor(ZeroInitializeTag, Args&&... args) : mStorage{} { construct(std::forward(args)...); } T* constructDefault() { return new (storage()) T; } template T* construct(Args&&... args) { return new (storage()) T(std::forward(args)...); } ~StorageFor() { if constexpr (AutoDestruct) destruct(); } /// @warning It is undefined behavior to call this if no object has been constructed. void destruct() { data()->~T(); } /// @warning It is undefined behavior to call this if no object has been constructed. T& ref() { return reinterpret_cast(mStorage); } /// @warning It is undefined behavior to call this if no object has been constructed. const T& ref() const { return reinterpret_cast(mStorage); } /// @warning It is undefined behavior to call this if no object has been constructed. T* data() { return reinterpret_cast(mStorage); } /// @warning It is undefined behavior to call this if no object has been constructed. const T* data() const { return reinterpret_cast(mStorage); } /// @warning It is undefined behavior to call this if no object has been constructed. T* operator->() { return data(); } /// @warning It is undefined behavior to call this if no object has been constructed. const T* operator->() const { return data(); } /// @warning It is undefined behavior to call this if no object has been constructed. T& operator*() { return ref(); } /// @warning It is undefined behavior to call this if no object has been constructed. const T& operator*() const { return ref(); } void* storage() { return mStorage; } const void* storage() const { return mStorage; } private: alignas(T) u8 mStorage[sizeof(T)]; }; } // namespace sead