algorithm: import searching publically
This commit is contained in:
parent
20c7e47ff7
commit
0fe7308a22
@ -9,7 +9,6 @@ language: d
|
||||
d:
|
||||
- dmd-2.085.0
|
||||
- dmd-2.084.1
|
||||
- dmd-2.083.1
|
||||
- dmd-2.082.1
|
||||
|
||||
env:
|
||||
|
@ -15,12 +15,6 @@ environment:
|
||||
- DC: dmd
|
||||
DVersion: 2.084.1
|
||||
arch: x86
|
||||
- DC: dmd
|
||||
DVersion: 2.083.1
|
||||
arch: x64
|
||||
- DC: dmd
|
||||
DVersion: 2.083.1
|
||||
arch: x86
|
||||
- DC: dmd
|
||||
DVersion: 2.082.1
|
||||
arch: x64
|
||||
|
@ -5,7 +5,7 @@
|
||||
/**
|
||||
* Algorithms for comparing values.
|
||||
*
|
||||
* Copyright: Eugene Wissner 2018.
|
||||
* Copyright: Eugene Wissner 2018-2019.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
@ -99,22 +99,6 @@ if (Args.length >= 2
|
||||
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
|
||||
Range min(Range)(Range range)
|
||||
if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
||||
@ -150,11 +134,6 @@ if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
||||
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.
|
||||
*
|
||||
@ -192,22 +171,6 @@ if (Args.length >= 2
|
||||
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
|
||||
Range max(Range)(Range range)
|
||||
if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
||||
@ -243,35 +206,6 @@ if (isForwardRange!Range && isOrderingComparable!(ElementType!Range))
|
||||
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.
|
||||
*
|
||||
@ -438,26 +372,3 @@ private int compareImpl(alias pred, R1, R2)(ref R1 r1, ref R2 r2)
|
||||
}
|
||||
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
|
||||
* original range on demand.
|
||||
*
|
||||
* Copyright: Eugene Wissner 2018.
|
||||
* Copyright: Eugene Wissner 2018-2019.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
@ -26,7 +26,6 @@ import tanya.meta.trait;
|
||||
import tanya.meta.transform;
|
||||
import tanya.range;
|
||||
import tanya.typecons;
|
||||
version (unittest) import tanya.test.stub;
|
||||
|
||||
private struct Take(R, bool exactly)
|
||||
{
|
||||
@ -49,21 +48,13 @@ private struct Take(R, bool exactly)
|
||||
}
|
||||
|
||||
@property auto ref front()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return this.source.front;
|
||||
}
|
||||
|
||||
void popFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
this.source.popFront();
|
||||
--this.length_;
|
||||
@ -92,21 +83,13 @@ private struct Take(R, bool exactly)
|
||||
static if (hasAssignableElements!R)
|
||||
{
|
||||
@property void front(ref ElementType!R value)
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
this.source.front = value;
|
||||
}
|
||||
|
||||
@property void front(ElementType!R value)
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
this.source.front = move(value);
|
||||
}
|
||||
@ -122,31 +105,19 @@ private struct Take(R, bool exactly)
|
||||
static if (isRandomAccessRange!R)
|
||||
{
|
||||
@property auto ref back()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return this.source[this.length - 1];
|
||||
}
|
||||
|
||||
void popBack()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
--this.length_;
|
||||
}
|
||||
|
||||
auto ref opIndex(size_t i)
|
||||
in
|
||||
{
|
||||
assert(i < length);
|
||||
}
|
||||
do
|
||||
in (i < length)
|
||||
{
|
||||
return this.source[i];
|
||||
}
|
||||
@ -154,41 +125,25 @@ private struct Take(R, bool exactly)
|
||||
static if (hasAssignableElements!R)
|
||||
{
|
||||
@property void back(ref ElementType!R value)
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
this.source[length - 1] = value;
|
||||
}
|
||||
|
||||
@property void back(ElementType!R value)
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
this.source[length - 1] = move(value);
|
||||
}
|
||||
|
||||
void opIndexAssign(ref ElementType!R value, size_t i)
|
||||
in
|
||||
{
|
||||
assert(i < length);
|
||||
}
|
||||
do
|
||||
in (i < length)
|
||||
{
|
||||
this.source[i] = value;
|
||||
}
|
||||
|
||||
void opIndexAssign(ElementType!R value, size_t i)
|
||||
in
|
||||
{
|
||||
assert(i < length);
|
||||
}
|
||||
do
|
||||
in (i < length)
|
||||
{
|
||||
this.source[i] = move(value);
|
||||
}
|
||||
@ -198,12 +153,8 @@ private struct Take(R, bool exactly)
|
||||
static if (!exactly && hasSlicing!R)
|
||||
{
|
||||
auto opSlice(size_t i, size_t j)
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
return typeof(this)(this.source[i .. j], length);
|
||||
}
|
||||
@ -322,18 +273,6 @@ if (isInputRange!R)
|
||||
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).
|
||||
*
|
||||
@ -428,32 +367,6 @@ if (isInputRange!R)
|
||||
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`.
|
||||
private struct Retro(Range)
|
||||
{
|
||||
@ -522,12 +435,8 @@ private struct Retro(Range)
|
||||
alias opDollar = length;
|
||||
|
||||
auto opSlice(size_t i, size_t j)
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
return typeof(this)(this.source[$-j .. $-i]);
|
||||
}
|
||||
@ -615,41 +524,6 @@ if (isBidirectionalRange!Range)
|
||||
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 Option!E element;
|
||||
@ -807,49 +681,3 @@ auto singleton(E)(return ref E element)
|
||||
singleChar.popFront();
|
||||
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.transform;
|
||||
import tanya.range;
|
||||
version (unittest) import tanya.test.stub;
|
||||
|
||||
deprecated("Use tanya.memory.lifetime.swap instead")
|
||||
alias swap = tanya.memory.lifetime.swap;
|
||||
@ -96,49 +95,6 @@ do
|
||||
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).
|
||||
*
|
||||
@ -176,42 +132,6 @@ if (isInputRange!Range && isAssignable!(ElementType!Range, Value))
|
||||
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
|
||||
* $(D_PARAM range) aren't initialized.
|
||||
@ -294,12 +214,6 @@ if (isInputRange!Range && hasLvalueElements!Range)
|
||||
assert(equal(actual[], expected[]));
|
||||
}
|
||||
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
NonCopyable[] nonCopyable;
|
||||
initializeAll(nonCopyable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys all elements in the $(D_PARAM range).
|
||||
*
|
||||
@ -390,38 +304,3 @@ if (isForwardRange!Range && hasSwappableElements!Range)
|
||||
rotate(actual[0 .. 2], actual[4 .. 6]);
|
||||
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.
|
||||
*
|
||||
* Copyright: Eugene Wissner 2017-2018.
|
||||
* Copyright: Eugene Wissner 2017-2019.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
@ -17,3 +17,4 @@ module tanya.algorithm;
|
||||
public import tanya.algorithm.comparison;
|
||||
public import tanya.algorithm.iteration;
|
||||
public import tanya.algorithm.mutation;
|
||||
public import tanya.algorithm.searching;
|
||||
|
@ -5,7 +5,7 @@
|
||||
/**
|
||||
* Searching algorithms.
|
||||
*
|
||||
* Copyright: Eugene Wissner 2018.
|
||||
* Copyright: Eugene Wissner 2018-2019.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
@ -51,28 +51,3 @@ if (isInputRange!R)
|
||||
int[3] array;
|
||||
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 (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.
|
||||
@ -160,7 +136,7 @@ alias EventMask = BitFlags!Event;
|
||||
*/
|
||||
abstract class Loop
|
||||
{
|
||||
private bool done = true;
|
||||
protected bool done = true;
|
||||
|
||||
/// Pending watchers.
|
||||
protected DList!Watcher pendings;
|
||||
@ -175,14 +151,6 @@ abstract class Loop
|
||||
return 128U;
|
||||
}
|
||||
|
||||
@nogc @system unittest
|
||||
{
|
||||
auto loop = defaultAllocator.make!TestLoop;
|
||||
assert(loop.maxEvents == 64);
|
||||
|
||||
defaultAllocator.dispose(loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the loop.
|
||||
*/
|
||||
@ -228,31 +196,6 @@ abstract class Loop
|
||||
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.
|
||||
*
|
||||
@ -329,17 +272,6 @@ abstract class Loop
|
||||
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.
|
||||
*/
|
||||
@ -418,16 +350,3 @@ do
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
version (unittest)
|
||||
{
|
||||
final class DummyWatcher : Watcher
|
||||
{
|
||||
bool invoked;
|
||||
|
||||
override void invoke() @nogc
|
||||
{
|
||||
this.invoked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Socket watcher.
|
||||
*/
|
||||
|
@ -21,7 +21,6 @@ import tanya.memory;
|
||||
import tanya.meta.trait;
|
||||
import tanya.meta.transform;
|
||||
import tanya.range;
|
||||
version (unittest) import tanya.test.stub;
|
||||
|
||||
/**
|
||||
* Random-access range for the $(D_PSYMBOL Array).
|
||||
@ -35,22 +34,15 @@ struct Range(A)
|
||||
private E* begin, end;
|
||||
private A* container;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.begin <= this.end);
|
||||
assert(this.container !is null);
|
||||
assert(this.begin >= this.container.data);
|
||||
assert(this.end <= this.container.data + this.container.length);
|
||||
}
|
||||
invariant (this.begin <= this.end);
|
||||
invariant (this.container !is null);
|
||||
invariant (this.begin >= this.container.data);
|
||||
invariant (this.end <= this.container.data + this.container.length);
|
||||
|
||||
private this(ref A container, E* begin, E* end) @trusted
|
||||
in
|
||||
{
|
||||
assert(begin <= end);
|
||||
assert(begin >= container.data);
|
||||
assert(end <= container.data + container.length);
|
||||
}
|
||||
do
|
||||
in (begin <= end)
|
||||
in (begin >= container.data)
|
||||
in (end <= container.data + container.length)
|
||||
{
|
||||
this.container = &container;
|
||||
this.begin = begin;
|
||||
@ -77,51 +69,31 @@ struct Range(A)
|
||||
alias opDollar = length;
|
||||
|
||||
@property ref inout(E) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return *this.begin;
|
||||
}
|
||||
|
||||
@property ref inout(E) back() inout @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return *(this.end - 1);
|
||||
}
|
||||
|
||||
void popFront() @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
++this.begin;
|
||||
}
|
||||
|
||||
void popBack() @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
--this.end;
|
||||
}
|
||||
|
||||
ref inout(E) opIndex(size_t i) inout @trusted
|
||||
in
|
||||
{
|
||||
assert(i < length);
|
||||
}
|
||||
do
|
||||
in (i < length)
|
||||
{
|
||||
return *(this.begin + i);
|
||||
}
|
||||
@ -137,23 +109,15 @@ struct Range(A)
|
||||
}
|
||||
|
||||
Range opSlice(size_t i, size_t j) @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
||||
}
|
||||
|
||||
A.ConstRange opSlice(size_t i, size_t j) const @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
||||
}
|
||||
@ -182,11 +146,8 @@ struct Array(T)
|
||||
private T* data;
|
||||
private size_t capacity_;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.length_ <= this.capacity_);
|
||||
assert(this.capacity_ == 0 || this.data !is null);
|
||||
}
|
||||
invariant (this.length_ <= this.capacity_);
|
||||
invariant (this.capacity_ == 0 || this.data !is null);
|
||||
|
||||
/**
|
||||
* Creates a new $(D_PSYMBOL Array) with the elements from a static array.
|
||||
@ -312,11 +273,7 @@ struct Array(T)
|
||||
|
||||
/// ditto
|
||||
this(shared Allocator allocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
allocator_ = allocator;
|
||||
}
|
||||
@ -567,11 +524,7 @@ struct Array(T)
|
||||
* Precondition: $(D_INLINECODE !empty).
|
||||
*/
|
||||
void removeBack()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
length = length - 1;
|
||||
}
|
||||
@ -589,11 +542,7 @@ struct Array(T)
|
||||
* Returns: The number of elements removed
|
||||
*/
|
||||
size_t removeBack(size_t howMany)
|
||||
out (removed)
|
||||
{
|
||||
assert(removed <= howMany);
|
||||
}
|
||||
do
|
||||
out (removed; removed <= howMany)
|
||||
{
|
||||
const toRemove = min(howMany, length);
|
||||
|
||||
@ -614,11 +563,7 @@ struct Array(T)
|
||||
}
|
||||
|
||||
private inout(T)[] slice(size_t length) inout @trusted
|
||||
in
|
||||
{
|
||||
assert(length <= capacity);
|
||||
}
|
||||
do
|
||||
in (length <= capacity)
|
||||
{
|
||||
return this.data[0 .. length];
|
||||
}
|
||||
@ -640,13 +585,9 @@ struct Array(T)
|
||||
* Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this).
|
||||
*/
|
||||
Range remove(Range r)
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= end);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= end)
|
||||
{
|
||||
auto target = r.begin;
|
||||
auto source = r.end;
|
||||
@ -801,13 +742,9 @@ struct Array(T)
|
||||
if (!isInfinite!R
|
||||
&& isInputRange!R
|
||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= this.data + length);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= this.data + length)
|
||||
{
|
||||
const oldLength = length;
|
||||
const after = r.end - this.data;
|
||||
@ -819,13 +756,9 @@ struct Array(T)
|
||||
|
||||
/// ditto
|
||||
size_t insertAfter(size_t R)(Range r, T[R] el)
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= this.data + length);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= this.data + length)
|
||||
{
|
||||
return insertAfter!(T[])(r, el[]);
|
||||
}
|
||||
@ -833,13 +766,9 @@ struct Array(T)
|
||||
/// ditto
|
||||
size_t insertAfter(R)(Range r, auto ref R el)
|
||||
if (isImplicitlyConvertible!(R, T))
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= this.data + length);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= this.data + length)
|
||||
{
|
||||
const oldLen = length;
|
||||
const offset = r.end - this.data;
|
||||
@ -862,26 +791,18 @@ struct Array(T)
|
||||
if (!isInfinite!R
|
||||
&& isInputRange!R
|
||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= this.data + length);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= this.data + length)
|
||||
{
|
||||
return insertAfter(Range(this, this.data, r.begin), el);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
size_t insertBefore(size_t R)(Range r, T[R] el)
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= this.data + length);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= this.data + length)
|
||||
{
|
||||
return insertBefore!(T[])(r, el[]);
|
||||
}
|
||||
@ -889,13 +810,9 @@ struct Array(T)
|
||||
/// ditto
|
||||
size_t insertBefore(R)(Range r, auto ref R el)
|
||||
if (isImplicitlyConvertible!(R, T))
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= this.data + length);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= this.data + length)
|
||||
{
|
||||
const oldLen = length;
|
||||
const offset = r.begin - this.data;
|
||||
@ -1063,11 +980,7 @@ struct Array(T)
|
||||
* Precondition: $(D_INLINECODE length > pos).
|
||||
*/
|
||||
ref inout(T) opIndex(size_t pos) inout @trusted
|
||||
in
|
||||
{
|
||||
assert(length > pos);
|
||||
}
|
||||
do
|
||||
in (length > pos)
|
||||
{
|
||||
return *(this.data + pos);
|
||||
}
|
||||
@ -1168,11 +1081,7 @@ struct Array(T)
|
||||
* Precondition: $(D_INLINECODE !empty).
|
||||
*/
|
||||
@property ref inout(T) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return *this.data;
|
||||
}
|
||||
@ -1195,11 +1104,7 @@ struct Array(T)
|
||||
* Precondition: $(D_INLINECODE !empty).
|
||||
*/
|
||||
@property ref inout(T) back() inout @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return *(this.data + length - 1);
|
||||
}
|
||||
@ -1227,24 +1132,16 @@ struct Array(T)
|
||||
* Precondition: $(D_INLINECODE i <= j && j <= length).
|
||||
*/
|
||||
Range opSlice(size_t i, size_t j) @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
return typeof(return)(this, this.data + i, this.data + j);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
ConstRange opSlice(size_t i, size_t j) const @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
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)
|
||||
@trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
copy(value[], this.data[i .. j]);
|
||||
return opSlice(i, j);
|
||||
@ -1315,12 +1208,8 @@ struct Array(T)
|
||||
/// ditto
|
||||
Range opSliceAssign(R : T)(auto ref R value, size_t i, size_t j)
|
||||
@trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
fill(this.data[i .. j], value);
|
||||
return opSlice(i, j);
|
||||
@ -1328,13 +1217,9 @@ struct Array(T)
|
||||
|
||||
/// ditto
|
||||
Range opSliceAssign()(Range value, size_t i, size_t j) @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
assert(j - i == value.length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
in (j - i == value.length)
|
||||
{
|
||||
copy(value, this.data[i .. j]);
|
||||
return opSlice(i, j);
|
||||
@ -1491,198 +1376,3 @@ struct Array(T)
|
||||
assert(r.front == 7);
|
||||
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,
|
||||
int start = 0,
|
||||
int end = 10) @nogc pure nothrow
|
||||
in
|
||||
{
|
||||
assert(start < end);
|
||||
}
|
||||
do
|
||||
in (start < end)
|
||||
{
|
||||
auto numberRead = end - start;
|
||||
for (ubyte i; i < numberRead; ++i)
|
||||
@ -71,12 +67,9 @@ if (isScalarType!T)
|
||||
/// Size by which the buffer will grow.
|
||||
private size_t blockSize = 8192;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.length_ <= this.buffer_.length);
|
||||
assert(this.blockSize > 0);
|
||||
assert(this.minAvailable > 0);
|
||||
}
|
||||
invariant (this.length_ <= this.buffer_.length);
|
||||
invariant (this.blockSize > 0);
|
||||
invariant (this.minAvailable > 0);
|
||||
|
||||
/**
|
||||
* Creates a new read buffer.
|
||||
@ -101,11 +94,7 @@ if (isScalarType!T)
|
||||
|
||||
/// ditto
|
||||
this(shared Allocator allocator)
|
||||
in
|
||||
{
|
||||
assert(allocator_ is null);
|
||||
}
|
||||
do
|
||||
in (allocator_ is null)
|
||||
{
|
||||
allocator_ = allocator;
|
||||
}
|
||||
@ -188,7 +177,7 @@ if (isScalarType!T)
|
||||
* Returns: $(D_KEYWORD this).
|
||||
*/
|
||||
ref ReadBuffer opOpAssign(string op)(size_t length)
|
||||
if (op == "+")
|
||||
if (op == "+")
|
||||
{
|
||||
this.length_ += length;
|
||||
ring = start;
|
||||
@ -293,11 +282,6 @@ if (isScalarType!T)
|
||||
mixin DefaultAllocator;
|
||||
}
|
||||
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
static assert(is(ReadBuffer!int));
|
||||
}
|
||||
|
||||
/**
|
||||
* Circular, self-expanding buffer with overflow support. Can be used with
|
||||
* functions returning the number of the transferred bytes.
|
||||
@ -328,12 +312,9 @@ if (isScalarType!T)
|
||||
/// The position of the free area in the buffer.
|
||||
private size_t position;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.blockSize > 0);
|
||||
// Position can refer to an element outside the buffer if the buffer is full.
|
||||
assert(this.position <= this.buffer_.length);
|
||||
}
|
||||
invariant (this.blockSize > 0);
|
||||
// Position can refer to an element outside the buffer if the buffer is full.
|
||||
invariant (this.position <= this.buffer_.length);
|
||||
|
||||
/**
|
||||
* Params:
|
||||
@ -344,12 +325,8 @@ if (isScalarType!T)
|
||||
* Precondition: $(D_INLINECODE size > 0 && allocator !is null)
|
||||
*/
|
||||
this(size_t size, shared Allocator allocator = defaultAllocator) @trusted
|
||||
in
|
||||
{
|
||||
assert(size > 0);
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (size > 0)
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.blockSize = size;
|
||||
ring = size - 1;
|
||||
@ -435,7 +412,7 @@ if (isScalarType!T)
|
||||
* buffer = Buffer chunk got with $(D_PSYMBOL opIndex).
|
||||
*/
|
||||
ref WriteBuffer opOpAssign(string op)(const T[] buffer)
|
||||
if (op == "~")
|
||||
if (op == "~")
|
||||
{
|
||||
size_t end, start;
|
||||
|
||||
@ -509,12 +486,8 @@ if (isScalarType!T)
|
||||
* Returns: $(D_KEYWORD this).
|
||||
*/
|
||||
ref WriteBuffer opOpAssign(string op)(size_t length)
|
||||
if (op == "+")
|
||||
in
|
||||
{
|
||||
assert(length <= this.length);
|
||||
}
|
||||
do
|
||||
if (op == "+")
|
||||
in (length <= this.length)
|
||||
{
|
||||
auto afterRing = ring + 1;
|
||||
auto oldStart = start;
|
||||
@ -649,11 +622,6 @@ if (isScalarType!T)
|
||||
mixin DefaultAllocator;
|
||||
}
|
||||
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
static assert(is(typeof(WriteBuffer!int(5))));
|
||||
}
|
||||
|
||||
@nogc nothrow pure @system unittest
|
||||
{
|
||||
auto b = WriteBuffer!ubyte(4);
|
||||
|
@ -20,7 +20,6 @@ import tanya.memory.lifetime;
|
||||
import tanya.meta.trait;
|
||||
import tanya.meta.transform;
|
||||
import tanya.typecons;
|
||||
version (unittest) import tanya.test.stub;
|
||||
|
||||
package struct SEntry(T)
|
||||
{
|
||||
@ -129,22 +128,14 @@ package struct HashArray(alias hasher, K, V = void)
|
||||
size_t length;
|
||||
|
||||
this(shared Allocator allocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.array = Buckets(allocator);
|
||||
}
|
||||
|
||||
this(T)(ref T data, shared Allocator allocator)
|
||||
if (is(Unqual!T == HashArray))
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.array = Buckets(data.array, allocator);
|
||||
this.lengthIndex = data.lengthIndex;
|
||||
@ -153,11 +144,7 @@ package struct HashArray(alias hasher, K, V = void)
|
||||
|
||||
// Move constructor
|
||||
void move(ref HashArray data, shared Allocator allocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.array = Buckets(.move(data.array), allocator);
|
||||
this.lengthIndex = data.lengthIndex;
|
||||
@ -238,11 +225,7 @@ package struct HashArray(alias hasher, K, V = void)
|
||||
|
||||
// Takes an index in the primes array.
|
||||
void rehashToSize(const size_t n)
|
||||
in
|
||||
{
|
||||
assert(n < primes.length);
|
||||
}
|
||||
do
|
||||
in (n < primes.length)
|
||||
{
|
||||
auto storage = typeof(this.array)(primes[n], this.array.allocator);
|
||||
DataLoop: foreach (ref e1; this.array[])
|
||||
@ -327,13 +310,3 @@ package struct HashArray(alias hasher, K, V = void)
|
||||
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.transform;
|
||||
import tanya.range.primitive;
|
||||
version (unittest) import tanya.test.stub;
|
||||
|
||||
/**
|
||||
* Bidirectional range whose element type is a tuple of a key and the
|
||||
@ -70,16 +69,9 @@ struct Range(T)
|
||||
}
|
||||
|
||||
void popFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.front.status == BucketStatus.used);
|
||||
}
|
||||
out
|
||||
{
|
||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.front.status == BucketStatus.used)
|
||||
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
do
|
||||
{
|
||||
@ -89,16 +81,9 @@ struct Range(T)
|
||||
}
|
||||
|
||||
void popBack()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
out
|
||||
{
|
||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.back.status == BucketStatus.used)
|
||||
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
do
|
||||
{
|
||||
@ -108,23 +93,15 @@ struct Range(T)
|
||||
}
|
||||
|
||||
@property ref inout(KV) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.front.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.front.status == BucketStatus.used)
|
||||
{
|
||||
return this.dataRange.front.kv;
|
||||
}
|
||||
|
||||
@property ref inout(KV) back() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
return this.dataRange.back.kv;
|
||||
}
|
||||
@ -185,16 +162,9 @@ struct ByKey(T)
|
||||
}
|
||||
|
||||
@property void popFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.front.status == BucketStatus.used);
|
||||
}
|
||||
out
|
||||
{
|
||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.front.status == BucketStatus.used)
|
||||
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
do
|
||||
{
|
||||
@ -204,16 +174,9 @@ struct ByKey(T)
|
||||
}
|
||||
|
||||
@property void popBack()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
out
|
||||
{
|
||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.back.status == BucketStatus.used)
|
||||
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
do
|
||||
{
|
||||
@ -223,23 +186,15 @@ struct ByKey(T)
|
||||
}
|
||||
|
||||
@property ref inout(Key) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.front.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.front.status == BucketStatus.used)
|
||||
{
|
||||
return this.dataRange.front.key;
|
||||
}
|
||||
|
||||
@property ref inout(Key) back() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
return this.dataRange.back.key;
|
||||
}
|
||||
@ -300,16 +255,9 @@ struct ByValue(T)
|
||||
}
|
||||
|
||||
@property void popFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.front.status == BucketStatus.used);
|
||||
}
|
||||
out
|
||||
{
|
||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.front.status == BucketStatus.used)
|
||||
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
do
|
||||
{
|
||||
@ -319,16 +267,9 @@ struct ByValue(T)
|
||||
}
|
||||
|
||||
@property void popBack()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
out
|
||||
{
|
||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.back.status == BucketStatus.used)
|
||||
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
do
|
||||
{
|
||||
@ -338,23 +279,15 @@ struct ByValue(T)
|
||||
}
|
||||
|
||||
@property ref inout(Value) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.front.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.front.status == BucketStatus.used)
|
||||
{
|
||||
return this.dataRange.front.kv.value;
|
||||
}
|
||||
|
||||
@property ref inout(Value) back() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
return this.dataRange.back.kv.value;
|
||||
}
|
||||
@ -412,10 +345,7 @@ if (isHashFunction!(hasher, Key))
|
||||
/// ditto
|
||||
alias ConstByValue = .ByValue!(const HashArray);
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.data.lengthIndex < primes.length);
|
||||
}
|
||||
invariant (this.data.lengthIndex < primes.length);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -427,11 +357,7 @@ if (isHashFunction!(hasher, Key))
|
||||
* Precondition: $(D_INLINECODE allocator !is null).
|
||||
*/
|
||||
this(size_t n, shared Allocator allocator = defaultAllocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this(allocator);
|
||||
this.data.rehash(n);
|
||||
@ -446,11 +372,7 @@ if (isHashFunction!(hasher, Key))
|
||||
|
||||
/// ditto
|
||||
this(shared Allocator allocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.data = HashArray(allocator);
|
||||
}
|
||||
@ -470,11 +392,7 @@ if (isHashFunction!(hasher, Key))
|
||||
*/
|
||||
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
|
||||
if (is(Unqual!S == HashTable))
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.data = HashArray(init.data, allocator);
|
||||
}
|
||||
@ -482,11 +400,7 @@ if (isHashFunction!(hasher, Key))
|
||||
/// ditto
|
||||
this(S)(S init, shared Allocator allocator = defaultAllocator)
|
||||
if (is(S == HashTable))
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.data.move(init.data, allocator);
|
||||
}
|
||||
@ -503,11 +417,7 @@ if (isHashFunction!(hasher, Key))
|
||||
*/
|
||||
this(R)(R range, shared Allocator allocator = defaultAllocator)
|
||||
if (isForwardRange!R && is(ElementType!R == KeyValue))
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this(allocator);
|
||||
insert(range);
|
||||
@ -537,11 +447,7 @@ if (isHashFunction!(hasher, Key))
|
||||
*/
|
||||
this(size_t n)(KeyValue[n] array,
|
||||
shared Allocator allocator = defaultAllocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
insert(array[]);
|
||||
}
|
||||
@ -589,11 +495,7 @@ if (isHashFunction!(hasher, Key))
|
||||
* Postcondition: $(D_INLINECODE allocator !is null)
|
||||
*/
|
||||
@property shared(Allocator) allocator() const
|
||||
out (allocator)
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
out (allocator; allocator !is null)
|
||||
{
|
||||
return this.data.array.allocator;
|
||||
}
|
||||
@ -1085,129 +987,3 @@ if (isHashFunction!(hasher, Key))
|
||||
dinos.clear();
|
||||
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.range.array;
|
||||
import tanya.range.primitive;
|
||||
version (unittest) import tanya.test.stub;
|
||||
|
||||
/**
|
||||
* Forward range for the $(D_PSYMBOL SList).
|
||||
@ -37,10 +36,7 @@ struct SRange(L)
|
||||
|
||||
private EntryPointer* head;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.head !is null);
|
||||
}
|
||||
invariant (this.head !is null);
|
||||
|
||||
private this(ref EntryPointer head) @trusted
|
||||
{
|
||||
@ -60,21 +56,13 @@ struct SRange(L)
|
||||
}
|
||||
|
||||
@property ref inout(E) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return (*this.head).content;
|
||||
}
|
||||
|
||||
void popFront() @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
this.head = &(*this.head).next;
|
||||
}
|
||||
@ -206,11 +194,7 @@ struct SList(T)
|
||||
|
||||
/// ditto
|
||||
this(shared Allocator allocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.allocator_ = allocator;
|
||||
}
|
||||
@ -332,11 +316,7 @@ struct SList(T)
|
||||
* Precondition: $(D_INLINECODE !empty).
|
||||
*/
|
||||
@property ref inout(T) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return this.head.content;
|
||||
}
|
||||
@ -477,11 +457,7 @@ struct SList(T)
|
||||
*/
|
||||
size_t insertBefore(R)(Range r, R el)
|
||||
if (isImplicitlyConvertible!(R, T))
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
return moveEntry(*r.head, el);
|
||||
}
|
||||
@ -500,11 +476,7 @@ struct SList(T)
|
||||
if (!isInfinite!R
|
||||
&& isInputRange!R
|
||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
size_t inserted;
|
||||
foreach (e; el)
|
||||
@ -529,11 +501,7 @@ struct SList(T)
|
||||
|
||||
/// ditto
|
||||
size_t insertBefore()(Range r, ref T el) @trusted
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
*r.head = allocator.make!Entry(el, *r.head);
|
||||
return 1;
|
||||
@ -629,11 +597,7 @@ struct SList(T)
|
||||
* Precondition: $(D_INLINECODE !empty)
|
||||
*/
|
||||
void removeFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
auto n = this.head.next;
|
||||
|
||||
@ -668,11 +632,7 @@ struct SList(T)
|
||||
* Returns: The number of elements removed.
|
||||
*/
|
||||
size_t removeFront(size_t howMany)
|
||||
out (removed)
|
||||
{
|
||||
assert(removed <= howMany);
|
||||
}
|
||||
do
|
||||
out (removed; removed <= howMany)
|
||||
{
|
||||
size_t i;
|
||||
for (; i < howMany && !empty; ++i)
|
||||
@ -704,11 +664,7 @@ struct SList(T)
|
||||
* Precondition: $(D_PARAM r) is extracted from this list.
|
||||
*/
|
||||
Range remove(Range r)
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
auto outOfScopeList = typeof(this)(allocator);
|
||||
outOfScopeList.head = *r.head;
|
||||
@ -742,12 +698,8 @@ struct SList(T)
|
||||
* $(D_PARAM range) is extracted from this list.
|
||||
*/
|
||||
Range popFirstOf(Range range)
|
||||
in
|
||||
{
|
||||
assert(!range.empty);
|
||||
assert(checkRangeBelonging(range));
|
||||
}
|
||||
do
|
||||
in (!range.empty)
|
||||
in (checkRangeBelonging(range))
|
||||
{
|
||||
auto next = (*range.head).next;
|
||||
|
||||
@ -923,46 +875,6 @@ struct SList(T)
|
||||
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).
|
||||
*
|
||||
@ -977,11 +889,8 @@ struct DRange(L)
|
||||
private EntryPointer* head;
|
||||
private EntryPointer* tail;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.head !is null);
|
||||
assert(this.tail !is null);
|
||||
}
|
||||
invariant (this.head !is null);
|
||||
invariant (this.tail !is null);
|
||||
|
||||
private this(ref EntryPointer head, ref EntryPointer tail) @trusted
|
||||
{
|
||||
@ -1002,41 +911,25 @@ struct DRange(L)
|
||||
}
|
||||
|
||||
@property ref inout(E) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return (*this.head).content;
|
||||
}
|
||||
|
||||
@property ref inout(E) back() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return (*this.tail).content;
|
||||
}
|
||||
|
||||
void popFront() @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
this.head = &(*this.head).next;
|
||||
}
|
||||
|
||||
void popBack() @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
this.tail = &(*this.tail).prev;
|
||||
}
|
||||
@ -1082,13 +975,10 @@ struct DList(T)
|
||||
// 0th and the last elements of the list.
|
||||
private Entry* head, tail;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert((this.tail is null && this.head is null)
|
||||
invariant ((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);
|
||||
assert(this.head is null || this.head.prev is null);
|
||||
}
|
||||
invariant (this.tail is null || this.tail.next 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.
|
||||
@ -1192,11 +1082,7 @@ struct DList(T)
|
||||
|
||||
/// ditto
|
||||
this(shared Allocator allocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.allocator_ = allocator;
|
||||
}
|
||||
@ -1322,11 +1208,7 @@ struct DList(T)
|
||||
* Precondition: $(D_INLINECODE !empty).
|
||||
*/
|
||||
@property ref inout(T) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return this.head.content;
|
||||
}
|
||||
@ -1337,11 +1219,7 @@ struct DList(T)
|
||||
* Precondition: $(D_INLINECODE !empty).
|
||||
*/
|
||||
@property ref inout(T) back() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return this.tail.content;
|
||||
}
|
||||
@ -1656,11 +1534,7 @@ struct DList(T)
|
||||
*/
|
||||
size_t insertBefore(R)(Range r, R el)
|
||||
if (isImplicitlyConvertible!(R, T))
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
return moveFront(*r.head, el);
|
||||
}
|
||||
@ -1676,11 +1550,7 @@ struct DList(T)
|
||||
|
||||
/// ditto
|
||||
size_t insertBefore()(Range r, ref T el) @trusted
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
auto temp = allocator.make!Entry(el, *r.head);
|
||||
|
||||
@ -1714,11 +1584,7 @@ struct DList(T)
|
||||
if (!isInfinite!R
|
||||
&& isInputRange!R
|
||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
size_t inserted;
|
||||
foreach (e; el)
|
||||
@ -1771,11 +1637,7 @@ struct DList(T)
|
||||
*/
|
||||
size_t insertAfter(R)(Range r, R el) @trusted
|
||||
if (isImplicitlyConvertible!(R, T))
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
return moveBack(*r.tail, el);
|
||||
}
|
||||
@ -1793,11 +1655,7 @@ struct DList(T)
|
||||
|
||||
/// ditto
|
||||
size_t insertAfter()(Range r, ref T el) @trusted
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
auto temp = allocator.make!Entry(el, null, *r.tail);
|
||||
|
||||
@ -1831,11 +1689,7 @@ struct DList(T)
|
||||
if (!isInfinite!R
|
||||
&& isInputRange!R
|
||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
size_t inserted;
|
||||
foreach (e; el)
|
||||
@ -1926,11 +1780,7 @@ struct DList(T)
|
||||
* Precondition: $(D_INLINECODE !empty)
|
||||
*/
|
||||
void removeFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
auto n = this.head.next;
|
||||
|
||||
@ -1962,11 +1812,7 @@ struct DList(T)
|
||||
|
||||
/// ditto
|
||||
void removeBack()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
auto n = this.tail.prev;
|
||||
|
||||
@ -2008,11 +1854,7 @@ struct DList(T)
|
||||
* Returns: The number of elements removed.
|
||||
*/
|
||||
size_t removeFront(size_t howMany)
|
||||
out (removed)
|
||||
{
|
||||
assert(removed <= howMany);
|
||||
}
|
||||
do
|
||||
out (removed; removed <= howMany)
|
||||
{
|
||||
size_t i;
|
||||
for (; i < howMany && !empty; ++i)
|
||||
@ -2035,11 +1877,7 @@ struct DList(T)
|
||||
|
||||
/// ditto
|
||||
size_t removeBack(size_t howMany)
|
||||
out (removed)
|
||||
{
|
||||
assert(removed <= howMany);
|
||||
}
|
||||
do
|
||||
out (removed; removed <= howMany)
|
||||
{
|
||||
size_t i;
|
||||
for (; i < howMany && !empty; ++i)
|
||||
@ -2071,11 +1909,7 @@ struct DList(T)
|
||||
* Precondition: $(D_PARAM r) is extracted from this list.
|
||||
*/
|
||||
Range remove(Range r)
|
||||
in
|
||||
{
|
||||
assert(checkRangeBelonging(r));
|
||||
}
|
||||
do
|
||||
in (checkRangeBelonging(r))
|
||||
{
|
||||
// Save references to the elements before and after the range.
|
||||
Entry* headPrev;
|
||||
@ -2147,11 +1981,7 @@ struct DList(T)
|
||||
* $(D_PARAM range) is extracted from this list.
|
||||
*/
|
||||
Range popFirstOf(Range range)
|
||||
in
|
||||
{
|
||||
assert(!range.empty);
|
||||
}
|
||||
do
|
||||
in (!range.empty)
|
||||
{
|
||||
remove(Range(*range.head, *range.head));
|
||||
return range;
|
||||
@ -2159,11 +1989,7 @@ struct DList(T)
|
||||
|
||||
/// ditto
|
||||
Range popLastOf(Range range)
|
||||
in
|
||||
{
|
||||
assert(!range.empty);
|
||||
}
|
||||
do
|
||||
in (!range.empty)
|
||||
{
|
||||
remove(Range(*range.tail, *range.tail));
|
||||
return range;
|
||||
@ -2317,82 +2143,3 @@ struct DList(T)
|
||||
}
|
||||
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.transform;
|
||||
import tanya.range.primitive;
|
||||
version (unittest) import tanya.test.stub;
|
||||
|
||||
/**
|
||||
* Bidirectional range that iterates over the $(D_PSYMBOL Set)'s values.
|
||||
@ -69,16 +68,9 @@ struct Range(T)
|
||||
}
|
||||
|
||||
void popFront()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.front.status == BucketStatus.used);
|
||||
}
|
||||
out
|
||||
{
|
||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.front.status == BucketStatus.used)
|
||||
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
do
|
||||
{
|
||||
@ -88,16 +80,9 @@ struct Range(T)
|
||||
}
|
||||
|
||||
void popBack()
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
out
|
||||
{
|
||||
assert(empty || this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.back.status == BucketStatus.used)
|
||||
out (; empty || this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
do
|
||||
{
|
||||
@ -107,23 +92,15 @@ struct Range(T)
|
||||
}
|
||||
|
||||
@property ref inout(E) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.front.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.front.status == BucketStatus.used)
|
||||
{
|
||||
return this.dataRange.front.key;
|
||||
}
|
||||
|
||||
@property ref inout(E) back() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
assert(this.dataRange.back.status == BucketStatus.used);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
in (this.dataRange.back.status == BucketStatus.used)
|
||||
{
|
||||
return this.dataRange.back.key;
|
||||
}
|
||||
@ -168,12 +145,9 @@ if (isHashFunction!(hasher, T))
|
||||
/// ditto
|
||||
alias ConstRange = .Range!(const HashArray);
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.data.lengthIndex < primes.length);
|
||||
assert(this.data.array.length == 0
|
||||
invariant (this.data.lengthIndex < primes.length);
|
||||
invariant (this.data.array.length == 0
|
||||
|| this.data.array.length == primes[this.data.lengthIndex]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -185,11 +159,7 @@ if (isHashFunction!(hasher, T))
|
||||
* Precondition: $(D_INLINECODE allocator !is null).
|
||||
*/
|
||||
this(size_t n, shared Allocator allocator = defaultAllocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this(allocator);
|
||||
this.data.rehash(n);
|
||||
@ -204,11 +174,7 @@ if (isHashFunction!(hasher, T))
|
||||
|
||||
/// ditto
|
||||
this(shared Allocator allocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.data = HashArray(allocator);
|
||||
}
|
||||
@ -228,11 +194,7 @@ if (isHashFunction!(hasher, T))
|
||||
*/
|
||||
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
|
||||
if (is(Unqual!S == Set))
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.data = HashArray(init.data, allocator);
|
||||
}
|
||||
@ -240,11 +202,7 @@ if (isHashFunction!(hasher, T))
|
||||
/// ditto
|
||||
this(S)(S init, shared Allocator allocator = defaultAllocator)
|
||||
if (is(S == Set))
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
this.data.move(init.data, allocator);
|
||||
}
|
||||
@ -261,11 +219,7 @@ if (isHashFunction!(hasher, T))
|
||||
*/
|
||||
this(R)(R range, shared Allocator allocator = defaultAllocator)
|
||||
if (isForwardRange!R && isImplicitlyConvertible!(ElementType!R, T))
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
insert(range);
|
||||
}
|
||||
@ -291,11 +245,7 @@ if (isHashFunction!(hasher, T))
|
||||
* Precondition: $(D_INLINECODE allocator !is null).
|
||||
*/
|
||||
this(size_t n)(T[n] array, shared Allocator allocator = defaultAllocator)
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
insert(array[]);
|
||||
}
|
||||
@ -342,11 +292,7 @@ if (isHashFunction!(hasher, T))
|
||||
* Postcondition: $(D_INLINECODE allocator !is null)
|
||||
*/
|
||||
@property shared(Allocator) allocator() const
|
||||
out (allocator)
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
out (allocator; allocator !is null)
|
||||
{
|
||||
return this.data.array.allocator;
|
||||
}
|
||||
@ -638,150 +584,3 @@ if (isHashFunction!(hasher, T))
|
||||
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.primitive;
|
||||
|
||||
version (unittest)
|
||||
{
|
||||
import tanya.test.assertion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown on encoding errors.
|
||||
*/
|
||||
@ -74,22 +69,15 @@ if (is(Unqual!E == char))
|
||||
private alias ContainerType = CopyConstness!(E, String);
|
||||
private ContainerType* container;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.begin <= this.end);
|
||||
assert(this.container !is null);
|
||||
assert(this.begin >= this.container.data);
|
||||
assert(this.end <= this.container.data + this.container.length);
|
||||
}
|
||||
invariant (this.begin <= this.end);
|
||||
invariant (this.container !is null);
|
||||
invariant (this.begin >= this.container.data);
|
||||
invariant (this.end <= this.container.data + this.container.length);
|
||||
|
||||
private this(ref ContainerType container, E* begin, E* end) @trusted
|
||||
in
|
||||
{
|
||||
assert(begin <= end);
|
||||
assert(begin >= container.data);
|
||||
assert(end <= container.data + container.length);
|
||||
}
|
||||
do
|
||||
in (begin <= end)
|
||||
in (begin >= container.data)
|
||||
in (end <= container.data + container.length)
|
||||
{
|
||||
this.container = &container;
|
||||
this.begin = begin;
|
||||
@ -116,51 +104,31 @@ if (is(Unqual!E == char))
|
||||
alias opDollar = length;
|
||||
|
||||
@property ref inout(E) front() inout
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return *this.begin;
|
||||
}
|
||||
|
||||
@property ref inout(E) back() inout @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
return *(this.end - 1);
|
||||
}
|
||||
|
||||
void popFront() @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
++this.begin;
|
||||
}
|
||||
|
||||
void popBack() @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
--this.end;
|
||||
}
|
||||
|
||||
ref inout(E) opIndex(const size_t i) inout @trusted
|
||||
in
|
||||
{
|
||||
assert(i < length);
|
||||
}
|
||||
do
|
||||
in (i < length)
|
||||
{
|
||||
return *(this.begin + i);
|
||||
}
|
||||
@ -176,23 +144,15 @@ if (is(Unqual!E == char))
|
||||
}
|
||||
|
||||
ByCodeUnit opSlice(const size_t i, const size_t j) @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
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
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
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 ContainerType* container;
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(this.begin <= this.end);
|
||||
assert(this.container !is null);
|
||||
assert(this.begin >= this.container.data);
|
||||
assert(this.end <= this.container.data + this.container.length);
|
||||
}
|
||||
invariant (this.begin <= this.end);
|
||||
invariant (this.container !is null);
|
||||
invariant (this.begin >= this.container.data);
|
||||
invariant (this.end <= this.container.data + this.container.length);
|
||||
|
||||
private this(ref ContainerType container, E* begin, E* end) @trusted
|
||||
in
|
||||
{
|
||||
assert(begin <= end);
|
||||
assert(begin >= container.data);
|
||||
assert(end <= container.data + container.length);
|
||||
}
|
||||
do
|
||||
in (begin <= end)
|
||||
in (begin >= container.data)
|
||||
in (end <= container.data + container.length)
|
||||
{
|
||||
this.container = &container;
|
||||
this.begin = begin;
|
||||
@ -251,15 +204,8 @@ if (is(Unqual!E == char))
|
||||
}
|
||||
|
||||
@property dchar front() const @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
out (chr)
|
||||
{
|
||||
assert(chr < 0xd800 || chr > 0xdfff);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
out (chr; chr < 0xd800 || chr > 0xdfff)
|
||||
{
|
||||
dchar chr;
|
||||
ubyte units;
|
||||
@ -289,11 +235,7 @@ if (is(Unqual!E == char))
|
||||
}
|
||||
|
||||
void popFront() @trusted
|
||||
in
|
||||
{
|
||||
assert(!empty);
|
||||
}
|
||||
do
|
||||
in (!empty)
|
||||
{
|
||||
ubyte units;
|
||||
if ((*begin & 0xf0) == 0xf0)
|
||||
@ -339,10 +281,7 @@ struct String
|
||||
private char* data;
|
||||
private size_t capacity_;
|
||||
|
||||
pure nothrow @safe @nogc invariant
|
||||
{
|
||||
assert(this.length_ <= this.capacity_);
|
||||
}
|
||||
@nogc nothrow pure @safe invariant (this.length_ <= this.capacity_);
|
||||
|
||||
/**
|
||||
* Constructs the string from a stringish range.
|
||||
@ -432,11 +371,7 @@ struct String
|
||||
|
||||
/// ditto
|
||||
this(shared Allocator allocator) @nogc nothrow pure @safe
|
||||
in
|
||||
{
|
||||
assert(allocator !is null);
|
||||
}
|
||||
do
|
||||
in (allocator !is null)
|
||||
{
|
||||
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
|
||||
{
|
||||
auto buf = this.data[0 .. this.length_];
|
||||
@ -521,12 +450,8 @@ struct String
|
||||
|
||||
private void write4Bytes(ref const dchar src)
|
||||
@nogc nothrow pure @trusted
|
||||
in
|
||||
{
|
||||
assert(capacity - length >= 4);
|
||||
assert(src - 0x10000 < 0x100000);
|
||||
}
|
||||
do
|
||||
in (capacity - length >= 4)
|
||||
in (src - 0x10000 < 0x100000)
|
||||
{
|
||||
auto dst = this.data + length;
|
||||
|
||||
@ -540,11 +465,7 @@ struct String
|
||||
|
||||
private size_t insertWideChar(C)(auto ref const C chr) @trusted
|
||||
if (is(C == wchar) || is(C == dchar))
|
||||
in
|
||||
{
|
||||
assert(capacity - length >= 3);
|
||||
}
|
||||
do
|
||||
in (capacity - length >= 3)
|
||||
{
|
||||
auto dst = this.data + length;
|
||||
if (chr < 0x80)
|
||||
@ -602,13 +523,6 @@ struct String
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Allocates enough space for 3-byte character.
|
||||
@nogc pure @safe unittest
|
||||
{
|
||||
String s;
|
||||
s.insertBack('\u8100');
|
||||
}
|
||||
|
||||
/// ditto
|
||||
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.
|
||||
*
|
||||
@ -880,13 +788,9 @@ struct String
|
||||
const size_t i,
|
||||
const size_t j)
|
||||
if (is(Unqual!R == char))
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
assert(j - i == value.length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
in (j - i == value.length)
|
||||
{
|
||||
auto target = opSlice(i, j);
|
||||
copy(value, target);
|
||||
@ -898,12 +802,8 @@ struct String
|
||||
const size_t i,
|
||||
const size_t j)
|
||||
@nogc nothrow pure @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
copy(value[], this.data[i .. j]);
|
||||
return opSlice(i, j);
|
||||
@ -914,12 +814,8 @@ struct String
|
||||
const size_t i,
|
||||
const size_t j)
|
||||
@nogc nothrow pure @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
for (auto p = this.data + i; p < this.data + j; ++p)
|
||||
{
|
||||
@ -996,11 +892,7 @@ struct String
|
||||
* Precondition: $(D_INLINECODE length > pos).
|
||||
*/
|
||||
ref inout(char) opIndex(const size_t pos) inout @nogc nothrow pure @trusted
|
||||
in
|
||||
{
|
||||
assert(length > pos);
|
||||
}
|
||||
do
|
||||
in (length > pos)
|
||||
{
|
||||
return *(this.data + pos);
|
||||
}
|
||||
@ -1145,12 +1037,8 @@ struct String
|
||||
*/
|
||||
ByCodeUnit!char opSlice(const size_t i, const size_t j)
|
||||
@nogc nothrow pure @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
return typeof(return)(this, this.data + i, this.data + j);
|
||||
}
|
||||
@ -1158,12 +1046,8 @@ struct String
|
||||
/// ditto
|
||||
ByCodeUnit!(const char) opSlice(const size_t i, const size_t j)
|
||||
const @nogc nothrow pure @trusted
|
||||
in
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
in (i <= j)
|
||||
in (j <= length)
|
||||
{
|
||||
return typeof(return)(this, this.data + i, this.data + j);
|
||||
}
|
||||
@ -1418,40 +1302,18 @@ struct String
|
||||
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
|
||||
ByCodeUnit!char opIndexAssign(const char value) @nogc nothrow pure @safe
|
||||
{
|
||||
return opSliceAssign(value, 0, length);
|
||||
}
|
||||
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
auto s1 = String("Wow");
|
||||
s1[] = 'a';
|
||||
assert(s1 == "aaa");
|
||||
}
|
||||
|
||||
/// ditto
|
||||
ByCodeUnit!char opIndexAssign(const char[] value) @nogc nothrow pure @safe
|
||||
{
|
||||
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).
|
||||
*
|
||||
@ -1466,13 +1328,9 @@ struct String
|
||||
*/
|
||||
R remove(R)(R r) @trusted
|
||||
if (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char))
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= this.data + length);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= this.data + length)
|
||||
{
|
||||
auto end = this.data + this.length;
|
||||
copy(ByCodeUnit!char(this, r.end, end), ByCodeUnit!char(this, r.begin, end));
|
||||
@ -1521,13 +1379,9 @@ struct String
|
||||
&& isInputRange!T
|
||||
&& isSomeChar!(ElementType!T)))
|
||||
&& (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char)))
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= this.data + length);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= this.data + length)
|
||||
{
|
||||
const oldLength = length;
|
||||
const after = r.end - this.data;
|
||||
@ -1555,13 +1409,9 @@ struct String
|
||||
&& isInputRange!T
|
||||
&& isSomeChar!(ElementType!T)))
|
||||
&& (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char)))
|
||||
in
|
||||
{
|
||||
assert(r.container is &this);
|
||||
assert(r.begin >= this.data);
|
||||
assert(r.end <= this.data + length);
|
||||
}
|
||||
do
|
||||
in (r.container is &this)
|
||||
in (r.begin >= this.data)
|
||||
in (r.end <= this.data + length)
|
||||
{
|
||||
return insertAfter(R(this, this.data, r.begin), el);
|
||||
}
|
||||
@ -1590,76 +1440,3 @@ struct String
|
||||
|
||||
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