-moved system destroy functionality to System structure "destroy()" function -now arrays are properly destroyed (with destructor calling (__xdtor)) -fixed bug which makes BlockAllocator crashing after freeing it's memory -fixed many smaller memory leaks
457 lines
12 KiB
D
457 lines
12 KiB
D
/************************************************************************************************************************
|
|
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 : 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!");
|
|
}
|