Implement insertion into the vector

This commit is contained in:
Eugen Wissner 2016-12-15 15:00:06 +01:00
parent 061cd6264b
commit c1fb89af99
4 changed files with 667 additions and 588 deletions

View File

@ -11,6 +11,7 @@
module tanya.container.vector;
import std.algorithm.comparison;
import std.range.primitives;
import std.traits;
import tanya.memory;
@ -20,18 +21,18 @@ import tanya.memory;
* Params:
* T = Content type.
*/
class Vector(T)
template Vector(T)
{
/**
* Defines the container's primary range.
*/
struct Range(V)
struct Range
{
private V[1] data;
private Vector* data;
private @property ref inout(V) outer() inout
private @property ref inout(Vector) outer() inout return
{
return data[0];
return *data;
}
private size_t start, end;
@ -39,13 +40,12 @@ class Vector(T)
invariant
{
assert(start <= end);
assert(start == 0 || end > 0);
}
private alias ElementType = typeof(data[0].vector[0]);
protected this(V data, in size_t a, in size_t b)
protected this(ref Vector data, in size_t a, in size_t b)
{
this.data = data;
this.data = &data;
start = a;
end = b;
}
@ -57,7 +57,7 @@ class Vector(T)
@property bool empty() inout const
{
return start >= end;
return start == end;
}
@property size_t length() inout const
@ -67,7 +67,7 @@ class Vector(T)
alias opDollar = length;
@property ref inout(ElementType) front() inout
@property ref inout(T) front() inout
in
{
assert(!empty);
@ -77,7 +77,7 @@ class Vector(T)
return outer[start];
}
@property ref inout(ElementType) back() inout
@property ref inout(T) back() inout
in
{
assert(!empty);
@ -107,7 +107,7 @@ class Vector(T)
--end;
}
ref inout(ElementType) opIndex(in size_t i) inout
ref inout(T) opIndex(in size_t i) inout
in
{
assert(start + i < end);
@ -133,12 +133,12 @@ class Vector(T)
return typeof(return)(outer, start + i, start + j);
}
Range!(const(V)) opIndex() const
Range opIndex()
{
return typeof(return)(outer, start, end);
}
Range!(const(V)) opSlice(in size_t i, in size_t j) const
Range opSlice(in size_t i, in size_t j)
in
{
assert(i <= j);
@ -149,9 +149,9 @@ class Vector(T)
return typeof(return)(outer, start + i, start + j);
}
static if (isMutable!V)
static if (isMutable!Vector)
{
Range opIndexAssign(in ElementType value)
Range opIndexAssign(in T value)
in
{
assert(end <= outer.length);
@ -161,7 +161,7 @@ class Vector(T)
return outer[start .. end] = value;
}
Range opSliceAssign(in ElementType value, in size_t i, in size_t j)
Range opSliceAssign(in T value, in size_t i, in size_t j)
in
{
assert(start + j <= end);
@ -171,7 +171,7 @@ class Vector(T)
return outer[start + i .. start + j] = value;
}
Range opSliceAssign(in Range!Vector value, in size_t i, in size_t j)
Range opSliceAssign(in Range value, in size_t i, in size_t j)
in
{
assert(length == value.length);
@ -193,6 +193,21 @@ class Vector(T)
}
}
struct Vector
{
private size_t length_;
invariant
{
assert(length_ <= vector.length);
}
/// Internal representation.
private T[] vector;
/// The allocator.
private shared Allocator allocator;
/**
* Creates an empty $(D_PSYMBOL Vector).
*
@ -200,7 +215,7 @@ class Vector(T)
* allocator = The allocator should be used for the element
* allocations.
*/
this(shared Allocator allocator = defaultAllocator)
this(shared Allocator allocator)
{
this.allocator = allocator;
}
@ -227,6 +242,8 @@ class Vector(T)
}
resizeArray!T(allocator, vector, values.length);
length_ = values.length;
foreach (i, v; values)
{
vector[i] = v;
@ -238,6 +255,10 @@ class Vector(T)
*/
~this()
{
if (allocator is null)
{
allocator = defaultAllocator;
}
dispose(allocator, vector);
}
@ -246,24 +267,31 @@ class Vector(T)
*/
void clear()
{
resizeArray!T(allocator, vector, 0);
length_ = 0;
}
///
unittest
{
auto v = defaultAllocator.make!(Vector!int)(18, 20, 15);
v.clear();
assert(v.length == 0);
}
/**
* Returns: How many elements the vector can contain without reallocating.
*/
@property size_t capacity() inout const
{
return vector.length;
}
/**
* Returns: Vector length.
*/
@property size_t length() inout const
{
return vector.length;
return length_;
}
/// Ditto.
@ -273,29 +301,60 @@ class Vector(T)
}
/**
* Expands/shrinks the vector.
*
* Params:
* length = New length.
* Reserves space for $(D_PARAM n) elements.
*/
@property void length(in size_t length)
void reserve(in size_t n)
{
resizeArray!T(allocator, vector, length);
if (allocator is null)
{
allocator = defaultAllocator;
}
if (vector.length < n)
{
allocator.resizeArray!T(vector, n);
}
}
///
unittest
{
auto v = defaultAllocator.make!(Vector!int);
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.
*
* Params:
* len = New length.
*/
@property void length(in size_t len)
{
reserve(len);
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);
v.length = 0;
assert(v.length == 0);
assert(v.capacity == 7);
}
/**
@ -303,7 +362,7 @@ class Vector(T)
*/
@property bool empty() inout const
{
return vector.length == 0;
return length == 0;
}
/**
@ -318,7 +377,7 @@ class Vector(T)
*
* Returns: The number of elements removed
*/
size_t removeBack(in size_t howMany)
size_t removeBack(in size_t howMany = 1)
{
immutable toRemove = min(howMany, length);
@ -329,22 +388,109 @@ class Vector(T)
allocator.dispose(e);
}
}
length = length - toRemove;
length_ -= toRemove;
return toRemove;
}
/// Ditto.
alias remove = removeBack;
///
unittest
{
auto v = defaultAllocator.make!(Vector!int)(5, 18, 17);
auto v = Vector!int(5, 18, 17);
assert(v.removeBack(0) == 0);
assert(v.removeBack(2) == 2);
assert(v.removeBack(3) == 1);
assert(v.removeBack(3) == 0);
}
defaultAllocator.dispose(v);
/**
* Inserts the $(D_PARAM el) into the vector.
*
* Returns: The number of elements inserted.
*/
size_t insertBack(in T el)
{
reserve(length + 1);
vector[length] = el;
++length_;
return 1;
}
/// Ditto.
size_t insertBack(in Range el)
{
immutable newLength = length + el.length;
reserve(newLength);
vector[length .. newLength] = el.data.vector[el.start .. el.end];
length_ = newLength;
return el.length;
}
/// Ditto.
size_t insertBack(R)(R el)
if (isInputRange!R && isImplicitlyConvertible!(ElementType!R, T))
{
immutable rLen = walkLength(el);
reserve(length + rLen);
while (!el.empty)
{
vector[length_] = el.front;
el.popFront();
length_++;
}
return rLen;
}
/// Ditto.
alias insert = insertBack;
///
unittest
{
struct TestRange
{
int counter = 6;
int front()
{
return counter;
}
void popFront()
{
counter -= 2;
}
bool empty()
{
return counter == 0;
}
}
Vector!int v1;
assert(v1.insertBack(5) == 1);
assert(v1.length == 1);
assert(v1.capacity == 1);
assert(v1.back == 5);
assert(v1.insertBack(TestRange()) == 3);
assert(v1.length == 4);
assert(v1.capacity == 4);
assert(v1[0] == 5 && v1[1] == 6 && v1[2] == 4 && v1[3] == 2);
auto v2 = Vector!int(34, 234);
assert(v1.insertBack(v2[]) == 2);
assert(v1.length == 6);
assert(v1.capacity == 6);
assert(v1[4] == 34 && v1[5] == 234);
}
/**
@ -352,6 +498,7 @@ class Vector(T)
*
* Params:
* value = Value.
* pos = Position.
*
* Returns: Assigned value.
*
@ -368,28 +515,26 @@ class Vector(T)
}
/// Ditto.
Range!Vector opIndexAssign(in T value)
Range opIndexAssign(in T value)
{
vector[0..$] = value;
vector[0 .. $] = value;
return opIndex();
}
///
unittest
{
auto v1 = defaultAllocator.make!(Vector!int)(12, 1, 7);
auto v1 = Vector!int(12, 1, 7);
v1[] = 3;
assert(v1[0] == 3);
assert(v1[1] == 3);
assert(v1[2] == 3);
defaultAllocator.dispose(v1);
}
/**
* Returns: The value on index $(D_PARAM pos).
* Returns: The value on index $(D_PARAM pos) or a range that iterates over
* elements of the vector, in forward order.
*
* Precondition: $(D_INLINECODE length > pos)
*/
@ -403,17 +548,21 @@ class Vector(T)
return vector[pos];
}
/// Ditto.
Range opIndex()
{
return typeof(return)(this, 0, length);
}
///
unittest
{
auto v = defaultAllocator.make!(Vector!int)(6, 123, 34, 5);
auto v = Vector!int(6, 123, 34, 5);
assert(v[0] == 6);
assert(v[1] == 123);
assert(v[2] == 34);
assert(v[3] == 5);
defaultAllocator.dispose(v);
}
/**
@ -425,19 +574,21 @@ class Vector(T)
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
* otherwise.
*/
override bool opEquals(Object o)
bool opEquals(typeof(this) v)
{
auto v = cast(Vector) o;
return opEquals(v);
}
return v is null ? super.opEquals(o) : vector == v.vector;
/// Ditto.
bool opEquals(ref typeof(this) v)
{
return vector == v.vector;
}
///
unittest
{
auto v1 = defaultAllocator.make!(Vector!int);
auto v2 = defaultAllocator.make!(Vector!int);
Vector!int v1, v2;
assert(v1 == v2);
v1.length = 1;
@ -452,9 +603,6 @@ class Vector(T)
v2[1] = 3;
assert(v1 == v2);
defaultAllocator.dispose(v1);
defaultAllocator.dispose(v2);
}
/**
@ -492,33 +640,7 @@ class Vector(T)
return result;
}
///
unittest
{
auto v = defaultAllocator.make!(Vector!int)(5, 15, 8);
size_t i;
foreach (j, ref e; v)
{
i = j;
}
assert(i == 2);
foreach (j, e; v)
{
assert(j != 0 || e == 5);
assert(j != 1 || e == 15);
assert(j != 2 || e == 8);
}
defaultAllocator.dispose(v);
}
/**
* $(D_KEYWORD foreach) iteration.
*
* Params:
* dg = $(D_KEYWORD foreach) body.
*/
/// Ditto.
int opApplyReverse(scope int delegate(ref T) dg)
{
int result;
@ -551,7 +673,27 @@ class Vector(T)
///
unittest
{
auto v = defaultAllocator.make!(Vector!int)(5, 15, 8);
auto v = Vector!int(5, 15, 8);
size_t i;
foreach (j, ref e; v)
{
i = j;
}
assert(i == 2);
foreach (j, e; v)
{
assert(j != 0 || e == 5);
assert(j != 1 || e == 15);
assert(j != 2 || e == 8);
}
}
///
unittest
{
auto v = Vector!int(5, 15, 8);
size_t i;
foreach_reverse (j, ref e; v)
@ -566,7 +708,6 @@ class Vector(T)
assert(j != 1 || e == 15);
assert(j != 0 || e == 5);
}
defaultAllocator.dispose(v);
}
/**
@ -577,7 +718,7 @@ class Vector(T)
@property ref inout(T) front() inout
in
{
assert(vector.length > 0);
assert(!empty);
}
body
{
@ -587,15 +728,13 @@ class Vector(T)
///
unittest
{
auto v = defaultAllocator.make!(Vector!int)(5);
auto v = Vector!int(5);
assert(v.front == 5);
v.length = 2;
v[1] = 15;
assert(v.front == 5);
defaultAllocator.dispose(v);
}
/**
@ -606,7 +745,7 @@ class Vector(T)
@property ref inout(T) back() inout
in
{
assert(vector.length > 0);
assert(!empty);
}
body
{
@ -616,36 +755,13 @@ class Vector(T)
///
unittest
{
auto v = defaultAllocator.make!(Vector!int)(5);
auto v = Vector!int(5);
assert(v.back == 5);
v.length = 2;
v[1] = 15;
assert(v.back == 15);
defaultAllocator.dispose(v);
}
/**
* Returns: A range that iterates over elements of the container, in
* forward order.
*/
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);
}
/**
@ -658,31 +774,7 @@ class Vector(T)
*
* Precondition: $(D_INLINECODE i <= j && j <= length)
*/
Range!Vector opSlice(in size_t i, in size_t j)
in
{
assert(i <= j);
assert(j <= length);
}
body
{
return typeof(return)(this, i, j);
}
/// Ditto.
Range!(const Vector) opSlice(in size_t i, in size_t j) const
in
{
assert(i <= j);
assert(j <= length);
}
body
{
return typeof(return)(this, i, j);
}
/// Ditto.
Range!(immutable Vector) opSlice(in size_t i, in size_t j) immutable
Range opSlice(in size_t i, in size_t j)
in
{
assert(i <= j);
@ -706,7 +798,7 @@ class Vector(T)
* Precondition: $(D_INLINECODE i <= j && j <= length);
* The lenghts of the ranges and slices match.
*/
Range!Vector opSliceAssign(in T value, in size_t i, in size_t j)
Range opSliceAssign(in T value, in size_t i, in size_t j)
in
{
assert(i <= j);
@ -719,7 +811,7 @@ class Vector(T)
}
/// Ditto.
Range!Vector opSliceAssign(in Range!Vector value, in size_t i, in size_t j)
Range opSliceAssign(in Range value, in size_t i, in size_t j)
in
{
assert(j - i == value.length);
@ -731,7 +823,7 @@ class Vector(T)
}
/// Ditto.
Range!Vector opSliceAssign(in T[] value, in size_t i, in size_t j)
Range opSliceAssign(in T[] value, in size_t i, in size_t j)
in
{
assert(j - i == value.length);
@ -745,37 +837,32 @@ class Vector(T)
///
unittest
{
auto v1 = defaultAllocator.make!(Vector!int)(3, 3, 3);
auto v2 = defaultAllocator.make!(Vector!int)(1, 2);
auto v1 = Vector!int(3, 3, 3);
auto v2 = Vector!int(1, 2);
v1[0..2] = 286;
v1[0 .. 2] = 286;
assert(v1[0] == 286);
assert(v1[1] == 286);
assert(v1[2] == 3);
v2[0..$] = v1[1..3];
v2[0 .. $] = v1[1 .. 3];
assert(v2[0] == 286);
assert(v2[1] == 3);
defaultAllocator.dispose(v2);
defaultAllocator.dispose(v1);
}
/// Internal representation.
protected T[] vector;
/// The allocator.
protected shared Allocator allocator;
}
}
///
unittest
{
auto v = defaultAllocator.make!(Vector!int)(5, 15, 8);
auto v = Vector!int(5, 15, 8);
assert(v.front == 5);
assert(v[1] == 15);
assert(v.back == 8);
defaultAllocator.dispose(v);
}
private unittest
{
// const Vector!int v;
}

View File

@ -10,6 +10,7 @@
*/
module tanya.math.mp;
import core.exception;
import std.algorithm.iteration;
import std.algorithm.searching;
import std.algorithm.mutation;
@ -29,7 +30,7 @@ struct Integer
pure nothrow @safe @nogc invariant
{
assert(!rep.count || rep.length || !sign, "0 should be positive.");
assert(rep.length || !sign, "0 should be positive.");
}
/**
@ -137,16 +138,14 @@ struct Integer
}
--size;
}
if (rep.count)
{
allocator.resizeArray(rep, size);
}
else
{
rep = () @trusted {
return cast(ubyte[]) allocator.allocate(size);
}();
void[] rep = this.rep;
if (!allocator.reallocate(rep, size))
{
onOutOfMemoryError();
}
return cast(ubyte[]) rep;
}();
/* Work backward through the int, masking off each byte (up to the
first 0 byte) and copy it into the internal representation in
big-endian format. */

View File

@ -15,8 +15,10 @@ module tanya.memory.allocator;
*/
interface Allocator
{
@nogc:
@property uint alignment() const shared pure nothrow @safe;
/**
* Returns: Alignment.
*/
@property uint alignment() const shared pure nothrow @safe @nogc;
/**
* Allocates $(D_PARAM size) bytes of memory.
@ -24,9 +26,9 @@ interface Allocator
* Params:
* size = Amount of memory to allocate.
*
* Returns: The pointer to the new allocated memory.
* Returns: Pointer to the new allocated memory.
*/
void[] allocate(size_t size, TypeInfo ti = null) shared nothrow @safe;
void[] allocate(size_t size) shared nothrow @safe @nogc;
/**
* Deallocates a memory block.
@ -36,7 +38,7 @@ interface Allocator
*
* Returns: Whether the deallocation was successful.
*/
bool deallocate(void[] p) shared nothrow @safe;
bool deallocate(void[] p) shared nothrow @safe @nogc;
/**
* Increases or decreases the size of a memory block.
@ -45,7 +47,7 @@ interface Allocator
* p = A pointer to the memory block.
* size = Size of the reallocated block.
*
* Returns: Whether the reallocation was successful.
* Returns: Pointer to the allocated memory.
*/
bool reallocate(ref void[] p, size_t size) shared nothrow @safe;
bool reallocate(ref void[] p, size_t size) shared nothrow @safe @nogc;
}

View File

@ -47,17 +47,8 @@ else version (Windows)
* | N | -----------> next| || N | | |
* | | | | | || | | |
* --------------------------------------------------- ------------------------
*
* TODO:
* $(UL
* $(LI Thread safety (core.atomic.cas))
* $(LI If two neighbour blocks are free, they can be merged)
* $(LI Reallocation shoud check if there is enough free space in the
* next block instead of always moving the memory)
* $(LI Make 64 KB regions mininmal region size on Linux)
* )
*/
class MmapPool : Allocator
final class MmapPool : Allocator
{
@nogc:
shared static this()
@ -80,9 +71,9 @@ class MmapPool : Allocator
* Params:
* size = Amount of memory to allocate.
*
* Returns: The pointer to the new allocated memory.
* Returns: Pointer to the new allocated memory.
*/
void[] allocate(size_t size, TypeInfo ti = null) shared nothrow @trusted
void[] allocate(size_t size) shared nothrow @trusted
{
if (!size)
{