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; module tanya.container.vector;
import std.algorithm.comparison; import std.algorithm.comparison;
import std.range.primitives;
import std.traits; import std.traits;
import tanya.memory; import tanya.memory;
@ -20,18 +21,18 @@ import tanya.memory;
* Params: * Params:
* T = Content type. * T = Content type.
*/ */
class Vector(T) template Vector(T)
{ {
/** /**
* Defines the container's primary range. * 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; private size_t start, end;
@ -39,13 +40,12 @@ class Vector(T)
invariant invariant
{ {
assert(start <= end); assert(start <= end);
assert(start == 0 || end > 0);
} }
private alias ElementType = typeof(data[0].vector[0]); protected this(ref Vector data, in size_t a, in size_t b)
protected this(V data, in size_t a, in size_t b)
{ {
this.data = data; this.data = &data;
start = a; start = a;
end = b; end = b;
} }
@ -57,7 +57,7 @@ class Vector(T)
@property bool empty() inout const @property bool empty() inout const
{ {
return start >= end; return start == end;
} }
@property size_t length() inout const @property size_t length() inout const
@ -67,7 +67,7 @@ class Vector(T)
alias opDollar = length; alias opDollar = length;
@property ref inout(ElementType) front() inout @property ref inout(T) front() inout
in in
{ {
assert(!empty); assert(!empty);
@ -77,7 +77,7 @@ class Vector(T)
return outer[start]; return outer[start];
} }
@property ref inout(ElementType) back() inout @property ref inout(T) back() inout
in in
{ {
assert(!empty); assert(!empty);
@ -107,7 +107,7 @@ class Vector(T)
--end; --end;
} }
ref inout(ElementType) opIndex(in size_t i) inout ref inout(T) opIndex(in size_t i) inout
in in
{ {
assert(start + i < end); assert(start + i < end);
@ -133,12 +133,12 @@ class Vector(T)
return typeof(return)(outer, start + i, start + j); return typeof(return)(outer, start + i, start + j);
} }
Range!(const(V)) opIndex() const Range opIndex()
{ {
return typeof(return)(outer, start, end); 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 in
{ {
assert(i <= j); assert(i <= j);
@ -149,9 +149,9 @@ class Vector(T)
return typeof(return)(outer, start + i, start + j); 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 in
{ {
assert(end <= outer.length); assert(end <= outer.length);
@ -161,7 +161,7 @@ class Vector(T)
return outer[start .. end] = value; 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 in
{ {
assert(start + j <= end); assert(start + j <= end);
@ -171,7 +171,7 @@ class Vector(T)
return outer[start + i .. start + j] = value; 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 in
{ {
assert(length == value.length); 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). * Creates an empty $(D_PSYMBOL Vector).
* *
@ -200,7 +215,7 @@ class Vector(T)
* allocator = The allocator should be used for the element * allocator = The allocator should be used for the element
* allocations. * allocations.
*/ */
this(shared Allocator allocator = defaultAllocator) this(shared Allocator allocator)
{ {
this.allocator = allocator; this.allocator = allocator;
} }
@ -227,6 +242,8 @@ class Vector(T)
} }
resizeArray!T(allocator, vector, values.length); resizeArray!T(allocator, vector, values.length);
length_ = values.length;
foreach (i, v; values) foreach (i, v; values)
{ {
vector[i] = v; vector[i] = v;
@ -238,6 +255,10 @@ class Vector(T)
*/ */
~this() ~this()
{ {
if (allocator is null)
{
allocator = defaultAllocator;
}
dispose(allocator, vector); dispose(allocator, vector);
} }
@ -246,24 +267,31 @@ class Vector(T)
*/ */
void clear() void clear()
{ {
resizeArray!T(allocator, vector, 0); length_ = 0;
} }
/// ///
unittest unittest
{ {
auto v = defaultAllocator.make!(Vector!int)(18, 20, 15); auto v = defaultAllocator.make!(Vector!int)(18, 20, 15);
v.clear(); v.clear();
assert(v.length == 0); 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. * Returns: Vector length.
*/ */
@property size_t length() inout const @property size_t length() inout const
{ {
return vector.length; return length_;
} }
/// Ditto. /// Ditto.
@ -273,29 +301,60 @@ class Vector(T)
} }
/** /**
* Expands/shrinks the vector. * Reserves space for $(D_PARAM n) elements.
*
* Params:
* length = New length.
*/ */
@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 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; v.length = 5;
assert(v.length == 5); assert(v.length == 5);
assert(v.capacity == 5);
v.length = 7; v.length = 7;
assert(v.length == 7); assert(v.length == 7);
assert(v.capacity == 7);
v.length = 0; v.length = 0;
assert(v.length == 0); assert(v.length == 0);
assert(v.capacity == 7);
} }
/** /**
@ -303,7 +362,7 @@ class Vector(T)
*/ */
@property bool empty() inout const @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 * 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); immutable toRemove = min(howMany, length);
@ -329,22 +388,109 @@ class Vector(T)
allocator.dispose(e); allocator.dispose(e);
} }
} }
length = length - toRemove; length_ -= toRemove;
return toRemove; return toRemove;
} }
/// Ditto.
alias remove = removeBack;
/// ///
unittest 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(0) == 0);
assert(v.removeBack(2) == 2); assert(v.removeBack(2) == 2);
assert(v.removeBack(3) == 1); assert(v.removeBack(3) == 1);
assert(v.removeBack(3) == 0); 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: * Params:
* value = Value. * value = Value.
* pos = Position.
* *
* Returns: Assigned value. * Returns: Assigned value.
* *
@ -368,28 +515,26 @@ class Vector(T)
} }
/// Ditto. /// Ditto.
Range!Vector opIndexAssign(in T value) Range opIndexAssign(in T value)
{ {
vector[0..$] = value; vector[0 .. $] = value;
return opIndex(); return opIndex();
} }
/// ///
unittest unittest
{ {
auto v1 = defaultAllocator.make!(Vector!int)(12, 1, 7); auto v1 = Vector!int(12, 1, 7);
v1[] = 3; v1[] = 3;
assert(v1[0] == 3); assert(v1[0] == 3);
assert(v1[1] == 3); assert(v1[1] == 3);
assert(v1[2] == 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) * Precondition: $(D_INLINECODE length > pos)
*/ */
@ -403,17 +548,21 @@ class Vector(T)
return vector[pos]; return vector[pos];
} }
/// Ditto.
Range opIndex()
{
return typeof(return)(this, 0, length);
}
/// ///
unittest 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[0] == 6);
assert(v[1] == 123); assert(v[1] == 123);
assert(v[2] == 34); assert(v[2] == 34);
assert(v[3] == 5); 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) * Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
* otherwise. * 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 unittest
{ {
auto v1 = defaultAllocator.make!(Vector!int); Vector!int v1, v2;
auto v2 = defaultAllocator.make!(Vector!int);
assert(v1 == v2); assert(v1 == v2);
v1.length = 1; v1.length = 1;
@ -452,9 +603,6 @@ class Vector(T)
v2[1] = 3; v2[1] = 3;
assert(v1 == v2); assert(v1 == v2);
defaultAllocator.dispose(v1);
defaultAllocator.dispose(v2);
} }
/** /**
@ -492,33 +640,7 @@ class Vector(T)
return result; return result;
} }
/// /// Ditto.
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.
*/
int opApplyReverse(scope int delegate(ref T) dg) int opApplyReverse(scope int delegate(ref T) dg)
{ {
int result; int result;
@ -551,7 +673,27 @@ class Vector(T)
/// ///
unittest 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; size_t i;
foreach_reverse (j, ref e; v) foreach_reverse (j, ref e; v)
@ -566,7 +708,6 @@ class Vector(T)
assert(j != 1 || e == 15); assert(j != 1 || e == 15);
assert(j != 0 || e == 5); assert(j != 0 || e == 5);
} }
defaultAllocator.dispose(v);
} }
/** /**
@ -577,7 +718,7 @@ class Vector(T)
@property ref inout(T) front() inout @property ref inout(T) front() inout
in in
{ {
assert(vector.length > 0); assert(!empty);
} }
body body
{ {
@ -587,15 +728,13 @@ class Vector(T)
/// ///
unittest unittest
{ {
auto v = defaultAllocator.make!(Vector!int)(5); auto v = Vector!int(5);
assert(v.front == 5); assert(v.front == 5);
v.length = 2; v.length = 2;
v[1] = 15; v[1] = 15;
assert(v.front == 5); assert(v.front == 5);
defaultAllocator.dispose(v);
} }
/** /**
@ -606,7 +745,7 @@ class Vector(T)
@property ref inout(T) back() inout @property ref inout(T) back() inout
in in
{ {
assert(vector.length > 0); assert(!empty);
} }
body body
{ {
@ -616,36 +755,13 @@ class Vector(T)
/// ///
unittest unittest
{ {
auto v = defaultAllocator.make!(Vector!int)(5); auto v = Vector!int(5);
assert(v.back == 5); assert(v.back == 5);
v.length = 2; v.length = 2;
v[1] = 15; v[1] = 15;
assert(v.back == 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) * Precondition: $(D_INLINECODE i <= j && j <= length)
*/ */
Range!Vector opSlice(in size_t i, in size_t j) Range 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
in in
{ {
assert(i <= j); assert(i <= j);
@ -706,7 +798,7 @@ class 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!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 in
{ {
assert(i <= j); assert(i <= j);
@ -719,7 +811,7 @@ class Vector(T)
} }
/// Ditto. /// 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 in
{ {
assert(j - i == value.length); assert(j - i == value.length);
@ -731,7 +823,7 @@ class Vector(T)
} }
/// Ditto. /// 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 in
{ {
assert(j - i == value.length); assert(j - i == value.length);
@ -745,37 +837,32 @@ class Vector(T)
/// ///
unittest unittest
{ {
auto v1 = defaultAllocator.make!(Vector!int)(3, 3, 3); auto v1 = Vector!int(3, 3, 3);
auto v2 = defaultAllocator.make!(Vector!int)(1, 2); auto v2 = Vector!int(1, 2);
v1[0..2] = 286; v1[0 .. 2] = 286;
assert(v1[0] == 286); assert(v1[0] == 286);
assert(v1[1] == 286); assert(v1[1] == 286);
assert(v1[2] == 3); assert(v1[2] == 3);
v2[0..$] = v1[1..3]; v2[0 .. $] = v1[1 .. 3];
assert(v2[0] == 286); assert(v2[0] == 286);
assert(v2[1] == 3); assert(v2[1] == 3);
defaultAllocator.dispose(v2);
defaultAllocator.dispose(v1);
} }
}
/// Internal representation.
protected T[] vector;
/// The allocator.
protected shared Allocator allocator;
} }
/// ///
unittest unittest
{ {
auto v = defaultAllocator.make!(Vector!int)(5, 15, 8); auto v = Vector!int(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);
}
defaultAllocator.dispose(v);
private unittest
{
// const Vector!int v;
} }

View File

@ -10,6 +10,7 @@
*/ */
module tanya.math.mp; module tanya.math.mp;
import core.exception;
import std.algorithm.iteration; import std.algorithm.iteration;
import std.algorithm.searching; import std.algorithm.searching;
import std.algorithm.mutation; import std.algorithm.mutation;
@ -29,7 +30,7 @@ struct Integer
pure nothrow @safe @nogc invariant 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; --size;
} }
if (rep.count)
{
allocator.resizeArray(rep, size);
}
else
{
rep = () @trusted { 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 /* Work backward through the int, masking off each byte (up to the
first 0 byte) and copy it into the internal representation in first 0 byte) and copy it into the internal representation in
big-endian format. */ big-endian format. */

View File

@ -15,8 +15,10 @@ module tanya.memory.allocator;
*/ */
interface 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. * Allocates $(D_PARAM size) bytes of memory.
@ -24,9 +26,9 @@ interface Allocator
* Params: * Params:
* size = Amount of memory to allocate. * 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. * Deallocates a memory block.
@ -36,7 +38,7 @@ interface Allocator
* *
* Returns: Whether the deallocation was successful. * 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. * Increases or decreases the size of a memory block.
@ -45,7 +47,7 @@ interface Allocator
* p = A pointer to the memory block. * p = A pointer to the memory block.
* size = Size of the reallocated 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 | | | * | 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: @nogc:
shared static this() shared static this()
@ -80,9 +71,9 @@ class MmapPool : Allocator
* Params: * Params:
* size = Amount of memory to allocate. * 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) if (!size)
{ {