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; module tanya.container.entry;
package struct Entry(T) package struct SEntry(T)
{ {
/// Item content. /// Item content.
T content; T content;
/// Next item. /// Next item.
Entry* next; SEntry* next;
} }

View File

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

View File

@ -44,7 +44,7 @@ struct Queue(T)
size_t length() const size_t length() const
{ {
size_t len; 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; ++len;
} }
@ -72,7 +72,7 @@ struct Queue(T)
assert(q.length == 0); assert(q.length == 0);
} }
private void enqueueEntry(ref Entry!T* entry) private void enqueueEntry(ref SEntry!T* entry)
{ {
if (empty) 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) if (temp is null)
{ {
onOutOfMemoryError(); onOutOfMemoryError();
@ -107,7 +107,7 @@ struct Queue(T)
{ {
auto temp = allocateEntry(); auto temp = allocateEntry();
*temp = Entry!T.init; *temp = SEntry!T.init;
temp.content = x; temp.content = x;
enqueueEntry(temp); enqueueEntry(temp);
@ -256,8 +256,8 @@ struct Queue(T)
assert(q.empty); assert(q.empty);
} }
private Entry!T* first; private SEntry!T* first;
private Entry!T* rear; private SEntry!T* rear;
mixin DefaultAllocator; mixin DefaultAllocator;
} }

View File

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