nCine 2025.08.r507-936d9b8
A cross-platform 2D game engine
Loading...
Searching...
No Matches
utility.h
1#ifndef NCTL_UTILITY
2#define NCTL_UTILITY
3
4#include <cstring> // for `memcpy()`
5#include "type_traits.h"
6
7namespace nctl {
8
10template <class T>
11inline typename removeReference<T>::type &&move(T &&arg)
12{
13 return static_cast<typename removeReference<T>::type &&>(arg);
14}
15
17template <typename T>
18inline constexpr T &&forward(typename removeReference<T>::type &arg)
19{
20 return static_cast<T &&>(arg);
21}
22
23template <typename T>
24inline constexpr T &&forward(typename removeReference<T>::type &&arg)
25{
26 static_assert(!isLValueReference<T>::value, "Invalid lvalue to rvalue conversion");
27 return static_cast<T &&>(arg);
28}
29
31template <class T>
32inline void swap(T &a, T &b)
33{
34 T temp = nctl::move(a);
35 a = nctl::move(b);
36 b = nctl::move(temp);
37}
38
40template <class T>
41inline bool equalTo(const T &a, const T &b) { return a == b; }
42
44template <class T>
45inline bool equalTo(const T *a, const T *b) { return a == b; }
46
47template <>
48inline bool equalTo<char>(const char *a, const char *b)
49{
50 while (*a && (*a == *b))
51 {
52 a++;
53 b++;
54 }
55 return (*a == *b);
56}
57
58namespace detail {
59
60// ---- Tags ----
61struct TrivialTag {}; // Trivially copyable types
62struct MovableTag {}; // Movable and copyable types
63struct MoveOnlyTag {}; // Movable but non-copyable types
64struct CopyableTag {}; // Copyable but non-movable types
65struct NonMovableTag {}; // Non-movable and non-copyable types
66
67template <typename T>
69{
70 static constexpr bool value =
73 !__is_union(T) &&
74 !__is_abstract(T);
75};
76
77// ---- ObjectPolicyTag ----
78template <class T>
95
96// ---- constructHelpersImplSingle ----
97template <typename T, typename Tag>
99
100template <typename T>
102{
103 static void constructObject(T *ptr) {}
104 static void copyConstructObject(T *dest, const T *src) { memcpy(dest, src, sizeof(T)); }
105 static void moveConstructObject(T *dest, T *src) { memcpy(dest, src, sizeof(T)); }
106};
107
108template <typename T>
110{
111 static void constructObject(T *ptr) { new (ptr) T(); }
112 static void copyConstructObject(T *dest, const T *src) { new (dest) T(*src); }
113 static void moveConstructObject(T *dest, T *src) { new (dest) T(nctl::move(*src)); }
114};
115
116template <typename T>
118{
119 static void constructObject(T *ptr) { new (ptr) T(); }
120 static void copyConstructObject(T *dest, const T *src) { new (dest) T(nctl::move(*src)); }
121 static void moveConstructObject(T *dest, T *src) { new (dest) T(nctl::move(*src)); }
122};
123
124template <typename T>
126{
127 static void constructObject(T *ptr) { new (ptr) T(); }
128 static void copyConstructObject(T *dest, const T *src) { new (dest) T(*src); }
129 static void moveConstructObject(T *dest, T *src) { new (dest) T(*src); }
130};
131
132template <typename T>
134{
135 static void constructObject(T *) { static_assert(sizeof(T) == 0, "Cannot construct this type"); }
136 static void copyConstructObject(T *, const T *) { static_assert(sizeof(T) == 0, "Cannot copy construct this type"); }
137 static void moveConstructObject(T *, T *) { static_assert(sizeof(T) == 0, "Cannot move construct this type"); }
138};
139
140// ---- constructHelpersImplSingleArray ----
141template <typename T, typename Tag>
143{
144 static void constructArray(T *ptr, unsigned int numElements)
145 {
146 for (unsigned int i = 0; i < numElements; i++)
147 new (ptr + i) T();
148 }
149};
150
151template <typename T>
153{
154 static void constructArray(T *, unsigned int) {}
155};
156
157template <typename T>
159{
160 static void constructArray(T *, unsigned int numElements)
161 {
162 if (numElements > 0)
163 static_assert(sizeof(T) == 0, "Cannot construct elements of this type");
164 }
165};
166
167// ---- constructHelpersImpl ----
168template <typename T, typename Tag>
170
171template <typename T>
173{
174 static void moveConstructArray(T *dest, T *src, unsigned int numElements)
175 {
176 memcpy(dest, src, numElements * sizeof(T));
177 }
178
179 static void copyConstructArray(T *dest, const T *src, unsigned int numElements)
180 {
181 memcpy(dest, src, numElements * sizeof(T));
182 }
183};
184
185template <typename T>
187{
188 static void moveConstructArray(T *dest, T *src, unsigned int numElements)
189 {
190 for (unsigned int i = 0; i < numElements; i++)
191 new (dest + i) T(nctl::move(src[i]));
192 }
193
194 static void copyConstructArray(T *dest, const T *src, unsigned int numElements)
195 {
196 for (unsigned int i = 0; i < numElements; i++)
197 new (dest + i) T(src[i]);
198 }
199};
200
201template <typename T>
203{
204 static void moveConstructArray(T *dest, T *src, unsigned int numElements)
205 {
206 for (unsigned int i = 0; i < numElements; i++)
207 new (dest + i) T(nctl::move(src[i]));
208 }
209
210 static void copyConstructArray(T *dest, const T *src, unsigned int numElements)
211 {
212 for (unsigned int i = 0; i < numElements; i++)
213 new (dest + i) T(nctl::move(src[i]));
214 }
215};
216
217template <typename T>
219{
220 static void moveConstructArray(T *dest, T *src, unsigned int numElements)
221 {
222 for (unsigned int i = 0; i < numElements; i++)
223 new (dest + i) T(src[i]);
224 }
225
226 static void copyConstructArray(T *dest, const T *src, unsigned int numElements)
227 {
228 for (unsigned int i = 0; i < numElements; i++)
229 new (dest + i) T(src[i]);
230 }
231};
232
233template <typename T>
235{
236 static void moveConstructArray(T *, T *, unsigned int numElements)
237 {
238 if (numElements > 0)
239 static_assert(sizeof(T) == 0, "Cannot move construct elements of this type");
240 }
241
242 static void copyConstructArray(T *, const T *, unsigned int numElements)
243 {
244 if (numElements > 0)
245 static_assert(sizeof(T) == 0, "Cannot copy construct elements of this type");
246 }
247};
248
249// ---- constructHelpers ----
250template <class T>
252{
253 using Tag = typename ObjectPolicyTag<T>::type;
254
255 static void constructObject(T *ptr)
256 {
258 }
259 static void constructArray(T *ptr, unsigned int numElements)
260 {
262 }
263
264 static void copyConstructObject(T *dest, const T *src)
265 {
267 }
268 static void copyConstructArray(T *dest, const T *src, unsigned int numElements)
269 {
270 if (numElements > 0)
272 }
273
274 static void moveConstructObject(T *dest, T *src)
275 {
277 }
278 static void moveConstructArray(T *dest, T *src, unsigned int numElements)
279 {
280 if (numElements > 0)
282 }
283};
284
285// ---- destructHelpers ----
286template <bool Trivial>
288{
289 template <class T>
290 static void destructObject(T *ptr) { ptr->~T(); }
291
292 template <class T>
293 static void destructArray(T *ptr, unsigned int numElements)
294 {
295 for (unsigned int i = 0; i < numElements; i++)
296 ptr[numElements - i - 1].~T();
297 }
298};
299
300template <>
302{
303 template <class T>
304 static void destructObject(T *) {}
305
306 template <class T>
307 static void destructArray(T *, unsigned int) {}
308};
309
310// ---- copyHelpersImpl ----
311template <typename T, typename Tag>
313
314template <typename T>
316{
317 static void moveAssignArray(T *dest, T *src, unsigned int numElements)
318 {
319 memcpy(dest, src, numElements * sizeof(T));
320 }
321
322 static void copyAssignArray(T *dest, const T *src, unsigned int numElements)
323 {
324 memcpy(dest, src, numElements * sizeof(T));
325 }
326};
327
328template <typename T>
330{
331 static void moveAssignArray(T *dest, T *src, unsigned int numElements)
332 {
333 for (unsigned int i = 0; i < numElements; i++)
334 dest[i] = nctl::move(src[i]);
335 }
336
337 static void copyAssignArray(T *dest, const T *src, unsigned int numElements)
338 {
339 for (unsigned int i = 0; i < numElements; i++)
340 dest[i] = src[i];
341 }
342};
343
344template <typename T>
346{
347 static void moveAssignArray(T *dest, T *src, unsigned int numElements)
348 {
349 for (unsigned int i = 0; i < numElements; i++)
350 dest[i] = nctl::move(src[i]);
351 }
352
353 static void copyAssignArray(T *dest, const T *src, unsigned int numElements)
354 {
355 for (unsigned int i = 0; i < numElements; i++)
356 dest[i] = nctl::move(src[i]);
357 }
358};
359
360template <typename T>
362{
363 static void moveAssignArray(T *dest, T *src, unsigned int numElements)
364 {
365 for (unsigned int i = 0; i < numElements; i++)
366 dest[i] = src[i];
367 }
368
369 static void copyAssignArray(T *dest, const T *src, unsigned int numElements)
370 {
371 for (unsigned int i = 0; i < numElements; i++)
372 dest[i] = src[i];
373 }
374};
375
376template <typename T>
378{
379 static void moveAssignArray(T *dest, T *src, unsigned int numElements)
380 {
381 if (numElements > 0)
382 static_assert(sizeof(T) == 0, "Cannot move assign elements of this type");
383 }
384
385 static void copyAssignArray(T *, const T *, unsigned int numElements)
386 {
387 if (numElements > 0)
388 static_assert(sizeof(T) == 0, "Cannot copy assign elements of this type");
389 }
390};
391
392}
393
394template <class T>
395inline void constructObject(T *ptr) { detail::constructHelpers<T>::constructObject(ptr); }
396
397template <class T>
398inline void constructArray(T *ptr, unsigned int numElements) { detail::constructHelpers<T>::constructArray(ptr, numElements); }
399
400template <class T>
401inline void copyConstructObject(T *dest, const T *src) { detail::constructHelpers<T>::copyConstructObject(dest, src); }
402
403template <class T>
404inline void copyConstructArray(T *dest, const T *src, unsigned int numElements) { detail::constructHelpers<T>::copyConstructArray(dest, src, numElements); }
405
406template <class T>
407inline void moveConstructObject(T *dest, T *src) { detail::constructHelpers<T>::moveConstructObject(dest, src); }
408
409template <class T>
410inline void moveConstructArray(T *dest, T *src, unsigned int numElements) { detail::constructHelpers<T>::moveConstructArray(dest, src, numElements); }
411
412template <class T>
413inline void destructObject(T *ptr) { detail::destructHelpers<isTriviallyDestructible<T>::value>::destructObject(ptr); }
414
415template <class T>
416inline void destructArray(T *ptr, unsigned int numElements) { detail::destructHelpers<isTriviallyDestructible<T>::value>::destructArray(ptr, numElements); }
417
418template <class T>
419inline void copyAssignObject(T *dest, const T *src)
420{
421 using Tag = typename detail::ObjectPolicyTag<T>::type;
422 detail::copyHelpersImpl<T, Tag>::copyAssignArray(dest, src, 1);
423}
424
425template <class T>
426inline void copyAssignArray(T *dest, const T *src, unsigned int numElements)
427{
428 using Tag = typename detail::ObjectPolicyTag<T>::type;
429 detail::copyHelpersImpl<T, Tag>::copyAssignArray(dest, src, numElements);
430}
431
432template <class T>
433inline void moveAssignObject(T *dest, T *src)
434{
435 using Tag = typename detail::ObjectPolicyTag<T>::type;
436 detail::copyHelpersImpl<T, Tag>::moveAssignArray(dest, src, 1);
437}
438
439template <class T>
440inline void moveAssignArray(T *dest, T *src, unsigned int numElements)
441{
442 using Tag = typename detail::ObjectPolicyTag<T>::type;
443 detail::copyHelpersImpl<T, Tag>::moveAssignArray(dest, src, numElements);
444}
445
446}
447
448#endif
A unique pointer implementation.
Definition UniquePtr.h:118
Definition type_traits.h:161
Definition utility.h:64
Definition utility.h:62
Definition utility.h:63
Definition utility.h:65
Definition utility.h:80
Definition utility.h:61
Definition utility.h:252
Definition utility.h:169
Definition utility.h:312
Definition utility.h:288
Definition utility.h:69
Definition type_traits.h:117
Definition type_traits.h:111