mirror of
https://github.com/CraftyBoss/SuperMarioOdysseyOnline.git
synced 2024-11-20 10:15:16 +00:00
86 lines
2.6 KiB
C
86 lines
2.6 KiB
C
|
#pragma once
|
||
|
|
||
|
#include <utility>
|
||
|
#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<sizeof(T), alignof(T)>).
|
||
|
template <typename T, bool AutoDestruct = false>
|
||
|
class StorageFor
|
||
|
{
|
||
|
public:
|
||
|
constexpr StorageFor() = default;
|
||
|
|
||
|
explicit StorageFor(InitializeTag) { constructDefault(); }
|
||
|
|
||
|
template <typename... Args>
|
||
|
explicit StorageFor(InitializeTag, Args&&... args)
|
||
|
{
|
||
|
construct(std::forward<Args>(args)...);
|
||
|
}
|
||
|
|
||
|
explicit StorageFor(ZeroInitializeTag) : mStorage{} { constructDefault(); }
|
||
|
|
||
|
template <typename... Args>
|
||
|
explicit StorageFor(ZeroInitializeTag, Args&&... args) : mStorage{}
|
||
|
{
|
||
|
construct(std::forward<Args>(args)...);
|
||
|
}
|
||
|
|
||
|
T* constructDefault() { return new (storage()) T; }
|
||
|
|
||
|
template <typename... Args>
|
||
|
T* construct(Args&&... args)
|
||
|
{
|
||
|
return new (storage()) T(std::forward<Args>(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<T&>(mStorage); }
|
||
|
|
||
|
/// @warning It is undefined behavior to call this if no object has been constructed.
|
||
|
const T& ref() const { return reinterpret_cast<const T&>(mStorage); }
|
||
|
|
||
|
/// @warning It is undefined behavior to call this if no object has been constructed.
|
||
|
T* data() { return reinterpret_cast<T*>(mStorage); }
|
||
|
|
||
|
/// @warning It is undefined behavior to call this if no object has been constructed.
|
||
|
const T* data() const { return reinterpret_cast<const T*>(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
|