summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-04-16 20:15:11 +0200
committerEugen Wissner <belka@caraus.de>2017-04-16 20:15:11 +0200
commit4b1cd2cbfd0ae9a3cfa598cb54a86c8e39a9763a (patch)
tree17b34b36bb1900dd2f154b80587f09483a1bc953
parentcd944a61b798a22e1ac05535abed6c3529134889 (diff)
parent628153e2e88063a9c20b39ec64c05ef0007fb0b9 (diff)
downloadtanya-4b1cd2cbfd0ae9a3cfa598cb54a86c8e39a9763a.tar.gz
Merge branch 'master' into utf8string
-rw-r--r--source/tanya/memory/package.d67
-rw-r--r--source/tanya/memory/types.d229
2 files changed, 168 insertions, 128 deletions
diff --git a/source/tanya/memory/package.d b/source/tanya/memory/package.d
index 5e05943..352476f 100644
--- a/source/tanya/memory/package.d
+++ b/source/tanya/memory/package.d
@@ -11,6 +11,7 @@
module tanya.memory;
import core.exception;
+import std.algorithm.iteration;
public import std.experimental.allocator : make;
import std.traits;
public import tanya.memory.allocator;
@@ -87,8 +88,8 @@ shared Allocator allocator;
shared static this() nothrow @trusted @nogc
{
- import tanya.memory.mallocator;
- allocator = Mallocator.instance;
+ import tanya.memory.mmappool;
+ allocator = MmapPool.instance;
}
@property ref shared(Allocator) defaultAllocator() nothrow @safe @nogc
@@ -202,41 +203,33 @@ private unittest
assert(p is null);
}
-/**
- * Destroys and deallocates $(D_PARAM p) of type $(D_PARAM T).
- * It is assumed the respective entities had been allocated with the same
- * allocator.
- *
- * Params:
- * T = Type of $(D_PARAM p).
- * allocator = Allocator the $(D_PARAM p) was allocated with.
- * p = Object or array to be destroyed.
+/*
+ * Destroys the object.
+ * Returns the memory should be freed.
*/
-void dispose(T)(shared Allocator allocator, auto ref T* p)
+package(tanya) void[] finalize(T)(ref T* p)
{
static if (hasElaborateDestructor!T)
{
destroy(*p);
}
- () @trusted { allocator.deallocate((cast(void*) p)[0 .. T.sizeof]); }();
- p = null;
+ return (cast(void*) p)[0 .. T.sizeof];
}
-/// Ditto.
-void dispose(T)(shared Allocator allocator, auto ref T p)
+package(tanya) void[] finalize(T)(ref T p)
if (is(T == class) || is(T == interface))
{
if (p is null)
{
- return;
+ return null;
}
static if (is(T == interface))
{
version(Windows)
{
import core.sys.windows.unknwn : IUnknown;
- static assert(!is(T: IUnknown), "COM interfaces can't be destroyed in "
- ~ __PRETTY_FUNCTION__);
+ static assert(!is(T : IUnknown), "COM interfaces can't be destroyed in "
+ ~ __PRETTY_FUNCTION__);
}
auto ob = cast(Object) p;
}
@@ -244,19 +237,13 @@ void dispose(T)(shared Allocator allocator, auto ref T p)
{
alias ob = p;
}
- auto ptr = cast(void *) ob;
-
+ auto ptr = cast(void*) ob;
auto support = ptr[0 .. typeid(ob).initializer.length];
- scope (success)
- {
- () @trusted { allocator.deallocate(support); }();
- p = null;
- }
auto ppv = cast(void**) ptr;
if (!*ppv)
{
- return;
+ return null;
}
auto pc = cast(ClassInfo*) *ppv;
scope (exit)
@@ -280,21 +267,35 @@ void dispose(T)(shared Allocator allocator, auto ref T p)
{
_d_monitordelete(cast(Object) ptr, true);
}
+ return support;
}
-/// Ditto.
-void dispose(T)(shared Allocator allocator, auto ref T[] p)
+package(tanya) void[] finalize(T)(ref T[] p)
{
static if (hasElaborateDestructor!(typeof(p[0])))
{
- import std.algorithm.iteration;
- p.each!(e => destroy(e));
+ p.each!((ref e) => destroy(e));
}
- () @trusted { allocator.deallocate(p); }();
+ return p;
+}
+
+/**
+ * Destroys and deallocates $(D_PARAM p) of type $(D_PARAM T).
+ * It is assumed the respective entities had been allocated with the same
+ * allocator.
+ *
+ * Params:
+ * T = Type of $(D_PARAM p).
+ * allocator = Allocator the $(D_PARAM p) was allocated with.
+ * p = Object or array to be destroyed.
+ */
+void dispose(T)(shared Allocator allocator, auto ref T p)
+{
+ () @trusted { allocator.deallocate(finalize(p)); }();
p = null;
}
-unittest
+private unittest
{
struct S
{
diff --git a/source/tanya/memory/types.d b/source/tanya/memory/types.d
index 1207d73..af0f1ac 100644
--- a/source/tanya/memory/types.d
+++ b/source/tanya/memory/types.d
@@ -14,91 +14,91 @@ import core.exception;
import std.algorithm.comparison;
import std.algorithm.mutation;
import std.conv;
+import std.range;
import std.traits;
import tanya.memory;
-/**
- * Reference-counted object containing a $(D_PARAM T) value as payload.
- * $(D_PSYMBOL RefCounted) keeps track of all references of an object, and
- * when the reference count goes down to zero, frees the underlying store.
- *
- * Params:
- * T = Type of the reference-counted value.
- */
-struct RefCounted(T)
+package(tanya) final class RefCountedStore(T)
{
- static if (is(T == class) || is(T == interface))
+ T payload;
+ size_t counter = 1;
+
+ size_t opUnary(string op)()
+ if (op == "--" || op == "++")
+ in
{
- private alias Payload = T;
+ assert(counter > 0);
}
- else
+ body
{
- private alias Payload = T*;
+ mixin("return " ~ op ~ "counter;");
}
- private class Storage
+ int opCmp(size_t counter)
{
- private Payload payload;
- private size_t counter = 1;
-
- private final size_t opUnary(string op)() pure nothrow @safe @nogc
- if (op == "--" || op == "++")
- in
+ if (this.counter > counter)
{
- assert(counter > 0);
+ return 1;
}
- body
+ else if (this.counter < counter)
{
- mixin("return " ~ op ~ "counter;");
+ return -1;
}
-
- private final int opCmp(size_t counter) const pure nothrow @safe @nogc
- {
- if (this.counter > counter)
- {
- return 1;
- }
- else if (this.counter < counter)
- {
- return -1;
- }
- else
- {
- return 0;
- }
- }
-
- private final int opEquals(size_t counter) const pure nothrow @safe @nogc
+ else
{
- return this.counter == counter;
+ return 0;
}
}
- private final class RefCountedStorage : Storage
+ int opEquals(size_t counter)
{
- private shared Allocator allocator;
+ return this.counter == counter;
+ }
+}
- this(shared Allocator allocator) pure nothrow @safe @nogc
- in
- {
- assert(allocator !is null);
- }
- body
- {
- this.allocator = allocator;
- }
+private void separateDeleter(T)(RefCountedStore!T storage,
+ shared Allocator allocator)
+{
+ allocator.dispose(storage.payload);
+ allocator.dispose(storage);
+}
- ~this() nothrow @nogc
- {
- allocator.dispose(payload);
- }
+private void unifiedDeleter(T)(RefCountedStore!T storage,
+ shared Allocator allocator)
+{
+ auto ptr1 = finalize(storage);
+ auto ptr2 = finalize(storage.payload);
+ allocator.deallocate(ptr1.ptr[0 .. ptr1.length + ptr2.length]);
+}
+
+/**
+ * Reference-counted object containing a $(D_PARAM T) value as payload.
+ * $(D_PSYMBOL RefCounted) keeps track of all references of an object, and
+ * when the reference count goes down to zero, frees the underlying store.
+ *
+ * Params:
+ * T = Type of the reference-counted value.
+ */
+struct RefCounted(T)
+{
+ static if (is(T == class) || is(T == interface) || isArray!T)
+ {
+ private alias Payload = T;
+ }
+ else
+ {
+ private alias Payload = T*;
}
+ private alias Storage = RefCountedStore!Payload;
private Storage storage;
+ private void function(Storage storage,
+ shared Allocator allocator) @nogc deleter;
invariant
{
assert(storage is null || allocator_ !is null);
+ assert(storage is null || deleter !is null);
}
/**
@@ -112,11 +112,13 @@ struct RefCounted(T)
*
* Precondition: $(D_INLINECODE allocator !is null)
*/
- this(Payload value, shared Allocator allocator = defaultAllocator)
+ this()(auto ref Payload value,
+ shared Allocator allocator = defaultAllocator)
{
this(allocator);
- storage = allocator.make!RefCountedStorage(allocator);
- move(value, storage.payload);
+ this.storage = allocator.make!Storage();
+ this.deleter = &separateDeleter!Payload;
+ move(value, this.storage.payload);
}
/// Ditto.
@@ -148,9 +150,9 @@ struct RefCounted(T)
*/
~this()
{
- if (storage !is null && !(storage.counter && --storage))
+ if (this.storage !is null && !(this.storage.counter && --this.storage))
{
- allocator_.dispose(storage);
+ deleter(storage, allocator);
}
}
@@ -170,54 +172,48 @@ struct RefCounted(T)
* Params:
* rhs = $(D_KEYWORD this).
*/
- ref typeof(this) opAssign(Payload rhs)
+ ref typeof(this) opAssign()(auto ref Payload rhs)
{
- if (storage is null)
+ if (this.storage is null)
{
- storage = allocator.make!RefCountedStorage(allocator);
+ this.storage = allocator.make!Storage();
+ this.deleter = &separateDeleter!Payload;
}
- else if (storage > 1)
+ else if (this.storage > 1)
{
- --storage;
- storage = allocator.make!RefCountedStorage(allocator);
- }
- else if (cast(RefCountedStorage) storage is null)
- {
- // Created with refCounted. Always destroyed togethter with the pointer.
- assert(storage.counter != 0);
- allocator.dispose(storage);
- storage = allocator.make!RefCountedStorage(allocator);
+ --this.storage;
+ this.storage = allocator.make!Storage();
+ this.deleter = &separateDeleter!Payload;
}
else
{
- allocator.dispose(storage.payload);
+ // Created with refCounted. Always destroyed togethter with the pointer.
+ assert(this.storage.counter != 0);
+ finalize(this.storage.payload);
+ this.storage.payload = Payload.init;
}
- move(rhs, storage.payload);
+ move(rhs, this.storage.payload);
return this;
}
/// Ditto.
ref typeof(this) opAssign(typeof(null))
{
- if (storage is null)
+ if (this.storage is null)
{
return this;
}
- else if (storage > 1)
- {
- --storage;
- storage = null;
- }
- else if (cast(RefCountedStorage) storage is null)
+ else if (this.storage > 1)
{
- // Created with refCounted. Always destroyed togethter with the pointer.
- assert(storage.counter != 0);
- allocator.dispose(storage);
- return this;
+ --this.storage;
+ this.storage = null;
}
else
{
- allocator.dispose(storage.payload);
+ // Created with refCounted. Always destroyed togethter with the pointer.
+ assert(this.storage.counter != 0);
+ finalize(this.storage.payload);
+ this.storage.payload = Payload.init;
}
return this;
}
@@ -225,8 +221,9 @@ struct RefCounted(T)
/// Ditto.
ref typeof(this) opAssign(typeof(this) rhs)
{
- swap(allocator_, rhs.allocator_);
- swap(storage, rhs.storage);
+ swap(this.allocator_, rhs.allocator_);
+ swap(this.storage, rhs.storage);
+ swap(this.deleter, rhs.deleter);
return this;
}
@@ -380,15 +377,22 @@ private unittest
* args = Constructor arguments of $(D_PARAM T).
*
* Returns: Newly created $(D_PSYMBOL RefCounted!T).
+ *
+ * Precondition: $(D_INLINECODE allocator !is null)
*/
RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args)
if (!is(T == interface) && !isAbstractClass!T
- && !isArray!T && !isAssociativeArray!T)
+ && !isAssociativeArray!T && !isArray!T)
+in
+{
+ assert(allocator !is null);
+}
+body
{
auto rc = typeof(return)(allocator);
- immutable storageSize = alignedSize(stateSize!(RefCounted!T.Storage));
- immutable size = alignedSize(stateSize!T + storageSize);
+ const storageSize = alignedSize(stateSize!(RefCounted!T.Storage));
+ const size = alignedSize(stateSize!T + storageSize);
auto mem = (() @trusted => allocator.allocate(size))();
if (mem is null)
@@ -399,7 +403,7 @@ RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args)
{
() @trusted { allocator.deallocate(mem); }();
}
- rc.storage = emplace!(RefCounted!T.Storage)(mem[0 .. storageSize]);
+ rc.storage = emplace!((RefCounted!T.Storage))(mem[0 .. storageSize]);
static if (is(T == class))
{
@@ -410,9 +414,38 @@ RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args)
auto ptr = (() @trusted => (cast(T*) mem[storageSize .. $].ptr))();
rc.storage.payload = emplace!T(ptr, args);
}
+ rc.deleter = &unifiedDeleter!(RefCounted!T.Payload);
return rc;
}
+/**
+ * Constructs a new array with $(D_PARAM size) elements and wraps it in a
+ * $(D_PSYMBOL RefCounted) using.
+ *
+ * Params:
+ * T = Array type.
+ * size = Array size.
+ * allocator = Allocator.
+ *
+ * Returns: Newly created $(D_PSYMBOL RefCounted!T).
+ *
+ * Precondition: $(D_INLINECODE allocator !is null
+ * && size <= size_t.max / ElementType!T.sizeof)
+ */
+ RefCounted!T refCounted(T)(shared Allocator allocator, const size_t size)
+ if (isArray!T)
+in
+{
+ assert(allocator !is null);
+ assert(size <= size_t.max / ElementType!T.sizeof);
+}
+body
+{
+ auto payload = cast(T) allocator.allocate(ElementType!T.sizeof * size);
+ initializeAll(payload);
+ return RefCounted!T(payload, allocator);
+}
+
///
unittest
{
@@ -456,3 +489,9 @@ private @nogc unittest
assert(rc.count);
}
}
+
+private @nogc unittest
+{
+ auto rc = defaultAllocator.refCounted!(int[])(5);
+ assert(rc.length == 5);
+}