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 }