algorithm: import searching publically

This commit is contained in:
2019-03-20 07:30:47 +01:00
parent 20c7e47ff7
commit 0fe7308a22
28 changed files with 1468 additions and 2020 deletions

View 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);
}
}

View 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);
}

View 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[]));
}

View 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);
}

View 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);
}

View 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(); })));
}

View 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))));
}

View 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)));
}

View 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)));
}

View 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));
}

View 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));
}

View 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);
}