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