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 }