diff options
Diffstat (limited to 'source/tanya/memory/package.d')
| -rw-r--r-- | source/tanya/memory/package.d | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/source/tanya/memory/package.d b/source/tanya/memory/package.d new file mode 100644 index 0000000..67114df --- /dev/null +++ b/source/tanya/memory/package.d @@ -0,0 +1,207 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Copyright: Eugene Wissner 2016. + * 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) +{ + import core.sys.windows.windows; +} +else version (Posix) +{ + public import tanya.memory.ullocator; + import core.sys.posix.pthread; +} + +@nogc: + +version (Windows) +{ + 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) + { + pthread_mutex_destroy(mtx) && assert(0); + } +} + +@property void defaultAllocator(Allocator allocator) @safe nothrow +{ + _defaultAllocator = allocator; +} + +@property Allocator defaultAllocator() @safe nothrow +{ + return _defaultAllocator; +} + +static this() @safe nothrow +{ + defaultAllocator = Ullocator.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 Allocator _defaultAllocator; |
