/************************************************************************************************************************ It's internal code! This module contain implementation of standard functionality. Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.std; version (Emscripten) version = ECSEmscripten; import std.traits; version (ECSEmscripten) { extern (C) struct pthread_mutex_t { union { int[6] __i; void[6]* __p; } } extern (C) struct pthread_mutexattr_t { uint __attr; } extern (C) int memcmp(const void* s1, const void* s2, size_t size); extern (C) void exit(int status) nothrow @nogc; extern (C) void __assert(const(char)* msg, const(char)* file, uint line) { exit(-20); } extern (C) void free(void*) @nogc nothrow @system; extern (C) void* malloc(size_t size) @nogc nothrow @system; extern (C) void* realloc(void*, size_t size) @nogc nothrow @system; extern (C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system; extern (C) void* memset(void*, int val, size_t size) @nogc nothrow @system; extern (C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system; extern (C) void qsort(void* base, size_t num, size_t size, int function(const void*, const void*) compar) @nogc nothrow @system; extern (C) int pthread_mutex_lock(pthread_mutex_t* mutex) @nogc nothrow; extern (C) int pthread_mutex_trylock(pthread_mutex_t* mutex) @nogc nothrow; extern (C) int pthread_mutex_unlock(pthread_mutex_t* mutex) @nogc nothrow; extern (C) void pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type) @nogc nothrow; extern (C) void pthread_mutexattr_destroy(pthread_mutexattr_t* attr) @nogc nothrow; extern (C) int pthread_mutexattr_init(pthread_mutexattr_t* attr) @nogc nothrow; extern (C) int pthread_mutex_destroy(pthread_mutex_t* mutex) @nogc nothrow; extern (C) int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) @nogc nothrow; } else { public import core.stdc.stdlib : malloc, free, realloc; public import core.stdc.string : memcpy, memset; public import core.stdc.stdlib : qsort; } version (ECSEmscripten) { } else version (Windows) { import core.sys.windows.windows; extern (Windows) void* _aligned_malloc(size_t size, size_t alignment) @nogc nothrow @system; extern (Windows) void _aligned_free(void* ptr) @nogc nothrow @system; version (LDC) { /*extern(Windows) void* __alloca(size_t size) @nogc nothrow @system; alias alloca = __alloca;*/ extern (Windows) void ___chkstk_ms() @nogc nothrow @system; extern (Windows) void __chkstk() { ___chkstk_ms(); } } } else version (Posix) { import core.sys.posix.pthread; import core.sys.posix.stdlib : posix_memalign; } version (ECSEmscripten) { private const uint max_alloca = 10000; private __gshared byte[max_alloca] alloca_array; private __gshared uint alloca_pos = 0; export extern (C) void* alloca(size_t length) @nogc nothrow { if (alloca_pos + length > max_alloca) alloca_pos = 0; void* ret = &alloca_array[alloca_pos]; alloca_pos += length; return ret; } //extern(C) void* alloca(size_t size) @nogc nothrow; /*export extern(C) void* alloca(size_t length) @nogc nothrow { return null; }*/ } else version (D_BetterC) { private const uint max_alloca = 10000; private __gshared byte[max_alloca] alloca_array; private __gshared uint alloca_pos = 0; export extern (C) void* __alloca(size_t length) @nogc nothrow { if (alloca_pos + length > max_alloca) alloca_pos = 0; void* ret = &alloca_array[alloca_pos]; alloca_pos += length; return ret; } alias alloca = __alloca; version (DigitalMars) { export extern (C) float* _memsetFloat(float* p, float value, size_t count) @nogc nothrow { float* pstart = p; float* ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } } version (GNU) { extern (C) void __gdc_personality_v0() { } } } else { public import core.stdc.stdlib : alloca; } static struct Mallocator { static T[] resizeArray(T)(T[] array, size_t length) nothrow @nogc { T[] ret; if (length > array.length) { ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length]; static if (__traits(isPOD, T)) { __gshared immutable T init = T.init; foreach (i; array.length .. ret.length) { memcpy(&ret[i], &init, T.sizeof); } } else { static import std.conv; foreach (i; array.length .. ret.length) { std.conv.emplace(&ret[i]); } } } else { static if (__traits(hasMember, T, "__xdtor")) { foreach (i; length .. array.length) { array[i].__xdtor(); } } else static if (__traits(hasMember, T, "__dtor")) { foreach (i; length .. array.length) { array[i].__dtor(); } } ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length]; } return ret; } static T[] makeArray(T)(size_t length) nothrow @nogc { T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length]; static if (__traits(isPOD, T)) { __gshared immutable T init = T.init; foreach (i; 0 .. ret.length) { memcpy(&ret[i], &init, T.sizeof); } } else { static import std.conv; foreach (i; 0 .. ret.length) { std.conv.emplace(&ret[i]); } } return ret; } static T[] alignMakeArray(T)(size_t length, size_t alignment) nothrow @nogc { T[] ret = (cast(T*) alignAlloc(T.sizeof * length, alignment))[0 .. length]; static if (__traits(isPOD, T)) { __gshared immutable T init = T.init; foreach (i; 0 .. ret.length) { memcpy(&ret[i], &init, T.sizeof); } } else { static import std.conv; foreach (i; 0 .. ret.length) { std.conv.emplace(&ret[i]); } } return ret; } static T[] makeArray(T)(size_t length, T initializer) nothrow @nogc { T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length]; foreach (ref v; ret) v = initializer; return ret; } static T[] expandArray(T)(T[] array, size_t length) nothrow @nogc { size_t new_length = array.length + length; return (cast(T*) realloc(array.ptr, T.sizeof * new_length))[0 .. new_length]; } static T[] makeArray(T)(T[] array) nothrow @nogc { T[] ret = (cast(T*) malloc(T.sizeof * array.length))[0 .. array.length]; //Mallocator.makeArray!(T)(array.length); foreach (i, ref v; ret) v = array[i]; return ret; } static T* make(T, Args...)(Args args) { T* ret = cast(T*) malloc(T.sizeof); static import std.conv; static if (__traits(isPOD, T)) { __gshared immutable T init = T.init; memcpy(ret, &init, T.sizeof); } else static if (is(T == struct)) std.conv.emplace(ret, args); return ret; } static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc { void* ret; version (Posix) posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length); else version (Windows) ret = _aligned_malloc(length, alignment); else version (ECSEmscripten) posix_memalign(&ret, alignment, length); //malloc(length); else static assert(0, "Unimplemented platform!"); return ret; } static void dispose(T)(T object) { static if (isArray!T) { alias TT = PointerTarget!(typeof(object.ptr)); static if (!isPointer!TT) { static if (__traits(hasMember, TT, "__xdtor")) { foreach (ref TT t; object) t.__xdtor(); } else static if (__traits(hasMember, TT, "__dtor")) { foreach (TT t; object) t.__dtor(); } } free(cast(void*) object.ptr); } else { static if (__traits(hasMember, T, "__xdtor")) object.__xdtor(); else static if (__traits(hasMember, T, "__dtor")) object.__dtor(); free(cast(void*) object); } } static void alignDispose(T)(T object) { static if (__traits(hasMember, T, "__xdtor")) object.__xdtor(); else static if (__traits(hasMember, T, "__dtor")) object.__dtor(); version (Posix) free(cast(void*) object); else version (Windows) _aligned_free(cast(void*) object); else version (ECSEmscripten) free(cast(void*) object); else static assert(0, "Unimplemented platform!"); } } struct Mutex { version (ECSEmscripten) { void initialize() nothrow @nogc { pthread_mutexattr_t attr = void; //pthread_mutexattr_init(&attr); //pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(cast(pthread_mutex_t*)&m_handle, &attr); //pthread_mutexattr_destroy(&attr); } void destroy() nothrow @nogc { pthread_mutex_destroy(&m_handle); } void lock() nothrow @nogc { pthread_mutex_lock(&m_handle); } void unlock() nothrow @nogc { pthread_mutex_unlock(&m_handle); } int tryLock() nothrow @nogc { return pthread_mutex_trylock(&m_handle) == 0; } private pthread_mutex_t m_handle; } else version (Windows) { void initialize() nothrow @nogc { InitializeCriticalSection(cast(CRITICAL_SECTION*)&m_handle); } void destroy() nothrow @nogc { DeleteCriticalSection(&m_handle); } void lock() nothrow @nogc { EnterCriticalSection(&m_handle); } void unlock() nothrow @nogc { LeaveCriticalSection(&m_handle); } int tryLock() nothrow @nogc { return TryEnterCriticalSection(&m_handle) != 0; } CRITICAL_SECTION m_handle; } else version (Posix) { void initialize() nothrow @nogc { pthread_mutexattr_t attr = void; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(cast(pthread_mutex_t*)&m_handle, &attr); pthread_mutexattr_destroy(&attr); } void destroy() nothrow @nogc { pthread_mutex_destroy(&m_handle); } void lock() nothrow @nogc { pthread_mutex_lock(&m_handle); } void unlock() nothrow @nogc { pthread_mutex_unlock(&m_handle); } int tryLock() nothrow @nogc { return pthread_mutex_trylock(&m_handle) == 0; } private pthread_mutex_t m_handle; } else static assert(0, "unsupported platform!"); }