Array support for refCounted factory function
This commit is contained in:
parent
a2dadda511
commit
b20f367aa8
@ -29,7 +29,7 @@ struct Integer
|
|||||||
|
|
||||||
pure nothrow @safe @nogc invariant
|
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.
|
* T = Value type.
|
||||||
* value = Initial value.
|
* value = Initial value.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
|
*
|
||||||
|
* Precondition: $(D_INLINECODE allocator !is null)
|
||||||
*/
|
*/
|
||||||
this(T)(in T value, shared Allocator allocator = defaultAllocator)
|
this(T)(in T value, shared Allocator allocator = defaultAllocator)
|
||||||
nothrow @safe @nogc
|
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
|
in
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
this(allocator);
|
this.allocator = allocator;
|
||||||
assignInt(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @nogc unittest
|
private @nogc unittest
|
||||||
@ -66,30 +85,6 @@ struct Integer
|
|||||||
assert(h2.sign);
|
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
|
* Figures out the minimum amount of space this value will take
|
||||||
* up in bytes and resizes the internal storage. Sets the sign.
|
* up in bytes and resizes the internal storage. Sets the sign.
|
||||||
@ -99,6 +94,7 @@ struct Integer
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
static assert(isIntegral!T);
|
static assert(isIntegral!T);
|
||||||
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
@ -123,8 +119,16 @@ struct Integer
|
|||||||
}
|
}
|
||||||
--size;
|
--size;
|
||||||
}
|
}
|
||||||
|
if (rep.count)
|
||||||
|
{
|
||||||
allocator.resizeArray(rep.get, size);
|
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
|
/* Work backward through the int, masking off each byte (up to the
|
||||||
first 0 byte) and copy it into the internal representation in
|
first 0 byte) and copy it into the internal representation in
|
||||||
big-endian format. */
|
big-endian format. */
|
||||||
@ -146,23 +150,31 @@ struct Integer
|
|||||||
* Returns: $(D_KEYWORD this).
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
ref Integer opAssign(T)(in T value) nothrow @safe @nogc
|
ref Integer opAssign(T)(in T value) nothrow @safe @nogc
|
||||||
if (isIntegral!T)
|
if (isIntegral!T || is(T == Integer))
|
||||||
{
|
{
|
||||||
checkAllocator();
|
if (allocator is null)
|
||||||
assignInt(value);
|
{
|
||||||
|
allocator = defaultAllocator;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
static if (isIntegral!T)
|
||||||
/// Ditto.
|
{
|
||||||
ref Integer opAssign(in Integer value) nothrow @safe @nogc
|
assignInt(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rep.count)
|
||||||
{
|
{
|
||||||
checkAllocator();
|
|
||||||
|
|
||||||
allocator.resizeArray(rep, value.length);
|
allocator.resizeArray(rep, value.length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rep = RefCounted!(ubyte[])(() @trusted {
|
||||||
|
return cast(ubyte[]) allocator.allocate(value.length);
|
||||||
|
}(), allocator);
|
||||||
|
}
|
||||||
value.rep.get.copy(rep.get);
|
value.rep.get.copy(rep.get);
|
||||||
|
|
||||||
sign = value.sign;
|
sign = value.sign;
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -368,7 +380,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
checkAllocator();
|
initialize();
|
||||||
static if (op == "+")
|
static if (op == "+")
|
||||||
{
|
{
|
||||||
if (h.sign == sign)
|
if (h.sign == sign)
|
||||||
@ -522,7 +534,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
checkAllocator();
|
initialize();
|
||||||
|
|
||||||
auto divisor = Integer(h, allocator);
|
auto divisor = Integer(h, allocator);
|
||||||
size_t bitSize;
|
size_t bitSize;
|
||||||
@ -654,7 +666,7 @@ struct Integer
|
|||||||
Integer opUnary(string op)() nothrow @safe @nogc
|
Integer opUnary(string op)() nothrow @safe @nogc
|
||||||
if ((op == "+") || (op == "-") || (op == "~"))
|
if ((op == "+") || (op == "-") || (op == "~"))
|
||||||
{
|
{
|
||||||
checkAllocator();
|
initialize();
|
||||||
auto h = Integer(this, allocator);
|
auto h = Integer(this, allocator);
|
||||||
static if (op == "-")
|
static if (op == "-")
|
||||||
{
|
{
|
||||||
@ -748,7 +760,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
checkAllocator();
|
initialize();
|
||||||
|
|
||||||
static if (op == "++")
|
static if (op == "++")
|
||||||
{
|
{
|
||||||
@ -820,12 +832,16 @@ struct Integer
|
|||||||
assert(h.rep[0] == 0x01);
|
assert(h.rep[0] == 0x01);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAllocator() nothrow @safe @nogc
|
private void initialize() nothrow @safe @nogc
|
||||||
{
|
{
|
||||||
if (allocator is null)
|
if (allocator is null)
|
||||||
{
|
{
|
||||||
allocator = defaultAllocator;
|
allocator = defaultAllocator;
|
||||||
}
|
}
|
||||||
|
if (!rep.count)
|
||||||
|
{
|
||||||
|
rep = allocator.refCounted!(ubyte[])(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -895,7 +911,7 @@ struct Integer
|
|||||||
{
|
{
|
||||||
immutable step = n / 8;
|
immutable step = n / 8;
|
||||||
|
|
||||||
checkAllocator();
|
initialize();
|
||||||
if (step >= rep.length)
|
if (step >= rep.length)
|
||||||
{
|
{
|
||||||
allocator.resizeArray(rep, 0);
|
allocator.resizeArray(rep, 0);
|
||||||
@ -976,7 +992,7 @@ struct Integer
|
|||||||
immutable bit = n % 8;
|
immutable bit = n % 8;
|
||||||
immutable delta = 8 - bit;
|
immutable delta = 8 - bit;
|
||||||
|
|
||||||
checkAllocator();
|
initialize();
|
||||||
if (cast(ubyte) (rep[0] >> delta))
|
if (cast(ubyte) (rep[0] >> delta))
|
||||||
{
|
{
|
||||||
allocator.resizeArray(rep, i + n / 8 + 1);
|
allocator.resizeArray(rep, i + n / 8 + 1);
|
||||||
@ -1015,7 +1031,7 @@ struct Integer
|
|||||||
if (op == "<<" || op == ">>" || op == "+" || op == "-" || op == "/"
|
if (op == "<<" || op == ">>" || op == "+" || op == "-" || op == "/"
|
||||||
|| op == "*" || op == "^^" || op == "%")
|
|| op == "*" || op == "^^" || op == "%")
|
||||||
{
|
{
|
||||||
checkAllocator();
|
initialize();
|
||||||
auto ret = Integer(this, allocator);
|
auto ret = Integer(this, allocator);
|
||||||
mixin("ret " ~ op ~ "= n;");
|
mixin("ret " ~ op ~ "= n;");
|
||||||
return ret;
|
return ret;
|
||||||
@ -1037,7 +1053,7 @@ struct Integer
|
|||||||
if (op == "+" || op == "-" || op == "/"
|
if (op == "+" || op == "-" || op == "/"
|
||||||
|| op == "*" || op == "^^" || op == "%")
|
|| op == "*" || op == "^^" || op == "%")
|
||||||
{
|
{
|
||||||
checkAllocator();
|
initialize();
|
||||||
auto ret = Integer(this, allocator);
|
auto ret = Integer(this, allocator);
|
||||||
mixin("ret " ~ op ~ "= h;");
|
mixin("ret " ~ op ~ "= h;");
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
module tanya.memory;
|
module tanya.memory;
|
||||||
|
|
||||||
import core.exception;
|
import core.exception;
|
||||||
import std.algorithm.mutation;
|
|
||||||
public import std.experimental.allocator : make, makeArray, expandArray,
|
public import std.experimental.allocator : make, makeArray, expandArray,
|
||||||
stateSize, shrinkArray;
|
stateSize, shrinkArray;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
@ -66,7 +65,7 @@ bool resizeArray(T)(shared Allocator allocator,
|
|||||||
array = () @trusted { return cast(T[]) buf; }();
|
array = () @trusted { return cast(T[]) buf; }();
|
||||||
if (oldLength < length)
|
if (oldLength < length)
|
||||||
{
|
{
|
||||||
array[oldLength .. $].uninitializedFill(init);
|
array[oldLength .. $] = init;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -30,12 +30,13 @@ struct RefCounted(T)
|
|||||||
{
|
{
|
||||||
static if (isReference!T)
|
static if (isReference!T)
|
||||||
{
|
{
|
||||||
private T payload;
|
private alias Payload = T;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
private T* payload;
|
private alias Payload = T*;
|
||||||
}
|
}
|
||||||
|
private Payload payload_;
|
||||||
|
|
||||||
private uint counter;
|
private uint counter;
|
||||||
|
|
||||||
@ -48,34 +49,21 @@ struct RefCounted(T)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes ownership over $(D_PARAM value), setting the counter to 1.
|
* 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:
|
* Params:
|
||||||
* value = Value whose ownership is taken over.
|
* value = Value whose ownership is taken over.
|
||||||
* allocator = Allocator used to destroy the $(D_PARAM value) and to
|
* allocator = Allocator used to destroy the $(D_PARAM value) and to
|
||||||
* allocate/deallocate internal storage.
|
* allocate/deallocate internal storage.
|
||||||
|
*
|
||||||
* Precondition: $(D_INLINECODE allocator !is null)
|
* Precondition: $(D_INLINECODE allocator !is null)
|
||||||
*/
|
*/
|
||||||
this(T value, shared Allocator allocator = defaultAllocator)
|
this(Payload value, shared Allocator allocator = defaultAllocator)
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
static if (!isReference!T)
|
move(value, payload_);
|
||||||
{
|
|
||||||
payload = cast(T*) allocator.allocate(stateSize!T).ptr;
|
|
||||||
move(value, *payload);
|
|
||||||
counter = 1;
|
counter = 1;
|
||||||
}
|
}
|
||||||
else if (value !is null)
|
|
||||||
{
|
|
||||||
move(value, payload);
|
|
||||||
counter = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
this(shared Allocator allocator) pure nothrow @safe @nogc
|
this(shared Allocator allocator) pure nothrow @safe @nogc
|
||||||
@ -93,7 +81,7 @@ struct RefCounted(T)
|
|||||||
*/
|
*/
|
||||||
this(this) pure nothrow @safe @nogc
|
this(this) pure nothrow @safe @nogc
|
||||||
{
|
{
|
||||||
if (isInitialized)
|
if (count)
|
||||||
{
|
{
|
||||||
++counter;
|
++counter;
|
||||||
}
|
}
|
||||||
@ -106,12 +94,12 @@ struct RefCounted(T)
|
|||||||
*/
|
*/
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
if (isInitialized && !--counter)
|
if (count && !--counter)
|
||||||
{
|
{
|
||||||
static if (isReference!T)
|
static if (isReference!T)
|
||||||
{
|
{
|
||||||
allocator.dispose(payload);
|
allocator.dispose(payload_);
|
||||||
payload = null;
|
payload_ = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,23 +126,34 @@ struct RefCounted(T)
|
|||||||
}
|
}
|
||||||
static if (isReference!T)
|
static if (isReference!T)
|
||||||
{
|
{
|
||||||
counter == 1 ? allocator.dispose(payload) : --counter;
|
if (counter > 1)
|
||||||
}
|
{
|
||||||
else if (!isInitialized)
|
--counter;
|
||||||
|
}
|
||||||
|
else if (counter == 1)
|
||||||
|
{
|
||||||
|
allocator.dispose(payload_);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
payload = cast(T*) allocator.allocate(stateSize!T).ptr;
|
|
||||||
counter = 1;
|
counter = 1;
|
||||||
}
|
}
|
||||||
move(rhs, get);
|
}
|
||||||
return get;
|
else if (!count)
|
||||||
|
{
|
||||||
|
payload_ = cast(T*) allocator.allocate(stateSize!T).ptr;
|
||||||
|
counter = 1;
|
||||||
|
}
|
||||||
|
move(rhs, payload);
|
||||||
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
ref typeof(this) opAssign(typeof(this) rhs)
|
ref typeof(this) opAssign(typeof(this) rhs)
|
||||||
{
|
{
|
||||||
swap(counter, rhs.counter);
|
|
||||||
swap(get, rhs.get);
|
|
||||||
swap(allocator, rhs.allocator);
|
swap(allocator, rhs.allocator);
|
||||||
|
swap(counter, rhs.counter);
|
||||||
|
swap(payload, rhs.payload);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -169,24 +168,27 @@ struct RefCounted(T)
|
|||||||
*/
|
*/
|
||||||
inout(T2) opCast(T2)() inout pure nothrow @safe @nogc
|
inout(T2) opCast(T2)() inout pure nothrow @safe @nogc
|
||||||
if (is(T : T2))
|
if (is(T : T2))
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(payload !is null, "Attempted to access an uninitialized reference.");
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
{
|
||||||
return get;
|
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)
|
static if (isReference!T)
|
||||||
{
|
{
|
||||||
return payload;
|
return payload_;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return *payload;
|
return *payload_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,12 +202,17 @@ struct RefCounted(T)
|
|||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
pragma(inline, true)
|
||||||
* Returns: Whether tihs $(D_PSYMBOL RefCounted) is initialized.
|
private ref inout(T) payload() inout return pure nothrow @safe @nogc
|
||||||
*/
|
|
||||||
@property bool isInitialized() const pure nothrow @safe @nogc
|
|
||||||
{
|
{
|
||||||
return counter != 0;
|
static if (isReference!T)
|
||||||
|
{
|
||||||
|
return payload_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return *payload_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
alias get this;
|
alias get this;
|
||||||
@ -248,9 +255,9 @@ unittest
|
|||||||
|
|
||||||
this(ref ubyte[] member)
|
this(ref ubyte[] member)
|
||||||
{
|
{
|
||||||
assert(!this.member.isInitialized);
|
assert(!this.member.count);
|
||||||
this.member = member;
|
this.member = member;
|
||||||
assert(this.member.isInitialized);
|
assert(this.member.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,17 +298,20 @@ private unittest
|
|||||||
assert(destroyed == 1);
|
assert(destroyed == 1);
|
||||||
|
|
||||||
RefCounted!int rc;
|
RefCounted!int rc;
|
||||||
|
assert(rc.count == 0);
|
||||||
rc = 8;
|
rc = 8;
|
||||||
|
assert(rc.count == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unittest
|
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(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(A) (RefCounted!A())) == A));
|
||||||
static assert(is(typeof(cast(Object) (RefCounted!A())) == Object));
|
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)
|
RefCounted!T refCounted(T, A...)(shared Allocator allocator, auto ref A args)
|
||||||
if (!is(T == interface) && !isAbstractClass!T)
|
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);
|
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);
|
auto rc = typeof(return)(allocator);
|
||||||
rc.counter = 1;
|
rc.counter = 1;
|
||||||
rc.payload = allocator.make!T(args);
|
rc.payload_ = allocator.make!T(args);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,6 +392,6 @@ private unittest
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto rc = defaultAllocator.refCounted!E();
|
auto rc = defaultAllocator.refCounted!E();
|
||||||
assert(rc.isInitialized);
|
assert(rc.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user