Remove mutation methods from vector range

in favor of std.algorithm.mutation.
This commit is contained in:
Eugen Wissner 2017-01-16 09:02:00 +01:00
parent 4ea9c2b740
commit 20c8b659d1
4 changed files with 102 additions and 308 deletions

View File

@ -12,29 +12,6 @@
*/
module tanya.container.entry;
version (unittest)
{
package struct ConstEqualsStruct
{
int opEquals(typeof(this) that) const @nogc
{
return true;
}
}
package struct MutableEqualsStruct
{
int opEquals(typeof(this) that) @nogc
{
return true;
}
}
package struct NoEqualsStruct
{
}
}
package struct Entry(T)
{
/// Item content.

View File

@ -18,18 +18,30 @@ import std.conv;
import std.range.primitives;
import std.meta;
import std.traits;
public import tanya.meta.gen : IL;
import tanya.memory;
version (unittest)
{
import tanya.container.entry;
struct SWithDtor
{
~this() @nogc
{
}
}
struct ConstEqualsStruct
{
int opEquals(typeof(this) that) const @nogc
{
return true;
}
}
struct MutableEqualsStruct
{
int opEquals(typeof(this) that) @nogc
{
return true;
}
}
}
// Defines the container's primary range.
@ -43,22 +55,6 @@ private struct Range(E)
}
private this(E* begin, E* end)
in
{
assert(begin <= end);
}
body
{
this.begin = begin;
this.end = end;
}
private this(in E* begin, in E* end) const
in
{
assert(begin <= end);
}
body
{
this.begin = begin;
this.end = end;
@ -136,12 +132,12 @@ private struct Range(E)
return typeof(return)(begin, end);
}
const(Range) opIndex() const
Range!(const E) opIndex() const
{
return typeof(return)(begin, end);
}
Range opSlice(in size_t i, in size_t j)
Range opSlice(in size_t i, in size_t j) @trusted
in
{
assert(i <= j);
@ -152,7 +148,7 @@ private struct Range(E)
return typeof(return)(begin + i, begin + j);
}
const(Range) opSlice(in size_t i, in size_t j) const
Range!(const E) opSlice(in size_t i, in size_t j) const @trusted
in
{
assert(i <= j);
@ -163,125 +159,10 @@ private struct Range(E)
return typeof(return)(begin + i, begin + j);
}
bool opEquals()(Range that) const @trusted
{
if (length != that.length)
{
return false;
}
for (const(E)* i = begin; i != end; ++i)
{
if (*i != that.front)
{
return false;
}
that.popFront();
}
return true;
}
inout(E[]) get() inout
inout(E[]) get() inout @trusted
{
return begin[0 .. length];
}
static if (isMutable!E)
{
bool opEquals(Range that) @trusted
{
if (length != that.length)
{
return false;
}
for (E* i = begin; i != end; ++i)
{
if (*i != that.front)
{
return false;
}
that.popFront();
}
return true;
}
ref E opIndexAssign(ref E value, in size_t pos) @trusted
in
{
assert(length > pos);
}
body
{
return *(begin + pos) = value;
}
/// Ditto.
E opIndexAssign(E value, in size_t pos)
{
return opIndexAssign(value, pos);
}
Range opIndexAssign(ref E value) @trusted
{
E* begin = this.begin;
for (E* e = this.begin; e != end; ++e)
{
*e = value;
}
return typeof(return)(begin, end);
}
Range opIndexAssign(E value)
{
return opIndexAssign(value);
}
Range opSliceAssign(ref E value, in size_t i, in size_t j) @trusted
in
{
assert(i <= j);
assert(j < length);
}
body
{
E* begin = this.begin + i;
E* end = this.begin + j;
for (E* e = begin; e != end; ++e)
{
*e = value;
}
return typeof(return)(begin, end);
}
Range opSliceAssign(E value)
{
return opSliceAssign(value);
}
Range opSliceAssign(R)(R value, in size_t i, in size_t j) @trusted
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
in
{
assert(j - i == walkLength(value));
}
body
{
T* begin = this.begin + i;
const T* end = this.begin + j;
for (T* v = begin; v != end; ++v, value.popFront())
{
*v = value.front;
}
return typeof(return)(begin, end);
}
Range opSliceAssign(R)(R value, in size_t i, in size_t j)
if (isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
{
return opSliceAssign(value[], i, j);
}
}
}
/**
@ -303,16 +184,16 @@ struct Vector(T)
}
/**
* Creates a new $(D_PSYMBOL Vector).
* Creates a new $(D_PSYMBOL Vector) with the elements from another input
* range or a static array $(D_PARAM init).
*
* Params:
* R = Type of the static array with the initial elements.
* init = Values to initialize the array with. Use $(D_PSYMBOL IL).
* R = Type of the initial range or size of the static array.
* init = Values to initialize the array with.
* to generate a list.
* allocator = Allocator.
*/
this(R)(auto in ref R init, shared Allocator allocator = defaultAllocator)
if (isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
this(size_t R)(auto in ref T[R] init, shared Allocator allocator = defaultAllocator)
{
this(allocator);
insertBack(init[]);
@ -344,7 +225,7 @@ struct Vector(T)
* init = Source vector.
* allocator = Allocator.
*/
this(ref Vector init, shared Allocator allocator = defaultAllocator) @trusted
this(ref Vector init, shared Allocator allocator = defaultAllocator)
{
this(allocator);
insertBack(init[]);
@ -353,10 +234,10 @@ struct Vector(T)
/// Ditto.
this(Vector init, shared Allocator allocator = defaultAllocator) @trusted
{
this(allocator);
if (allocator is init.allocator)
{
// Just steal all references and the allocator.
this(init.allocator);
vector = init.vector;
length_ = init.length_;
capacity_ = init.capacity_;
@ -368,7 +249,6 @@ struct Vector(T)
else
{
// Move each element.
this(allocator);
reserve(init.length);
const T* end = vector + init.length;
@ -382,14 +262,14 @@ struct Vector(T)
}
///
@nogc @safe unittest
unittest
{
auto v1 = Vector!int(IL(1, 2, 3));
auto v1 = Vector!int([1, 2, 3]);
auto v2 = Vector!int(v1);
assert(v1.vector !is v2.vector);
assert(v1 == v2);
auto v3 = Vector!int(Vector!int(IL(1, 2, 3)));
auto v3 = Vector!int(Vector!int([1, 2, 3]));
assert(v1 == v3);
assert(v3.length == 3);
assert(v3.capacity == 3);
@ -444,7 +324,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(3, 8, 2));
auto v = Vector!int([3, 8, 2]);
assert(v.capacity == 3);
assert(v.length == 3);
@ -497,7 +377,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(18, 20, 15));
auto v = Vector!int([18, 20, 15]);
v.clear();
assert(v.length == 0);
assert(v.capacity == 3);
@ -705,7 +585,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(5, 18, 17));
auto v = Vector!int([5, 18, 17]);
assert(v.removeBack(0) == 0);
assert(v.removeBack(2) == 2);
@ -750,16 +630,16 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(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 == Vector!int(IL(5, 2, 4, 6, 1)));
assert(v == Vector!int([5, 2, 4, 6, 1]));
v.remove(v[4..4]);
assert(v == Vector!int(IL(5, 2, 4, 6, 1)));
assert(v == Vector!int([5, 2, 4, 6, 1]));
v.remove(v[4..5]);
assert(v == Vector!int(IL(5, 2, 4, 6)));
assert(v == Vector!int([5, 2, 4, 6]));
v.remove(v[]);
assert(v.empty);
@ -846,7 +726,7 @@ struct Vector(T)
assert(v1.capacity == 4);
assert(v1[0] == 5 && v1[1] == 6 && v1[2] == 4 && v1[3] == 2);
auto v2 = Vector!int(IL(34, 234));
auto v2 = Vector!int([34, 234]);
assert(v1.insertBack(v2[]) == 2);
assert(v1.length == 6);
assert(v1.capacity == 6);
@ -864,10 +744,10 @@ struct Vector(T)
*
* Precondition: $(D_INLINECODE length > pos)
*/
ref T opIndexAssign(ref T value, in size_t pos) @trusted
ref T opIndexAssign(ref T value, in size_t pos)
in
{
assert(length_ > pos);
assert(length > pos);
}
body
{
@ -881,31 +761,44 @@ struct Vector(T)
}
/// Ditto.
Range!T opIndexAssign(ref T value) @trusted
Range!T opIndexAssign()(auto ref T value)
{
const T* end = vector + length_;
for (T* v = vector; v != end; ++v)
{
*v = value;
}
return opIndex();
return opSliceAssign(value, 0, length);
}
/// Ditto.
Range!T opIndexAssign(T value)
/**
* Assigns a range. The range should have the same length as the vector.
*
* Params:
* R = Range type.
* value = Value.
*
* Returns: Assigned value.
*
* Precondition: $(D_INLINECODE length == value.length)
*/
Range!T opIndexAssign(R)(R value)
if ((!isInfinite!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
|| isStaticArray!R && is(ElementType!R == T))
{
return opIndexAssign(value);
return opSliceAssign(value, 0, length);
}
///
unittest
{
auto v1 = Vector!int(IL(12, 1, 7));
auto v1 = Vector!int([12, 1, 7]);
v1[] = 3;
assert(v1[0] == 3);
assert(v1[1] == 3);
assert(v1[2] == 3);
v1[] = [7, 1, 12];
assert(v1[0] == 7);
assert(v1[1] == 1);
assert(v1[2] == 12);
}
/**
@ -919,7 +812,7 @@ struct Vector(T)
ref inout(T) opIndex(in size_t pos) inout @trusted
in
{
assert(length_ > pos);
assert(length > pos);
}
body
{
@ -944,7 +837,7 @@ struct Vector(T)
///
unittest
{
const v1 = Vector!int(IL(6, 123, 34, 5));
const v1 = Vector!int([6, 123, 34, 5]);
assert(v1[0] == 6);
assert(v1[1] == 123);
@ -963,9 +856,9 @@ struct Vector(T)
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
* otherwise.
*/
bool opEquals()(auto ref typeof(this) v) @trusted
bool opEquals()(auto ref typeof(this) v)
{
if (length_ != v.length_)
if (length != v.length)
{
return false;
}
@ -981,9 +874,9 @@ struct Vector(T)
}
/// Ditto.
bool opEquals()(in auto ref typeof(this) v) const @trusted
bool opEquals()(in auto ref typeof(this) v) const
{
if (length_ != v.length_)
if (length != v.length)
{
return false;
}
@ -999,9 +892,9 @@ struct Vector(T)
}
/// Ditto.
bool opEquals(Range!T v) @trusted
bool opEquals(Range!T v)
{
if (length_ != v.length)
if (length != v.length)
{
return false;
}
@ -1027,10 +920,10 @@ struct Vector(T)
* Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
* otherwise.
*/
bool opEquals(R)(Range!R v) const @trusted
bool opEquals(R)(Range!R v) const
if (is(Unqual!R == T))
{
if (length_ != v.length)
if (length != v.length)
{
return false;
}
@ -1141,7 +1034,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(5, 15, 8));
auto v = Vector!int([5, 15, 8]);
size_t i;
foreach (j, ref e; v)
@ -1161,7 +1054,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(5, 15, 8));
auto v = Vector!int([5, 15, 8]);
size_t i;
foreach_reverse (j, ref e; v)
@ -1196,7 +1089,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(5));
auto v = Vector!int([5]);
assert(v.front == 5);
@ -1223,7 +1116,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(5));
auto v = Vector!int([5]);
assert(v.back == 5);
@ -1242,11 +1135,11 @@ struct Vector(T)
*
* Precondition: $(D_INLINECODE i <= j && j <= length)
*/
Range!T opSlice(in size_t i, in size_t j)
Range!T opSlice(in size_t i, in size_t j) @trusted
in
{
assert(i <= j);
assert(j <= length_);
assert(j <= length);
}
body
{
@ -1254,7 +1147,7 @@ struct Vector(T)
}
/// Ditto.
Range!(const T) opSlice(in size_t i, in size_t j) const
Range!(const T) opSlice(in size_t i, in size_t j) const @trusted
in
{
assert(i <= j);
@ -1277,7 +1170,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(1, 2, 3));
auto v = Vector!int([1, 2, 3]);
auto r = v[];
assert(r.front == 1);
@ -1295,7 +1188,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(1, 2, 3, 4));
auto v = Vector!int([1, 2, 3, 4]);
auto r = v[1 .. 4];
assert(r.length == 3);
assert(r[0] == 2);
@ -1322,7 +1215,7 @@ struct Vector(T)
* Precondition: $(D_INLINECODE i <= j && j <= length);
* The lenghts of the range and slice match.
*/
Range!T opSliceAssign(ref T value, in size_t i, in size_t j) @trusted
Range!T opSliceAssign(ref T value, in size_t i, in size_t j)
in
{
assert(i <= j);
@ -1330,7 +1223,7 @@ struct Vector(T)
}
body
{
vector[i .. j].fill(value);
fill((() @trusted => vector[i .. j])(), value);
return opSlice(i, j);
}
@ -1342,9 +1235,9 @@ struct Vector(T)
/// Ditto.
Range!T opSliceAssign(R)(R value, in size_t i, in size_t j)
if (!isInfinite!R
&& isInputRange!R
if ((!isInfinite!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
|| isStaticArray!R && is(ElementType!R == T))
in
{
assert(i <= j);
@ -1353,26 +1246,15 @@ struct Vector(T)
}
body
{
const T* end = vector + j;
for (T* v = vector + i; v != end; ++v, value.popFront())
{
*v = value.front;
}
copy(value, (() @trusted => vector[i .. j])());
return opSlice(i, j);
}
/// Ditto.
Range!T opSliceAssign(R)(R value, in size_t i, in size_t j)
if (isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
{
return opSliceAssign(value[], i, j);
}
///
unittest
@safe unittest
{
auto v1 = Vector!int(IL(3, 3, 3));
auto v2 = Vector!int(IL(1, 2));
auto v1 = Vector!int([3, 3, 3]);
auto v2 = Vector!int([1, 2]);
v1[0 .. 2] = 286;
assert(v1[0] == 286);
@ -1382,6 +1264,11 @@ struct Vector(T)
v2[0 .. $] = v1[1 .. 3];
assert(v2[0] == 286);
assert(v2[1] == 3);
v1[0 .. 2] = [5, 8];
assert(v1[0] == 5);
assert(v1[1] == 8);
assert(v1[2] == 3);
}
/**
@ -1392,7 +1279,7 @@ struct Vector(T)
*
* Returns: The array with elements of this vector.
*/
inout(T[]) get() inout
inout(T[]) get() inout @trusted
{
return vector[0 .. length];
}
@ -1400,7 +1287,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(1, 2, 4));
auto v = Vector!int([1, 2, 4]);
auto data = v.get();
assert(data[0] == 1);
@ -1419,7 +1306,7 @@ struct Vector(T)
///
unittest
{
auto v = Vector!int(IL(5, 15, 8));
auto v = Vector!int([5, 15, 8]);
assert(v.front == 5);
assert(v[1] == 15);
@ -1435,14 +1322,14 @@ unittest
{
const v1 = Vector!int();
const Vector!int v2;
const v3 = Vector!int(IL(1, 5, 8));
const v3 = Vector!int([1, 5, 8]);
static assert(is(PointerTarget!(typeof(v3.vector)) == const(int)));
}
@nogc unittest
{
// Test that const vectors return usable ranges.
auto v = const Vector!int(IL(1, 2, 4));
auto v = const Vector!int([1, 2, 4]);
auto r1 = v[];
assert(r1.back == 4);
@ -1497,18 +1384,12 @@ unittest
assert(v3 == v4[]);
assert(v3[] == v4[]);
auto v7 = Vector!MutableEqualsStruct();
auto v8 = Vector!MutableEqualsStruct();
auto v7 = Vector!MutableEqualsStruct(1, MutableEqualsStruct());
auto v8 = Vector!MutableEqualsStruct(1, MutableEqualsStruct());
assert(v7 == v8);
assert(v7[] == v8);
assert(v7 == v8[]);
assert(v7[] == v8[]);
}
@nogc unittest
{
// Implicitly convertible works.
auto v = Vector!int(IL(cast(short) 1, cast(short) 2));
assert(equal(v7[], v8[]));
}
@nogc unittest

View File

@ -1,49 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Templates that generate values.
*
* Copyright: Eugene Wissner 2016.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
*/
module tanya.meta.gen;
import std.traits;
/**
* 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.
*/
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);
static assert(IL(1, 5, 8).sizeof == 3 * int.sizeof);
}

View File

@ -1,15 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Metaprogramming.
*
* Copyright: Eugene Wissner 2016.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
*/
module tanya.meta;
public import tanya.meta.gen;