This commit is contained in:
Eugen Wissner 2017-01-22 10:48:34 +01:00
parent 1450a6adfe
commit a7206cbd02
4 changed files with 258 additions and 79 deletions

View File

@ -12,11 +12,11 @@
*/
module tanya.container.entry;
package struct Entry(T)
package struct SEntry(T)
{
/// Item content.
T content;
/// Next item.
Entry* next;
SEntry* next;
}

View File

@ -72,7 +72,7 @@ struct SList(T)
*/
void insertFront(ref T x)
{
auto temp = allocator.make!(Entry!T);
auto temp = allocator.make!(SEntry!T);
temp.content = x;
temp.next = first.next;
@ -233,7 +233,7 @@ struct SList(T)
}
/// 0th element of the list.
private Entry!T first;
private SEntry!T first;
mixin DefaultAllocator;
}

View File

@ -44,7 +44,7 @@ struct Queue(T)
size_t length() const
{
size_t len;
for (const(Entry!T)* i = first; i !is null; i = i.next)
for (const(SEntry!T)* i = first; i !is null; i = i.next)
{
++len;
}
@ -72,7 +72,7 @@ struct Queue(T)
assert(q.length == 0);
}
private void enqueueEntry(ref Entry!T* entry)
private void enqueueEntry(ref SEntry!T* entry)
{
if (empty)
{
@ -85,9 +85,9 @@ struct Queue(T)
}
}
private Entry!T* allocateEntry()
private SEntry!T* allocateEntry()
{
auto temp = cast(Entry!T*) allocator.allocate(Entry!T.sizeof);
auto temp = cast(SEntry!T*) allocator.allocate(SEntry!T.sizeof);
if (temp is null)
{
onOutOfMemoryError();
@ -107,7 +107,7 @@ struct Queue(T)
{
auto temp = allocateEntry();
*temp = Entry!T.init;
*temp = SEntry!T.init;
temp.content = x;
enqueueEntry(temp);
@ -256,8 +256,8 @@ struct Queue(T)
assert(q.empty);
}
private Entry!T* first;
private Entry!T* rear;
private SEntry!T* first;
private SEntry!T* rear;
mixin DefaultAllocator;
}

View File

@ -169,10 +169,10 @@ struct Vector(T)
* to generate a list.
* allocator = Allocator.
*/
this(size_t R)(in T[R] init, shared Allocator allocator = defaultAllocator)
this(size_t R)(T[R] init, shared Allocator allocator = defaultAllocator)
{
this(allocator);
insertBack(init);
insertBack!(T[])(init[]);
}
/// Ditto.
@ -229,12 +229,7 @@ struct Vector(T)
{
// Move each element.
reserve(init.length);
const T* end = vector + init.length;
for (T* src = init.vector, dest = vector; dest != end; ++src, ++dest)
{
moveEmplace(*src, *dest);
}
moveEmplaceAll(init.vector[0 .. init.length_], vector[0 .. init.length_]);
length_ = init.length;
// Destructor of init should destroy it here.
}
@ -335,21 +330,21 @@ struct Vector(T)
/**
* Destroys this $(D_PSYMBOL Vector).
*/
~this()
~this() @trusted
{
length = 0;
shrink(0);
clear();
allocator.deallocate(vector[0 .. capacity_]);
}
/**
* Copies the vector.
*/
this(this) @trusted
this(this)
{
auto buf = vector;
immutable oldLen = length_;
auto buf = opIndex();
length_ = capacity_ = 0;
insertBack(buf[0 .. oldLen]);
vector = null;
insertBack(buf);
}
/**
@ -357,7 +352,7 @@ struct Vector(T)
*/
void clear()
{
length_ = 0;
length = 0;
}
///
@ -399,11 +394,11 @@ struct Vector(T)
*/
@property void length(in size_t len) @trusted
{
if (len == length_)
if (len == length)
{
return;
}
else if (len > length_)
else if (len > length)
{
reserve(len);
initializeAll(vector[length_ .. len]);
@ -597,70 +592,71 @@ struct Vector(T)
Range!T remove(Range!T r) @trusted
in
{
assert(r.begin >= vector && r.end <= vector + length_);
assert(r.begin >= vector);
assert(r.end <= vector + length_);
}
body
{
const T* end = vector + length_;
T* a = r.begin;
for (T* b = r.end; b != end; ++a, ++b)
{
*a = *b;
}
for (; a != end; ++a)
{
static if (hasElaborateDestructor!T)
{
destroy(*a);
}
--length_;
}
auto end = vector + length_;
moveAll(Range!T(r.end, end), Range!T(r.begin, end));
length = length - r.length;
return r;
}
///
unittest
@safe @nogc unittest
{
auto v = Vector!int([5, 18, 17, 2, 4, 6, 1]);
v.remove(v[1..3]);
assert(v == Vector!int([5, 2, 4, 6, 1]));
assert(v.remove(v[1 .. 3]).length == 2);
assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1);
assert(v.length == 5);
v.remove(v[4..4]);
assert(v == Vector!int([5, 2, 4, 6, 1]));
assert(v.remove(v[4 .. 4]).length == 0);
assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1);
assert(v.length == 5);
v.remove(v[4..5]);
assert(v == Vector!int([5, 2, 4, 6]));
assert(v.remove(v[4 .. 5]).length == 1);
assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6);
assert(v.length == 4);
v.remove(v[]);
assert(v.remove(v[]).length == 4);
assert(v.empty);
v.remove(v[]);
assert(v.remove(v[]).length == 0);
assert(v.empty);
}
private void moveBack(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T))
{
reserve(length + 1);
moveEmplace(el, *(vector + length_));
++length_;
}
/**
* Inserts the $(D_PARAM el) into the vector.
*
* Params:
* R = Parameter type (single value, range or static array).
* el = Values should be inserted.
* R = Type of the inserted value(s) (single value, range or static array).
* el = Value(s) should be inserted.
*
* Returns: The number of elements inserted.
*/
size_t insertBack(R)(auto ref R el) @trusted
if (isImplicitlyConvertible!(R, T))
{
reserve(length_ + 1);
static if (__traits(isRef, el))
{
reserve(length + 1);
emplace(vector + length_, el);
++length_;
}
else
{
moveEmplace(el, *(vector + length_));
moveBack(el);
}
++length_;
return 1;
}
@ -672,7 +668,7 @@ struct Vector(T)
{
static if (hasLength!R)
{
reserve(length_ + el.length);
reserve(length + el.length);
}
size_t retLength;
foreach (e; el)
@ -683,14 +679,9 @@ struct Vector(T)
}
/// Ditto.
size_t insertBack(size_t R)(in T[R] el)
size_t insertBack(size_t R)(T[R] el)
{
reserve(length_ + el.length);
foreach (e; el)
{
insertBack(e);
}
return el.length;
return insertBack!(T[])(el[]);
}
/// Ditto.
@ -731,13 +722,191 @@ struct 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]);
assert(v1.insertBack(v2[]) == 2);
assert(v1.insertBack([34, 234]) == 2);
assert(v1.length == 6);
assert(v1.capacity == 6);
assert(v1[4] == 34 && v1[5] == 234);
}
/**
* Inserts $(D_PARAM el) before or after $(D_PARAM r).
*
* Params:
* R = Type of the inserted value(s) (single value, range or static array).
* r = Range originally obtained from this vector.
* el = Value(s) should be inserted.
*
* Returns: The number of elements inserted.
*/
size_t insertAfter(R)(Range!T r, R el)
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
in
{
assert(r.begin >= vector);
assert(r.end <= vector + length_);
}
body
{
immutable oldLen = length;
immutable offset = r.end - vector;
immutable inserted = insertBack(el);
bringToFront(vector[offset .. oldLen], vector[oldLen .. length]);
return inserted;
}
/// Ditto.
size_t insertAfter(size_t R)(Range!T r, T[R] el)
{
return insertAfter!(T[])(r, el[]);
}
/// Ditto.
size_t insertAfter(R)(Range!T r, auto ref R el)
if (isImplicitlyConvertible!(R, T))
in
{
assert(r.begin >= vector);
assert(r.end <= vector + length_);
}
body
{
immutable oldLen = length;
immutable offset = r.end - vector;
static if (__traits(isRef, el))
{
insertBack(el);
}
else
{
moveBack(el);
}
bringToFront(vector[offset .. oldLen], vector[oldLen .. length_]);
return 1;
}
/// Ditto.
size_t insertBefore(R)(Range!T r, R el)
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
in
{
assert(r.begin >= vector);
assert(r.end <= vector + length_);
}
body
{
return insertAfter(Range!T(vector, r.begin), el);
}
/// Ditto.
size_t insertBefore(size_t R)(Range!T r, T[R] el)
{
return insertBefore!(T[])(r, el[]);
}
/// Ditto.
size_t insertBefore(R)(Range!T r, auto ref R el)
if (isImplicitlyConvertible!(R, T))
in
{
assert(r.begin >= vector);
assert(r.end <= vector + length_);
}
body
{
immutable oldLen = length;
immutable offset = r.begin - vector;
static if (__traits(isRef, el))
{
insertBack(el);
}
else
{
moveBack(el);
}
bringToFront(vector[offset .. oldLen], vector[oldLen .. length_]);
return 1;
}
///
unittest
{
Vector!int v1;
v1.insertAfter(v1[], [2, 8]);
assert(v1[0] == 2);
assert(v1[1] == 8);
assert(v1.length == 2);
v1.insertAfter(v1[], [1, 2]);
assert(v1[0] == 2);
assert(v1[1] == 8);
assert(v1[2] == 1);
assert(v1[3] == 2);
assert(v1.length == 4);
v1.insertAfter(v1[0 .. 0], [1, 2]);
assert(v1[0] == 1);
assert(v1[1] == 2);
assert(v1[2] == 2);
assert(v1[3] == 8);
assert(v1[4] == 1);
assert(v1[5] == 2);
assert(v1.length == 6);
v1.insertAfter(v1[0 .. 4], 9);
assert(v1[0] == 1);
assert(v1[1] == 2);
assert(v1[2] == 2);
assert(v1[3] == 8);
assert(v1[4] == 9);
assert(v1[5] == 1);
assert(v1[6] == 2);
assert(v1.length == 7);
}
///
unittest
{
Vector!int v1;
v1.insertBefore(v1[], [2, 8]);
assert(v1[0] == 2);
assert(v1[1] == 8);
assert(v1.length == 2);
v1.insertBefore(v1[], [1, 2]);
assert(v1[0] == 1);
assert(v1[1] == 2);
assert(v1[2] == 2);
assert(v1[3] == 8);
assert(v1.length == 4);
v1.insertBefore(v1[0 .. 1], [1, 2]);
assert(v1[0] == 1);
assert(v1[1] == 2);
assert(v1[2] == 1);
assert(v1[3] == 2);
assert(v1[4] == 2);
assert(v1[5] == 8);
assert(v1.length == 6);
v1.insertBefore(v1[2 .. $], 9);
assert(v1[0] == 1);
assert(v1[1] == 2);
assert(v1[2] == 9);
assert(v1[3] == 1);
assert(v1[4] == 2);
assert(v1[5] == 2);
assert(v1[6] == 8);
assert(v1.length == 7);
}
/**
* Assigns a value to the element with the index $(D_PARAM pos).
*
@ -841,13 +1010,13 @@ struct Vector(T)
* Returns: Random access range that iterates over elements of the vector, in
* forward order.
*/
Range!T opIndex()
Range!T opIndex() @trusted
{
return typeof(return)(vector, vector + length_);
}
/// Ditto.
Range!(const T) opIndex() const
Range!(const T) opIndex() const @trusted
{
return typeof(return)(vector, vector + length_);
}
@ -874,15 +1043,15 @@ struct Vector(T)
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
* otherwise.
*/
bool opEquals()(auto ref typeof(this) v)
bool opEquals()(auto ref typeof(this) v) @trusted
{
return equal(opIndex(), v[]);
return equal(vector[0 .. length_], v.vector[0 .. v.length_]);
}
/// Ditto.
bool opEquals()(in auto ref typeof(this) v) const
bool opEquals()(in auto ref typeof(this) v) const @trusted
{
return equal(opIndex(), v[]);
return equal(vector[0 .. length_], v.vector[0 .. length_]);
}
/// Ditto.
@ -1185,8 +1354,9 @@ struct Vector(T)
* Precondition: $(D_INLINECODE i <= j && j <= length
* && value.length == j - i)
*/
Range!T opSliceAssign(R)(R value, in size_t i, in size_t j)
if (!isInfinite!R && isInputRange!R
Range!T opSliceAssign(R)(R value, in size_t i, in size_t j) @trusted
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
in
{
@ -1196,7 +1366,7 @@ struct Vector(T)
}
body
{
copy(value, opSlice(i, j));
copy(value, vector[i .. j]);
return opSlice(i, j);
}
@ -1207,7 +1377,7 @@ struct Vector(T)
}
/// Ditto.
Range!T opSliceAssign(ref T value, in size_t i, in size_t j)
Range!T opSliceAssign(ref T value, in size_t i, in size_t j) @trusted
in
{
assert(i <= j);
@ -1215,7 +1385,7 @@ struct Vector(T)
}
body
{
fill(opSlice(i, j), value);
fill(vector[i .. j], value);
return opSlice(i, j);
}
@ -1392,3 +1562,12 @@ unittest
}
auto v = Vector!SWithDtor(); // Destructor can destroy empty vectors.
}
unittest
{
class A
{
}
A a1, a2;
auto v1 = Vector!A([a1, a2]);
}