Unstandard

Manual memory management routines.

Warning:
Never use functions like malloc directly unless you know what you are doing as unaligned memory which it returns may lead to random crashed, incorrect behaviour and/or performance reduction.

Also manual count * element size multiplication often leads to buffer overflow vulnerability as one forgets the check.
License
Boost License 1.0.
Authors
Denis Shelomovskij

template  isUnalignedAllocator(A)

Returns true if A is an unaligned allocator.

The following code should compile for any unaligned allocator.

A a = void;
auto p = a.tryUnalignedAllocate(cast(size_t) 1);
auto q = a.tryUnalignedReallocate(p, cast(size_t) 1, cast(size_t) 1);
a.unalignedFree(p);
static assert(is(typeof(p) == void*) && is(typeof(q) == void*));


T[]  allocate(T, A)(ref A allocator, in size_t count, in bool initialize = true, in bool gcScan = hasIndirections!T) if (isUnalignedAllocator!A);
T[]  tryAllocate(T, A)(ref A allocator, in size_t count, in bool initialize = true, in bool gcScan = hasIndirections!T) if (isUnalignedAllocator!A);

Requests a properly aligned block of memory of count * T.sizeof bytes from allocator.

If initialize is true the returned memory will be set to T.init.

If allocation fails  allocate will also call core.exception.onOutOfMemoryError which is expected to throw an core.exception.OutOfMemoryError.

Preconditions:
count != 0
Returns
Allocated array or null if allocaton failed.

void  reallocate(T, A)(ref A allocator, ref T[] array, in size_t newCount, in bool initialize = true, in bool gcScan = hasIndirections!T) if (isUnalignedAllocator!A);
bool  tryReallocate(T, A)(ref A allocator, ref T[] array, in size_t newCount, in bool initialize = true, in bool gcScan = hasIndirections!T) if (isUnalignedAllocator!A);

Requests resize of a properly aligned block of memory allocated from allocator or if ptr is null requests memory allocation like allocate/tryAllocate. Memory may be moved, but array elements content will stay the same.

If initialize is true and array.length < newCount the memory of "rest" elements will be set to T.init.

If reallocation fails array isn't changed. tryReallocate returns whether reallocation succeeded.

If reallocation fails  reallocate will also call core.exception.onOutOfMemoryError which is expected to throw an core.exception.OutOfMemoryError.

Preconditions:
newCount

void  free(T, A)(ref A allocator, ref T[] array, in bool gcScan = hasIndirections!T) if (isUnalignedAllocator!A);

Deallocates the memory referenced by array.ptr from allocator and sets array to null.

If array.ptr is null, no action occurs.


void  free(T, A)(ref A allocator, T* ptr, in bool gcScan = hasIndirections!T) if (isUnalignedAllocator!A);

Deallocates the memory referenced by ptr from allocator.

If ptr is null, no action occurs.


void*  rawAllocate(A)(ref A allocator, in size_t alignment, in size_t elementSize, in size_t count, in bool zeroFill = true, in bool gcScan = false) if (isUnalignedAllocator!A);
void*  tryRawAllocate(A)(ref A allocator, in size_t alignment, in size_t elementSize, in size_t count, in bool zeroFill = true, in bool gcScan = false) if (isUnalignedAllocator!A);

Requests an alignment-byte aligned block of memory of count * elementSize bytes from allocator.

If zeroFill is true the returned memory will be zero-filled.

If allocation fails  rawAllocate will also call core.exception.onOutOfMemoryError which is expected to throw an core.exception.OutOfMemoryError.

Preconditions:
alignment != 0 && elementSize % alignment == 0 && count != 0
Returns
A pointer to the allocated memory or null if allocaton failed.

void  rawReallocate(A)(ref A allocator, in size_t alignment, in size_t elementSize, ref void* ptr, in size_t preserveCount, in size_t newCount, in bool zeroFill = true, in bool gcScan = false) if (isUnalignedAllocator!A);
bool  tryRawReallocate(A)(ref A allocator, in size_t alignment, in size_t elementSize, ref void* ptr, in size_t preserveCount, in size_t newCount, in bool zeroFill = true, in bool gcScan = false) if (isUnalignedAllocator!A);

Requests resize of an alignment-byte aligned block of memory allocated from allocator or if ptr is null requests memory allocation like rawAllocate/tryRawAllocate. Memory may be moved, but preserveCount elements content will stay the same.

If zeroFill is true and preserveCount < newCount the memory of "unpreserved" elements will be zero-filled.

If reallocation fails ptr isn't changed. tryRawReallocate returns whether reallocation succeeded.

If reallocation fails  rawReallocate will also call core.exception.onOutOfMemoryError which is expected to throw an core.exception.OutOfMemoryError.

Preconditions:
alignment && elementSize % alignment == 0 && (ptr || !preserveCount) && preserveCount <= newCount && newCount

void  rawFree(A)(ref A allocator, in size_t alignment, void* ptr, in bool gcScan = false) if (isUnalignedAllocator!A);

Deallocates the memory referenced by ptr from allocator.

If ptr is null, no action occurs.


@property ref auto  heap();

An unaligned shared allocator which can be safely used from multiple threads.


@property ref auto  threadHeap();

An unaligned thread local allocator.

It can be faster than heap as it doesn't require a synchronization.

Note:
Class destructors are called asynchronously from GC thread on collection so  threadHeap in a destructor may reflect different thread than the one the class instance was created and used in.
Known Bugs
On non-Windows systems it behaves just like heap i.e. it may lock shared mutex.

nothrow @property ref @trusted CHeap  cHeap();

An unaligned allocator which uses C's malloc/free.


@system auto  tempAlloc(T)(in size_t count, in bool initialize = true);
@system auto  tempAlloc(T, size_t stackCount)(in size_t count, in bool initialize = true);
@system auto  tempAlloc(T, size_t stackCount : 0)(in size_t count, in bool initialize = true);

Creates temporary buffer.

Returned object has two properties: ptr to access the buffer as T* and arr to access it as T[].

The temporary buffer is valid unless returned object is destroyed. Thus if returned object is assigned to a variable the temporary is valid unless the variable goes out of scope. If returned object isn't assigned to a variable it will be destroyed at the end of creating primary expression.

If count <= stackCount or stackCount isn't specified and no more than 1 KiB is requested  tempAlloc will use stack allocated buffer, for larger requests it will allocate temporary buffer from threadHeap.

Preconditions:
count != 0
Note:
This function can be used in function call expression (like needBuffFunc( tempAlloc(n).ptr)). Incorrect usage of this function may lead to memory corruption. See WARNING in tempCString Examples section (tempCString is an analog of  tempAlloc for C strings).
See Also
unstd.c.string.tempCString