summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2016-12-18 18:48:25 +0100
committerEugen Wissner <belka@caraus.de>2016-12-18 18:48:25 +0100
commit40857e69b770333de8c5d26ebe04e604860c1869 (patch)
tree4d8d5ed980ea01763df8eae8961b0dfed2237401
parentc1fb89af9953738175ca4f28fb1ce2aacc2958e3 (diff)
downloadtanya-40857e69b770333de8c5d26ebe04e604860c1869.tar.gz
Add capacity capabilities to the vector
-rw-r--r--source/tanya/async/event/epoll.d2
-rw-r--r--source/tanya/async/event/kqueue.d4
-rw-r--r--source/tanya/async/event/selector.d2
-rw-r--r--source/tanya/container/vector.d447
-rw-r--r--source/tanya/math/mp.d186
-rw-r--r--source/tanya/math/package.d2
-rw-r--r--source/tanya/memory/allocator.d33
-rw-r--r--source/tanya/memory/mmappool.d14
-rw-r--r--source/tanya/memory/package.d82
-rw-r--r--source/tanya/network/socket.d11
-rw-r--r--source/tanya/traits.d34
11 files changed, 488 insertions, 329 deletions
diff --git a/source/tanya/async/event/epoll.d b/source/tanya/async/event/epoll.d
index 28af1c9..b48fc37 100644
--- a/source/tanya/async/event/epoll.d
+++ b/source/tanya/async/event/epoll.d
@@ -48,7 +48,7 @@ class EpollLoop : SelectorLoop
throw MmapPool.instance.make!BadLoopException("epoll initialization failed");
}
super();
- events = MmapPool.instance.makeArray!epoll_event(maxEvents);
+ MmapPool.instance.resizeArray(events, maxEvents);
}
/**
diff --git a/source/tanya/async/event/kqueue.d b/source/tanya/async/event/kqueue.d
index 85c9a2a..cf7f3c1 100644
--- a/source/tanya/async/event/kqueue.d
+++ b/source/tanya/async/event/kqueue.d
@@ -165,8 +165,8 @@ class KqueueLoop : SelectorLoop
{
throw MmapPool.instance.make!BadLoopException("epoll initialization failed");
}
- events = MmapPool.instance.makeArray!kevent_t(64);
- changes = MmapPool.instance.makeArray!kevent_t(64);
+ MmapPool.instance.resizeArray(events, 64);
+ MmapPool.instance.resizeArray(changes, 64);
}
/**
diff --git a/source/tanya/async/event/selector.d b/source/tanya/async/event/selector.d
index b023f50..85f8298 100644
--- a/source/tanya/async/event/selector.d
+++ b/source/tanya/async/event/selector.d
@@ -116,7 +116,7 @@ abstract class SelectorLoop : Loop
this() @nogc
{
super();
- connections = MmapPool.instance.makeArray!ConnectionWatcher(maxEvents);
+ MmapPool.instance.resizeArray(connections, maxEvents);
}
~this() @nogc
diff --git a/source/tanya/container/vector.d b/source/tanya/container/vector.d
index 695fae9..699aa89 100644
--- a/source/tanya/container/vector.d
+++ b/source/tanya/container/vector.d
@@ -10,11 +10,23 @@
*/
module tanya.container.vector;
+import core.exception;
import std.algorithm.comparison;
import std.range.primitives;
import std.traits;
import tanya.memory;
+version (unittest)
+{
+ import tanya.traits;
+ struct TestA
+ {
+ ~this() @nogc
+ {
+ }
+ }
+}
+
/**
* One dimensional array.
*
@@ -26,11 +38,13 @@ template Vector(T)
/**
* Defines the container's primary range.
*/
- struct Range
+ struct Range(V)
{
- private Vector* data;
+ private alias E = typeof(data.vector[0]);
+
+ private V* data;
- private @property ref inout(Vector) outer() inout return
+ private @property ref inout(V) outer() inout return
{
return *data;
}
@@ -40,10 +54,15 @@ template Vector(T)
invariant
{
assert(start <= end);
- assert(start == 0 || end > 0);
}
- protected this(ref Vector data, in size_t a, in size_t b)
+ private this(ref inout V data, in size_t a, in size_t b) inout
+ in
+ {
+ assert(a <= b);
+ assert(b <= data.length);
+ }
+ body
{
this.data = &data;
start = a;
@@ -67,22 +86,12 @@ template Vector(T)
alias opDollar = length;
- @property ref inout(T) front() inout
- in
- {
- assert(!empty);
- }
- body
+ @property ref inout(E) front() inout
{
return outer[start];
}
- @property ref inout(T) back() inout
- in
- {
- assert(!empty);
- }
- body
+ @property ref inout(E) back() inout
{
return outer[end - 1];
}
@@ -107,12 +116,7 @@ template Vector(T)
--end;
}
- ref inout(T) opIndex(in size_t i) inout
- in
- {
- assert(start + i < end);
- }
- body
+ ref inout(E) opIndex(in size_t i) inout
{
return outer[start + i];
}
@@ -133,60 +137,24 @@ template Vector(T)
return typeof(return)(outer, start + i, start + j);
}
- Range opIndex()
- {
- return typeof(return)(outer, start, end);
- }
-
- Range opSlice(in size_t i, in size_t j)
- in
+ static if (isMutable!V)
{
- assert(i <= j);
- assert(start + j <= end);
- }
- body
- {
- return typeof(return)(outer, start + i, start + j);
- }
-
- static if (isMutable!Vector)
- {
- Range opIndexAssign(in T value)
- in
- {
- assert(end <= outer.length);
- }
- body
+ Range opIndexAssign(T value)
{
return outer[start .. end] = value;
}
- Range opSliceAssign(in T value, in size_t i, in size_t j)
- in
- {
- assert(start + j <= end);
- }
- body
+ Range opSliceAssign(T value, in size_t i, in size_t j)
{
return outer[start + i .. start + j] = value;
}
- Range opSliceAssign(in Range value, in size_t i, in size_t j)
- in
- {
- assert(length == value.length);
- }
- body
+ Range opSliceAssign(Range value, in size_t i, in size_t j)
{
return outer[start + i .. start + j] = value;
}
- Range opSliceAssign(in T[] value, in size_t i, in size_t j)
- in
- {
- assert(j - i == value.length);
- }
- body
+ Range opSliceAssign(T[] value, in size_t i, in size_t j)
{
return outer[start + i .. start + j] = value;
}
@@ -205,49 +173,92 @@ template Vector(T)
/// Internal representation.
private T[] vector;
- /// The allocator.
- private shared Allocator allocator;
-
/**
- * Creates an empty $(D_PSYMBOL Vector).
+ * Creates a new $(D_PSYMBOL Vector).
*
* Params:
- * allocator = The allocator should be used for the element
- * allocations.
+ * U = Type of the static array with the initial elements.
+ * params = Values to initialize the array with. Use $(D_PSYMBOL IL)
+ * to generate a list.
+ * allocator = Allocator.
*/
- this(shared Allocator allocator)
+ this(U)(U init, shared Allocator allocator = defaultAllocator)
+ if (isStaticArray!U)
+ in
{
- this.allocator = allocator;
+ static assert(init.length > 0);
}
-
- /**
- * Creates a new $(D_PSYMBOL Vector).
- *
- * Params:
- * U = Variadic template for the constructor parameters.
- * params = Values to initialize the array with. The last parameter can
- * be an allocator, if not, $(D_PSYMBOL defaultAllocator) is used.
- */
- this(U...)(U params)
+ body
{
- static if (isImplicitlyConvertible!(typeof(params[$ - 1]), Allocator))
+ this(allocator);
+ vector = cast(T[]) allocator.allocate(init.length * T.sizeof);
+ if (vector is null)
{
- allocator = params[$ - 1];
- auto values = params[0 .. $ - 1];
+ onOutOfMemoryError();
}
- else
+ vector[0 .. $] = init[0 .. $];
+ length_ = init.length;
+ }
+
+ /// Ditto.
+ this(U)(U init, shared Allocator allocator = defaultAllocator) const
+ if (isStaticArray!U)
+ in
+ {
+ static assert(init.length > 0);
+ }
+ body
+ {
+ allocator_ = cast(const shared Allocator) allocator;
+ auto buf = cast(T[]) allocator.allocate(init.length * T.sizeof);
+ if (buf is null)
{
- allocator = defaultAllocator;
- alias values = params;
+ onOutOfMemoryError();
}
+ buf[0 .. $] = init[0 .. $];
+ vector = cast(const (T[])) buf;
+ length_ = init.length;
+ }
- resizeArray!T(allocator, vector, values.length);
- length_ = values.length;
-
- foreach (i, v; values)
+ /// Ditto.
+ this(U)(U init, shared Allocator allocator = defaultAllocator) immutable
+ if (isStaticArray!U)
+ in
+ {
+ static assert(init.length > 0);
+ }
+ body
+ {
+ allocator_ = cast(immutable Allocator) allocator;
+ auto buf = cast(T[]) allocator.allocate(init.length * T.sizeof);
+ if (buf is null)
{
- vector[i] = v;
+ onOutOfMemoryError();
}
+ buf[0 .. $] = init[0 .. $];
+ vector = cast(immutable(T[])) buf;
+ length_ = init.length;
+ }
+
+ /// Ditto.
+ this(shared Allocator allocator)
+ in
+ {
+ assert(allocator !is null);
+ }
+ body
+ {
+ allocator_ = allocator;
+ }
+
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(3, 8, 2));
+
+ assert(v.capacity == 3);
+ assert(v.length == 3);
+ assert(v[0] == 3 && v[1] == 8 && v[2] == 2);
}
/**
@@ -255,11 +266,7 @@ template Vector(T)
*/
~this()
{
- if (allocator is null)
- {
- allocator = defaultAllocator;
- }
- dispose(allocator, vector);
+ allocator.dispose(vector);
}
/**
@@ -267,15 +274,16 @@ template Vector(T)
*/
void clear()
{
- length_ = 0;
+ length = 0;
}
///
unittest
{
- auto v = defaultAllocator.make!(Vector!int)(18, 20, 15);
+ auto v = Vector!int(IL(18, 20, 15));
v.clear();
assert(v.length == 0);
+ assert(v.capacity == 3);
}
/**
@@ -295,23 +303,73 @@ template Vector(T)
}
/// Ditto.
- size_t opDollar() inout const
- {
- return length;
- }
+ alias opDollar = length;
/**
- * Reserves space for $(D_PARAM n) elements.
+ * Expands/shrinks the vector.
+ *
+ * Params:
+ * len = New length.
*/
- void reserve(in size_t n)
+ @property void length(in size_t len)
{
- if (allocator is null)
+ if (len > length)
+ {
+ reserve(len);
+ vector[length .. len] = T.init;
+ }
+ else if (len < length)
{
- allocator = defaultAllocator;
+ static if (hasElaborateDestructor!T)
+ {
+ foreach (ref e; vector[len - 1 .. length_])
+ {
+ destroy(e);
+ }
+ }
}
- if (vector.length < n)
+ else
{
- allocator.resizeArray!T(vector, n);
+ return;
+ }
+ length_ = len;
+ }
+
+ ///
+ unittest
+ {
+ Vector!int v;
+
+ v.length = 5;
+ assert(v.length == 5);
+ assert(v.capacity == 5);
+
+ v.length = 7;
+ assert(v.length == 7);
+ assert(v.capacity == 7);
+
+ assert(v[$ - 1] == 0);
+ v[$ - 1] = 3;
+ assert(v[$ - 1] == 3);
+
+ v.length = 0;
+ assert(v.length == 0);
+ assert(v.capacity == 7);
+ }
+
+ /**
+ * Reserves space for $(D_PARAM size) elements.
+ *
+ * Params:
+ * size = Desired size.
+ */
+ void reserve(in size_t size) @trusted
+ {
+ if (vector.length < size)
+ {
+ void[] buf = vector;
+ allocator.reallocate(buf, size * T.sizeof);
+ vector = cast(T[]) buf;
}
}
@@ -328,33 +386,42 @@ template Vector(T)
}
/**
- * Expands/shrinks the vector.
+ * Requests the vector to reduce its capacity to fit the $(D_PARAM size).
+ *
+ * The request is non-binding. The vector won't become smaller than the
+ * $(D_PARAM length).
*
* Params:
- * len = New length.
+ * size = Desired size.
*/
- @property void length(in size_t len)
+ void shrink(in size_t size) @trusted
{
- reserve(len);
- length_ = len;
+ auto n = max(length, size);
+ void[] buf = vector;
+ allocator.reallocate(buf, n * T.sizeof);
+ vector = cast(T[]) buf;
}
///
unittest
{
Vector!int v;
+ assert(v.capacity == 0);
+ assert(v.length == 0);
- v.length = 5;
- assert(v.length == 5);
+ v.reserve(5);
+ v.insertBack(1);
+ v.insertBack(3);
assert(v.capacity == 5);
+ assert(v.length == 2);
- v.length = 7;
- assert(v.length == 7);
- assert(v.capacity == 7);
+ v.shrink(4);
+ assert(v.capacity == 4);
+ assert(v.length == 2);
- v.length = 0;
- assert(v.length == 0);
- assert(v.capacity == 7);
+ v.shrink(1);
+ assert(v.capacity == 2);
+ assert(v.length == 2);
}
/**
@@ -381,14 +448,7 @@ template Vector(T)
{
immutable toRemove = min(howMany, length);
- static if (hasElaborateDestructor!T)
- {
- foreach (ref e; vector[$ - toRemove ..$])
- {
- allocator.dispose(e);
- }
- }
- length_ -= toRemove;
+ length = length - toRemove;
return toRemove;
}
@@ -399,7 +459,7 @@ template Vector(T)
///
unittest
{
- auto v = Vector!int(5, 18, 17);
+ auto v = Vector!int(IL(5, 18, 17));
assert(v.removeBack(0) == 0);
assert(v.removeBack(2) == 2);
@@ -412,7 +472,7 @@ template Vector(T)
*
* Returns: The number of elements inserted.
*/
- size_t insertBack(in T el)
+ size_t insertBack(T el)
{
reserve(length + 1);
vector[length] = el;
@@ -421,12 +481,12 @@ template Vector(T)
}
/// Ditto.
- size_t insertBack(in Range el)
+ size_t insertBack(Range!Vector el)
{
immutable newLength = length + el.length;
reserve(newLength);
- vector[length .. newLength] = el.data.vector[el.start .. el.end];
+ vector[length .. newLength] = el.outer.vector[el.start .. el.end];
length_ = newLength;
return el.length;
@@ -486,7 +546,7 @@ template Vector(T)
assert(v1.capacity == 4);
assert(v1[0] == 5 && v1[1] == 6 && v1[2] == 4 && v1[3] == 2);
- auto v2 = Vector!int(34, 234);
+ auto v2 = Vector!int(IL(34, 234));
assert(v1.insertBack(v2[]) == 2);
assert(v1.length == 6);
assert(v1.capacity == 6);
@@ -504,7 +564,7 @@ template Vector(T)
*
* Precondition: $(D_INLINECODE length > pos)
*/
- T opIndexAssign(in T value, in size_t pos)
+ T opIndexAssign(T value, in size_t pos)
in
{
assert(length > pos);
@@ -515,7 +575,7 @@ template Vector(T)
}
/// Ditto.
- Range opIndexAssign(in T value)
+ Range!Vector opIndexAssign(T value)
{
vector[0 .. $] = value;
return opIndex();
@@ -524,7 +584,7 @@ template Vector(T)
///
unittest
{
- auto v1 = Vector!int(12, 1, 7);
+ auto v1 = Vector!int(IL(12, 1, 7));
v1[] = 3;
assert(v1[0] == 3);
@@ -549,7 +609,19 @@ template Vector(T)
}
/// Ditto.
- Range opIndex()
+ Range!Vector opIndex()
+ {
+ return typeof(return)(this, 0, length);
+ }
+
+ /// Ditto.
+ Range!(const Vector) opIndex() const
+ {
+ return typeof(return)(this, 0, length);
+ }
+
+ /// Ditto.
+ Range!(immutable Vector) opIndex() immutable
{
return typeof(return)(this, 0, length);
}
@@ -557,12 +629,18 @@ template Vector(T)
///
unittest
{
- auto v = Vector!int(6, 123, 34, 5);
+ const v1 = Vector!int(IL(6, 123, 34, 5));
+
+ assert(v1[0] == 6);
+ assert(v1[1] == 123);
+ assert(v1[2] == 34);
+ assert(v1[3] == 5);
+ static assert(is(typeof(v1[0]) == const(int)));
+ static assert(is(typeof(v1[])));
- assert(v[0] == 6);
- assert(v[1] == 123);
- assert(v[2] == 34);
- assert(v[3] == 5);
+ auto v2 = immutable Vector!int(IL(6, 123, 34, 5));
+ static assert(is(typeof(v2[0]) == immutable(int)));
+ static assert(is(typeof(v2[])));
}
/**
@@ -574,13 +652,13 @@ template Vector(T)
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
* otherwise.
*/
- bool opEquals(typeof(this) v)
+ bool opEquals(typeof(this) v) const
{
return opEquals(v);
}
/// Ditto.
- bool opEquals(ref typeof(this) v)
+ bool opEquals(ref typeof(this) v) const
{
return vector == v.vector;
}
@@ -673,7 +751,7 @@ template Vector(T)
///
unittest
{
- auto v = Vector!int(5, 15, 8);
+ auto v = Vector!int(IL(5, 15, 8));
size_t i;
foreach (j, ref e; v)
@@ -693,7 +771,7 @@ template Vector(T)
///
unittest
{
- auto v = Vector!int(5, 15, 8);
+ auto v = Vector!int(IL(5, 15, 8));
size_t i;
foreach_reverse (j, ref e; v)
@@ -728,7 +806,7 @@ template Vector(T)
///
unittest
{
- auto v = Vector!int(5);
+ auto v = Vector!int(IL(5));
assert(v.front == 5);
@@ -755,7 +833,7 @@ template Vector(T)
///
unittest
{
- auto v = Vector!int(5);
+ auto v = Vector!int(IL(5));
assert(v.back == 5);
@@ -774,7 +852,7 @@ template Vector(T)
*
* Precondition: $(D_INLINECODE i <= j && j <= length)
*/
- Range opSlice(in size_t i, in size_t j)
+ Range!Vector opSlice(in size_t i, in size_t j)
in
{
assert(i <= j);
@@ -798,7 +876,7 @@ template Vector(T)
* Precondition: $(D_INLINECODE i <= j && j <= length);
* The lenghts of the ranges and slices match.
*/
- Range opSliceAssign(in T value, in size_t i, in size_t j)
+ Range!Vector opSliceAssign(T value, in size_t i, in size_t j)
in
{
assert(i <= j);
@@ -811,7 +889,7 @@ template Vector(T)
}
/// Ditto.
- Range opSliceAssign(in Range value, in size_t i, in size_t j)
+ Range!Vector opSliceAssign(Range!Vector value, in size_t i, in size_t j)
in
{
assert(j - i == value.length);
@@ -823,7 +901,7 @@ template Vector(T)
}
/// Ditto.
- Range opSliceAssign(in T[] value, in size_t i, in size_t j)
+ Range!Vector opSliceAssign(T[] value, in size_t i, in size_t j)
in
{
assert(j - i == value.length);
@@ -837,8 +915,8 @@ template Vector(T)
///
unittest
{
- auto v1 = Vector!int(3, 3, 3);
- auto v2 = Vector!int(1, 2);
+ auto v1 = Vector!int(IL(3, 3, 3));
+ auto v2 = Vector!int(IL(1, 2));
v1[0 .. 2] = 286;
assert(v1[0] == 286);
@@ -849,20 +927,69 @@ template Vector(T)
assert(v2[0] == 286);
assert(v2[1] == 3);
}
+
+ mixin DefaultAllocator;
}
}
///
unittest
{
- auto v = Vector!int(5, 15, 8);
+ auto v = Vector!int(IL(5, 15, 8));
assert(v.front == 5);
assert(v[1] == 15);
assert(v.back == 8);
}
-private unittest
+private @nogc unittest
{
-// const Vector!int v;
+ // Test the destructor can be called at the end of the scope.
+ auto a = Vector!A();
+
+ // Test that structs can be members of the vector.
+ static assert(is(typeof(Vector!TestA())));
+ static assert(is(typeof(immutable Vector!TestA(IL(TestA())))));
+ static assert(is(typeof(const Vector!TestA(IL(TestA())))));
+}
+
+private @nogc unittest
+{
+ const v1 = Vector!int();
+ const Vector!int v2;
+ const v3 = Vector!int(IL(1, 5, 8));
+ static assert(is(typeof(v3.vector) == const(int[])));
+ static assert(is(typeof(v3.vector[0]) == const(int)));
+
+ immutable v4 = immutable Vector!int();
+ immutable v5 = immutable Vector!int(IL(2, 5, 8));
+ static assert(is(typeof(v4.vector) == immutable(int[])));
+ static assert(is(typeof(v4.vector[0]) == immutable(int)));
+}
+
+private @nogc unittest
+{
+ // Test that immutable/const vectors return usable ranges.
+ auto v = immutable Vector!int(IL(1, 2, 4));
+ auto r = v[];
+
+ assert(r.back == 4);
+ r.popBack();
+ assert(r.back == 2);
+ r.popBack();
+ assert(r.back == 1);
+ r.popBack();
+}
+
+private @nogc unittest
+{
+ Vector!int v1;
+ const Vector!int v2;
+
+ auto r1 = v1[];
+ auto r2 = v1[];
+
+ assert(r1.length == 0);
+ assert(r2.empty);
+ assert(r1 == r2);
}
diff --git a/source/tanya/math/mp.d b/source/tanya/math/mp.d
index fafe077..1dd9075 100644
--- a/source/tanya/math/mp.d
+++ b/source/tanya/math/mp.d
@@ -26,12 +26,6 @@ struct Integer
{
private ubyte[] rep;
private bool sign;
- private shared Allocator allocator;
-
- pure nothrow @safe @nogc invariant
- {
- assert(rep.length || !sign, "0 should be positive.");
- }
/**
* Creates a multiple precision integer.
@@ -52,25 +46,29 @@ struct Integer
{
assignInt(value);
}
- else
+ else if (value.length > 0)
{
rep = () @trusted {
- return cast(ubyte[]) allocator.allocate(value.length);
+ return cast(ubyte[]) allocator_.allocate(value.length);
}();
+ if (rep is null)
+ {
+ onOutOfMemoryError();
+ }
value.rep.copy(rep);
sign = value.sign;
}
}
/// Ditto.
- this(shared Allocator allocator) nothrow @safe @nogc
+ this(shared Allocator allocator) pure nothrow @safe @nogc
in
{
assert(allocator !is null);
}
body
{
- this.allocator = allocator;
+ allocator_ = allocator;
}
private @nogc unittest
@@ -86,22 +84,12 @@ struct Integer
assert(h2.sign);
}
+ /**
+ * Destroys the internal representation.
+ */
~this() nothrow @safe @nogc
- in
{
- assert(allocator !is null || !rep.length);
- }
- body
- {
- if (allocator !is null)
- {
- allocator.dispose(rep);
- }
- }
-
- private @nogc unittest
- {
- Integer h; // allocator isn't set, but the destructor should work
+ allocator.dispose(rep);
}
/*
@@ -113,7 +101,6 @@ struct Integer
in
{
static assert(isIntegral!T);
- assert(allocator !is null);
}
body
{
@@ -169,7 +156,6 @@ struct Integer
ref Integer opAssign(T)(in auto ref T value) nothrow @safe @nogc
if (isIntegral!T || is(T == Integer))
{
- initialize();
static if (isIntegral!T)
{
assignInt(value);
@@ -215,10 +201,10 @@ struct Integer
*
* Returns: Whether the two integers are equal.
*/
- bool opEquals(in Integer h) const nothrow @safe @nogc
- {
- return rep == h.rep;
- }
+ bool opEquals(in Integer h) const nothrow @safe @nogc
+ {
+ return rep == h.rep;
+ }
/// Ditto.
bool opEquals(in ref Integer h) const nothrow @safe @nogc
@@ -235,52 +221,52 @@ struct Integer
assert(h1 != Integer(109));
}
- /**
+ /**
* Params:
* h = The second integer.
- *
- * Returns: A positive number if $(D_INLINECODE this > h), a negative
- * number if $(D_INLINECODE this > h), `0` otherwise.
- */
- int opCmp(in ref Integer h) const nothrow @safe @nogc
- {
- if (length > h.length)
- {
- return 1;
- }
- if (length < h.length)
- {
- return -1;
- }
- // Otherwise, keep searching through the representational integers
- // until one is bigger than another - once we've found one, it's
- // safe to stop, since the lower order bytes can't affect the
- // comparison
- for (size_t i, j; i < length && j < h.length; ++i, ++j)
- {
- if (rep[i] < h.rep[j])
- {
- return -1;
- }
- else if (rep[i] > h.rep[j])
- {
- return 1;
- }
- }
- // if we got all the way to the end without a comparison, the
- // two are equal
- return 0;
- }
+ *
+ * Returns: A positive number if $(D_INLINECODE this > h), a negative
+ * number if $(D_INLINECODE this > h), `0` otherwise.
+ */
+ int opCmp(in ref Integer h) const nothrow @safe @nogc
+ {
+ if (length > h.length)
+ {
+ return 1;
+ }
+ if (length < h.length)
+ {
+ return -1;
+ }
+ // Otherwise, keep searching through the representational integers
+ // until one is bigger than another - once we've found one, it's
+ // safe to stop, since the lower order bytes can't affect the
+ // comparison
+ for (size_t i, j; i < length && j < h.length; ++i, ++j)
+ {
+ if (rep[i] < h.rep[j])
+ {
+ return -1;
+ }
+ else if (rep[i] > h.rep[j])
+ {
+ return 1;
+ }
+ }
+ // if we got all the way to the end without a comparison, the
+ // two are equal
+ return 0;
+ }
/// Ditto.
- int opCmp(in Integer h) const nothrow @safe @nogc
- {
+ int opCmp(in Integer h) const nothrow @safe @nogc
+ {
return opCmp(h);
}
///
- unittest
- {
+ unittest
+ {
auto h1 = Integer(1019);
auto h2 = Integer(1019);
assert(h1 == h2);
@@ -290,18 +276,24 @@ struct Integer
h2 = 688;
assert(h1 > h2);
- }
+ }
- private void add(in ref ubyte[] h) nothrow @safe @nogc
+ private void add(in ref ubyte[] h) nothrow @trusted @nogc
{
uint sum;
uint carry = 0;
+ ubyte[] tmp;
if (h.length > length)
{
- auto tmp = allocator.makeArray!ubyte(h.length);
+ tmp = cast(ubyte[]) allocator.allocate(h.length);
+ if (tmp is null)
+ {
+ onOutOfMemoryError();
+ }
+ tmp[0 .. h.length] = 0;
tmp[h.length - length .. $] = rep[0 .. length];
- rep = tmp;
+ swap(rep, tmp);
}
auto i = length;
@@ -327,15 +319,16 @@ struct Integer
if (carry)
{
// Still overflowed; allocate more space
- auto tmp = allocator.makeArray!ubyte(length + 1);
- tmp[1 .. $] = rep[0..length];
+ void[]* vtmp = cast(void[]*) &tmp;
+ allocator.reallocate(*vtmp, length + 1);
+ tmp[1 .. $] = rep[0 .. length];
tmp[0] = 0x01;
- rep = tmp;
+ swap(rep, tmp);
}
-
+ allocator.deallocate(tmp);
}
- private void subtract(in ref ubyte[] h) nothrow @safe @nogc
+ private void subtract(in ref ubyte[] h) nothrow @trusted @nogc
{
auto i = rep.length;
auto j = h.length;
@@ -369,13 +362,14 @@ struct Integer
immutable offset = rep.countUntil!((const ref a) => a != 0);
if (offset > 0)
{
- ubyte[] tmp = allocator.makeArray!ubyte(rep.length - offset);
+ ubyte[] tmp = cast(ubyte[]) allocator.allocate(rep.length - offset);
rep[offset .. $].copy(tmp);
+ allocator.deallocate(rep);
rep = tmp;
}
else if (offset == -1)
{
- allocator.resizeArray(rep, 0);
+ allocator.dispose(rep);
}
}
@@ -392,11 +386,11 @@ struct Integer
if ((op == "+") || (op == "-"))
out
{
+ assert(rep.length || !sign, "0 should be positive.");
assert(!rep.length || rep[0]);
}
body
{
- initialize();
static if (op == "+")
{
if (h.sign == sign)
@@ -505,6 +499,7 @@ struct Integer
if (op == "*")
out
{
+ assert(rep.length || !sign, "0 should be positive.");
assert(!rep.length || rep[0]);
}
body
@@ -550,8 +545,6 @@ struct Integer
}
body
{
- initialize();
-
auto divisor = Integer(h, allocator);
size_t bitSize;
@@ -562,7 +555,9 @@ struct Integer
}
static if (op == "/")
{
- auto quotient = allocator.makeArray!ubyte(bitSize / 8 + 1);
+ auto quotient = (() @trusted =>
+ cast(ubyte[]) allocator.allocate(bitSize / 8 + 1)
+ )();
}
// "bitPosition" keeps track of which bit, of the quotient,
@@ -592,8 +587,8 @@ struct Integer
static if (op == "/")
{
- swap(rep, quotient);
- allocator.dispose(quotient);
+ () @trusted { allocator.deallocate(rep); }();
+ rep = quotient;
sign = sign == h.sign ? false : true;
}
return this;
@@ -628,6 +623,7 @@ struct Integer
if (op == "^^")
out
{
+ assert(rep.length || !sign, "0 should be positive.");
assert(!rep.length || rep[0]);
}
body
@@ -683,7 +679,6 @@ struct Integer
Integer opUnary(string op)() nothrow @safe @nogc
if ((op == "+") || (op == "-") || (op == "~"))
{
- initialize();
auto h = Integer(this, allocator);
static if (op == "-")
{
@@ -772,12 +767,11 @@ struct Integer
if ((op == "++") || (op == "--"))
out
{
+ assert(rep.length || !sign, "0 should be positive.");
assert(!rep.length || rep[0]);
}
body
{
- initialize();
-
static if (op == "++")
{
if (sign)
@@ -848,14 +842,6 @@ struct Integer
assert(h.rep[0] == 0x01);
}
- private void initialize() nothrow @safe @nogc
- {
- if (allocator is null)
- {
- allocator = defaultAllocator;
- }
- }
-
/**
* Casting.
*
@@ -917,13 +903,13 @@ struct Integer
if (op == ">>")
out
{
+ assert(rep.length || !sign, "0 should be positive.");
assert(!rep.length || rep[0]);
}
body
{
immutable step = n / 8;
- initialize();
if (step >= rep.length)
{
allocator.resizeArray(rep, 0);
@@ -994,6 +980,7 @@ struct Integer
if (op == "<<")
out
{
+ assert(rep.length || !sign, "0 should be positive.");
assert(!rep.length || rep[0]);
}
body
@@ -1004,7 +991,6 @@ struct Integer
immutable bit = n % 8;
immutable delta = 8 - bit;
- initialize();
if (cast(ubyte) (rep[0] >> delta))
{
allocator.resizeArray(rep, i + n / 8 + 1);
@@ -1043,7 +1029,6 @@ struct Integer
if (op == "<<" || op == ">>" || op == "+" || op == "-" || op == "/"
|| op == "*" || op == "^^" || op == "%")
{
- initialize();
auto ret = Integer(this, allocator);
mixin("ret " ~ op ~ "= n;");
return ret;
@@ -1065,9 +1050,10 @@ struct Integer
if (op == "+" || op == "-" || op == "/"
|| op == "*" || op == "^^" || op == "%")
{
- initialize();
auto ret = Integer(this, allocator);
mixin("ret " ~ op ~ "= h;");
return ret;
}
+
+ mixin DefaultAllocator;
}
diff --git a/source/tanya/math/package.d b/source/tanya/math/package.d
index 9eb5ed4..e6cc4f9 100644
--- a/source/tanya/math/package.d
+++ b/source/tanya/math/package.d
@@ -103,7 +103,7 @@ bool isPseudoprime(ulong x) nothrow pure @safe @nogc
unittest
{
uint[30] known = [74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719,
- 74843, 74747, 74759, 74761, 74771, 74779, 74797, 74821,
+ 74843, 74747, 74759, 74761, 74771, 74779, 74797, 74821,
74827, 9973, 104729, 15485867, 49979693, 104395303,
593441861, 104729, 15485867, 49979693, 104395303,
593441861, 899809363, 982451653];
diff --git a/source/tanya/memory/allocator.d b/source/tanya/memory/allocator.d
index fb86818..c9b7386 100644
--- a/source/tanya/memory/allocator.d
+++ b/source/tanya/memory/allocator.d
@@ -28,7 +28,7 @@ interface Allocator
*
* Returns: Pointer to the new allocated memory.
*/
- void[] allocate(size_t size) shared nothrow @safe @nogc;
+ void[] allocate(size_t size) shared nothrow @nogc;
/**
* Deallocates a memory block.
@@ -38,7 +38,7 @@ interface Allocator
*
* Returns: Whether the deallocation was successful.
*/
- bool deallocate(void[] p) shared nothrow @safe @nogc;
+ bool deallocate(void[] p) shared nothrow @nogc;
/**
* Increases or decreases the size of a memory block.
@@ -49,5 +49,32 @@ interface Allocator
*
* Returns: Pointer to the allocated memory.
*/
- bool reallocate(ref void[] p, size_t size) shared nothrow @safe @nogc;
+ bool reallocate(ref void[] p, size_t size) shared nothrow @nogc;
+}
+
+/**
+ * The mixin generates common methods for classes and structs using
+ * allocators. It provides a protected member and a read-only property,
+ * that checks if an allocator was already set and sets it to the default
+ * one, if not (useful for structs which don't have a default constructor).
+ */
+mixin template DefaultAllocator()
+{
+ /// Allocator.
+ protected shared Allocator allocator_;
+
+ /**
+ * This property checks if the allocator was set in the constructor
+ * and sets it to the default one, if not.
+ *
+ * Returns: Used allocator.
+ */
+ @property shared(Allocator) allocator() nothrow @safe @nogc
+ {
+ if (allocator_ is null)
+ {
+ allocator_ = defaultAllocator;
+ }
+ return allocator_;
+ }
}
diff --git a/source/tanya/memory/mmappool.d b/source/tanya/memory/mmappool.d
index e915659..788407e 100644
--- a/source/tanya/memory/mmappool.d
+++ b/source/tanya/memory/mmappool.d
@@ -73,7 +73,7 @@ final class MmapPool : Allocator
*
* Returns: Pointer to the new allocated memory.
*/
- void[] allocate(size_t size) shared nothrow @trusted
+ void[] allocate(size_t size) shared nothrow
{
if (!size)
{
@@ -91,7 +91,7 @@ final class MmapPool : Allocator
}
///
- @safe nothrow unittest
+ nothrow unittest
{
auto p = MmapPool.instance.allocate(20);
@@ -167,7 +167,7 @@ final class MmapPool : Allocator
*
* Returns: Whether the deallocation was successful.
*/
- bool deallocate(void[] p) shared nothrow @trusted
+ bool deallocate(void[] p) shared nothrow
{
if (p is null)
{
@@ -207,7 +207,7 @@ final class MmapPool : Allocator
}
///
- @safe nothrow unittest
+ nothrow unittest
{
auto p = MmapPool.instance.allocate(20);
@@ -223,7 +223,7 @@ final class MmapPool : Allocator
*
* Returns: Whether the reallocation was successful.
*/
- bool reallocate(ref void[] p, size_t size) shared nothrow @trusted
+ bool reallocate(ref void[] p, size_t size) shared nothrow
{
void[] reallocP;
@@ -291,7 +291,7 @@ final class MmapPool : Allocator
*
* Returns: Global $(D_PSYMBOL MmapPool) instance.
*/
- static @property ref shared(MmapPool) instance() nothrow @trusted
+ static @property ref shared(MmapPool) instance() nothrow
{
if (instance_ is null)
{
@@ -310,7 +310,7 @@ final class MmapPool : Allocator
}
///
- @safe nothrow unittest
+ nothrow unittest
{
assert(instance is instance);
}
diff --git a/source/tanya/memory/package.d b/source/tanya/memory/package.d
index a19796e..e7564c4 100644
--- a/source/tanya/memory/package.d
+++ b/source/tanya/memory/package.d
@@ -20,7 +20,7 @@ private extern (C) void _d_monitordelete(Object h, bool det) nothrow @nogc;
shared Allocator allocator;
-shared static this() nothrow @safe @nogc
+shared static this() nothrow @trusted @nogc
{
import tanya.memory.mmappool;
allocator = MmapPool.instance;
@@ -75,17 +75,20 @@ bool resizeArray(T)(shared Allocator allocator,
void[] buf = array;
immutable oldLength = array.length;
- if (!allocator.reallocate(buf, length * T.sizeof))
- {
- return false;
- }
- // Casting from void[] is unsafe, but we know we cast to the original type
- array = () @trusted { return cast(T[]) buf; }();
- if (oldLength < length)
+ auto result = () @trusted {
+ if (!allocator.reallocate(buf, length * T.sizeof))
+ {
+ return false;
+ }
+ // Casting from void[] is unsafe, but we know we cast to the original type.
+ array = cast(T[]) buf;
+ return true;
+ }();
+ if (result && oldLength < length)
{
array[oldLength .. $] = init;
}
- return true;
+ return result;
}
///
@@ -106,26 +109,6 @@ unittest
assert(p is null);
}
-private void deStruct(T)(ref T s)
- if (is(T == struct))
-{
- static if (__traits(hasMember, T, "__xdtor")
- && __traits(isSame, T, __traits(parent, s.__xdtor)))
- {
- s.__xdtor();
- }
- auto buf = (cast(ubyte*) &s)[0 .. T.sizeof];
- auto init = cast(ubyte[])typeid(T).initializer();
- if (init.ptr is null) // null ptr means initialize to 0s
- {
- buf[] = 0;
- }
- else
- {
- buf[] = init[];
- }
-}
-
/**
* Destroys and deallocates $(D_PARAM p) of type $(D_PARAM T).
* It is assumed the respective entities had been allocated with the same
@@ -136,17 +119,18 @@ private void deStruct(T)(ref T s)
* allocator = Allocator the $(D_PARAM p) was allocated with.
* p = Object or array to be destroyed.
*/
-void dispose(T)(shared Allocator allocator, T* p)
+void dispose(T)(shared Allocator allocator, auto ref T* p)
{
- static if (hasElaborateDestructor!T)
- {
- deStruct(*p);
- }
- allocator.deallocate((cast(void*) p)[0 .. T.sizeof]);
+ static if (hasElaborateDestructor!T)
+ {
+ destroy(*p);
+ }
+ () @trusted { allocator.deallocate((cast(void*) p)[0 .. T.sizeof]); }();
+ p = null;
}
/// Ditto.
-void dispose(T)(shared Allocator allocator, T p)
+void dispose(T)(shared Allocator allocator, auto ref T p)
if (is(T == class) || is(T == interface))
{
if (p is null)
@@ -172,7 +156,8 @@ void dispose(T)(shared Allocator allocator, T p)
auto support = ptr[0 .. typeid(ob).initializer.length];
scope (success)
{
- allocator.deallocate(support);
+ () @trusted { allocator.deallocate(support); }();
+ p = null;
}
auto ppv = cast(void**) ptr;
@@ -193,7 +178,7 @@ void dispose(T)(shared Allocator allocator, T p)
// shouldn't throw and if it does, it is an error anyway.
if (c.destructor)
{
- (cast(void function (Object) nothrow @nogc) c.destructor)(ob);
+ (cast(void function (Object) nothrow @safe @nogc) c.destructor)(ob);
}
}
while ((c = c.base) !is null);
@@ -202,19 +187,18 @@ void dispose(T)(shared Allocator allocator, T p)
{
_d_monitordelete(cast(Object) ptr, true);
}
- auto w = (*pc).initializer;
- ptr[0 .. w.length] = w[];
}
/// Ditto.
-void dispose(T)(shared Allocator allocator, T[] array)
+void dispose(T)(shared Allocator allocator, auto ref T[] array)
{
- static if (hasElaborateDestructor!(typeof(array[0])))
- {
- foreach (ref e; array)
- {
- deStruct(e);
- }
- }
- allocator.deallocate(array);
+ static if (hasElaborateDestructor!(typeof(array[0])))
+ {
+ foreach (ref e; array)
+ {
+ destroy(e);
+ }
+ }
+ () @trusted { allocator.deallocate(array); }();
+ array = null;
}
diff --git a/source/tanya/network/socket.d b/source/tanya/network/socket.d
index a63b231..281a4d2 100644
--- a/source/tanya/network/socket.d
+++ b/source/tanya/network/socket.d
@@ -425,9 +425,10 @@ else version (Windows)
DWORD dwBytes;
overlapped.handle = cast(HANDLE) socket;
overlapped.event = OverlappedSocketEvent.accept;
- overlapped.buffer.len = (sockaddr_in.sizeof + 16) * 2;
- overlapped.buffer.buf = makeArray!char(defaultAllocator,
- overlapped.buffer.len).ptr;
+
+ immutable len = (sockaddr_in.sizeof + 16) * 2;
+ overlapped.buffer.len = len;
+ overlapped.buffer.buf = cast(char*) defaultAllocator.allocate(len).ptr;
// We don't want to get any data now, but only start to accept the connections
BOOL result = acceptExtension(handle_,
@@ -1267,12 +1268,12 @@ class InternetAddress : Address
port_ = port;
// Make C-string from host.
- char[] node = defaultAllocator.makeArray!char(host.length + 1);
+ auto node = cast(char[]) allocator.allocate(host.length + 1);
node[0.. $ - 1] = host;
node[$ - 1] = '\0';
scope (exit)
{
- defaultAllocator.dispose(node);
+ allocator.deallocate(node);
}
// Convert port to a C-string.
diff --git a/source/tanya/traits.d b/source/tanya/traits.d
index 74e18be..3f7dfcf 100644
--- a/source/tanya/traits.d
+++ b/source/tanya/traits.d
@@ -11,6 +11,7 @@
module tanya.traits;
import std.traits;
+import std.meta;
/**
* Params:
@@ -21,3 +22,36 @@ import std.traits;
*/
enum bool isReference(T) = isDynamicArray!T || isPointer!T
|| is(T == class) || is(T == interface);
+
+/**
+ * Initializer list.
+ *
+ * Generates a static array with elements from $(D_PARAM args). All elements
+ * should have the same type. It can be used in constructors which accept a
+ * list of the elements of the same type in the situations where variadic
+ * functions and templates can't be used.
+ *
+ * Params:
+ * Args = Argument type.
+ * args = Arguments.
+ */
+static enum IL(Args...)(Args args)
+ if (Args.length > 0)
+{
+ alias BaseType = typeof(args[0]);
+
+ BaseType[args.length] result;
+
+ foreach (i, a; args)
+ {
+ static assert(isImplicitlyConvertible!(typeof(a), BaseType));
+ result[i] = a;
+ }
+ return result;
+}
+
+///
+unittest
+{
+ static assert(IL(1, 5, 8).length == 3);
+}