MGL(Win32)
読み取り中…
検索中…
一致する文字列を見つけられません
mgl_stl_memory.h
[詳解]
1// SPDX-License-Identifier: Zlib
2/* ------------------------------------------------------------------------- */
9/* ------------------------------------------------------------------------- */
10
11#ifndef INCGUARD_MGL_STL_MEMORY_H_1651241952
12#define INCGUARD_MGL_STL_MEMORY_H_1651241952
13
14#include <memory>
15#include <type_traits>
16
18
19namespace MGL::STL
20{
22template <typename T>
24{
25public:
26 using value_type = T;
27
28 Allocator() noexcept = default;
29 Allocator(const Allocator &) noexcept = default;
30
31 template <class U>
32 Allocator(const Allocator<U> & /*unused*/) noexcept {};
33
34 ~Allocator() = default;
35
36 T *allocate(std::size_t n)
37 {
38 auto *ptr = reinterpret_cast<T *>(MGL::Memory::Allocate(n * sizeof(T)));
39 if (ptr == nullptr)
40 {
41 throw std::bad_alloc();
42 }
43
44 return ptr;
45 }
46
47 void deallocate(T *p, [[maybe_unused]] std::size_t n)
48 {
49 MGL::Memory::Deallocate(p);
50 }
51};
52
53template <class T, class U>
54bool operator==(const Allocator<T> & /*unused*/, const Allocator<U> & /*unused*/) noexcept
55{
56 return true;
57}
58
59template <class T, class U>
60bool operator!=(const Allocator<T> & /*unused*/, const Allocator<U> & /*unused*/) noexcept
61{
62 return false;
63}
64
66struct Deleter
67{
68 using DestroyFunc = void (*)(void *obj, size_t size);
69
70 struct Header
71 {
72 DestroyFunc destroyer;
73 size_t size;
74 };
75 static_assert(sizeof(Header) <= 16);
76
77 void operator()(void *ptr) const
78 {
79 if (ptr != nullptr)
80 {
81 auto *top = reinterpret_cast<Header *>(ptr) - 1;
82
83 if (top->destroyer != nullptr)
84 {
85 top->destroyer(top + 1, top->size);
86 }
87
88 MGL::Memory::Deallocate(top);
89 }
90 }
91};
92
94template <class T>
95constexpr void NonTrivialDestroyer(void *obj, size_t size)
96{
97 std::destroy_n(reinterpret_cast<T *>(obj), size);
98}
99
100
102template <class T>
104{
105 using UniquePtr_Single = std::unique_ptr<T, Deleter>;
106};
107
109template <class T>
110struct UniquePtrType<T[]>
111{
112 using UniquePtr_Array = std::unique_ptr<T[], Deleter>;
113};
114
116template <class T, size_t n>
117struct UniquePtrType<T[n]>
118{
119 using UniquePtr_Invalid = void;
120};
121
122
124template <class T, class... Args>
125[[nodiscard]] inline typename UniquePtrType<T>::UniquePtr_Single make_unique(Args &&...args)
126{
127 // 必要な容量のバッファをアロケートして先頭アドレスをヘッダに設定する
128 auto *header = reinterpret_cast<Deleter::Header *>(MGL::Memory::Allocate(sizeof(T) + sizeof(Deleter::Header)));
129 if (header == nullptr)
130 {
131 throw std::bad_alloc();
132 }
133
134 // 必要ならばデストラクタの呼び出し関数を設定
135 if constexpr (std::is_trivially_destructible_v<T>)
136 {
137 header->destroyer = nullptr;
138 }
139 else
140 {
141 header->destroyer = NonTrivialDestroyer<T>;
142 }
143
144 // サイズは常に1
145 header->size = 1;
146
147 // 生成するオブジェクトはヘッダの次のアドレス
148 auto *obj = reinterpret_cast<T *>(header + 1);
149
150 // 例外なし
151 if constexpr (std::is_nothrow_constructible_v<T, Args...>)
152 {
153 obj = new (obj) T(std::forward<Args>(args)...);
154 }
155 // 例外あり
156 else
157 {
158 try
159 {
160 obj = new (obj) T(std::forward<Args>(args)...);
161 }
162 catch (...)
163 {
164 MGL::Memory::Deallocate(header);
165 throw;
166 }
167 }
168
169 return std::unique_ptr<T, Deleter>(obj);
170}
171
173template <class T>
174[[nodiscard]] inline typename UniquePtrType<T>::UniquePtr_Array make_unique(size_t n)
175{
176 using U = std::remove_extent_t<T>;
177
178 // 必要な容量のバッファをアロケートして先頭アドレスをヘッダに設定する
179 auto *header = reinterpret_cast<Deleter::Header *>(MGL::Memory::Allocate((sizeof(U) * n) + sizeof(Deleter::Header)));
180 if (header == nullptr)
181 {
182 return std::unique_ptr<T, Deleter>(nullptr);
183 }
184
185 // 必要ならばデストラクタの呼び出し関数を設定
186 if constexpr (std::is_trivially_destructible_v<U>)
187 {
188 header->destroyer = nullptr;
189 }
190 else
191 {
192 header->destroyer = NonTrivialDestroyer<U>;
193 }
194
195 // ヘッダにサイズを設定
196 header->size = n;
197
198 // 生成するオブジェクトはヘッダの次のアドレス
199 auto *obj = reinterpret_cast<U *>(header + 1);
200 U *top = nullptr;
201
202 // 例外なし
203 if constexpr (std::is_nothrow_constructible_v<U>)
204 {
205 for (size_t i = 0; i < n; i++)
206 {
207 auto *ptr = obj + i;
208 ptr = new (ptr) U();
209
210 if (i == 0)
211 {
212 top = ptr;
213 }
214 }
215 }
216 // 例外あり
217 else
218 {
219 for (size_t i = 0; i < n; i++)
220 {
221 U *ptr = nullptr;
222 try
223 {
224 ptr = new (obj + i) U();
225 }
226 catch (...)
227 {
228 if (top != nullptr)
229 {
230 for (auto j = static_cast<int64_t>(i) - 1; j >= 0; j--)
231 {
232 std::destroy_at(top + j);
233 }
234 }
235
236 MGL::Memory::Deallocate(header);
237 throw;
238 }
239
240 if (i == 0)
241 {
242 top = ptr;
243 }
244 }
245 }
246
247 return std::unique_ptr<T, Deleter>(top);
248}
249
250// サイズ指定の配列型のユニークポインタは扱えない
251template <class T, class... Args>
252constexpr typename UniquePtrType<T>::UniquePtr_Invalid make_unique(Args &&...) = delete;
253
255template <class T>
256using unique_ptr = std::unique_ptr<T, Deleter>;
257
259template <class T, class... Args>
260[[nodiscard]] constexpr auto make_shared(Args &&...args)
261{
262 const Allocator<void> alloc;
263 return std::allocate_shared<T>(alloc, std::forward<Args>(args)...);
264}
265
266} // namespace MGL::STL
267
268#endif // INCGUARD_MGL_STL_MEMORY_H_1651241952
269
270// vim: et ts=4 sw=4 sts=4
STL用アロケータ
Definition mgl_stl_memory.h:24
MGL メモリ関連
constexpr auto make_shared(Args &&...args)
シェアードポインタの生成
Definition mgl_stl_memory.h:260
constexpr void NonTrivialDestroyer(void *obj, size_t size)
デストラクタ呼び出し用テンプレート関数
Definition mgl_stl_memory.h:95
std::unique_ptr< T, Deleter > unique_ptr
MGLのアロケータを利用するユニークポインタ
Definition mgl_stl_memory.h:256
UniquePtrType< T >::UniquePtr_Single make_unique(Args &&...args)
非配列型のユニークポインタの生成
Definition mgl_stl_memory.h:125
Definition mgl_stl_memory.h:71
STL用デリータ
Definition mgl_stl_memory.h:67
非配列型の判別用テンプレート
Definition mgl_stl_memory.h:104