/************************************************************************************************************************ It's internal code! This module contain implementation of standard functionality. Copyright: Copyright © 2018-2019, 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; } 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 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; } } else { public import core.stdc.stdlib : alloca; } static struct Mallocator { static T[] makeArray(T)(size_t length) nothrow @nogc { T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length]; static if(__traits(isPOD, T)) { static 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)) { static 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) nothrow @nogc { 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!"); }