summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/tanya/memory/mallocator.d173
1 files changed, 173 insertions, 0 deletions
diff --git a/source/tanya/memory/mallocator.d b/source/tanya/memory/mallocator.d
new file mode 100644
index 0000000..f878ae8
--- /dev/null
+++ b/source/tanya/memory/mallocator.d
@@ -0,0 +1,173 @@
+/* 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.mallocator;
+
+import tanya.memory.allocator;
+import core.exception;
+import core.stdc.stdlib;
+import std.algorithm.comparison;
+
+/**
+ * Wrapper for malloc/realloc/free from the C standard library.
+ */
+class Mallocator : Allocator
+{
+ /**
+ * Allocates $(D_PARAM size) bytes of memory.
+ *
+ * Params:
+ * size = Amount of memory to allocate.
+ *
+ * Returns: The pointer to the new allocated memory.
+ */
+ void[] allocate(size_t size) shared @nogc nothrow
+ {
+ if (!size)
+ {
+ return null;
+ }
+ auto p = malloc(size + psize);
+
+ if (!p)
+ {
+ onOutOfMemoryError();
+ }
+ return p[psize.. psize + size];
+ }
+
+ ///
+ @nogc nothrow unittest
+ {
+ auto p = Mallocator.instance.allocate(20);
+
+ assert(p.length == 20);
+
+ Mallocator.instance.deallocate(p);
+ }
+
+ /**
+ * Deallocates a memory block.
+ *
+ * Params:
+ * p = A pointer to the memory block to be freed.
+ *
+ * Returns: Whether the deallocation was successful.
+ */
+ bool deallocate(void[] p) shared @nogc nothrow
+ {
+ if (p !is null)
+ {
+ free(p.ptr - psize);
+ }
+ return true;
+ }
+
+ ///
+ @nogc nothrow unittest
+ {
+ void[] p;
+ assert(Mallocator.instance.deallocate(p));
+
+ p = Mallocator.instance.allocate(10);
+ assert(Mallocator.instance.deallocate(p));
+ }
+
+ /**
+ * Increases or decreases the size of a memory block.
+ *
+ * Params:
+ * p = A pointer to the memory block.
+ * size = Size of the reallocated block.
+ *
+ * Returns: Whether the reallocation was successful.
+ */
+ bool reallocate(ref void[] p, size_t size) shared @nogc nothrow
+ {
+ if (!size)
+ {
+ deallocate(p);
+ p = null;
+ return true;
+ }
+ else if (p is null)
+ {
+ p = allocate(size);
+ return true;
+ }
+ auto r = realloc(p.ptr - psize, size + psize);
+
+ if (!r)
+ {
+ onOutOfMemoryError();
+ }
+ p = r[psize.. psize + size];
+
+ return true;
+ }
+
+ ///
+ @nogc nothrow unittest
+ {
+ void[] p;
+
+ Mallocator.instance.reallocate(p, 20);
+ assert(p.length == 20);
+
+ Mallocator.instance.reallocate(p, 30);
+ assert(p.length == 30);
+
+ Mallocator.instance.reallocate(p, 10);
+ assert(p.length == 10);
+
+ Mallocator.instance.reallocate(p, 0);
+ assert(p is null);
+ }
+
+ /**
+ * Returns: The alignment offered.
+ */
+ @property immutable(uint) alignment() shared const @safe pure nothrow
+ {
+ return cast(uint) max(double.alignof, real.alignof);
+ }
+
+ /**
+ * Static allocator instance and initializer.
+ *
+ * Returns: The global $(D_PSYMBOL Allocator) instance.
+ */
+ static @property ref shared(Mallocator) instance() @nogc nothrow
+ {
+ if (instance_ is null)
+ {
+ immutable size = __traits(classInstanceSize, Mallocator) + psize;
+ void* p = malloc(size);
+
+ if (p is null)
+ {
+ onOutOfMemoryError();
+ }
+ p[psize..size] = typeid(Mallocator).initializer[];
+ instance_ = cast(shared Mallocator) p[psize..size].ptr;
+ }
+ return instance_;
+ }
+
+ ///
+ @nogc nothrow unittest
+ {
+ assert(instance is instance);
+ }
+
+ private enum psize = 8;
+
+ private shared static Mallocator instance_;
+}