diff --git a/.travis.yml b/.travis.yml index 5f27c09..5ac104b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ language: d d: - dmd-2.085.0 - dmd-2.084.1 -- dmd-2.083.1 - dmd-2.082.1 env: diff --git a/appveyor.yml b/appveyor.yml index e94c1e5..2b15380 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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 diff --git a/source/tanya/algorithm/comparison.d b/source/tanya/algorithm/comparison.d index 904f045..2faeaab 100644 --- a/source/tanya/algorithm/comparison.d +++ b/source/tanya/algorithm/comparison.d @@ -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); - } -} diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d index 0cca49f..907aa1a 100644 --- a/source/tanya/algorithm/iteration.d +++ b/source/tanya/algorithm/iteration.d @@ -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); -} diff --git a/source/tanya/algorithm/mutation.d b/source/tanya/algorithm/mutation.d index fd6a9d6..cf44f18 100644 --- a/source/tanya/algorithm/mutation.d +++ b/source/tanya/algorithm/mutation.d @@ -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[])); -} diff --git a/source/tanya/algorithm/package.d b/source/tanya/algorithm/package.d index a0f95b2..e64eff0 100644 --- a/source/tanya/algorithm/package.d +++ b/source/tanya/algorithm/package.d @@ -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; diff --git a/source/tanya/algorithm/searching.d b/source/tanya/algorithm/searching.d index 065bcde..dd5f4c9 100644 --- a/source/tanya/algorithm/searching.d +++ b/source/tanya/algorithm/searching.d @@ -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); -} diff --git a/source/tanya/async/loop.d b/source/tanya/async/loop.d index b706ff3..3fba090 100644 --- a/source/tanya/async/loop.d +++ b/source/tanya/async/loop.d @@ -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); -} diff --git a/source/tanya/async/watcher.d b/source/tanya/async/watcher.d index 9ecb300..b257b5b 100644 --- a/source/tanya/async/watcher.d +++ b/source/tanya/async/watcher.d @@ -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. */ diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d index 1c6842f..1bad819 100644 --- a/source/tanya/container/array.d +++ b/source/tanya/container/array.d @@ -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(); }))); -} diff --git a/source/tanya/container/buffer.d b/source/tanya/container/buffer.d index b2eeb74..1bb0c4d 100644 --- a/source/tanya/container/buffer.d +++ b/source/tanya/container/buffer.d @@ -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); diff --git a/source/tanya/container/entry.d b/source/tanya/container/entry.d index cf4484c..cc434b8 100644 --- a/source/tanya/container/entry.d +++ b/source/tanya/container/entry.d @@ -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))); -} diff --git a/source/tanya/container/hashtable.d b/source/tanya/container/hashtable.d index 3571f63..4df8af0 100644 --- a/source/tanya/container/hashtable.d +++ b/source/tanya/container/hashtable.d @@ -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))); -} diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d index e6e01d5..bb1870c 100644 --- a/source/tanya/container/list.d +++ b/source/tanya/container/list.d @@ -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)); -} diff --git a/source/tanya/container/set.d b/source/tanya/container/set.d index b06ef91..3c9c362 100644 --- a/source/tanya/container/set.d +++ b/source/tanya/container/set.d @@ -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)); -} diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d index 2a50dc6..4263b1c 100644 --- a/source/tanya/container/string.d +++ b/source/tanya/container/string.d @@ -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); -} diff --git a/tests/tanya/algorithm/tests/comparison.d b/tests/tanya/algorithm/tests/comparison.d new file mode 100644 index 0000000..5bd561a --- /dev/null +++ b/tests/tanya/algorithm/tests/comparison.d @@ -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); + } +} diff --git a/tests/tanya/algorithm/tests/iteration.d b/tests/tanya/algorithm/tests/iteration.d new file mode 100644 index 0000000..52e99b3 --- /dev/null +++ b/tests/tanya/algorithm/tests/iteration.d @@ -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); +} diff --git a/tests/tanya/algorithm/tests/mutation.d b/tests/tanya/algorithm/tests/mutation.d new file mode 100644 index 0000000..5d98233 --- /dev/null +++ b/tests/tanya/algorithm/tests/mutation.d @@ -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[])); +} diff --git a/tests/tanya/algorithm/tests/searching.d b/tests/tanya/algorithm/tests/searching.d new file mode 100644 index 0000000..ca8fdb0 --- /dev/null +++ b/tests/tanya/algorithm/tests/searching.d @@ -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); +} diff --git a/tests/tanya/async/tests/loop.d b/tests/tanya/async/tests/loop.d new file mode 100644 index 0000000..60841b1 --- /dev/null +++ b/tests/tanya/async/tests/loop.d @@ -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); +} diff --git a/tests/tanya/container/tests/array.d b/tests/tanya/container/tests/array.d new file mode 100644 index 0000000..f551fb9 --- /dev/null +++ b/tests/tanya/container/tests/array.d @@ -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(); }))); +} diff --git a/tests/tanya/container/tests/buffer.d b/tests/tanya/container/tests/buffer.d new file mode 100644 index 0000000..7071976 --- /dev/null +++ b/tests/tanya/container/tests/buffer.d @@ -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)))); +} + diff --git a/tests/tanya/container/tests/entry.d b/tests/tanya/container/tests/entry.d new file mode 100644 index 0000000..e4a13c1 --- /dev/null +++ b/tests/tanya/container/tests/entry.d @@ -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))); +} diff --git a/tests/tanya/container/tests/hashtable.d b/tests/tanya/container/tests/hashtable.d new file mode 100644 index 0000000..98c9c53 --- /dev/null +++ b/tests/tanya/container/tests/hashtable.d @@ -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))); +} diff --git a/tests/tanya/container/tests/list.d b/tests/tanya/container/tests/list.d new file mode 100644 index 0000000..58fb34e --- /dev/null +++ b/tests/tanya/container/tests/list.d @@ -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)); +} diff --git a/tests/tanya/container/tests/set.d b/tests/tanya/container/tests/set.d new file mode 100644 index 0000000..187869f --- /dev/null +++ b/tests/tanya/container/tests/set.d @@ -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)); +} diff --git a/tests/tanya/container/tests/string.d b/tests/tanya/container/tests/string.d new file mode 100644 index 0000000..755cf22 --- /dev/null +++ b/tests/tanya/container/tests/string.d @@ -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); +}