1#pragma once
2
3#include <utility>
4
5#include "basis/seadNew.h"
6#include "basis/seadTypes.h"
7
8namespace sead
9{
10struct InitializeTag
11{
12};
13
14struct ZeroInitializeTag
15{
16};
17
18/// Provides suitably aligned uninitialized storage for a type T.
19/// Use this as a std::aligned_storage replacement that is easier to use and less error prone for
20/// common cases (std::aligned_storage_t<sizeof(T), alignof(T)>).
21template <typename T, bool AutoDestruct = false>
22class StorageFor
23{
24public:
25 constexpr StorageFor() = default;
26
27 explicit StorageFor(InitializeTag) { constructDefault(); }
28
29 template <typename... Args>
30 explicit StorageFor(InitializeTag, Args&&... args)
31 {
32 construct(std::forward<Args>(args)...);
33 }
34
35 explicit StorageFor(ZeroInitializeTag) : mStorage{} { constructDefault(); }
36
37 template <typename... Args>
38 explicit StorageFor(ZeroInitializeTag, Args&&... args) : mStorage{}
39 {
40 construct(std::forward<Args>(args)...);
41 }
42
43 T* constructDefault() { return new (storage()) T; }
44
45 template <typename... Args>
46 T* construct(Args&&... args)
47 {
48 return new (storage()) T(std::forward<Args>(args)...);
49 }
50
51 ~StorageFor()
52 {
53 if constexpr (AutoDestruct)
54 destruct();
55 }
56
57 /// @warning It is undefined behavior to call this if no object has been constructed.
58 void destruct() { data()->~T(); }
59
60 /// @warning It is undefined behavior to call this if no object has been constructed.
61 T& ref() { return reinterpret_cast<T&>(mStorage); }
62
63 /// @warning It is undefined behavior to call this if no object has been constructed.
64 const T& ref() const { return reinterpret_cast<const T&>(mStorage); }
65
66 /// @warning It is undefined behavior to call this if no object has been constructed.
67 T* data() { return reinterpret_cast<T*>(mStorage); }
68
69 /// @warning It is undefined behavior to call this if no object has been constructed.
70 const T* data() const { return reinterpret_cast<const T*>(mStorage); }
71
72 /// @warning It is undefined behavior to call this if no object has been constructed.
73 T* operator->() { return data(); }
74 /// @warning It is undefined behavior to call this if no object has been constructed.
75 const T* operator->() const { return data(); }
76 /// @warning It is undefined behavior to call this if no object has been constructed.
77 T& operator*() { return ref(); }
78 /// @warning It is undefined behavior to call this if no object has been constructed.
79 const T& operator*() const { return ref(); }
80
81 void* storage() { return mStorage; }
82 const void* storage() const { return mStorage; }
83
84private:
85 alignas(T) u8 mStorage[sizeof(T)];
86};
87} // namespace sead
88