Add capacity capabilities to the vector
This commit is contained in:
parent
c1fb89af99
commit
40857e69b7
@ -48,7 +48,7 @@ class EpollLoop : SelectorLoop
|
|||||||
throw MmapPool.instance.make!BadLoopException("epoll initialization failed");
|
throw MmapPool.instance.make!BadLoopException("epoll initialization failed");
|
||||||
}
|
}
|
||||||
super();
|
super();
|
||||||
events = MmapPool.instance.makeArray!epoll_event(maxEvents);
|
MmapPool.instance.resizeArray(events, maxEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,8 +165,8 @@ class KqueueLoop : SelectorLoop
|
|||||||
{
|
{
|
||||||
throw MmapPool.instance.make!BadLoopException("epoll initialization failed");
|
throw MmapPool.instance.make!BadLoopException("epoll initialization failed");
|
||||||
}
|
}
|
||||||
events = MmapPool.instance.makeArray!kevent_t(64);
|
MmapPool.instance.resizeArray(events, 64);
|
||||||
changes = MmapPool.instance.makeArray!kevent_t(64);
|
MmapPool.instance.resizeArray(changes, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -116,7 +116,7 @@ abstract class SelectorLoop : Loop
|
|||||||
this() @nogc
|
this() @nogc
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
connections = MmapPool.instance.makeArray!ConnectionWatcher(maxEvents);
|
MmapPool.instance.resizeArray(connections, maxEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
~this() @nogc
|
~this() @nogc
|
||||||
|
@ -10,11 +10,23 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.container.vector;
|
module tanya.container.vector;
|
||||||
|
|
||||||
|
import core.exception;
|
||||||
import std.algorithm.comparison;
|
import std.algorithm.comparison;
|
||||||
import std.range.primitives;
|
import std.range.primitives;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
|
|
||||||
|
version (unittest)
|
||||||
|
{
|
||||||
|
import tanya.traits;
|
||||||
|
struct TestA
|
||||||
|
{
|
||||||
|
~this() @nogc
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One dimensional array.
|
* One dimensional array.
|
||||||
*
|
*
|
||||||
@ -26,11 +38,13 @@ template Vector(T)
|
|||||||
/**
|
/**
|
||||||
* Defines the container's primary range.
|
* Defines the container's primary range.
|
||||||
*/
|
*/
|
||||||
struct Range
|
struct Range(V)
|
||||||
{
|
{
|
||||||
private Vector* data;
|
private alias E = typeof(data.vector[0]);
|
||||||
|
|
||||||
private @property ref inout(Vector) outer() inout return
|
private V* data;
|
||||||
|
|
||||||
|
private @property ref inout(V) outer() inout return
|
||||||
{
|
{
|
||||||
return *data;
|
return *data;
|
||||||
}
|
}
|
||||||
@ -40,10 +54,15 @@ template Vector(T)
|
|||||||
invariant
|
invariant
|
||||||
{
|
{
|
||||||
assert(start <= end);
|
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;
|
this.data = &data;
|
||||||
start = a;
|
start = a;
|
||||||
@ -67,22 +86,12 @@ template Vector(T)
|
|||||||
|
|
||||||
alias opDollar = length;
|
alias opDollar = length;
|
||||||
|
|
||||||
@property ref inout(T) front() inout
|
@property ref inout(E) front() inout
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
{
|
||||||
return outer[start];
|
return outer[start];
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(T) back() inout
|
@property ref inout(E) back() inout
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
{
|
||||||
return outer[end - 1];
|
return outer[end - 1];
|
||||||
}
|
}
|
||||||
@ -107,12 +116,7 @@ template Vector(T)
|
|||||||
--end;
|
--end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref inout(T) opIndex(in size_t i) inout
|
ref inout(E) opIndex(in size_t i) inout
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(start + i < end);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
{
|
||||||
return outer[start + i];
|
return outer[start + i];
|
||||||
}
|
}
|
||||||
@ -133,60 +137,24 @@ template Vector(T)
|
|||||||
return typeof(return)(outer, start + i, start + j);
|
return typeof(return)(outer, start + i, start + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
Range opIndex()
|
static if (isMutable!V)
|
||||||
{
|
{
|
||||||
return typeof(return)(outer, start, end);
|
Range opIndexAssign(T value)
|
||||||
}
|
|
||||||
|
|
||||||
Range opSlice(in size_t i, in size_t j)
|
|
||||||
in
|
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
return outer[start .. end] = value;
|
return outer[start .. end] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Range opSliceAssign(in T value, in size_t i, in size_t j)
|
Range opSliceAssign(T value, in size_t i, in size_t j)
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(start + j <= end);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
{
|
||||||
return outer[start + i .. start + j] = value;
|
return outer[start + i .. start + j] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Range opSliceAssign(in Range value, in size_t i, in size_t j)
|
Range opSliceAssign(Range value, in size_t i, in size_t j)
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(length == value.length);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
{
|
||||||
return outer[start + i .. start + j] = value;
|
return outer[start + i .. start + j] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Range opSliceAssign(in T[] value, in size_t i, in size_t j)
|
Range opSliceAssign(T[] value, in size_t i, in size_t j)
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(j - i == value.length);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
{
|
||||||
return outer[start + i .. start + j] = value;
|
return outer[start + i .. start + j] = value;
|
||||||
}
|
}
|
||||||
@ -205,49 +173,92 @@ template Vector(T)
|
|||||||
/// Internal representation.
|
/// Internal representation.
|
||||||
private T[] vector;
|
private T[] vector;
|
||||||
|
|
||||||
/// The allocator.
|
|
||||||
private shared Allocator allocator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty $(D_PSYMBOL Vector).
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* allocator = The allocator should be used for the element
|
|
||||||
* allocations.
|
|
||||||
*/
|
|
||||||
this(shared Allocator allocator)
|
|
||||||
{
|
|
||||||
this.allocator = allocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new $(D_PSYMBOL Vector).
|
* Creates a new $(D_PSYMBOL Vector).
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* U = Variadic template for the constructor parameters.
|
* U = Type of the static array with the initial elements.
|
||||||
* params = Values to initialize the array with. The last parameter can
|
* params = Values to initialize the array with. Use $(D_PSYMBOL IL)
|
||||||
* be an allocator, if not, $(D_PSYMBOL defaultAllocator) is used.
|
* to generate a list.
|
||||||
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(U...)(U params)
|
this(U)(U init, shared Allocator allocator = defaultAllocator)
|
||||||
|
if (isStaticArray!U)
|
||||||
|
in
|
||||||
{
|
{
|
||||||
static if (isImplicitlyConvertible!(typeof(params[$ - 1]), Allocator))
|
static assert(init.length > 0);
|
||||||
{
|
|
||||||
allocator = params[$ - 1];
|
|
||||||
auto values = params[0 .. $ - 1];
|
|
||||||
}
|
}
|
||||||
else
|
body
|
||||||
{
|
{
|
||||||
allocator = defaultAllocator;
|
this(allocator);
|
||||||
alias values = params;
|
vector = cast(T[]) allocator.allocate(init.length * T.sizeof);
|
||||||
|
if (vector is null)
|
||||||
|
{
|
||||||
|
onOutOfMemoryError();
|
||||||
|
}
|
||||||
|
vector[0 .. $] = init[0 .. $];
|
||||||
|
length_ = init.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeArray!T(allocator, vector, values.length);
|
/// Ditto.
|
||||||
length_ = values.length;
|
this(U)(U init, shared Allocator allocator = defaultAllocator) const
|
||||||
|
if (isStaticArray!U)
|
||||||
foreach (i, v; values)
|
in
|
||||||
{
|
{
|
||||||
vector[i] = v;
|
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)
|
||||||
|
{
|
||||||
|
onOutOfMemoryError();
|
||||||
|
}
|
||||||
|
buf[0 .. $] = init[0 .. $];
|
||||||
|
vector = cast(const (T[])) buf;
|
||||||
|
length_ = init.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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)
|
||||||
|
{
|
||||||
|
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()
|
~this()
|
||||||
{
|
{
|
||||||
if (allocator is null)
|
allocator.dispose(vector);
|
||||||
{
|
|
||||||
allocator = defaultAllocator;
|
|
||||||
}
|
|
||||||
dispose(allocator, vector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -267,15 +274,16 @@ template Vector(T)
|
|||||||
*/
|
*/
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
length_ = 0;
|
length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v = defaultAllocator.make!(Vector!int)(18, 20, 15);
|
auto v = Vector!int(IL(18, 20, 15));
|
||||||
v.clear();
|
v.clear();
|
||||||
assert(v.length == 0);
|
assert(v.length == 0);
|
||||||
|
assert(v.capacity == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -295,37 +303,7 @@ template Vector(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
size_t opDollar() inout const
|
alias opDollar = length;
|
||||||
{
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reserves space for $(D_PARAM n) elements.
|
|
||||||
*/
|
|
||||||
void reserve(in size_t n)
|
|
||||||
{
|
|
||||||
if (allocator is null)
|
|
||||||
{
|
|
||||||
allocator = defaultAllocator;
|
|
||||||
}
|
|
||||||
if (vector.length < n)
|
|
||||||
{
|
|
||||||
allocator.resizeArray!T(vector, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
Vector!int v;
|
|
||||||
assert(v.capacity == 0);
|
|
||||||
assert(v.length == 0);
|
|
||||||
|
|
||||||
v.reserve(3);
|
|
||||||
assert(v.capacity == 3);
|
|
||||||
assert(v.length == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expands/shrinks the vector.
|
* Expands/shrinks the vector.
|
||||||
@ -334,8 +312,26 @@ template Vector(T)
|
|||||||
* len = New length.
|
* len = New length.
|
||||||
*/
|
*/
|
||||||
@property void length(in size_t len)
|
@property void length(in size_t len)
|
||||||
|
{
|
||||||
|
if (len > length)
|
||||||
{
|
{
|
||||||
reserve(len);
|
reserve(len);
|
||||||
|
vector[length .. len] = T.init;
|
||||||
|
}
|
||||||
|
else if (len < length)
|
||||||
|
{
|
||||||
|
static if (hasElaborateDestructor!T)
|
||||||
|
{
|
||||||
|
foreach (ref e; vector[len - 1 .. length_])
|
||||||
|
{
|
||||||
|
destroy(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
length_ = len;
|
length_ = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,11 +348,82 @@ template Vector(T)
|
|||||||
assert(v.length == 7);
|
assert(v.length == 7);
|
||||||
assert(v.capacity == 7);
|
assert(v.capacity == 7);
|
||||||
|
|
||||||
|
assert(v[$ - 1] == 0);
|
||||||
|
v[$ - 1] = 3;
|
||||||
|
assert(v[$ - 1] == 3);
|
||||||
|
|
||||||
v.length = 0;
|
v.length = 0;
|
||||||
assert(v.length == 0);
|
assert(v.length == 0);
|
||||||
assert(v.capacity == 7);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
Vector!int v;
|
||||||
|
assert(v.capacity == 0);
|
||||||
|
assert(v.length == 0);
|
||||||
|
|
||||||
|
v.reserve(3);
|
||||||
|
assert(v.capacity == 3);
|
||||||
|
assert(v.length == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
||||||
|
* size = Desired size.
|
||||||
|
*/
|
||||||
|
void shrink(in size_t size) @trusted
|
||||||
|
{
|
||||||
|
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.reserve(5);
|
||||||
|
v.insertBack(1);
|
||||||
|
v.insertBack(3);
|
||||||
|
assert(v.capacity == 5);
|
||||||
|
assert(v.length == 2);
|
||||||
|
|
||||||
|
v.shrink(4);
|
||||||
|
assert(v.capacity == 4);
|
||||||
|
assert(v.length == 2);
|
||||||
|
|
||||||
|
v.shrink(1);
|
||||||
|
assert(v.capacity == 2);
|
||||||
|
assert(v.length == 2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: $(D_KEYWORD true) if the vector is empty.
|
* Returns: $(D_KEYWORD true) if the vector is empty.
|
||||||
*/
|
*/
|
||||||
@ -381,14 +448,7 @@ template Vector(T)
|
|||||||
{
|
{
|
||||||
immutable toRemove = min(howMany, length);
|
immutable toRemove = min(howMany, length);
|
||||||
|
|
||||||
static if (hasElaborateDestructor!T)
|
length = length - toRemove;
|
||||||
{
|
|
||||||
foreach (ref e; vector[$ - toRemove ..$])
|
|
||||||
{
|
|
||||||
allocator.dispose(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
length_ -= toRemove;
|
|
||||||
|
|
||||||
return toRemove;
|
return toRemove;
|
||||||
}
|
}
|
||||||
@ -399,7 +459,7 @@ template Vector(T)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v = Vector!int(5, 18, 17);
|
auto v = Vector!int(IL(5, 18, 17));
|
||||||
|
|
||||||
assert(v.removeBack(0) == 0);
|
assert(v.removeBack(0) == 0);
|
||||||
assert(v.removeBack(2) == 2);
|
assert(v.removeBack(2) == 2);
|
||||||
@ -412,7 +472,7 @@ template Vector(T)
|
|||||||
*
|
*
|
||||||
* Returns: The number of elements inserted.
|
* Returns: The number of elements inserted.
|
||||||
*/
|
*/
|
||||||
size_t insertBack(in T el)
|
size_t insertBack(T el)
|
||||||
{
|
{
|
||||||
reserve(length + 1);
|
reserve(length + 1);
|
||||||
vector[length] = el;
|
vector[length] = el;
|
||||||
@ -421,12 +481,12 @@ template Vector(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
size_t insertBack(in Range el)
|
size_t insertBack(Range!Vector el)
|
||||||
{
|
{
|
||||||
immutable newLength = length + el.length;
|
immutable newLength = length + el.length;
|
||||||
|
|
||||||
reserve(newLength);
|
reserve(newLength);
|
||||||
vector[length .. newLength] = el.data.vector[el.start .. el.end];
|
vector[length .. newLength] = el.outer.vector[el.start .. el.end];
|
||||||
length_ = newLength;
|
length_ = newLength;
|
||||||
|
|
||||||
return el.length;
|
return el.length;
|
||||||
@ -486,7 +546,7 @@ template Vector(T)
|
|||||||
assert(v1.capacity == 4);
|
assert(v1.capacity == 4);
|
||||||
assert(v1[0] == 5 && v1[1] == 6 && v1[2] == 4 && v1[3] == 2);
|
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.insertBack(v2[]) == 2);
|
||||||
assert(v1.length == 6);
|
assert(v1.length == 6);
|
||||||
assert(v1.capacity == 6);
|
assert(v1.capacity == 6);
|
||||||
@ -504,7 +564,7 @@ template Vector(T)
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE length > pos)
|
* Precondition: $(D_INLINECODE length > pos)
|
||||||
*/
|
*/
|
||||||
T opIndexAssign(in T value, in size_t pos)
|
T opIndexAssign(T value, in size_t pos)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(length > pos);
|
assert(length > pos);
|
||||||
@ -515,7 +575,7 @@ template Vector(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
Range opIndexAssign(in T value)
|
Range!Vector opIndexAssign(T value)
|
||||||
{
|
{
|
||||||
vector[0 .. $] = value;
|
vector[0 .. $] = value;
|
||||||
return opIndex();
|
return opIndex();
|
||||||
@ -524,7 +584,7 @@ template Vector(T)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v1 = Vector!int(12, 1, 7);
|
auto v1 = Vector!int(IL(12, 1, 7));
|
||||||
|
|
||||||
v1[] = 3;
|
v1[] = 3;
|
||||||
assert(v1[0] == 3);
|
assert(v1[0] == 3);
|
||||||
@ -549,7 +609,19 @@ template Vector(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// 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);
|
return typeof(return)(this, 0, length);
|
||||||
}
|
}
|
||||||
@ -557,12 +629,18 @@ template Vector(T)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v = Vector!int(6, 123, 34, 5);
|
const v1 = Vector!int(IL(6, 123, 34, 5));
|
||||||
|
|
||||||
assert(v[0] == 6);
|
assert(v1[0] == 6);
|
||||||
assert(v[1] == 123);
|
assert(v1[1] == 123);
|
||||||
assert(v[2] == 34);
|
assert(v1[2] == 34);
|
||||||
assert(v[3] == 5);
|
assert(v1[3] == 5);
|
||||||
|
static assert(is(typeof(v1[0]) == const(int)));
|
||||||
|
static assert(is(typeof(v1[])));
|
||||||
|
|
||||||
|
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)
|
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
bool opEquals(typeof(this) v)
|
bool opEquals(typeof(this) v) const
|
||||||
{
|
{
|
||||||
return opEquals(v);
|
return opEquals(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
bool opEquals(ref typeof(this) v)
|
bool opEquals(ref typeof(this) v) const
|
||||||
{
|
{
|
||||||
return vector == v.vector;
|
return vector == v.vector;
|
||||||
}
|
}
|
||||||
@ -673,7 +751,7 @@ template Vector(T)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v = Vector!int(5, 15, 8);
|
auto v = Vector!int(IL(5, 15, 8));
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
foreach (j, ref e; v)
|
foreach (j, ref e; v)
|
||||||
@ -693,7 +771,7 @@ template Vector(T)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v = Vector!int(5, 15, 8);
|
auto v = Vector!int(IL(5, 15, 8));
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
foreach_reverse (j, ref e; v)
|
foreach_reverse (j, ref e; v)
|
||||||
@ -728,7 +806,7 @@ template Vector(T)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v = Vector!int(5);
|
auto v = Vector!int(IL(5));
|
||||||
|
|
||||||
assert(v.front == 5);
|
assert(v.front == 5);
|
||||||
|
|
||||||
@ -755,7 +833,7 @@ template Vector(T)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v = Vector!int(5);
|
auto v = Vector!int(IL(5));
|
||||||
|
|
||||||
assert(v.back == 5);
|
assert(v.back == 5);
|
||||||
|
|
||||||
@ -774,7 +852,7 @@ template Vector(T)
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE i <= j && j <= length)
|
* 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
|
in
|
||||||
{
|
{
|
||||||
assert(i <= j);
|
assert(i <= j);
|
||||||
@ -798,7 +876,7 @@ template Vector(T)
|
|||||||
* Precondition: $(D_INLINECODE i <= j && j <= length);
|
* Precondition: $(D_INLINECODE i <= j && j <= length);
|
||||||
* The lenghts of the ranges and slices match.
|
* 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
|
in
|
||||||
{
|
{
|
||||||
assert(i <= j);
|
assert(i <= j);
|
||||||
@ -811,7 +889,7 @@ template Vector(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// 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
|
in
|
||||||
{
|
{
|
||||||
assert(j - i == value.length);
|
assert(j - i == value.length);
|
||||||
@ -823,7 +901,7 @@ template Vector(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// 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
|
in
|
||||||
{
|
{
|
||||||
assert(j - i == value.length);
|
assert(j - i == value.length);
|
||||||
@ -837,8 +915,8 @@ template Vector(T)
|
|||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v1 = Vector!int(3, 3, 3);
|
auto v1 = Vector!int(IL(3, 3, 3));
|
||||||
auto v2 = Vector!int(1, 2);
|
auto v2 = Vector!int(IL(1, 2));
|
||||||
|
|
||||||
v1[0 .. 2] = 286;
|
v1[0 .. 2] = 286;
|
||||||
assert(v1[0] == 286);
|
assert(v1[0] == 286);
|
||||||
@ -849,20 +927,69 @@ template Vector(T)
|
|||||||
assert(v2[0] == 286);
|
assert(v2[0] == 286);
|
||||||
assert(v2[1] == 3);
|
assert(v2[1] == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mixin DefaultAllocator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
auto v = Vector!int(5, 15, 8);
|
auto v = Vector!int(IL(5, 15, 8));
|
||||||
|
|
||||||
assert(v.front == 5);
|
assert(v.front == 5);
|
||||||
assert(v[1] == 15);
|
assert(v[1] == 15);
|
||||||
assert(v.back == 8);
|
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);
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,6 @@ struct Integer
|
|||||||
{
|
{
|
||||||
private ubyte[] rep;
|
private ubyte[] rep;
|
||||||
private bool sign;
|
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.
|
* Creates a multiple precision integer.
|
||||||
@ -52,25 +46,29 @@ struct Integer
|
|||||||
{
|
{
|
||||||
assignInt(value);
|
assignInt(value);
|
||||||
}
|
}
|
||||||
else
|
else if (value.length > 0)
|
||||||
{
|
{
|
||||||
rep = () @trusted {
|
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);
|
value.rep.copy(rep);
|
||||||
sign = value.sign;
|
sign = value.sign;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
this(shared Allocator allocator) nothrow @safe @nogc
|
this(shared Allocator allocator) pure nothrow @safe @nogc
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
this.allocator = allocator;
|
allocator_ = allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @nogc unittest
|
private @nogc unittest
|
||||||
@ -86,23 +84,13 @@ struct Integer
|
|||||||
assert(h2.sign);
|
assert(h2.sign);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the internal representation.
|
||||||
|
*/
|
||||||
~this() nothrow @safe @nogc
|
~this() nothrow @safe @nogc
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(allocator !is null || !rep.length);
|
|
||||||
}
|
|
||||||
body
|
|
||||||
{
|
|
||||||
if (allocator !is null)
|
|
||||||
{
|
{
|
||||||
allocator.dispose(rep);
|
allocator.dispose(rep);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
Integer h; // allocator isn't set, but the destructor should work
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Figures out the minimum amount of space this value will take
|
* Figures out the minimum amount of space this value will take
|
||||||
@ -113,7 +101,6 @@ struct Integer
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
static assert(isIntegral!T);
|
static assert(isIntegral!T);
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
@ -169,7 +156,6 @@ struct Integer
|
|||||||
ref Integer opAssign(T)(in auto ref T value) nothrow @safe @nogc
|
ref Integer opAssign(T)(in auto ref T value) nothrow @safe @nogc
|
||||||
if (isIntegral!T || is(T == Integer))
|
if (isIntegral!T || is(T == Integer))
|
||||||
{
|
{
|
||||||
initialize();
|
|
||||||
static if (isIntegral!T)
|
static if (isIntegral!T)
|
||||||
{
|
{
|
||||||
assignInt(value);
|
assignInt(value);
|
||||||
@ -292,16 +278,22 @@ struct Integer
|
|||||||
assert(h1 > h2);
|
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 sum;
|
||||||
uint carry = 0;
|
uint carry = 0;
|
||||||
|
ubyte[] tmp;
|
||||||
|
|
||||||
if (h.length > length)
|
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];
|
tmp[h.length - length .. $] = rep[0 .. length];
|
||||||
rep = tmp;
|
swap(rep, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto i = length;
|
auto i = length;
|
||||||
@ -327,15 +319,16 @@ struct Integer
|
|||||||
if (carry)
|
if (carry)
|
||||||
{
|
{
|
||||||
// Still overflowed; allocate more space
|
// Still overflowed; allocate more space
|
||||||
auto tmp = allocator.makeArray!ubyte(length + 1);
|
void[]* vtmp = cast(void[]*) &tmp;
|
||||||
|
allocator.reallocate(*vtmp, length + 1);
|
||||||
tmp[1 .. $] = rep[0 .. length];
|
tmp[1 .. $] = rep[0 .. length];
|
||||||
tmp[0] = 0x01;
|
tmp[0] = 0x01;
|
||||||
rep = tmp;
|
swap(rep, tmp);
|
||||||
|
}
|
||||||
|
allocator.deallocate(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
private void subtract(in ref ubyte[] h) nothrow @trusted @nogc
|
||||||
|
|
||||||
private void subtract(in ref ubyte[] h) nothrow @safe @nogc
|
|
||||||
{
|
{
|
||||||
auto i = rep.length;
|
auto i = rep.length;
|
||||||
auto j = h.length;
|
auto j = h.length;
|
||||||
@ -369,13 +362,14 @@ struct Integer
|
|||||||
immutable offset = rep.countUntil!((const ref a) => a != 0);
|
immutable offset = rep.countUntil!((const ref a) => a != 0);
|
||||||
if (offset > 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);
|
rep[offset .. $].copy(tmp);
|
||||||
|
allocator.deallocate(rep);
|
||||||
rep = tmp;
|
rep = tmp;
|
||||||
}
|
}
|
||||||
else if (offset == -1)
|
else if (offset == -1)
|
||||||
{
|
{
|
||||||
allocator.resizeArray(rep, 0);
|
allocator.dispose(rep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,11 +386,11 @@ struct Integer
|
|||||||
if ((op == "+") || (op == "-"))
|
if ((op == "+") || (op == "-"))
|
||||||
out
|
out
|
||||||
{
|
{
|
||||||
|
assert(rep.length || !sign, "0 should be positive.");
|
||||||
assert(!rep.length || rep[0]);
|
assert(!rep.length || rep[0]);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
initialize();
|
|
||||||
static if (op == "+")
|
static if (op == "+")
|
||||||
{
|
{
|
||||||
if (h.sign == sign)
|
if (h.sign == sign)
|
||||||
@ -505,6 +499,7 @@ struct Integer
|
|||||||
if (op == "*")
|
if (op == "*")
|
||||||
out
|
out
|
||||||
{
|
{
|
||||||
|
assert(rep.length || !sign, "0 should be positive.");
|
||||||
assert(!rep.length || rep[0]);
|
assert(!rep.length || rep[0]);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
@ -550,8 +545,6 @@ struct Integer
|
|||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
initialize();
|
|
||||||
|
|
||||||
auto divisor = Integer(h, allocator);
|
auto divisor = Integer(h, allocator);
|
||||||
size_t bitSize;
|
size_t bitSize;
|
||||||
|
|
||||||
@ -562,7 +555,9 @@ struct Integer
|
|||||||
}
|
}
|
||||||
static if (op == "/")
|
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,
|
// "bitPosition" keeps track of which bit, of the quotient,
|
||||||
@ -592,8 +587,8 @@ struct Integer
|
|||||||
|
|
||||||
static if (op == "/")
|
static if (op == "/")
|
||||||
{
|
{
|
||||||
swap(rep, quotient);
|
() @trusted { allocator.deallocate(rep); }();
|
||||||
allocator.dispose(quotient);
|
rep = quotient;
|
||||||
sign = sign == h.sign ? false : true;
|
sign = sign == h.sign ? false : true;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@ -628,6 +623,7 @@ struct Integer
|
|||||||
if (op == "^^")
|
if (op == "^^")
|
||||||
out
|
out
|
||||||
{
|
{
|
||||||
|
assert(rep.length || !sign, "0 should be positive.");
|
||||||
assert(!rep.length || rep[0]);
|
assert(!rep.length || rep[0]);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
@ -683,7 +679,6 @@ struct Integer
|
|||||||
Integer opUnary(string op)() nothrow @safe @nogc
|
Integer opUnary(string op)() nothrow @safe @nogc
|
||||||
if ((op == "+") || (op == "-") || (op == "~"))
|
if ((op == "+") || (op == "-") || (op == "~"))
|
||||||
{
|
{
|
||||||
initialize();
|
|
||||||
auto h = Integer(this, allocator);
|
auto h = Integer(this, allocator);
|
||||||
static if (op == "-")
|
static if (op == "-")
|
||||||
{
|
{
|
||||||
@ -772,12 +767,11 @@ struct Integer
|
|||||||
if ((op == "++") || (op == "--"))
|
if ((op == "++") || (op == "--"))
|
||||||
out
|
out
|
||||||
{
|
{
|
||||||
|
assert(rep.length || !sign, "0 should be positive.");
|
||||||
assert(!rep.length || rep[0]);
|
assert(!rep.length || rep[0]);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
initialize();
|
|
||||||
|
|
||||||
static if (op == "++")
|
static if (op == "++")
|
||||||
{
|
{
|
||||||
if (sign)
|
if (sign)
|
||||||
@ -848,14 +842,6 @@ struct Integer
|
|||||||
assert(h.rep[0] == 0x01);
|
assert(h.rep[0] == 0x01);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize() nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
if (allocator is null)
|
|
||||||
{
|
|
||||||
allocator = defaultAllocator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Casting.
|
* Casting.
|
||||||
*
|
*
|
||||||
@ -917,13 +903,13 @@ struct Integer
|
|||||||
if (op == ">>")
|
if (op == ">>")
|
||||||
out
|
out
|
||||||
{
|
{
|
||||||
|
assert(rep.length || !sign, "0 should be positive.");
|
||||||
assert(!rep.length || rep[0]);
|
assert(!rep.length || rep[0]);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
immutable step = n / 8;
|
immutable step = n / 8;
|
||||||
|
|
||||||
initialize();
|
|
||||||
if (step >= rep.length)
|
if (step >= rep.length)
|
||||||
{
|
{
|
||||||
allocator.resizeArray(rep, 0);
|
allocator.resizeArray(rep, 0);
|
||||||
@ -994,6 +980,7 @@ struct Integer
|
|||||||
if (op == "<<")
|
if (op == "<<")
|
||||||
out
|
out
|
||||||
{
|
{
|
||||||
|
assert(rep.length || !sign, "0 should be positive.");
|
||||||
assert(!rep.length || rep[0]);
|
assert(!rep.length || rep[0]);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
@ -1004,7 +991,6 @@ struct Integer
|
|||||||
immutable bit = n % 8;
|
immutable bit = n % 8;
|
||||||
immutable delta = 8 - bit;
|
immutable delta = 8 - bit;
|
||||||
|
|
||||||
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);
|
||||||
@ -1043,7 +1029,6 @@ struct Integer
|
|||||||
if (op == "<<" || op == ">>" || op == "+" || op == "-" || op == "/"
|
if (op == "<<" || op == ">>" || op == "+" || op == "-" || op == "/"
|
||||||
|| op == "*" || op == "^^" || op == "%")
|
|| op == "*" || op == "^^" || op == "%")
|
||||||
{
|
{
|
||||||
initialize();
|
|
||||||
auto ret = Integer(this, allocator);
|
auto ret = Integer(this, allocator);
|
||||||
mixin("ret " ~ op ~ "= n;");
|
mixin("ret " ~ op ~ "= n;");
|
||||||
return ret;
|
return ret;
|
||||||
@ -1065,9 +1050,10 @@ struct Integer
|
|||||||
if (op == "+" || op == "-" || op == "/"
|
if (op == "+" || op == "-" || op == "/"
|
||||||
|| op == "*" || op == "^^" || op == "%")
|
|| op == "*" || op == "^^" || op == "%")
|
||||||
{
|
{
|
||||||
initialize();
|
|
||||||
auto ret = Integer(this, allocator);
|
auto ret = Integer(this, allocator);
|
||||||
mixin("ret " ~ op ~ "= h;");
|
mixin("ret " ~ op ~ "= h;");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mixin DefaultAllocator;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ interface Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Pointer to the new allocated memory.
|
* 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.
|
* Deallocates a memory block.
|
||||||
@ -38,7 +38,7 @@ interface Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Whether the deallocation was successful.
|
* 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.
|
* Increases or decreases the size of a memory block.
|
||||||
@ -49,5 +49,32 @@ interface Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Pointer to the allocated memory.
|
* 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_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ final class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Pointer to the new allocated memory.
|
* Returns: Pointer to the new allocated memory.
|
||||||
*/
|
*/
|
||||||
void[] allocate(size_t size) shared nothrow @trusted
|
void[] allocate(size_t size) shared nothrow
|
||||||
{
|
{
|
||||||
if (!size)
|
if (!size)
|
||||||
{
|
{
|
||||||
@ -91,7 +91,7 @@ final class MmapPool : Allocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@safe nothrow unittest
|
nothrow unittest
|
||||||
{
|
{
|
||||||
auto p = MmapPool.instance.allocate(20);
|
auto p = MmapPool.instance.allocate(20);
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ final class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Whether the deallocation was successful.
|
* Returns: Whether the deallocation was successful.
|
||||||
*/
|
*/
|
||||||
bool deallocate(void[] p) shared nothrow @trusted
|
bool deallocate(void[] p) shared nothrow
|
||||||
{
|
{
|
||||||
if (p is null)
|
if (p is null)
|
||||||
{
|
{
|
||||||
@ -207,7 +207,7 @@ final class MmapPool : Allocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@safe nothrow unittest
|
nothrow unittest
|
||||||
{
|
{
|
||||||
auto p = MmapPool.instance.allocate(20);
|
auto p = MmapPool.instance.allocate(20);
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ final class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Whether the reallocation was successful.
|
* 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;
|
void[] reallocP;
|
||||||
|
|
||||||
@ -291,7 +291,7 @@ final class MmapPool : Allocator
|
|||||||
*
|
*
|
||||||
* Returns: Global $(D_PSYMBOL MmapPool) instance.
|
* 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)
|
if (instance_ is null)
|
||||||
{
|
{
|
||||||
@ -310,7 +310,7 @@ final class MmapPool : Allocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@safe nothrow unittest
|
nothrow unittest
|
||||||
{
|
{
|
||||||
assert(instance is instance);
|
assert(instance is instance);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ private extern (C) void _d_monitordelete(Object h, bool det) nothrow @nogc;
|
|||||||
|
|
||||||
shared Allocator allocator;
|
shared Allocator allocator;
|
||||||
|
|
||||||
shared static this() nothrow @safe @nogc
|
shared static this() nothrow @trusted @nogc
|
||||||
{
|
{
|
||||||
import tanya.memory.mmappool;
|
import tanya.memory.mmappool;
|
||||||
allocator = MmapPool.instance;
|
allocator = MmapPool.instance;
|
||||||
@ -75,17 +75,20 @@ bool resizeArray(T)(shared Allocator allocator,
|
|||||||
void[] buf = array;
|
void[] buf = array;
|
||||||
immutable oldLength = array.length;
|
immutable oldLength = array.length;
|
||||||
|
|
||||||
|
auto result = () @trusted {
|
||||||
if (!allocator.reallocate(buf, length * T.sizeof))
|
if (!allocator.reallocate(buf, length * T.sizeof))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Casting from void[] is unsafe, but we know we cast to the original type
|
// Casting from void[] is unsafe, but we know we cast to the original type.
|
||||||
array = () @trusted { return cast(T[]) buf; }();
|
array = cast(T[]) buf;
|
||||||
if (oldLength < length)
|
return true;
|
||||||
|
}();
|
||||||
|
if (result && oldLength < length)
|
||||||
{
|
{
|
||||||
array[oldLength .. $] = init;
|
array[oldLength .. $] = init;
|
||||||
}
|
}
|
||||||
return true;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -106,26 +109,6 @@ unittest
|
|||||||
assert(p is null);
|
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).
|
* Destroys and deallocates $(D_PARAM p) of type $(D_PARAM T).
|
||||||
* It is assumed the respective entities had been allocated with the same
|
* 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.
|
* allocator = Allocator the $(D_PARAM p) was allocated with.
|
||||||
* p = Object or array to be destroyed.
|
* 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)
|
static if (hasElaborateDestructor!T)
|
||||||
{
|
{
|
||||||
deStruct(*p);
|
destroy(*p);
|
||||||
}
|
}
|
||||||
allocator.deallocate((cast(void*) p)[0 .. T.sizeof]);
|
() @trusted { allocator.deallocate((cast(void*) p)[0 .. T.sizeof]); }();
|
||||||
|
p = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// 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 (is(T == class) || is(T == interface))
|
||||||
{
|
{
|
||||||
if (p is null)
|
if (p is null)
|
||||||
@ -172,7 +156,8 @@ void dispose(T)(shared Allocator allocator, T p)
|
|||||||
auto support = ptr[0 .. typeid(ob).initializer.length];
|
auto support = ptr[0 .. typeid(ob).initializer.length];
|
||||||
scope (success)
|
scope (success)
|
||||||
{
|
{
|
||||||
allocator.deallocate(support);
|
() @trusted { allocator.deallocate(support); }();
|
||||||
|
p = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ppv = cast(void**) ptr;
|
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.
|
// shouldn't throw and if it does, it is an error anyway.
|
||||||
if (c.destructor)
|
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);
|
while ((c = c.base) !is null);
|
||||||
@ -202,19 +187,18 @@ void dispose(T)(shared Allocator allocator, T p)
|
|||||||
{
|
{
|
||||||
_d_monitordelete(cast(Object) ptr, true);
|
_d_monitordelete(cast(Object) ptr, true);
|
||||||
}
|
}
|
||||||
auto w = (*pc).initializer;
|
|
||||||
ptr[0 .. w.length] = w[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// 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])))
|
static if (hasElaborateDestructor!(typeof(array[0])))
|
||||||
{
|
{
|
||||||
foreach (ref e; array)
|
foreach (ref e; array)
|
||||||
{
|
{
|
||||||
deStruct(e);
|
destroy(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allocator.deallocate(array);
|
() @trusted { allocator.deallocate(array); }();
|
||||||
|
array = null;
|
||||||
}
|
}
|
||||||
|
@ -425,9 +425,10 @@ else version (Windows)
|
|||||||
DWORD dwBytes;
|
DWORD dwBytes;
|
||||||
overlapped.handle = cast(HANDLE) socket;
|
overlapped.handle = cast(HANDLE) socket;
|
||||||
overlapped.event = OverlappedSocketEvent.accept;
|
overlapped.event = OverlappedSocketEvent.accept;
|
||||||
overlapped.buffer.len = (sockaddr_in.sizeof + 16) * 2;
|
|
||||||
overlapped.buffer.buf = makeArray!char(defaultAllocator,
|
immutable len = (sockaddr_in.sizeof + 16) * 2;
|
||||||
overlapped.buffer.len).ptr;
|
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
|
// We don't want to get any data now, but only start to accept the connections
|
||||||
BOOL result = acceptExtension(handle_,
|
BOOL result = acceptExtension(handle_,
|
||||||
@ -1267,12 +1268,12 @@ class InternetAddress : Address
|
|||||||
port_ = port;
|
port_ = port;
|
||||||
|
|
||||||
// Make C-string from host.
|
// 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[0.. $ - 1] = host;
|
||||||
node[$ - 1] = '\0';
|
node[$ - 1] = '\0';
|
||||||
scope (exit)
|
scope (exit)
|
||||||
{
|
{
|
||||||
defaultAllocator.dispose(node);
|
allocator.deallocate(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert port to a C-string.
|
// Convert port to a C-string.
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
module tanya.traits;
|
module tanya.traits;
|
||||||
|
|
||||||
import std.traits;
|
import std.traits;
|
||||||
|
import std.meta;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
@ -21,3 +22,36 @@ import std.traits;
|
|||||||
*/
|
*/
|
||||||
enum bool isReference(T) = isDynamicArray!T || isPointer!T
|
enum bool isReference(T) = isDynamicArray!T || isPointer!T
|
||||||
|| is(T == class) || is(T == interface);
|
|| 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);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user