Use dispose from std.experimental

This commit is contained in:
2016-10-05 13:12:50 +02:00
parent 9241ec503c
commit 721bb110e5
11 changed files with 98 additions and 251 deletions

View File

@ -7,12 +7,17 @@
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
*/
*/
module tanya.memory.allocator;
import std.experimental.allocator;
import std.traits;
version (unittest)
{
import tanya.memory : defaultAllocator;
}
/**
* Allocator interface.
*/
@ -80,5 +85,23 @@ bool resizeArray(T)(shared Allocator allocator,
return true;
}
///
unittest
{
int[] p;
defaultAllocator.resizeArray(p, 20);
assert(p.length == 20);
defaultAllocator.resizeArray(p, 30);
assert(p.length == 30);
defaultAllocator.resizeArray(p, 10);
assert(p.length == 10);
defaultAllocator.resizeArray(p, 0);
assert(p is null);
}
enum bool isFinalizable(T) = is(T == class) || is(T == interface)
|| hasElaborateDestructor!T || isDynamicArray!T;

View File

@ -7,199 +7,23 @@
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
*/
*/
module tanya.memory;
public import tanya.memory.allocator;
public import std.experimental.allocator : make, makeArray, expandArray, shrinkArray, IAllocator;
import core.atomic;
import core.stdc.stdlib;
import std.traits;
version (Windows)
public
{
import core.sys.windows.windows;
}
else version (Posix)
{
public import tanya.memory.mmappool;
import core.sys.posix.pthread;
import tanya.memory.allocator;
import std.experimental.allocator : make, dispose, shrinkArray, expandArray, makeArray, dispose;
}
version (Windows)
shared Allocator allocator;
@property ref shared(Allocator) defaultAllocator()
{
package alias Mutex = CRITICAL_SECTION;
package alias destroyMutex = DeleteCriticalSection;
}
else version (Posix)
{
package alias Mutex = pthread_mutex_t;
package void destroyMutex(pthread_mutex_t* mtx)
import tanya.memory.mallocator;
if (allocator is null)
{
pthread_mutex_destroy(mtx) && assert(0);
}
allocator = Mallocator.instance;
}
return allocator;
}
@property void defaultAllocator(shared Allocator allocator) @safe nothrow
{
_defaultAllocator = allocator;
}
@property shared(Allocator) defaultAllocator() @safe nothrow
{
return _defaultAllocator;
}
static this() @safe nothrow
{
defaultAllocator = MmapPool.instance;
}
package struct Monitor
{
Object.Monitor impl; // for user-level monitors
void delegate(Object) @nogc[] devt; // for internal monitors
size_t refs; // reference count
version (Posix)
{
Mutex mtx;
}
}
package @property ref shared(Monitor*) monitor(Object h) pure nothrow
{
return *cast(shared Monitor**)&h.__monitor;
}
/**
* Destroys and then deallocates (using $(D_PARAM allocator)) the class
* object referred to by a $(D_KEYWORD class) or $(D_KEYWORD interface)
* reference. It is assumed the respective entities had been allocated with
* the same allocator.
*
* Params:
* A = The type of the allocator used for the ojbect allocation.
* T = The type of the object that should be destroyed.
* allocator = The allocator used for the object allocation.
* p = The object should be destroyed.
*/
void finalize(A, T)(auto ref A allocator, ref T p)
if (is(T == class) || is(T == interface))
{
static if (is(T == interface))
{
auto ob = cast(Object) p;
}
else
{
alias ob = p;
}
auto pp = cast(void*) ob;
auto ppv = cast(void**) pp;
if (!pp || !*ppv)
{
return;
}
auto support = (cast(void*) ob)[0 .. typeid(ob).initializer.length];
auto pc = cast(ClassInfo*) *ppv;
auto c = *pc;
do
{
if (c.destructor)
{
(cast(void function(Object)) c.destructor)(ob);
}
} while ((c = c.base) !is null);
// Take care of monitors for synchronized blocks
if (ppv[1])
{
shared(Monitor)* m = atomicLoad!(MemoryOrder.acq)(ob.monitor);
if (m !is null)
{
auto mc = cast(Monitor*) m;
if (!atomicOp!("-=")(m.refs, cast(size_t) 1))
{
foreach (v; mc.devt)
{
if (v)
{
v(ob);
}
}
if (mc.devt.ptr)
{
free(mc.devt.ptr);
}
destroyMutex(&mc.mtx);
free(mc);
atomicStore!(MemoryOrder.rel)(ob.monitor, null);
}
}
}
*ppv = null;
allocator.deallocate(support);
p = null;
}
/// Ditto.
void finalize(A, T)(auto ref A allocator, ref T *p)
if (is(T == struct))
{
if (p is null)
{
return;
}
static if (hasElaborateDestructor!T)
{
*p.__xdtor();
}
allocator.deallocate((cast(void*)p)[0 .. T.sizeof]);
p = null;
}
/// Ditto.
void finalize(A, T)(auto ref A allocator, ref T[] p)
{
static if (hasElaborateDestructor!T)
{
foreach (ref e; p)
{
finalize(allocator, e);
}
}
allocator.deallocate(p);
p = null;
}
bool resizeArray(T, A)(auto ref A allocator, ref T[] array, in size_t length)
@trusted
{
if (length == array.length)
{
return true;
}
if (array is null && length > 0)
{
array = makeArray!T(allocator, length);
return array !is null;
}
if (length == 0)
{
finalize(allocator, array);
return true;
}
void[] buf = array;
if (!allocator.reallocate(buf, length * T.sizeof))
{
return false;
}
array = cast(T[]) buf;
return true;
}
enum bool isFinalizable(T) = is(T == class) || is(T == interface)
|| hasElaborateDestructor!T || isDynamicArray!T;
private shared Allocator _defaultAllocator;