1 /************************************************************************************************************************
2 It's internal code!
3 This module contain implementation of standard functionality.
4
5 Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
6 License: BSD 3-clause, see LICENSE file in project root folder.
7 */
8 module bubel.ecs.std;
9
10 version (Emscripten) version = ECSEmscripten;
11
12 import std.traits;
13
14 version (ECSEmscripten)
15 {
16 extern (C) struct pthread_mutex_t
17 {
18 union
19 {
20 int[6] __i;
21 void[6]* __p;
22 }
23 }
24
25 extern (C) struct pthread_mutexattr_t
26 {
27 uint __attr;
28 }
29
30 extern (C) int memcmp(const void* s1, const void* s2, size_t size);
31 extern (C) void exit(int status) nothrow @nogc;
32 extern (C) void __assert(const(char)* msg, const(char)* file, uint line)
33 {
34 exit(-20);
35 }
36
37 extern (C) void free(void*) @nogc nothrow @system;
38 extern (C) void* malloc(size_t size) @nogc nothrow @system;
39 extern (C) void* realloc(void*, size_t size) @nogc nothrow @system;
40 extern (C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system;
41 extern (C) void* memset(void*, int val, size_t size) @nogc nothrow @system;
42 extern (C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system;
43 extern (C) void qsort(void* base, size_t num, size_t size,
44 int function(const void*, const void*) compar) @nogc nothrow @system;
45
46 extern (C) int pthread_mutex_lock(pthread_mutex_t* mutex) @nogc nothrow;
47 extern (C) int pthread_mutex_trylock(pthread_mutex_t* mutex) @nogc nothrow;
48 extern (C) int pthread_mutex_unlock(pthread_mutex_t* mutex) @nogc nothrow;
49 extern (C) void pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type) @nogc nothrow;
50 extern (C) void pthread_mutexattr_destroy(pthread_mutexattr_t* attr) @nogc nothrow;
51 extern (C) int pthread_mutexattr_init(pthread_mutexattr_t* attr) @nogc nothrow;
52 extern (C) int pthread_mutex_destroy(pthread_mutex_t* mutex) @nogc nothrow;
53 extern (C) int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) @nogc nothrow;
54
55 }
56 else
57 {
58 public import core.stdc.stdlib : malloc, free, realloc;
59 public import core.stdc.string : memcpy, memset;
60 public import core.stdc.stdlib : qsort;
61 }
62
63 version (ECSEmscripten)
64 {
65 }
66 else version (Windows)
67 {
68 import core.sys.windows.windows;
69
70 extern (Windows) void* _aligned_malloc(size_t size, size_t alignment) @nogc nothrow @system;
71 extern (Windows) void _aligned_free(void* ptr) @nogc nothrow @system;
72
73 version (LDC)
74 {
75 /*extern(Windows) void* __alloca(size_t size) @nogc nothrow @system;
76 alias alloca = __alloca;*/
77
78 extern (Windows) void ___chkstk_ms() @nogc nothrow @system;
79
80 extern (Windows) void __chkstk()
81 {
82 ___chkstk_ms();
83 }
84 }
85 }
86 else version (Posix)
87 {
88 import core.sys.posix.pthread;
89 import core.sys.posix.stdlib : posix_memalign;
90 }
91
92 version (ECSEmscripten)
93 {
94 private const uint max_alloca = 10000;
95 private __gshared byte[max_alloca] alloca_array;
96 private __gshared uint alloca_pos = 0;
97 export extern (C) void* alloca(size_t length) @nogc nothrow
98 {
99 if (alloca_pos + length > max_alloca)
100 alloca_pos = 0;
101 void* ret = &alloca_array[alloca_pos];
102 alloca_pos += length;
103 return ret;
104 }
105 //extern(C) void* alloca(size_t size) @nogc nothrow;
106 /*export extern(C) void* alloca(size_t length) @nogc nothrow
107 {
108 return null;
109 }*/
110 }
111 else version (D_BetterC)
112 {
113 private const uint max_alloca = 10000;
114 private __gshared byte[max_alloca] alloca_array;
115 private __gshared uint alloca_pos = 0;
116 export extern (C) void* __alloca(size_t length) @nogc nothrow
117 {
118 if (alloca_pos + length > max_alloca)
119 alloca_pos = 0;
120 void* ret = &alloca_array[alloca_pos];
121 alloca_pos += length;
122 return ret;
123 }
124
125 alias alloca = __alloca;
126
127 version (DigitalMars)
128 {
129 export extern (C) float* _memsetFloat(float* p, float value, size_t count) @nogc nothrow
130 {
131 float* pstart = p;
132 float* ptop;
133
134 for (ptop = &p[count]; p < ptop; p++)
135 *p = value;
136 return pstart;
137 }
138 }
139
140 version (GNU)
141 {
142 extern (C) void __gdc_personality_v0()
143 {
144
145 }
146 }
147 }
148 else
149 {
150 public import core.stdc.stdlib : alloca;
151 }
152
153 static struct Mallocator
154 {
155 static T[] resizeArray(T)(T[] array, size_t length) nothrow @nogc
156 {
157 T[] ret;
158
159 if (length > array.length)
160 {
161 ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length];
162 static if (__traits(isPOD, T))
163 {
164 __gshared immutable T init = T.init;
165
166 foreach (i; array.length .. ret.length)
167 {
168 memcpy(&ret[i], &init, T.sizeof);
169 }
170 }
171 else
172 {
173 static import std.conv;
174
175 foreach (i; array.length .. ret.length)
176 {
177 std.conv.emplace(&ret[i]);
178 }
179 }
180 }
181 else
182 {
183 static if (__traits(hasMember, T, "__xdtor"))
184 {
185 foreach (i; length .. array.length)
186 {
187 array[i].__xdtor();
188 }
189 }
190 else static if (__traits(hasMember, T, "__dtor"))
191 {
192 foreach (i; length .. array.length)
193 {
194 array[i].__dtor();
195 }
196 }
197 ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length];
198 }
199
200 return ret;
201 }
202
203 static T[] makeArray(T)(size_t length) nothrow @nogc
204 {
205 T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length];
206
207 static if (__traits(isPOD, T))
208 {
209 __gshared immutable T init = T.init;
210
211 foreach (i; 0 .. ret.length)
212 {
213 memcpy(&ret[i], &init, T.sizeof);
214 }
215 }
216 else
217 {
218 static import std.conv;
219
220 foreach (i; 0 .. ret.length)
221 {
222 std.conv.emplace(&ret[i]);
223 }
224 }
225 return ret;
226 }
227
228 static T[] alignMakeArray(T)(size_t length, size_t alignment) nothrow @nogc
229 {
230 T[] ret = (cast(T*) alignAlloc(T.sizeof * length, alignment))[0 .. length];
231
232 static if (__traits(isPOD, T))
233 {
234 __gshared immutable T init = T.init;
235
236 foreach (i; 0 .. ret.length)
237 {
238 memcpy(&ret[i], &init, T.sizeof);
239 }
240 }
241 else
242 {
243 static import std.conv;
244
245 foreach (i; 0 .. ret.length)
246 {
247 std.conv.emplace(&ret[i]);
248 }
249 }
250 return ret;
251 }
252
253 static T[] makeArray(T)(size_t length, T initializer) nothrow @nogc
254 {
255 T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length];
256 foreach (ref v; ret)
257 v = initializer;
258 return ret;
259 }
260
261 static T[] expandArray(T)(T[] array, size_t length) nothrow @nogc
262 {
263 size_t new_length = array.length + length;
264 return (cast(T*) realloc(array.ptr, T.sizeof * new_length))[0 .. new_length];
265 }
266
267 static T[] makeArray(T)(T[] array) nothrow @nogc
268 {
269 T[] ret = (cast(T*) malloc(T.sizeof * array.length))[0 .. array.length]; //Mallocator.makeArray!(T)(array.length);
270 foreach (i, ref v; ret)
271 v = array[i];
272 return ret;
273 }
274
275 static T* make(T, Args...)(Args args)
276 {
277 T* ret = cast(T*) malloc(T.sizeof);
278 static import std.conv;
279
280 static if (__traits(isPOD, T))
281 {
282 __gshared immutable T init = T.init;
283 memcpy(ret, &init, T.sizeof);
284 }
285 else static if (is(T == struct))
286 std.conv.emplace(ret, args);
287 return ret;
288 }
289
290 static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc
291 {
292 void* ret;
293 version (Posix)
294 posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length);
295 else version (Windows)
296 ret = _aligned_malloc(length, alignment);
297 else version (ECSEmscripten)
298 posix_memalign(&ret, alignment, length); //malloc(length);
299 else
300 static assert(0, "Unimplemented platform!");
301 return ret;
302 }
303
304 static void dispose(T)(T object)
305 {
306 static if (isArray!T)
307 {
308 alias TT = PointerTarget!(typeof(object.ptr));
309 static if (!isPointer!TT)
310 {
311 static if (__traits(hasMember, TT, "__xdtor"))
312 {
313 foreach (ref TT t; object)
314 t.__xdtor();
315 }
316 else static if (__traits(hasMember, TT, "__dtor"))
317 {
318 foreach (TT t; object)
319 t.__dtor();
320 }
321 }
322 free(cast(void*) object.ptr);
323 }
324 else
325 {
326 static if (__traits(hasMember, T, "__xdtor"))
327 object.__xdtor();
328 else static if (__traits(hasMember, T, "__dtor"))
329 object.__dtor();
330 free(cast(void*) object);
331 }
332 }
333
334 static void alignDispose(T)(T object)
335 {
336 static if (__traits(hasMember, T, "__xdtor"))
337 object.__xdtor();
338 else static if (__traits(hasMember, T, "__dtor"))
339 object.__dtor();
340 version (Posix)
341 free(cast(void*) object);
342 else version (Windows)
343 _aligned_free(cast(void*) object);
344 else version (ECSEmscripten)
345 free(cast(void*) object);
346 else
347 static assert(0, "Unimplemented platform!");
348 }
349 }
350
351 struct Mutex
352 {
353
354 version (ECSEmscripten)
355 {
356 void initialize() nothrow @nogc
357 {
358 pthread_mutexattr_t attr = void;
359
360 //pthread_mutexattr_init(&attr);
361
362 //pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
363 pthread_mutex_init(cast(pthread_mutex_t*)&m_handle, &attr);
364
365 //pthread_mutexattr_destroy(&attr);
366 }
367
368 void destroy() nothrow @nogc
369 {
370 pthread_mutex_destroy(&m_handle);
371 }
372
373 void lock() nothrow @nogc
374 {
375 pthread_mutex_lock(&m_handle);
376 }
377
378 void unlock() nothrow @nogc
379 {
380 pthread_mutex_unlock(&m_handle);
381 }
382
383 int tryLock() nothrow @nogc
384 {
385 return pthread_mutex_trylock(&m_handle) == 0;
386 }
387
388 private pthread_mutex_t m_handle;
389 }
390 else version (Windows)
391 {
392 void initialize() nothrow @nogc
393 {
394 InitializeCriticalSection(cast(CRITICAL_SECTION*)&m_handle);
395 }
396
397 void destroy() nothrow @nogc
398 {
399 DeleteCriticalSection(&m_handle);
400 }
401
402 void lock() nothrow @nogc
403 {
404 EnterCriticalSection(&m_handle);
405 }
406
407 void unlock() nothrow @nogc
408 {
409 LeaveCriticalSection(&m_handle);
410 }
411
412 int tryLock() nothrow @nogc
413 {
414 return TryEnterCriticalSection(&m_handle) != 0;
415 }
416
417 CRITICAL_SECTION m_handle;
418 }
419 else version (Posix)
420 {
421 void initialize() nothrow @nogc
422 {
423 pthread_mutexattr_t attr = void;
424
425 pthread_mutexattr_init(&attr);
426
427 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
428 pthread_mutex_init(cast(pthread_mutex_t*)&m_handle, &attr);
429
430 pthread_mutexattr_destroy(&attr);
431 }
432
433 void destroy() nothrow @nogc
434 {
435 pthread_mutex_destroy(&m_handle);
436 }
437
438 void lock() nothrow @nogc
439 {
440 pthread_mutex_lock(&m_handle);
441 }
442
443 void unlock() nothrow @nogc
444 {
445 pthread_mutex_unlock(&m_handle);
446 }
447
448 int tryLock() nothrow @nogc
449 {
450 return pthread_mutex_trylock(&m_handle) == 0;
451 }
452
453 private pthread_mutex_t m_handle;
454 }
455 else
456 static assert(0, "unsupported platform!");
457 }