From b20f367aa86d669a131aa87ded1c0f24ca3d624e Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 11 Dec 2016 11:42:09 +0100 Subject: [PATCH] Array support for refCounted factory function --- source/tanya/math/mp.d | 126 +++++++++++++++++++--------------- source/tanya/memory/package.d | 3 +- source/tanya/memory/types.d | 118 +++++++++++++++++-------------- 3 files changed, 138 insertions(+), 109 deletions(-) diff --git a/source/tanya/math/mp.d b/source/tanya/math/mp.d index 6da1027..10bf0a8 100644 --- a/source/tanya/math/mp.d +++ b/source/tanya/math/mp.d @@ -29,7 +29,7 @@ struct Integer pure nothrow @safe @nogc invariant { - assert(rep.length || !sign, "0 should be positive."); + assert(!rep.count || rep.length || !sign, "0 should be positive."); } /** @@ -39,18 +39,37 @@ struct Integer * T = Value type. * value = Initial value. * allocator = Allocator. + * + * Precondition: $(D_INLINECODE allocator !is null) */ this(T)(in T value, shared Allocator allocator = defaultAllocator) nothrow @safe @nogc - if (isIntegral!T) + if (isIntegral!T || is(T == Integer)) + { + this(allocator); + static if (isIntegral!T) + { + assignInt(value); + } + else + { + rep = RefCounted!(ubyte[])(() @trusted { + return cast(ubyte[]) allocator.allocate(value.length); + }(), allocator); + value.rep.get.copy(rep.get); + sign = value.sign; + } + } + + /// Ditto. + this(shared Allocator allocator) nothrow @safe @nogc in { assert(allocator !is null); } body { - this(allocator); - assignInt(value); + this.allocator = allocator; } private @nogc unittest @@ -66,30 +85,6 @@ struct Integer assert(h2.sign); } - /// Ditto. - this(T)(in T value, shared Allocator allocator = defaultAllocator) - nothrow @safe @nogc - if (is(T == Integer)) - in - { - assert(allocator !is null); - } - body - { - this(allocator); - - allocator.resizeArray(rep, value.length); - value.rep.get.copy(rep.get); - sign = value.sign; - } - - /// Ditto. - this(shared Allocator allocator) nothrow @safe @nogc - { - this.allocator = allocator; - rep = RefCounted!(ubyte[])(allocator); - } - /* * Figures out the minimum amount of space this value will take * up in bytes and resizes the internal storage. Sets the sign. @@ -99,6 +94,7 @@ struct Integer in { static assert(isIntegral!T); + assert(allocator !is null); } body { @@ -123,8 +119,16 @@ struct Integer } --size; } - allocator.resizeArray(rep.get, size); - + if (rep.count) + { + allocator.resizeArray(rep.get, size); + } + else + { + rep = RefCounted!(ubyte[])(() @trusted { + return cast(ubyte[]) allocator.allocate(size); + }(), allocator); + } /* Work backward through the int, masking off each byte (up to the first 0 byte) and copy it into the internal representation in big-endian format. */ @@ -146,23 +150,31 @@ struct Integer * Returns: $(D_KEYWORD this). */ ref Integer opAssign(T)(in T value) nothrow @safe @nogc - if (isIntegral!T) + if (isIntegral!T || is(T == Integer)) { - checkAllocator(); - assignInt(value); - - return this; - } - - /// Ditto. - ref Integer opAssign(in Integer value) nothrow @safe @nogc - { - checkAllocator(); - - allocator.resizeArray(rep, value.length); - value.rep.get.copy(rep.get); - - sign = value.sign; + if (allocator is null) + { + allocator = defaultAllocator; + } + static if (isIntegral!T) + { + assignInt(value); + } + else + { + if (rep.count) + { + allocator.resizeArray(rep, value.length); + } + else + { + rep = RefCounted!(ubyte[])(() @trusted { + return cast(ubyte[]) allocator.allocate(value.length); + }(), allocator); + } + value.rep.get.copy(rep.get); + sign = value.sign; + } return this; } @@ -368,7 +380,7 @@ struct Integer } body { - checkAllocator(); + initialize(); static if (op == "+") { if (h.sign == sign) @@ -522,7 +534,7 @@ struct Integer } body { - checkAllocator(); + initialize(); auto divisor = Integer(h, allocator); size_t bitSize; @@ -654,7 +666,7 @@ struct Integer Integer opUnary(string op)() nothrow @safe @nogc if ((op == "+") || (op == "-") || (op == "~")) { - checkAllocator(); + initialize(); auto h = Integer(this, allocator); static if (op == "-") { @@ -748,7 +760,7 @@ struct Integer } body { - checkAllocator(); + initialize(); static if (op == "++") { @@ -820,12 +832,16 @@ struct Integer assert(h.rep[0] == 0x01); } - private void checkAllocator() nothrow @safe @nogc + private void initialize() nothrow @safe @nogc { if (allocator is null) { allocator = defaultAllocator; } + if (!rep.count) + { + rep = allocator.refCounted!(ubyte[])(0); + } } /** @@ -895,7 +911,7 @@ struct Integer { immutable step = n / 8; - checkAllocator(); + initialize(); if (step >= rep.length) { allocator.resizeArray(rep, 0); @@ -976,7 +992,7 @@ struct Integer immutable bit = n % 8; immutable delta = 8 - bit; - checkAllocator(); + initialize(); if (cast(ubyte) (rep[0] >> delta)) { allocator.resizeArray(rep, i + n / 8 + 1); @@ -1015,7 +1031,7 @@ struct Integer if (op == "<<" || op == ">>" || op == "+" || op == "-" || op == "/" || op == "*" || op == "^^" || op == "%") { - checkAllocator(); + initialize(); auto ret = Integer(this, allocator); mixin("ret " ~ op ~ "= n;"); return ret; @@ -1037,7 +1053,7 @@ struct Integer if (op == "+" || op == "-" || op == "/" || op == "*" || op == "^^" || op == "%") { - checkAllocator(); + initialize(); auto ret = Integer(this, allocator); mixin("ret " ~ op ~ "= h;"); return ret; diff --git a/source/tanya/memory/package.d b/source/tanya/memory/package.d index 9a3a2ef..9832d74 100644 --- a/source/tanya/memory/package.d +++ b/source/tanya/memory/package.d @@ -11,7 +11,6 @@ module tanya.memory; import core.exception; -import std.algorithm.mutation; public import std.experimental.allocator : make, makeArray, expandArray, stateSize, shrinkArray; import std.traits; @@ -66,7 +65,7 @@ bool resizeArray(T)(shared Allocator allocator, array = () @trusted { return cast(T[]) buf; }(); if (oldLength < length) { - array[oldLength .. $].uninitializedFill(init); + array[oldLength .. $] = init; } return true; } diff --git a/source/tanya/memory/types.d b/source/tanya/memory/types.d index 1c899be..e269a7c 100644 --- a/source/tanya/memory/types.d +++ b/source/tanya/memory/types.d @@ -30,12 +30,13 @@ struct RefCounted(T) { static if (isReference!T) { - private T payload; + private alias Payload = T; } else { - private T* payload; + private alias Payload = T*; } + private Payload payload_; private uint counter; @@ -48,33 +49,20 @@ struct RefCounted(T) /** * Takes ownership over $(D_PARAM value), setting the counter to 1. + * $(D_PARAM value) may be a pointer, an object or a dynamic array. * * Params: * value = Value whose ownership is taken over. * allocator = Allocator used to destroy the $(D_PARAM value) and to * allocate/deallocate internal storage. - + * * Precondition: $(D_INLINECODE allocator !is null) */ - this(T value, shared Allocator allocator = defaultAllocator) - in - { - assert(allocator !is null); - } - body + this(Payload value, shared Allocator allocator = defaultAllocator) { this(allocator); - static if (!isReference!T) - { - payload = cast(T*) allocator.allocate(stateSize!T).ptr; - move(value, *payload); - counter = 1; - } - else if (value !is null) - { - move(value, payload); - counter = 1; - } + move(value, payload_); + counter = 1; } /// Ditto. @@ -93,7 +81,7 @@ struct RefCounted(T) */ this(this) pure nothrow @safe @nogc { - if (isInitialized) + if (count) { ++counter; } @@ -106,12 +94,12 @@ struct RefCounted(T) */ ~this() { - if (isInitialized && !--counter) + if (count && !--counter) { static if (isReference!T) { - allocator.dispose(payload); - payload = null; + allocator.dispose(payload_); + payload_ = null; } } } @@ -138,23 +126,34 @@ struct RefCounted(T) } static if (isReference!T) { - counter == 1 ? allocator.dispose(payload) : --counter; + if (counter > 1) + { + --counter; + } + else if (counter == 1) + { + allocator.dispose(payload_); + } + else + { + counter = 1; + } } - else if (!isInitialized) + else if (!count) { - payload = cast(T*) allocator.allocate(stateSize!T).ptr; + payload_ = cast(T*) allocator.allocate(stateSize!T).ptr; counter = 1; } - move(rhs, get); - return get; + move(rhs, payload); + return payload; } /// Ditto. ref typeof(this) opAssign(typeof(this) rhs) { - swap(counter, rhs.counter); - swap(get, rhs.get); swap(allocator, rhs.allocator); + swap(counter, rhs.counter); + swap(payload, rhs.payload); return this; } @@ -169,24 +168,27 @@ struct RefCounted(T) */ inout(T2) opCast(T2)() inout pure nothrow @safe @nogc if (is(T : T2)) - in - { - assert(payload !is null, "Attempted to access an uninitialized reference."); - } - body { return get; } - ref inout(T) get() inout return pure nothrow @safe @nogc + /** + * Returns: Reference to the owned object. + */ + ref inout(T) get() inout pure nothrow @safe @nogc + in + { + assert(counter, "Attempted to access an uninitialized reference."); + } + body { static if (isReference!T) { - return payload; + return payload_; } else { - return *payload; + return *payload_; } } @@ -200,12 +202,17 @@ struct RefCounted(T) return counter; } - /** - * Returns: Whether tihs $(D_PSYMBOL RefCounted) is initialized. - */ - @property bool isInitialized() const pure nothrow @safe @nogc + pragma(inline, true) + private ref inout(T) payload() inout return pure nothrow @safe @nogc { - return counter != 0; + static if (isReference!T) + { + return payload_; + } + else + { + return *payload_; + } } alias get this; @@ -248,9 +255,9 @@ unittest this(ref ubyte[] member) { - assert(!this.member.isInitialized); + assert(!this.member.count); this.member = member; - assert(this.member.isInitialized); + assert(this.member.count); } } @@ -291,17 +298,20 @@ private unittest assert(destroyed == 1); RefCounted!int rc; + assert(rc.count == 0); rc = 8; + assert(rc.count == 1); } private unittest { - auto rc = RefCounted!int(5); + auto val = defaultAllocator.make!int(5); + auto rc = RefCounted!int(val); - static assert(is(typeof(rc.payload) == int*)); + static assert(is(typeof(rc.payload_) == int*)); static assert(is(typeof(cast(int) rc) == int)); - static assert(is(typeof(RefCounted!(int*).payload) == int*)); + static assert(is(typeof(RefCounted!(int*).payload_) == int*)); static assert(is(typeof(cast(A) (RefCounted!A())) == A)); static assert(is(typeof(cast(Object) (RefCounted!A())) == Object)); @@ -326,7 +336,11 @@ private unittest RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args) if (!is(T == interface) && !isAbstractClass!T) { - static if (isReference!T) + static if (isDynamicArray!T) + { + return typeof(return)(allocator.makeArray!(ForeachType!T)(args), allocator); + } + else static if (isReference!T) { return typeof(return)(allocator.make!T(args), allocator); } @@ -334,7 +348,7 @@ RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args) { auto rc = typeof(return)(allocator); rc.counter = 1; - rc.payload = allocator.make!T(args); + rc.payload_ = allocator.make!T(args); return rc; } } @@ -378,6 +392,6 @@ private unittest } { auto rc = defaultAllocator.refCounted!E(); - assert(rc.isInitialized); + assert(rc.count); } }