algorithm: import searching publically
This commit is contained in:
parent
20c7e47ff7
commit
0fe7308a22
@ -9,7 +9,6 @@ language: d
|
|||||||
d:
|
d:
|
||||||
- dmd-2.085.0
|
- dmd-2.085.0
|
||||||
- dmd-2.084.1
|
- dmd-2.084.1
|
||||||
- dmd-2.083.1
|
|
||||||
- dmd-2.082.1
|
- dmd-2.082.1
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
@ -15,12 +15,6 @@ environment:
|
|||||||
- DC: dmd
|
- DC: dmd
|
||||||
DVersion: 2.084.1
|
DVersion: 2.084.1
|
||||||
arch: x86
|
arch: x86
|
||||||
- DC: dmd
|
|
||||||
DVersion: 2.083.1
|
|
||||||
arch: x64
|
|
||||||
- DC: dmd
|
|
||||||
DVersion: 2.083.1
|
|
||||||
arch: x86
|
|
||||||
- DC: dmd
|
- DC: dmd
|
||||||
DVersion: 2.082.1
|
DVersion: 2.082.1
|
||||||
arch: x64
|
arch: x64
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/**
|
/**
|
||||||
* Algorithms for comparing values.
|
* Algorithms for comparing values.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2018.
|
* Copyright: Eugene Wissner 2018-2019.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
@ -99,22 +99,6 @@ if (Args.length >= 2
|
|||||||
return minMax!((ref a, ref b) => a < b)(args);
|
return minMax!((ref a, ref b) => a < b)(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(!is(typeof(min(1, 1UL))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
assert(min(5, 3) == 3);
|
|
||||||
assert(min(4, 4) == 4);
|
|
||||||
assert(min(5.2, 3.0) == 3.0);
|
|
||||||
|
|
||||||
assert(min(5.2, double.nan) == 5.2);
|
|
||||||
assert(min(double.nan, 3.0) == 3.0);
|
|
||||||
assert(isNaN(min(double.nan, double.nan)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
Range min(Range)(Range range)
|
Range min(Range)(Range range)
|
||||||
if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
||||||
@ -150,11 +134,6 @@ if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
|||||||
assert(minElement.length == 3);
|
assert(minElement.length == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
assert(min(cast(ubyte[]) []).empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the largest element in the argument list or a range.
|
* Finds the largest element in the argument list or a range.
|
||||||
*
|
*
|
||||||
@ -192,22 +171,6 @@ if (Args.length >= 2
|
|||||||
return minMax!((ref a, ref b) => a > b)(args);
|
return minMax!((ref a, ref b) => a > b)(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(!is(typeof(max(1, 1UL))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
assert(max(5, 3) == 5);
|
|
||||||
assert(max(4, 4) == 4);
|
|
||||||
assert(max(5.2, 3.0) == 5.2);
|
|
||||||
|
|
||||||
assert(max(5.2, double.nan) == 5.2);
|
|
||||||
assert(max(double.nan, 3.0) == 3.0);
|
|
||||||
assert(isNaN(max(double.nan, double.nan)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
Range max(Range)(Range range)
|
Range max(Range)(Range range)
|
||||||
if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
||||||
@ -243,35 +206,6 @@ if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
|||||||
assert(maxElement.length == 3);
|
assert(maxElement.length == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
assert(max(cast(ubyte[]) []).empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// min/max compare const and mutable structs.
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static struct S
|
|
||||||
{
|
|
||||||
int s;
|
|
||||||
|
|
||||||
int opCmp(typeof(this) that) const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return this.s - that.s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const s1 = S(1);
|
|
||||||
assert(min(s1, S(2)).s == 1);
|
|
||||||
assert(max(s1, S(2)).s == 2);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto s2 = S(2), s3 = S(3);
|
|
||||||
assert(min(s2, s3).s == 2);
|
|
||||||
assert(max(s2, s3).s == 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares element-wise two ranges for equality.
|
* Compares element-wise two ranges for equality.
|
||||||
*
|
*
|
||||||
@ -438,26 +372,3 @@ private int compareImpl(alias pred, R1, R2)(ref R1 r1, ref R2 r2)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static struct OpCmp(int value)
|
|
||||||
{
|
|
||||||
int opCmp(OpCmp) @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
OpCmp!(-1)[1] range;
|
|
||||||
assert(compare(range[], range[]) < 0);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
OpCmp!1[1] range;
|
|
||||||
assert(compare(range[], range[]) > 0);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
OpCmp!0[1] range;
|
|
||||||
assert(compare(range[], range[]) == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* All algorithms in this module are lazy, they request the next element of the
|
* All algorithms in this module are lazy, they request the next element of the
|
||||||
* original range on demand.
|
* original range on demand.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2018.
|
* Copyright: Eugene Wissner 2018-2019.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
@ -26,7 +26,6 @@ import tanya.meta.trait;
|
|||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range;
|
import tanya.range;
|
||||||
import tanya.typecons;
|
import tanya.typecons;
|
||||||
version (unittest) import tanya.test.stub;
|
|
||||||
|
|
||||||
private struct Take(R, bool exactly)
|
private struct Take(R, bool exactly)
|
||||||
{
|
{
|
||||||
@ -49,21 +48,13 @@ private struct Take(R, bool exactly)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property auto ref front()
|
@property auto ref front()
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.source.front;
|
return this.source.front;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront()
|
void popFront()
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.source.popFront();
|
this.source.popFront();
|
||||||
--this.length_;
|
--this.length_;
|
||||||
@ -92,21 +83,13 @@ private struct Take(R, bool exactly)
|
|||||||
static if (hasAssignableElements!R)
|
static if (hasAssignableElements!R)
|
||||||
{
|
{
|
||||||
@property void front(ref ElementType!R value)
|
@property void front(ref ElementType!R value)
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.source.front = value;
|
this.source.front = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property void front(ElementType!R value)
|
@property void front(ElementType!R value)
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.source.front = move(value);
|
this.source.front = move(value);
|
||||||
}
|
}
|
||||||
@ -122,31 +105,19 @@ private struct Take(R, bool exactly)
|
|||||||
static if (isRandomAccessRange!R)
|
static if (isRandomAccessRange!R)
|
||||||
{
|
{
|
||||||
@property auto ref back()
|
@property auto ref back()
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.source[this.length - 1];
|
return this.source[this.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
void popBack()
|
void popBack()
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
--this.length_;
|
--this.length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ref opIndex(size_t i)
|
auto ref opIndex(size_t i)
|
||||||
in
|
in (i < length)
|
||||||
{
|
|
||||||
assert(i < length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.source[i];
|
return this.source[i];
|
||||||
}
|
}
|
||||||
@ -154,41 +125,25 @@ private struct Take(R, bool exactly)
|
|||||||
static if (hasAssignableElements!R)
|
static if (hasAssignableElements!R)
|
||||||
{
|
{
|
||||||
@property void back(ref ElementType!R value)
|
@property void back(ref ElementType!R value)
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.source[length - 1] = value;
|
this.source[length - 1] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property void back(ElementType!R value)
|
@property void back(ElementType!R value)
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.source[length - 1] = move(value);
|
this.source[length - 1] = move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void opIndexAssign(ref ElementType!R value, size_t i)
|
void opIndexAssign(ref ElementType!R value, size_t i)
|
||||||
in
|
in (i < length)
|
||||||
{
|
|
||||||
assert(i < length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.source[i] = value;
|
this.source[i] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void opIndexAssign(ElementType!R value, size_t i)
|
void opIndexAssign(ElementType!R value, size_t i)
|
||||||
in
|
in (i < length)
|
||||||
{
|
|
||||||
assert(i < length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.source[i] = move(value);
|
this.source[i] = move(value);
|
||||||
}
|
}
|
||||||
@ -198,12 +153,8 @@ private struct Take(R, bool exactly)
|
|||||||
static if (!exactly && hasSlicing!R)
|
static if (!exactly && hasSlicing!R)
|
||||||
{
|
{
|
||||||
auto opSlice(size_t i, size_t j)
|
auto opSlice(size_t i, size_t j)
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(this)(this.source[i .. j], length);
|
return typeof(this)(this.source[i .. j], length);
|
||||||
}
|
}
|
||||||
@ -322,18 +273,6 @@ if (isInputRange!R)
|
|||||||
assert(t.empty);
|
assert(t.empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// length is unknown when taking from a range without length
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static struct R
|
|
||||||
{
|
|
||||||
mixin InputRangeStub;
|
|
||||||
}
|
|
||||||
auto actual = take(R(), 100);
|
|
||||||
|
|
||||||
static assert(!hasLength!(typeof(actual)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes exactly $(D_PARAM n) elements from $(D_PARAM range).
|
* Takes exactly $(D_PARAM n) elements from $(D_PARAM range).
|
||||||
*
|
*
|
||||||
@ -428,32 +367,6 @@ if (isInputRange!R)
|
|||||||
assert(t.empty);
|
assert(t.empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes minimum length if the range length > n
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto range = take(cast(int[]) null, 8);
|
|
||||||
assert(range.length == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
const int[9] range = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
||||||
{
|
|
||||||
auto slice = take(range[], 8)[1 .. 3];
|
|
||||||
|
|
||||||
assert(slice.length == 2);
|
|
||||||
assert(slice.front == 2);
|
|
||||||
assert(slice.back == 3);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto slice = takeExactly(range[], 8)[1 .. 3];
|
|
||||||
|
|
||||||
assert(slice.length == 2);
|
|
||||||
assert(slice.front == 2);
|
|
||||||
assert(slice.back == 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reverse-access-order range returned by `retro`.
|
// Reverse-access-order range returned by `retro`.
|
||||||
private struct Retro(Range)
|
private struct Retro(Range)
|
||||||
{
|
{
|
||||||
@ -522,12 +435,8 @@ private struct Retro(Range)
|
|||||||
alias opDollar = length;
|
alias opDollar = length;
|
||||||
|
|
||||||
auto opSlice(size_t i, size_t j)
|
auto opSlice(size_t i, size_t j)
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(this)(this.source[$-j .. $-i]);
|
return typeof(this)(this.source[$-j .. $-i]);
|
||||||
}
|
}
|
||||||
@ -615,41 +524,6 @@ if (isBidirectionalRange!Range)
|
|||||||
assert(equal(actual, expected[]));
|
assert(equal(actual, expected[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elements are accessible in reverse order
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
const int[3] given = [1, 2, 3];
|
|
||||||
auto actual = retro(given[]);
|
|
||||||
|
|
||||||
assert(actual.back == given[].front);
|
|
||||||
assert(actual[0] == 3);
|
|
||||||
assert(actual[2] == 1);
|
|
||||||
|
|
||||||
actual.popBack();
|
|
||||||
assert(actual.back == 2);
|
|
||||||
assert(actual[1] == 2);
|
|
||||||
|
|
||||||
// Check slicing.
|
|
||||||
auto slice = retro(given[])[1 .. $];
|
|
||||||
assert(slice.length == 2 && slice.front == 2 && slice.back == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Elements can be assigned
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
int[4] given = [1, 2, 3, 4];
|
|
||||||
auto actual = retro(given[]);
|
|
||||||
|
|
||||||
actual.front = 5;
|
|
||||||
assert(given[].back == 5);
|
|
||||||
|
|
||||||
actual.back = 8;
|
|
||||||
assert(given[].front == 8);
|
|
||||||
|
|
||||||
actual[2] = 10;
|
|
||||||
assert(given[1] == 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct SingletonByValue(E)
|
private struct SingletonByValue(E)
|
||||||
{
|
{
|
||||||
private Option!E element;
|
private Option!E element;
|
||||||
@ -807,49 +681,3 @@ auto singleton(E)(return ref E element)
|
|||||||
singleChar.popFront();
|
singleChar.popFront();
|
||||||
assert(singleChar.empty);
|
assert(singleChar.empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Singleton range is bidirectional and random-access
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(isBidirectionalRange!(typeof(singleton('a'))));
|
|
||||||
static assert(isRandomAccessRange!(typeof(singleton('a'))));
|
|
||||||
|
|
||||||
assert({ char a; return isBidirectionalRange!(typeof(singleton(a))); });
|
|
||||||
assert({ char a; return isRandomAccessRange!(typeof(singleton(a))); });
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
char a = 'a';
|
|
||||||
auto single = singleton(a);
|
|
||||||
|
|
||||||
assert(single.front == 'a');
|
|
||||||
assert(single.back == 'a');
|
|
||||||
assert(single[0] == 'a');
|
|
||||||
assert(single.length == 1);
|
|
||||||
assert(!single.empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// popFront makes SingletonByRef empty
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
char a = 'a';
|
|
||||||
auto single = singleton(a);
|
|
||||||
|
|
||||||
single.popFront();
|
|
||||||
assert(single.empty);
|
|
||||||
assert(single.length == 0);
|
|
||||||
assert(single.empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// popBack makes SingletonByRef empty
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
char a = 'b';
|
|
||||||
auto single = singleton(a);
|
|
||||||
|
|
||||||
single.popBack();
|
|
||||||
assert(single.empty);
|
|
||||||
assert(single.length == 0);
|
|
||||||
assert(single.empty);
|
|
||||||
}
|
|
||||||
|
@ -19,7 +19,6 @@ static import tanya.memory.op;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range;
|
import tanya.range;
|
||||||
version (unittest) import tanya.test.stub;
|
|
||||||
|
|
||||||
deprecated("Use tanya.memory.lifetime.swap instead")
|
deprecated("Use tanya.memory.lifetime.swap instead")
|
||||||
alias swap = tanya.memory.lifetime.swap;
|
alias swap = tanya.memory.lifetime.swap;
|
||||||
@ -96,49 +95,6 @@ do
|
|||||||
assert(equal(source[], target[]));
|
assert(equal(source[], target[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns advanced target
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
int[5] input = [1, 2, 3, 4, 5];
|
|
||||||
assert(copy(input[3 .. 5], input[]).front == 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copies overlapping arrays
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
import tanya.algorithm.comparison : equal;
|
|
||||||
|
|
||||||
int[6] actual = [1, 2, 3, 4, 5, 6];
|
|
||||||
const int[6] expected = [1, 2, 1, 2, 3, 4];
|
|
||||||
|
|
||||||
copy(actual[0 .. 4], actual[2 .. 6]);
|
|
||||||
assert(equal(actual[], expected[]));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(is(typeof(copy((ubyte[]).init, (ushort[]).init))));
|
|
||||||
static assert(!is(typeof(copy((ushort[]).init, (ubyte[]).init))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static struct OutPutRange
|
|
||||||
{
|
|
||||||
int value;
|
|
||||||
|
|
||||||
void opCall(int value) @nogc nothrow pure @safe
|
|
||||||
in (this.value == 0)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int[1] source = [5];
|
|
||||||
OutPutRange target;
|
|
||||||
|
|
||||||
assert(copy(source[], target).value == 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills $(D_PARAM range) with $(D_PARAM value).
|
* Fills $(D_PARAM range) with $(D_PARAM value).
|
||||||
*
|
*
|
||||||
@ -176,42 +132,6 @@ if (isInputRange!Range && isAssignable!(ElementType!Range, Value))
|
|||||||
assert(equal(actual[], expected[]));
|
assert(equal(actual[], expected[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// [] is called where possible
|
|
||||||
@nogc nothrow pure @system unittest
|
|
||||||
{
|
|
||||||
static struct Slice
|
|
||||||
{
|
|
||||||
bool* slicingCalled;
|
|
||||||
|
|
||||||
int front() @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void front(int) @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void popFront() @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void opIndexAssign(int) @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
*this.slicingCalled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool slicingCalled;
|
|
||||||
auto range = Slice(&slicingCalled);
|
|
||||||
fill(range, 0);
|
|
||||||
assert(slicingCalled);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills $(D_PARAM range) with $(D_PARAM value) assuming the elements of the
|
* Fills $(D_PARAM range) with $(D_PARAM value) assuming the elements of the
|
||||||
* $(D_PARAM range) aren't initialized.
|
* $(D_PARAM range) aren't initialized.
|
||||||
@ -294,12 +214,6 @@ if (isInputRange!Range && hasLvalueElements!Range)
|
|||||||
assert(equal(actual[], expected[]));
|
assert(equal(actual[], expected[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
NonCopyable[] nonCopyable;
|
|
||||||
initializeAll(nonCopyable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys all elements in the $(D_PARAM range).
|
* Destroys all elements in the $(D_PARAM range).
|
||||||
*
|
*
|
||||||
@ -390,38 +304,3 @@ if (isForwardRange!Range && hasSwappableElements!Range)
|
|||||||
rotate(actual[0 .. 2], actual[4 .. 6]);
|
rotate(actual[0 .. 2], actual[4 .. 6]);
|
||||||
assert(equal(actual[], expected[]));
|
assert(equal(actual[], expected[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
import tanya.algorithm.comparison : equal;
|
|
||||||
|
|
||||||
const int[5] expected = [1, 2, 3, 4, 5];
|
|
||||||
int[5] actual = [4, 5, 1, 2, 3];
|
|
||||||
|
|
||||||
rotate(actual[0 .. 2], actual[2 .. $]);
|
|
||||||
assert(equal(actual[], expected[]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Doesn't cause an infinite loop if back is shorter than the front
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
import tanya.algorithm.comparison : equal;
|
|
||||||
|
|
||||||
const int[5] expected = [1, 2, 3, 4, 5];
|
|
||||||
int[5] actual = [3, 4, 5, 1, 2];
|
|
||||||
|
|
||||||
rotate(actual[0 .. 3], actual[3 .. $]);
|
|
||||||
assert(equal(actual[], expected[]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Doesn't call .front on an empty front
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
import tanya.algorithm.comparison : equal;
|
|
||||||
|
|
||||||
const int[2] expected = [2, 8];
|
|
||||||
int[2] actual = expected;
|
|
||||||
|
|
||||||
rotate(actual[0 .. 0], actual[]);
|
|
||||||
assert(equal(actual[], expected[]));
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/**
|
/**
|
||||||
* Collection of generic algorithms.
|
* Collection of generic algorithms.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2017-2018.
|
* Copyright: Eugene Wissner 2017-2019.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
@ -17,3 +17,4 @@ module tanya.algorithm;
|
|||||||
public import tanya.algorithm.comparison;
|
public import tanya.algorithm.comparison;
|
||||||
public import tanya.algorithm.iteration;
|
public import tanya.algorithm.iteration;
|
||||||
public import tanya.algorithm.mutation;
|
public import tanya.algorithm.mutation;
|
||||||
|
public import tanya.algorithm.searching;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/**
|
/**
|
||||||
* Searching algorithms.
|
* Searching algorithms.
|
||||||
*
|
*
|
||||||
* Copyright: Eugene Wissner 2018.
|
* Copyright: Eugene Wissner 2018-2019.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
@ -51,28 +51,3 @@ if (isInputRange!R)
|
|||||||
int[3] array;
|
int[3] array;
|
||||||
assert(count(array) == 3);
|
assert(count(array) == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static struct Range
|
|
||||||
{
|
|
||||||
private int counter = 3;
|
|
||||||
|
|
||||||
int front() const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return this.counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
void popFront() @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
--this.counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return this.counter == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Range range;
|
|
||||||
assert(count(range) == 3);
|
|
||||||
}
|
|
||||||
|
@ -116,30 +116,6 @@ else version (DragonFlyBSD)
|
|||||||
{
|
{
|
||||||
version = Kqueue;
|
version = Kqueue;
|
||||||
}
|
}
|
||||||
version (unittest)
|
|
||||||
{
|
|
||||||
final class TestLoop : Loop
|
|
||||||
{
|
|
||||||
override protected bool reify(SocketWatcher watcher,
|
|
||||||
EventMask oldEvents,
|
|
||||||
EventMask events) @nogc
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
override protected void poll() @nogc
|
|
||||||
{
|
|
||||||
assert(!this.done);
|
|
||||||
unloop();
|
|
||||||
}
|
|
||||||
|
|
||||||
override protected @property uint maxEvents()
|
|
||||||
const pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
return 64U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Events.
|
* Events.
|
||||||
@ -160,7 +136,7 @@ alias EventMask = BitFlags!Event;
|
|||||||
*/
|
*/
|
||||||
abstract class Loop
|
abstract class Loop
|
||||||
{
|
{
|
||||||
private bool done = true;
|
protected bool done = true;
|
||||||
|
|
||||||
/// Pending watchers.
|
/// Pending watchers.
|
||||||
protected DList!Watcher pendings;
|
protected DList!Watcher pendings;
|
||||||
@ -175,14 +151,6 @@ abstract class Loop
|
|||||||
return 128U;
|
return 128U;
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc @system unittest
|
|
||||||
{
|
|
||||||
auto loop = defaultAllocator.make!TestLoop;
|
|
||||||
assert(loop.maxEvents == 64);
|
|
||||||
|
|
||||||
defaultAllocator.dispose(loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the loop.
|
* Initializes the loop.
|
||||||
*/
|
*/
|
||||||
@ -228,31 +196,6 @@ abstract class Loop
|
|||||||
this.done = true;
|
this.done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc @system unittest
|
|
||||||
{
|
|
||||||
auto loop = defaultAllocator.make!TestLoop;
|
|
||||||
assert(loop.done);
|
|
||||||
|
|
||||||
loop.run();
|
|
||||||
assert(loop.done);
|
|
||||||
|
|
||||||
defaultAllocator.dispose(loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc @system unittest
|
|
||||||
{
|
|
||||||
auto loop = defaultAllocator.make!TestLoop;
|
|
||||||
auto watcher = defaultAllocator.make!DummyWatcher;
|
|
||||||
loop.pendings.insertBack(watcher);
|
|
||||||
|
|
||||||
assert(!watcher.invoked);
|
|
||||||
loop.run();
|
|
||||||
assert(watcher.invoked);
|
|
||||||
|
|
||||||
defaultAllocator.dispose(loop);
|
|
||||||
defaultAllocator.dispose(watcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start watching.
|
* Start watching.
|
||||||
*
|
*
|
||||||
@ -329,17 +272,6 @@ abstract class Loop
|
|||||||
blockTime_ = blockTime;
|
blockTime_ = blockTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc @system unittest
|
|
||||||
{
|
|
||||||
auto loop = defaultAllocator.make!TestLoop;
|
|
||||||
assert(loop.blockTime == 1.dur!"minutes");
|
|
||||||
|
|
||||||
loop.blockTime = 2.dur!"minutes";
|
|
||||||
assert(loop.blockTime == 2.dur!"minutes");
|
|
||||||
|
|
||||||
defaultAllocator.dispose(loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the actual polling.
|
* Does the actual polling.
|
||||||
*/
|
*/
|
||||||
@ -418,16 +350,3 @@ do
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Loop defaultLoop_;
|
private Loop defaultLoop_;
|
||||||
|
|
||||||
@nogc @system unittest
|
|
||||||
{
|
|
||||||
auto oldLoop = defaultLoop_;
|
|
||||||
auto loop = defaultAllocator.make!TestLoop;
|
|
||||||
|
|
||||||
defaultLoop = loop;
|
|
||||||
assert(defaultLoop_ is loop);
|
|
||||||
assert(defaultLoop is loop);
|
|
||||||
|
|
||||||
defaultLoop_ = oldLoop;
|
|
||||||
defaultAllocator.dispose(loop);
|
|
||||||
}
|
|
||||||
|
@ -37,19 +37,6 @@ abstract class Watcher
|
|||||||
void invoke() @nogc;
|
void invoke() @nogc;
|
||||||
}
|
}
|
||||||
|
|
||||||
version (unittest)
|
|
||||||
{
|
|
||||||
final class DummyWatcher : Watcher
|
|
||||||
{
|
|
||||||
bool invoked;
|
|
||||||
|
|
||||||
override void invoke() @nogc
|
|
||||||
{
|
|
||||||
this.invoked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Socket watcher.
|
* Socket watcher.
|
||||||
*/
|
*/
|
||||||
|
@ -21,7 +21,6 @@ import tanya.memory;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range;
|
import tanya.range;
|
||||||
version (unittest) import tanya.test.stub;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Random-access range for the $(D_PSYMBOL Array).
|
* Random-access range for the $(D_PSYMBOL Array).
|
||||||
@ -35,22 +34,15 @@ struct Range(A)
|
|||||||
private E* begin, end;
|
private E* begin, end;
|
||||||
private A* container;
|
private A* container;
|
||||||
|
|
||||||
invariant
|
invariant (this.begin <= this.end);
|
||||||
{
|
invariant (this.container !is null);
|
||||||
assert(this.begin <= this.end);
|
invariant (this.begin >= this.container.data);
|
||||||
assert(this.container !is null);
|
invariant (this.end <= this.container.data + this.container.length);
|
||||||
assert(this.begin >= this.container.data);
|
|
||||||
assert(this.end <= this.container.data + this.container.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private this(ref A container, E* begin, E* end) @trusted
|
private this(ref A container, E* begin, E* end) @trusted
|
||||||
in
|
in (begin <= end)
|
||||||
{
|
in (begin >= container.data)
|
||||||
assert(begin <= end);
|
in (end <= container.data + container.length)
|
||||||
assert(begin >= container.data);
|
|
||||||
assert(end <= container.data + container.length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.container = &container;
|
this.container = &container;
|
||||||
this.begin = begin;
|
this.begin = begin;
|
||||||
@ -77,51 +69,31 @@ struct Range(A)
|
|||||||
alias opDollar = length;
|
alias opDollar = length;
|
||||||
|
|
||||||
@property ref inout(E) front() inout
|
@property ref inout(E) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *this.begin;
|
return *this.begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(E) back() inout @trusted
|
@property ref inout(E) back() inout @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *(this.end - 1);
|
return *(this.end - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront() @trusted
|
void popFront() @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
++this.begin;
|
++this.begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popBack() @trusted
|
void popBack() @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
--this.end;
|
--this.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref inout(E) opIndex(size_t i) inout @trusted
|
ref inout(E) opIndex(size_t i) inout @trusted
|
||||||
in
|
in (i < length)
|
||||||
{
|
|
||||||
assert(i < length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *(this.begin + i);
|
return *(this.begin + i);
|
||||||
}
|
}
|
||||||
@ -137,23 +109,15 @@ struct Range(A)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Range opSlice(size_t i, size_t j) @trusted
|
Range opSlice(size_t i, size_t j) @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
A.ConstRange opSlice(size_t i, size_t j) const @trusted
|
A.ConstRange opSlice(size_t i, size_t j) const @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
||||||
}
|
}
|
||||||
@ -182,11 +146,8 @@ struct Array(T)
|
|||||||
private T* data;
|
private T* data;
|
||||||
private size_t capacity_;
|
private size_t capacity_;
|
||||||
|
|
||||||
invariant
|
invariant (this.length_ <= this.capacity_);
|
||||||
{
|
invariant (this.capacity_ == 0 || this.data !is null);
|
||||||
assert(this.length_ <= this.capacity_);
|
|
||||||
assert(this.capacity_ == 0 || this.data !is null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new $(D_PSYMBOL Array) with the elements from a static array.
|
* Creates a new $(D_PSYMBOL Array) with the elements from a static array.
|
||||||
@ -312,11 +273,7 @@ struct Array(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(shared Allocator allocator)
|
this(shared Allocator allocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
allocator_ = allocator;
|
allocator_ = allocator;
|
||||||
}
|
}
|
||||||
@ -567,11 +524,7 @@ struct Array(T)
|
|||||||
* Precondition: $(D_INLINECODE !empty).
|
* Precondition: $(D_INLINECODE !empty).
|
||||||
*/
|
*/
|
||||||
void removeBack()
|
void removeBack()
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
length = length - 1;
|
length = length - 1;
|
||||||
}
|
}
|
||||||
@ -589,11 +542,7 @@ struct Array(T)
|
|||||||
* Returns: The number of elements removed
|
* Returns: The number of elements removed
|
||||||
*/
|
*/
|
||||||
size_t removeBack(size_t howMany)
|
size_t removeBack(size_t howMany)
|
||||||
out (removed)
|
out (removed; removed <= howMany)
|
||||||
{
|
|
||||||
assert(removed <= howMany);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
const toRemove = min(howMany, length);
|
const toRemove = min(howMany, length);
|
||||||
|
|
||||||
@ -614,11 +563,7 @@ struct Array(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inout(T)[] slice(size_t length) inout @trusted
|
private inout(T)[] slice(size_t length) inout @trusted
|
||||||
in
|
in (length <= capacity)
|
||||||
{
|
|
||||||
assert(length <= capacity);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.data[0 .. length];
|
return this.data[0 .. length];
|
||||||
}
|
}
|
||||||
@ -640,13 +585,9 @@ struct Array(T)
|
|||||||
* Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this).
|
* Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
Range remove(Range r)
|
Range remove(Range r)
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= end)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= end);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto target = r.begin;
|
auto target = r.begin;
|
||||||
auto source = r.end;
|
auto source = r.end;
|
||||||
@ -801,13 +742,9 @@ struct Array(T)
|
|||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= this.data + length)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= this.data + length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
const oldLength = length;
|
const oldLength = length;
|
||||||
const after = r.end - this.data;
|
const after = r.end - this.data;
|
||||||
@ -819,13 +756,9 @@ struct Array(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertAfter(size_t R)(Range r, T[R] el)
|
size_t insertAfter(size_t R)(Range r, T[R] el)
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= this.data + length)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= this.data + length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return insertAfter!(T[])(r, el[]);
|
return insertAfter!(T[])(r, el[]);
|
||||||
}
|
}
|
||||||
@ -833,13 +766,9 @@ struct Array(T)
|
|||||||
/// ditto
|
/// ditto
|
||||||
size_t insertAfter(R)(Range r, auto ref R el)
|
size_t insertAfter(R)(Range r, auto ref R el)
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= this.data + length)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= this.data + length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
const oldLen = length;
|
const oldLen = length;
|
||||||
const offset = r.end - this.data;
|
const offset = r.end - this.data;
|
||||||
@ -862,26 +791,18 @@ struct Array(T)
|
|||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= this.data + length)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= this.data + length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return insertAfter(Range(this, this.data, r.begin), el);
|
return insertAfter(Range(this, this.data, r.begin), el);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBefore(size_t R)(Range r, T[R] el)
|
size_t insertBefore(size_t R)(Range r, T[R] el)
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= this.data + length)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= this.data + length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return insertBefore!(T[])(r, el[]);
|
return insertBefore!(T[])(r, el[]);
|
||||||
}
|
}
|
||||||
@ -889,13 +810,9 @@ struct Array(T)
|
|||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBefore(R)(Range r, auto ref R el)
|
size_t insertBefore(R)(Range r, auto ref R el)
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= this.data + length)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= this.data + length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
const oldLen = length;
|
const oldLen = length;
|
||||||
const offset = r.begin - this.data;
|
const offset = r.begin - this.data;
|
||||||
@ -1063,11 +980,7 @@ struct Array(T)
|
|||||||
* Precondition: $(D_INLINECODE length > pos).
|
* Precondition: $(D_INLINECODE length > pos).
|
||||||
*/
|
*/
|
||||||
ref inout(T) opIndex(size_t pos) inout @trusted
|
ref inout(T) opIndex(size_t pos) inout @trusted
|
||||||
in
|
in (length > pos)
|
||||||
{
|
|
||||||
assert(length > pos);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *(this.data + pos);
|
return *(this.data + pos);
|
||||||
}
|
}
|
||||||
@ -1168,11 +1081,7 @@ struct Array(T)
|
|||||||
* Precondition: $(D_INLINECODE !empty).
|
* Precondition: $(D_INLINECODE !empty).
|
||||||
*/
|
*/
|
||||||
@property ref inout(T) front() inout
|
@property ref inout(T) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *this.data;
|
return *this.data;
|
||||||
}
|
}
|
||||||
@ -1195,11 +1104,7 @@ struct Array(T)
|
|||||||
* Precondition: $(D_INLINECODE !empty).
|
* Precondition: $(D_INLINECODE !empty).
|
||||||
*/
|
*/
|
||||||
@property ref inout(T) back() inout @trusted
|
@property ref inout(T) back() inout @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *(this.data + length - 1);
|
return *(this.data + length - 1);
|
||||||
}
|
}
|
||||||
@ -1227,24 +1132,16 @@ struct Array(T)
|
|||||||
* Precondition: $(D_INLINECODE i <= j && j <= length).
|
* Precondition: $(D_INLINECODE i <= j && j <= length).
|
||||||
*/
|
*/
|
||||||
Range opSlice(size_t i, size_t j) @trusted
|
Range opSlice(size_t i, size_t j) @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(return)(this, this.data + i, this.data + j);
|
return typeof(return)(this, this.data + i, this.data + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
ConstRange opSlice(size_t i, size_t j) const @trusted
|
ConstRange opSlice(size_t i, size_t j) const @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(return)(this, this.data + i, this.data + j);
|
return typeof(return)(this, this.data + i, this.data + j);
|
||||||
}
|
}
|
||||||
@ -1301,12 +1198,8 @@ struct Array(T)
|
|||||||
*/
|
*/
|
||||||
Range opSliceAssign(size_t R)(T[R] value, size_t i, size_t j)
|
Range opSliceAssign(size_t R)(T[R] value, size_t i, size_t j)
|
||||||
@trusted
|
@trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
copy(value[], this.data[i .. j]);
|
copy(value[], this.data[i .. j]);
|
||||||
return opSlice(i, j);
|
return opSlice(i, j);
|
||||||
@ -1315,12 +1208,8 @@ struct Array(T)
|
|||||||
/// ditto
|
/// ditto
|
||||||
Range opSliceAssign(R : T)(auto ref R value, size_t i, size_t j)
|
Range opSliceAssign(R : T)(auto ref R value, size_t i, size_t j)
|
||||||
@trusted
|
@trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
fill(this.data[i .. j], value);
|
fill(this.data[i .. j], value);
|
||||||
return opSlice(i, j);
|
return opSlice(i, j);
|
||||||
@ -1328,13 +1217,9 @@ struct Array(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
Range opSliceAssign()(Range value, size_t i, size_t j) @trusted
|
Range opSliceAssign()(Range value, size_t i, size_t j) @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
in (j - i == value.length)
|
||||||
assert(j <= length);
|
|
||||||
assert(j - i == value.length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
copy(value, this.data[i .. j]);
|
copy(value, this.data[i .. j]);
|
||||||
return opSlice(i, j);
|
return opSlice(i, j);
|
||||||
@ -1491,198 +1376,3 @@ struct Array(T)
|
|||||||
assert(r.front == 7);
|
assert(r.front == 7);
|
||||||
assert(r.front == v.front);
|
assert(r.front == v.front);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
const v1 = Array!int();
|
|
||||||
const Array!int v2;
|
|
||||||
const v3 = Array!int([1, 5, 8]);
|
|
||||||
static assert(is(PointerTarget!(typeof(v3.data)) == const(int)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
// Test that const arrays return usable ranges.
|
|
||||||
auto v = const Array!int([1, 2, 4]);
|
|
||||||
auto r1 = v[];
|
|
||||||
|
|
||||||
assert(r1.back == 4);
|
|
||||||
r1.popBack();
|
|
||||||
assert(r1.back == 2);
|
|
||||||
r1.popBack();
|
|
||||||
assert(r1.back == 1);
|
|
||||||
r1.popBack();
|
|
||||||
assert(r1.length == 0);
|
|
||||||
|
|
||||||
static assert(!is(typeof(r1[0] = 5)));
|
|
||||||
static assert(!is(typeof(v[0] = 5)));
|
|
||||||
|
|
||||||
const r2 = r1[];
|
|
||||||
static assert(is(typeof(r2[])));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
Array!int v1;
|
|
||||||
const Array!int v2;
|
|
||||||
|
|
||||||
auto r1 = v1[];
|
|
||||||
auto r2 = v1[];
|
|
||||||
|
|
||||||
assert(r1.length == 0);
|
|
||||||
assert(r2.empty);
|
|
||||||
assert(r1 == r2);
|
|
||||||
|
|
||||||
v1.insertBack([1, 2, 4]);
|
|
||||||
assert(v1[] == v1);
|
|
||||||
assert(v2[] == v2);
|
|
||||||
assert(v2[] != v1);
|
|
||||||
assert(v1[] != v2);
|
|
||||||
assert(v1[].equal(v1[]));
|
|
||||||
assert(v2[].equal(v2[]));
|
|
||||||
assert(!v1[].equal(v2[]));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
struct MutableEqualsStruct
|
|
||||||
{
|
|
||||||
bool opEquals(typeof(this) that) @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
struct ConstEqualsStruct
|
|
||||||
{
|
|
||||||
bool opEquals(const typeof(this) that) const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto v1 = Array!ConstEqualsStruct();
|
|
||||||
auto v2 = Array!ConstEqualsStruct();
|
|
||||||
assert(v1 == v2);
|
|
||||||
assert(v1[] == v2);
|
|
||||||
assert(v1 == v2[]);
|
|
||||||
assert(v1[].equal(v2[]));
|
|
||||||
|
|
||||||
auto v3 = const Array!ConstEqualsStruct();
|
|
||||||
auto v4 = const Array!ConstEqualsStruct();
|
|
||||||
assert(v3 == v4);
|
|
||||||
assert(v3[] == v4);
|
|
||||||
assert(v3 == v4[]);
|
|
||||||
assert(v3[].equal(v4[]));
|
|
||||||
|
|
||||||
auto v7 = Array!MutableEqualsStruct(1, MutableEqualsStruct());
|
|
||||||
auto v8 = Array!MutableEqualsStruct(1, MutableEqualsStruct());
|
|
||||||
assert(v7 == v8);
|
|
||||||
assert(v7[] == v8);
|
|
||||||
assert(v7 == v8[]);
|
|
||||||
assert(v7[].equal(v8[]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destructor can destroy empty arrays
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto v = Array!WithDtor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
class A
|
|
||||||
{
|
|
||||||
}
|
|
||||||
A a1, a2;
|
|
||||||
auto v1 = Array!A([a1, a2]);
|
|
||||||
|
|
||||||
static assert(is(Array!(A*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto v = Array!int([5, 15, 8]);
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
foreach (e; v)
|
|
||||||
{
|
|
||||||
assert(i != 0 || e == 5);
|
|
||||||
assert(i != 1 || e == 15);
|
|
||||||
assert(i != 2 || e == 8);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
assert(i == 3);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
size_t i = 3;
|
|
||||||
|
|
||||||
foreach_reverse (e; v)
|
|
||||||
{
|
|
||||||
--i;
|
|
||||||
assert(i != 2 || e == 8);
|
|
||||||
assert(i != 1 || e == 15);
|
|
||||||
assert(i != 0 || e == 5);
|
|
||||||
}
|
|
||||||
assert(i == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// const constructor tests
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto v1 = const Array!int([1, 2, 3]);
|
|
||||||
auto v2 = Array!int(v1);
|
|
||||||
assert(v1.data !is v2.data);
|
|
||||||
assert(v1 == v2);
|
|
||||||
|
|
||||||
auto v3 = const Array!int(Array!int([1, 2, 3]));
|
|
||||||
assert(v1 == v3);
|
|
||||||
assert(v3.length == 3);
|
|
||||||
assert(v3.capacity == 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto v1 = Array!int(defaultAllocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
Array!int v;
|
|
||||||
auto r = v[];
|
|
||||||
assert(r.length == 0);
|
|
||||||
assert(r.empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto v1 = const Array!int([5, 15, 8]);
|
|
||||||
Array!int v2;
|
|
||||||
v2 = v1[0 .. 2];
|
|
||||||
assert(equal(v1[0 .. 2], v2[]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move assignment
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
Array!int v1;
|
|
||||||
v1 = Array!int([5, 15, 8]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Postblit is safe
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto array = Array!int(3);
|
|
||||||
void func(Array!int arg)
|
|
||||||
{
|
|
||||||
assert(arg.capacity == 3);
|
|
||||||
}
|
|
||||||
func(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can have non-copyable elements
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(is(Array!NonCopyable));
|
|
||||||
static assert(is(typeof({ Array!NonCopyable.init[0] = NonCopyable(); })));
|
|
||||||
}
|
|
||||||
|
@ -22,11 +22,7 @@ version (unittest)
|
|||||||
private int fillBuffer(ubyte[] buffer,
|
private int fillBuffer(ubyte[] buffer,
|
||||||
int start = 0,
|
int start = 0,
|
||||||
int end = 10) @nogc pure nothrow
|
int end = 10) @nogc pure nothrow
|
||||||
in
|
in (start < end)
|
||||||
{
|
|
||||||
assert(start < end);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto numberRead = end - start;
|
auto numberRead = end - start;
|
||||||
for (ubyte i; i < numberRead; ++i)
|
for (ubyte i; i < numberRead; ++i)
|
||||||
@ -71,12 +67,9 @@ if (isScalarType!T)
|
|||||||
/// Size by which the buffer will grow.
|
/// Size by which the buffer will grow.
|
||||||
private size_t blockSize = 8192;
|
private size_t blockSize = 8192;
|
||||||
|
|
||||||
invariant
|
invariant (this.length_ <= this.buffer_.length);
|
||||||
{
|
invariant (this.blockSize > 0);
|
||||||
assert(this.length_ <= this.buffer_.length);
|
invariant (this.minAvailable > 0);
|
||||||
assert(this.blockSize > 0);
|
|
||||||
assert(this.minAvailable > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new read buffer.
|
* Creates a new read buffer.
|
||||||
@ -101,11 +94,7 @@ if (isScalarType!T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(shared Allocator allocator)
|
this(shared Allocator allocator)
|
||||||
in
|
in (allocator_ is null)
|
||||||
{
|
|
||||||
assert(allocator_ is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
allocator_ = allocator;
|
allocator_ = allocator;
|
||||||
}
|
}
|
||||||
@ -188,7 +177,7 @@ if (isScalarType!T)
|
|||||||
* Returns: $(D_KEYWORD this).
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
ref ReadBuffer opOpAssign(string op)(size_t length)
|
ref ReadBuffer opOpAssign(string op)(size_t length)
|
||||||
if (op == "+")
|
if (op == "+")
|
||||||
{
|
{
|
||||||
this.length_ += length;
|
this.length_ += length;
|
||||||
ring = start;
|
ring = start;
|
||||||
@ -293,11 +282,6 @@ if (isScalarType!T)
|
|||||||
mixin DefaultAllocator;
|
mixin DefaultAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(is(ReadBuffer!int));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Circular, self-expanding buffer with overflow support. Can be used with
|
* Circular, self-expanding buffer with overflow support. Can be used with
|
||||||
* functions returning the number of the transferred bytes.
|
* functions returning the number of the transferred bytes.
|
||||||
@ -328,12 +312,9 @@ if (isScalarType!T)
|
|||||||
/// The position of the free area in the buffer.
|
/// The position of the free area in the buffer.
|
||||||
private size_t position;
|
private size_t position;
|
||||||
|
|
||||||
invariant
|
invariant (this.blockSize > 0);
|
||||||
{
|
// Position can refer to an element outside the buffer if the buffer is full.
|
||||||
assert(this.blockSize > 0);
|
invariant (this.position <= this.buffer_.length);
|
||||||
// Position can refer to an element outside the buffer if the buffer is full.
|
|
||||||
assert(this.position <= this.buffer_.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
@ -344,12 +325,8 @@ if (isScalarType!T)
|
|||||||
* Precondition: $(D_INLINECODE size > 0 && allocator !is null)
|
* Precondition: $(D_INLINECODE size > 0 && allocator !is null)
|
||||||
*/
|
*/
|
||||||
this(size_t size, shared Allocator allocator = defaultAllocator) @trusted
|
this(size_t size, shared Allocator allocator = defaultAllocator) @trusted
|
||||||
in
|
in (size > 0)
|
||||||
{
|
in (allocator !is null)
|
||||||
assert(size > 0);
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.blockSize = size;
|
this.blockSize = size;
|
||||||
ring = size - 1;
|
ring = size - 1;
|
||||||
@ -435,7 +412,7 @@ if (isScalarType!T)
|
|||||||
* buffer = Buffer chunk got with $(D_PSYMBOL opIndex).
|
* buffer = Buffer chunk got with $(D_PSYMBOL opIndex).
|
||||||
*/
|
*/
|
||||||
ref WriteBuffer opOpAssign(string op)(const T[] buffer)
|
ref WriteBuffer opOpAssign(string op)(const T[] buffer)
|
||||||
if (op == "~")
|
if (op == "~")
|
||||||
{
|
{
|
||||||
size_t end, start;
|
size_t end, start;
|
||||||
|
|
||||||
@ -509,12 +486,8 @@ if (isScalarType!T)
|
|||||||
* Returns: $(D_KEYWORD this).
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
ref WriteBuffer opOpAssign(string op)(size_t length)
|
ref WriteBuffer opOpAssign(string op)(size_t length)
|
||||||
if (op == "+")
|
if (op == "+")
|
||||||
in
|
in (length <= this.length)
|
||||||
{
|
|
||||||
assert(length <= this.length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto afterRing = ring + 1;
|
auto afterRing = ring + 1;
|
||||||
auto oldStart = start;
|
auto oldStart = start;
|
||||||
@ -649,11 +622,6 @@ if (isScalarType!T)
|
|||||||
mixin DefaultAllocator;
|
mixin DefaultAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(is(typeof(WriteBuffer!int(5))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @system unittest
|
@nogc nothrow pure @system unittest
|
||||||
{
|
{
|
||||||
auto b = WriteBuffer!ubyte(4);
|
auto b = WriteBuffer!ubyte(4);
|
||||||
|
@ -20,7 +20,6 @@ import tanya.memory.lifetime;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.typecons;
|
import tanya.typecons;
|
||||||
version (unittest) import tanya.test.stub;
|
|
||||||
|
|
||||||
package struct SEntry(T)
|
package struct SEntry(T)
|
||||||
{
|
{
|
||||||
@ -129,22 +128,14 @@ package struct HashArray(alias hasher, K, V = void)
|
|||||||
size_t length;
|
size_t length;
|
||||||
|
|
||||||
this(shared Allocator allocator)
|
this(shared Allocator allocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.array = Buckets(allocator);
|
this.array = Buckets(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
this(T)(ref T data, shared Allocator allocator)
|
this(T)(ref T data, shared Allocator allocator)
|
||||||
if (is(Unqual!T == HashArray))
|
if (is(Unqual!T == HashArray))
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.array = Buckets(data.array, allocator);
|
this.array = Buckets(data.array, allocator);
|
||||||
this.lengthIndex = data.lengthIndex;
|
this.lengthIndex = data.lengthIndex;
|
||||||
@ -153,11 +144,7 @@ package struct HashArray(alias hasher, K, V = void)
|
|||||||
|
|
||||||
// Move constructor
|
// Move constructor
|
||||||
void move(ref HashArray data, shared Allocator allocator)
|
void move(ref HashArray data, shared Allocator allocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.array = Buckets(.move(data.array), allocator);
|
this.array = Buckets(.move(data.array), allocator);
|
||||||
this.lengthIndex = data.lengthIndex;
|
this.lengthIndex = data.lengthIndex;
|
||||||
@ -238,11 +225,7 @@ package struct HashArray(alias hasher, K, V = void)
|
|||||||
|
|
||||||
// Takes an index in the primes array.
|
// Takes an index in the primes array.
|
||||||
void rehashToSize(const size_t n)
|
void rehashToSize(const size_t n)
|
||||||
in
|
in (n < primes.length)
|
||||||
{
|
|
||||||
assert(n < primes.length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto storage = typeof(this.array)(primes[n], this.array.allocator);
|
auto storage = typeof(this.array)(primes[n], this.array.allocator);
|
||||||
DataLoop: foreach (ref e1; this.array[])
|
DataLoop: foreach (ref e1; this.array[])
|
||||||
@ -327,13 +310,3 @@ package struct HashArray(alias hasher, K, V = void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can be constructed with non-copyable key/values
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(is(Bucket!NonCopyable));
|
|
||||||
static assert(is(Bucket!(NonCopyable, NonCopyable)));
|
|
||||||
|
|
||||||
static assert(is(HashArray!((ref NonCopyable) => 0U, NonCopyable)));
|
|
||||||
static assert(is(HashArray!((ref NonCopyable) => 0U, NonCopyable, NonCopyable)));
|
|
||||||
}
|
|
||||||
|
@ -22,7 +22,6 @@ import tanya.memory;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
version (unittest) import tanya.test.stub;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bidirectional range whose element type is a tuple of a key and the
|
* Bidirectional range whose element type is a tuple of a key and the
|
||||||
@ -70,16 +69,9 @@ struct Range(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void popFront()
|
void popFront()
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.front.status == BucketStatus.used)
|
||||||
assert(!empty);
|
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(this.dataRange.front.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
{
|
|
||||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -89,16 +81,9 @@ struct Range(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void popBack()
|
void popBack()
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(!empty);
|
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
{
|
|
||||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -108,23 +93,15 @@ struct Range(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(KV) front() inout
|
@property ref inout(KV) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.front.status == BucketStatus.used)
|
||||||
assert(!empty);
|
|
||||||
assert(this.dataRange.front.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.dataRange.front.kv;
|
return this.dataRange.front.kv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(KV) back() inout
|
@property ref inout(KV) back() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(!empty);
|
|
||||||
assert(this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.dataRange.back.kv;
|
return this.dataRange.back.kv;
|
||||||
}
|
}
|
||||||
@ -185,16 +162,9 @@ struct ByKey(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property void popFront()
|
@property void popFront()
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.front.status == BucketStatus.used)
|
||||||
assert(!empty);
|
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(this.dataRange.front.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
{
|
|
||||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -204,16 +174,9 @@ struct ByKey(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property void popBack()
|
@property void popBack()
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(!empty);
|
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
{
|
|
||||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -223,23 +186,15 @@ struct ByKey(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(Key) front() inout
|
@property ref inout(Key) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.front.status == BucketStatus.used)
|
||||||
assert(!empty);
|
|
||||||
assert(this.dataRange.front.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.dataRange.front.key;
|
return this.dataRange.front.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(Key) back() inout
|
@property ref inout(Key) back() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(!empty);
|
|
||||||
assert(this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.dataRange.back.key;
|
return this.dataRange.back.key;
|
||||||
}
|
}
|
||||||
@ -300,16 +255,9 @@ struct ByValue(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property void popFront()
|
@property void popFront()
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.front.status == BucketStatus.used)
|
||||||
assert(!empty);
|
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(this.dataRange.front.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
{
|
|
||||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -319,16 +267,9 @@ struct ByValue(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property void popBack()
|
@property void popBack()
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(!empty);
|
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
{
|
|
||||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -338,23 +279,15 @@ struct ByValue(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(Value) front() inout
|
@property ref inout(Value) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.front.status == BucketStatus.used)
|
||||||
assert(!empty);
|
|
||||||
assert(this.dataRange.front.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.dataRange.front.kv.value;
|
return this.dataRange.front.kv.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(Value) back() inout
|
@property ref inout(Value) back() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(!empty);
|
|
||||||
assert(this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.dataRange.back.kv.value;
|
return this.dataRange.back.kv.value;
|
||||||
}
|
}
|
||||||
@ -412,10 +345,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
/// ditto
|
/// ditto
|
||||||
alias ConstByValue = .ByValue!(const HashArray);
|
alias ConstByValue = .ByValue!(const HashArray);
|
||||||
|
|
||||||
invariant
|
invariant (this.data.lengthIndex < primes.length);
|
||||||
{
|
|
||||||
assert(this.data.lengthIndex < primes.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@ -427,11 +357,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
* Precondition: $(D_INLINECODE allocator !is null).
|
* Precondition: $(D_INLINECODE allocator !is null).
|
||||||
*/
|
*/
|
||||||
this(size_t n, shared Allocator allocator = defaultAllocator)
|
this(size_t n, shared Allocator allocator = defaultAllocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
this.data.rehash(n);
|
this.data.rehash(n);
|
||||||
@ -446,11 +372,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(shared Allocator allocator)
|
this(shared Allocator allocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.data = HashArray(allocator);
|
this.data = HashArray(allocator);
|
||||||
}
|
}
|
||||||
@ -470,11 +392,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
*/
|
*/
|
||||||
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
|
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
|
||||||
if (is(Unqual!S == HashTable))
|
if (is(Unqual!S == HashTable))
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.data = HashArray(init.data, allocator);
|
this.data = HashArray(init.data, allocator);
|
||||||
}
|
}
|
||||||
@ -482,11 +400,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
/// ditto
|
/// ditto
|
||||||
this(S)(S init, shared Allocator allocator = defaultAllocator)
|
this(S)(S init, shared Allocator allocator = defaultAllocator)
|
||||||
if (is(S == HashTable))
|
if (is(S == HashTable))
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.data.move(init.data, allocator);
|
this.data.move(init.data, allocator);
|
||||||
}
|
}
|
||||||
@ -503,11 +417,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
*/
|
*/
|
||||||
this(R)(R range, shared Allocator allocator = defaultAllocator)
|
this(R)(R range, shared Allocator allocator = defaultAllocator)
|
||||||
if (isForwardRange!R && is(ElementType!R == KeyValue))
|
if (isForwardRange!R && is(ElementType!R == KeyValue))
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
insert(range);
|
insert(range);
|
||||||
@ -537,11 +447,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
*/
|
*/
|
||||||
this(size_t n)(KeyValue[n] array,
|
this(size_t n)(KeyValue[n] array,
|
||||||
shared Allocator allocator = defaultAllocator)
|
shared Allocator allocator = defaultAllocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
insert(array[]);
|
insert(array[]);
|
||||||
}
|
}
|
||||||
@ -589,11 +495,7 @@ if (isHashFunction!(hasher, Key))
|
|||||||
* Postcondition: $(D_INLINECODE allocator !is null)
|
* Postcondition: $(D_INLINECODE allocator !is null)
|
||||||
*/
|
*/
|
||||||
@property shared(Allocator) allocator() const
|
@property shared(Allocator) allocator() const
|
||||||
out (allocator)
|
out (allocator; allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.data.array.allocator;
|
return this.data.array.allocator;
|
||||||
}
|
}
|
||||||
@ -1085,129 +987,3 @@ if (isHashFunction!(hasher, Key))
|
|||||||
dinos.clear();
|
dinos.clear();
|
||||||
assert(dinos.empty);
|
assert(dinos.empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
import tanya.range.primitive : isForwardRange;
|
|
||||||
static assert(is(HashTable!(string, int) a));
|
|
||||||
static assert(is(const HashTable!(string, int)));
|
|
||||||
static assert(isForwardRange!(HashTable!(string, int).Range));
|
|
||||||
|
|
||||||
static assert(is(HashTable!(int, int, (ref const int) => size_t.init)));
|
|
||||||
static assert(is(HashTable!(int, int, (int) => size_t.init)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructs by reference
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto hashTable1 = HashTable!(string, int)(7);
|
|
||||||
auto hashTable2 = HashTable!(string, int)(hashTable1);
|
|
||||||
assert(hashTable1.length == hashTable2.length);
|
|
||||||
assert(hashTable1.capacity == hashTable2.capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructs by value
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto hashTable = HashTable!(string, int)(HashTable!(string, int)(7));
|
|
||||||
assert(hashTable.capacity == 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assigns by reference
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto hashTable1 = HashTable!(string, int)(7);
|
|
||||||
HashTable!(string, int) hashTable2;
|
|
||||||
hashTable1 = hashTable2;
|
|
||||||
assert(hashTable1.length == hashTable2.length);
|
|
||||||
assert(hashTable1.capacity == hashTable2.capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assigns by value
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
HashTable!(string, int) hashTable;
|
|
||||||
hashTable = HashTable!(string, int)(7);
|
|
||||||
assert(hashTable.capacity == 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Postblit copies
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto hashTable = HashTable!(string, int)(7);
|
|
||||||
void testFunc(HashTable!(string, int) hashTable)
|
|
||||||
{
|
|
||||||
assert(hashTable.capacity == 7);
|
|
||||||
}
|
|
||||||
testFunc(hashTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issue 53: https://github.com/caraus-ecms/tanya/issues/53
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
{
|
|
||||||
HashTable!(uint, uint) hashTable;
|
|
||||||
foreach (uint i; 0 .. 14)
|
|
||||||
{
|
|
||||||
hashTable[i + 1] = i;
|
|
||||||
}
|
|
||||||
assert(hashTable.length == 14);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
HashTable!(int, int) hashtable;
|
|
||||||
|
|
||||||
hashtable[1194250162] = 3;
|
|
||||||
hashtable[-1131293824] = 6;
|
|
||||||
hashtable[838100082] = 9;
|
|
||||||
|
|
||||||
hashtable.rehash(11);
|
|
||||||
|
|
||||||
assert(hashtable[-1131293824] == 6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static struct String
|
|
||||||
{
|
|
||||||
bool opEquals(string) const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool opEquals(ref const string) const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool opEquals(String) const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool opEquals(ref const String) const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t toHash() const @nogc nothrow pure @safe
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static assert(is(typeof("asdf" in HashTable!(String, int)())));
|
|
||||||
static assert(is(typeof(HashTable!(String, int)()["asdf"])));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can have non-copyable keys and elements
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
@NonCopyable @Hashable
|
|
||||||
static struct S
|
|
||||||
{
|
|
||||||
mixin StructStub;
|
|
||||||
}
|
|
||||||
static assert(is(HashTable!(S, int)));
|
|
||||||
static assert(is(HashTable!(int, S)));
|
|
||||||
static assert(is(HashTable!(S, S)));
|
|
||||||
}
|
|
||||||
|
@ -22,7 +22,6 @@ import tanya.meta.trait;
|
|||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range.array;
|
import tanya.range.array;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
version (unittest) import tanya.test.stub;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forward range for the $(D_PSYMBOL SList).
|
* Forward range for the $(D_PSYMBOL SList).
|
||||||
@ -37,10 +36,7 @@ struct SRange(L)
|
|||||||
|
|
||||||
private EntryPointer* head;
|
private EntryPointer* head;
|
||||||
|
|
||||||
invariant
|
invariant (this.head !is null);
|
||||||
{
|
|
||||||
assert(this.head !is null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private this(ref EntryPointer head) @trusted
|
private this(ref EntryPointer head) @trusted
|
||||||
{
|
{
|
||||||
@ -60,21 +56,13 @@ struct SRange(L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(E) front() inout
|
@property ref inout(E) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return (*this.head).content;
|
return (*this.head).content;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront() @trusted
|
void popFront() @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.head = &(*this.head).next;
|
this.head = &(*this.head).next;
|
||||||
}
|
}
|
||||||
@ -206,11 +194,7 @@ struct SList(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(shared Allocator allocator)
|
this(shared Allocator allocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.allocator_ = allocator;
|
this.allocator_ = allocator;
|
||||||
}
|
}
|
||||||
@ -332,11 +316,7 @@ struct SList(T)
|
|||||||
* Precondition: $(D_INLINECODE !empty).
|
* Precondition: $(D_INLINECODE !empty).
|
||||||
*/
|
*/
|
||||||
@property ref inout(T) front() inout
|
@property ref inout(T) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.head.content;
|
return this.head.content;
|
||||||
}
|
}
|
||||||
@ -477,11 +457,7 @@ struct SList(T)
|
|||||||
*/
|
*/
|
||||||
size_t insertBefore(R)(Range r, R el)
|
size_t insertBefore(R)(Range r, R el)
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return moveEntry(*r.head, el);
|
return moveEntry(*r.head, el);
|
||||||
}
|
}
|
||||||
@ -500,11 +476,7 @@ struct SList(T)
|
|||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
size_t inserted;
|
size_t inserted;
|
||||||
foreach (e; el)
|
foreach (e; el)
|
||||||
@ -529,11 +501,7 @@ struct SList(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBefore()(Range r, ref T el) @trusted
|
size_t insertBefore()(Range r, ref T el) @trusted
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
*r.head = allocator.make!Entry(el, *r.head);
|
*r.head = allocator.make!Entry(el, *r.head);
|
||||||
return 1;
|
return 1;
|
||||||
@ -629,11 +597,7 @@ struct SList(T)
|
|||||||
* Precondition: $(D_INLINECODE !empty)
|
* Precondition: $(D_INLINECODE !empty)
|
||||||
*/
|
*/
|
||||||
void removeFront()
|
void removeFront()
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto n = this.head.next;
|
auto n = this.head.next;
|
||||||
|
|
||||||
@ -668,11 +632,7 @@ struct SList(T)
|
|||||||
* Returns: The number of elements removed.
|
* Returns: The number of elements removed.
|
||||||
*/
|
*/
|
||||||
size_t removeFront(size_t howMany)
|
size_t removeFront(size_t howMany)
|
||||||
out (removed)
|
out (removed; removed <= howMany)
|
||||||
{
|
|
||||||
assert(removed <= howMany);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (; i < howMany && !empty; ++i)
|
for (; i < howMany && !empty; ++i)
|
||||||
@ -704,11 +664,7 @@ struct SList(T)
|
|||||||
* Precondition: $(D_PARAM r) is extracted from this list.
|
* Precondition: $(D_PARAM r) is extracted from this list.
|
||||||
*/
|
*/
|
||||||
Range remove(Range r)
|
Range remove(Range r)
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto outOfScopeList = typeof(this)(allocator);
|
auto outOfScopeList = typeof(this)(allocator);
|
||||||
outOfScopeList.head = *r.head;
|
outOfScopeList.head = *r.head;
|
||||||
@ -742,12 +698,8 @@ struct SList(T)
|
|||||||
* $(D_PARAM range) is extracted from this list.
|
* $(D_PARAM range) is extracted from this list.
|
||||||
*/
|
*/
|
||||||
Range popFirstOf(Range range)
|
Range popFirstOf(Range range)
|
||||||
in
|
in (!range.empty)
|
||||||
{
|
in (checkRangeBelonging(range))
|
||||||
assert(!range.empty);
|
|
||||||
assert(checkRangeBelonging(range));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto next = (*range.head).next;
|
auto next = (*range.head).next;
|
||||||
|
|
||||||
@ -923,46 +875,6 @@ struct SList(T)
|
|||||||
assert(i == 3);
|
assert(i == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
interface Stuff
|
|
||||||
{
|
|
||||||
}
|
|
||||||
static assert(is(SList!Stuff));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto l = SList!int(0, 0);
|
|
||||||
assert(l.empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// foreach called using opIndex().
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
SList!int l;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
l.insertFront(5);
|
|
||||||
l.insertFront(4);
|
|
||||||
l.insertFront(9);
|
|
||||||
foreach (e; l)
|
|
||||||
{
|
|
||||||
assert(i != 0 || e == 9);
|
|
||||||
assert(i != 1 || e == 4);
|
|
||||||
assert(i != 2 || e == 5);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto l1 = SList!int();
|
|
||||||
auto l2 = SList!int([9, 4]);
|
|
||||||
l1 = l2[];
|
|
||||||
assert(l1 == l2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bidirectional range for the $(D_PSYMBOL DList).
|
* Bidirectional range for the $(D_PSYMBOL DList).
|
||||||
*
|
*
|
||||||
@ -977,11 +889,8 @@ struct DRange(L)
|
|||||||
private EntryPointer* head;
|
private EntryPointer* head;
|
||||||
private EntryPointer* tail;
|
private EntryPointer* tail;
|
||||||
|
|
||||||
invariant
|
invariant (this.head !is null);
|
||||||
{
|
invariant (this.tail !is null);
|
||||||
assert(this.head !is null);
|
|
||||||
assert(this.tail !is null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private this(ref EntryPointer head, ref EntryPointer tail) @trusted
|
private this(ref EntryPointer head, ref EntryPointer tail) @trusted
|
||||||
{
|
{
|
||||||
@ -1002,41 +911,25 @@ struct DRange(L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(E) front() inout
|
@property ref inout(E) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return (*this.head).content;
|
return (*this.head).content;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(E) back() inout
|
@property ref inout(E) back() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return (*this.tail).content;
|
return (*this.tail).content;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront() @trusted
|
void popFront() @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.head = &(*this.head).next;
|
this.head = &(*this.head).next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popBack() @trusted
|
void popBack() @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.tail = &(*this.tail).prev;
|
this.tail = &(*this.tail).prev;
|
||||||
}
|
}
|
||||||
@ -1082,13 +975,10 @@ struct DList(T)
|
|||||||
// 0th and the last elements of the list.
|
// 0th and the last elements of the list.
|
||||||
private Entry* head, tail;
|
private Entry* head, tail;
|
||||||
|
|
||||||
invariant
|
invariant ((this.tail is null && this.head is null)
|
||||||
{
|
|
||||||
assert((this.tail is null && this.head is null)
|
|
||||||
|| (this.tail !is null && this.head !is null));
|
|| (this.tail !is null && this.head !is null));
|
||||||
assert(this.tail is null || this.tail.next is null);
|
invariant (this.tail is null || this.tail.next is null);
|
||||||
assert(this.head is null || this.head.prev is null);
|
invariant (this.head is null || this.head.prev is null);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new $(D_PSYMBOL DList) with the elements from a static array.
|
* Creates a new $(D_PSYMBOL DList) with the elements from a static array.
|
||||||
@ -1192,11 +1082,7 @@ struct DList(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(shared Allocator allocator)
|
this(shared Allocator allocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.allocator_ = allocator;
|
this.allocator_ = allocator;
|
||||||
}
|
}
|
||||||
@ -1322,11 +1208,7 @@ struct DList(T)
|
|||||||
* Precondition: $(D_INLINECODE !empty).
|
* Precondition: $(D_INLINECODE !empty).
|
||||||
*/
|
*/
|
||||||
@property ref inout(T) front() inout
|
@property ref inout(T) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.head.content;
|
return this.head.content;
|
||||||
}
|
}
|
||||||
@ -1337,11 +1219,7 @@ struct DList(T)
|
|||||||
* Precondition: $(D_INLINECODE !empty).
|
* Precondition: $(D_INLINECODE !empty).
|
||||||
*/
|
*/
|
||||||
@property ref inout(T) back() inout
|
@property ref inout(T) back() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.tail.content;
|
return this.tail.content;
|
||||||
}
|
}
|
||||||
@ -1656,11 +1534,7 @@ struct DList(T)
|
|||||||
*/
|
*/
|
||||||
size_t insertBefore(R)(Range r, R el)
|
size_t insertBefore(R)(Range r, R el)
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return moveFront(*r.head, el);
|
return moveFront(*r.head, el);
|
||||||
}
|
}
|
||||||
@ -1676,11 +1550,7 @@ struct DList(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBefore()(Range r, ref T el) @trusted
|
size_t insertBefore()(Range r, ref T el) @trusted
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto temp = allocator.make!Entry(el, *r.head);
|
auto temp = allocator.make!Entry(el, *r.head);
|
||||||
|
|
||||||
@ -1714,11 +1584,7 @@ struct DList(T)
|
|||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
size_t inserted;
|
size_t inserted;
|
||||||
foreach (e; el)
|
foreach (e; el)
|
||||||
@ -1771,11 +1637,7 @@ struct DList(T)
|
|||||||
*/
|
*/
|
||||||
size_t insertAfter(R)(Range r, R el) @trusted
|
size_t insertAfter(R)(Range r, R el) @trusted
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return moveBack(*r.tail, el);
|
return moveBack(*r.tail, el);
|
||||||
}
|
}
|
||||||
@ -1793,11 +1655,7 @@ struct DList(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertAfter()(Range r, ref T el) @trusted
|
size_t insertAfter()(Range r, ref T el) @trusted
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto temp = allocator.make!Entry(el, null, *r.tail);
|
auto temp = allocator.make!Entry(el, null, *r.tail);
|
||||||
|
|
||||||
@ -1831,11 +1689,7 @@ struct DList(T)
|
|||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
size_t inserted;
|
size_t inserted;
|
||||||
foreach (e; el)
|
foreach (e; el)
|
||||||
@ -1926,11 +1780,7 @@ struct DList(T)
|
|||||||
* Precondition: $(D_INLINECODE !empty)
|
* Precondition: $(D_INLINECODE !empty)
|
||||||
*/
|
*/
|
||||||
void removeFront()
|
void removeFront()
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto n = this.head.next;
|
auto n = this.head.next;
|
||||||
|
|
||||||
@ -1962,11 +1812,7 @@ struct DList(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
void removeBack()
|
void removeBack()
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto n = this.tail.prev;
|
auto n = this.tail.prev;
|
||||||
|
|
||||||
@ -2008,11 +1854,7 @@ struct DList(T)
|
|||||||
* Returns: The number of elements removed.
|
* Returns: The number of elements removed.
|
||||||
*/
|
*/
|
||||||
size_t removeFront(size_t howMany)
|
size_t removeFront(size_t howMany)
|
||||||
out (removed)
|
out (removed; removed <= howMany)
|
||||||
{
|
|
||||||
assert(removed <= howMany);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (; i < howMany && !empty; ++i)
|
for (; i < howMany && !empty; ++i)
|
||||||
@ -2035,11 +1877,7 @@ struct DList(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t removeBack(size_t howMany)
|
size_t removeBack(size_t howMany)
|
||||||
out (removed)
|
out (removed; removed <= howMany)
|
||||||
{
|
|
||||||
assert(removed <= howMany);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (; i < howMany && !empty; ++i)
|
for (; i < howMany && !empty; ++i)
|
||||||
@ -2071,11 +1909,7 @@ struct DList(T)
|
|||||||
* Precondition: $(D_PARAM r) is extracted from this list.
|
* Precondition: $(D_PARAM r) is extracted from this list.
|
||||||
*/
|
*/
|
||||||
Range remove(Range r)
|
Range remove(Range r)
|
||||||
in
|
in (checkRangeBelonging(r))
|
||||||
{
|
|
||||||
assert(checkRangeBelonging(r));
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
// Save references to the elements before and after the range.
|
// Save references to the elements before and after the range.
|
||||||
Entry* headPrev;
|
Entry* headPrev;
|
||||||
@ -2147,11 +1981,7 @@ struct DList(T)
|
|||||||
* $(D_PARAM range) is extracted from this list.
|
* $(D_PARAM range) is extracted from this list.
|
||||||
*/
|
*/
|
||||||
Range popFirstOf(Range range)
|
Range popFirstOf(Range range)
|
||||||
in
|
in (!range.empty)
|
||||||
{
|
|
||||||
assert(!range.empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
remove(Range(*range.head, *range.head));
|
remove(Range(*range.head, *range.head));
|
||||||
return range;
|
return range;
|
||||||
@ -2159,11 +1989,7 @@ struct DList(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
Range popLastOf(Range range)
|
Range popLastOf(Range range)
|
||||||
in
|
in (!range.empty)
|
||||||
{
|
|
||||||
assert(!range.empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
remove(Range(*range.tail, *range.tail));
|
remove(Range(*range.tail, *range.tail));
|
||||||
return range;
|
return range;
|
||||||
@ -2317,82 +2143,3 @@ struct DList(T)
|
|||||||
}
|
}
|
||||||
assert(i == 3);
|
assert(i == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
class A
|
|
||||||
{
|
|
||||||
}
|
|
||||||
static assert(is(SList!(A*)));
|
|
||||||
static assert(is(DList!(A*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes all elements
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto l = DList!int([5]);
|
|
||||||
assert(l.remove(l[]).empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto l1 = DList!int([5, 234, 30, 1]);
|
|
||||||
auto l2 = DList!int([5, 1]);
|
|
||||||
auto r = l1[];
|
|
||||||
|
|
||||||
r.popFront();
|
|
||||||
r.popBack();
|
|
||||||
assert(r.front == 234);
|
|
||||||
assert(r.back == 30);
|
|
||||||
|
|
||||||
assert(!l1.remove(r).empty);
|
|
||||||
assert(l1 == l2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto l = DList!int(0, 0);
|
|
||||||
assert(l.empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto l1 = DList!int([5, 234]);
|
|
||||||
assert(l1.head is l1.head.next.prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
DList!int l;
|
|
||||||
l.insertAfter(l[], 234);
|
|
||||||
assert(l.front == 234);
|
|
||||||
assert(l.back == 234);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto l1 = DList!int();
|
|
||||||
auto l2 = DList!int([9, 4]);
|
|
||||||
l1 = l2[];
|
|
||||||
assert(l1 == l2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the new head
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto l1 = DList!int([5, 234, 30, 1]);
|
|
||||||
auto l2 = DList!int([1]);
|
|
||||||
auto r = l1[];
|
|
||||||
|
|
||||||
r.popBack();
|
|
||||||
|
|
||||||
assert(!l1.remove(r).empty);
|
|
||||||
assert(l1 == l2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can have non-copyable elements
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(is(SList!NonCopyable));
|
|
||||||
static assert(is(DList!NonCopyable));
|
|
||||||
}
|
|
||||||
|
@ -22,7 +22,6 @@ import tanya.memory;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
version (unittest) import tanya.test.stub;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bidirectional range that iterates over the $(D_PSYMBOL Set)'s values.
|
* Bidirectional range that iterates over the $(D_PSYMBOL Set)'s values.
|
||||||
@ -69,16 +68,9 @@ struct Range(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void popFront()
|
void popFront()
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.front.status == BucketStatus.used)
|
||||||
assert(!empty);
|
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(this.dataRange.front.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
{
|
|
||||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -88,16 +80,9 @@ struct Range(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void popBack()
|
void popBack()
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(!empty);
|
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
{
|
|
||||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -107,23 +92,15 @@ struct Range(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(E) front() inout
|
@property ref inout(E) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.front.status == BucketStatus.used)
|
||||||
assert(!empty);
|
|
||||||
assert(this.dataRange.front.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.dataRange.front.key;
|
return this.dataRange.front.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(E) back() inout
|
@property ref inout(E) back() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
in (this.dataRange.back.status == BucketStatus.used)
|
||||||
assert(!empty);
|
|
||||||
assert(this.dataRange.back.status == BucketStatus.used);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.dataRange.back.key;
|
return this.dataRange.back.key;
|
||||||
}
|
}
|
||||||
@ -168,12 +145,9 @@ if (isHashFunction!(hasher, T))
|
|||||||
/// ditto
|
/// ditto
|
||||||
alias ConstRange = .Range!(const HashArray);
|
alias ConstRange = .Range!(const HashArray);
|
||||||
|
|
||||||
invariant
|
invariant (this.data.lengthIndex < primes.length);
|
||||||
{
|
invariant (this.data.array.length == 0
|
||||||
assert(this.data.lengthIndex < primes.length);
|
|
||||||
assert(this.data.array.length == 0
|
|
||||||
|| this.data.array.length == primes[this.data.lengthIndex]);
|
|| this.data.array.length == primes[this.data.lengthIndex]);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@ -185,11 +159,7 @@ if (isHashFunction!(hasher, T))
|
|||||||
* Precondition: $(D_INLINECODE allocator !is null).
|
* Precondition: $(D_INLINECODE allocator !is null).
|
||||||
*/
|
*/
|
||||||
this(size_t n, shared Allocator allocator = defaultAllocator)
|
this(size_t n, shared Allocator allocator = defaultAllocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
this.data.rehash(n);
|
this.data.rehash(n);
|
||||||
@ -204,11 +174,7 @@ if (isHashFunction!(hasher, T))
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(shared Allocator allocator)
|
this(shared Allocator allocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.data = HashArray(allocator);
|
this.data = HashArray(allocator);
|
||||||
}
|
}
|
||||||
@ -228,11 +194,7 @@ if (isHashFunction!(hasher, T))
|
|||||||
*/
|
*/
|
||||||
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
|
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
|
||||||
if (is(Unqual!S == Set))
|
if (is(Unqual!S == Set))
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.data = HashArray(init.data, allocator);
|
this.data = HashArray(init.data, allocator);
|
||||||
}
|
}
|
||||||
@ -240,11 +202,7 @@ if (isHashFunction!(hasher, T))
|
|||||||
/// ditto
|
/// ditto
|
||||||
this(S)(S init, shared Allocator allocator = defaultAllocator)
|
this(S)(S init, shared Allocator allocator = defaultAllocator)
|
||||||
if (is(S == Set))
|
if (is(S == Set))
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.data.move(init.data, allocator);
|
this.data.move(init.data, allocator);
|
||||||
}
|
}
|
||||||
@ -261,11 +219,7 @@ if (isHashFunction!(hasher, T))
|
|||||||
*/
|
*/
|
||||||
this(R)(R range, shared Allocator allocator = defaultAllocator)
|
this(R)(R range, shared Allocator allocator = defaultAllocator)
|
||||||
if (isForwardRange!R && isImplicitlyConvertible!(ElementType!R, T))
|
if (isForwardRange!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
insert(range);
|
insert(range);
|
||||||
}
|
}
|
||||||
@ -291,11 +245,7 @@ if (isHashFunction!(hasher, T))
|
|||||||
* Precondition: $(D_INLINECODE allocator !is null).
|
* Precondition: $(D_INLINECODE allocator !is null).
|
||||||
*/
|
*/
|
||||||
this(size_t n)(T[n] array, shared Allocator allocator = defaultAllocator)
|
this(size_t n)(T[n] array, shared Allocator allocator = defaultAllocator)
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
insert(array[]);
|
insert(array[]);
|
||||||
}
|
}
|
||||||
@ -342,11 +292,7 @@ if (isHashFunction!(hasher, T))
|
|||||||
* Postcondition: $(D_INLINECODE allocator !is null)
|
* Postcondition: $(D_INLINECODE allocator !is null)
|
||||||
*/
|
*/
|
||||||
@property shared(Allocator) allocator() const
|
@property shared(Allocator) allocator() const
|
||||||
out (allocator)
|
out (allocator; allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return this.data.array.allocator;
|
return this.data.array.allocator;
|
||||||
}
|
}
|
||||||
@ -638,150 +584,3 @@ if (isHashFunction!(hasher, T))
|
|||||||
assert(set[].back == 8);
|
assert(set[].back == 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic insertion logic.
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
Set!int set;
|
|
||||||
|
|
||||||
assert(set.insert(5) == 1);
|
|
||||||
assert(5 in set);
|
|
||||||
assert(set.data.array.length == 3);
|
|
||||||
|
|
||||||
assert(set.insert(5) == 0);
|
|
||||||
assert(5 in set);
|
|
||||||
assert(set.data.array.length == 3);
|
|
||||||
|
|
||||||
assert(set.insert(9) == 1);
|
|
||||||
assert(9 in set);
|
|
||||||
assert(5 in set);
|
|
||||||
assert(set.data.array.length == 3);
|
|
||||||
|
|
||||||
assert(set.insert(7) == 1);
|
|
||||||
assert(set.insert(8) == 1);
|
|
||||||
assert(8 in set);
|
|
||||||
assert(5 in set);
|
|
||||||
assert(9 in set);
|
|
||||||
assert(7 in set);
|
|
||||||
assert(set.data.array.length == 7);
|
|
||||||
|
|
||||||
assert(set.insert(16) == 1);
|
|
||||||
assert(16 in set);
|
|
||||||
assert(set.data.array.length == 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Static checks.
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
import tanya.range.primitive;
|
|
||||||
|
|
||||||
static assert(isBidirectionalRange!(Set!int.ConstRange));
|
|
||||||
static assert(isBidirectionalRange!(Set!int.Range));
|
|
||||||
|
|
||||||
static assert(!isInfinite!(Set!int.Range));
|
|
||||||
static assert(!hasLength!(Set!int.Range));
|
|
||||||
|
|
||||||
static assert(is(Set!uint));
|
|
||||||
static assert(is(Set!long));
|
|
||||||
static assert(is(Set!ulong));
|
|
||||||
static assert(is(Set!short));
|
|
||||||
static assert(is(Set!ushort));
|
|
||||||
static assert(is(Set!bool));
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
const Set!int set;
|
|
||||||
assert(set[].empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
Set!int set;
|
|
||||||
set.insert(8);
|
|
||||||
|
|
||||||
auto r1 = set[];
|
|
||||||
auto r2 = r1.save();
|
|
||||||
|
|
||||||
r1.popFront();
|
|
||||||
assert(r1.empty);
|
|
||||||
|
|
||||||
r2.popBack();
|
|
||||||
assert(r2.empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initial capacity is 0.
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto set = Set!int(defaultAllocator);
|
|
||||||
assert(set.capacity == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capacity is set to a prime.
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto set = Set!int(8);
|
|
||||||
assert(set.capacity == 13);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructs by reference
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto set1 = Set!int(7);
|
|
||||||
auto set2 = Set!int(set1);
|
|
||||||
assert(set1.length == set2.length);
|
|
||||||
assert(set1.capacity == set2.capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructs by value
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto set = Set!int(Set!int(7));
|
|
||||||
assert(set.capacity == 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assigns by reference
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto set1 = Set!int(7);
|
|
||||||
Set!int set2;
|
|
||||||
set1 = set2;
|
|
||||||
assert(set1.length == set2.length);
|
|
||||||
assert(set1.capacity == set2.capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assigns by value
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
Set!int set;
|
|
||||||
set = Set!int(7);
|
|
||||||
assert(set.capacity == 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Postblit copies
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto set = Set!int(7);
|
|
||||||
void testFunc(Set!int set)
|
|
||||||
{
|
|
||||||
assert(set.capacity == 7);
|
|
||||||
}
|
|
||||||
testFunc(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hasher can take argument by ref
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
static assert(is(Set!(int, (const ref x) => cast(size_t) x)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can have non-copyable elements
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
@NonCopyable @Hashable
|
|
||||||
static struct S
|
|
||||||
{
|
|
||||||
mixin StructStub;
|
|
||||||
}
|
|
||||||
static assert(is(Set!S));
|
|
||||||
}
|
|
||||||
|
@ -35,11 +35,6 @@ import tanya.meta.transform;
|
|||||||
import tanya.range.array;
|
import tanya.range.array;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
|
|
||||||
version (unittest)
|
|
||||||
{
|
|
||||||
import tanya.test.assertion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown on encoding errors.
|
* Thrown on encoding errors.
|
||||||
*/
|
*/
|
||||||
@ -74,22 +69,15 @@ if (is(Unqual!E == char))
|
|||||||
private alias ContainerType = CopyConstness!(E, String);
|
private alias ContainerType = CopyConstness!(E, String);
|
||||||
private ContainerType* container;
|
private ContainerType* container;
|
||||||
|
|
||||||
invariant
|
invariant (this.begin <= this.end);
|
||||||
{
|
invariant (this.container !is null);
|
||||||
assert(this.begin <= this.end);
|
invariant (this.begin >= this.container.data);
|
||||||
assert(this.container !is null);
|
invariant (this.end <= this.container.data + this.container.length);
|
||||||
assert(this.begin >= this.container.data);
|
|
||||||
assert(this.end <= this.container.data + this.container.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private this(ref ContainerType container, E* begin, E* end) @trusted
|
private this(ref ContainerType container, E* begin, E* end) @trusted
|
||||||
in
|
in (begin <= end)
|
||||||
{
|
in (begin >= container.data)
|
||||||
assert(begin <= end);
|
in (end <= container.data + container.length)
|
||||||
assert(begin >= container.data);
|
|
||||||
assert(end <= container.data + container.length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.container = &container;
|
this.container = &container;
|
||||||
this.begin = begin;
|
this.begin = begin;
|
||||||
@ -116,51 +104,31 @@ if (is(Unqual!E == char))
|
|||||||
alias opDollar = length;
|
alias opDollar = length;
|
||||||
|
|
||||||
@property ref inout(E) front() inout
|
@property ref inout(E) front() inout
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *this.begin;
|
return *this.begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(E) back() inout @trusted
|
@property ref inout(E) back() inout @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *(this.end - 1);
|
return *(this.end - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront() @trusted
|
void popFront() @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
++this.begin;
|
++this.begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popBack() @trusted
|
void popBack() @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
--this.end;
|
--this.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref inout(E) opIndex(const size_t i) inout @trusted
|
ref inout(E) opIndex(const size_t i) inout @trusted
|
||||||
in
|
in (i < length)
|
||||||
{
|
|
||||||
assert(i < length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *(this.begin + i);
|
return *(this.begin + i);
|
||||||
}
|
}
|
||||||
@ -176,23 +144,15 @@ if (is(Unqual!E == char))
|
|||||||
}
|
}
|
||||||
|
|
||||||
ByCodeUnit opSlice(const size_t i, const size_t j) @trusted
|
ByCodeUnit opSlice(const size_t i, const size_t j) @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByCodeUnit!(const E) opSlice(const size_t i, const size_t j) const @trusted
|
ByCodeUnit!(const E) opSlice(const size_t i, const size_t j) const @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
||||||
}
|
}
|
||||||
@ -216,22 +176,15 @@ if (is(Unqual!E == char))
|
|||||||
private alias ContainerType = CopyConstness!(E, String);
|
private alias ContainerType = CopyConstness!(E, String);
|
||||||
private ContainerType* container;
|
private ContainerType* container;
|
||||||
|
|
||||||
invariant
|
invariant (this.begin <= this.end);
|
||||||
{
|
invariant (this.container !is null);
|
||||||
assert(this.begin <= this.end);
|
invariant (this.begin >= this.container.data);
|
||||||
assert(this.container !is null);
|
invariant (this.end <= this.container.data + this.container.length);
|
||||||
assert(this.begin >= this.container.data);
|
|
||||||
assert(this.end <= this.container.data + this.container.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private this(ref ContainerType container, E* begin, E* end) @trusted
|
private this(ref ContainerType container, E* begin, E* end) @trusted
|
||||||
in
|
in (begin <= end)
|
||||||
{
|
in (begin >= container.data)
|
||||||
assert(begin <= end);
|
in (end <= container.data + container.length)
|
||||||
assert(begin >= container.data);
|
|
||||||
assert(end <= container.data + container.length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.container = &container;
|
this.container = &container;
|
||||||
this.begin = begin;
|
this.begin = begin;
|
||||||
@ -251,15 +204,8 @@ if (is(Unqual!E == char))
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property dchar front() const @trusted
|
@property dchar front() const @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
out (chr; chr < 0xd800 || chr > 0xdfff)
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
out (chr)
|
|
||||||
{
|
|
||||||
assert(chr < 0xd800 || chr > 0xdfff);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
dchar chr;
|
dchar chr;
|
||||||
ubyte units;
|
ubyte units;
|
||||||
@ -289,11 +235,7 @@ if (is(Unqual!E == char))
|
|||||||
}
|
}
|
||||||
|
|
||||||
void popFront() @trusted
|
void popFront() @trusted
|
||||||
in
|
in (!empty)
|
||||||
{
|
|
||||||
assert(!empty);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
ubyte units;
|
ubyte units;
|
||||||
if ((*begin & 0xf0) == 0xf0)
|
if ((*begin & 0xf0) == 0xf0)
|
||||||
@ -339,10 +281,7 @@ struct String
|
|||||||
private char* data;
|
private char* data;
|
||||||
private size_t capacity_;
|
private size_t capacity_;
|
||||||
|
|
||||||
pure nothrow @safe @nogc invariant
|
@nogc nothrow pure @safe invariant (this.length_ <= this.capacity_);
|
||||||
{
|
|
||||||
assert(this.length_ <= this.capacity_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the string from a stringish range.
|
* Constructs the string from a stringish range.
|
||||||
@ -432,11 +371,7 @@ struct String
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(shared Allocator allocator) @nogc nothrow pure @safe
|
this(shared Allocator allocator) @nogc nothrow pure @safe
|
||||||
in
|
in (allocator !is null)
|
||||||
{
|
|
||||||
assert(allocator !is null);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
this.allocator_ = allocator;
|
this.allocator_ = allocator;
|
||||||
}
|
}
|
||||||
@ -497,12 +432,6 @@ struct String
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto s = String(0, 'K');
|
|
||||||
assert(s.length == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
this(this) @nogc nothrow pure @trusted
|
this(this) @nogc nothrow pure @trusted
|
||||||
{
|
{
|
||||||
auto buf = this.data[0 .. this.length_];
|
auto buf = this.data[0 .. this.length_];
|
||||||
@ -521,12 +450,8 @@ struct String
|
|||||||
|
|
||||||
private void write4Bytes(ref const dchar src)
|
private void write4Bytes(ref const dchar src)
|
||||||
@nogc nothrow pure @trusted
|
@nogc nothrow pure @trusted
|
||||||
in
|
in (capacity - length >= 4)
|
||||||
{
|
in (src - 0x10000 < 0x100000)
|
||||||
assert(capacity - length >= 4);
|
|
||||||
assert(src - 0x10000 < 0x100000);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto dst = this.data + length;
|
auto dst = this.data + length;
|
||||||
|
|
||||||
@ -540,11 +465,7 @@ struct String
|
|||||||
|
|
||||||
private size_t insertWideChar(C)(auto ref const C chr) @trusted
|
private size_t insertWideChar(C)(auto ref const C chr) @trusted
|
||||||
if (is(C == wchar) || is(C == dchar))
|
if (is(C == wchar) || is(C == dchar))
|
||||||
in
|
in (capacity - length >= 3)
|
||||||
{
|
|
||||||
assert(capacity - length >= 3);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto dst = this.data + length;
|
auto dst = this.data + length;
|
||||||
if (chr < 0x80)
|
if (chr < 0x80)
|
||||||
@ -602,13 +523,6 @@ struct String
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocates enough space for 3-byte character.
|
|
||||||
@nogc pure @safe unittest
|
|
||||||
{
|
|
||||||
String s;
|
|
||||||
s.insertBack('\u8100');
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBack(const dchar chr) @nogc pure @trusted
|
size_t insertBack(const dchar chr) @nogc pure @trusted
|
||||||
{
|
{
|
||||||
@ -630,12 +544,6 @@ struct String
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc pure @safe unittest
|
|
||||||
{
|
|
||||||
assertThrown!UTFException(() => String(1, cast(dchar) 0xd900));
|
|
||||||
assertThrown!UTFException(() => String(1, cast(wchar) 0xd900));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a stringish range at the end of the string.
|
* Inserts a stringish range at the end of the string.
|
||||||
*
|
*
|
||||||
@ -880,13 +788,9 @@ struct String
|
|||||||
const size_t i,
|
const size_t i,
|
||||||
const size_t j)
|
const size_t j)
|
||||||
if (is(Unqual!R == char))
|
if (is(Unqual!R == char))
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
in (j - i == value.length)
|
||||||
assert(j <= length);
|
|
||||||
assert(j - i == value.length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto target = opSlice(i, j);
|
auto target = opSlice(i, j);
|
||||||
copy(value, target);
|
copy(value, target);
|
||||||
@ -898,12 +802,8 @@ struct String
|
|||||||
const size_t i,
|
const size_t i,
|
||||||
const size_t j)
|
const size_t j)
|
||||||
@nogc nothrow pure @trusted
|
@nogc nothrow pure @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
copy(value[], this.data[i .. j]);
|
copy(value[], this.data[i .. j]);
|
||||||
return opSlice(i, j);
|
return opSlice(i, j);
|
||||||
@ -914,12 +814,8 @@ struct String
|
|||||||
const size_t i,
|
const size_t i,
|
||||||
const size_t j)
|
const size_t j)
|
||||||
@nogc nothrow pure @trusted
|
@nogc nothrow pure @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
for (auto p = this.data + i; p < this.data + j; ++p)
|
for (auto p = this.data + i; p < this.data + j; ++p)
|
||||||
{
|
{
|
||||||
@ -996,11 +892,7 @@ struct String
|
|||||||
* Precondition: $(D_INLINECODE length > pos).
|
* Precondition: $(D_INLINECODE length > pos).
|
||||||
*/
|
*/
|
||||||
ref inout(char) opIndex(const size_t pos) inout @nogc nothrow pure @trusted
|
ref inout(char) opIndex(const size_t pos) inout @nogc nothrow pure @trusted
|
||||||
in
|
in (length > pos)
|
||||||
{
|
|
||||||
assert(length > pos);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return *(this.data + pos);
|
return *(this.data + pos);
|
||||||
}
|
}
|
||||||
@ -1145,12 +1037,8 @@ struct String
|
|||||||
*/
|
*/
|
||||||
ByCodeUnit!char opSlice(const size_t i, const size_t j)
|
ByCodeUnit!char opSlice(const size_t i, const size_t j)
|
||||||
@nogc nothrow pure @trusted
|
@nogc nothrow pure @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(return)(this, this.data + i, this.data + j);
|
return typeof(return)(this, this.data + i, this.data + j);
|
||||||
}
|
}
|
||||||
@ -1158,12 +1046,8 @@ struct String
|
|||||||
/// ditto
|
/// ditto
|
||||||
ByCodeUnit!(const char) opSlice(const size_t i, const size_t j)
|
ByCodeUnit!(const char) opSlice(const size_t i, const size_t j)
|
||||||
const @nogc nothrow pure @trusted
|
const @nogc nothrow pure @trusted
|
||||||
in
|
in (i <= j)
|
||||||
{
|
in (j <= length)
|
||||||
assert(i <= j);
|
|
||||||
assert(j <= length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return typeof(return)(this, this.data + i, this.data + j);
|
return typeof(return)(this, this.data + i, this.data + j);
|
||||||
}
|
}
|
||||||
@ -1418,40 +1302,18 @@ struct String
|
|||||||
return opSliceAssign(value, 0, length);
|
return opSliceAssign(value, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto s1 = String("Buttercup");
|
|
||||||
auto s2 = String("Cap");
|
|
||||||
s2[] = s1[6 .. $];
|
|
||||||
assert(s2 == "cup");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
ByCodeUnit!char opIndexAssign(const char value) @nogc nothrow pure @safe
|
ByCodeUnit!char opIndexAssign(const char value) @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
return opSliceAssign(value, 0, length);
|
return opSliceAssign(value, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto s1 = String("Wow");
|
|
||||||
s1[] = 'a';
|
|
||||||
assert(s1 == "aaa");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
ByCodeUnit!char opIndexAssign(const char[] value) @nogc nothrow pure @safe
|
ByCodeUnit!char opIndexAssign(const char[] value) @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
return opSliceAssign(value, 0, length);
|
return opSliceAssign(value, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto s1 = String("ö");
|
|
||||||
s1[] = "oe";
|
|
||||||
assert(s1 == "oe");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all characters beloning to $(D_PARAM r).
|
* Remove all characters beloning to $(D_PARAM r).
|
||||||
*
|
*
|
||||||
@ -1466,13 +1328,9 @@ struct String
|
|||||||
*/
|
*/
|
||||||
R remove(R)(R r) @trusted
|
R remove(R)(R r) @trusted
|
||||||
if (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char))
|
if (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char))
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= this.data + length)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= this.data + length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
auto end = this.data + this.length;
|
auto end = this.data + this.length;
|
||||||
copy(ByCodeUnit!char(this, r.end, end), ByCodeUnit!char(this, r.begin, end));
|
copy(ByCodeUnit!char(this, r.end, end), ByCodeUnit!char(this, r.begin, end));
|
||||||
@ -1521,13 +1379,9 @@ struct String
|
|||||||
&& isInputRange!T
|
&& isInputRange!T
|
||||||
&& isSomeChar!(ElementType!T)))
|
&& isSomeChar!(ElementType!T)))
|
||||||
&& (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char)))
|
&& (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char)))
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= this.data + length)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= this.data + length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
const oldLength = length;
|
const oldLength = length;
|
||||||
const after = r.end - this.data;
|
const after = r.end - this.data;
|
||||||
@ -1555,13 +1409,9 @@ struct String
|
|||||||
&& isInputRange!T
|
&& isInputRange!T
|
||||||
&& isSomeChar!(ElementType!T)))
|
&& isSomeChar!(ElementType!T)))
|
||||||
&& (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char)))
|
&& (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char)))
|
||||||
in
|
in (r.container is &this)
|
||||||
{
|
in (r.begin >= this.data)
|
||||||
assert(r.container is &this);
|
in (r.end <= this.data + length)
|
||||||
assert(r.begin >= this.data);
|
|
||||||
assert(r.end <= this.data + length);
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
return insertAfter(R(this, this.data, r.begin), el);
|
return insertAfter(R(this, this.data, r.begin), el);
|
||||||
}
|
}
|
||||||
@ -1590,76 +1440,3 @@ struct String
|
|||||||
|
|
||||||
mixin DefaultAllocator;
|
mixin DefaultAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Postblit works
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
void internFunc(String arg)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void middleFunc(S...)(S args)
|
|
||||||
{
|
|
||||||
foreach (arg; args)
|
|
||||||
{
|
|
||||||
internFunc(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void topFunc(String args)
|
|
||||||
{
|
|
||||||
middleFunc(args);
|
|
||||||
}
|
|
||||||
topFunc(String("asdf"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Const range produces mutable ranges
|
|
||||||
@nogc pure @safe unittest
|
|
||||||
{
|
|
||||||
auto s = const String("И снизу лед, и сверху - маюсь между.");
|
|
||||||
{
|
|
||||||
const constRange = s[];
|
|
||||||
|
|
||||||
auto fromConstRange = constRange[];
|
|
||||||
fromConstRange.popFront();
|
|
||||||
assert(fromConstRange.front == s[1]);
|
|
||||||
|
|
||||||
fromConstRange = constRange[0 .. $];
|
|
||||||
fromConstRange.popFront();
|
|
||||||
assert(fromConstRange.front == s[1]);
|
|
||||||
|
|
||||||
assert(constRange.get() is s.get());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const constRange = s.byCodePoint();
|
|
||||||
|
|
||||||
auto fromConstRange = constRange[];
|
|
||||||
fromConstRange.popFront();
|
|
||||||
assert(fromConstRange.front == ' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can pop multibyte characters
|
|
||||||
@nogc pure @safe unittest
|
|
||||||
{
|
|
||||||
auto s = String("\U00024B62\U00002260");
|
|
||||||
auto range = s.byCodePoint();
|
|
||||||
|
|
||||||
range.popFront();
|
|
||||||
assert(!range.empty);
|
|
||||||
|
|
||||||
range.popFront();
|
|
||||||
assert(range.empty);
|
|
||||||
|
|
||||||
range = s.byCodePoint();
|
|
||||||
range.popFront();
|
|
||||||
s[$ - 3] = 0xf0;
|
|
||||||
assertThrown!UTFException(&(range.popFront));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inserts own char range correctly
|
|
||||||
@nogc nothrow pure @safe unittest
|
|
||||||
{
|
|
||||||
auto s1 = String(`ü`);
|
|
||||||
String s2;
|
|
||||||
s2.insertBack(s1[]);
|
|
||||||
assert(s1 == s2);
|
|
||||||
}
|
|
||||||
|
97
tests/tanya/algorithm/tests/comparison.d
Normal file
97
tests/tanya/algorithm/tests/comparison.d
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.algorithm.tests.comparison;
|
||||||
|
|
||||||
|
import tanya.algorithm.comparison;
|
||||||
|
import tanya.math;
|
||||||
|
import tanya.range;
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(!is(typeof(min(1, 1UL))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(min(5, 3) == 3);
|
||||||
|
assert(min(4, 4) == 4);
|
||||||
|
assert(min(5.2, 3.0) == 3.0);
|
||||||
|
|
||||||
|
assert(min(5.2, double.nan) == 5.2);
|
||||||
|
assert(min(double.nan, 3.0) == 3.0);
|
||||||
|
assert(isNaN(min(double.nan, double.nan)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(min(cast(ubyte[]) []).empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(!is(typeof(max(1, 1UL))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(max(5, 3) == 5);
|
||||||
|
assert(max(4, 4) == 4);
|
||||||
|
assert(max(5.2, 3.0) == 5.2);
|
||||||
|
|
||||||
|
assert(max(5.2, double.nan) == 5.2);
|
||||||
|
assert(max(double.nan, 3.0) == 3.0);
|
||||||
|
assert(isNaN(max(double.nan, double.nan)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(max(cast(ubyte[]) []).empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// min/max compare const and mutable structs.
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static struct S
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
|
||||||
|
int opCmp(typeof(this) that) const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return this.s - that.s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const s1 = S(1);
|
||||||
|
assert(min(s1, S(2)).s == 1);
|
||||||
|
assert(max(s1, S(2)).s == 2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto s2 = S(2), s3 = S(3);
|
||||||
|
assert(min(s2, s3).s == 2);
|
||||||
|
assert(max(s2, s3).s == 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static struct OpCmp(int value)
|
||||||
|
{
|
||||||
|
int opCmp(OpCmp) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OpCmp!(-1)[1] range;
|
||||||
|
assert(compare(range[], range[]) < 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OpCmp!1[1] range;
|
||||||
|
assert(compare(range[], range[]) > 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
OpCmp!0[1] range;
|
||||||
|
assert(compare(range[], range[]) == 0);
|
||||||
|
}
|
||||||
|
}
|
127
tests/tanya/algorithm/tests/iteration.d
Normal file
127
tests/tanya/algorithm/tests/iteration.d
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.algorithm.tests.iteration;
|
||||||
|
|
||||||
|
import tanya.algorithm.iteration;
|
||||||
|
import tanya.range;
|
||||||
|
import tanya.test.stub;
|
||||||
|
|
||||||
|
// length is unknown when taking from a range without length
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static struct R
|
||||||
|
{
|
||||||
|
mixin InputRangeStub;
|
||||||
|
}
|
||||||
|
auto actual = take(R(), 100);
|
||||||
|
|
||||||
|
static assert(!hasLength!(typeof(actual)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes minimum length if the range length > n
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto range = take(cast(int[]) null, 8);
|
||||||
|
assert(range.length == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
const int[9] range = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
{
|
||||||
|
auto slice = take(range[], 8)[1 .. 3];
|
||||||
|
|
||||||
|
assert(slice.length == 2);
|
||||||
|
assert(slice.front == 2);
|
||||||
|
assert(slice.back == 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto slice = takeExactly(range[], 8)[1 .. 3];
|
||||||
|
|
||||||
|
assert(slice.length == 2);
|
||||||
|
assert(slice.front == 2);
|
||||||
|
assert(slice.back == 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elements are accessible in reverse order
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
const int[3] given = [1, 2, 3];
|
||||||
|
auto actual = retro(given[]);
|
||||||
|
|
||||||
|
assert(actual.back == given[].front);
|
||||||
|
assert(actual[0] == 3);
|
||||||
|
assert(actual[2] == 1);
|
||||||
|
|
||||||
|
actual.popBack();
|
||||||
|
assert(actual.back == 2);
|
||||||
|
assert(actual[1] == 2);
|
||||||
|
|
||||||
|
// Check slicing.
|
||||||
|
auto slice = retro(given[])[1 .. $];
|
||||||
|
assert(slice.length == 2 && slice.front == 2 && slice.back == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elements can be assigned
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
int[4] given = [1, 2, 3, 4];
|
||||||
|
auto actual = retro(given[]);
|
||||||
|
|
||||||
|
actual.front = 5;
|
||||||
|
assert(given[].back == 5);
|
||||||
|
|
||||||
|
actual.back = 8;
|
||||||
|
assert(given[].front == 8);
|
||||||
|
|
||||||
|
actual[2] = 10;
|
||||||
|
assert(given[1] == 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Singleton range is bidirectional and random-access
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(isBidirectionalRange!(typeof(singleton('a'))));
|
||||||
|
static assert(isRandomAccessRange!(typeof(singleton('a'))));
|
||||||
|
|
||||||
|
assert({ char a; return isBidirectionalRange!(typeof(singleton(a))); });
|
||||||
|
assert({ char a; return isRandomAccessRange!(typeof(singleton(a))); });
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
char a = 'a';
|
||||||
|
auto single = singleton(a);
|
||||||
|
|
||||||
|
assert(single.front == 'a');
|
||||||
|
assert(single.back == 'a');
|
||||||
|
assert(single[0] == 'a');
|
||||||
|
assert(single.length == 1);
|
||||||
|
assert(!single.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// popFront makes SingletonByRef empty
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
char a = 'a';
|
||||||
|
auto single = singleton(a);
|
||||||
|
|
||||||
|
single.popFront();
|
||||||
|
assert(single.empty);
|
||||||
|
assert(single.length == 0);
|
||||||
|
assert(single.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// popBack makes SingletonByRef empty
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
char a = 'b';
|
||||||
|
auto single = singleton(a);
|
||||||
|
|
||||||
|
single.popBack();
|
||||||
|
assert(single.empty);
|
||||||
|
assert(single.length == 0);
|
||||||
|
assert(single.empty);
|
||||||
|
}
|
128
tests/tanya/algorithm/tests/mutation.d
Normal file
128
tests/tanya/algorithm/tests/mutation.d
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.algorithm.tests.mutation;
|
||||||
|
|
||||||
|
import tanya.algorithm.mutation;
|
||||||
|
import tanya.range;
|
||||||
|
import tanya.test.stub;
|
||||||
|
|
||||||
|
// Returns advanced target
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
int[5] input = [1, 2, 3, 4, 5];
|
||||||
|
assert(copy(input[3 .. 5], input[]).front == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies overlapping arrays
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
import tanya.algorithm.comparison : equal;
|
||||||
|
|
||||||
|
int[6] actual = [1, 2, 3, 4, 5, 6];
|
||||||
|
const int[6] expected = [1, 2, 1, 2, 3, 4];
|
||||||
|
|
||||||
|
copy(actual[0 .. 4], actual[2 .. 6]);
|
||||||
|
assert(equal(actual[], expected[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(typeof(copy((ubyte[]).init, (ushort[]).init))));
|
||||||
|
static assert(!is(typeof(copy((ushort[]).init, (ubyte[]).init))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static struct OutPutRange
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
|
||||||
|
void opCall(int value) @nogc nothrow pure @safe
|
||||||
|
in (this.value == 0)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int[1] source = [5];
|
||||||
|
OutPutRange target;
|
||||||
|
|
||||||
|
assert(copy(source[], target).value == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [] is called where possible
|
||||||
|
@nogc nothrow pure @system unittest
|
||||||
|
{
|
||||||
|
static struct Slice
|
||||||
|
{
|
||||||
|
bool* slicingCalled;
|
||||||
|
|
||||||
|
int front() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void front(int) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opIndexAssign(int) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
*this.slicingCalled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool slicingCalled;
|
||||||
|
auto range = Slice(&slicingCalled);
|
||||||
|
fill(range, 0);
|
||||||
|
assert(slicingCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
NonCopyable[] nonCopyable;
|
||||||
|
initializeAll(nonCopyable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
import tanya.algorithm.comparison : equal;
|
||||||
|
|
||||||
|
const int[5] expected = [1, 2, 3, 4, 5];
|
||||||
|
int[5] actual = [4, 5, 1, 2, 3];
|
||||||
|
|
||||||
|
rotate(actual[0 .. 2], actual[2 .. $]);
|
||||||
|
assert(equal(actual[], expected[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doesn't cause an infinite loop if back is shorter than the front
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
import tanya.algorithm.comparison : equal;
|
||||||
|
|
||||||
|
const int[5] expected = [1, 2, 3, 4, 5];
|
||||||
|
int[5] actual = [3, 4, 5, 1, 2];
|
||||||
|
|
||||||
|
rotate(actual[0 .. 3], actual[3 .. $]);
|
||||||
|
assert(equal(actual[], expected[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doesn't call .front on an empty front
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
import tanya.algorithm.comparison : equal;
|
||||||
|
|
||||||
|
const int[2] expected = [2, 8];
|
||||||
|
int[2] actual = expected;
|
||||||
|
|
||||||
|
rotate(actual[0 .. 0], actual[]);
|
||||||
|
assert(equal(actual[], expected[]));
|
||||||
|
}
|
17
tests/tanya/algorithm/tests/searching.d
Normal file
17
tests/tanya/algorithm/tests/searching.d
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.algorithm.tests.searching;
|
||||||
|
|
||||||
|
import tanya.algorithm.searching;
|
||||||
|
import tanya.test.stub;
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
@Count(3)
|
||||||
|
static struct Range
|
||||||
|
{
|
||||||
|
mixin InputRangeStub!int;
|
||||||
|
}
|
||||||
|
assert(count(Range()) == 3);
|
||||||
|
}
|
97
tests/tanya/async/tests/loop.d
Normal file
97
tests/tanya/async/tests/loop.d
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.async.tests.loop;
|
||||||
|
|
||||||
|
import core.time;
|
||||||
|
import tanya.async.loop;
|
||||||
|
import tanya.async.watcher;
|
||||||
|
import tanya.memory;
|
||||||
|
|
||||||
|
private final class DummyWatcher : Watcher
|
||||||
|
{
|
||||||
|
bool invoked;
|
||||||
|
|
||||||
|
override void invoke() @nogc
|
||||||
|
{
|
||||||
|
this.invoked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TestLoop : Loop
|
||||||
|
{
|
||||||
|
override protected bool reify(SocketWatcher watcher,
|
||||||
|
EventMask oldEvents,
|
||||||
|
EventMask events) @nogc
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected void poll() @nogc
|
||||||
|
{
|
||||||
|
assert(!this.done);
|
||||||
|
unloop();
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected @property uint maxEvents()
|
||||||
|
const pure nothrow @safe @nogc
|
||||||
|
{
|
||||||
|
return 64U;
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc @system unittest
|
||||||
|
{
|
||||||
|
auto loop = defaultAllocator.make!TestLoop;
|
||||||
|
assert(loop.blockTime == 1.dur!"minutes");
|
||||||
|
|
||||||
|
loop.blockTime = 2.dur!"minutes";
|
||||||
|
assert(loop.blockTime == 2.dur!"minutes");
|
||||||
|
|
||||||
|
defaultAllocator.dispose(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc @system unittest
|
||||||
|
{
|
||||||
|
auto loop = defaultAllocator.make!TestLoop;
|
||||||
|
assert(loop.done);
|
||||||
|
|
||||||
|
loop.run();
|
||||||
|
assert(loop.done);
|
||||||
|
|
||||||
|
defaultAllocator.dispose(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc @system unittest
|
||||||
|
{
|
||||||
|
auto loop = defaultAllocator.make!TestLoop;
|
||||||
|
auto watcher = defaultAllocator.make!DummyWatcher;
|
||||||
|
loop.pendings.insertBack(watcher);
|
||||||
|
|
||||||
|
assert(!watcher.invoked);
|
||||||
|
loop.run();
|
||||||
|
assert(watcher.invoked);
|
||||||
|
|
||||||
|
defaultAllocator.dispose(loop);
|
||||||
|
defaultAllocator.dispose(watcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc @system unittest
|
||||||
|
{
|
||||||
|
auto loop = defaultAllocator.make!TestLoop;
|
||||||
|
assert(loop.maxEvents == 64);
|
||||||
|
|
||||||
|
defaultAllocator.dispose(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc @system unittest
|
||||||
|
{
|
||||||
|
auto oldLoop = defaultLoop;
|
||||||
|
auto loop = defaultAllocator.make!TestLoop;
|
||||||
|
|
||||||
|
defaultLoop = loop;
|
||||||
|
assert(defaultLoop is loop);
|
||||||
|
|
||||||
|
defaultLoop = oldLoop;
|
||||||
|
defaultAllocator.dispose(loop);
|
||||||
|
}
|
196
tests/tanya/container/tests/array.d
Normal file
196
tests/tanya/container/tests/array.d
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.container.tests.array;
|
||||||
|
|
||||||
|
import tanya.algorithm.comparison;
|
||||||
|
import tanya.container.array;
|
||||||
|
import tanya.memory;
|
||||||
|
import tanya.test.stub;
|
||||||
|
|
||||||
|
// const arrays return usable ranges
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto v = const Array!int([1, 2, 4]);
|
||||||
|
auto r1 = v[];
|
||||||
|
|
||||||
|
assert(r1.back == 4);
|
||||||
|
r1.popBack();
|
||||||
|
assert(r1.back == 2);
|
||||||
|
r1.popBack();
|
||||||
|
assert(r1.back == 1);
|
||||||
|
r1.popBack();
|
||||||
|
assert(r1.length == 0);
|
||||||
|
|
||||||
|
static assert(!is(typeof(r1[0] = 5)));
|
||||||
|
static assert(!is(typeof(v[0] = 5)));
|
||||||
|
|
||||||
|
const r2 = r1[];
|
||||||
|
static assert(is(typeof(r2[])));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
Array!int v1;
|
||||||
|
const Array!int v2;
|
||||||
|
|
||||||
|
auto r1 = v1[];
|
||||||
|
auto r2 = v1[];
|
||||||
|
|
||||||
|
assert(r1.length == 0);
|
||||||
|
assert(r2.empty);
|
||||||
|
assert(r1 == r2);
|
||||||
|
|
||||||
|
v1.insertBack([1, 2, 4]);
|
||||||
|
assert(v1[] == v1);
|
||||||
|
assert(v2[] == v2);
|
||||||
|
assert(v2[] != v1);
|
||||||
|
assert(v1[] != v2);
|
||||||
|
assert(v1[].equal(v1[]));
|
||||||
|
assert(v2[].equal(v2[]));
|
||||||
|
assert(!v1[].equal(v2[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
struct MutableEqualsStruct
|
||||||
|
{
|
||||||
|
bool opEquals(typeof(this) that) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct ConstEqualsStruct
|
||||||
|
{
|
||||||
|
bool opEquals(const typeof(this) that) const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto v1 = Array!ConstEqualsStruct();
|
||||||
|
auto v2 = Array!ConstEqualsStruct();
|
||||||
|
assert(v1 == v2);
|
||||||
|
assert(v1[] == v2);
|
||||||
|
assert(v1 == v2[]);
|
||||||
|
assert(v1[].equal(v2[]));
|
||||||
|
|
||||||
|
auto v3 = const Array!ConstEqualsStruct();
|
||||||
|
auto v4 = const Array!ConstEqualsStruct();
|
||||||
|
assert(v3 == v4);
|
||||||
|
assert(v3[] == v4);
|
||||||
|
assert(v3 == v4[]);
|
||||||
|
assert(v3[].equal(v4[]));
|
||||||
|
|
||||||
|
auto v7 = Array!MutableEqualsStruct(1, MutableEqualsStruct());
|
||||||
|
auto v8 = Array!MutableEqualsStruct(1, MutableEqualsStruct());
|
||||||
|
assert(v7 == v8);
|
||||||
|
assert(v7[] == v8);
|
||||||
|
assert(v7 == v8[]);
|
||||||
|
assert(v7[].equal(v8[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor can destroy empty arrays
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto v = Array!WithDtor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
class A
|
||||||
|
{
|
||||||
|
}
|
||||||
|
A a1, a2;
|
||||||
|
auto v1 = Array!A([a1, a2]);
|
||||||
|
|
||||||
|
static assert(is(Array!(A*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto v = Array!int([5, 15, 8]);
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
foreach (e; v)
|
||||||
|
{
|
||||||
|
assert(i != 0 || e == 5);
|
||||||
|
assert(i != 1 || e == 15);
|
||||||
|
assert(i != 2 || e == 8);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
assert(i == 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
size_t i = 3;
|
||||||
|
|
||||||
|
foreach_reverse (e; v)
|
||||||
|
{
|
||||||
|
--i;
|
||||||
|
assert(i != 2 || e == 8);
|
||||||
|
assert(i != 1 || e == 15);
|
||||||
|
assert(i != 0 || e == 5);
|
||||||
|
}
|
||||||
|
assert(i == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const constructor tests
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto v1 = const Array!int([1, 2, 3]);
|
||||||
|
auto v2 = Array!int(v1);
|
||||||
|
assert(v1.get !is v2.get);
|
||||||
|
assert(v1 == v2);
|
||||||
|
|
||||||
|
auto v3 = const Array!int(Array!int([1, 2, 3]));
|
||||||
|
assert(v1 == v3);
|
||||||
|
assert(v3.length == 3);
|
||||||
|
assert(v3.capacity == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto v1 = Array!int(defaultAllocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
Array!int v;
|
||||||
|
auto r = v[];
|
||||||
|
assert(r.length == 0);
|
||||||
|
assert(r.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto v1 = const Array!int([5, 15, 8]);
|
||||||
|
Array!int v2;
|
||||||
|
v2 = v1[0 .. 2];
|
||||||
|
assert(equal(v1[0 .. 2], v2[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move assignment
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
Array!int v1;
|
||||||
|
v1 = Array!int([5, 15, 8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Postblit is safe
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto array = Array!int(3);
|
||||||
|
void func(Array!int arg)
|
||||||
|
{
|
||||||
|
assert(arg.capacity == 3);
|
||||||
|
}
|
||||||
|
func(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can have non-copyable elements
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(Array!NonCopyable));
|
||||||
|
static assert(is(typeof({ Array!NonCopyable.init[0] = NonCopyable(); })));
|
||||||
|
}
|
17
tests/tanya/container/tests/buffer.d
Normal file
17
tests/tanya/container/tests/buffer.d
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.container.tests.buffer;
|
||||||
|
|
||||||
|
import tanya.container.buffer;
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(ReadBuffer!int));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(typeof(WriteBuffer!int(5))));
|
||||||
|
}
|
||||||
|
|
17
tests/tanya/container/tests/entry.d
Normal file
17
tests/tanya/container/tests/entry.d
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.container.tests.entry;
|
||||||
|
|
||||||
|
import tanya.container.entry;
|
||||||
|
import tanya.test.stub;
|
||||||
|
|
||||||
|
// Can be constructed with non-copyable key/values
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(Bucket!NonCopyable));
|
||||||
|
static assert(is(Bucket!(NonCopyable, NonCopyable)));
|
||||||
|
|
||||||
|
static assert(is(HashArray!((ref NonCopyable) => 0U, NonCopyable)));
|
||||||
|
static assert(is(HashArray!((ref NonCopyable) => 0U, NonCopyable, NonCopyable)));
|
||||||
|
}
|
133
tests/tanya/container/tests/hashtable.d
Normal file
133
tests/tanya/container/tests/hashtable.d
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.container.tests.hashtable;
|
||||||
|
|
||||||
|
import tanya.container.hashtable;
|
||||||
|
import tanya.test.stub;
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
import tanya.range.primitive : isForwardRange;
|
||||||
|
static assert(is(HashTable!(string, int) a));
|
||||||
|
static assert(is(const HashTable!(string, int)));
|
||||||
|
static assert(isForwardRange!(HashTable!(string, int).Range));
|
||||||
|
|
||||||
|
static assert(is(HashTable!(int, int, (ref const int) => size_t.init)));
|
||||||
|
static assert(is(HashTable!(int, int, (int) => size_t.init)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs by reference
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto hashTable1 = HashTable!(string, int)(7);
|
||||||
|
auto hashTable2 = HashTable!(string, int)(hashTable1);
|
||||||
|
assert(hashTable1.length == hashTable2.length);
|
||||||
|
assert(hashTable1.capacity == hashTable2.capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs by value
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto hashTable = HashTable!(string, int)(HashTable!(string, int)(7));
|
||||||
|
assert(hashTable.capacity == 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assigns by reference
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto hashTable1 = HashTable!(string, int)(7);
|
||||||
|
HashTable!(string, int) hashTable2;
|
||||||
|
hashTable1 = hashTable2;
|
||||||
|
assert(hashTable1.length == hashTable2.length);
|
||||||
|
assert(hashTable1.capacity == hashTable2.capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assigns by value
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
HashTable!(string, int) hashTable;
|
||||||
|
hashTable = HashTable!(string, int)(7);
|
||||||
|
assert(hashTable.capacity == 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Postblit copies
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto hashTable = HashTable!(string, int)(7);
|
||||||
|
void testFunc(HashTable!(string, int) hashTable)
|
||||||
|
{
|
||||||
|
assert(hashTable.capacity == 7);
|
||||||
|
}
|
||||||
|
testFunc(hashTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue 53: https://github.com/caraus-ecms/tanya/issues/53
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
{
|
||||||
|
HashTable!(uint, uint) hashTable;
|
||||||
|
foreach (uint i; 0 .. 14)
|
||||||
|
{
|
||||||
|
hashTable[i + 1] = i;
|
||||||
|
}
|
||||||
|
assert(hashTable.length == 14);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
HashTable!(int, int) hashtable;
|
||||||
|
|
||||||
|
hashtable[1194250162] = 3;
|
||||||
|
hashtable[-1131293824] = 6;
|
||||||
|
hashtable[838100082] = 9;
|
||||||
|
|
||||||
|
hashtable.rehash(11);
|
||||||
|
|
||||||
|
assert(hashtable[-1131293824] == 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static struct String
|
||||||
|
{
|
||||||
|
bool opEquals(string) const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opEquals(ref const string) const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opEquals(String) const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opEquals(ref const String) const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t toHash() const @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(is(typeof("asdf" in HashTable!(String, int)())));
|
||||||
|
static assert(is(typeof(HashTable!(String, int)()["asdf"])));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can have non-copyable keys and elements
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
@NonCopyable @Hashable
|
||||||
|
static struct S
|
||||||
|
{
|
||||||
|
mixin StructStub;
|
||||||
|
}
|
||||||
|
static assert(is(HashTable!(S, int)));
|
||||||
|
static assert(is(HashTable!(int, S)));
|
||||||
|
static assert(is(HashTable!(S, S)));
|
||||||
|
}
|
120
tests/tanya/container/tests/list.d
Normal file
120
tests/tanya/container/tests/list.d
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.container.tests.list;
|
||||||
|
|
||||||
|
import tanya.container.list;
|
||||||
|
import tanya.test.stub;
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
interface Stuff
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static assert(is(SList!Stuff));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto l = SList!int(0, 0);
|
||||||
|
assert(l.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// foreach called using opIndex().
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
SList!int l;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
l.insertFront(5);
|
||||||
|
l.insertFront(4);
|
||||||
|
l.insertFront(9);
|
||||||
|
foreach (e; l)
|
||||||
|
{
|
||||||
|
assert(i != 0 || e == 9);
|
||||||
|
assert(i != 1 || e == 4);
|
||||||
|
assert(i != 2 || e == 5);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto l1 = SList!int();
|
||||||
|
auto l2 = SList!int([9, 4]);
|
||||||
|
l1 = l2[];
|
||||||
|
assert(l1 == l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
class A
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static assert(is(SList!(A*)));
|
||||||
|
static assert(is(DList!(A*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes all elements
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto l = DList!int([5]);
|
||||||
|
assert(l.remove(l[]).empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto l1 = DList!int([5, 234, 30, 1]);
|
||||||
|
auto l2 = DList!int([5, 1]);
|
||||||
|
auto r = l1[];
|
||||||
|
|
||||||
|
r.popFront();
|
||||||
|
r.popBack();
|
||||||
|
assert(r.front == 234);
|
||||||
|
assert(r.back == 30);
|
||||||
|
|
||||||
|
assert(!l1.remove(r).empty);
|
||||||
|
assert(l1 == l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto l = DList!int(0, 0);
|
||||||
|
assert(l.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
DList!int l;
|
||||||
|
l.insertAfter(l[], 234);
|
||||||
|
assert(l.front == 234);
|
||||||
|
assert(l.back == 234);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto l1 = DList!int();
|
||||||
|
auto l2 = DList!int([9, 4]);
|
||||||
|
l1 = l2[];
|
||||||
|
assert(l1 == l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the new head
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto l1 = DList!int([5, 234, 30, 1]);
|
||||||
|
auto l2 = DList!int([1]);
|
||||||
|
auto r = l1[];
|
||||||
|
|
||||||
|
r.popBack();
|
||||||
|
|
||||||
|
assert(!l1.remove(r).empty);
|
||||||
|
assert(l1 == l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can have non-copyable elements
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(SList!NonCopyable));
|
||||||
|
static assert(is(DList!NonCopyable));
|
||||||
|
}
|
155
tests/tanya/container/tests/set.d
Normal file
155
tests/tanya/container/tests/set.d
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.container.tests.set;
|
||||||
|
|
||||||
|
import tanya.container.set;
|
||||||
|
import tanya.memory;
|
||||||
|
import tanya.test.stub;
|
||||||
|
|
||||||
|
// Basic insertion logic.
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
Set!int set;
|
||||||
|
|
||||||
|
assert(set.insert(5) == 1);
|
||||||
|
assert(5 in set);
|
||||||
|
assert(set.capacity == 3);
|
||||||
|
|
||||||
|
assert(set.insert(5) == 0);
|
||||||
|
assert(5 in set);
|
||||||
|
assert(set.capacity == 3);
|
||||||
|
|
||||||
|
assert(set.insert(9) == 1);
|
||||||
|
assert(9 in set);
|
||||||
|
assert(5 in set);
|
||||||
|
assert(set.capacity == 3);
|
||||||
|
|
||||||
|
assert(set.insert(7) == 1);
|
||||||
|
assert(set.insert(8) == 1);
|
||||||
|
assert(8 in set);
|
||||||
|
assert(5 in set);
|
||||||
|
assert(9 in set);
|
||||||
|
assert(7 in set);
|
||||||
|
assert(set.capacity == 7);
|
||||||
|
|
||||||
|
assert(set.insert(16) == 1);
|
||||||
|
assert(16 in set);
|
||||||
|
assert(set.capacity == 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static checks.
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
import tanya.range.primitive;
|
||||||
|
|
||||||
|
static assert(isBidirectionalRange!(Set!int.ConstRange));
|
||||||
|
static assert(isBidirectionalRange!(Set!int.Range));
|
||||||
|
|
||||||
|
static assert(!isInfinite!(Set!int.Range));
|
||||||
|
static assert(!hasLength!(Set!int.Range));
|
||||||
|
|
||||||
|
static assert(is(Set!uint));
|
||||||
|
static assert(is(Set!long));
|
||||||
|
static assert(is(Set!ulong));
|
||||||
|
static assert(is(Set!short));
|
||||||
|
static assert(is(Set!ushort));
|
||||||
|
static assert(is(Set!bool));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
const Set!int set;
|
||||||
|
assert(set[].empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
Set!int set;
|
||||||
|
set.insert(8);
|
||||||
|
|
||||||
|
auto r1 = set[];
|
||||||
|
auto r2 = r1.save();
|
||||||
|
|
||||||
|
r1.popFront();
|
||||||
|
assert(r1.empty);
|
||||||
|
|
||||||
|
r2.popBack();
|
||||||
|
assert(r2.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial capacity is 0.
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto set = Set!int(defaultAllocator);
|
||||||
|
assert(set.capacity == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capacity is set to a prime.
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto set = Set!int(8);
|
||||||
|
assert(set.capacity == 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs by reference
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto set1 = Set!int(7);
|
||||||
|
auto set2 = Set!int(set1);
|
||||||
|
assert(set1.length == set2.length);
|
||||||
|
assert(set1.capacity == set2.capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs by value
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto set = Set!int(Set!int(7));
|
||||||
|
assert(set.capacity == 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assigns by reference
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto set1 = Set!int(7);
|
||||||
|
Set!int set2;
|
||||||
|
set1 = set2;
|
||||||
|
assert(set1.length == set2.length);
|
||||||
|
assert(set1.capacity == set2.capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assigns by value
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
Set!int set;
|
||||||
|
set = Set!int(7);
|
||||||
|
assert(set.capacity == 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Postblit copies
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto set = Set!int(7);
|
||||||
|
void testFunc(Set!int set)
|
||||||
|
{
|
||||||
|
assert(set.capacity == 7);
|
||||||
|
}
|
||||||
|
testFunc(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hasher can take argument by ref
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(Set!(int, (const ref x) => cast(size_t) x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can have non-copyable elements
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
@NonCopyable @Hashable
|
||||||
|
static struct S
|
||||||
|
{
|
||||||
|
mixin StructStub;
|
||||||
|
}
|
||||||
|
static assert(is(Set!S));
|
||||||
|
}
|
121
tests/tanya/container/tests/string.d
Normal file
121
tests/tanya/container/tests/string.d
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/* 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/. */
|
||||||
|
module tanya.container.tests.string;
|
||||||
|
|
||||||
|
import tanya.container.string;
|
||||||
|
import tanya.test.assertion;
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto s = String(0, 'K');
|
||||||
|
assert(s.length == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates enough space for 3-byte character.
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
String s;
|
||||||
|
s.insertBack('\u8100');
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
assertThrown!UTFException(() => String(1, cast(dchar) 0xd900));
|
||||||
|
assertThrown!UTFException(() => String(1, cast(wchar) 0xd900));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto s1 = String("Buttercup");
|
||||||
|
auto s2 = String("Cap");
|
||||||
|
s2[] = s1[6 .. $];
|
||||||
|
assert(s2 == "cup");
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto s1 = String("Wow");
|
||||||
|
s1[] = 'a';
|
||||||
|
assert(s1 == "aaa");
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto s1 = String("ö");
|
||||||
|
s1[] = "oe";
|
||||||
|
assert(s1 == "oe");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Postblit works
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
void internFunc(String arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void middleFunc(S...)(S args)
|
||||||
|
{
|
||||||
|
foreach (arg; args)
|
||||||
|
{
|
||||||
|
internFunc(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void topFunc(String args)
|
||||||
|
{
|
||||||
|
middleFunc(args);
|
||||||
|
}
|
||||||
|
topFunc(String("asdf"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Const range produces mutable ranges
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
auto s = const String("И снизу лед, и сверху - маюсь между.");
|
||||||
|
{
|
||||||
|
const constRange = s[];
|
||||||
|
|
||||||
|
auto fromConstRange = constRange[];
|
||||||
|
fromConstRange.popFront();
|
||||||
|
assert(fromConstRange.front == s[1]);
|
||||||
|
|
||||||
|
fromConstRange = constRange[0 .. $];
|
||||||
|
fromConstRange.popFront();
|
||||||
|
assert(fromConstRange.front == s[1]);
|
||||||
|
|
||||||
|
assert(constRange.get() is s.get());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const constRange = s.byCodePoint();
|
||||||
|
|
||||||
|
auto fromConstRange = constRange[];
|
||||||
|
fromConstRange.popFront();
|
||||||
|
assert(fromConstRange.front == ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can pop multibyte characters
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
auto s = String("\U00024B62\U00002260");
|
||||||
|
auto range = s.byCodePoint();
|
||||||
|
|
||||||
|
range.popFront();
|
||||||
|
assert(!range.empty);
|
||||||
|
|
||||||
|
range.popFront();
|
||||||
|
assert(range.empty);
|
||||||
|
|
||||||
|
range = s.byCodePoint();
|
||||||
|
range.popFront();
|
||||||
|
s[$ - 3] = 0xf0;
|
||||||
|
assertThrown!UTFException(&(range.popFront));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inserts own char range correctly
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto s1 = String(`ü`);
|
||||||
|
String s2;
|
||||||
|
s2.insertBack(s1[]);
|
||||||
|
assert(s1 == s2);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user