diff --git a/libphobos/testsuite/libphobos.phobos/phobos.exp b/libphobos/testsuite/libphobos.phobos/phobos.exp new file mode 100644 index 0000000000000000000000000000000000000000..21ce4cea448210134c7870b6cb61e25bf66af044 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/phobos.exp @@ -0,0 +1,50 @@ +# Copyright (C) 2019-2025 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Immediately exit if we can't run target executables. +if { ![isnative] } { + return +} + +# Skip running test if phobos was not built on the target. +if { ![is-effective-target d_runtime_has_std_library] } { + return +} + +# Gather a list of all tests. +set tests [lsort [find $srcdir/$subdir *.d]] + +set version_flags "-fversion=StdUnittest" + +if { [is-effective-target linux_pre_2639] } { + lappend version_flags "-fversion=Linux_Pre_2639" +} + +set libphobos_skip_tests { + # Skip concurrency.d test: SEGVs or hangs on macOS 13+ (PR d/111628). + { libphobos.phobos/std_concurrency.d { x86_64-apple-darwin2[2-9]* } } +} + +# Initialize dg. +dg-init + +# Main loop. +foreach test $tests { + dg-runtest $test "" "-Wno-deprecated -fmain $version_flags" +} + +# All done. +dg-finish diff --git a/libphobos/testsuite/libphobos.phobos/shared/phobos-shared.exp b/libphobos/testsuite/libphobos.phobos/shared/phobos-shared.exp index 31cc13dd9ae22db930a6d88cc0146726bbbb7f5d..3f62864b42a20f9bd06019489942581731875ba9 100644 --- a/libphobos/testsuite/libphobos.phobos/shared/phobos-shared.exp +++ b/libphobos/testsuite/libphobos.phobos/shared/phobos-shared.exp @@ -24,6 +24,11 @@ if { ![is-effective-target d_runtime_has_std_library] } { return } +# Skip running test if not doing expensive tests. +if { ![is-effective-target run_expensive_tests] } { + return +} + # Gather a list of all tests. set tests [lsort [filter_libphobos_unittests [find $srcdir/../src "*.d"]]] diff --git a/libphobos/testsuite/libphobos.phobos/static/phobos-static.exp b/libphobos/testsuite/libphobos.phobos/static/phobos-static.exp index 642019c7f6d7027c4d97d4c425722c6921920d74..ecccbc952cf8b1653ea04cd946c8df1c21f6ca18 100644 --- a/libphobos/testsuite/libphobos.phobos/static/phobos-static.exp +++ b/libphobos/testsuite/libphobos.phobos/static/phobos-static.exp @@ -24,6 +24,11 @@ if { ![is-effective-target d_runtime_has_std_library] } { return } +# Skip running test if not doing expensive tests. +if { ![is-effective-target run_expensive_tests] } { + return +} + # Gather a list of all tests. set tests [lsort [filter_libphobos_unittests [find $srcdir/../src "*.d"]]] diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_comparison.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_comparison.d new file mode 100644 index 0000000000000000000000000000000000000000..800694039a09b2b9517277b817d4ee6a502176da --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_comparison.d @@ -0,0 +1,454 @@ +@safe @nogc unittest +{ + import std.algorithm.comparison; + + assert(3.among(1, 42, 24, 3, 2)); + + if (auto pos = "bar".among("foo", "bar", "baz")) + assert(pos == 2); + else + assert(false); + + // 42 is larger than 24 + assert(42.among!((lhs, rhs) => lhs > rhs)(43, 24, 100) == 2); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + assert(3.among!(2, 3, 4)); + assert("bar".among!("foo", "bar", "baz") == 2); +} + +@system unittest +{ + import std.algorithm.comparison; + + import std.algorithm.iteration : map; + import std.format : format; + + class A + { + int a; + this(int a) {this.a = a;} + @property int i() { return a; } + } + interface I { } + class B : I { } + + Object[] arr = [new A(1), new B(), null]; + + auto results = arr.map!(castSwitch!( + (A a) => "A with a value of %d".format(a.a), + (I i) => "derived from I", + () => "null reference", + ))(); + + // A is handled directly: + assert(results[0] == "A with a value of 1"); + // B has no handler - it is handled by the handler of I: + assert(results[1] == "derived from I"); + // null is handled by the null handler: + assert(results[2] == "null reference"); +} + +@system unittest +{ + import std.algorithm.comparison; + + import std.exception : assertThrown; + + class A { } + class B { } + // Void handlers are allowed if they throw: + assertThrown!Exception( + new B().castSwitch!( + (A a) => 1, + (B d) { throw new Exception("B is not allowed!"); } + )() + ); + + // Void handlers are also allowed if all the handlers are void: + new A().castSwitch!( + (A a) { }, + (B b) { assert(false); }, + )(); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + assert(clamp(2, 1, 3) == 2); + assert(clamp(0, 1, 3) == 1); + assert(clamp(4, 1, 3) == 3); + + assert(clamp(1, 1, 1) == 1); + + assert(clamp(5, -1, 2u) == 2); + + auto x = clamp(42, uint.max, uint.max); + static assert(is(typeof(x) == int)); + assert(x == -1); +} + +pure @safe unittest +{ + import std.algorithm.comparison; + + int result; + + result = cmp("abc", "abc"); + assert(result == 0); + result = cmp("", ""); + assert(result == 0); + result = cmp("abc", "abcd"); + assert(result < 0); + result = cmp("abcd", "abc"); + assert(result > 0); + result = cmp("abc"d, "abd"); + assert(result < 0); + result = cmp("bbc", "abc"w); + assert(result > 0); + result = cmp("aaa", "aaaa"d); + assert(result < 0); + result = cmp("aaaa", "aaa"d); + assert(result > 0); + result = cmp("aaa", "aaa"d); + assert(result == 0); + result = cmp("aaa"d, "aaa"d); + assert(result == 0); + result = cmp(cast(int[])[], cast(int[])[]); + assert(result == 0); + result = cmp([1, 2, 3], [1, 2, 3]); + assert(result == 0); + result = cmp([1, 3, 2], [1, 2, 3]); + assert(result > 0); + result = cmp([1, 2, 3], [1L, 2, 3, 4]); + assert(result < 0); + result = cmp([1L, 2, 3], [1, 2]); + assert(result > 0); +} + +pure @safe unittest +{ + import std.algorithm.comparison; + + int result; + + result = cmp!"a > b"("abc", "abc"); + assert(result == 0); + result = cmp!"a > b"("", ""); + assert(result == 0); + result = cmp!"a > b"("abc", "abcd"); + assert(result < 0); + result = cmp!"a > b"("abcd", "abc"); + assert(result > 0); + result = cmp!"a > b"("abc"d, "abd"); + assert(result > 0); + result = cmp!"a > b"("bbc", "abc"w); + assert(result < 0); + result = cmp!"a > b"("aaa", "aaaa"d); + assert(result < 0); + result = cmp!"a > b"("aaaa", "aaa"d); + assert(result > 0); + result = cmp!"a > b"("aaa", "aaa"d); + assert(result == 0); + result = cmp("aaa"d, "aaa"d); + assert(result == 0); + result = cmp!"a > b"(cast(int[])[], cast(int[])[]); + assert(result == 0); + result = cmp!"a > b"([1, 2, 3], [1, 2, 3]); + assert(result == 0); + result = cmp!"a > b"([1, 3, 2], [1, 2, 3]); + assert(result < 0); + result = cmp!"a > b"([1, 2, 3], [1L, 2, 3, 4]); + assert(result < 0); + result = cmp!"a > b"([1L, 2, 3], [1, 2]); + assert(result > 0); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + import std.algorithm.comparison : equal; + import std.math.operations : isClose; + + int[4] a = [ 1, 2, 4, 3 ]; + assert(!equal(a[], a[1..$])); + assert(equal(a[], a[])); + assert(equal!((a, b) => a == b)(a[], a[])); + + // different types + double[4] b = [ 1.0, 2, 4, 3]; + assert(!equal(a[], b[1..$])); + assert(equal(a[], b[])); + + // predicated: ensure that two vectors are approximately equal + double[4] c = [ 1.0000000005, 2, 4, 3]; + assert(equal!isClose(b[], c[])); +} + +@safe unittest +{ + import std.algorithm.comparison; + + import std.algorithm.comparison : equal; + import std.range : iota, chunks; + assert(equal!(equal!equal)( + [[[0, 1], [2, 3]], [[4, 5], [6, 7]]], + iota(0, 8).chunks(2).chunks(2) + )); +} + +@safe unittest +{ + import std.algorithm.comparison; + + with(EditOp) + { + assert(levenshteinDistanceAndPath("foo", "foobar")[1] == [none, none, none, insert, insert, insert]); + assert(levenshteinDistanceAndPath("banana", "fazan")[1] == [substitute, none, substitute, none, none, remove]); + } +} + +@safe unittest +{ + import std.algorithm.comparison; + + import std.algorithm.iteration : filter; + import std.uni : toUpper; + + assert(levenshteinDistance("cat", "rat") == 1); + assert(levenshteinDistance("parks", "spark") == 2); + assert(levenshteinDistance("abcde", "abcde") == 0); + assert(levenshteinDistance("abcde", "abCde") == 1); + assert(levenshteinDistance("kitten", "sitting") == 3); + assert(levenshteinDistance!((a, b) => toUpper(a) == toUpper(b)) + ("parks", "SPARK") == 2); + assert(levenshteinDistance("parks".filter!"true", "spark".filter!"true") == 2); + assert(levenshteinDistance("ID", "I♥D") == 1); +} + +@safe unittest +{ + import std.algorithm.comparison; + + string a = "Saturday", b = "Sundays"; + auto p = levenshteinDistanceAndPath(a, b); + assert(p[0] == 4); + assert(equal(p[1], "nrrnsnnni")); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + int a = 5; + short b = 6; + double c = 2; + auto d = max(a, b); + assert(is(typeof(d) == int)); + assert(d == 6); + auto e = min(a, b, c); + assert(is(typeof(e) == double)); + assert(e == 2); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + int a = 5; + short b = 6; + double c = 2; + auto d = min(a, b); + static assert(is(typeof(d) == int)); + assert(d == 5); + auto e = min(a, b, c); + static assert(is(typeof(e) == double)); + assert(e == 2); + ulong f = 0xffff_ffff_ffff; + const uint g = min(f, 0xffff_0000); + assert(g == 0xffff_0000); + dchar h = 100; + uint i = 101; + static assert(is(typeof(min(h, i)) == dchar)); + static assert(is(typeof(min(i, h)) == uint)); + assert(min(h, i) == 100); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + int a = -10; + uint f = 10; + static assert(is(typeof(min(a, f)) == int)); + assert(min(a, f) == -10); +} + +@safe unittest +{ + import std.algorithm.comparison; + + import std.datetime; + assert(min(Date(2012, 12, 21), Date(1982, 1, 4)) == Date(1982, 1, 4)); + assert(min(Date(1982, 1, 4), Date(2012, 12, 21)) == Date(1982, 1, 4)); + assert(min(Date(1982, 1, 4), Date.min) == Date.min); + assert(min(Date.min, Date(1982, 1, 4)) == Date.min); + assert(min(Date(1982, 1, 4), Date.max) == Date(1982, 1, 4)); + assert(min(Date.max, Date(1982, 1, 4)) == Date(1982, 1, 4)); + assert(min(Date.min, Date.max) == Date.min); + assert(min(Date.max, Date.min) == Date.min); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + int[6] x = [ 1, 5, 2, 7, 4, 3 ]; + double[6] y = [ 1.0, 5, 2, 7.3, 4, 8 ]; + auto m = mismatch(x[], y[]); + assert(m[0] == x[3 .. $]); + assert(m[1] == y[3 .. $]); + + auto m2 = mismatch(x[], y[], x[], y[]); + assert(m2[0] == x[3 .. $]); + assert(m2[1] == y[3 .. $]); + assert(m2[2] == x[3 .. $]); + assert(m2[3] == y[3 .. $]); +} + +@safe unittest +{ + import std.algorithm.comparison; + + string res = 2.predSwitch!"a < b"( + 1, "less than 1", + 5, "less than 5", + 10, "less than 10", + "greater or equal to 10"); + + assert(res == "less than 5"); + + //The arguments are lazy, which allows us to use predSwitch to create + //recursive functions: + int factorial(int n) + { + return n.predSwitch!"a <= b"( + -1, {throw new Exception("Can not calculate n! for n < 0");}(), + 0, 1, // 0! = 1 + n * factorial(n - 1) // n! = n * (n - 1)! for n >= 0 + ); + } + assert(factorial(3) == 6); + + //Void return expressions are allowed if they always throw: + import std.exception : assertThrown; + assertThrown!Exception(factorial(-9)); +} + +@safe nothrow pure unittest +{ + import std.algorithm.comparison; + + assert(isSameLength([1, 2, 3], [4, 5, 6])); + assert(isSameLength([1, 2, 3], [4, 5, 6], [7, 8, 9])); + assert(isSameLength([0.3, 90.4, 23.7, 119.2], [42.6, 23.6, 95.5, 6.3])); + assert(isSameLength("abc", "xyz")); + assert(isSameLength("abc", "xyz", [1, 2, 3])); + + int[] a; + int[] b; + assert(isSameLength(a, b)); + assert(isSameLength(a, b, a, a, b, b, b)); + + assert(!isSameLength([1, 2, 3], [4, 5])); + assert(!isSameLength([1, 2, 3], [4, 5, 6], [7, 8])); + assert(!isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3])); + assert(!isSameLength("abcd", "xyz")); + assert(!isSameLength("abcd", "xyz", "123")); + assert(!isSameLength("abcd", "xyz", "1234")); +} + +@safe pure unittest +{ + import std.algorithm.comparison; + + import std.typecons : Yes; + + assert(isPermutation([1, 2, 3], [3, 2, 1])); + assert(isPermutation([1.1, 2.3, 3.5], [2.3, 3.5, 1.1])); + assert(isPermutation("abc", "bca")); + + assert(!isPermutation([1, 2], [3, 4])); + assert(!isPermutation([1, 1, 2, 3], [1, 2, 2, 3])); + assert(!isPermutation([1, 1], [1, 1, 1])); + + // Faster, but allocates GC handled memory + assert(isPermutation!(Yes.allocateGC)([1.1, 2.3, 3.5], [2.3, 3.5, 1.1])); + assert(!isPermutation!(Yes.allocateGC)([1, 2], [3, 4])); +} + +@safe pure unittest +{ + import std.algorithm.comparison; + + const a = 1; + const b = 2; + auto ab = either(a, b); + static assert(is(typeof(ab) == const(int))); + assert(ab == a); + + auto c = 2; + const d = 3; + auto cd = either!(a => a == 3)(c, d); // use predicate + static assert(is(typeof(cd) == int)); + assert(cd == d); + + auto e = 0; + const f = 2; + auto ef = either(e, f); + static assert(is(typeof(ef) == int)); + assert(ef == f); +} + +@safe pure unittest +{ + import std.algorithm.comparison; + + immutable p = 1; + immutable q = 2; + auto pq = either(p, q); + static assert(is(typeof(pq) == immutable(int))); + assert(pq == p); + + assert(either(3, 4) == 3); + assert(either(0, 4) == 4); + assert(either(0, 0) == 0); + assert(either("", "a") == ""); +} + +@safe pure unittest +{ + import std.algorithm.comparison; + + string r = null; + assert(either(r, "a") == "a"); + assert(either("a", "") == "a"); + + immutable s = [1, 2]; + assert(either(s, s) == s); + + assert(either([0, 1], [1, 2]) == [0, 1]); + assert(either([0, 1], [1]) == [0, 1]); + assert(either("a", "b") == "a"); + + static assert(!__traits(compiles, either(1, "a"))); + static assert(!__traits(compiles, either(1.0, "a"))); + static assert(!__traits(compiles, either('a', "a"))); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_iteration.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_iteration.d new file mode 100644 index 0000000000000000000000000000000000000000..a4f74fb9394ae3a7949738e954b64bf9a961c256 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_iteration.d @@ -0,0 +1,1004 @@ +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range, std.stdio; + import std.typecons : tuple; + + ulong counter = 0; + double fun(int x) + { + ++counter; + // http://en.wikipedia.org/wiki/Quartic_function + return ( (x + 4.0) * (x + 1.0) * (x - 1.0) * (x - 3.0) ) / 14.0 + 0.5; + } + // Without cache, with array (greedy) + auto result1 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() + .filter!(a => a[1] < 0)() + .map!(a => a[0])() + .array(); + + // the values of x that have a negative y are: + assert(equal(result1, [-3, -2, 2])); + + // Check how many times fun was evaluated. + // As many times as the number of items in both source and result. + assert(counter == iota(-4, 5).length + result1.length); + + counter = 0; + // Without array, with cache (lazy) + auto result2 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() + .cache() + .filter!(a => a[1] < 0)() + .map!(a => a[0])(); + + // the values of x that have a negative y are: + assert(equal(result2, [-3, -2, 2])); + + // Check how many times fun was evaluated. + // Only as many times as the number of items in source. + assert(counter == iota(-4, 5).length); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range; + int i = 0; + + auto r = iota(0, 4).tee!((a){i = a;}, No.pipeOnPop); + auto r1 = r.take(3).cache(); + auto r2 = r.cache().take(3); + + assert(equal(r1, [0, 1, 2])); + assert(i == 2); //The last "seen" element was 2. The data in cache has been cleared. + + assert(equal(r2, [0, 1, 2])); + assert(i == 3); //cache has accessed 3. It is still stored internally by cache. +} + +@safe @nogc unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : chain, only; + auto squares = + chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a); + assert(equal(squares, only(1, 4, 9, 16, 25, 36))); +} + +@safe unittest +{ + import std.algorithm.iteration; + + auto sums = [2, 4, 6, 8]; + auto products = [1, 4, 9, 16]; + + size_t i = 0; + foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a")) + { + assert(result[0] == sums[i]); + assert(result[1] == products[i]); + ++i; + } +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.conv : to; + + alias stringize = map!(to!string); + assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.range : iota; + import std.typecons : No; + + int[] arr; + iota(5).each!(n => arr ~= n); + assert(arr == [0, 1, 2, 3, 4]); + + // stop iterating early + iota(5).each!((n) { arr ~= n; return No.each; }); + assert(arr == [0, 1, 2, 3, 4, 0]); + + // If the range supports it, the value can be mutated in place + arr.each!((ref n) => n++); + assert(arr == [1, 2, 3, 4, 5, 1]); + + arr.each!"a++"; + assert(arr == [2, 3, 4, 5, 6, 2]); + + auto m = arr.map!(n => n); + // by-ref lambdas are not allowed for non-ref ranges + static assert(!__traits(compiles, m.each!((ref n) => n++))); + + // The default predicate consumes the range + (&m).each(); + assert(m.empty); +} + +@safe unittest +{ + import std.algorithm.iteration; + + auto arr = new size_t[4]; + + arr.each!"a=i"(); + assert(arr == [0, 1, 2, 3]); + + arr.each!((i, ref e) => e = i * 2); + assert(arr == [0, 2, 4, 6]); +} + +@system unittest +{ + import std.algorithm.iteration; + + static class S + { + int x; + int opApply(scope int delegate(ref int _x) dg) { return dg(x); } + } + + auto s = new S; + s.each!"a++"; + assert(s.x == 1); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.math.operations : isClose; + import std.range; + + int[] arr = [ 1, 2, 3, 4, 5 ]; + + // Filter below 3 + auto small = filter!(a => a < 3)(arr); + assert(equal(small, [ 1, 2 ])); + + // Filter again, but with Uniform Function Call Syntax (UFCS) + auto sum = arr.filter!(a => a < 3); + assert(equal(sum, [ 1, 2 ])); + + // In combination with chain() to span multiple ranges + int[] a = [ 3, -2, 400 ]; + int[] b = [ 100, -101, 102 ]; + auto r = chain(a, b).filter!(a => a > 0); + assert(equal(r, [ 3, 400, 100, 102 ])); + + // Mixing convertible types is fair game, too + double[] c = [ 2.5, 3.0 ]; + auto r1 = chain(c, a, b).filter!(a => cast(int) a != a); + assert(isClose(r1, [ 2.5 ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range; + + int[] arr = [ 1, 2, 3, 4, 5 ]; + auto small = filterBidirectional!("a < 3")(arr); + static assert(isBidirectionalRange!(typeof(small))); + assert(small.back == 2); + assert(equal(small, [ 1, 2 ])); + assert(equal(retro(small), [ 2, 1 ])); + // In combination with chain() to span multiple ranges + int[] a = [ 3, -2, 400 ]; + int[] b = [ 100, -101, 102 ]; + auto r = filterBidirectional!("a > 0")(chain(a, b)); + assert(r.back == 102); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : tuple, Tuple; + + int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; + assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u), + tuple(4, 3u), tuple(5, 1u) ][])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.sorting : sort; + import std.array : assocArray; + + uint[string] result; + auto range = ["a", "b", "a", "c", "b", "c", "c", "d", "e"]; + result = range.sort!((a, b) => a < b) + .group + .assocArray; + + assert(result == ["a": 2U, "b": 2U, "c": 3U, "d": 1U, "e": 1U]); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + // Grouping by particular attribute of each element: + auto data = [ + [1, 1], + [1, 2], + [2, 2], + [2, 3] + ]; + + auto r1 = data.chunkBy!((a,b) => a[0] == b[0]); + assert(r1.equal!equal([ + [[1, 1], [1, 2]], + [[2, 2], [2, 3]] + ])); + + auto r2 = data.chunkBy!((a,b) => a[1] == b[1]); + assert(r2.equal!equal([ + [[1, 1]], + [[1, 2], [2, 2]], + [[2, 3]] + ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range.primitives; + import std.typecons : tuple; + + // Grouping by particular attribute of each element: + auto range = + [ + [1, 1], + [1, 1], + [1, 2], + [2, 2], + [2, 3], + [2, 3], + [3, 3] + ]; + + auto byX = chunkBy!(a => a[0])(range); + auto expected1 = + [ + tuple(1, [[1, 1], [1, 1], [1, 2]]), + tuple(2, [[2, 2], [2, 3], [2, 3]]), + tuple(3, [[3, 3]]) + ]; + foreach (e; byX) + { + assert(!expected1.empty); + assert(e[0] == expected1.front[0]); + assert(e[1].equal(expected1.front[1])); + expected1.popFront(); + } + + auto byY = chunkBy!(a => a[1])(range); + auto expected2 = + [ + tuple(1, [[1, 1], [1, 1]]), + tuple(2, [[1, 2], [2, 2]]), + tuple(3, [[2, 3], [2, 3], [3, 3]]) + ]; + foreach (e; byY) + { + assert(!expected2.empty); + assert(e[0] == expected2.front[0]); + assert(e[1].equal(expected2.front[1])); + expected2.popFront(); + } +} + +nothrow pure @safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : dropExactly; + auto source = [4, 3, 2, 11, 0, -3, -3, 5, 3, 0]; + + auto result1 = source.splitWhen!((a,b) => a <= b); + assert(result1.save.equal!equal([ + [4, 3, 2], + [11, 0, -3], + [-3], + [5, 3, 0] + ])); + + //splitWhen, like chunkBy, is currently a reference range (this may change + //in future). Remember to call `save` when appropriate. + auto result2 = result1.dropExactly(2); + assert(result1.save.equal!equal([ + [-3], + [5, 3, 0] + ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.conv : text; + + assert(["abc", "def"].joiner.equal("abcdef")); + assert(["Mary", "has", "a", "little", "lamb"] + .joiner("...") + .equal("Mary...has...a...little...lamb")); + assert(["", "abc"].joiner("xyz").equal("xyzabc")); + assert([""].joiner("xyz").equal("")); + assert(["", ""].joiner("xyz").equal("xyz")); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : repeat; + + assert([""].joiner.equal("")); + assert(["", ""].joiner.equal("")); + assert(["", "abc"].joiner.equal("abc")); + assert(["abc", ""].joiner.equal("abc")); + assert(["abc", "def"].joiner.equal("abcdef")); + assert(["Mary", "has", "a", "little", "lamb"].joiner.equal("Maryhasalittlelamb")); + assert("abc".repeat(3).joiner.equal("abcabcabc")); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + auto a = [ [1, 2, 3], [42, 43] ]; + auto j = joiner(a); + j.front = 44; + assert(a == [ [44, 2, 3], [42, 43] ]); + assert(equal(j, [44, 2, 3, 42, 43])); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : chain, cycle, iota, only, retro, take, zip; + import std.format : format; + + static immutable number = "12345678"; + static immutable delimiter = ","; + auto formatted = number.retro + .zip(3.iota.cycle.take(number.length)) + .map!(z => chain(z[0].only, z[1] == 2 ? delimiter : null)) + .joiner + .retro; + static immutable expected = "12,345,678"; + assert(formatted.equal(expected)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : retro; + + auto a = [[1, 2, 3], [4, 5]]; + auto j = a.joiner; + j.back = 44; + assert(a == [[1, 2, 3], [4, 44]]); + assert(equal(j.retro, [44, 4, 3, 2, 1])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : max, min; + import std.math.operations : isClose; + import std.range; + + int[] arr = [ 1, 2, 3, 4, 5 ]; + // Sum all elements + auto sum = reduce!((a,b) => a + b)(0, arr); + assert(sum == 15); + + // Sum again, using a string predicate with "a" and "b" + sum = reduce!"a + b"(0, arr); + assert(sum == 15); + + // Compute the maximum of all elements + auto largest = reduce!(max)(arr); + assert(largest == 5); + + // Max again, but with Uniform Function Call Syntax (UFCS) + largest = arr.reduce!(max); + assert(largest == 5); + + // Compute the number of odd elements + auto odds = reduce!((a,b) => a + (b & 1))(0, arr); + assert(odds == 3); + + // Compute the sum of squares + auto ssquares = reduce!((a,b) => a + b * b)(0, arr); + assert(ssquares == 55); + + // Chain multiple ranges into seed + int[] a = [ 3, 4 ]; + int[] b = [ 100 ]; + auto r = reduce!("a + b")(chain(a, b)); + assert(r == 107); + + // Mixing convertible types is fair game, too + double[] c = [ 2.5, 3.0 ]; + auto r1 = reduce!("a + b")(chain(a, b, c)); + assert(isClose(r1, 112.5)); + + // To minimize nesting of parentheses, Uniform Function Call Syntax can be used + auto r2 = chain(a, b, c).reduce!("a + b"); + assert(isClose(r2, 112.5)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : max, min; + import std.math.operations : isClose; + import std.math.algebraic : sqrt; + import std.typecons : tuple, Tuple; + + double[] a = [ 3.0, 4, 7, 11, 3, 2, 5 ]; + // Compute minimum and maximum in one pass + auto r = reduce!(min, max)(a); + // The type of r is Tuple!(int, int) + assert(isClose(r[0], 2)); // minimum + assert(isClose(r[1], 11)); // maximum + + // Compute sum and sum of squares in one pass + r = reduce!("a + b", "a + b * b")(tuple(0.0, 0.0), a); + assert(isClose(r[0], 35)); // sum + assert(isClose(r[1], 233)); // sum of squares + // Compute average and standard deviation from the above + auto avg = r[0] / a.length; + assert(avg == 5); + auto stdev = sqrt(r[1] / a.length - avg * avg); + assert(cast(int) stdev == 2); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + immutable arr = [1, 2, 3, 4, 5]; + + // Sum all elements + assert(arr.fold!((a, e) => a + e) == 15); + + // Sum all elements with explicit seed + assert(arr.fold!((a, e) => a + e)(6) == 21); + + import std.algorithm.comparison : min, max; + import std.typecons : tuple; + + // Compute minimum and maximum at the same time + assert(arr.fold!(min, max) == tuple(1, 5)); + + // Compute minimum and maximum at the same time with seeds + assert(arr.fold!(min, max)(0, 7) == tuple(0, 7)); + + // Can be used in a UFCS chain + assert(arr.map!(a => a + 1).fold!((a, e) => a + e) == 20); + + // Return the last element of any range + assert(arr.fold!((a, e) => e) == 5); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : max, min; + import std.array : array; + import std.math.operations : isClose; + import std.range : chain; + + int[] arr = [1, 2, 3, 4, 5]; + // Partial sum of all elements + auto sum = cumulativeFold!((a, b) => a + b)(arr, 0); + assert(sum.array == [1, 3, 6, 10, 15]); + + // Partial sum again, using a string predicate with "a" and "b" + auto sum2 = cumulativeFold!"a + b"(arr, 0); + assert(sum2.array == [1, 3, 6, 10, 15]); + + // Compute the partial maximum of all elements + auto largest = cumulativeFold!max(arr); + assert(largest.array == [1, 2, 3, 4, 5]); + + // Partial max again, but with Uniform Function Call Syntax (UFCS) + largest = arr.cumulativeFold!max; + assert(largest.array == [1, 2, 3, 4, 5]); + + // Partial count of odd elements + auto odds = arr.cumulativeFold!((a, b) => a + (b & 1))(0); + assert(odds.array == [1, 1, 2, 2, 3]); + + // Compute the partial sum of squares + auto ssquares = arr.cumulativeFold!((a, b) => a + b * b)(0); + assert(ssquares.array == [1, 5, 14, 30, 55]); + + // Chain multiple ranges into seed + int[] a = [3, 4]; + int[] b = [100]; + auto r = cumulativeFold!"a + b"(chain(a, b)); + assert(r.array == [3, 7, 107]); + + // Mixing convertible types is fair game, too + double[] c = [2.5, 3.0]; + auto r1 = cumulativeFold!"a + b"(chain(a, b, c)); + assert(isClose(r1, [3, 7, 107, 109.5, 112.5])); + + // To minimize nesting of parentheses, Uniform Function Call Syntax can be used + auto r2 = chain(a, b, c).cumulativeFold!"a + b"; + assert(isClose(r2, [3, 7, 107, 109.5, 112.5])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : max, min; + import std.algorithm.iteration : map; + import std.math.operations : isClose; + import std.typecons : tuple; + + double[] a = [3.0, 4, 7, 11, 3, 2, 5]; + // Compute minimum and maximum in one pass + auto r = a.cumulativeFold!(min, max); + // The type of r is Tuple!(int, int) + assert(isClose(r.map!"a[0]", [3, 3, 3, 3, 3, 2, 2])); // minimum + assert(isClose(r.map!"a[1]", [3, 4, 7, 11, 11, 11, 11])); // maximum + + // Compute sum and sum of squares in one pass + auto r2 = a.cumulativeFold!("a + b", "a + b * b")(tuple(0.0, 0.0)); + assert(isClose(r2.map!"a[0]", [3, 7, 14, 25, 28, 30, 35])); // sum + assert(isClose(r2.map!"a[1]", [9, 25, 74, 195, 204, 208, 233])); // sum of squares +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + assert("a|bc|def".splitter('|').equal([ "a", "bc", "def" ])); + + int[] a = [1, 0, 2, 3, 0, 4, 5, 6]; + int[][] w = [ [1], [2, 3], [4, 5, 6] ]; + assert(a.splitter(0).equal(w)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "a", "|", "bc", "|", "def" ])); + + int[] a = [1, 0, 2, 3, 0, 4, 5, 6]; + int[][] w = [ [1], [0], [2, 3], [0], [4, 5, 6] ]; + assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + assert("|ab|".splitter('|').equal([ "", "ab", "" ])); + assert("ab".splitter('|').equal([ "ab" ])); + + assert("a|b||c".splitter('|').equal([ "a", "b", "", "c" ])); + assert("hello world".splitter(' ').equal([ "hello", "", "world" ])); + + auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + auto w = [ [1, 2], [], [3], [4, 5], [] ]; + assert(a.splitter(0).equal(w)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "", "|", "ab", "|", "" ])); + assert("ab".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "ab" ])); + + assert("a|b||c".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "a", "|", "b", "|", "", "|", "c" ])); + assert("hello world".splitter!("a == b", Yes.keepSeparators)(' ') + .equal([ "hello", " ", "", " ", "world" ])); + + auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + auto w = [ [1, 2], [0], [], [0], [3], [0], [4, 5], [0], [] ]; + assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : empty; + + assert("".splitter('|').empty); + assert("|".splitter('|').equal([ "", "" ])); + assert("||".splitter('|').equal([ "", "", "" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + import std.range : empty; + + assert("".splitter!("a == b", Yes.keepSeparators)('|').empty); + assert("|".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "", "|", "" ])); + assert("||".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "", "|", "", "|", "" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + assert("a=>bc=>def".splitter("=>").equal([ "a", "bc", "def" ])); + assert("a|b||c".splitter("||").equal([ "a|b", "c" ])); + assert("hello world".splitter(" ").equal([ "hello", "world" ])); + + int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ]; + assert(a.splitter([0, 0]).equal(w)); + + a = [ 0, 0 ]; + assert(a.splitter([0, 0]).equal([ (int[]).init, (int[]).init ])); + + a = [ 0, 0, 1 ]; + assert(a.splitter([0, 0]).equal([ [], [1] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + assert("a=>bc=>def".splitter!("a == b", Yes.keepSeparators)("=>") + .equal([ "a", "=>", "bc", "=>", "def" ])); + assert("a|b||c".splitter!("a == b", Yes.keepSeparators)("||") + .equal([ "a|b", "||", "c" ])); + assert("hello world".splitter!("a == b", Yes.keepSeparators)(" ") + .equal([ "hello", " ", "world" ])); + + int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + int[][] w = [ [1, 2], [0, 0], [3, 0, 4, 5, 0] ]; + assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]).equal(w)); + + a = [ 0, 0 ]; + assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]) + .equal([ (int[]).init, [0, 0], (int[]).init ])); + + a = [ 0, 0, 1 ]; + assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]) + .equal([ [], [0, 0], [1] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.ascii : toLower; + + assert("abXcdxef".splitter!"a.toLower == b"('x').equal( + [ "ab", "cd", "ef" ])); + + auto w = [ [0], [1], [2] ]; + assert(w.splitter!"a.front == b"(1).equal([ [[0]], [[2]] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + import std.ascii : toLower; + + assert("abXcdxef".splitter!("a.toLower == b", Yes.keepSeparators)('x') + .equal([ "ab", "X", "cd", "x", "ef" ])); + + auto w = [ [0], [1], [2] ]; + assert(w.splitter!("a.front == b", Yes.keepSeparators)(1) + .equal([ [[0]], [[1]], [[2]] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range.primitives : front; + + assert(equal(splitter!(a => a == '|')("a|bc|def"), [ "a", "bc", "def" ])); + assert(equal(splitter!(a => a == ' ')("hello world"), [ "hello", "", "world" ])); + + int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + int[][] w = [ [1, 2], [], [3], [4, 5], [] ]; + assert(equal(splitter!(a => a == 0)(a), w)); + + a = [ 0 ]; + assert(equal(splitter!(a => a == 0)(a), [ (int[]).init, (int[]).init ])); + + a = [ 0, 1 ]; + assert(equal(splitter!(a => a == 0)(a), [ [], [1] ])); + + w = [ [0], [1], [2] ]; + assert(equal(splitter!(a => a.front == 1)(w), [ [[0]], [[2]] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + assert("|ab|".splitter('|').equal([ "", "ab", "" ])); + assert("ab".splitter('|').equal([ "ab" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "", "|", "ab", "|", "" ])); + assert("ab".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "ab" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : retro; + assert("a|bc|def".splitter('|').retro.equal([ "def", "bc", "a" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + import std.range : retro; + assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|') + .retro.equal([ "def", "|", "bc", "|", "a" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.ascii : isWhite; + import std.algorithm.comparison : equal; + import std.algorithm.iteration : splitter; + + string str = "Hello World!"; + assert(str.splitter!(isWhite).equal(["Hello", "World!"])); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + auto a = " a bcd ef gh "; + assert(equal(splitter(a), ["a", "bcd", "ef", "gh"][])); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + // substitute single elements + assert("do_it".substitute('_', ' ').equal("do it")); + + // substitute multiple, single elements + assert("do_it".substitute('_', ' ', + 'd', 'g', + 'i', 't', + 't', 'o') + .equal("go to")); + + // substitute subranges + assert("do_it".substitute("_", " ", + "do", "done") + .equal("done it")); + + // substitution works for any ElementType + int[] x = [1, 2, 3]; + auto y = x.substitute(1, 0.1); + assert(y.equal([0.1, 2, 3])); + static assert(is(typeof(y.front) == double)); + + import std.range : retro; + assert([1, 2, 3].substitute(1, 0.1).retro.equal([3, 2, 0.1])); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + // substitute subranges of a range + assert("apple_tree".substitute!("apple", "banana", + "tree", "shrub").equal("banana_shrub")); + + // substitute subranges of a range + assert("apple_tree".substitute!('a', 'b', + 't', 'f').equal("bpple_free")); + + // substitute values + assert('a'.substitute!('a', 'b', 't', 'f') == 'b'); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range.primitives : ElementType; + + int[3] x = [1, 2, 3]; + auto y = x[].substitute(1, 0.1) + .substitute(0.1, 0.2); + static assert(is(typeof(y.front) == double)); + assert(y.equal([0.2, 2, 3])); + + auto z = "42".substitute('2', '3') + .substitute('3', '1'); + static assert(is(ElementType!(typeof(z)) == dchar)); + assert(equal(z, "41")); +} + +@safe pure nothrow unittest +{ + import std.algorithm.iteration; + + import std.range; + + //simple integral sumation + assert(sum([ 1, 2, 3, 4]) == 10); + + //with integral promotion + assert(sum([false, true, true, false, true]) == 3); + assert(sum(ubyte.max.repeat(100)) == 25500); + + //The result may overflow + assert(uint.max.repeat(3).sum() == 4294967293U ); + //But a seed can be used to change the sumation primitive + assert(uint.max.repeat(3).sum(ulong.init) == 12884901885UL); + + //Floating point sumation + assert(sum([1.0, 2.0, 3.0, 4.0]) == 10); + + //Floating point operations have double precision minimum + static assert(is(typeof(sum([1F, 2F, 3F, 4F])) == double)); + assert(sum([1F, 2, 3, 4]) == 10); + + //Force pair-wise floating point sumation on large integers + import std.math.operations : isClose; + assert(iota(ulong.max / 2, ulong.max / 2 + 4096).sum(0.0) + .isClose((ulong.max / 2) * 4096.0 + 4096^^2 / 2)); +} + +@safe @nogc pure nothrow unittest +{ + import std.algorithm.iteration; + + import std.math.operations : isClose; + import std.math.traits : isNaN; + + static immutable arr1 = [1, 2, 3]; + static immutable arr2 = [1.5, 2.5, 12.5]; + + assert(arr1.mean.isClose(2)); + assert(arr2.mean.isClose(5.5)); + + assert(arr1[0 .. 0].mean.isNaN); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.algorithm.mutation : copy; + + int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; + assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][])); + + // Filter duplicates in-place using copy + arr.length -= arr.uniq().copy(arr).length; + assert(arr == [ 1, 2, 3, 4, 5 ]); + + // Note that uniqueness is only determined consecutively; duplicated + // elements separated by an intervening different element will not be + // eliminated: + assert(equal(uniq([ 1, 1, 2, 1, 1, 3, 1]), [1, 2, 1, 3, 1])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : iota; + assert(equal!equal(iota(3).permutations, + [[0, 1, 2], + [1, 0, 2], + [2, 0, 1], + [0, 2, 1], + [1, 2, 0], + [2, 1, 0]])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_mutation.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_mutation.d new file mode 100644 index 0000000000000000000000000000000000000000..3f38d60b8596e2837adb7a6f43f2e6adaaf0ad0d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_mutation.d @@ -0,0 +1,627 @@ +@safe unittest +{ + import std.algorithm.mutation; + + auto arr = [4, 5, 6, 7, 1, 2, 3]; + auto p = bringToFront(arr[0 .. 4], arr[4 .. $]); + assert(p == arr.length - 4); + assert(arr == [ 1, 2, 3, 4, 5, 6, 7 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm.comparison : equal; + import std.container : SList; + import std.range.primitives : popFrontN; + + auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3); + auto r1 = list[]; + auto r2 = list[]; popFrontN(r2, 4); + assert(equal(r2, [ 1, 2, 3 ])); + bringToFront(r1, r2); + assert(equal(list[], [ 1, 2, 3, 4, 5, 6, 7 ])); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm.comparison : equal; + import std.container : SList; + + auto list = SList!(int)(4, 5, 6, 7); + auto vec = [ 1, 2, 3 ]; + bringToFront(list[], vec); + assert(equal(list[], [ 1, 2, 3, 4 ])); + assert(equal(vec, [ 5, 6, 7 ])); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.string : representation; + auto ar = representation("a".dup); + auto br = representation("ç".dup); + + bringToFront(ar, br); + + auto a = cast(char[]) ar; + auto b = cast(char[]) br; + + // Illegal UTF-8 + assert(a == "\303"); + // Illegal UTF-8 + assert(b == "\247a"); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] a = [ 1, 5 ]; + int[] b = [ 9, 8 ]; + int[] buf = new int[](a.length + b.length + 10); + auto rem = a.copy(buf); // copy a into buf + rem = b.copy(rem); // copy b into remainder of buf + assert(buf[0 .. a.length + b.length] == [1, 5, 9, 8]); + assert(rem.length == 10); // unused slots in buf +} + +@safe unittest +{ + import std.algorithm.mutation; + + float[] src = [ 1.0f, 5 ]; + double[] dest = new double[src.length]; + src.copy(dest); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.range; + int[] src = [ 1, 5, 8, 9, 10 ]; + auto dest = new int[](3); + src.take(dest.length).copy(dest); + assert(dest == [ 1, 5, 8 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm.iteration : filter; + int[] src = [ 1, 5, 8, 9, 10, 1, 2, 0 ]; + auto dest = new int[src.length]; + auto rem = src + .filter!(a => (a & 1) == 1) + .copy(dest); + assert(dest[0 .. $ - rem.length] == [ 1, 5, 9, 1 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm, std.range; + int[] src = [1, 2, 4]; + int[] dest = [0, 0, 0, 0, 0]; + src.retro.copy(dest.retro); + assert(dest == [0, 0, 1, 2, 4]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] a = [ 1, 2, 3, 4 ]; + fill(a, 5); + assert(a == [ 5, 5, 5, 5 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] a = [ 1, 2, 3, 4, 5 ]; + int[] b = [ 8, 9 ]; + fill(a, b); + assert(a == [ 8, 9, 8, 9, 8 ]); +} + +@system unittest +{ + import std.algorithm.mutation; + + import core.stdc.stdlib : malloc, free; + + struct S + { + int a = 10; + } + + auto s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5]; + initializeAll(s); + assert(s == [S(10), S(10), S(10), S(10), S(10)]); + + scope(exit) free(s.ptr); +} + +@safe unittest +{ + import std.algorithm.mutation; + + Object obj1 = new Object; + Object obj2 = obj1; + Object obj3; + + move(obj2, obj3); + assert(obj3 is obj1); + // obj2 unchanged + assert(obj2 is obj1); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + // Structs without destructors are simply copied + struct S1 + { + int a = 1; + int b = 2; + } + S1 s11 = { 10, 11 }; + S1 s12; + + move(s11, s12); + + assert(s12 == S1(10, 11)); + assert(s11 == s12); + + // But structs with destructors or postblits are reset to their .init value + // after copying to the target. + struct S2 + { + int a = 1; + int b = 2; + + ~this() pure nothrow @safe @nogc { } + } + S2 s21 = { 3, 4 }; + S2 s22; + + move(s21, s22); + + assert(s21 == S2(1, 2)); + assert(s22 == S2(3, 4)); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + struct S + { + int a = 1; + @disable this(this); + ~this() pure nothrow @safe @nogc {} + } + S s1; + s1.a = 2; + S s2 = move(s1); + assert(s1.a == 1); + assert(s2.a == 2); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + struct S + { + int a; + void opPostMove(const ref S old) + { + assert(a == old.a); + a++; + } + } + S s1; + s1.a = 41; + S s2 = move(s1); + assert(s2.a == 42); +} + +pure nothrow @nogc @system unittest +{ + import std.algorithm.mutation; + + static struct Foo + { + pure nothrow @nogc: + this(int* ptr) { _ptr = ptr; } + ~this() { if (_ptr) ++*_ptr; } + int* _ptr; + } + + int val; + Foo foo1 = void; // uninitialized + auto foo2 = Foo(&val); // initialized + assert(foo2._ptr is &val); + + // Using `move(foo2, foo1)` would have an undefined effect because it would destroy + // the uninitialized foo1. + // moveEmplace directly overwrites foo1 without destroying or initializing it first. + moveEmplace(foo2, foo1); + assert(foo1._ptr is &val); + assert(foo2._ptr is null); + assert(val == 0); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + int[3] a = [ 1, 2, 3 ]; + int[5] b; + assert(moveAll(a[], b[]) is b[3 .. $]); + assert(a[] == b[0 .. 3]); + int[3] cmp = [ 1, 2, 3 ]; + assert(a[] == cmp[]); +} + +pure nothrow @nogc @system unittest +{ + import std.algorithm.mutation; + + static struct Foo + { + ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } + int* _ptr; + } + int[3] refs = [0, 1, 2]; + Foo[3] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2])]; + Foo[5] dst = void; + + auto tail = moveEmplaceAll(src[], dst[]); // move 3 value from src over dst + assert(tail.length == 2); // returns remaining uninitialized values + initializeAll(tail); + + import std.algorithm.searching : all; + assert(src[].all!(e => e._ptr is null)); + assert(dst[0 .. 3].all!(e => e._ptr !is null)); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + int[5] a = [ 1, 2, 3, 4, 5 ]; + int[3] b; + assert(moveSome(a[], b[])[0] is a[3 .. $]); + assert(a[0 .. 3] == b); + assert(a == [ 1, 2, 3, 4, 5 ]); +} + +pure nothrow @nogc @system unittest +{ + import std.algorithm.mutation; + + static struct Foo + { + ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } + int* _ptr; + } + int[4] refs = [0, 1, 2, 3]; + Foo[4] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2]), Foo(&refs[3])]; + Foo[3] dst = void; + + auto res = moveEmplaceSome(src[], dst[]); + assert(res.length == 2); + + import std.algorithm.searching : all; + assert(src[0 .. 3].all!(e => e._ptr is null)); + assert(src[3]._ptr !is null); + assert(dst[].all!(e => e._ptr !is null)); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] a = [0, 1, 2, 3]; + assert(remove!(SwapStrategy.stable)(a, 1) == [0, 2, 3]); + a = [0, 1, 2, 3]; + assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 3, 2]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm.sorting : partition; + + // Put stuff greater than 3 on the left + auto arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert(partition!(a => a > 3, SwapStrategy.stable)(arr) == [1, 2, 3]); + assert(arr == [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]); + + arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert(partition!(a => a > 3, SwapStrategy.semistable)(arr) == [2, 3, 1]); + assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1]); + + arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert(partition!(a => a > 3, SwapStrategy.unstable)(arr) == [3, 2, 1]); + assert(arr == [10, 9, 8, 4, 5, 6, 7, 3, 2, 1]); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + import std.typecons : tuple; + + auto a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.stable)(a, 1) == [ 0, 2, 3, 4, 5 ]); + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.stable)(a, 1, 3) == [ 0, 2, 4, 5] ); + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 6)) == [ 0, 2 ]); + + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 5, 2, 3, 4]); + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4)) == [0, 5, 4]); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + import std.typecons : tuple; + + // Delete an index + assert([4, 5, 6].remove(1) == [4, 6]); + + // Delete multiple indices + assert([4, 5, 6, 7, 8].remove(1, 3) == [4, 6, 8]); + + // Use an indices range + assert([4, 5, 6, 7, 8].remove(tuple(1, 3)) == [4, 7, 8]); + + // Use an indices range and individual indices + assert([4, 5, 6, 7, 8].remove(0, tuple(1, 3), 4) == [7]); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert([5, 6, 7, 8].remove!(SwapStrategy.stable)(1) == [5, 7, 8]); + assert([5, 6, 7, 8].remove!(SwapStrategy.unstable)(1) == [5, 8, 7]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + static immutable base = [1, 2, 3, 2, 4, 2, 5, 2]; + + int[] arr = base[].dup; + + // using a string-based predicate + assert(remove!("a == 2")(arr) == [ 1, 3, 4, 5 ]); + + // The original array contents have been modified, + // so we need to reset it to its original state. + // The length is unmodified however. + arr[] = base[]; + + // using a lambda predicate + assert(remove!(a => a == 2)(arr) == [ 1, 3, 4, 5 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] arr = [ 1, 2, 3 ]; + assert(arr.reverse == [ 3, 2, 1 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + char[] arr = "hello\U00010143\u0100\U00010143".dup; + assert(arr.reverse == "\U00010143\u0100\U00010143olleh"); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".strip(' ') == "foobar"); + assert("00223.444500".strip('0') == "223.4445"); + assert("ëëêéüŗÅpéêëë".strip('ë') == "êéüŗÅpéê"); + assert([1, 1, 0, 1, 1].strip(1) == [0]); + assert([0.0, 0.01, 0.01, 0.0].strip(0).length == 2); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".strip!(a => a == ' ')() == "foobar"); + assert("00223.444500".strip!(a => a == '0')() == "223.4445"); + assert("ëëêéüŗÅpéêëë".strip!(a => a == 'ë')() == "êéüŗÅpéê"); + assert([1, 1, 0, 1, 1].strip!(a => a == 1)() == [0]); + assert([0.0, 0.01, 0.5, 0.6, 0.01, 0.0].strip!(a => a < 0.4)().length == 2); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".stripLeft(' ') == "foobar "); + assert("00223.444500".stripLeft('0') == "223.444500"); + assert("ůůűniçodêéé".stripLeft('ů') == "űniçodêéé"); + assert([1, 1, 0, 1, 1].stripLeft(1) == [0, 1, 1]); + assert([0.0, 0.01, 0.01, 0.0].stripLeft(0).length == 3); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".stripLeft!(a => a == ' ')() == "foobar "); + assert("00223.444500".stripLeft!(a => a == '0')() == "223.444500"); + assert("ůůűniçodêéé".stripLeft!(a => a == 'ů')() == "űniçodêéé"); + assert([1, 1, 0, 1, 1].stripLeft!(a => a == 1)() == [0, 1, 1]); + assert([0.0, 0.01, 0.10, 0.5, 0.6].stripLeft!(a => a < 0.4)().length == 2); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".stripRight(' ') == " foobar"); + assert("00223.444500".stripRight('0') == "00223.4445"); + assert("ùniçodêéé".stripRight('é') == "ùniçodê"); + assert([1, 1, 0, 1, 1].stripRight(1) == [1, 1, 0]); + assert([0.0, 0.01, 0.01, 0.0].stripRight(0).length == 3); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".stripRight!(a => a == ' ')() == " foobar"); + assert("00223.444500".stripRight!(a => a == '0')() == "00223.4445"); + assert("ùniçodêéé".stripRight!(a => a == 'é')() == "ùniçodê"); + assert([1, 1, 0, 1, 1].stripRight!(a => a == 1)() == [1, 1, 0]); + assert([0.0, 0.01, 0.10, 0.5, 0.6].stripRight!(a => a > 0.4)().length == 3); +} + +@safe unittest +{ + import std.algorithm.mutation; + + // Swapping POD (plain old data) types: + int a = 42, b = 34; + swap(a, b); + assert(a == 34 && b == 42); + + // Swapping structs with indirection: + static struct S { int x; char c; int[] y; } + S s1 = { 0, 'z', [ 1, 2 ] }; + S s2 = { 42, 'a', [ 4, 6 ] }; + swap(s1, s2); + assert(s1.x == 42); + assert(s1.c == 'a'); + assert(s1.y == [ 4, 6 ]); + + assert(s2.x == 0); + assert(s2.c == 'z'); + assert(s2.y == [ 1, 2 ]); + + // Immutables cannot be swapped: + immutable int imm1 = 1, imm2 = 2; + static assert(!__traits(compiles, swap(imm1, imm2))); + + int c = imm1 + 0; + int d = imm2 + 0; + swap(c, d); + assert(c == 2); + assert(d == 1); +} + +@safe unittest +{ + import std.algorithm.mutation; + + // Non-copyable types can still be swapped. + static struct NoCopy + { + this(this) { assert(0); } + int n; + string s; + } + NoCopy nc1, nc2; + nc1.n = 127; nc1.s = "abc"; + nc2.n = 513; nc2.s = "uvwxyz"; + + swap(nc1, nc2); + assert(nc1.n == 513 && nc1.s == "uvwxyz"); + assert(nc2.n == 127 && nc2.s == "abc"); + + swap(nc1, nc1); + swap(nc2, nc2); + assert(nc1.n == 513 && nc1.s == "uvwxyz"); + assert(nc2.n == 127 && nc2.s == "abc"); + + // Types containing non-copyable fields can also be swapped. + static struct NoCopyHolder + { + NoCopy noCopy; + } + NoCopyHolder h1, h2; + h1.noCopy.n = 31; h1.noCopy.s = "abc"; + h2.noCopy.n = 65; h2.noCopy.s = null; + + swap(h1, h2); + assert(h1.noCopy.n == 65 && h1.noCopy.s == null); + assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); + + swap(h1, h1); + swap(h2, h2); + assert(h1.noCopy.n == 65 && h1.noCopy.s == null); + assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); + + // Const types cannot be swapped. + const NoCopy const1, const2; + assert(const1.n == 0 && const2.n == 0); + static assert(!__traits(compiles, swap(const1, const2))); +} + +pure @safe nothrow unittest +{ + import std.algorithm.mutation; + + import std.algorithm.comparison : equal; + auto a = [1, 2, 3]; + a.swapAt(1, 2); + assert(a.equal([1, 3, 2])); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.range : empty; + int[] a = [ 100, 101, 102, 103 ]; + int[] b = [ 0, 1, 2, 3 ]; + auto c = swapRanges(a[1 .. 3], b[2 .. 4]); + assert(c[0].empty && c[1].empty); + assert(a == [ 100, 2, 3, 103 ]); + assert(b == [ 0, 1, 101, 102 ]); +} + +nothrow @system unittest +{ + import std.algorithm.mutation; + + import core.stdc.stdlib : malloc, free; + + auto s = (cast(int*) malloc(5 * int.sizeof))[0 .. 5]; + uninitializedFill(s, 42); + assert(s == [ 42, 42, 42, 42, 42 ]); + + scope(exit) free(s.ptr); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_searching.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_searching.d new file mode 100644 index 0000000000000000000000000000000000000000..fd09d0abcd442e77cab2e212fda39eb04b7995de --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_searching.d @@ -0,0 +1,668 @@ +@safe unittest +{ + import std.algorithm.searching; + + assert( all!"a & 1"([1, 3, 5, 7, 9])); + assert(!all!"a & 1"([1, 2, 3, 5, 7, 9])); +} + +@safe unittest +{ + import std.algorithm.searching; + + int[3] vals = [5, 3, 18]; + assert( all(vals[])); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isWhite; + assert( all!(any!isWhite)(["a a", "b b"])); + assert(!any!(all!isWhite)(["a a", "b b"])); +} + +@safe unittest +{ + import std.algorithm.searching; + + int[3] vals1 = [0, 0, 0]; + assert(!any(vals1[])); //none of vals1 evaluate to true + + int[3] vals2 = [2, 0, 2]; + assert( any(vals2[])); + assert(!all(vals2[])); + + int[3] vals3 = [3, 3, 3]; + assert( any(vals3[])); + assert( all(vals3[])); +} + +@safe pure unittest +{ + import std.algorithm.searching; + + auto s = "1 + (2 * (3 + 1 / 2)"; + assert(!balancedParens(s, '(', ')')); + s = "1 + (2 * (3 + 1) / 2)"; + assert(balancedParens(s, '(', ')')); + s = "1 + (2 * (3 + 1) / 2)"; + assert(!balancedParens(s, '(', ')', 0)); + s = "1 + (2 * 3 + 1) / (2 - 5)"; + assert(balancedParens(s, '(', ')', 0)); + s = "f(x) = ⌈x⌉"; + assert(balancedParens(s, '⌈', '⌉')); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + auto bmFinder = boyerMooreFinder("TG"); + + string r = "TAGTGCCTGA"; + // search for the first match in the haystack r + r = bmFinder.beFound(r); + assert(r == "TGCCTGA"); + + // continue search in haystack + r = bmFinder.beFound(r[2 .. $]); + assert(r == "TGA"); +} + +@safe unittest +{ + import std.algorithm.searching; + + assert(commonPrefix("hello, world", "hello, there") == "hello, "); +} + +@safe unittest +{ + import std.algorithm.searching; + + // count elements in range + int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; + assert(count(a, 2) == 3); + assert(count!("a > b")(a, 2) == 5); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.uni : toLower; + // count range in range + assert(count("abcadfabf", "ab") == 2); + assert(count("ababab", "abab") == 1); + assert(count("ababab", "abx") == 0); + // fuzzy count range in range + assert(count!((a, b) => toLower(a) == toLower(b))("AbcAdFaBf", "ab") == 2); +} + +@safe unittest +{ + import std.algorithm.searching; + + // count elements in range + int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; + assert(count(a) == 9); + // count predicate in range + assert(count!("a > 2")(a) == 5); +} + +@safe unittest +{ + import std.algorithm.searching; + + assert(countUntil("hello world", "world") == 6); + assert(countUntil("hello world", 'r') == 8); + assert(countUntil("hello world", "programming") == -1); + assert(countUntil("日本語", "本語") == 1); + assert(countUntil("日本語", '語') == 2); + assert(countUntil("日本語", "五") == -1); + assert(countUntil("日本語", '五') == -1); + assert(countUntil([0, 7, 12, 22, 9], [12, 22]) == 2); + assert(countUntil([0, 7, 12, 22, 9], 9) == 4); + assert(countUntil!"a > b"([0, 7, 12, 22, 9], 20) == 3); + + // supports multiple needles + auto res = "...hello".countUntil("ha", "he"); + assert(res.steps == 3); + assert(res.needle == 1); + + // returns -1 if no needle was found + res = "hello".countUntil("ha", "hu"); + assert(res.steps == -1); + assert(res.needle == -1); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isDigit; + import std.uni : isWhite; + + assert(countUntil!(isWhite)("hello world") == 5); + assert(countUntil!(isDigit)("hello world") == -1); + assert(countUntil!"a > 20"([0, 7, 12, 22, 9]) == 3); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isAlpha; + assert("abc".endsWith!(a => a.isAlpha)); + assert("abc".endsWith!isAlpha); + + assert(!"ab1".endsWith!(a => a.isAlpha)); + + assert(!"ab1".endsWith!isAlpha); + assert(!"".endsWith!(a => a.isAlpha)); + + import std.algorithm.comparison : among; + assert("abc".endsWith!(a => a.among('c', 'd') != 0)); + assert(!"abc".endsWith!(a => a.among('a', 'b') != 0)); + + assert(endsWith("abc", "")); + assert(!endsWith("abc", "b")); + assert(endsWith("abc", "a", 'c') == 2); + assert(endsWith("abc", "c", "a") == 1); + assert(endsWith("abc", "c", "c") == 1); + assert(endsWith("abc", "bc", "c") == 2); + assert(endsWith("abc", "x", "c", "b") == 2); + assert(endsWith("abc", "x", "aa", "bc") == 3); + assert(endsWith("abc", "x", "aaa", "sab") == 0); + assert(endsWith("abc", "x", "aaa", 'c', "sab") == 3); +} + +@safe unittest +{ + import std.algorithm.searching; + + auto arr = [ 1, 2, 3, 4, 1 ]; + assert(find!("a > 2")(arr) == [ 3, 4, 1 ]); + + // with predicate alias + bool pred(int e) => e + 1 > 1.5; + assert(find!(pred)(arr) == arr); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.range.primitives; + + auto arr = [1, 2, 4, 4, 4, 4, 5, 6, 9]; + assert(arr.find(4) == [4, 4, 4, 4, 5, 6, 9]); + assert(arr.find(1) == arr); + assert(arr.find(9) == [9]); + assert(arr.find!((e, n) => e > n)(4) == [5, 6, 9]); + assert(arr.find!((e, n) => e < n)(4) == arr); + assert(arr.find(0).empty); + assert(arr.find(10).empty); + assert(arr.find(8).empty); + + assert(find("hello, world", ',') == ", world"); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.range.primitives; + import std.uni : toLower; + + string[] s = ["Hello", "world", "!"]; + assert(s.find!((e, n) => toLower(e) == n)("hello") == s); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.container : SList; + import std.range.primitives : empty; + import std.typecons : Tuple; + + assert(find("hello, world", "World").empty); + assert(find("hello, world", "wo") == "world"); + assert([1, 2, 3, 4].find(SList!int(2, 3)[]) == [2, 3, 4]); + alias C = Tuple!(int, "x", int, "y"); + auto a = [C(1,0), C(2,0), C(3,1), C(4,0)]; + assert(a.find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]); + assert(a[1 .. $].find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.typecons : tuple; + int[] a = [ 1, 4, 2, 3 ]; + assert(find(a, 4) == [ 4, 2, 3 ]); + assert(find(a, [ 1, 4 ]) == [ 1, 4, 2, 3 ]); + assert(find(a, [ 1, 3 ], 4) == tuple([ 4, 2, 3 ], 2)); + // Mixed types allowed if comparable + assert(find(a, 5, [ 1.2, 3.5 ], 2.0) == tuple([ 2, 3 ], 3)); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.range.primitives : empty; + int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; + int[] b = [ 1, 2, 3 ]; + + assert(find(a, boyerMooreFinder(b)) == [ 1, 2, 3, 4, 5 ]); + assert(find(b, boyerMooreFinder(a)).empty); +} + +@safe unittest +{ + import std.algorithm.searching; + + const arr = [0, 1, 2, 3]; + assert(canFind(arr, 2)); + assert(!canFind(arr, 4)); + + // find one of several needles + assert(arr.canFind(3, 2)); + assert(arr.canFind(3, 2) == 2); // second needle found + assert(arr.canFind([1, 3], 2) == 2); + + assert(canFind(arr, [1, 2], [2, 3])); + assert(canFind(arr, [1, 2], [2, 3]) == 1); + assert(canFind(arr, [1, 7], [2, 3])); + assert(canFind(arr, [1, 7], [2, 3]) == 2); + assert(!canFind(arr, [1, 3], [2, 4])); + assert(canFind(arr, [1, 3], [2, 4]) == 0); +} + +@safe unittest +{ + import std.algorithm.searching; + + auto words = [ + "apple", + "beeswax", + "cardboard" + ]; + assert(!canFind(words, "bees")); + assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees")); +} + +@safe unittest +{ + import std.algorithm.searching; + + string s1 = "aaa111aaa"; + string s2 = "aaa222aaa"; + string s3 = "aaa333aaa"; + string s4 = "aaa444aaa"; + const hay = [s1, s2, s3, s4]; + assert(hay.canFind!(e => e.canFind("111", "222"))); +} + +@safe unittest +{ + import std.algorithm.searching; + + int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ]; + auto r = findAdjacent(a); + assert(r == [ 10, 10, 9, 8, 8, 7, 8, 9 ]); + auto p = findAdjacent!("a < b")(a); + assert(p == [ 7, 8, 9 ]); + +} + +@safe unittest +{ + import std.algorithm.searching; + + int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; + int[] b = [ 3, 1, 2 ]; + assert(findAmong(a, b) == a[2 .. $]); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.range.primitives : empty; + // Needle is found; s is replaced by the substring following the first + // occurrence of the needle. + string s = "abcdef"; + assert(findSkip(s, "cd") && s == "ef"); + + // Needle is not found; s is left untouched. + s = "abcdef"; + assert(!findSkip(s, "cxd") && s == "abcdef"); + + // If the needle occurs at the end of the range, the range is left empty. + s = "abcdef"; + assert(findSkip(s, "def") && s.empty); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isWhite; + string s = " abc"; + assert(findSkip!isWhite(s) && s == "abc"); + assert(!findSkip!isWhite(s) && s == "abc"); + + s = " "; + assert(findSkip!isWhite(s) == 2); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + // findSplit returns a triplet + if (auto split = "dlang-rocks".findSplit("-")) + { + assert(split[0] == "dlang"); + assert(split[1] == "-"); + assert(split[2] == "rocks"); + } + else assert(0); + + // findSplitBefore returns 2 ranges + if (const split = [2, 3, 2, 3, 4, 1].findSplitBefore!"a > b"([2, 2])) + { + assert(split[0] == [2, 3, 2]); + // [3, 4] each greater than [2, 2] + assert(split[1] == [3, 4, 1]); + } + else assert(0); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + import std.range.primitives : empty; + + auto a = "Carl Sagan Memorial Station"; + auto r = findSplit(a, "Velikovsky"); + import std.typecons : isTuple; + static assert(isTuple!(typeof(r.asTuple))); + static assert(isTuple!(typeof(r))); + assert(!r); + assert(r[0] == a); + assert(r[1].empty); + assert(r[2].empty); + r = findSplit(a, " "); + assert(r[0] == "Carl"); + assert(r[1] == " "); + assert(r[2] == "Sagan Memorial Station"); + if (const r1 = findSplitBefore(a, "Sagan")) + { + assert(r1); + assert(r1[0] == "Carl "); + assert(r1[1] == "Sagan Memorial Station"); + } + if (const r2 = findSplitAfter(a, "Sagan")) + { + assert(r2); + assert(r2[0] == "Carl Sagan"); + assert(r2[1] == " Memorial Station"); + } +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + import std.range : only; + assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.conv : text; + import std.typecons : tuple; + + int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; + // Minimum is 1 and occurs 3 times + assert(a.minCount == tuple(1, 3)); + // Maximum is 4 and occurs 2 times + assert(a.maxCount == tuple(4, 2)); +} + +@safe pure unittest +{ + import std.algorithm.searching; + + import std.range : enumerate; + import std.typecons : tuple; + + assert([2, 7, 1, 3].minElement == 1); + + // allows to get the index of an element too + assert([5, 3, 7, 9].enumerate.minElement!"a.value" == tuple(1, 3)); + + // any custom accessor can be passed + assert([[0, 4], [1, 2]].minElement!"a[1]" == [1, 2]); + + // can be seeded + int[] arr; + assert(arr.minElement(1) == 1); +} + +@safe pure unittest +{ + import std.algorithm.searching; + + import std.range : enumerate; + import std.typecons : tuple; + assert([2, 1, 4, 3].maxElement == 4); + + // allows to get the index of an element too + assert([2, 1, 4, 3].enumerate.maxElement!"a.value" == tuple(2, 4)); + + // any custom accessor can be passed + assert([[0, 4], [1, 2]].maxElement!"a[1]" == [0, 4]); + + // can be seeded + int[] arr; + assert(arr.minElement(1) == 1); +} + +@safe unittest +{ + import std.algorithm.searching; + + assert(extrema([5,2,9,4,1]) == [1, 9]); +} + +@safe unittest +{ + import std.algorithm.searching; + + int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; + // Minimum is 1 and first occurs in position 3 + assert(a.minPos == [ 1, 2, 4, 1, 1, 2 ]); + // Maximum is 4 and first occurs in position 2 + assert(a.maxPos == [ 4, 1, 2, 4, 1, 1, 2 ]); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2]; + + // Minimum is 1 and first occurs in position 3 + assert(a.minIndex == 3); + // Get maximum index with minIndex + assert(a.minIndex!"a > b" == 2); + + // Range is empty, so return value is -1 + int[] b; + assert(b.minIndex == -1); + + // Works with more custom types + struct Dog { int age; } + Dog[] dogs = [Dog(10), Dog(5), Dog(15)]; + assert(dogs.minIndex!"a.age < b.age" == 1); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + // Maximum is 4 and first occurs in position 2 + int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2]; + assert(a.maxIndex == 2); + + // Empty range + int[] b; + assert(b.maxIndex == -1); + + // Works with more custom types + struct Dog { int age; } + Dog[] dogs = [Dog(10), Dog(15), Dog(5)]; + assert(dogs.maxIndex!"a.age < b.age" == 1); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.algorithm.comparison : equal; + + auto s1 = "Hello world"; + assert(!skipOver(s1, "Ha")); + assert(s1 == "Hello world"); + assert(skipOver(s1, "Hell") && s1 == "o world", s1); + + string[] r1 = ["abc", "def", "hij"]; + dstring[] r2 = ["abc"d]; + assert(!skipOver!((a, b) => a.equal(b))(r1, ["def"d]), r1[0]); + assert(r1 == ["abc", "def", "hij"]); + assert(skipOver!((a, b) => a.equal(b))(r1, r2)); + assert(r1 == ["def", "hij"]); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isWhite; + import std.range.primitives : empty; + + auto s2 = "\t\tvalue"; + auto s3 = ""; + auto s4 = "\t\t\t"; + assert(s2.skipOver!isWhite && s2 == "value"); + assert(!s3.skipOver!isWhite); + assert(s4.skipOver!isWhite && s3.empty); +} + +@safe unittest +{ + import std.algorithm.searching; + + auto s = "Hello world"; + assert(!skipOver(s, "hello", "HellO")); + assert(s == "Hello world"); + + // the range is skipped over the longest matching needle is skipped + assert(skipOver(s, "foo", "hell", "Hello ")); + assert(s == "world"); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.algorithm.comparison : equal; + + auto s1 = "Hello world"; + assert(!skipOver(s1, 'a')); + assert(s1 == "Hello world"); + assert(skipOver(s1, 'H') && s1 == "ello world"); + + string[] r = ["abc", "def", "hij"]; + dstring e = "abc"d; + assert(!skipOver!((a, b) => a.equal(b))(r, "def"d)); + assert(r == ["abc", "def", "hij"]); + assert(skipOver!((a, b) => a.equal(b))(r, e)); + assert(r == ["def", "hij"]); + + auto s2 = ""; + assert(!s2.skipOver('a')); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isWhite; + import std.range.primitives : empty; + + alias whitespaceSkiper = skipOver!isWhite; + + auto s2 = "\t\tvalue"; + auto s3 = ""; + auto s4 = "\t\t\t"; + assert(whitespaceSkiper(s2) && s2 == "value"); + assert(!whitespaceSkiper(s2)); + assert(whitespaceSkiper(s4) && s3.empty); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isAlpha; + + assert("abc".startsWith!(a => a.isAlpha)); + assert("abc".startsWith!isAlpha); + assert(!"1ab".startsWith!(a => a.isAlpha)); + assert(!"".startsWith!(a => a.isAlpha)); + + import std.algorithm.comparison : among; + assert("abc".startsWith!(a => a.among('a', 'b') != 0)); + assert(!"abc".startsWith!(a => a.among('b', 'c') != 0)); + + assert(startsWith("abc", "")); + assert(startsWith("abc", "a")); + assert(!startsWith("abc", "b")); + assert(startsWith("abc", 'a', "b") == 1); + assert(startsWith("abc", "b", "a") == 2); + assert(startsWith("abc", "a", "a") == 1); + assert(startsWith("abc", "ab", "a") == 2); + assert(startsWith("abc", "x", "a", "b") == 2); + assert(startsWith("abc", "x", "aa", "ab") == 3); + assert(startsWith("abc", "x", "aaa", "sab") == 0); + assert(startsWith("abc", "x", "aaa", "a", "sab") == 3); + + import std.typecons : Tuple; + alias C = Tuple!(int, "x", int, "y"); + assert(startsWith!"a.x == b"([ C(1,1), C(1,2), C(2,2) ], [1, 1])); + assert(startsWith!"a.x == b"([ C(1,1), C(2,1), C(2,2) ], [1, 1], [1, 2], [1, 3]) == 2); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.algorithm.comparison : equal; + import std.typecons : No; + int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5]; + assert(equal(a.until(7), [1, 2, 4])); + assert(equal(a.until(7, No.openRight), [1, 2, 4, 7])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_setops.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_setops.d new file mode 100644 index 0000000000000000000000000000000000000000..ecbfc5857a87fe22c0b249d105078985f4b319d9 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_setops.d @@ -0,0 +1,281 @@ +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.searching : canFind; + import std.range; + import std.typecons : tuple; + + auto N = sequence!"n"(0); // the range of natural numbers + auto N2 = cartesianProduct(N, N); // the range of all pairs of natural numbers + + // Various arbitrary number pairs can be found in the range in finite time. + assert(canFind(N2, tuple(0, 0))); + assert(canFind(N2, tuple(123, 321))); + assert(canFind(N2, tuple(11, 35))); + assert(canFind(N2, tuple(279, 172))); +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.searching : canFind; + import std.typecons : tuple; + + auto B = [ 1, 2, 3 ]; + auto C = [ 4, 5, 6 ]; + auto BC = cartesianProduct(B, C); + + foreach (n; [[1, 4], [2, 4], [3, 4], [1, 5], [2, 5], [3, 5], [1, 6], + [2, 6], [3, 6]]) + { + assert(canFind(BC, tuple(n[0], n[1]))); + } +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + import std.typecons : tuple; + + auto A = [ 1, 2, 3 ]; + auto B = [ 'a', 'b', 'c' ]; + auto C = [ "x", "y", "z" ]; + auto ABC = cartesianProduct(A, B, C); + + assert(ABC.equal([ + tuple(1, 'a', "x"), tuple(1, 'a', "y"), tuple(1, 'a', "z"), + tuple(1, 'b', "x"), tuple(1, 'b', "y"), tuple(1, 'b', "z"), + tuple(1, 'c', "x"), tuple(1, 'c', "y"), tuple(1, 'c', "z"), + tuple(2, 'a', "x"), tuple(2, 'a', "y"), tuple(2, 'a', "z"), + tuple(2, 'b', "x"), tuple(2, 'b', "y"), tuple(2, 'b', "z"), + tuple(2, 'c', "x"), tuple(2, 'c', "y"), tuple(2, 'c', "z"), + tuple(3, 'a', "x"), tuple(3, 'a', "y"), tuple(3, 'a', "z"), + tuple(3, 'b', "x"), tuple(3, 'b', "y"), tuple(3, 'b', "z"), + tuple(3, 'c', "x"), tuple(3, 'c', "y"), tuple(3, 'c', "z") + ])); +} + +@system unittest +{ + import std.algorithm.setops; + + import std.typecons : tuple, Tuple; + + // Figure which number can be found in most arrays of the set of + // arrays below. + double[][] a = + [ + [ 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + auto b = new Tuple!(double, uint)[1]; + // it will modify the input range, hence we need to create a duplicate + largestPartialIntersection(a.dup, b); + // First member is the item, second is the occurrence count + assert(b[0] == tuple(7.0, 4u)); + // 7.0 occurs in 4 out of 5 inputs, more than any other number + + // If more of the top-frequent numbers are needed, just create a larger + // tgt range + auto c = new Tuple!(double, uint)[2]; + largestPartialIntersection(a, c); + assert(c[0] == tuple(1.0, 3u)); + // 1.0 occurs in 3 inputs + + // multiset + double[][] x = + [ + [1, 1, 1, 1, 4, 7, 8], + [1, 7], + [1, 7, 8], + [4, 7], + [7] + ]; + auto y = new Tuple!(double, uint)[2]; + largestPartialIntersection(x.dup, y); + // 7.0 occurs 5 times + assert(y[0] == tuple(7.0, 5u)); + // 1.0 occurs 6 times + assert(y[1] == tuple(1.0, 6u)); +} + +@system unittest +{ + import std.algorithm.setops; + + import std.typecons : tuple, Tuple; + + // Figure which number can be found in most arrays of the set of + // arrays below, with specific per-element weights + double[][] a = + [ + [ 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + auto b = new Tuple!(double, uint)[1]; + double[double] weights = [ 1:1.2, 4:2.3, 7:1.1, 8:1.1 ]; + largestPartialIntersectionWeighted(a, b, weights); + // First member is the item, second is the occurrence count + assert(b[0] == tuple(4.0, 2u)); + // 4.0 occurs 2 times -> 4.6 (2 * 2.3) + // 7.0 occurs 3 times -> 4.4 (3 * 1.1) + + // multiset + double[][] x = + [ + [ 1, 1, 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + auto y = new Tuple!(double, uint)[1]; + largestPartialIntersectionWeighted(x, y, weights); + assert(y[0] == tuple(1.0, 5u)); + // 1.0 occurs 5 times -> 1.2 * 5 = 6 +} + +@system unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + + double[][] a = + [ + [ 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + auto witness = [ + 1, 1, 1, 4, 4, 7, 7, 7, 7, 8, 8 + ]; + assert(equal(multiwayMerge(a), witness)); + + double[][] b = + [ + // range with duplicates + [ 1, 1, 4, 7, 8 ], + [ 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + // duplicates are propagated to the resulting range + assert(equal(multiwayMerge(b), witness)); +} + +@system unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + + // sets + double[][] a = + [ + [ 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + + auto witness = [1, 4, 7, 8]; + assert(equal(multiwayUnion(a), witness)); + + // multisets + double[][] b = + [ + [ 1, 1, 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 7, 8], + [ 4 ], + [ 7 ], + ]; + assert(equal(multiwayUnion(b), witness)); + + double[][] c = + [ + [9, 8, 8, 8, 7, 6], + [9, 8, 6], + [9, 8, 5] + ]; + auto witness2 = [9, 8, 7, 6, 5]; + assert(equal(multiwayUnion!"a > b"(c), witness2)); +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + import std.range.primitives : isForwardRange; + + //sets + int[] a = [ 1, 2, 4, 5, 7, 9 ]; + int[] b = [ 0, 1, 2, 4, 7, 8 ]; + assert(equal(setDifference(a, b), [5, 9])); + static assert(isForwardRange!(typeof(setDifference(a, b)))); + + // multisets + int[] x = [1, 1, 1, 2, 3]; + int[] y = [1, 1, 2, 4, 5]; + auto r = setDifference(x, y); + assert(equal(r, [1, 3])); + assert(setDifference(r, x).empty); +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + + // sets + int[] a = [ 1, 2, 4, 5, 7, 9 ]; + int[] b = [ 0, 1, 2, 4, 7, 8 ]; + int[] c = [ 0, 1, 4, 5, 7, 8 ]; + assert(equal(setIntersection(a, a), a)); + assert(equal(setIntersection(a, b), [1, 2, 4, 7])); + assert(equal(setIntersection(a, b, c), [1, 4, 7])); + + // multisets + int[] d = [ 1, 1, 2, 2, 7, 7 ]; + int[] e = [ 1, 1, 1, 7]; + assert(equal(setIntersection(a, d), [1, 2, 7])); + assert(equal(setIntersection(d, e), [1, 1, 7])); +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + import std.range.primitives : isForwardRange; + + // sets + int[] a = [ 1, 2, 4, 5, 7, 9 ]; + int[] b = [ 0, 1, 2, 4, 7, 8 ]; + assert(equal(setSymmetricDifference(a, b), [0, 5, 8, 9][])); + static assert(isForwardRange!(typeof(setSymmetricDifference(a, b)))); + + //mutisets + int[] c = [1, 1, 1, 1, 2, 2, 2, 4, 5, 6]; + int[] d = [1, 1, 2, 2, 2, 2, 4, 7, 9]; + assert(equal(setSymmetricDifference(c, d), setSymmetricDifference(d, c))); + assert(equal(setSymmetricDifference(c, d), [1, 1, 2, 5, 6, 7, 9])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_sorting.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_sorting.d new file mode 100644 index 0000000000000000000000000000000000000000..df4bca62761ab43d6d7710f1ebff6f36f9d29cb0 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_sorting.d @@ -0,0 +1,462 @@ +@safe unittest +{ + import std.algorithm.sorting; + + import std.range : assumeSorted; + int[] a = [ 1, 2, 3 ]; + int[] b = [ 4, 0, 6, 5 ]; + completeSort(assumeSorted(a), b); + assert(a == [ 0, 1, 2 ]); + assert(b == [ 3, 4, 5, 6 ]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + assert([1, 1, 2].isSorted); + // strictly monotonic doesn't allow duplicates + assert(![1, 1, 2].isStrictlyMonotonic); + + int[] arr = [4, 3, 2, 1]; + assert(!isSorted(arr)); + assert(!isStrictlyMonotonic(arr)); + + assert(isSorted!"a > b"(arr)); + assert(isStrictlyMonotonic!"a > b"(arr)); + + sort(arr); + assert(isSorted(arr)); + assert(isStrictlyMonotonic(arr)); +} + +@safe unittest +{ + import std.algorithm.sorting; + + assert(ordered(42, 42, 43)); + assert(!strictlyOrdered(43, 42, 45)); + assert(ordered(42, 42, 43)); + assert(!strictlyOrdered(42, 42, 43)); + assert(!ordered(43, 42, 45)); + // Ordered lexicographically + assert(ordered("Jane", "Jim", "Joe")); + assert(strictlyOrdered("Jane", "Jim", "Joe")); + // Incidentally also ordered by length decreasing + assert(ordered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe")); + // ... but not strictly so: "Jim" and "Joe" have the same length + assert(!strictlyOrdered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe")); +} + +@safe unittest +{ + import std.algorithm.sorting; + + import std.algorithm.mutation : SwapStrategy; + import std.algorithm.searching : count, find; + import std.conv : text; + import std.range.primitives : empty; + + auto Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + auto arr = Arr.dup; + static bool even(int a) { return (a & 1) == 0; } + // Partition arr such that even numbers come first + auto r = partition!(even)(arr); + // Now arr is separated in evens and odds. + // Numbers may have become shuffled due to instability + assert(r == arr[5 .. $]); + assert(count!(even)(arr[0 .. 5]) == 5); + assert(find!(even)(r).empty); + + // Can also specify the predicate as a string. + // Use 'a' as the predicate argument name + arr[] = Arr[]; + r = partition!(q{(a & 1) == 0})(arr); + assert(r == arr[5 .. $]); + + // Now for a stable partition: + arr[] = Arr[]; + r = partition!(q{(a & 1) == 0}, SwapStrategy.stable)(arr); + // Now arr is [2 4 6 8 10 1 3 5 7 9], and r points to 1 + assert(arr == [2, 4, 6, 8, 10, 1, 3, 5, 7, 9] && r == arr[5 .. $]); + + // In case the predicate needs to hold its own state, use a delegate: + arr[] = Arr[]; + int x = 3; + // Put stuff greater than 3 on the left + bool fun(int a) { return a > x; } + r = partition!(fun, SwapStrategy.semistable)(arr); + // Now arr is [4 5 6 7 8 9 10 2 3 1] and r points to 2 + assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1] && r == arr[7 .. $]); +} + +@safe nothrow unittest +{ + import std.algorithm.sorting; + + int[] a = [5, 3, 2, 6, 4, 1, 3, 7]; + size_t pivot = pivotPartition(a, a.length / 2); + import std.algorithm.searching : all; + assert(a[0 .. pivot].all!(x => x <= a[pivot])); + assert(a[pivot .. $].all!(x => x >= a[pivot])); +} + +@safe unittest +{ + import std.algorithm.sorting; + + int[] r = [ 1, 3, 5, 7, 8, 2, 4, ]; + assert(isPartitioned!"a & 1"(r)); +} + +@safe unittest +{ + import std.algorithm.sorting; + + auto a = [ 8, 3, 4, 1, 4, 7, 4 ]; + auto pieces = partition3(a, 4); + assert(pieces[0] == [ 1, 3 ]); + assert(pieces[1] == [ 4, 4, 4 ]); + assert(pieces[2] == [ 8, 7 ]); +} + +@system unittest +{ + import std.algorithm.sorting; + + immutable(int[]) arr = [ 2, 3, 1, 5, 0 ]; + // index using pointers + auto index1 = new immutable(int)*[arr.length]; + makeIndex!("a < b")(arr, index1); + assert(isSorted!("*a < *b")(index1)); + // index using offsets + auto index2 = new size_t[arr.length]; + makeIndex!("a < b")(arr, index2); + assert(isSorted! + ((size_t a, size_t b){ return arr[a] < arr[b];}) + (index2)); +} + +@safe pure nothrow unittest +{ + import std.algorithm.sorting; + + import std.algorithm.comparison : equal; + import std.range : retro; + + int[] a = [1, 3, 5]; + int[] b = [2, 3, 4]; + + assert(a.merge(b).equal([1, 2, 3, 3, 4, 5])); + assert(a.merge(b).retro.equal([5, 4, 3, 3, 2, 1])); +} + +@safe pure nothrow unittest +{ + import std.algorithm.sorting; + + import std.algorithm.comparison : equal; + import std.range : retro; + import std.traits : CommonType; + + alias S = short; + alias I = int; + alias D = double; + + S[] a = [1, 2, 3]; + I[] b = [50, 60]; + D[] c = [10, 20, 30, 40]; + + auto m = merge(a, b, c); + + static assert(is(typeof(m.front) == CommonType!(S, I, D))); + + assert(equal(m, [1, 2, 3, 10, 20, 30, 40, 50, 60])); + assert(equal(m.retro, [60, 50, 40, 30, 20, 10, 3, 2, 1])); + + m.popFront(); + assert(equal(m, [2, 3, 10, 20, 30, 40, 50, 60])); + m.popBack(); + assert(equal(m, [2, 3, 10, 20, 30, 40, 50])); + m.popFront(); + assert(equal(m, [3, 10, 20, 30, 40, 50])); + m.popBack(); + assert(equal(m, [3, 10, 20, 30, 40])); + m.popFront(); + assert(equal(m, [10, 20, 30, 40])); + m.popBack(); + assert(equal(m, [10, 20, 30])); + m.popFront(); + assert(equal(m, [20, 30])); + m.popBack(); + assert(equal(m, [20])); + m.popFront(); + assert(m.empty); +} + +@safe unittest +{ + import std.algorithm.sorting; + + import std.algorithm.mutation : SwapStrategy; + static struct Point { int x, y; } + auto pts1 = [ Point(0, 0), Point(5, 5), Point(0, 1), Point(0, 2) ]; + auto pts2 = [ Point(0, 0), Point(0, 1), Point(0, 2), Point(5, 5) ]; + multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts1); + assert(pts1 == pts2); +} + +@safe pure nothrow unittest +{ + import std.algorithm.sorting; + + int[] array = [ 1, 2, 3, 4 ]; + + // sort in descending order + array.sort!("a > b"); + assert(array == [ 4, 3, 2, 1 ]); + + // sort in ascending order + array.sort(); + assert(array == [ 1, 2, 3, 4 ]); + + // sort with reusable comparator and chain + alias myComp = (x, y) => x > y; + assert(array.sort!(myComp).release == [ 4, 3, 2, 1 ]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Showcase stable sorting + import std.algorithm.mutation : SwapStrategy; + string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ]; + sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words); + assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Sorting floating-point numbers in presence of NaN + double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan]; + + import std.algorithm.comparison : equal; + import std.math.operations : cmp; + import std.math.traits : isIdentical; + + sort!((a, b) => cmp(a, b) < 0)(numbers); + + double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan]; + assert(numbers.equal!isIdentical(sorted)); +} + +@safe pure unittest +{ + import std.algorithm.sorting; + + import std.algorithm.iteration : map; + import std.numeric : entropy; + + auto lowEnt = [ 1.0, 0, 0 ], + midEnt = [ 0.1, 0.1, 0.8 ], + highEnt = [ 0.31, 0.29, 0.4 ]; + auto arr = new double[][3]; + arr[0] = midEnt; + arr[1] = lowEnt; + arr[2] = highEnt; + + schwartzSort!(entropy, "a > b")(arr); + + assert(arr[0] == highEnt); + assert(arr[1] == midEnt); + assert(arr[2] == lowEnt); + assert(isSorted!("a > b")(map!(entropy)(arr))); +} + +@system unittest +{ + import std.algorithm.sorting; + + int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]; + partialSort(a, 5); + assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]); +} + +@system unittest +{ + import std.algorithm.sorting; + + int[] a = [5, 7, 2, 6, 7]; + int[] b = [2, 1, 5, 6, 7, 3, 0]; + + partialSort(a, b); + assert(a == [0, 1, 2, 2, 3]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + int[] v = [ 25, 7, 9, 2, 0, 5, 21 ]; + topN!"a < b"(v, 100); + assert(v == [ 25, 7, 9, 2, 0, 5, 21 ]); + auto n = 4; + topN!((a, b) => a < b)(v, n); + assert(v[n] == 9); +} + +@system unittest +{ + import std.algorithm.sorting; + + int[] a = [ 5, 7, 2, 6, 7 ]; + int[] b = [ 2, 1, 5, 6, 7, 3, 0 ]; + topN(a, b); + sort(a); + assert(a == [0, 1, 2, 2, 3]); +} + +@system unittest +{ + import std.algorithm.sorting; + + import std.typecons : Yes; + + int[] a = [ 10, 16, 2, 3, 1, 5, 0 ]; + int[] b = new int[3]; + topNCopy(a, b, Yes.sortOutput); + assert(b == [ 0, 1, 2 ]); +} + +@system unittest +{ + import std.algorithm.sorting; + + import std.typecons : Yes; + + // Construct index to top 3 elements using numerical indices: + int[] a = [ 10, 2, 7, 5, 8, 1 ]; + int[] index = new int[3]; + topNIndex(a, index, Yes.sortOutput); + assert(index == [5, 1, 3]); // because a[5]==1, a[1]==2, a[3]==5 + + // Construct index to top 3 elements using pointer indices: + int*[] ptrIndex = new int*[3]; + topNIndex(a, ptrIndex, Yes.sortOutput); + assert(ptrIndex == [ &a[5], &a[1], &a[3] ]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Step through all permutations of a sorted array in lexicographic order + int[] a = [1,2,3]; + assert(nextPermutation(a) == true); + assert(a == [1,3,2]); + assert(nextPermutation(a) == true); + assert(a == [2,1,3]); + assert(nextPermutation(a) == true); + assert(a == [2,3,1]); + assert(nextPermutation(a) == true); + assert(a == [3,1,2]); + assert(nextPermutation(a) == true); + assert(a == [3,2,1]); + assert(nextPermutation(a) == false); + assert(a == [1,2,3]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Step through permutations of an array containing duplicate elements: + int[] a = [1,1,2]; + assert(nextPermutation(a) == true); + assert(a == [1,2,1]); + assert(nextPermutation(a) == true); + assert(a == [2,1,1]); + assert(nextPermutation(a) == false); + assert(a == [1,1,2]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Step through even permutations of a sorted array in lexicographic order + int[] a = [1,2,3]; + assert(nextEvenPermutation(a) == true); + assert(a == [2,3,1]); + assert(nextEvenPermutation(a) == true); + assert(a == [3,1,2]); + assert(nextEvenPermutation(a) == false); + assert(a == [1,2,3]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + import std.math.algebraic : sqrt; + + // Print the 60 vertices of a uniform truncated icosahedron (soccer ball) + enum real Phi = (1.0 + sqrt(5.0)) / 2.0; // Golden ratio + real[][] seeds = [ + [0.0, 1.0, 3.0*Phi], + [1.0, 2.0+Phi, 2.0*Phi], + [Phi, 2.0, Phi^^3] + ]; + size_t n; + foreach (seed; seeds) + { + // Loop over even permutations of each seed + do + { + // Loop over all sign changes of each permutation + size_t i; + do + { + // Generate all possible sign changes + for (i=0; i < seed.length; i++) + { + if (seed[i] != 0.0) + { + seed[i] = -seed[i]; + if (seed[i] < 0.0) + break; + } + } + n++; + } while (i < seed.length); + } while (nextEvenPermutation(seed)); + } + assert(n == 60); +} + +pure @safe unittest +{ + import std.algorithm.sorting; + + auto src = [0, 1, 2, 3, 4, 5, 6]; + auto rslt = [4, 0, 6, 2, 1, 3, 5]; + + src = nthPermutation(src, 2982); + assert(src == rslt); +} + +pure @safe unittest +{ + import std.algorithm.sorting; + + auto src = [0, 1, 2, 3, 4, 5, 6]; + auto rslt = [4, 0, 6, 2, 1, 3, 5]; + + bool worked = nthPermutationImpl(src, 2982); + assert(worked); + assert(src == rslt); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_array.d b/libphobos/testsuite/libphobos.phobos/std_array.d new file mode 100644 index 0000000000000000000000000000000000000000..1370d089943371b2ab0aa8e326892761e1d0b4e8 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_array.d @@ -0,0 +1,560 @@ +@safe pure nothrow unittest +{ + import std.array; + + auto a = array([1, 2, 3, 4, 5][]); + assert(a == [ 1, 2, 3, 4, 5 ]); +} + +@safe pure nothrow unittest +{ + import std.array; + + import std.range.primitives : isRandomAccessRange; + import std.traits : isAutodecodableString; + + // note that if autodecoding is turned off, `array` will not transcode these. + static if (isAutodecodableString!string) + assert("Hello D".array == "Hello D"d); + else + assert("Hello D".array == "Hello D"); + + static if (isAutodecodableString!wstring) + assert("Hello D"w.array == "Hello D"d); + else + assert("Hello D"w.array == "Hello D"w); + + static assert(isRandomAccessRange!dstring == true); +} + +@safe pure unittest +{ + import std.array; + + import std.range : repeat, zip; + import std.typecons : tuple; + import std.range.primitives : autodecodeStrings; + auto a = assocArray(zip([0, 1, 2], ["a", "b", "c"])); // aka zipMap + static assert(is(typeof(a) == string[int])); + assert(a == [0:"a", 1:"b", 2:"c"]); + + auto b = assocArray([ tuple("foo", "bar"), tuple("baz", "quux") ]); + static assert(is(typeof(b) == string[string])); + assert(b == ["foo":"bar", "baz":"quux"]); + + static if (autodecodeStrings) + alias achar = dchar; + else + alias achar = immutable(char); + auto c = assocArray("ABCD", true.repeat); + static assert(is(typeof(c) == bool[achar])); + bool[achar] expected = ['D':true, 'A':true, 'B':true, 'C':true]; + assert(c == expected); +} + +@safe pure nothrow unittest +{ + import std.array; + + import std.algorithm.sorting : sort; + import std.typecons : tuple, Tuple; + + auto aa = ["a": 1, "b": 2, "c": 3]; + Tuple!(string, int)[] pairs; + + // Iteration over key/value pairs. + foreach (pair; aa.byPair) + { + if (pair.key == "b") + pairs ~= tuple("B", pair.value); + else + pairs ~= pair; + } + + // Iteration order is implementation-dependent, so we should sort it to get + // a fixed order. + pairs.sort(); + assert(pairs == [ + tuple("B", 2), + tuple("a", 1), + tuple("c", 3) + ]); +} + +@system nothrow pure unittest +{ + import std.array; + + double[] arr = uninitializedArray!(double[])(100); + assert(arr.length == 100); + + double[][] matrix = uninitializedArray!(double[][])(42, 31); + assert(matrix.length == 42); + assert(matrix[0].length == 31); + + char*[] ptrs = uninitializedArray!(char*[])(100); + assert(ptrs.length == 100); +} + +@safe pure nothrow unittest +{ + import std.array; + + import std.algorithm.comparison : equal; + import std.range : repeat; + + auto arr = minimallyInitializedArray!(int[])(42); + assert(arr.length == 42); + + // Elements aren't necessarily initialized to 0, so don't do this: + // assert(arr.equal(0.repeat(42))); + // If that is needed, initialize the array normally instead: + auto arr2 = new int[42]; + assert(arr2.equal(0.repeat(42))); +} + +@safe pure nothrow unittest +{ + import std.array; + + int[] a = [ 10, 11, 12, 13, 14 ]; + int[] b = a[1 .. 3]; + assert(overlap(a, b) == [ 11, 12 ]); + b = b.dup; + // overlap disappears even though the content is the same + assert(overlap(a, b).empty); + + static test()() @nogc + { + auto a = "It's three o'clock"d; + auto b = a[5 .. 10]; + return b.overlap(a); + } + + //works at compile-time + static assert(test == "three"d); +} + +@safe pure nothrow unittest +{ + import std.array; + + import std.meta : AliasSeq; + + // can be used as an alternative implementation of overlap that returns + // `true` or `false` instead of a slice of the overlap + bool isSliceOf(T)(const scope T[] part, const scope T[] whole) + { + return part.overlap(whole) is part; + } + + auto x = [1, 2, 3, 4, 5]; + + assert(isSliceOf(x[3..$], x)); + assert(isSliceOf(x[], x)); + assert(!isSliceOf(x, x[3..$])); + assert(!isSliceOf([7, 8], x)); + assert(isSliceOf(null, x)); + + // null is a slice of itself + assert(isSliceOf(null, null)); + + foreach (T; AliasSeq!(int[], const(int)[], immutable(int)[], const int[], immutable int[])) + { + T a = [1, 2, 3, 4, 5]; + T b = a; + T c = a[1 .. $]; + T d = a[0 .. 1]; + T e = null; + + assert(isSliceOf(a, a)); + assert(isSliceOf(b, a)); + assert(isSliceOf(a, b)); + + assert(isSliceOf(c, a)); + assert(isSliceOf(c, b)); + assert(!isSliceOf(a, c)); + assert(!isSliceOf(b, c)); + + assert(isSliceOf(d, a)); + assert(isSliceOf(d, b)); + assert(!isSliceOf(a, d)); + assert(!isSliceOf(b, d)); + + assert(isSliceOf(e, a)); + assert(isSliceOf(e, b)); + assert(isSliceOf(e, c)); + assert(isSliceOf(e, d)); + + //verifies R-value compatibilty + assert(!isSliceOf(a[$ .. $], a)); + assert(isSliceOf(a[0 .. 0], a)); + assert(isSliceOf(a, a[0.. $])); + assert(isSliceOf(a[0 .. $], a)); + } +} + +@safe pure unittest +{ + import std.array; + + int[] a = [ 1, 2, 3, 4 ]; + a.insertInPlace(2, [ 1, 2 ]); + assert(a == [ 1, 2, 1, 2, 3, 4 ]); + a.insertInPlace(3, 10u, 11); + assert(a == [ 1, 2, 1, 10, 11, 2, 3, 4]); + + union U + { + float a = 3.0; + int b; + } + + U u1 = { b : 3 }; + U u2 = { b : 4 }; + U u3 = { b : 5 }; + U[] unionArr = [u2, u3]; + unionArr.insertInPlace(2, [u1]); + assert(unionArr == [u2, u3, u1]); + unionArr.insertInPlace(0, [u3, u2]); + assert(unionArr == [u3, u2, u2, u3, u1]); + + static class C + { + int a; + float b; + + this(int a, float b) { this.a = a; this.b = b; } + } + + C c1 = new C(42, 1.0); + C c2 = new C(0, 0.0); + C c3 = new C(int.max, float.init); + + C[] classArr = [c1, c2, c3]; + insertInPlace(classArr, 3, [c2, c3]); + C[5] classArr1 = classArr; + assert(classArr1 == [c1, c2, c3, c2, c3]); + insertInPlace(classArr, 0, c3, c1); + C[7] classArr2 = classArr; + assert(classArr2 == [c3, c1, c1, c2, c3, c2, c3]); +} + +@safe pure nothrow unittest +{ + import std.array; + + auto a = [1, 2, 3, 4, 5]; + auto b = a[0 .. 2]; + + assert(a.sameHead(b)); +} + +@safe pure nothrow unittest +{ + import std.array; + + auto a = [1, 2, 3, 4, 5]; + auto b = a[3..$]; + + assert(a.sameTail(b)); +} + +@safe unittest +{ + import std.array; + + auto a = "abc"; + auto s = replicate(a, 3); + + assert(s == "abcabcabc"); + + auto b = [1, 2, 3]; + auto c = replicate(b, 3); + + assert(c == [1, 2, 3, 1, 2, 3, 1, 2, 3]); + + auto d = replicate(b, 0); + + assert(d == []); +} + +@safe unittest +{ + import std.array; + + import std.uni : isWhite; + assert("Learning,D,is,fun".split(",") == ["Learning", "D", "is", "fun"]); + assert("Learning D is fun".split!isWhite == ["Learning", "D", "is", "fun"]); + assert("Learning D is fun".split(" D ") == ["Learning", "is fun"]); +} + +@safe unittest +{ + import std.array; + + string str = "Hello World!"; + assert(str.split == ["Hello", "World!"]); + + string str2 = "Hello\t\tWorld\t!"; + assert(str2.split == ["Hello", "World", "!"]); +} + +@safe unittest +{ + import std.array; + + assert(split("hello world") == ["hello","world"]); + assert(split("192.168.0.1", ".") == ["192", "168", "0", "1"]); + + auto a = split([1, 2, 3, 4, 5, 1, 2, 3, 4, 5], [2, 3]); + assert(a == [[1], [4, 5, 1], [4, 5]]); +} + +@safe pure nothrow unittest +{ + import std.array; + + assert(join(["hello", "silly", "world"], " ") == "hello silly world"); + assert(join(["hello", "silly", "world"]) == "hellosillyworld"); + + assert(join([[1, 2, 3], [4, 5]], [72, 73]) == [1, 2, 3, 72, 73, 4, 5]); + assert(join([[1, 2, 3], [4, 5]]) == [1, 2, 3, 4, 5]); + + const string[] arr = ["apple", "banana"]; + assert(arr.join(",") == "apple,banana"); + assert(arr.join() == "applebanana"); +} + +@safe unittest +{ + import std.array; + + assert("Hello Wörld".replace("o Wö", "o Wo") == "Hello World"); + assert("Hello Wörld".replace("l", "h") == "Hehho Wörhd"); +} + +@safe unittest +{ + import std.array; + + size_t changed = 0; + assert("Hello Wörld".replace("o Wö", "o Wo", changed) == "Hello World"); + assert(changed == 1); + + changed = 0; + assert("Hello Wörld".replace("l", "h", changed) == "Hehho Wörhd"); + import std.stdio : writeln; + writeln(changed); + assert(changed == 3); +} + +@safe unittest +{ + import std.array; + + auto arr = [1, 2, 3, 4, 5]; + auto from = [2, 3]; + auto to = [4, 6]; + auto sink = appender!(int[])(); + + replaceInto(sink, arr, from, to); + + assert(sink.data == [1, 4, 6, 4, 5]); +} + +@safe unittest +{ + import std.array; + + auto arr = [1, 2, 3, 4, 5]; + auto from = [2, 3]; + auto to = [4, 6]; + auto sink = appender!(int[])(); + + size_t changed = 0; + replaceInto(sink, arr, from, to, changed); + + assert(sink.data == [1, 4, 6, 4, 5]); + assert(changed == 1); +} + +@safe unittest +{ + import std.array; + + auto a = [ 1, 2, 3, 4 ]; + auto b = a.replace(1, 3, [ 9, 9, 9 ]); + assert(a == [ 1, 2, 3, 4 ]); + assert(b == [ 1, 9, 9, 9, 4 ]); +} + +@safe unittest +{ + import std.array; + + int[] a = [1, 4, 5]; + replaceInPlace(a, 1u, 2u, [2, 3, 4]); + assert(a == [1, 2, 3, 4, 5]); + replaceInPlace(a, 1u, 2u, cast(int[])[]); + assert(a == [1, 3, 4, 5]); + replaceInPlace(a, 1u, 3u, a[2 .. 4]); + assert(a == [1, 4, 5, 5]); +} + +@safe unittest +{ + import std.array; + + auto a = [1, 2, 2, 3, 4, 5]; + auto b = a.replaceFirst([2], [1337]); + assert(b == [1, 1337, 2, 3, 4, 5]); + + auto s = "This is a foo foo list"; + auto r = s.replaceFirst("foo", "silly"); + assert(r == "This is a silly foo list"); +} + +@safe unittest +{ + import std.array; + + auto a = [1, 2, 2, 3, 4, 5]; + auto b = a.replaceLast([2], [1337]); + assert(b == [1, 2, 1337, 3, 4, 5]); + + auto s = "This is a foo foo list"; + auto r = s.replaceLast("foo", "silly"); + assert(r == "This is a foo silly list", r); +} + +@safe unittest +{ + import std.array; + + auto a = [1, 2, 3, 4, 5]; + auto b = replaceSlice(a, a[1 .. 4], [0, 0, 0]); + + assert(b == [1, 0, 0, 0, 5]); +} + +@safe pure nothrow unittest +{ + import std.array; + + auto app = appender!string(); + string b = "abcdefg"; + foreach (char c; b) + app.put(c); + assert(app[] == "abcdefg"); + + int[] a = [ 1, 2 ]; + auto app2 = appender(a); + app2.put(3); + assert(app2.length == 3); + app2.put([ 4, 5, 6 ]); + assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]); +} + +@safe pure nothrow unittest +{ + import std.array; + + int[] a = [1, 2]; + auto app2 = appender(&a); + assert(app2[] == [1, 2]); + assert(a == [1, 2]); + app2 ~= 3; + assert(app2.length == 3); + app2 ~= [4, 5, 6]; + assert(app2[] == [1, 2, 3, 4, 5, 6]); + assert(a == [1, 2, 3, 4, 5, 6]); + + app2.reserve(5); + assert(app2.capacity >= 5); +} + +@safe pure nothrow unittest +{ + import std.array; + + auto w = appender!string; + // pre-allocate space for at least 10 elements (this avoids costly reallocations) + w.reserve(10); + assert(w.capacity >= 10); + + w.put('a'); // single elements + w.put("bc"); // multiple elements + + // use the append syntax + w ~= 'd'; + w ~= "ef"; + + assert(w[] == "abcdef"); +} + +@safe pure nothrow unittest +{ + import std.array; + + int[] a = [1, 2]; + auto app2 = appender(&a); + assert(app2[] == [1, 2]); + assert(a == [1, 2]); + app2 ~= 3; + app2 ~= [4, 5, 6]; + assert(app2[] == [1, 2, 3, 4, 5, 6]); + assert(a == [1, 2, 3, 4, 5, 6]); + + app2.reserve(5); + assert(app2.capacity >= 5); +} + +nothrow pure @safe @nogc unittest +{ + import std.array; + + auto a = [0, 1].staticArray; + static assert(is(typeof(a) == int[2])); + assert(a == [0, 1]); +} + +nothrow pure @safe @nogc unittest +{ + import std.array; + + auto b = [0, 1].staticArray!long; + static assert(is(typeof(b) == long[2])); + assert(b == [0, 1]); +} + +nothrow pure @safe @nogc unittest +{ + import std.array; + + import std.range : iota; + + auto input = 3.iota; + auto a = input.staticArray!2; + static assert(is(typeof(a) == int[2])); + assert(a == [0, 1]); + auto b = input.staticArray!(long[4]); + static assert(is(typeof(b) == long[4])); + assert(b == [0, 1, 2, 0]); +} + +nothrow pure @safe @nogc unittest +{ + import std.array; + + import std.range : iota; + + enum a = staticArray!(2.iota); + static assert(is(typeof(a) == int[2])); + assert(a == [0, 1]); + + enum b = staticArray!(long, 2.iota); + static assert(is(typeof(b) == long[2])); + assert(b == [0, 1]); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_ascii.d b/libphobos/testsuite/libphobos.phobos/std_ascii.d new file mode 100644 index 0000000000000000000000000000000000000000..dcdc5fd28c48857eb6a95956c72583b9ccd8576d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_ascii.d @@ -0,0 +1,262 @@ +@safe unittest +{ + import std.ascii; + + import std.conv : to; + + assert(42.to!string(16, LetterCase.upper) == "2A"); + assert(42.to!string(16, LetterCase.lower) == "2a"); +} + +@safe unittest +{ + import std.ascii; + + import std.digest.hmac : hmac; + import std.digest : toHexString; + import std.digest.sha : SHA1; + import std.string : representation; + + const sha1HMAC = "A very long phrase".representation + .hmac!SHA1("secret".representation) + .toHexString!(LetterCase.lower); + assert(sha1HMAC == "49f2073c7bf58577e8c9ae59fe8cfd37c9ab94e5"); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + import std.algorithm.comparison, std.algorithm.searching, std.range, std.traits; + + // Because all ASCII characters fit in char, so do these + static assert(ControlChar.ack.sizeof == 1); + + // All control characters except del are in row starting from 0 + static assert(EnumMembers!ControlChar.only.until(ControlChar.del).equal(iota(32))); + + static assert(ControlChar.nul == '\0'); + static assert(ControlChar.bel == '\a'); + static assert(ControlChar.bs == '\b'); + static assert(ControlChar.ff == '\f'); + static assert(ControlChar.lf == '\n'); + static assert(ControlChar.cr == '\r'); + static assert(ControlChar.tab == '\t'); + static assert(ControlChar.vt == '\v'); +} + +@safe pure nothrow unittest +{ + import std.ascii; + + import std.conv; + //Control character table can be used in place of hexcodes. + with (ControlChar) assert(text("Phobos", us, "Deimos", us, "Tango", rs) == "Phobos\x1FDeimos\x1FTango\x1E"); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isAlphaNum('A')); + assert( isAlphaNum('1')); + assert(!isAlphaNum('#')); + + // N.B.: does not return true for non-ASCII Unicode alphanumerics: + assert(!isAlphaNum('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isAlpha('A')); + assert(!isAlpha('1')); + assert(!isAlpha('#')); + + // N.B.: does not return true for non-ASCII Unicode alphabetic characters: + assert(!isAlpha('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isLower('a')); + assert(!isLower('A')); + assert(!isLower('#')); + + // N.B.: does not return true for non-ASCII Unicode lowercase letters + assert(!isLower('á')); + assert(!isLower('Ã')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isUpper('A')); + assert(!isUpper('a')); + assert(!isUpper('#')); + + // N.B.: does not return true for non-ASCII Unicode uppercase letters + assert(!isUpper('á')); + assert(!isUpper('Ã')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isDigit('3')); + assert( isDigit('8')); + assert(!isDigit('B')); + assert(!isDigit('#')); + + // N.B.: does not return true for non-ASCII Unicode numbers + assert(!isDigit('ï¼')); // full-width digit zero (U+FF10) + assert(!isDigit('ï¼”')); // full-width digit four (U+FF14) +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isOctalDigit('0')); + assert( isOctalDigit('7')); + assert(!isOctalDigit('8')); + assert(!isOctalDigit('A')); + assert(!isOctalDigit('#')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isHexDigit('0')); + assert( isHexDigit('A')); + assert( isHexDigit('f')); // lowercase hex digits are accepted + assert(!isHexDigit('g')); + assert(!isHexDigit('G')); + assert(!isHexDigit('#')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isWhite(' ')); + assert( isWhite('\t')); + assert( isWhite('\n')); + assert(!isWhite('1')); + assert(!isWhite('a')); + assert(!isWhite('#')); + + // N.B.: Does not return true for non-ASCII Unicode whitespace characters. + static import std.uni; + assert(std.uni.isWhite('\u00A0')); + assert(!isWhite('\u00A0')); // std.ascii.isWhite +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isControl('\0')); + assert( isControl('\022')); + assert( isControl('\n')); // newline is both whitespace and control + assert(!isControl(' ')); + assert(!isControl('1')); + assert(!isControl('a')); + assert(!isControl('#')); + + // N.B.: non-ASCII Unicode control characters are not recognized: + assert(!isControl('\u0080')); + assert(!isControl('\u2028')); + assert(!isControl('\u2029')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isPunctuation('.')); + assert( isPunctuation(',')); + assert( isPunctuation(':')); + assert( isPunctuation('!')); + assert( isPunctuation('#')); + assert( isPunctuation('~')); + assert( isPunctuation('+')); + assert( isPunctuation('_')); + + assert(!isPunctuation('1')); + assert(!isPunctuation('a')); + assert(!isPunctuation(' ')); + assert(!isPunctuation('\n')); + assert(!isPunctuation('\0')); + + // N.B.: Non-ASCII Unicode punctuation characters are not recognized. + assert(!isPunctuation('\u2012')); // (U+2012 = en-dash) +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isGraphical('1')); + assert( isGraphical('a')); + assert( isGraphical('#')); + assert(!isGraphical(' ')); // whitespace is not graphical + assert(!isGraphical('\n')); + assert(!isGraphical('\0')); + + // N.B.: Unicode graphical characters are not regarded as such. + assert(!isGraphical('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isPrintable(' ')); // whitespace is printable + assert( isPrintable('1')); + assert( isPrintable('a')); + assert( isPrintable('#')); + assert(!isPrintable('\0')); // control characters are not printable + + // N.B.: Printable non-ASCII Unicode characters are not recognized. + assert(!isPrintable('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isASCII('a')); + assert(!isASCII('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert(toLower('a') == 'a'); + assert(toLower('A') == 'a'); + assert(toLower('#') == '#'); + + // N.B.: Non-ASCII Unicode uppercase letters are not converted. + assert(toLower('Ã') == 'Ã'); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert(toUpper('a') == 'A'); + assert(toUpper('A') == 'A'); + assert(toUpper('#') == '#'); + + // N.B.: Non-ASCII Unicode lowercase letters are not converted. + assert(toUpper('á') == 'á'); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_base64.d b/libphobos/testsuite/libphobos.phobos/std_base64.d new file mode 100644 index 0000000000000000000000000000000000000000..3a49eeaacaaa298fa887b4426d5dbf600bda2ae7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_base64.d @@ -0,0 +1,180 @@ +pure @safe unittest +{ + import std.base64; + + ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; + assert(Base64.encode(data) == "g9cwegE/"); + assert(Base64.decode("g9cwegE/") == data); +} + +pure @safe unittest +{ + import std.base64; + + ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; + assert(Base64URL.encode(data) == "g9cwegE_"); + assert(Base64URL.decode("g9cwegE_") == data); +} + +pure @safe unittest +{ + import std.base64; + + ubyte[] data = [0x83, 0xd7, 0x30, 0x7b, 0xef]; + assert(Base64URLNoPadding.encode(data) == "g9cwe-8"); + assert(Base64URLNoPadding.decode("g9cwe-8") == data); +} + +@safe unittest +{ + import std.base64; + + ubyte[] data = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; + + // Allocate a buffer large enough to hold the encoded string. + auto buf = new char[Base64.encodeLength(data.length)]; + + Base64.encode(data, buf); + assert(buf == "Gis8TV1u"); + +} + +@nogc nothrow @safe unittest +{ + import std.base64; + + ubyte[6] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; + char[32] buffer; // much bigger than necessary + + // Just to be sure... + auto encodedLength = Base64.encodeLength(data.length); + assert(buffer.length >= encodedLength); + + // encode() returns a slice to the provided buffer. + auto encoded = Base64.encode(data[], buffer[]); + assert(encoded is buffer[0 .. encodedLength]); + assert(encoded == "g9cwegE/"); + +} + +@safe pure nothrow unittest +{ + import std.base64; + + import std.array : appender; + + auto output = appender!string(); + ubyte[] data = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; + + // This overload of encode() returns the number of calls to the output + // range's put method. + assert(Base64.encode(data, output) == 8); + assert(output.data == "Gis8TV1u"); + +} + +@safe unittest +{ + import std.base64; + + ubyte[] data = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; + assert(Base64.encode(data) == "Gis8TV1u"); + +} + +@safe unittest +{ + import std.base64; + + auto encoded = "Gis8TV1u"; + + // Allocate a sufficiently large buffer to hold to decoded result. + auto buffer = new ubyte[Base64.decodeLength(encoded.length)]; + + Base64.decode(encoded, buffer); + assert(buffer == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); + +} + +@safe unittest +{ + import std.base64; + + auto encoded = "Gis8TV1u"; + ubyte[32] buffer; // much bigger than necessary + + // Just to be sure... + auto decodedLength = Base64.decodeLength(encoded.length); + assert(buffer.length >= decodedLength); + + // decode() returns a slice of the given buffer. + auto decoded = Base64.decode(encoded, buffer[]); + assert(decoded is buffer[0 .. decodedLength]); + assert(decoded == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); + +} + +@system unittest +{ + import std.base64; + + struct OutputRange + { + ubyte[] result; + void put(ubyte b) { result ~= b; } + } + OutputRange output; + + // This overload of decode() returns the number of calls to put(). + assert(Base64.decode("Gis8TV1u", output) == 6); + assert(output.result == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); + +} + +@safe unittest +{ + import std.base64; + + auto data = "Gis8TV1u"; + assert(Base64.decode(data) == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); + +} + +@safe pure unittest +{ + import std.base64; + + import std.algorithm.comparison : equal; + string encoded = + "VGhvdSBzaGFsdCBuZXZlciBjb250aW51ZSBhZnRlciBhc3NlcnRpbmcgbnVsbA=="; + + assert(Base64.decoder(encoded) + .equal("Thou shalt never continue after asserting null")); + +} + +@safe unittest +{ + import std.base64; + + import std.string : representation; + + // pre-defined: alias Base64 = Base64Impl!('+', '/'); + ubyte[] emptyArr; + assert(Base64.encode(emptyArr) == ""); + assert(Base64.encode("f".representation) == "Zg=="); + assert(Base64.encode("foo".representation) == "Zm9v"); + + alias Base64Re = Base64Impl!('!', '=', Base64.NoPadding); + assert(Base64Re.encode("f".representation) == "Zg"); + assert(Base64Re.encode("foo".representation) == "Zm9v"); +} + +@safe unittest +{ + import std.base64; + + import std.exception : assertThrown; + assertThrown!Base64Exception(Base64.decode("ab|c")); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_bigint.d b/libphobos/testsuite/libphobos.phobos/std_bigint.d new file mode 100644 index 0000000000000000000000000000000000000000..627d15c04698d555b9f7d683461dfcf48c333caf --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_bigint.d @@ -0,0 +1,465 @@ +pure @safe unittest +{ + import std.bigint; + + ubyte[] magnitude = [1, 2, 3, 4, 5, 6]; + auto b1 = BigInt(false, magnitude); + assert(cast(long) b1 == 0x01_02_03_04_05_06L); + auto b2 = BigInt(true, magnitude); + assert(cast(long) b2 == -0x01_02_03_04_05_06L); + +} + +@safe unittest +{ + import std.bigint; + + ulong data = 1_000_000_000_000; + auto bigData = BigInt(data); + assert(bigData == BigInt("1_000_000_000_000")); + +} + +@safe unittest +{ + import std.bigint; + + const(BigInt) b1 = BigInt("1_234_567_890"); + BigInt b2 = BigInt(b1); + assert(b2 == BigInt("1_234_567_890")); + +} + +@safe unittest +{ + import std.bigint; + + auto b = BigInt("123"); + b = 456; + assert(b == BigInt("456")); + +} + +@safe unittest +{ + import std.bigint; + + auto b1 = BigInt("123"); + auto b2 = BigInt("456"); + b2 = b1; + assert(b2 == BigInt("123")); + +} + +@safe unittest +{ + import std.bigint; + + auto b = BigInt("1_000_000_000"); + + b += 12345; + assert(b == BigInt("1_000_012_345")); + + b /= 5; + assert(b == BigInt("200_002_469")); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("123"); + auto y = BigInt("321"); + x += y; + assert(x == BigInt("444")); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("123"); + auto y = BigInt("456"); + BigInt z = x * y; + assert(z == BigInt("56088")); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("123"); + x *= 300; + assert(x == BigInt("36900")); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("1_000_000_500"); + long l = 1_000_000L; + ulong ul = 2_000_000UL; + int i = 500_000; + short s = 30_000; + + assert(is(typeof(x % l) == long) && x % l == 500L); + assert(is(typeof(x % ul) == BigInt) && x % ul == BigInt(500)); + assert(is(typeof(x % i) == int) && x % i == 500); + assert(is(typeof(x % s) == int) && x % s == 10500); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("100"); + BigInt y = 123 + x; + assert(y == BigInt("223")); + + BigInt z = 123 - x; + assert(z == BigInt("23")); + + // Dividing a built-in integer type by BigInt always results in + // something that fits in a built-in type, so the built-in type is + // returned, not BigInt. + assert(is(typeof(1000 / x) == int)); + assert(1000 / x == 10); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("1234"); + assert(-x == BigInt("-1234")); + + ++x; + assert(x == BigInt("1235")); + +} + +@safe unittest +{ + import std.bigint; + + // Note that when comparing a BigInt to a float or double the + // full precision of the BigInt is always considered, unlike + // when comparing an int to a float or a long to a double. + assert(BigInt(123456789) != cast(float) 123456789); + +} + +@safe unittest +{ + import std.bigint; + + // Non-zero values are regarded as true + auto x = BigInt("1"); + auto y = BigInt("10"); + assert(x); + assert(y); + + // Zero value is regarded as false + auto z = BigInt("0"); + assert(!z); + +} + +@safe unittest +{ + import std.bigint; + + import std.conv : to, ConvOverflowException; + import std.exception : assertThrown; + + assert(BigInt("0").to!int == 0); + + assert(BigInt("0").to!ubyte == 0); + assert(BigInt("255").to!ubyte == 255); + assertThrown!ConvOverflowException(BigInt("256").to!ubyte); + assertThrown!ConvOverflowException(BigInt("-1").to!ubyte); + +} + +@system unittest +{ + import std.bigint; + + assert(cast(float) BigInt("35540592535949172786332045140593475584") + == 35540592535949172786332045140593475584.0f); + assert(cast(double) BigInt("35540601499647381470685035515422441472") + == 35540601499647381470685035515422441472.0); + assert(cast(real) BigInt("35540601499647381470685035515422441472") + == 35540601499647381470685035515422441472.0L); + + assert(cast(float) BigInt("-0x1345_6780_0000_0000_0000_0000_0000") == -0x1.3456_78p+108f ); + assert(cast(double) BigInt("-0x1345_678a_bcde_f000_0000_0000_0000") == -0x1.3456_78ab_cdefp+108 ); + assert(cast(real) BigInt("-0x1345_678a_bcde_f000_0000_0000_0000") == -0x1.3456_78ab_cdefp+108L); + +} + +@system unittest +{ + import std.bigint; + + // BigInts whose values cannot be exactly represented as float/double/real + // are rounded when cast to float/double/real. When cast to float or + // double or 64-bit real the rounding is strictly defined. When cast + // to extended-precision real the rounding rules vary by environment. + + // BigInts that fall somewhere between two non-infinite floats/doubles + // are rounded to the closer value when cast to float/double. + assert(cast(float) BigInt(0x1aaa_aae7) == 0x1.aaa_aaep+28f); + assert(cast(float) BigInt(0x1aaa_aaff) == 0x1.aaa_ab0p+28f); + assert(cast(float) BigInt(-0x1aaa_aae7) == -0x1.aaaaaep+28f); + assert(cast(float) BigInt(-0x1aaa_aaff) == -0x1.aaaab0p+28f); + + assert(cast(double) BigInt(0x1aaa_aaaa_aaaa_aa77) == 0x1.aaa_aaaa_aaaa_aa00p+60); + assert(cast(double) BigInt(0x1aaa_aaaa_aaaa_aaff) == 0x1.aaa_aaaa_aaaa_ab00p+60); + assert(cast(double) BigInt(-0x1aaa_aaaa_aaaa_aa77) == -0x1.aaa_aaaa_aaaa_aa00p+60); + assert(cast(double) BigInt(-0x1aaa_aaaa_aaaa_aaff) == -0x1.aaa_aaaa_aaaa_ab00p+60); + + // BigInts that fall exactly between two non-infinite floats/doubles + // are rounded away from zero when cast to float/double. (Note that + // in most environments this is NOT the same rounding rule rule used + // when casting int/long to float/double.) + assert(cast(float) BigInt(0x1aaa_aaf0) == 0x1.aaa_ab0p+28f); + assert(cast(float) BigInt(-0x1aaa_aaf0) == -0x1.aaaab0p+28f); + + assert(cast(double) BigInt(0x1aaa_aaaa_aaaa_aa80) == 0x1.aaa_aaaa_aaaa_ab00p+60); + assert(cast(double) BigInt(-0x1aaa_aaaa_aaaa_aa80) == -0x1.aaa_aaaa_aaaa_ab00p+60); + + // BigInts that are bounded on one side by the largest positive or + // most negative finite float/double and on the other side by infinity + // or -infinity are rounded as if in place of infinity was the value + // `2^^(T.max_exp)` when cast to float/double. + assert(cast(float) BigInt("999_999_999_999_999_999_999_999_999_999_999_999_999") == float.infinity); + assert(cast(float) BigInt("-999_999_999_999_999_999_999_999_999_999_999_999_999") == -float.infinity); + + assert(cast(double) BigInt("999_999_999_999_999_999_999_999_999_999_999_999_999") < double.infinity); + assert(cast(real) BigInt("999_999_999_999_999_999_999_999_999_999_999_999_999") < real.infinity); + +} + +@safe unittest +{ + import std.bigint; + + const(BigInt) x = BigInt("123"); + BigInt y = cast() x; // cast away const + assert(y == x); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("100"); + auto y = BigInt("10"); + int z = 50; + const int w = 200; + + assert(y < x); + assert(x > z); + assert(z > y); + assert(x < w); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("0x1abc_de80_0000_0000_0000_0000_0000_0000"); + BigInt y = x - 1; + BigInt z = x + 1; + + double d = 0x1.abcde8p124; + assert(y < d); + assert(z > d); + assert(x >= d && x <= d); + + // Note that when comparing a BigInt to a float or double the + // full precision of the BigInt is always considered, unlike + // when comparing an int to a float or a long to a double. + assert(BigInt(123456789) < cast(float) 123456789); + +} + +@safe unittest +{ + import std.bigint; + + auto b = BigInt("12345"); + long l = b.toLong(); + assert(l == 12345); + +} + +@safe unittest +{ + import std.bigint; + + auto big = BigInt("5_000_000"); + auto i = big.toInt(); + assert(i == 5_000_000); + + // Numbers that are too big to fit into an int will be clamped to int.max. + auto tooBig = BigInt("5_000_000_000"); + i = tooBig.toInt(); + assert(i == int.max); + +} + +@safe unittest +{ + import std.bigint; + + import std.format : format; + + auto x = BigInt("1_000_000"); + x *= 12345; + + assert(format("%d", x) == "12345000000"); + assert(format("%x", x) == "2_dfd1c040"); + assert(format("%X", x) == "2_DFD1C040"); + assert(format("%o", x) == "133764340100"); + +} + +@safe pure unittest +{ + import std.bigint; + + string[BigInt] aa; + aa[BigInt(123)] = "abc"; + aa[BigInt(456)] = "def"; + + assert(aa[BigInt(123)] == "abc"); + assert(aa[BigInt(456)] == "def"); + +} + +@safe pure unittest +{ + import std.bigint; + + auto a = BigInt("1000"); + assert(a.ulongLength() == 1); + assert(a.getDigit(0) == 1000); + + assert(a.uintLength() == 1); + assert(a.getDigit!uint(0) == 1000); + + auto b = BigInt("2_000_000_000_000_000_000_000_000_000"); + assert(b.ulongLength() == 2); + assert(b.getDigit(0) == 4584946418820579328); + assert(b.getDigit(1) == 108420217); + + assert(b.uintLength() == 3); + assert(b.getDigit!uint(0) == 3489660928); + assert(b.getDigit!uint(1) == 1067516025); + assert(b.getDigit!uint(2) == 108420217); + +} + +@safe unittest +{ + import std.bigint; + + BigInt a = "9588669891916142"; + BigInt b = "7452469135154800"; + auto c = a * b; + assert(c == BigInt("71459266416693160362545788781600")); + auto d = b * a; + assert(d == BigInt("71459266416693160362545788781600")); + assert(d == c); + d = c * BigInt("794628672112"); + assert(d == BigInt("56783581982794522489042432639320434378739200")); + auto e = c + d; + assert(e == BigInt("56783581982865981755459125799682980167520800")); + auto f = d + c; + assert(f == e); + auto g = f - c; + assert(g == d); + g = f - d; + assert(g == c); + e = 12345678; + g = c + e; + auto h = g / b; + auto i = g % b; + assert(h == a); + assert(i == e); + BigInt j = "-0x9A56_57f4_7B83_AB78"; + BigInt k = j; + j ^^= 11; + assert(k ^^ 11 == j); +} + +@safe pure unittest +{ + import std.bigint; + + auto x = BigInt("123"); + x *= 1000; + x += 456; + + auto xstr = x.toDecimalString(); + assert(xstr == "123456"); +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("123"); + x *= 1000; + x += 456; + + auto xstr = x.toHex(); + assert(xstr == "1E240"); +} + +nothrow pure @safe unittest +{ + import std.bigint; + + assert((-1).absUnsign == 1); + assert(1.absUnsign == 1); +} + +@safe pure nothrow unittest +{ + import std.bigint; + + auto a = BigInt(123); + auto b = BigInt(25); + BigInt q, r; + + divMod(a, b, q, r); + + assert(q == 4); + assert(r == 23); + assert(q * b + r == a); +} + +@safe unittest +{ + import std.bigint; + + BigInt base = BigInt("123456789012345678901234567890"); + BigInt exponent = BigInt("1234567890123456789012345678901234567"); + BigInt modulus = BigInt("1234567"); + + BigInt result = powmod(base, exponent, modulus); + assert(result == 359079); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_bitmanip.d b/libphobos/testsuite/libphobos.phobos/std_bitmanip.d new file mode 100644 index 0000000000000000000000000000000000000000..6bd658d011868229278e6046a13385befe843100 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_bitmanip.d @@ -0,0 +1,1628 @@ +@safe unittest +{ + import std.bitmanip; + + struct A + { + int a; + mixin(bitfields!( + uint, "x", 2, + int, "y", 3, + uint, "z", 2, + bool, "flag", 1)); + } + + A obj; + obj.x = 2; + obj.z = obj.x; + + assert(obj.x == 2); + assert(obj.y == 0); + assert(obj.z == 2); + assert(obj.flag == false); +} + +@safe unittest +{ + import std.bitmanip; + + struct A + { + mixin(bitfields!( + bool, "flag1", 1, + bool, "flag2", 1, + uint, "", 6)); + } + + A a; + assert(a.flag1 == 0); + a.flag1 = 1; + assert(a.flag1 == 1); + a.flag1 = 0; + assert(a.flag1 == 0); +} + +@safe unittest +{ + import std.bitmanip; + + enum ABC { A, B, C } + struct EnumTest + { + mixin(bitfields!( + ABC, "x", 2, + bool, "y", 1, + ubyte, "z", 5)); + } +} + +@safe unittest +{ + import std.bitmanip; + + struct A + { + int a; + mixin(taggedPointer!( + uint*, "x", + bool, "b1", 1, + bool, "b2", 1)); + } + A obj; + obj.x = new uint; + obj.b1 = true; + obj.b2 = false; +} + +@safe unittest +{ + import std.bitmanip; + + struct A + { + int a; + mixin(taggedClassRef!( + Object, "o", + uint, "i", 2)); + } + A obj; + obj.o = new Object(); + obj.i = 3; +} + +@safe unittest +{ + import std.bitmanip; + + FloatRep rep = {value: 0}; + assert(rep.fraction == 0); + assert(rep.exponent == 0); + assert(!rep.sign); + + rep.value = 42; + assert(rep.fraction == 2621440); + assert(rep.exponent == 132); + assert(!rep.sign); + + rep.value = 10; + assert(rep.fraction == 2097152); + assert(rep.exponent == 130); +} + +@safe unittest +{ + import std.bitmanip; + + FloatRep rep = {value: 1}; + assert(rep.fraction == 0); + assert(rep.exponent == 127); + assert(!rep.sign); + + rep.exponent = 126; + assert(rep.value == 0.5); + + rep.exponent = 130; + assert(rep.value == 8); +} + +@safe unittest +{ + import std.bitmanip; + + FloatRep rep = {value: 1}; + rep.value = -0.5; + assert(rep.fraction == 0); + assert(rep.exponent == 126); + assert(rep.sign); + + rep.value = -1. / 3; + assert(rep.fraction == 2796203); + assert(rep.exponent == 125); + assert(rep.sign); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep rep = {value: 0}; + assert(rep.fraction == 0); + assert(rep.exponent == 0); + assert(!rep.sign); + + rep.value = 42; + assert(rep.fraction == 1407374883553280); + assert(rep.exponent == 1028); + assert(!rep.sign); + + rep.value = 10; + assert(rep.fraction == 1125899906842624); + assert(rep.exponent == 1026); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep rep = {value: 1}; + assert(rep.fraction == 0); + assert(rep.exponent == 1023); + assert(!rep.sign); + + rep.exponent = 1022; + assert(rep.value == 0.5); + + rep.exponent = 1026; + assert(rep.value == 8); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep rep = {value: 1}; + rep.value = -0.5; + assert(rep.fraction == 0); + assert(rep.exponent == 1022); + assert(rep.sign); + + rep.value = -1. / 3; + assert(rep.fraction == 1501199875790165); + assert(rep.exponent == 1021); + assert(rep.sign); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep x; + x.value = 1.0; + assert(x.fraction == 0 && x.exponent == 1023 && !x.sign); + x.value = -0.5; + assert(x.fraction == 0 && x.exponent == 1022 && x.sign); + x.value = 0.5; + assert(x.fraction == 0 && x.exponent == 1022 && !x.sign); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep x; + x.fraction = 1125899906842624; + x.exponent = 1025; + x.sign = true; + assert(x.value == -5.0); +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + bool[] input = [true, false, false, true, true]; + auto a = BitArray(input); + assert(a.length == 5); + assert(a.bitsSet.equal([0, 3, 4])); + + // This also works because an implicit cast to bool[] occurs for this array. + auto b = BitArray([0, 0, 1]); + assert(b.length == 3); + assert(b.bitsSet.equal([2])); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.array : array; + import std.range : iota, repeat; + + BitArray a = true.repeat(70).array; + assert(a.length == 70); + assert(a.bitsSet.equal(iota(0, 70))); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto a = BitArray([1, 0, 0, 1, 1]); + + // Inverse of the cast. + auto v = cast(void[]) a; + auto b = BitArray(v, a.length); + + assert(b.length == 5); + assert(b.bitsSet.equal([0, 3, 4])); + + // a and b share the underlying data. + a[0] = 0; + assert(b[0] == 0); + assert(a == b); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + size_t[] source = [0b1100, 0b0011]; + enum sbits = size_t.sizeof * 8; + auto ba = BitArray(source, source.length * sbits); + // The least significant bit in each unit is this unit's starting bit. + assert(ba.bitsSet.equal([2, 3, sbits, sbits + 1])); + +} + +@system unittest +{ + import std.bitmanip; + + // Example from the doc for this constructor. + static immutable size_t[] sourceData = [1, 0b101, 3, 3424234, 724398, 230947, 389492]; + size_t[] source = sourceData.dup; + enum sbits = size_t.sizeof * 8; + auto ba = BitArray(source, source.length * sbits); + foreach (n; 0 .. source.length * sbits) + { + auto nth_bit = cast(bool) (source[n / sbits] & (1L << (n % sbits))); + assert(ba[n] == nth_bit); + } + + // Example of mapping only part of the array. + import std.algorithm.comparison : equal; + + auto bc = BitArray(source, sbits + 1); + assert(bc.bitsSet.equal([0, sbits])); + // Source array has not been modified. + assert(source == sourceData); + +} + +@system unittest +{ + import std.bitmanip; + + static void fun(const BitArray arr) + { + auto x = arr[0]; + assert(x == 1); + } + BitArray a; + a.length = 3; + a[0] = 1; + fun(a); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto b = BitArray([1, 0, 1, 0, 1, 1]); + + b[] = true; + // all bits are set + assert(b.bitsSet.equal([0, 1, 2, 3, 4, 5])); + + b[] = false; + // none of the bits are set + assert(b.bitsSet.empty); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.range : iota; + import std.stdio; + + auto b = BitArray([1, 0, 0, 0, 1, 1, 0]); + b[1 .. 3] = true; + assert(b.bitsSet.equal([0, 1, 2, 4, 5])); + + bool[72] bitArray; + auto b1 = BitArray(bitArray); + b1[63 .. 67] = true; + assert(b1.bitsSet.equal([63, 64, 65, 66])); + b1[63 .. 67] = false; + assert(b1.bitsSet.empty); + b1[0 .. 64] = true; + assert(b1.bitsSet.equal(iota(0, 64))); + b1[0 .. 64] = false; + assert(b1.bitsSet.empty); + + bool[256] bitArray2; + auto b2 = BitArray(bitArray2); + b2[3 .. 245] = true; + assert(b2.bitsSet.equal(iota(3, 245))); + b2[3 .. 245] = false; + assert(b2.bitsSet.empty); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.range : iota; + + // positions 0, 2, 4 are set + auto b = BitArray([1, 0, 1, 0, 1, 0]); + b.flip(); + // after flipping, positions 1, 3, 5 are set + assert(b.bitsSet.equal([1, 3, 5])); + + bool[270] bits; + auto b1 = BitArray(bits); + b1.flip(); + assert(b1.bitsSet.equal(iota(0, 270))); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + auto ax = BitArray([1, 0, 0, 1]); + ax.flip(0); + assert(ax[0] == 0); + + bool[200] y; + y[90 .. 130] = true; + auto ay = BitArray(y); + ay.flip(100); + assert(ay[100] == 0); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + auto a = BitArray([0, 1, 1, 0, 0, 1, 1]); + assert(a.count == 4); + + BitArray b; + assert(b.count == 0); + + bool[200] boolArray; + boolArray[45 .. 130] = true; + auto c = BitArray(boolArray); + assert(c.count == 85); + +} + +@system unittest +{ + import std.bitmanip; + + BitArray a; + BitArray b; + + a.length = 3; + a[0] = 1; a[1] = 0; a[2] = 1; + b = a.dup; + assert(b.length == 3); + foreach (i; 0 .. 3) + assert(b[i] == (((i ^ 1) & 1) ? true : false)); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1]; + + auto a = BitArray(ba); + + int i; + foreach (b;a) + { + switch (i) + { + case 0: assert(b == true); break; + case 1: assert(b == false); break; + case 2: assert(b == true); break; + default: assert(0); + } + i++; + } + + foreach (j,b;a) + { + switch (j) + { + case 0: assert(b == true); break; + case 1: assert(b == false); break; + case 2: assert(b == true); break; + default: assert(0); + } + } + +} + +@system unittest +{ + import std.bitmanip; + + BitArray b; + bool[5] data = [1,0,1,1,0]; + + b = BitArray(data); + b.reverse; + foreach (i; 0 .. data.length) + assert(b[i] == data[4 - i]); + +} + +@system unittest +{ + import std.bitmanip; + + size_t x = 0b1100011000; + auto ba = BitArray(10, &x); + ba.sort; + foreach (i; 0 .. 6) + assert(ba[i] == false); + foreach (i; 6 .. 10) + assert(ba[i] == true); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1]; + bool[] bc = [1,0,1,0,1,0,1]; + bool[] bd = [1,0,1,1,1]; + bool[] be = [1,0,1,0,1]; + bool[] bf = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + bool[] bg = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + auto c = BitArray(bc); + auto d = BitArray(bd); + auto e = BitArray(be); + auto f = BitArray(bf); + auto g = BitArray(bg); + + assert(a != b); + assert(a != c); + assert(a != d); + assert(a == e); + assert(f != g); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1]; + bool[] bc = [1,0,1,0,1,0,1]; + bool[] bd = [1,0,1,1,1]; + bool[] be = [1,0,1,0,1]; + bool[] bf = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]; + bool[] bg = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + auto c = BitArray(bc); + auto d = BitArray(bd); + auto e = BitArray(be); + auto f = BitArray(bf); + auto g = BitArray(bg); + + assert(a > b); + assert(a >= b); + assert(a < c); + assert(a <= c); + assert(a < d); + assert(a <= d); + assert(a == e); + assert(a <= e); + assert(a >= e); + assert(f < g); + assert(g <= g); + +} + +@system unittest +{ + import std.bitmanip; + + import std.array : array; + import std.range : repeat, take; + + // bit array with 300 elements + auto a = BitArray(true.repeat.take(300).array); + size_t[] v = cast(size_t[]) a; + const blockSize = size_t.sizeof * 8; + assert(v.length == (a.length + blockSize - 1) / blockSize); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + + auto a = BitArray(ba); + BitArray b = ~a; + + assert(b[0] == 0); + assert(b[1] == 1); + assert(b[2] == 0); + assert(b[3] == 1); + assert(b[4] == 0); + +} + +@system unittest +{ + import std.bitmanip; + + static bool[] ba = [1,0,1,0,1]; + static bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + BitArray c = a & b; + + assert(c[0] == 1); + assert(c[1] == 0); + assert(c[2] == 1); + assert(c[3] == 0); + assert(c[4] == 0); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + BitArray c = a | b; + + assert(c[0] == 1); + assert(c[1] == 0); + assert(c[2] == 1); + assert(c[3] == 1); + assert(c[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + BitArray c = a ^ b; + + assert(c[0] == 0); + assert(c[1] == 0); + assert(c[2] == 0); + assert(c[3] == 1); + assert(c[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + BitArray c = a - b; + + assert(c[0] == 0); + assert(c[1] == 0); + assert(c[2] == 0); + assert(c[3] == 0); + assert(c[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1,1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + auto a = BitArray(ba); + auto b = BitArray(bb); + BitArray c = a; + c.length = 5; + c &= b; + assert(a[5] == 1); + assert(a[6] == 0); + assert(a[7] == 1); + assert(a[8] == 0); + assert(a[9] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + a &= b; + assert(a[0] == 1); + assert(a[1] == 0); + assert(a[2] == 1); + assert(a[3] == 0); + assert(a[4] == 0); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + a |= b; + assert(a[0] == 1); + assert(a[1] == 0); + assert(a[2] == 1); + assert(a[3] == 1); + assert(a[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + a ^= b; + assert(a[0] == 0); + assert(a[1] == 0); + assert(a[2] == 0); + assert(a[3] == 1); + assert(a[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + a -= b; + assert(a[0] == 0); + assert(a[1] == 0); + assert(a[2] == 0); + assert(a[3] == 0); + assert(a[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + + auto a = BitArray(ba); + BitArray b; + + b = (a ~= true); + assert(a[0] == 1); + assert(a[1] == 0); + assert(a[2] == 1); + assert(a[3] == 0); + assert(a[4] == 1); + assert(a[5] == 1); + + assert(b == a); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0]; + bool[] bb = [0,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + BitArray c; + + c = (a ~= b); + assert(a.length == 5); + assert(a[0] == 1); + assert(a[1] == 0); + assert(a[2] == 0); + assert(a[3] == 1); + assert(a[4] == 0); + + assert(c == a); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0]; + bool[] bb = [0,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + BitArray c; + + c = (a ~ b); + assert(c.length == 5); + assert(c[0] == 1); + assert(c[1] == 0); + assert(c[2] == 0); + assert(c[3] == 1); + assert(c[4] == 0); + + c = (a ~ true); + assert(c.length == 3); + assert(c[0] == 1); + assert(c[1] == 0); + assert(c[2] == 1); + + c = (false ~ a); + assert(c.length == 3); + assert(c[0] == 0); + assert(c[1] == 1); + assert(c[2] == 0); + +} + +@system unittest +{ + import std.bitmanip; + + import std.format : format; + + auto b = BitArray([1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1]); + + b <<= 1; + assert(format("%b", b) == "01100_10101101"); + + b >>= 1; + assert(format("%b", b) == "11001_01011010"); + + b <<= 4; + assert(format("%b", b) == "00001_10010101"); + + b >>= 5; + assert(format("%b", b) == "10010_10100000"); + + b <<= 13; + assert(format("%b", b) == "00000_00000000"); + + b = BitArray([1, 0, 1, 1, 0, 1, 1, 1]); + b >>= 8; + assert(format("%b", b) == "00000000"); + + +} + +@system pure unittest +{ + import std.bitmanip; + + import std.format : format; + + auto b = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + + auto s1 = format("%s", b); + assert(s1 == "[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]"); + + auto s2 = format("%b", b); + assert(s2 == "00001111_00001111"); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto b1 = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(b1.bitsSet.equal([4, 5, 6, 7, 12, 13, 14, 15])); + + BitArray b2; + b2.length = 1000; + b2[333] = true; + b2[666] = true; + b2[999] = true; + assert(b2.bitsSet.equal([333, 666, 999])); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.range : iota; + + bool[] buf = new bool[64 * 3]; + buf[0 .. 64] = true; + BitArray b = BitArray(buf); + assert(b.bitsSet.equal(iota(0, 64))); + b <<= 64; + assert(b.bitsSet.equal(iota(64, 128))); +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto b = BitArray([1, 0]); + b ~= true; + assert(b[2] == 1); + b ~= BitArray([0, 1]); + auto c = BitArray([1, 0, 1, 0, 1]); + assert(b == c); + assert(b.bitsSet.equal([0, 2, 4])); +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto b = BitArray([1, 1, 0, 1]); + b &= BitArray([0, 1, 1, 0]); + assert(b.bitsSet.equal([1])); + b.flip; + assert(b.bitsSet.equal([0, 2, 3])); +} + +@system unittest +{ + import std.bitmanip; + + import std.format : format; + auto b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%b", b) == "1_00001111_00001111"); +} + +@system unittest +{ + import std.bitmanip; + + import std.format : format; + + BitArray b; + + b = BitArray([]); + assert(format("%s", b) == "[]"); + assert(format("%b", b) is null); + + b = BitArray([1]); + assert(format("%s", b) == "[1]"); + assert(format("%b", b) == "1"); + + b = BitArray([0, 0, 0, 0]); + assert(format("%b", b) == "0000"); + + b = BitArray([0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%s", b) == "[0, 0, 0, 0, 1, 1, 1, 1]"); + assert(format("%b", b) == "00001111"); + + b = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%s", b) == "[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]"); + assert(format("%b", b) == "00001111_00001111"); + + b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%b", b) == "1_00001111"); + + b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%b", b) == "1_00001111_00001111"); +} + +@safe unittest +{ + import std.bitmanip; + + assert(42.swapEndian == 704643072); + assert(42.swapEndian.swapEndian == 42); // reflexive + assert(1.swapEndian == 16777216); + + assert(true.swapEndian == true); + assert(byte(10).swapEndian == 10); + assert(char(10).swapEndian == 10); + + assert(ushort(10).swapEndian == 2560); + assert(long(10).swapEndian == 720575940379279360); + assert(ulong(10).swapEndian == 720575940379279360); +} + +@safe unittest +{ + import std.bitmanip; + + int i = 12345; + ubyte[4] swappedI = nativeToBigEndian(i); + assert(i == bigEndianToNative!int(swappedI)); + + float f = 123.45f; + ubyte[4] swappedF = nativeToBigEndian(f); + assert(f == bigEndianToNative!float(swappedF)); + + const float cf = 123.45f; + ubyte[4] swappedCF = nativeToBigEndian(cf); + assert(cf == bigEndianToNative!float(swappedCF)); + + double d = 123.45; + ubyte[8] swappedD = nativeToBigEndian(d); + assert(d == bigEndianToNative!double(swappedD)); + + const double cd = 123.45; + ubyte[8] swappedCD = nativeToBigEndian(cd); + assert(cd == bigEndianToNative!double(swappedCD)); +} + +@safe unittest +{ + import std.bitmanip; + + ushort i = 12345; + ubyte[2] swappedI = nativeToBigEndian(i); + assert(i == bigEndianToNative!ushort(swappedI)); + + dchar c = 'D'; + ubyte[4] swappedC = nativeToBigEndian(c); + assert(c == bigEndianToNative!dchar(swappedC)); +} + +@safe unittest +{ + import std.bitmanip; + + int i = 12345; + ubyte[4] swappedI = nativeToLittleEndian(i); + assert(i == littleEndianToNative!int(swappedI)); + + float f = 123.45f; + ubyte[4] swappedF = nativeToLittleEndian(f); + assert(f == littleEndianToNative!float(swappedF)); + + const float cf = 123.45f; + ubyte[4] swappedCF = nativeToLittleEndian(cf); + assert(cf == littleEndianToNative!float(swappedCF)); + + double d = 123.45; + ubyte[8] swappedD = nativeToLittleEndian(d); + assert(d == littleEndianToNative!double(swappedD)); + + const double cd = 123.45; + ubyte[8] swappedCD = nativeToLittleEndian(cd); + assert(cd == littleEndianToNative!double(swappedCD)); +} + +@safe unittest +{ + import std.bitmanip; + + ushort i = 12345; + ubyte[2] swappedI = nativeToLittleEndian(i); + assert(i == littleEndianToNative!ushort(swappedI)); + + dchar c = 'D'; + ubyte[4] swappedC = nativeToLittleEndian(c); + assert(c == littleEndianToNative!dchar(swappedC)); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; + assert(buffer.peek!uint() == 17110537); + assert(buffer.peek!ushort() == 261); + assert(buffer.peek!ubyte() == 1); + + assert(buffer.peek!uint(2) == 369700095); + assert(buffer.peek!ushort(2) == 5641); + assert(buffer.peek!ubyte(2) == 22); + + size_t index = 0; + assert(buffer.peek!ushort(&index) == 261); + assert(index == 2); + + assert(buffer.peek!uint(&index) == 369700095); + assert(index == 6); + + assert(buffer.peek!ubyte(&index) == 8); + assert(index == 7); +} + +@safe unittest +{ + import std.bitmanip; + + import std.algorithm.iteration : filter; + ubyte[] buffer = [1, 5, 22, 9, 44, 255, 7]; + auto range = filter!"true"(buffer); + assert(range.peek!uint() == 17110537); + assert(range.peek!ushort() == 261); + assert(range.peek!ubyte() == 1); +} + +@safe unittest +{ + import std.bitmanip; + + import std.range.primitives : empty; + ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; + assert(buffer.length == 7); + + assert(buffer.read!ushort() == 261); + assert(buffer.length == 5); + + assert(buffer.read!uint() == 369700095); + assert(buffer.length == 1); + + assert(buffer.read!ubyte() == 8); + assert(buffer.empty); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + buffer.write!uint(29110231u, 0); + assert(buffer == [1, 188, 47, 215, 0, 0, 0, 0]); + + buffer.write!ushort(927, 0); + assert(buffer == [3, 159, 47, 215, 0, 0, 0, 0]); + + buffer.write!ubyte(42, 0); + assert(buffer == [42, 159, 47, 215, 0, 0, 0, 0]); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + buffer.write!uint(142700095u, 2); + assert(buffer == [0, 0, 8, 129, 110, 63, 0, 0, 0]); + + buffer.write!ushort(19839, 2); + assert(buffer == [0, 0, 77, 127, 110, 63, 0, 0, 0]); + + buffer.write!ubyte(132, 2); + assert(buffer == [0, 0, 132, 127, 110, 63, 0, 0, 0]); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + size_t index = 0; + buffer.write!ushort(261, &index); + assert(buffer == [1, 5, 0, 0, 0, 0, 0, 0]); + assert(index == 2); + + buffer.write!uint(369700095u, &index); + assert(buffer == [1, 5, 22, 9, 44, 255, 0, 0]); + assert(index == 6); + + buffer.write!ubyte(8, &index); + assert(buffer == [1, 5, 22, 9, 44, 255, 8, 0]); + assert(index == 7); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0]; + buffer.write!bool(false, 0); + assert(buffer == [0, 0]); + + buffer.write!bool(true, 0); + assert(buffer == [1, 0]); + + buffer.write!bool(true, 1); + assert(buffer == [1, 1]); + + buffer.write!bool(false, 1); + assert(buffer == [1, 0]); + + size_t index = 0; + buffer.write!bool(false, &index); + assert(buffer == [0, 0]); + assert(index == 1); + + buffer.write!bool(true, &index); + assert(buffer == [0, 1]); + assert(index == 2); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0]; + + buffer.write!char('a', 0); + assert(buffer == [97, 0, 0]); + + buffer.write!char('b', 1); + assert(buffer == [97, 98, 0]); + + size_t index = 0; + buffer.write!char('a', &index); + assert(buffer == [97, 98, 0]); + assert(index == 1); + + buffer.write!char('b', &index); + assert(buffer == [97, 98, 0]); + assert(index == 2); + + buffer.write!char('c', &index); + assert(buffer == [97, 98, 99]); + assert(index == 3); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0]; + + buffer.write!wchar('Ä…', 0); + assert(buffer == [1, 5, 0, 0]); + + buffer.write!wchar('â€', 2); + assert(buffer == [1, 5, 32, 29]); + + size_t index = 0; + buffer.write!wchar('ć', &index); + assert(buffer == [1, 7, 32, 29]); + assert(index == 2); + + buffer.write!wchar('Ä…', &index); + assert(buffer == [1, 7, 1, 5]); + assert(index == 4); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + + buffer.write!dchar('Ä…', 0); + assert(buffer == [0, 0, 1, 5, 0, 0, 0, 0]); + + buffer.write!dchar('â€', 4); + assert(buffer == [0, 0, 1, 5, 0, 0, 32, 29]); + + size_t index = 0; + buffer.write!dchar('ć', &index); + assert(buffer == [0, 0, 1, 7, 0, 0, 32, 29]); + assert(index == 4); + + buffer.write!dchar('Ä…', &index); + assert(buffer == [0, 0, 1, 7, 0, 0, 1, 5]); + assert(index == 8); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + + buffer.write!float(32.0f, 0); + assert(buffer == [66, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!float(25.0f, 4); + assert(buffer == [66, 0, 0, 0, 65, 200, 0, 0]); + + size_t index = 0; + buffer.write!float(25.0f, &index); + assert(buffer == [65, 200, 0, 0, 65, 200, 0, 0]); + assert(index == 4); + + buffer.write!float(32.0f, &index); + assert(buffer == [65, 200, 0, 0, 66, 0, 0, 0]); + assert(index == 8); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + buffer.write!double(32.0, 0); + assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!double(25.0, 8); + assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); + + size_t index = 0; + buffer.write!double(25.0, &index); + assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); + assert(index == 8); + + buffer.write!double(32.0, &index); + assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); + assert(index == 16); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + enum Foo + { + one = 10, + two = 20, + three = 30 + } + + buffer.write!Foo(Foo.one, 0); + assert(buffer == [0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!Foo(Foo.two, 4); + assert(buffer == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 0]); + + buffer.write!Foo(Foo.three, 8); + assert(buffer == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]); + + size_t index = 0; + buffer.write!Foo(Foo.three, &index); + assert(buffer == [0, 0, 0, 30, 0, 0, 0, 20, 0, 0, 0, 30]); + assert(index == 4); + + buffer.write!Foo(Foo.one, &index); + assert(buffer == [0, 0, 0, 30, 0, 0, 0, 10, 0, 0, 0, 30]); + assert(index == 8); + + buffer.write!Foo(Foo.two, &index); + assert(buffer == [0, 0, 0, 30, 0, 0, 0, 10, 0, 0, 0, 20]); + assert(index == 12); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + + enum Float: float + { + one = 32.0f, + two = 25.0f + } + + buffer.write!Float(Float.one, 0); + assert(buffer == [66, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!Float(Float.two, 4); + assert(buffer == [66, 0, 0, 0, 65, 200, 0, 0]); + + size_t index = 0; + buffer.write!Float(Float.two, &index); + assert(buffer == [65, 200, 0, 0, 65, 200, 0, 0]); + assert(index == 4); + + buffer.write!Float(Float.one, &index); + assert(buffer == [65, 200, 0, 0, 66, 0, 0, 0]); + assert(index == 8); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + enum Double: double + { + one = 32.0, + two = 25.0 + } + + buffer.write!Double(Double.one, 0); + assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!Double(Double.two, 8); + assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); + + size_t index = 0; + buffer.write!Double(Double.two, &index); + assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); + assert(index == 8); + + buffer.write!Double(Double.one, &index); + assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); + assert(index == 16); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + enum Real: real + { + one = 32.0, + two = 25.0 + } + + static assert(!__traits(compiles, buffer.write!Real(Real.one))); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array; + auto buffer = appender!(const ubyte[])(); + buffer.append!ushort(261); + assert(buffer.data == [1, 5]); + + buffer.append!uint(369700095u); + assert(buffer.data == [1, 5, 22, 9, 44, 255]); + + buffer.append!ubyte(8); + assert(buffer.data == [1, 5, 22, 9, 44, 255, 8]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + buffer.append!bool(true); + assert(buffer.data == [1]); + + buffer.append!bool(false); + assert(buffer.data == [1, 0]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + buffer.append!char('a'); + assert(buffer.data == [97]); + + buffer.append!char('b'); + assert(buffer.data == [97, 98]); + + buffer.append!wchar('Ä…'); + assert(buffer.data == [97, 98, 1, 5]); + + buffer.append!dchar('Ä…'); + assert(buffer.data == [97, 98, 1, 5, 0, 0, 1, 5]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + buffer.append!float(32.0f); + assert(buffer.data == [66, 0, 0, 0]); + + buffer.append!double(32.0); + assert(buffer.data == [66, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Foo + { + one = 10, + two = 20, + three = 30 + } + + buffer.append!Foo(Foo.one); + assert(buffer.data == [0, 0, 0, 10]); + + buffer.append!Foo(Foo.two); + assert(buffer.data == [0, 0, 0, 10, 0, 0, 0, 20]); + + buffer.append!Foo(Foo.three); + assert(buffer.data == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Bool: bool + { + bfalse = false, + btrue = true, + } + + buffer.append!Bool(Bool.btrue); + assert(buffer.data == [1]); + + buffer.append!Bool(Bool.bfalse); + assert(buffer.data == [1, 0]); + + buffer.append!Bool(Bool.btrue); + assert(buffer.data == [1, 0, 1]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Float: float + { + one = 32.0f, + two = 25.0f + } + + buffer.append!Float(Float.one); + assert(buffer.data == [66, 0, 0, 0]); + + buffer.append!Float(Float.two); + assert(buffer.data == [66, 0, 0, 0, 65, 200, 0, 0]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Double: double + { + one = 32.0, + two = 25.0 + } + + buffer.append!Double(Double.one); + assert(buffer.data == [64, 64, 0, 0, 0, 0, 0, 0]); + + buffer.append!Double(Double.two); + assert(buffer.data == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Real: real + { + one = 32.0, + two = 25.0 + } + + static assert(!__traits(compiles, buffer.append!Real(Real.one))); +} + +@safe unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.range : iota; + + assert(bitsSet(1).equal([0])); + assert(bitsSet(5).equal([0, 2])); + assert(bitsSet(-1).equal(iota(32))); + assert(bitsSet(int.min).equal([31])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_checkedint.d b/libphobos/testsuite/libphobos.phobos/std_checkedint.d new file mode 100644 index 0000000000000000000000000000000000000000..589d8d3a716cfae47e2a93cd7d2e1e60bedbbfe9 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_checkedint.d @@ -0,0 +1,628 @@ +@safe unittest +{ + import std.checkedint; + + int[] concatAndAdd(int[] a, int[] b, int offset) + { + // Aborts on overflow on size computation + auto r = new int[(checked(a.length) + b.length).get]; + // Aborts on overflow on element computation + foreach (i; 0 .. a.length) + r[i] = (a[i] + checked(offset)).get; + foreach (i; 0 .. b.length) + r[i + a.length] = (b[i] + checked(offset)).get; + return r; + } + assert(concatAndAdd([1, 2, 3], [4, 5], -1) == [0, 1, 2, 3, 4]); +} + +@safe unittest +{ + import std.checkedint; + + auto x = (cast(byte) 127).checked!Saturate; + assert(x == 127); + x++; + assert(x == 127); +} + +@safe unittest +{ + import std.checkedint; + + auto x = 100.checked!WithNaN; + assert(x == 100); + x /= 0; + assert(x.isNaN); +} + +@safe unittest +{ + import std.checkedint; + + uint x = 1; + auto y = x.checked!ProperCompare; + assert(x < -1); // built-in comparison + assert(y > -1); // ProperCompare +} + +@safe unittest +{ + import std.checkedint; + + import std.exception : assertThrown; + auto x = -1.checked!Throw; + assertThrown(x / 0); + assertThrown(x + int.min); + assertThrown(x == uint.max); +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked(ubyte(42)); + static assert(is(typeof(x.get()) == ubyte)); + assert(x.get == 42); + const y = checked(ubyte(42)); + static assert(is(typeof(y.get()) == const ubyte)); + assert(y.get == 42); + +} + +@safe unittest +{ + import std.checkedint; + + assert(Checked!short.min == -32768); + assert(Checked!(short, WithNaN).min == -32767); + assert(Checked!(uint, WithNaN).max == uint.max - 1); + +} + +@safe unittest +{ + import std.checkedint; + + auto a = checked(42L); + assert(a == 42); + auto b = Checked!long(4242); // convert 4242 to long + assert(b == 4242); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!long a; + a = 42L; + assert(a == 42); + a = 4242; + assert(a == 4242); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!long a, b; + a = b = 3; + assert(a == 3 && b == 3); + +} + +@system unittest +{ + import std.checkedint; + + import std.conv : to; + + const a = to!long("1234"); + const b = to!(Checked!long)("1234"); + assert(a == b); + +} + +@safe unittest +{ + import std.checkedint; + + assert(cast(uint) checked(42) == 42); + assert(cast(uint) checked!WithNaN(-42) == uint.max); + +} + +@safe unittest +{ + import std.checkedint; + + import std.traits : isUnsigned; + + static struct MyHook + { + static bool thereWereErrors; + static bool hookOpEquals(L, R)(L lhs, R rhs) + { + if (lhs != rhs) return false; + static if (isUnsigned!L && !isUnsigned!R) + { + if (lhs > 0 && rhs < 0) thereWereErrors = true; + } + else static if (isUnsigned!R && !isUnsigned!L) + if (lhs < 0 && rhs > 0) thereWereErrors = true; + // Preserve built-in behavior. + return true; + } + } + auto a = checked!MyHook(-42); + assert(a == uint(-42)); + assert(MyHook.thereWereErrors); + MyHook.thereWereErrors = false; + assert(checked!MyHook(uint(-42)) == -42); + assert(MyHook.thereWereErrors); + static struct MyHook2 + { + static bool hookOpEquals(L, R)(L lhs, R rhs) + { + return lhs == rhs; + } + } + MyHook.thereWereErrors = false; + assert(checked!MyHook2(uint(-42)) == a); + // Hook on left hand side takes precedence, so no errors + assert(!MyHook.thereWereErrors); + +} + +@system unittest +{ + import std.checkedint; + + import std.format; + + assert(format("%04d", checked(15)) == "0015"); + assert(format("0x%02x", checked(15)) == "0x0f"); + +} + +@safe unittest +{ + import std.checkedint; + + import std.traits : isUnsigned; + + static struct MyHook + { + static bool thereWereErrors; + static int hookOpCmp(L, R)(L lhs, R rhs) + { + static if (isUnsigned!L && !isUnsigned!R) + { + if (rhs < 0 && rhs >= lhs) + thereWereErrors = true; + } + else static if (isUnsigned!R && !isUnsigned!L) + { + if (lhs < 0 && lhs >= rhs) + thereWereErrors = true; + } + // Preserve built-in behavior. + return lhs < rhs ? -1 : lhs > rhs; + } + } + auto a = checked!MyHook(-42); + assert(a > uint(42)); + assert(MyHook.thereWereErrors); + static struct MyHook2 + { + static int hookOpCmp(L, R)(L lhs, R rhs) + { + // Default behavior + return lhs < rhs ? -1 : lhs > rhs; + } + } + MyHook.thereWereErrors = false; + assert(Checked!(uint, MyHook2)(uint(-42)) <= a); + //assert(Checked!(uint, MyHook2)(uint(-42)) >= a); + // Hook on left hand side takes precedence, so no errors + assert(!MyHook.thereWereErrors); + assert(a <= Checked!(uint, MyHook2)(uint(-42))); + assert(MyHook.thereWereErrors); + +} + +@safe unittest +{ + import std.checkedint; + + static struct MyHook + { + static bool thereWereErrors; + static L hookOpUnary(string x, L)(L lhs) + { + if (x == "-" && lhs == -lhs) thereWereErrors = true; + return -lhs; + } + } + auto a = checked!MyHook(long.min); + assert(a == -a); + assert(MyHook.thereWereErrors); + auto b = checked!void(42); + assert(++b == 43); + +} + +@safe unittest +{ + import std.checkedint; + + static struct MyHook + { + static bool thereWereErrors; + static T onLowerBound(Rhs, T)(Rhs rhs, T bound) + { + thereWereErrors = true; + return bound; + } + static T onUpperBound(Rhs, T)(Rhs rhs, T bound) + { + thereWereErrors = true; + return bound; + } + } + auto x = checked!MyHook(byte.min); + x -= 1; + assert(MyHook.thereWereErrors); + MyHook.thereWereErrors = false; + x = byte.max; + x += 1; + assert(MyHook.thereWereErrors); + +} + +@safe @nogc pure nothrow unittest +{ + import std.checkedint; + + // Hook that ignores all problems. + static struct Ignore + { + @nogc nothrow pure @safe static: + Dst onBadCast(Dst, Src)(Src src) { return cast(Dst) src; } + Lhs onLowerBound(Rhs, T)(Rhs rhs, T bound) { return cast(T) rhs; } + T onUpperBound(Rhs, T)(Rhs rhs, T bound) { return cast(T) rhs; } + bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs) { return lhs == rhs; } + int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs) { return (lhs > rhs) - (lhs < rhs); } + typeof(~Lhs()) onOverflow(string x, Lhs)(ref Lhs lhs) { return mixin(x ~ "lhs"); } + typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs) + { + static if (x == "/") + return typeof(lhs / rhs).min; + else + return mixin("lhs" ~ x ~ "rhs"); + } + } + + auto x = Checked!(int, Ignore)(5) + 7; +} + +@safe unittest +{ + import std.checkedint; + + static assert(is(typeof(checked(42)) == Checked!int)); + assert(checked(42) == Checked!int(42)); + static assert(is(typeof(checked!WithNaN(42)) == Checked!(int, WithNaN))); + assert(checked!WithNaN(42) == Checked!(int, WithNaN)(42)); +} + +@safe unittest +{ + import std.checkedint; + + void test(T)() + { + Checked!(int, Abort) x; + x = 42; + auto x1 = cast(T) x; + assert(x1 == 42); + //x1 += long(int.max); + } + test!short; + test!(const short); + test!(immutable short); +} + +@safe unittest +{ + import std.checkedint; + + void test(T)() + { + Checked!(int, Throw) x; + x = 42; + auto x1 = cast(T) x; + assert(x1 == 42); + x = T.max + 1; + import std.exception : assertThrown, assertNotThrown; + assertThrown(cast(T) x); + x = x.max; + assertThrown(x += 42); + assertThrown(x += 42L); + x = x.min; + assertThrown(-x); + assertThrown(x -= 42); + assertThrown(x -= 42L); + x = -1; + assertNotThrown(x == -1); + assertThrown(x == uint(-1)); + assertNotThrown(x <= -1); + assertThrown(x <= uint(-1)); + } + test!short; + test!(const short); + test!(immutable short); +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Warn(-42); + // Passes + assert(x == -42); + // Passes but prints a warning + // assert(x == uint(-42)); + +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Warn(-42); + // Passes + assert(x <= -42); + // Passes but prints a warning + // assert(x <= uint(-42)); + +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Warn(42); + short x1 = cast(short) x; + //x += long(int.max); + auto y = checked!Warn(cast(const int) 42); + short y1 = cast(const byte) y; +} + +@safe unittest +{ + import std.checkedint; + + alias opEqualsProper = ProperCompare.hookOpEquals; + assert(opEqualsProper(42, 42)); + assert(opEqualsProper(42.0, 42.0)); + assert(opEqualsProper(42u, 42)); + assert(opEqualsProper(42, 42u)); + assert(-1 == 4294967295u); + assert(!opEqualsProper(-1, 4294967295u)); + assert(!opEqualsProper(const uint(-1), -1)); + assert(!opEqualsProper(uint(-1), -1.0)); + assert(3_000_000_000U == -1_294_967_296); + assert(!opEqualsProper(3_000_000_000U, -1_294_967_296)); +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!WithNaN(422); + assert((cast(ubyte) x) == 255); + x = checked!WithNaN(-422); + assert((cast(byte) x) == -128); + assert(cast(short) x == -422); + assert(cast(bool) x); + x = x.init; // set back to NaN + assert(x != true); + assert(x != false); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + assert(!(x < 0) && !(x > 0) && !(x == 0)); + x = 1; + assert(x > 0 && !(x < 0) && !(x == 0)); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + ++x; + assert(x.isNaN); + x = 1; + assert(!x.isNaN); + x = -x; + ++x; + assert(!x.isNaN); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + assert((x + 1).isNaN); + x = 100; + assert(!(x + 1).isNaN); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + assert((1 + x).isNaN); + x = 100; + assert(!(1 + x).isNaN); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + x += 4; + assert(x.isNaN); + x = 0; + x += 4; + assert(!x.isNaN); + x += int.max; + assert(x.isNaN); + +} + +@safe unittest +{ + import std.checkedint; + + auto x1 = Checked!(int, WithNaN)(); + assert(x1.isNaN); + assert(x1.get == int.min); + assert(x1 != x1); + assert(!(x1 < x1)); + assert(!(x1 > x1)); + assert(!(x1 == x1)); + ++x1; + assert(x1.isNaN); + assert(x1.get == int.min); + --x1; + assert(x1.isNaN); + assert(x1.get == int.min); + x1 = 42; + assert(!x1.isNaN); + assert(x1 == x1); + assert(x1 <= x1); + assert(x1 >= x1); + static assert(x1.min == int.min + 1); + x1 += long(int.max); +} + +@safe unittest +{ + import std.checkedint; + + auto x1 = Checked!(int, WithNaN)(); + assert(x1.isNaN); + x1 = 1; + assert(!x1.isNaN); + x1 = x1.init; + assert(x1.isNaN); +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Saturate(short(100)); + x += 33000; + assert(x == short.max); + x -= 70000; + assert(x == short.min); + +} + +@safe unittest +{ + import std.checkedint; + + assert(checked!Saturate(int.max) + 1 == int.max); + assert(checked!Saturate(100) ^^ 10 == int.max); + assert(checked!Saturate(-100) ^^ 10 == int.max); + assert(checked!Saturate(100) / 0 == int.max); + assert(checked!Saturate(100) << -1 == 0); + assert(checked!Saturate(100) << 33 == int.max); + assert(checked!Saturate(100) >> -1 == int.max); + assert(checked!Saturate(100) >> 33 == 0); + +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Saturate(int.max); + ++x; + assert(x == int.max); + --x; + assert(x == int.max - 1); + x = int.min; + assert(-x == int.max); + x -= 42; + assert(x == int.min); + assert(x * -2 == int.max); +} + +@safe unittest +{ + import std.checkedint; + + bool overflow; + assert(opChecked!"+"(const short(1), short(1), overflow) == 2 && !overflow); + assert(opChecked!"+"(1, 1, overflow) == 2 && !overflow); + assert(opChecked!"+"(1, 1u, overflow) == 2 && !overflow); + assert(opChecked!"+"(-1, 1u, overflow) == 0 && !overflow); + assert(opChecked!"+"(1u, -1, overflow) == 0 && !overflow); +} + +@safe unittest +{ + import std.checkedint; + + bool overflow; + assert(opChecked!"-"(1, 1, overflow) == 0 && !overflow); + assert(opChecked!"-"(1, 1u, overflow) == 0 && !overflow); + assert(opChecked!"-"(1u, -1, overflow) == 2 && !overflow); + assert(opChecked!"-"(-1, 1u, overflow) == 0 && overflow); +} + +@safe unittest +{ + import std.checkedint; + + struct MyHook + { + static size_t hookToHash(T)(const T payload) nothrow @trusted + { + return .hashOf(payload); + } + } + + int[Checked!(int, MyHook)] aa; + Checked!(int, MyHook) var = 42; + aa[var] = 100; + + assert(aa[var] == 100); + + int[Checked!(int, Abort)] bb; + Checked!(int, Abort) var2 = 42; + bb[var2] = 100; + + assert(bb[var2] == 100); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_complex.d b/libphobos/testsuite/libphobos.phobos/std_complex.d new file mode 100644 index 0000000000000000000000000000000000000000..44ac5d7fdf2a6e6b06c34ade00fc126439a0cd31 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_complex.d @@ -0,0 +1,403 @@ +@safe pure nothrow unittest +{ + import std.complex; + + auto a = complex(1.0); + static assert(is(typeof(a) == Complex!double)); + assert(a.re == 1.0); + assert(a.im == 0.0); + + auto b = complex(2.0L); + static assert(is(typeof(b) == Complex!real)); + assert(b.re == 2.0L); + assert(b.im == 0.0L); + + auto c = complex(1.0, 2.0); + static assert(is(typeof(c) == Complex!double)); + assert(c.re == 1.0); + assert(c.im == 2.0); + + auto d = complex(3.0, 4.0L); + static assert(is(typeof(d) == Complex!real)); + assert(d.re == 3.0); + assert(d.im == 4.0L); + + auto e = complex(1); + static assert(is(typeof(e) == Complex!double)); + assert(e.re == 1); + assert(e.im == 0); + + auto f = complex(1L, 2); + static assert(is(typeof(f) == Complex!double)); + assert(f.re == 1L); + assert(f.im == 2); + + auto g = complex(3, 4.0L); + static assert(is(typeof(g) == Complex!real)); + assert(g.re == 3); + assert(g.im == 4.0L); +} + +@safe unittest +{ + import std.complex; + + auto c = complex(1.2, 3.4); + + // Vanilla toString formatting: + assert(c.toString() == "1.2+3.4i"); + + // Formatting with std.string.format specs: the precision and width + // specifiers apply to both the real and imaginary parts of the + // complex number. + import std.format : format; + assert(format("%.2f", c) == "1.20+3.40i"); + assert(format("%4.1f", c) == " 1.2+ 3.4i"); + +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import core.math; + assert(abs(complex(1.0)) == 1.0); + assert(abs(complex(0.0, 1.0)) == 1.0); + assert(abs(complex(1.0L, -2.0L)) == core.math.sqrt(5.0L)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + assert(sqAbs(complex(0.0)) == 0.0); + assert(sqAbs(complex(1.0)) == 1.0); + assert(sqAbs(complex(0.0, 1.0)) == 1.0); + assert(isClose(sqAbs(complex(1.0L, -2.0L)), 5.0L)); + assert(isClose(sqAbs(complex(-3.0L, 1.0L)), 10.0L)); + assert(isClose(sqAbs(complex(1.0f,-1.0f)), 2.0f)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.constants : PI_2, PI_4; + assert(arg(complex(1.0)) == 0.0); + assert(arg(complex(0.0L, 1.0L)) == PI_2); + assert(arg(complex(1.0L, 1.0L)) == PI_4); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + assert(norm(complex(3.0, 4.0)) == 25.0); + assert(norm(fromPolar(5.0, 0.0)) == 25.0); + assert(isClose(norm(fromPolar(5.0L, PI / 6)), 25.0L)); + assert(isClose(norm(fromPolar(5.0L, 13 * PI / 6)), 25.0L)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + assert(conj(complex(1.0)) == complex(1.0)); + assert(conj(complex(1.0, 2.0)) == complex(1.0, -2.0)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + assert(proj(complex(1.0)) == complex(1.0)); + assert(proj(complex(double.infinity, 5.0)) == complex(double.infinity, 0.0)); + assert(proj(complex(5.0, -double.infinity)) == complex(double.infinity, -0.0)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import core.math; + import std.math.operations : isClose; + import std.math.algebraic : sqrt; + import std.math.constants : PI_4; + auto z = fromPolar(core.math.sqrt(2.0L), PI_4); + assert(isClose(z.re, 1.0L)); + assert(isClose(z.im, 1.0L)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import core.math; + assert(sin(complex(0.0)) == 0.0); + assert(sin(complex(2.0, 0)) == core.math.sin(2.0)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import core.math; + static import std.math; + assert(cos(complex(0.0)) == 1.0); + assert(cos(complex(1.3, 0.0)) == core.math.cos(1.3)); + assert(cos(complex(0.0, 5.2)) == std.math.cosh(5.2)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + static import std.math; + + int ceqrel(T)(const Complex!T x, const Complex!T y) @safe pure nothrow @nogc + { + import std.math.operations : feqrel; + const r = feqrel(x.re, y.re); + const i = feqrel(x.im, y.im); + return r < i ? r : i; + } + assert(ceqrel(tan(complex(1.0, 0.0)), complex(std.math.tan(1.0), 0.0)) >= double.mant_dig - 2); + assert(ceqrel(tan(complex(0.0, 1.0)), complex(0.0, std.math.tanh(1.0))) >= double.mant_dig - 2); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + assert(asin(complex(0.0)) == 0.0); + assert(isClose(asin(complex(0.5L)), PI / 6)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + import std.math.trigonometry : std_math_acos = acos; + assert(acos(complex(0.0)) == std_math_acos(0.0)); + assert(isClose(acos(complex(0.5L)), PI / 3)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + assert(atan(complex(0.0)) == 0.0); + assert(isClose(atan(sqrt(complex(3.0L))), PI / 3)); + assert(isClose(atan(sqrt(complex(3.0f))), float(PI) / 3)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import std.math; + assert(sinh(complex(0.0)) == 0.0); + assert(sinh(complex(1.0L)) == std.math.sinh(1.0L)); + assert(sinh(complex(1.0f)) == std.math.sinh(1.0f)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import std.math; + assert(cosh(complex(0.0)) == 1.0); + assert(cosh(complex(1.0L)) == std.math.cosh(1.0L)); + assert(cosh(complex(1.0f)) == std.math.cosh(1.0f)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.trigonometry : std_math_tanh = tanh; + assert(tanh(complex(0.0)) == 0.0); + assert(isClose(tanh(complex(1.0L)), std_math_tanh(1.0L))); + assert(isClose(tanh(complex(1.0f)), std_math_tanh(1.0f))); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.trigonometry : std_math_asinh = asinh; + assert(asinh(complex(0.0)) == 0.0); + assert(isClose(asinh(complex(1.0L)), std_math_asinh(1.0L))); + assert(isClose(asinh(complex(1.0f)), std_math_asinh(1.0f))); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.trigonometry : std_math_acosh = acosh; + assert(acosh(complex(1.0)) == 0.0); + assert(isClose(acosh(complex(3.0L)), std_math_acosh(3.0L))); + assert(isClose(acosh(complex(3.0f)), std_math_acosh(3.0f))); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.trigonometry : std_math_atanh = atanh; + assert(atanh(complex(0.0)) == 0.0); + assert(isClose(atanh(complex(0.5L)), std_math_atanh(0.5L))); + assert(isClose(atanh(complex(0.5f)), std_math_atanh(0.5f))); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import core.math : cos, sin; + assert(expi(0.0L) == 1.0L); + assert(expi(1.3e5L) == complex(cos(1.3e5L), sin(1.3e5L))); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.trigonometry : cosh, sinh; + assert(coshisinh(3.0L) == complex(cosh(3.0L), sinh(3.0L))); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import core.math; + assert(sqrt(complex(0.0)) == 0.0); + assert(sqrt(complex(1.0L, 0)) == core.math.sqrt(1.0L)); + assert(sqrt(complex(-1.0L, 0)) == complex(0, 1.0L)); + assert(sqrt(complex(-8.0, -6.0)) == complex(1.0, -3.0)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + + assert(exp(complex(0.0, 0.0)) == complex(1.0, 0.0)); + + auto a = complex(2.0, 1.0); + assert(exp(conj(a)) == conj(exp(a))); + + auto b = exp(complex(0.0L, 1.0L) * PI); + assert(isClose(b, -1.0L, 0.0, 1e-15)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import core.math : sqrt; + import std.math.constants : PI; + import std.math.operations : isClose; + + auto a = complex(2.0, 1.0); + assert(log(conj(a)) == conj(log(a))); + + auto b = 2.0 * log10(complex(0.0, 1.0)); + auto c = 4.0 * log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)); + assert(isClose(b, c, 0.0, 1e-15)); + + assert(log(complex(-1.0L, 0.0L)) == complex(0.0L, PI)); + assert(log(complex(-1.0L, -0.0L)) == complex(0.0L, -PI)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import core.math : sqrt; + import std.math.constants : LN10, PI; + import std.math.operations : isClose; + + auto a = complex(2.0, 1.0); + assert(log10(a) == log(a) / log(complex(10.0))); + + auto b = log10(complex(0.0, 1.0)) * 2.0; + auto c = log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)) * 4.0; + assert(isClose(b, c, 0.0, 1e-15)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + + auto a = complex(1.0, 2.0); + assert(pow(a, 2) == a * a); + assert(pow(a, 3) == a * a * a); + assert(pow(a, -2) == 1.0 / (a * a)); + assert(isClose(pow(a, -3), 1.0 / (a * a * a))); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + assert(pow(complex(0.0), 2.0) == complex(0.0)); + assert(pow(complex(5.0), 2.0) == complex(25.0)); + + auto a = pow(complex(-1.0, 0.0), 0.5); + assert(isClose(a, complex(0.0, +1.0), 0.0, 1e-16)); + + auto b = pow(complex(-1.0, -0.0), 0.5); + assert(isClose(b, complex(0.0, -1.0), 0.0, 1e-16)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.exponential : exp; + import std.math.constants : PI; + auto a = complex(0.0); + auto b = complex(2.0); + assert(pow(a, b) == complex(0.0)); + + auto c = complex(0.0L, 1.0L); + assert(isClose(pow(c, c), exp((-PI) / 2))); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + assert(pow(2.0, complex(0.0)) == complex(1.0)); + assert(pow(2.0, complex(5.0)) == complex(32.0)); + + auto a = pow(-2.0, complex(-1.0)); + assert(isClose(a, complex(-0.5), 0.0, 1e-16)); + + auto b = pow(-0.5, complex(-1.0)); + assert(isClose(b, complex(-2.0), 0.0, 1e-15)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_concurrency.d b/libphobos/testsuite/libphobos.phobos/std_concurrency.d new file mode 100644 index 0000000000000000000000000000000000000000..46da87d47af6ba6c0a370d31082f9dd040f2d23e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_concurrency.d @@ -0,0 +1,235 @@ +@system unittest +{ + import std.concurrency; + + __gshared string received; + static void spawnedFunc(Tid ownerTid) + { + import std.conv : text; + // Receive a message from the owner thread. + receive((int i){ + received = text("Received the number ", i); + + // Send a message back to the owner thread + // indicating success. + send(ownerTid, true); + }); + } + + // Start spawnedFunc in a new thread. + auto childTid = spawn(&spawnedFunc, thisTid); + + // Send the number 42 to this new thread. + send(childTid, 42); + + // Receive the result code. + auto wasSuccessful = receiveOnly!(bool); + assert(wasSuccessful); + assert(received == "Received the number 42"); +} + +@system unittest +{ + import std.concurrency; + + static void f(string msg) + { + assert(msg == "Hello World"); + } + + auto tid = spawn(&f, "Hello World"); +} + +@system unittest +{ + import std.concurrency; + + string msg = "Hello, World!"; + + static void f1(string msg) {} + static assert(!__traits(compiles, spawn(&f1, msg.dup))); + static assert( __traits(compiles, spawn(&f1, msg.idup))); + + static void f2(char[] msg) {} + static assert(!__traits(compiles, spawn(&f2, msg.dup))); + static assert(!__traits(compiles, spawn(&f2, msg.idup))); +} + +@system unittest +{ + import std.concurrency; + + spawn({ + ownerTid.send("This is so great!"); + }); + assert(receiveOnly!string == "This is so great!"); +} + +@system unittest +{ + import std.concurrency; + + import std.variant : Variant; + + auto process = () + { + receive( + (int i) { ownerTid.send(1); }, + (double f) { ownerTid.send(2); }, + (Variant v) { ownerTid.send(3); } + ); + }; + + { + auto tid = spawn(process); + send(tid, 42); + assert(receiveOnly!int == 1); + } + + { + auto tid = spawn(process); + send(tid, 3.14); + assert(receiveOnly!int == 2); + } + + { + auto tid = spawn(process); + send(tid, "something else"); + assert(receiveOnly!int == 3); + } +} + +@system unittest +{ + import std.concurrency; + + auto tid = spawn( + { + assert(receiveOnly!int == 42); + }); + send(tid, 42); +} + +@system unittest +{ + import std.concurrency; + + auto tid = spawn( + { + assert(receiveOnly!string == "text"); + }); + send(tid, "text"); +} + +@system unittest +{ + import std.concurrency; + + struct Record { string name; int age; } + + auto tid = spawn( + { + auto msg = receiveOnly!(double, Record); + assert(msg[0] == 0.5); + assert(msg[1].name == "Alice"); + assert(msg[1].age == 31); + }); + + send(tid, 0.5, Record("Alice", 31)); +} + +@system unittest +{ + import std.concurrency; + + auto tid = spawn({ + int i; + while (i < 9) + i = receiveOnly!int; + + ownerTid.send(i * 2); + }); + + auto r = new Generator!int({ + foreach (i; 1 .. 10) + yield(i); + }); + + foreach (e; r) + tid.send(e); + + assert(receiveOnly!int == 18); +} + +@system unittest +{ + import std.concurrency; + + import std.range; + + InputRange!int myIota = iota(10).inputRangeObject; + + myIota.popFront(); + myIota.popFront(); + assert(myIota.moveFront == 2); + assert(myIota.front == 2); + myIota.popFront(); + assert(myIota.front == 3); + + //can be assigned to std.range.interfaces.InputRange directly + myIota = new Generator!int( + { + foreach (i; 0 .. 10) yield(i); + }); + + myIota.popFront(); + myIota.popFront(); + assert(myIota.moveFront == 2); + assert(myIota.front == 2); + myIota.popFront(); + assert(myIota.front == 3); + + size_t[2] counter = [0, 0]; + foreach (i, unused; myIota) counter[] += [1, i]; + + assert(myIota.empty); + assert(counter == [7, 21]); +} + +@system unittest +{ + import std.concurrency; + + static class MySingleton + { + static MySingleton instance() + { + __gshared MySingleton inst; + return initOnce!inst(new MySingleton); + } + } + + assert(MySingleton.instance !is null); +} + +@system unittest +{ + import std.concurrency; + + import core.sync.mutex : Mutex; + + static shared bool varA, varB; + static shared Mutex m; + m = new shared Mutex; + + spawn({ + // use a different mutex for varB to avoid a dead-lock + initOnce!varB(true, m); + ownerTid.send(true); + }); + // init depends on the result of the spawned thread + initOnce!varA(receiveOnly!bool); + assert(varA == true); + assert(varB == true); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_array.d b/libphobos/testsuite/libphobos.phobos/std_container_array.d new file mode 100644 index 0000000000000000000000000000000000000000..abf8dd57ceb95adafb5c96b98bceef7e62055a6c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_array.d @@ -0,0 +1,56 @@ +pure @system unittest +{ + import std.container.array; + + auto arr = Array!int(0, 2, 3); + assert(arr[0] == 0); + assert(arr.front == 0); + assert(arr.back == 3); + + // reserve space + arr.reserve(1000); + assert(arr.length == 3); + assert(arr.capacity >= 1000); + + // insertion + arr.insertBefore(arr[1..$], 1); + assert(arr.front == 0); + assert(arr.length == 4); + + arr.insertBack(4); + assert(arr.back == 4); + assert(arr.length == 5); + + // set elements + arr[1] *= 42; + assert(arr[1] == 42); +} + +pure @system unittest +{ + import std.container.array; + + import std.algorithm.comparison : equal; + auto arr = Array!int(1, 2, 3); + + // concat + auto b = Array!int(11, 12, 13); + arr ~= b; + assert(arr.length == 6); + + // slicing + assert(arr[1 .. 3].equal([2, 3])); + + // remove + arr.linearRemove(arr[1 .. 3]); + assert(arr[0 .. 2].equal([1, 11])); +} + +pure @system unittest +{ + import std.container.array; + + auto arr = Array!bool([true, true, false, true, false]); + assert(arr.length == 5); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_binaryheap.d b/libphobos/testsuite/libphobos.phobos/std_container_binaryheap.d new file mode 100644 index 0000000000000000000000000000000000000000..1ebcc6738feca377eb4636c1d11ec1b1546840f5 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_binaryheap.d @@ -0,0 +1,102 @@ +@system unittest +{ + import std.container.binaryheap; + + import std.algorithm.comparison : equal; + import std.range : take; + auto maxHeap = heapify([4, 7, 3, 1, 5]); + assert(maxHeap.take(3).equal([7, 5, 4])); + + auto minHeap = heapify!"a > b"([4, 7, 3, 1, 5]); + assert(minHeap.take(3).equal([1, 3, 4])); +} + +@system unittest +{ + import std.container.binaryheap; + + import std.algorithm.comparison : equal; + int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; + auto h = heapify(a); + // largest element + assert(h.front == 16); + // a has the heap property + assert(equal(a, [ 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 ])); +} + +@system unittest +{ + import std.container.binaryheap; + + import std.algorithm.comparison : equal; + import std.range : take; + int[] a = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]; + auto top5 = heapify(a).take(5); + assert(top5.equal([16, 14, 10, 9, 8])); +} + +@system unittest +{ + import std.container.binaryheap; + + import std.conv : to; + import std.range.primitives; + { + // example from "Introduction to Algorithms" Cormen et al., p 146 + int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; + auto h = heapify(a); + h = heapify!"a < b"(a); + assert(h.front == 16); + assert(a == [ 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 ]); + auto witness = [ 16, 14, 10, 9, 8, 7, 4, 3, 2, 1 ]; + for (; !h.empty; h.removeFront(), witness.popFront()) + { + assert(!witness.empty); + assert(witness.front == h.front); + } + assert(witness.empty); + } + { + int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; + int[] b = new int[a.length]; + BinaryHeap!(int[]) h = BinaryHeap!(int[])(b, 0); + foreach (e; a) + { + h.insert(e); + } + assert(b == [ 16, 14, 10, 8, 7, 3, 9, 1, 4, 2 ], to!string(b)); + } +} + +@system unittest +{ + import std.container.binaryheap; + + import std.stdio; + import std.algorithm.comparison : equal; + import std.container.binaryheap; + + int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; + auto h = heapify(a); + + // Internal representation of Binary Heap tree + assert(a.equal([16, 14, 10, 8, 7, 9, 3, 2, 4, 1])); + + h.replaceFront(30); + // Value 16 was replaced by 30 + assert(a.equal([30, 14, 10, 8, 7, 9, 3, 2, 4, 1])); + + // Making changes to the Store will be seen in the Heap + a[0] = 40; + assert(h.front() == 40); + + // Inserting a new element will reallocate the Store, leaving + // the original Store unchanged. + h.insert(20); + assert(a.equal([40, 14, 10, 8, 7, 9, 3, 2, 4, 1])); + + // Making changes to the original Store will not affect the Heap anymore + a[0] = 60; + assert(h.front() == 40); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_dlist.d b/libphobos/testsuite/libphobos.phobos/std_container_dlist.d new file mode 100644 index 0000000000000000000000000000000000000000..f9510485a08e32b4f1385f281a23c9c7d04d59d1 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_dlist.d @@ -0,0 +1,47 @@ +@safe unittest +{ + import std.container.dlist; + + import std.algorithm.comparison : equal; + import std.container : DList; + + auto s = DList!int(1, 2, 3); + assert(equal(s[], [1, 2, 3])); + + s.removeFront(); + assert(equal(s[], [2, 3])); + s.removeBack(); + assert(equal(s[], [2])); + + s.insertFront([4, 5]); + assert(equal(s[], [4, 5, 2])); + s.insertBack([6, 7]); + assert(equal(s[], [4, 5, 2, 6, 7])); + + // If you want to apply range operations, simply slice it. + import std.algorithm.searching : countUntil; + import std.range : popFrontN, popBackN, walkLength; + + auto sl = DList!int([1, 2, 3, 4, 5]); + assert(countUntil(sl[], 2) == 1); + + auto r = sl[]; + popFrontN(r, 2); + popBackN(r, 2); + assert(r.equal([3])); + assert(walkLength(r) == 1); + + // DList.Range can be used to remove elements from the list it spans + auto nl = DList!int([1, 2, 3, 4, 5]); + for (auto rn = nl[]; !rn.empty;) + if (rn.front % 2 == 0) + nl.popFirstOf(rn); + else + rn.popFront(); + assert(equal(nl[], [1, 3, 5])); + auto rs = nl[]; + rs.popFront(); + nl.remove(rs); + assert(equal(nl[], [1])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_rbtree.d b/libphobos/testsuite/libphobos.phobos/std_container_rbtree.d new file mode 100644 index 0000000000000000000000000000000000000000..a9d333550dc78fca3c093d7c32ea422e640051f5 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_rbtree.d @@ -0,0 +1,60 @@ +@safe pure unittest +{ + import std.container.rbtree; + + import std.algorithm.comparison : equal; + import std.container.rbtree; + + auto rbt = redBlackTree(3, 1, 4, 2, 5); + assert(rbt.front == 1); + assert(equal(rbt[], [1, 2, 3, 4, 5])); + + rbt.removeKey(1, 4); + assert(equal(rbt[], [2, 3, 5])); + + rbt.removeFront(); + assert(equal(rbt[], [3, 5])); + + rbt.insert([1, 2, 4]); + assert(equal(rbt[], [1, 2, 3, 4, 5])); + + // Query bounds in O(log(n)) + assert(rbt.lowerBound(3).equal([1, 2])); + assert(rbt.equalRange(3).equal([3])); + assert(rbt.upperBound(3).equal([4, 5])); + + // A Red Black tree with the highest element at front: + import std.range : iota; + auto maxTree = redBlackTree!"a > b"(iota(5)); + assert(equal(maxTree[], [4, 3, 2, 1, 0])); + + // adding duplicates will not add them, but return 0 + auto rbt2 = redBlackTree(1, 3); + assert(rbt2.insert(1) == 0); + assert(equal(rbt2[], [1, 3])); + assert(rbt2.insert(2) == 1); + + // however you can allow duplicates + auto ubt = redBlackTree!true([0, 1, 0, 1]); + assert(equal(ubt[], [0, 0, 1, 1])); +} + +@safe pure unittest +{ + import std.container.rbtree; + + import std.range : iota; + + auto rbt1 = redBlackTree(0, 1, 5, 7); + auto rbt2 = redBlackTree!string("hello", "world"); + auto rbt3 = redBlackTree!true(0, 1, 5, 7, 5); + auto rbt4 = redBlackTree!"a > b"(0, 1, 5, 7); + auto rbt5 = redBlackTree!("a > b", true)(0.1, 1.3, 5.9, 7.2, 5.9); + + // also works with ranges + auto rbt6 = redBlackTree(iota(3)); + auto rbt7 = redBlackTree!true(iota(3)); + auto rbt8 = redBlackTree!"a > b"(iota(3)); + auto rbt9 = redBlackTree!("a > b", true)(iota(3)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_slist.d b/libphobos/testsuite/libphobos.phobos/std_container_slist.d new file mode 100644 index 0000000000000000000000000000000000000000..7c9a2b66ac1c90b5705e6a66cdfbb99a5244da21 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_slist.d @@ -0,0 +1,28 @@ +@safe unittest +{ + import std.container.slist; + + import std.algorithm.comparison : equal; + import std.container : SList; + + auto s = SList!int(1, 2, 3); + assert(equal(s[], [1, 2, 3])); + + s.removeFront(); + assert(equal(s[], [2, 3])); + + s.insertFront([5, 6]); + assert(equal(s[], [5, 6, 2, 3])); + + // If you want to apply range operations, simply slice it. + import std.algorithm.searching : countUntil; + import std.range : popFrontN, walkLength; + + auto sl = SList!int(1, 2, 3, 4, 5); + assert(countUntil(sl[], 2) == 1); + + auto r = sl[]; + popFrontN(r, 2); + assert(walkLength(r) == 3); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_util.d b/libphobos/testsuite/libphobos.phobos/std_container_util.d new file mode 100644 index 0000000000000000000000000000000000000000..07d8831464b89cbbb27b27e5d893cb5cd41a4292 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_util.d @@ -0,0 +1,51 @@ +@system unittest +{ + import std.container.util; + + import std.algorithm.comparison : equal; + import std.container; + + auto arr = make!(Array!int)([4, 2, 3, 1]); + assert(equal(arr[], [4, 2, 3, 1])); + + auto rbt = make!(RedBlackTree!(int, "a > b"))([4, 2, 3, 1]); + assert(equal(rbt[], [4, 3, 2, 1])); + + alias makeList = make!(SList!int); + auto slist = makeList(1, 2, 3); + assert(equal(slist[], [1, 2, 3])); +} + +@safe unittest +{ + import std.container.util; + + import std.container.array : Array; + import std.range : only, repeat; + import std.range.primitives : isInfinite; + static assert(__traits(compiles, { auto arr = make!Array(only(5)); })); + static assert(!__traits(compiles, { auto arr = make!Array(repeat(5)); })); +} + +@system unittest +{ + import std.container.util; + + import std.algorithm.comparison : equal; + import std.container.array, std.container.rbtree, std.container.slist; + import std.range : iota; + + auto arr = make!Array(iota(5)); + assert(equal(arr[], [0, 1, 2, 3, 4])); + + auto rbtmax = make!(RedBlackTree, "a > b")(iota(5)); + assert(equal(rbtmax[], [4, 3, 2, 1, 0])); + + auto rbtmin = make!RedBlackTree(4, 1, 3, 2); + assert(equal(rbtmin[], [1, 2, 3, 4])); + + alias makeList = make!SList; + auto list = makeList(1, 7, 42); + assert(equal(list[], [1, 7, 42])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_conv.d b/libphobos/testsuite/libphobos.phobos/std_conv.d new file mode 100644 index 0000000000000000000000000000000000000000..01f6fb7e2569cfb4ad2a450d355d0f0193e6ddf5 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_conv.d @@ -0,0 +1,511 @@ +@safe unittest +{ + import std.conv; + + import std.exception : assertThrown; + assertThrown!ConvException(to!int("abc")); +} + +@safe unittest +{ + import std.conv; + + import std.exception : assertThrown; + assertThrown!ConvOverflowException(to!ubyte(1_000_000)); +} + +@safe pure unittest +{ + import std.conv; + + int a = 42; + int b = to!int(a); + double c = to!double(3.14); // c is double with value 3.14 +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + + int a = 420; + assert(to!long(a) == a); + assertThrown!ConvOverflowException(to!byte(a)); + + assert(to!int(4.2e6) == 4200000); + assertThrown!ConvOverflowException(to!uint(-3.14)); + assert(to!uint(3.14) == 3); + assert(to!uint(3.99) == 3); + assert(to!int(-3.99) == -3); +} + +@safe pure unittest +{ + import std.conv; + + auto str = to!string(42, 16); + assert(str == "2A"); + auto i = to!int(str, 16); + assert(i == 42); +} + +@safe pure unittest +{ + import std.conv; + + // 2^24 - 1, largest proper integer representable as float + int a = 16_777_215; + assert(to!int(to!float(a)) == a); + assert(to!int(to!float(-a)) == -a); +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + + assert(to!char("a") == 'a'); + assertThrown(to!char("ñ")); // 'ñ' does not fit into a char + assert(to!wchar("ñ") == 'ñ'); + assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar + assert(to!dchar("😃") == '😃'); + + // Using wstring or dstring as source type does not affect the result + assert(to!char("a"w) == 'a'); + assert(to!char("a"d) == 'a'); + + // Two code points cannot be converted to a single one + assertThrown(to!char("ab")); +} + +@safe pure unittest +{ + import std.conv; + + import std.string : split; + + int[] a = [1, 2, 3]; + auto b = to!(float[])(a); + assert(b == [1.0f, 2, 3]); + string str = "1 2 3 4 5 6"; + auto numbers = to!(double[])(split(str)); + assert(numbers == [1.0, 2, 3, 4, 5, 6]); + int[string] c; + c["a"] = 1; + c["b"] = 2; + auto d = to!(double[wstring])(c); + assert(d["a"w] == 1 && d["b"w] == 2); +} + +@safe unittest +{ + import std.conv; + + int[string][double[int[]]] a; + auto b = to!(short[wstring][string[double[]]])(a); +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + // Testing object conversions + class A {} + class B : A {} + class C : A {} + A a1 = new A, a2 = new B, a3 = new C; + assert(to!B(a2) is a2); + assert(to!C(a3) is a3); + assertThrown!ConvException(to!B(a3)); +} + +@system pure unittest +{ + import std.conv; + + // Conversion representing dynamic/static array with string + long[] a = [ 1, 3, 5 ]; + assert(to!string(a) == "[1, 3, 5]"); + + // Conversion representing associative array with string + int[string] associativeArray = ["0":1, "1":2]; + assert(to!string(associativeArray) == `["0":1, "1":2]` || + to!string(associativeArray) == `["1":2, "0":1]`); + + // char* to string conversion + assert(to!string(cast(char*) null) == ""); + assert(to!string("foo\0".ptr) == "foo"); + + // Conversion reinterpreting void array to string + auto w = "abcx"w; + const(void)[] b = w; + assert(b.length == 8); + + auto c = to!(wchar[])(b); + assert(c == "abcx"); +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + + enum E { a, b, c } + assert(to!E("a") == E.a); + assert(to!E("b") == E.b); + assertThrown!ConvException(to!E("A")); +} + +@safe unittest +{ + import std.conv; + + assert(roundTo!int(3.14) == 3); + assert(roundTo!int(3.49) == 3); + assert(roundTo!int(3.5) == 4); + assert(roundTo!int(3.999) == 4); + assert(roundTo!int(-3.14) == -3); + assert(roundTo!int(-3.49) == -3); + assert(roundTo!int(-3.5) == -4); + assert(roundTo!int(-3.999) == -4); + assert(roundTo!(const int)(to!(const double)(-3.999)) == -4); +} + +@safe unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No; + auto s = "true"; + bool b = parse!bool(s); + assert(b); + auto s2 = "true"; + bool b2 = parse!(bool, string, No.doCount)(s2); + assert(b2); + auto s3 = "true"; + auto b3 = parse!(bool, string, Yes.doCount)(s3); + assert(b3.data && b3.count == 4); + auto s4 = "falSE"; + auto b4 = parse!(bool, string, Yes.doCount)(s4); + assert(!b4.data && b4.count == 5); +} + +@safe pure unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No; + string s = "123"; + auto a = parse!int(s); + assert(a == 123); + + string s1 = "123"; + auto a1 = parse!(int, string, Yes.doCount)(s1); + assert(a1.data == 123 && a1.count == 3); +} + +@safe pure unittest +{ + import std.conv; + + import std.string : tr; + import std.typecons : Flag, Yes, No; + string test = "123 \t 76.14"; + auto a = parse!uint(test); + assert(a == 123); + assert(test == " \t 76.14"); // parse bumps string + test = tr(test, " \t\n\r", "", "d"); // skip ws + assert(test == "76.14"); + auto b = parse!double(test); + assert(b == 76.14); + assert(test == ""); + + string test2 = "123 \t 76.14"; + auto a2 = parse!(uint, string, Yes.doCount)(test2); + assert(a2.data == 123 && a2.count == 3); + assert(test2 == " \t 76.14");// parse bumps string + test2 = tr(test2, " \t\n\r", "", "d"); // skip ws + assert(test2 == "76.14"); + auto b2 = parse!(double, string, Yes.doCount)(test2); + assert(b2.data == 76.14 && b2.count == 5); + assert(test2 == ""); + +} + +@safe unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No, tuple; + enum EnumType : bool { a = true, b = false, c = a } + + auto str = "a"; + assert(parse!EnumType(str) == EnumType.a); + auto str2 = "a"; + assert(parse!(EnumType, string, No.doCount)(str2) == EnumType.a); + auto str3 = "a"; + assert(parse!(EnumType, string, Yes.doCount)(str3) == tuple(EnumType.a, 1)); + +} + +@safe unittest +{ + import std.conv; + + import std.math.operations : isClose; + import std.math.traits : isNaN, isInfinity; + import std.typecons : Flag, Yes, No; + auto str = "123.456"; + assert(parse!double(str).isClose(123.456)); + auto str2 = "123.456"; + assert(parse!(double, string, No.doCount)(str2).isClose(123.456)); + auto str3 = "123.456"; + auto r = parse!(double, string, Yes.doCount)(str3); + assert(r.data.isClose(123.456)); + assert(r.count == 7); + auto str4 = "-123.456"; + r = parse!(double, string, Yes.doCount)(str4); + assert(r.data.isClose(-123.456)); + assert(r.count == 8); + auto str5 = "+123.456"; + r = parse!(double, string, Yes.doCount)(str5); + assert(r.data.isClose(123.456)); + assert(r.count == 8); + auto str6 = "inf0"; + r = parse!(double, string, Yes.doCount)(str6); + assert(isInfinity(r.data) && r.count == 3 && str6 == "0"); + auto str7 = "-0"; + auto r2 = parse!(float, string, Yes.doCount)(str7); + assert(r2.data.isClose(0.0) && r2.count == 2); + auto str8 = "nan"; + auto r3 = parse!(real, string, Yes.doCount)(str8); + assert(isNaN(r3.data) && r3.count == 3); +} + +@safe pure unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No; + auto s = "Hello, World!"; + char first = parse!char(s); + assert(first == 'H'); + assert(s == "ello, World!"); + char second = parse!(char, string, No.doCount)(s); + assert(second == 'e'); + assert(s == "llo, World!"); + auto third = parse!(char, string, Yes.doCount)(s); + assert(third.data == 'l' && third.count == 1); + assert(s == "lo, World!"); +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + import std.typecons : Flag, Yes, No; + + alias NullType = typeof(null); + auto s1 = "null"; + assert(parse!NullType(s1) is null); + assert(s1 == ""); + + auto s2 = "NUll"d; + assert(parse!NullType(s2) is null); + assert(s2 == ""); + + auto s3 = "nuLlNULl"; + assert(parse!(NullType, string, No.doCount)(s3) is null); + auto r = parse!(NullType, string, Yes.doCount)(s3); + assert(r.data is null && r.count == 4); + + auto m = "maybe"; + assertThrown!ConvException(parse!NullType(m)); + assertThrown!ConvException(parse!(NullType, string, Yes.doCount)(m)); + assert(m == "maybe"); // m shouldn't change on failure + + auto s = "NULL"; + assert(parse!(const NullType)(s) is null); +} + +@safe pure unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No; + auto s1 = `[['h', 'e', 'l', 'l', 'o'], "world"]`; + auto a1 = parse!(string[])(s1); + assert(a1 == ["hello", "world"]); + + auto s2 = `["aaa", "bbb", "ccc"]`; + auto a2 = parse!(string[])(s2); + assert(a2 == ["aaa", "bbb", "ccc"]); + + auto s3 = `[['h', 'e', 'l', 'l', 'o'], "world"]`; + auto len3 = s3.length; + auto a3 = parse!(string[], string, Yes.doCount)(s3); + assert(a3.data == ["hello", "world"]); + assert(a3.count == len3); +} + +@safe pure unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No, tuple; + import std.range.primitives : save; + import std.array : assocArray; + auto s1 = "[1:10, 2:20, 3:30]"; + auto copyS1 = s1.save; + auto aa1 = parse!(int[int])(s1); + assert(aa1 == [1:10, 2:20, 3:30]); + assert(tuple([1:10, 2:20, 3:30], copyS1.length) == parse!(int[int], string, Yes.doCount)(copyS1)); + + auto s2 = `["aaa":10, "bbb":20, "ccc":30]`; + auto copyS2 = s2.save; + auto aa2 = parse!(int[string])(s2); + assert(aa2 == ["aaa":10, "bbb":20, "ccc":30]); + assert(tuple(["aaa":10, "bbb":20, "ccc":30], copyS2.length) == + parse!(int[string], string, Yes.doCount)(copyS2)); + + auto s3 = `["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]`; + auto copyS3 = s3.save; + auto aa3 = parse!(int[][string])(s3); + assert(aa3 == ["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]); + assert(tuple(["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]], copyS3.length) == + parse!(int[][string], string, Yes.doCount)(copyS3)); + + auto s4 = `[]`; + int[int] emptyAA; + assert(tuple(emptyAA, s4.length) == parse!(int[int], string, Yes.doCount)(s4)); +} + +@safe unittest +{ + import std.conv; + + assert( text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"c); + assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w); + assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d); +} + +@safe unittest +{ + import std.conv; + + // Same as 0177 + auto a = octal!177; + // octal is a compile-time device + enum b = octal!160; + // Create an unsigned octal + auto c = octal!"1_000_000u"; + // Leading zeros are allowed when converting from a string + auto d = octal!"0001_200_000"; +} + +@safe unittest +{ + import std.conv; + + import std.traits : Unsigned; + immutable int s = 42; + auto u1 = unsigned(s); //not qualified + static assert(is(typeof(u1) == uint)); + Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification + static assert(is(typeof(u2) == immutable uint)); + immutable u3 = unsigned(s); //explicitly qualified +} + +@safe unittest +{ + import std.conv; + + import std.traits : Signed; + + immutable uint u = 42; + auto s1 = signed(u); //not qualified + static assert(is(typeof(s1) == int)); + Signed!(typeof(u)) s2 = signed(u); //same qualification + static assert(is(typeof(s2) == immutable int)); + immutable s3 = signed(u); //explicitly qualified +} + +@safe unittest +{ + import std.conv; + + enum A { a = 42 } + static assert(is(typeof(A.a.asOriginalType) == int)); + assert(A.a.asOriginalType == 42); + enum B : double { a = 43 } + static assert(is(typeof(B.a.asOriginalType) == double)); + assert(B.a.asOriginalType == 43); +} + +@system unittest +{ + import std.conv; + + // Regular cast, which has been verified to be legal by the programmer: + { + long x; + auto y = cast(int) x; + } + + // However this will still compile if 'x' is changed to be a pointer: + { + long* x; + auto y = cast(int) x; + } + + // castFrom provides a more reliable alternative to casting: + { + long x; + auto y = castFrom!long.to!int(x); + } + + // Changing the type of 'x' will now issue a compiler error, + // allowing bad casts to be caught before it's too late: + { + long* x; + static assert( + !__traits(compiles, castFrom!long.to!int(x)) + ); + + // if cast is still needed, must be changed to: + auto y = castFrom!(long*).to!int(x); + } +} + +@safe unittest +{ + import std.conv; + + // conversion at compile time + auto string1 = hexString!"304A314B"; + assert(string1 == "0J1K"); + auto string2 = hexString!"304A314B"w; + assert(string2 == "0J1K"w); + auto string3 = hexString!"304A314B"d; + assert(string3 == "0J1K"d); +} + +@safe unittest +{ + import std.conv; + + import std.algorithm.comparison : equal; + + assert(toChars(1).equal("1")); + assert(toChars(1_000_000).equal("1000000")); + + assert(toChars!(2)(2U).equal("10")); + assert(toChars!(16)(255U).equal("ff")); + assert(toChars!(16, char, LetterCase.upper)(255U).equal("FF")); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_csv.d b/libphobos/testsuite/libphobos.phobos/std_csv.d new file mode 100644 index 0000000000000000000000000000000000000000..e35df43da688388792c693acb284931233418599 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_csv.d @@ -0,0 +1,228 @@ +@safe unittest +{ + import std.csv; + + import std.exception : collectException; + import std.algorithm.searching : count; + string text = "a,b,c\nHello,65"; + auto ex = collectException!CSVException(csvReader(text).count); + assert(ex.toString == "(Row: 0, Col: 0) Row 2's length 2 does not match previous length of 3."); +} + +@safe unittest +{ + import std.csv; + + import std.exception : collectException; + import std.algorithm.searching : count; + import std.typecons : Tuple; + string text = "a,b\nHello,65"; + auto ex = collectException!CSVException(csvReader!(Tuple!(string,int))(text).count); + assert(ex.toString == "(Row: 1, Col: 2) Unexpected 'b' when converting from type string to type int"); +} + +@safe unittest +{ + import std.csv; + + import std.exception : assertThrown; + string text = "a,\"b,c\nHello,65,2.5"; + assertThrown!IncompleteCellException(text.csvReader(["a","b","c"])); +} + +@safe unittest +{ + import std.csv; + + import std.exception : assertThrown; + string text = "a,b,c\nHello,65,2.5"; + assertThrown!HeaderMismatchException(text.csvReader(["b","c","invalid"])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + import std.algorithm.searching : count; + import std.exception : assertThrown; + + string text = "a,b,c\nHello,65,\"2.5"; + assertThrown!IncompleteCellException(text.csvReader.count); + + // ignore the exceptions and try to handle invalid CSV + auto firstLine = text.csvReader!(string, Malformed.ignore)(null).front; + assert(firstLine.equal(["Hello", "65", "2.5"])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + string text = "76,26,22"; + auto records = text.csvReader!int; + assert(records.equal!equal([ + [76, 26, 22], + ])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + string text = "Hello;65;2.5\nWorld;123;7.5"; + struct Layout + { + string name; + int value; + double other; + } + + auto records = text.csvReader!Layout(';'); + assert(records.equal([ + Layout("Hello", 65, 2.5), + Layout("World", 123, 7.5), + ])); +} + +@safe unittest +{ + import std.csv; + + string text = "A \" is now part of the data"; + auto records = text.csvReader!(string, Malformed.ignore); + auto record = records.front; + + assert(record.front == text); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + string text = "a,b,c\nHello,65,63.63\nWorld,123,3673.562"; + auto records = text.csvReader!int(["b"]); + + assert(records.equal!equal([ + [65], + [123], + ])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + string text = "a,b,c\nHello,65,2.5\nWorld,123,7.5"; + struct Layout + { + int value; + double other; + string name; + } + + auto records = text.csvReader!Layout(["b","c","a"]); + assert(records.equal([ + Layout(65, 2.5, "Hello"), + Layout(123, 7.5, "World") + ])); +} + +@safe unittest +{ + import std.csv; + + string text = "a,b,c\nHello,65,63.63"; + auto records = text.csvReader(null); + + assert(records.header == ["a","b","c"]); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + + string text = "76,26,22\n1,2\n3,4,5,6"; + auto records = text.csvReader!int(',', '"', true); + + assert(records.equal!equal([ + [76, 26, 22], + [1, 2], + [3, 4, 5, 6] + ])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + + static struct Three + { + int a; + int b; + int c; + } + + string text = "76,26,22\n1,2\n3,4,5,6"; + auto records = text.csvReader!Three(',', '"', true); + + assert(records.equal([ + Three(76, 26, 22), + Three(1, 2, 0), + Three(3, 4, 5) + ])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + + auto text = "Name,Occupation,Salary\r" ~ + "Joe,Carpenter,300000\nFred,Blacksmith\r\n"; + + auto r = csvReader!(string[string])(text, null, ',', '"', true); + + assert(r.equal([ + [ "Name" : "Joe", "Occupation" : "Carpenter", "Salary" : "300000" ], + [ "Name" : "Fred", "Occupation" : "Blacksmith" ] + ])); +} + +@safe unittest +{ + import std.csv; + + import std.array : appender; + import std.range.primitives : popFront; + + string str = "65,63\n123,3673"; + + auto a = appender!(char[])(); + + csvNextToken(str,a,',','"'); + assert(a.data == "65"); + assert(str == ",63\n123,3673"); + + str.popFront(); + a.shrinkTo(0); + csvNextToken(str,a,',','"'); + assert(a.data == "63"); + assert(str == "\n123,3673"); + + str.popFront(); + a.shrinkTo(0); + csvNextToken(str,a,',','"'); + assert(a.data == "123"); + assert(str == ",3673"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_date.d b/libphobos/testsuite/libphobos.phobos/std_datetime_date.d new file mode 100644 index 0000000000000000000000000000000000000000..0ecf625562af9c17ba0708f457cca518ff7f43bf --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_date.d @@ -0,0 +1,992 @@ +@safe pure unittest +{ + import std.datetime.date; + + assert(Date(2018, 10, 1).month == Month.oct); + assert(DateTime(1, 1, 1).month == Month.jan); +} + +@safe pure unittest +{ + import std.datetime.date; + + assert(Date(2018, 10, 1).dayOfWeek == DayOfWeek.mon); + assert(DateTime(5, 5, 5).dayOfWeek == DayOfWeek.thu); +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).year == 1999); + assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).year == 2010); + assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).year == -7); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)).yearBC == 1); + assert(DateTime(Date(-1, 1, 1), TimeOfDay(10, 7, 2)).yearBC == 2); + assert(DateTime(Date(-100, 1, 1), TimeOfDay(4, 59, 0)).yearBC == 101); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(7, 30, 0)); + dt.yearBC = 1; + assert(dt == DateTime(Date(0, 1, 1), TimeOfDay(7, 30, 0))); + + dt.yearBC = 10; + assert(dt == DateTime(Date(-9, 1, 1), TimeOfDay(7, 30, 0))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).month == 7); + assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).month == 10); + assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).month == 4); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).day == 6); + assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).day == 4); + assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).day == 5); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt1 = DateTime(2010, 1, 1, 12, 30, 33); + dt1.add!"months"(11); + assert(dt1 == DateTime(2010, 12, 1, 12, 30, 33)); + + auto dt2 = DateTime(2010, 1, 1, 12, 30, 33); + dt2.add!"months"(-11); + assert(dt2 == DateTime(2009, 2, 1, 12, 30, 33)); + + auto dt3 = DateTime(2000, 2, 29, 12, 30, 33); + dt3.add!"years"(1); + assert(dt3 == DateTime(2001, 3, 1, 12, 30, 33)); + + auto dt4 = DateTime(2000, 2, 29, 12, 30, 33); + dt4.add!"years"(1, AllowDayOverflow.no); + assert(dt4 == DateTime(2001, 2, 28, 12, 30, 33)); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt1 = DateTime(2010, 1, 1, 12, 33, 33); + dt1.roll!"months"(1); + assert(dt1 == DateTime(2010, 2, 1, 12, 33, 33)); + + auto dt2 = DateTime(2010, 1, 1, 12, 33, 33); + dt2.roll!"months"(-1); + assert(dt2 == DateTime(2010, 12, 1, 12, 33, 33)); + + auto dt3 = DateTime(1999, 1, 29, 12, 33, 33); + dt3.roll!"months"(1); + assert(dt3 == DateTime(1999, 3, 1, 12, 33, 33)); + + auto dt4 = DateTime(1999, 1, 29, 12, 33, 33); + dt4.roll!"months"(1, AllowDayOverflow.no); + assert(dt4 == DateTime(1999, 2, 28, 12, 33, 33)); + + auto dt5 = DateTime(2000, 2, 29, 12, 30, 33); + dt5.roll!"years"(1); + assert(dt5 == DateTime(2001, 3, 1, 12, 30, 33)); + + auto dt6 = DateTime(2000, 2, 29, 12, 30, 33); + dt6.roll!"years"(1, AllowDayOverflow.no); + assert(dt6 == DateTime(2001, 2, 28, 12, 30, 33)); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt1 = DateTime(2010, 1, 1, 11, 23, 12); + dt1.roll!"days"(1); + assert(dt1 == DateTime(2010, 1, 2, 11, 23, 12)); + dt1.roll!"days"(365); + assert(dt1 == DateTime(2010, 1, 26, 11, 23, 12)); + dt1.roll!"days"(-32); + assert(dt1 == DateTime(2010, 1, 25, 11, 23, 12)); + + auto dt2 = DateTime(2010, 7, 4, 12, 0, 0); + dt2.roll!"hours"(1); + assert(dt2 == DateTime(2010, 7, 4, 13, 0, 0)); + + auto dt3 = DateTime(2010, 1, 1, 0, 0, 0); + dt3.roll!"seconds"(-1); + assert(dt3 == DateTime(2010, 1, 1, 0, 0, 59)); + +} + +@safe unittest +{ + import std.datetime.date; + + import core.time : hours, seconds; + + assert(DateTime(2015, 12, 31, 23, 59, 59) + seconds(1) == + DateTime(2016, 1, 1, 0, 0, 0)); + + assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) == + DateTime(2016, 1, 1, 0, 59, 59)); + + assert(DateTime(2016, 1, 1, 0, 0, 0) - seconds(1) == + DateTime(2015, 12, 31, 23, 59, 59)); + + assert(DateTime(2016, 1, 1, 0, 59, 59) - hours(1) == + DateTime(2015, 12, 31, 23, 59, 59)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths( + DateTime(1999, 1, 31, 23, 59, 59)) == 1); + + assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths( + DateTime(1999, 2, 1, 12, 3, 42)) == -1); + + assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths( + DateTime(1999, 1, 1, 2, 4, 7)) == 2); + + assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths( + DateTime(1999, 3, 31, 0, 30, 58)) == -2); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1); + assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365); + assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1); + assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365); + assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366); + + assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0); + assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365); + assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366); + + assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120); + assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0)); + dt.dayOfGregorianCal = 1; + assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 365; + assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 366; + assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 0; + assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = -365; + assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = -366; + assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 730_120; + assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 734_137; + assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth == + DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59))); + + assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth == + DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59))); + + assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth == + DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59))); + + assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth == + DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31); + assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28); + assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29); + assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD); + assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD); + assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD); + assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() == + "20100704T070612"); + + assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() == + "19981225T021500"); + + assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() == + "00000105T230959"); + + assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() == + "-00040105T000002"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() == + "2010-07-04T07:06:12"); + + assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() == + "1998-12-25T02:15:00"); + + assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() == + "0000-01-05T23:09:59"); + + assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() == + "-0004-01-05T00:00:02"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() == + "2010-Jul-04 07:06:12"); + + assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() == + "1998-Dec-25 02:15:00"); + + assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() == + "0000-Jan-05 23:09:59"); + + assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() == + "-0004-Jan-05 00:00:02"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime.fromISOString("20100704T070612") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + + assert(DateTime.fromISOString("19981225T021500") == + DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); + + assert(DateTime.fromISOString("00000105T230959") == + DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); + + assert(DateTime.fromISOString("-00040105T000002") == + DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); + + assert(DateTime.fromISOString(" 20100704T070612 ") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime.fromISOExtString("2010-07-04T07:06:12") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + + assert(DateTime.fromISOExtString("1998-12-25T02:15:00") == + DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); + + assert(DateTime.fromISOExtString("0000-01-05T23:09:59") == + DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); + + assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") == + DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); + + assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") == + DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); + assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") == + DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); + assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") == + DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); + assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + +} + +@safe pure unittest +{ + import std.datetime.date; + + import core.time : days, seconds; + + auto dt = DateTime(2000, 6, 1, 10, 30, 0); + + assert(dt.date == Date(2000, 6, 1)); + assert(dt.timeOfDay == TimeOfDay(10, 30, 0)); + assert(dt.dayOfYear == 153); + assert(dt.dayOfWeek == DayOfWeek.thu); + + dt += 10.days + 100.seconds; + assert(dt == DateTime(2000, 6, 11, 10, 31, 40)); + + assert(dt.toISOExtString() == "2000-06-11T10:31:40"); + assert(dt.toISOString() == "20000611T103140"); + assert(dt.toSimpleString() == "2000-Jun-11 10:31:40"); + + assert(DateTime.fromISOExtString("2018-01-01T12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); + assert(DateTime.fromISOString("20180101T120000") == DateTime(2018, 1, 1, 12, 0, 0)); + assert(DateTime.fromSimpleString("2018-Jan-01 12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 7, 6).year == 1999); + assert(Date(2010, 10, 4).year == 2010); + assert(Date(-7, 4, 5).year == -7); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 7, 6).year == 1999); + assert(Date(2010, 10, 4).year == 2010); + assert(Date(-7, 4, 5).year == -7); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(0, 1, 1).yearBC == 1); + assert(Date(-1, 1, 1).yearBC == 2); + assert(Date(-100, 1, 1).yearBC == 101); + +} + +@safe unittest +{ + import std.datetime.date; + + auto date = Date(2010, 1, 1); + date.yearBC = 1; + assert(date == Date(0, 1, 1)); + + date.yearBC = 10; + assert(date == Date(-9, 1, 1)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 7, 6).month == 7); + assert(Date(2010, 10, 4).month == 10); + assert(Date(-7, 4, 5).month == 4); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 7, 6).day == 6); + assert(Date(2010, 10, 4).day == 4); + assert(Date(-7, 4, 5).day == 5); + +} + +@safe unittest +{ + import std.datetime.date; + + auto d1 = Date(2010, 1, 1); + d1.add!"months"(11); + assert(d1 == Date(2010, 12, 1)); + + auto d2 = Date(2010, 1, 1); + d2.add!"months"(-11); + assert(d2 == Date(2009, 2, 1)); + + auto d3 = Date(2000, 2, 29); + d3.add!"years"(1); + assert(d3 == Date(2001, 3, 1)); + + auto d4 = Date(2000, 2, 29); + d4.add!"years"(1, AllowDayOverflow.no); + assert(d4 == Date(2001, 2, 28)); + +} + +@safe unittest +{ + import std.datetime.date; + + auto d1 = Date(2010, 1, 1); + d1.roll!"months"(1); + assert(d1 == Date(2010, 2, 1)); + + auto d2 = Date(2010, 1, 1); + d2.roll!"months"(-1); + assert(d2 == Date(2010, 12, 1)); + + auto d3 = Date(1999, 1, 29); + d3.roll!"months"(1); + assert(d3 == Date(1999, 3, 1)); + + auto d4 = Date(1999, 1, 29); + d4.roll!"months"(1, AllowDayOverflow.no); + assert(d4 == Date(1999, 2, 28)); + + auto d5 = Date(2000, 2, 29); + d5.roll!"years"(1); + assert(d5 == Date(2001, 3, 1)); + + auto d6 = Date(2000, 2, 29); + d6.roll!"years"(1, AllowDayOverflow.no); + assert(d6 == Date(2001, 2, 28)); + +} + +@safe unittest +{ + import std.datetime.date; + + auto d = Date(2010, 1, 1); + d.roll!"days"(1); + assert(d == Date(2010, 1, 2)); + d.roll!"days"(365); + assert(d == Date(2010, 1, 26)); + d.roll!"days"(-32); + assert(d == Date(2010, 1, 25)); + +} + +@safe unittest +{ + import std.datetime.date; + + import core.time : days; + + assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1)); + assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1)); + + assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31)); + assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1); + assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1); + assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2); + assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 1, 1).dayOfYear == 1); + assert(Date(1999, 12, 31).dayOfYear == 365); + assert(Date(2000, 12, 31).dayOfYear == 366); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1, 1, 1).dayOfGregorianCal == 1); + assert(Date(1, 12, 31).dayOfGregorianCal == 365); + assert(Date(2, 1, 1).dayOfGregorianCal == 366); + + assert(Date(0, 12, 31).dayOfGregorianCal == 0); + assert(Date(0, 1, 1).dayOfGregorianCal == -365); + assert(Date(-1, 12, 31).dayOfGregorianCal == -366); + + assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120); + assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137); + +} + +@safe unittest +{ + import std.datetime.date; + + auto date = Date.init; + date.dayOfGregorianCal = 1; + assert(date == Date(1, 1, 1)); + + date.dayOfGregorianCal = 365; + assert(date == Date(1, 12, 31)); + + date.dayOfGregorianCal = 366; + assert(date == Date(2, 1, 1)); + + date.dayOfGregorianCal = 0; + assert(date == Date(0, 12, 31)); + + date.dayOfGregorianCal = -365; + assert(date == Date(-0, 1, 1)); + + date.dayOfGregorianCal = -366; + assert(date == Date(-1, 12, 31)); + + date.dayOfGregorianCal = 730_120; + assert(date == Date(2000, 1, 1)); + + date.dayOfGregorianCal = 734_137; + assert(date == Date(2010, 12, 31)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31)); + assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28)); + assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29)); + assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 1, 6).daysInMonth == 31); + assert(Date(1999, 2, 7).daysInMonth == 28); + assert(Date(2000, 2, 7).daysInMonth == 29); + assert(Date(2000, 6, 4).daysInMonth == 30); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1, 1, 1).isAD); + assert(Date(2010, 12, 31).isAD); + assert(!Date(0, 12, 31).isAD); + assert(!Date(-2010, 1, 1).isAD); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(2010, 7, 4).toISOString() == "20100704"); + assert(Date(1998, 12, 25).toISOString() == "19981225"); + assert(Date(0, 1, 5).toISOString() == "00000105"); + assert(Date(-4, 1, 5).toISOString() == "-00040105"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04"); + assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25"); + assert(Date(0, 1, 5).toISOExtString() == "0000-01-05"); + assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04"); + assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25"); + assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05"); + assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date.fromISOString("20100704") == Date(2010, 7, 4)); + assert(Date.fromISOString("19981225") == Date(1998, 12, 25)); + assert(Date.fromISOString("00000105") == Date(0, 1, 5)); + assert(Date.fromISOString("-00040105") == Date(-4, 1, 5)); + assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4)); + assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25)); + assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5)); + assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5)); + assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4)); + assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25)); + assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5)); + assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5)); + assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4)); + +} + +@safe pure unittest +{ + import std.datetime.date; + + import core.time : days; + + auto d = Date(2000, 6, 1); + + assert(d.dayOfYear == 153); + assert(d.dayOfWeek == DayOfWeek.thu); + + d += 10.days; + assert(d == Date(2000, 6, 11)); + + assert(d.toISOExtString() == "2000-06-11"); + assert(d.toISOString() == "20000611"); + assert(d.toSimpleString() == "2000-Jun-11"); + + assert(Date.fromISOExtString("2018-01-01") == Date(2018, 1, 1)); + assert(Date.fromISOString("20180101") == Date(2018, 1, 1)); + assert(Date.fromSimpleString("2018-Jan-01") == Date(2018, 1, 1)); +} + +@safe unittest +{ + import std.datetime.date; + + auto tod1 = TimeOfDay(7, 12, 0); + tod1.roll!"hours"(1); + assert(tod1 == TimeOfDay(8, 12, 0)); + + auto tod2 = TimeOfDay(7, 12, 0); + tod2.roll!"hours"(-1); + assert(tod2 == TimeOfDay(6, 12, 0)); + + auto tod3 = TimeOfDay(23, 59, 0); + tod3.roll!"minutes"(1); + assert(tod3 == TimeOfDay(23, 0, 0)); + + auto tod4 = TimeOfDay(0, 0, 0); + tod4.roll!"minutes"(-1); + assert(tod4 == TimeOfDay(0, 59, 0)); + + auto tod5 = TimeOfDay(23, 59, 59); + tod5.roll!"seconds"(1); + assert(tod5 == TimeOfDay(23, 59, 0)); + + auto tod6 = TimeOfDay(0, 0, 0); + tod6.roll!"seconds"(-1); + assert(tod6 == TimeOfDay(0, 0, 59)); + +} + +@safe unittest +{ + import std.datetime.date; + + import core.time : hours, minutes, seconds; + + assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13)); + assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12)); + assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12)); + assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0)); + + assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11)); + assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12)); + assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12)); + assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(TimeOfDay(0, 0, 0).toISOString() == "000000"); + assert(TimeOfDay(12, 30, 33).toISOString() == "123033"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00"); + assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0)); + assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33)); + assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0)); + assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33)); + assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33)); + +} + +@safe pure unittest +{ + import std.datetime.date; + + import core.time : minutes, seconds; + + auto t = TimeOfDay(12, 30, 0); + + t += 10.minutes + 100.seconds; + assert(t == TimeOfDay(12, 41, 40)); + + assert(t.toISOExtString() == "12:41:40"); + assert(t.toISOString() == "124140"); + + assert(TimeOfDay.fromISOExtString("15:00:00") == TimeOfDay(15, 0, 0)); + assert(TimeOfDay.fromISOString("015000") == TimeOfDay(1, 50, 0)); +} + +@safe unittest +{ + import std.datetime.date; + + assert(valid!"hours"(12)); + assert(!valid!"hours"(32)); + assert(valid!"months"(12)); + assert(!valid!"months"(13)); +} + +@safe pure nothrow @nogc unittest +{ + import std.datetime.date; + + assert(valid!"days"(2016, 2, 29)); + assert(!valid!"days"(2016, 2, 30)); + assert(valid!"days"(2017, 2, 20)); + assert(!valid!"days"(2017, 2, 29)); +} + +@safe pure unittest +{ + import std.datetime.date; + + import std.exception : assertThrown, assertNotThrown; + + assertNotThrown(enforceValid!"months"(10)); + assertNotThrown(enforceValid!"seconds"(40)); + + assertThrown!DateTimeException(enforceValid!"months"(0)); + assertThrown!DateTimeException(enforceValid!"hours"(24)); + assertThrown!DateTimeException(enforceValid!"minutes"(60)); + assertThrown!DateTimeException(enforceValid!"seconds"(60)); +} + +@safe pure unittest +{ + import std.datetime.date; + + import std.exception : assertThrown, assertNotThrown; + + assertNotThrown(enforceValid!"days"(2000, Month.jan, 1)); + // leap year + assertNotThrown(enforceValid!"days"(2000, Month.feb, 29)); + + assertThrown!DateTimeException(enforceValid!"days"(2001, Month.feb, 29)); + assertThrown!DateTimeException(enforceValid!"days"(2000, Month.jan, 32)); + assertThrown!DateTimeException(enforceValid!"days"(2000, Month.apr, 31)); +} + +@safe pure nothrow @nogc unittest +{ + import std.datetime.date; + + assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); + assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); + assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); +} + +@safe pure unittest +{ + import std.datetime.date; + + assert(monthsToMonth(Month.jan, Month.jan) == 0); + assert(monthsToMonth(Month.jan, Month.dec) == 11); + assert(monthsToMonth(Month.jul, Month.oct) == 3); +} + +@safe unittest +{ + import std.datetime.date; + + foreach (year; [1, 2, 100, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010]) + { + assert(!yearIsLeapYear(year)); + assert(!yearIsLeapYear(-year)); + } + + foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) + { + assert(yearIsLeapYear(year)); + assert(yearIsLeapYear(-year)); + } +} + +@safe unittest +{ + import std.datetime.date; + + import core.time : Duration; + import std.datetime.interval : Interval; + import std.datetime.systime : SysTime; + + static assert(isTimePoint!Date); + static assert(isTimePoint!DateTime); + static assert(isTimePoint!SysTime); + static assert(isTimePoint!TimeOfDay); + + static assert(!isTimePoint!int); + static assert(!isTimePoint!Duration); + static assert(!isTimePoint!(Interval!SysTime)); +} + +@safe @nogc nothrow unittest +{ + import std.datetime.date; + + assert(validTimeUnits("msecs", "seconds", "minutes")); + assert(validTimeUnits("days", "weeks", "months")); + assert(!validTimeUnits("ms", "seconds", "minutes")); +} + +@safe pure unittest +{ + import std.datetime.date; + + import std.exception : assertThrown; + + assert(cmpTimeUnits("hours", "hours") == 0); + assert(cmpTimeUnits("hours", "weeks") < 0); + assert(cmpTimeUnits("months", "seconds") > 0); + + assertThrown!DateTimeException(cmpTimeUnits("month", "second")); +} + +@safe pure unittest +{ + import std.datetime.date; + + static assert(CmpTimeUnits!("years", "weeks") > 0); + static assert(CmpTimeUnits!("days", "days") == 0); + static assert(CmpTimeUnits!("seconds", "hours") < 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_interval.d b/libphobos/testsuite/libphobos.phobos/std_datetime_interval.d new file mode 100644 index 0000000000000000000000000000000000000000..e741f3aeed16f3d580e2e558593ed199ef3b7cb6 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_interval.d @@ -0,0 +1,112 @@ +@system unittest +{ + import std.datetime.interval; + + import std.datetime.date : Date, DayOfWeek; + + auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27)); + auto func = everyDayOfWeek!Date(DayOfWeek.mon); + auto range = interval.fwdRange(func); + + // A Thursday. Using PopFirst.yes would have made this Date(2010, 9, 6). + assert(range.front == Date(2010, 9, 2)); + + range.popFront(); + assert(range.front == Date(2010, 9, 6)); + + range.popFront(); + assert(range.front == Date(2010, 9, 13)); + + range.popFront(); + assert(range.front == Date(2010, 9, 20)); + + range.popFront(); + assert(range.empty); +} + +@system unittest +{ + import std.datetime.interval; + + import std.datetime.date : Date, Month; + + auto interval = Interval!Date(Date(2000, 1, 30), Date(2004, 8, 5)); + auto func = everyMonth!Date(Month.feb); + auto range = interval.fwdRange(func); + + // Using PopFirst.yes would have made this Date(2010, 2, 29). + assert(range.front == Date(2000, 1, 30)); + + range.popFront(); + assert(range.front == Date(2000, 2, 29)); + + range.popFront(); + assert(range.front == Date(2001, 2, 28)); + + range.popFront(); + assert(range.front == Date(2002, 2, 28)); + + range.popFront(); + assert(range.front == Date(2003, 2, 28)); + + range.popFront(); + assert(range.front == Date(2004, 2, 28)); + + range.popFront(); + assert(range.empty); +} + +@system unittest +{ + import std.datetime.interval; + + import core.time : dur; + import std.datetime.date : Date; + + auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27)); + auto func = everyDuration!Date(dur!"days"(8)); + auto range = interval.fwdRange(func); + + // Using PopFirst.yes would have made this Date(2010, 9, 10). + assert(range.front == Date(2010, 9, 2)); + + range.popFront(); + assert(range.front == Date(2010, 9, 10)); + + range.popFront(); + assert(range.front == Date(2010, 9, 18)); + + range.popFront(); + assert(range.front == Date(2010, 9, 26)); + + range.popFront(); + assert(range.empty); +} + +@system unittest +{ + import std.datetime.interval; + + import core.time : dur; + import std.datetime.date : AllowDayOverflow, Date; + + auto interval = Interval!Date(Date(2010, 9, 2), Date(2025, 9, 27)); + auto func = everyDuration!Date(4, 1, AllowDayOverflow.yes, dur!"days"(2)); + auto range = interval.fwdRange(func); + + // Using PopFirst.yes would have made this Date(2014, 10, 12). + assert(range.front == Date(2010, 9, 2)); + + range.popFront(); + assert(range.front == Date(2014, 10, 4)); + + range.popFront(); + assert(range.front == Date(2018, 11, 6)); + + range.popFront(); + assert(range.front == Date(2022, 12, 8)); + + range.popFront(); + assert(range.empty); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_package.d b/libphobos/testsuite/libphobos.phobos/std_datetime_package.d new file mode 100644 index 0000000000000000000000000000000000000000..d40ad44f080e43bbe7ac5ccad3a68e55e4cf144b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_package.d @@ -0,0 +1,34 @@ +@safe unittest +{ + import std.datetime; + + import std.datetime.systime : SysTime, Clock; + + SysTime currentTime = Clock.currTime(); +} + +@safe unittest +{ + import std.datetime; + + import std.datetime.date : DateTime; + + auto dt = DateTime(2018, 1, 1, 12, 30, 10); + assert(dt.toISOString() == "20180101T123010"); + assert(dt.toISOExtString() == "2018-01-01T12:30:10"); +} + +@safe unittest +{ + import std.datetime; + + import std.datetime.systime : SysTime; + import std.datetime.timezone : UTC; + import core.time : days; + + auto st = SysTime(DateTime(2018, 1, 1, 12, 30, 10), UTC()); + assert(st.toISOExtString() == "2018-01-01T12:30:10Z"); + st += 2.days; + assert(st.toISOExtString() == "2018-01-03T12:30:10Z"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_stopwatch.d b/libphobos/testsuite/libphobos.phobos/std_datetime_stopwatch.d new file mode 100644 index 0000000000000000000000000000000000000000..df58cb1c9413ef94f8697a41d1172225f0425758 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_stopwatch.d @@ -0,0 +1,210 @@ +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + { + auto sw = StopWatch(AutoStart.yes); + assert(sw.running); + Thread.sleep(usecs(1)); + assert(sw.peek() > Duration.zero); + } + { + auto sw = StopWatch(AutoStart.no); + assert(!sw.running); + Thread.sleep(usecs(1)); + assert(sw.peek() == Duration.zero); + } + { + StopWatch sw; + assert(!sw.running); + Thread.sleep(usecs(1)); + assert(sw.peek() == Duration.zero); + } + + assert(StopWatch.init == StopWatch(AutoStart.no)); + assert(StopWatch.init != StopWatch(AutoStart.yes)); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + auto sw = StopWatch(AutoStart.yes); + Thread.sleep(usecs(1)); + sw.stop(); + assert(sw.peek() > Duration.zero); + sw.reset(); + assert(sw.peek() == Duration.zero); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + StopWatch sw; + assert(!sw.running); + assert(sw.peek() == Duration.zero); + sw.start(); + assert(sw.running); + Thread.sleep(usecs(1)); + assert(sw.peek() > Duration.zero); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + auto sw = StopWatch(AutoStart.yes); + assert(sw.running); + Thread.sleep(usecs(1)); + immutable t1 = sw.peek(); + assert(t1 > Duration.zero); + + sw.stop(); + assert(!sw.running); + immutable t2 = sw.peek(); + assert(t2 >= t1); + immutable t3 = sw.peek(); + assert(t2 == t3); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + auto sw = StopWatch(AutoStart.no); + assert(sw.peek() == Duration.zero); + sw.start(); + + Thread.sleep(usecs(1)); + assert(sw.peek() >= usecs(1)); + + Thread.sleep(usecs(1)); + assert(sw.peek() >= usecs(2)); + + sw.stop(); + immutable stopped = sw.peek(); + Thread.sleep(usecs(1)); + assert(sw.peek() == stopped); + + sw.start(); + Thread.sleep(usecs(1)); + assert(sw.peek() > stopped); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + StopWatch sw; + sw.setTimeElapsed(hours(1)); + + // As discussed in MonoTime's documentation, converting between + // Duration and ticks is not exact, though it will be close. + // How exact it is depends on the frequency/resolution of the + // system's monotonic clock. + assert(abs(sw.peek() - hours(1)) < usecs(1)); + + sw.start(); + Thread.sleep(usecs(1)); + assert(sw.peek() > hours(1) + usecs(1)); + +} + +@safe nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + StopWatch sw; + assert(!sw.running); + sw.start(); + assert(sw.running); + sw.stop(); + assert(!sw.running); + +} + +@safe nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + auto sw = StopWatch(AutoStart.no); + sw.start(); + // ... Insert operations to be timed here ... + sw.stop(); + + long msecs = sw.peek.total!"msecs"; + long usecs = sw.peek.total!"usecs"; + long nsecs = sw.peek.total!"nsecs"; + + assert(usecs >= msecs * 1000); + assert(nsecs >= usecs * 1000); +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + auto sw = StopWatch(AutoStart.yes); + + Duration t1 = sw.peek(); + Thread.sleep(usecs(1)); + Duration t2 = sw.peek(); + assert(t2 > t1); + + Thread.sleep(usecs(1)); + sw.stop(); + + Duration t3 = sw.peek(); + assert(t3 > t2); + Duration t4 = sw.peek(); + assert(t3 == t4); + + sw.start(); + Thread.sleep(usecs(1)); + + Duration t5 = sw.peek(); + assert(t5 > t4); + + // If stopping or resetting the StopWatch is not required, then + // MonoTime can easily be used by itself without StopWatch. + auto before = MonoTime.currTime; + // do stuff... + auto timeElapsed = MonoTime.currTime - before; +} + +@safe unittest +{ + import std.datetime.stopwatch; + + import std.conv : to; + + int a; + void f0() {} + void f1() { auto b = a; } + void f2() { auto b = to!string(a); } + auto r = benchmark!(f0, f1, f2)(10_000); + Duration f0Result = r[0]; // time f0 took to run 10,000 times + Duration f1Result = r[1]; // time f1 took to run 10,000 times + Duration f2Result = r[2]; // time f2 took to run 10,000 times +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_systime.d b/libphobos/testsuite/libphobos.phobos/std_datetime_systime.d new file mode 100644 index 0000000000000000000000000000000000000000..a0f410374d6b40c9acfc73db3b6ec08c6edbedee --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_systime.d @@ -0,0 +1,750 @@ +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.timezone : LocalTime; + SysTime today = Clock.currTime(); + assert(today.timezone is LocalTime()); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + import std.datetime.timezone : UTC; + + auto st = SysTime.fromISOExtString("2018-01-01T10:30:00Z"); + assert(st == SysTime(DateTime(2018, 1, 1, 10, 30, 0), UTC())); +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone; + + auto ny = SysTime( + DateTime(2018, 1, 1, 10, 30, 0), + new immutable SimpleTimeZone(-5.hours, "America/New_York") + ); + + // ISO standard time strings + assert(ny.toISOString() == "20180101T103000-05:00"); + assert(ny.toISOExtString() == "2018-01-01T10:30:00-05:00"); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.timezone : LocalTime; + SysTime today = Clock.currTime(); + assert(today.timezone is LocalTime()); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999); + assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010); + assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7); + +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1); + assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2); + assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101); + +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7); + assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10); + assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4); + +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6); + assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4); + assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, usecs, hnsecs, nsecs; + import std.datetime.date : DateTime; + + auto dt = DateTime(1982, 4, 1, 20, 59, 22); + assert(SysTime(dt, msecs(213)).fracSecs == msecs(213)); + assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202)); + assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567)); + + // SysTime and Duration both have a precision of hnsecs (100 ns), + // so nsecs are going to be truncated. + assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700)); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : Duration, msecs, hnsecs, nsecs; + import std.datetime.date : DateTime; + + auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22)); + assert(st.fracSecs == Duration.zero); + + st.fracSecs = msecs(213); + assert(st.fracSecs == msecs(213)); + + st.fracSecs = hnsecs(1234567); + assert(st.fracSecs == hnsecs(1234567)); + + // SysTime has a precision of hnsecs (100 ns), so nsecs are + // going to be truncated. + st.fracSecs = nsecs(123456789); + assert(st.fracSecs == hnsecs(1234567)); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0); + + auto pst = new immutable SimpleTimeZone(hours(-8)); + assert(SysTime(DateTime(1970, 1, 1), pst).toUnixTime() == 28800); + + auto utc = SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()); + assert(utc.toUnixTime() == 1_198_311_285); + + auto ca = SysTime(DateTime(2007, 12, 22, 8, 14, 45), pst); + assert(ca.toUnixTime() == 1_198_340_085); + + static void testScope(scope ref SysTime st) @safe + { + auto result = st.toUnixTime(); + } + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime.fromUnixTime(0) == + SysTime(DateTime(1970, 1, 1), UTC())); + + auto pst = new immutable SimpleTimeZone(hours(-8)); + assert(SysTime.fromUnixTime(28800) == + SysTime(DateTime(1970, 1, 1), pst)); + + auto st1 = SysTime.fromUnixTime(1_198_311_285, UTC()); + assert(st1 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC())); + assert(st1.timezone is UTC()); + assert(st1 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst)); + + auto st2 = SysTime.fromUnixTime(1_198_311_285, pst); + assert(st2 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC())); + assert(st2.timezone is pst); + assert(st2 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst)); + +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : AllowDayOverflow, DateTime; + + auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33)); + st1.roll!"months"(1); + assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33))); + + auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33)); + st2.roll!"months"(-1); + assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33))); + + auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33)); + st3.roll!"months"(1); + assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33))); + + auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33)); + st4.roll!"months"(1, AllowDayOverflow.no); + assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33))); + + auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33)); + st5.roll!"years"(1); + assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33))); + + auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33)); + st6.roll!"years"(1, AllowDayOverflow.no); + assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, hnsecs; + import std.datetime.date : DateTime; + + auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12)); + st1.roll!"days"(1); + assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12))); + st1.roll!"days"(365); + assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12))); + st1.roll!"days"(-32); + assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12))); + + auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0)); + st2.roll!"hours"(1); + assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0))); + + auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0)); + st3.roll!"hours"(-1); + assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0))); + + auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0)); + st4.roll!"minutes"(1); + assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0))); + + auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0)); + st5.roll!"minutes"(-1); + assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0))); + + auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0)); + st6.roll!"seconds"(1); + assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1))); + + auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0)); + st7.roll!"seconds"(-1); + assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59))); + + auto dt = DateTime(2010, 1, 1, 0, 0, 0); + auto st8 = SysTime(dt); + st8.roll!"msecs"(1); + assert(st8 == SysTime(dt, msecs(1))); + + auto st9 = SysTime(dt); + st9.roll!"msecs"(-1); + assert(st9 == SysTime(dt, msecs(999))); + + auto st10 = SysTime(dt); + st10.roll!"hnsecs"(1); + assert(st10 == SysTime(dt, hnsecs(1))); + + auto st11 = SysTime(dt); + st11.roll!"hnsecs"(-1); + assert(st11 == SysTime(dt, hnsecs(9_999_999))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours, seconds; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) == + SysTime(DateTime(2016, 1, 1, 0, 0, 0))); + + assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) == + SysTime(DateTime(2016, 1, 1, 0, 59, 59))); + + assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) == + SysTime(DateTime(2015, 12, 31, 23, 59, 59))); + + assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) == + SysTime(DateTime(2015, 12, 31, 23, 59, 59))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : Date; + + assert(SysTime(Date(1999, 2, 1)).diffMonths( + SysTime(Date(1999, 1, 31))) == 1); + + assert(SysTime(Date(1999, 1, 31)).diffMonths( + SysTime(Date(1999, 2, 1))) == -1); + + assert(SysTime(Date(1999, 3, 1)).diffMonths( + SysTime(Date(1999, 1, 1))) == 2); + + assert(SysTime(Date(1999, 1, 1)).diffMonths( + SysTime(Date(1999, 3, 31))) == -2); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1); + assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365); + assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1); + assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365); + assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366); + + assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0); + assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365); + assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366); + + assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120); + assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0)); + st.dayOfGregorianCal = 1; + assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0))); + + st.dayOfGregorianCal = 365; + assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0))); + + st.dayOfGregorianCal = 366; + assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0))); + + st.dayOfGregorianCal = 0; + assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0))); + + st.dayOfGregorianCal = -365; + assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0))); + + st.dayOfGregorianCal = -366; + assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0))); + + st.dayOfGregorianCal = 730_120; + assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0))); + + st.dayOfGregorianCal = 734_137; + assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : Date; + + auto st = SysTime(Date(1999, 7, 6)); + const cst = SysTime(Date(2010, 5, 1)); + immutable ist = SysTime(Date(2015, 10, 10)); + + assert(st.isoWeek == 27); + assert(cst.isoWeek == 17); + assert(ist.isoWeek == 41); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, usecs, hnsecs; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth == + SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999))); + + assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth == + SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999))); + + assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth == + SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999))); + + assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth == + SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31); + assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28); + assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29); + assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD); + assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD); + assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD); + assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, hnsecs; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() == + "20100704T070612"); + + assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() == + "19981225T021500.024"); + + assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() == + "00000105T230959"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() == + "-00040105T000002.052092"); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, hnsecs; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() == + "2010-07-04T07:06:12"); + + assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() == + "1998-12-25T02:15:00.024"); + + assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() == + "0000-01-05T23:09:59"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() == + "-0004-01-05T00:00:02.052092"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(4) == + "-0004-01-05T00:00:02.0520"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(2) == + "-0004-01-05T00:00:02.05"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(7) == + "-0004-01-05T00:00:02.0520920"); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, hnsecs; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() == + "2010-Jul-04 07:06:12"); + + assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() == + "1998-Dec-25 02:15:00.024"); + + assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() == + "0000-Jan-05 23:09:59"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() == + "-0004-Jan-05 00:00:02.052092"); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours, msecs, usecs, hnsecs; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime.fromISOString("20100704T070612") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromISOString("19981225T021500.007") == + SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7))); + + assert(SysTime.fromISOString("00000105T230959.00002") == + SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20))); + + assert(SysTime.fromISOString("20130207T043937.000050392") == + SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503))); + + assert(SysTime.fromISOString("-00040105T000002") == + SysTime(DateTime(-4, 1, 5, 0, 0, 2))); + + assert(SysTime.fromISOString(" 20100704T070612 ") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromISOString("20100704T070612Z") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC())); + + assert(SysTime.fromISOString("20100704T070612-0800") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(-8)))); + + assert(SysTime.fromISOString("20100704T070612+0800") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(8)))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours, msecs, usecs, hnsecs; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime.fromISOExtString("2010-07-04T07:06:12") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") == + SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7))); + + assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") == + SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20))); + + assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") == + SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503))); + + assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") == + SysTime(DateTime(-4, 1, 5, 0, 0, 2))); + + assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC())); + + assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(-8)))); + assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(8)))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours, msecs, usecs, hnsecs; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") == + SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7))); + + assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") == + SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20))); + + assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") == + SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503))); + + assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") == + SysTime(DateTime(-4, 1, 5, 0, 0, 2))); + + assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC())); + + assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(-8)))); + + assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(8)))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : days, hours, seconds; + import std.datetime.date : Date, DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + const dt = DateTime(2018, 1, 1, 10, 30, 0); + // make a specific point in time in the UTC timezone + auto st = SysTime(dt, UTC()); + assert(st.year == 2018); + assert(st.hour == 10); + + // cast to convert + assert(cast(DateTime) st == dt); + assert(cast(Date) st == Date(2018, 1, 1)); + + // make a specific point in time in the New York timezone + const ny = SysTime(dt, + new immutable SimpleTimeZone(-5.hours, "America/New_York") + ); + assert(ny != st); + assert(ny.hour == 10); + + // ISO standard time strings + assert(st.toISOString() == "20180101T103000Z"); + assert(st.toISOExtString() == "2018-01-01T10:30:00Z"); + + // add two days and 30 seconds + st += 2.days + 30.seconds; + assert(st.toISOExtString() == "2018-01-03T10:30:30Z"); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + import std.datetime.timezone : UTC; + + // Midnight, January 1st, 1970 + assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L); + assert(SysTime(unixTimeToStdTime(0)) == + SysTime(DateTime(1970, 1, 1), UTC())); + + assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L); + assert(SysTime(unixTimeToStdTime(int.max)) == + SysTime(DateTime(2038, 1, 19, 3, 14, 7), UTC())); + + assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L); + assert(SysTime(unixTimeToStdTime(-127_127)) == + SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC())); +} + +@safe unittest +{ + import std.datetime.systime; + + // Midnight, January 1st, 1970 UTC + assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0); + + // 2038-01-19 03:14:07 UTC + assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0))); + assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58))); + assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44))); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000); + assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101); + assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456); +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours; + import std.datetime.date : DateTime, DateTimeException; + import std.datetime.timezone : SimpleTimeZone, UTC; + import std.exception : assertThrown; + + auto tz = new immutable SimpleTimeZone(hours(-8)); + assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") == + SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz)); + + assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") == + SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC())); + + auto badStr = "29 Feb 2001 12:17:16 +0200"; + assertThrown!DateTimeException(parseRFC822DateTime(badStr)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_timezone.d b/libphobos/testsuite/libphobos.phobos/std_datetime_timezone.d new file mode 100644 index 0000000000000000000000000000000000000000..007902c339ec9b7517984fce82ad9a7a6059915a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_timezone.d @@ -0,0 +1,15 @@ +@safe unittest +{ + import std.datetime.timezone; + + version (Posix) + { + auto tz = PosixTimeZone.getTimeZone("America/Los_Angeles"); + + assert(tz.name == "America/Los_Angeles"); + assert(tz.stdName == "PST"); + assert(tz.dstName == "PDT"); + } + +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_demangle.d b/libphobos/testsuite/libphobos.phobos/std_demangle.d new file mode 100644 index 0000000000000000000000000000000000000000..7ec7843a7c6b54dd6cfbcb4793ff6ae798b55012 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_demangle.d @@ -0,0 +1,33 @@ +@safe pure unittest +{ + import std.demangle; + + // int b in module a + assert(demangle("_D1a1bi") == "int a.b"); + // char array foo in module test + assert(demangle("_D4test3fooAa") == "char[] test.foo"); +} + +@system unittest +{ + import std.demangle; + + import std.ascii : isAlphaNum; + import std.algorithm.iteration : chunkBy, joiner, map; + import std.algorithm.mutation : copy; + import std.conv : to; + import std.demangle : demangle; + import std.functional : pipe; + import std.stdio : stdin, stdout; + + void main() + { + stdin.byLineCopy + .map!( + l => l.chunkBy!(a => isAlphaNum(a) || a == '_') + .map!(a => a[1].pipe!(to!string, demangle)).joiner + ) + .copy(stdout.lockingTextWriter); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_crc.d b/libphobos/testsuite/libphobos.phobos/std_digest_crc.d new file mode 100644 index 0000000000000000000000000000000000000000..9ca8dd698f7d57d57178a4604f5735a88e9c146b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_crc.d @@ -0,0 +1,207 @@ +@safe unittest +{ + import std.digest.crc; + + //Template API + import std.digest.crc; + + ubyte[4] hash = crc32Of("The quick brown fox jumps over the lazy dog"); + assert(crcHexString(hash) == "414FA339"); + + //Feeding data + ubyte[1024] data; + CRC32 crc; + crc.put(data[]); + crc.start(); //Start again + crc.put(data[]); + hash = crc.finish(); +} + +@safe unittest +{ + import std.digest.crc; + + //OOP API + import std.digest.crc; + + auto crc = new CRC32Digest(); + ubyte[] hash = crc.digest("The quick brown fox jumps over the lazy dog"); + assert(crcHexString(hash) == "414FA339"); //352441c2 + + //Feeding data + ubyte[1024] data; + crc.put(data[]); + crc.reset(); //Start again + crc.put(data[]); + hash = crc.finish(); +} + +@safe unittest +{ + import std.digest.crc; + + //Simple example, hashing a string using crc32Of helper function + ubyte[4] hash32 = crc32Of("abc"); + //Let's get a hash string + assert(crcHexString(hash32) == "352441C2"); + // Repeat for CRC64 + ubyte[8] hash64ecma = crc64ECMAOf("abc"); + assert(crcHexString(hash64ecma) == "2CD8094A1A277627"); + ubyte[8] hash64iso = crc64ISOOf("abc"); + assert(crcHexString(hash64iso) == "3776C42000000000"); +} + +@safe unittest +{ + import std.digest.crc; + + ubyte[1024] data; + //Using the basic API + CRC32 hash32; + CRC64ECMA hash64ecma; + CRC64ISO hash64iso; + //Initialize data here... + hash32.put(data); + ubyte[4] result32 = hash32.finish(); + hash64ecma.put(data); + ubyte[8] result64ecma = hash64ecma.finish(); + hash64iso.put(data); + ubyte[8] result64iso = hash64iso.finish(); +} + +@safe unittest +{ + import std.digest.crc; + + //Let's use the template features: + //Note: When passing a CRC32 to a function, it must be passed by reference! + void doSomething(T)(ref T hash) + if (isDigest!T) + { + hash.put(cast(ubyte) 0); + } + CRC32 crc32; + crc32.start(); + doSomething(crc32); + assert(crcHexString(crc32.finish()) == "D202EF8D"); + // repeat for CRC64 + CRC64ECMA crc64ecma; + crc64ecma.start(); + doSomething(crc64ecma); + assert(crcHexString(crc64ecma.finish()) == "1FADA17364673F59"); + CRC64ISO crc64iso; + crc64iso.start(); + doSomething(crc64iso); + assert(crcHexString(crc64iso.finish()) == "6F90000000000000"); +} + +@system unittest +{ + import std.digest.crc; + + ubyte[] data = [4,5,7,25]; + assert(data.crc32Of == [167, 180, 199, 131]); + + import std.utf : byChar; + assert("hello"d.byChar.crc32Of == [134, 166, 16, 54]); + + ubyte[4] hash = "abc".crc32Of(); + assert(hash == digest!CRC32("ab", "c")); + + import std.range : iota; + enum ubyte S = 5, F = 66; + assert(iota(S, F).crc32Of == [59, 140, 234, 154]); +} + +@system unittest +{ + import std.digest.crc; + + ubyte[] data = [4,5,7,25]; + assert(data.crc64ECMAOf == [58, 142, 220, 214, 118, 98, 105, 69]); + + import std.utf : byChar; + assert("hello"d.byChar.crc64ECMAOf == [177, 55, 185, 219, 229, 218, 30, 155]); + + ubyte[8] hash = "abc".crc64ECMAOf(); + assert("abc".crc64ECMAOf == [39, 118, 39, 26, 74, 9, 216, 44]); + assert(hash == digest!CRC64ECMA("ab", "c")); + + import std.range : iota; + enum ubyte S = 5, F = 66; + assert(iota(S, F).crc64ECMAOf == [6, 184, 91, 238, 46, 213, 127, 188]); +} + +@system unittest +{ + import std.digest.crc; + + ubyte[] data = [4,5,7,25]; + assert(data.crc64ISOOf == [0, 0, 0, 80, 137, 232, 203, 120]); + + import std.utf : byChar; + assert("hello"d.byChar.crc64ISOOf == [0, 0, 16, 216, 226, 238, 62, 60]); + + ubyte[8] hash = "abc".crc64ISOOf(); + assert("abc".crc64ISOOf == [0, 0, 0, 0, 32, 196, 118, 55]); + assert(hash == digest!CRC64ISO("ab", "c")); + + import std.range : iota; + enum ubyte S = 5, F = 66; + + assert(iota(S, F).crc64ISOOf == [21, 185, 116, 95, 219, 11, 54, 7]); +} + +@safe unittest +{ + import std.digest.crc; + + //Simple example, hashing a string using CRC32Digest.digest helper function + auto crc = new CRC32Digest(); + ubyte[] hash = crc.digest("abc"); + //Let's get a hash string + assert(crcHexString(hash) == "352441C2"); +} + +@system unittest +{ + import std.digest.crc; + + //Let's use the OOP features: + void test(Digest dig) + { + dig.put(cast(ubyte) 0); + } + auto crc = new CRC32Digest(); + test(crc); + + //Let's use a custom buffer: + ubyte[4] buf; + ubyte[] result = crc.finish(buf[]); + assert(crcHexString(result) == "D202EF8D"); +} + +@safe unittest +{ + import std.digest.crc; + + //Simple example + auto hash = new CRC32Digest(); + hash.put(cast(ubyte) 0); + ubyte[] result = hash.finish(); +} + +@system unittest +{ + import std.digest.crc; + + //using a supplied buffer + ubyte[4] buf; + auto hash = new CRC32Digest(); + hash.put(cast(ubyte) 0); + ubyte[] result = hash.finish(buf[]); + //The result is now in result (and in buf. If you pass a buffer which is bigger than + //necessary, result will have the correct length, but buf will still have it's original + //length) +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_hmac.d b/libphobos/testsuite/libphobos.phobos/std_digest_hmac.d new file mode 100644 index 0000000000000000000000000000000000000000..db5fb972078216e17b8aea4761bf4de8871ab83c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_hmac.d @@ -0,0 +1,145 @@ +@safe unittest +{ + import std.digest.hmac; + + import std.ascii : LetterCase; + import std.digest : toHexString; + import std.digest.sha : SHA1; + import std.string : representation; + + auto secret = "secret".representation; + assert("The quick brown fox jumps over the lazy dog" + .representation + .hmac!SHA1(secret) + .toHexString!(LetterCase.lower) == "198ea1ea04c435c1246b586a06d5cf11c3ffcda6"); +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + hmac.put("Hello, world".representation); + static immutable expected = [ + 130, 32, 235, 44, 208, 141, + 150, 232, 211, 214, 162, 195, + 188, 127, 52, 89, 100, 68, 90, 216]; + assert(hmac.finish() == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + hmac.put(data1.representation); + hmac.start(); // reset digest + hmac.put(data2.representation); // start over + static immutable expected = [ + 122, 151, 232, 240, 249, 80, + 19, 178, 186, 77, 110, 23, 208, + 52, 11, 88, 34, 151, 192, 255]; + assert(hmac.finish() == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.hmac, std.digest.sha; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + hmac.put(data1.representation) + .put(data2.representation); + static immutable expected = [ + 197, 57, 52, 3, 13, 194, 13, + 36, 117, 228, 8, 11, 111, 51, + 165, 3, 123, 31, 251, 113]; + assert(hmac.finish() == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + auto testDigest = hmac.put(data1.representation) + .put(data2.representation) + .finish(); + static immutable expected = [ + 197, 57, 52, 3, 13, 194, 13, + 36, 117, 228, 8, 11, 111, 51, + 165, 3, 123, 31, 251, 113]; + assert(testDigest == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto digest = hmac!SHA1("My s3cR3T keY".representation) + .put(data1.representation) + .put(data2.representation) + .finish(); + static immutable expected = [ + 197, 57, 52, 3, 13, 194, 13, 36, + 117, 228, 8, 11, 111, 51, 165, + 3, 123, 31, 251, 113]; + assert(digest == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.algorithm.iteration : map; + import std.digest.sha : SHA1; + import std.string : representation; + string data = "Hello, world"; + auto digest = data.representation + .map!(a => cast(ubyte)(a+1)) + .hmac!SHA1("My s3cR3T keY".representation); + static assert(is(typeof(digest) == ubyte[20])); + static immutable expected = [ + 163, 208, 118, 179, 216, 93, + 17, 10, 84, 200, 87, 104, 244, + 111, 136, 214, 167, 210, 58, 10]; + assert(digest == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + auto digest = hmac.put(data1.representation) + .put(data2.representation) + .finish(); + static immutable expected = [ + 197, 57, 52, 3, 13, 194, 13, + 36, 117, 228, 8, 11, 111, 51, + 165, 3, 123, 31, 251, 113]; + assert(digest == expected); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_md.d b/libphobos/testsuite/libphobos.phobos/std_digest_md.d new file mode 100644 index 0000000000000000000000000000000000000000..a9cf45fa94e056b4a2fd8fd18dfe51e7c546ae36 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_md.d @@ -0,0 +1,124 @@ +@safe unittest +{ + import std.digest.md; + + //Template API + import std.digest.md; + + //Feeding data + ubyte[1024] data; + MD5 md5; + md5.start(); + md5.put(data[]); + md5.start(); //Start again + md5.put(data[]); + auto hash = md5.finish(); +} + +@safe unittest +{ + import std.digest.md; + + //OOP API + import std.digest.md; + + auto md5 = new MD5Digest(); + ubyte[] hash = md5.digest("abc"); + assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); + + //Feeding data + ubyte[1024] data; + md5.put(data[]); + md5.reset(); //Start again + md5.put(data[]); + hash = md5.finish(); +} + +@safe unittest +{ + import std.digest.md; + + //Simple example + MD5 hash; + hash.start(); + hash.put(cast(ubyte) 0); + ubyte[16] result = hash.finish(); + +} + +@safe unittest +{ + import std.digest.md; + + //Simple example, hashing a string using md5Of helper function + ubyte[16] hash = md5Of("abc"); + //Let's get a hash string + assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); +} + +@safe unittest +{ + import std.digest.md; + + //Using the basic API + MD5 hash; + hash.start(); + ubyte[1024] data; + //Initialize data here... + hash.put(data); + ubyte[16] result = hash.finish(); +} + +@safe unittest +{ + import std.digest.md; + + //Let's use the template features: + void doSomething(T)(ref T hash) + if (isDigest!T) + { + hash.put(cast(ubyte) 0); + } + MD5 md5; + md5.start(); + doSomething(md5); + assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); +} + +@safe unittest +{ + import std.digest.md; + + ubyte[16] hash = md5Of("abc"); + assert(hash == digest!MD5("abc")); +} + +@safe unittest +{ + import std.digest.md; + + //Simple example, hashing a string using Digest.digest helper function + auto md5 = new MD5Digest(); + ubyte[] hash = md5.digest("abc"); + //Let's get a hash string + assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); +} + +@system unittest +{ + import std.digest.md; + + //Let's use the OOP features: + void test(Digest dig) + { + dig.put(cast(ubyte) 0); + } + auto md5 = new MD5Digest(); + test(md5); + + //Let's use a custom buffer: + ubyte[16] buf; + ubyte[] result = md5.finish(buf[]); + assert(toHexString(result) == "93B885ADFE0DA089CDF634904FD59F71"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_murmurhash.d b/libphobos/testsuite/libphobos.phobos/std_digest_murmurhash.d new file mode 100644 index 0000000000000000000000000000000000000000..c44496d54780e69f7689c51bfcc3bb37743d08b7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_murmurhash.d @@ -0,0 +1,82 @@ +@safe unittest +{ + import std.digest.murmurhash; + + // MurmurHash3!32, MurmurHash3!(128, 32) and MurmurHash3!(128, 64) implement + // the std.digest Template API. + static assert(isDigest!(MurmurHash3!32)); + // The convenient digest template allows for quick hashing of any data. + ubyte[4] hashed = digest!(MurmurHash3!32)([1, 2, 3, 4]); + assert(hashed == [0, 173, 69, 68]); +} + +@safe unittest +{ + import std.digest.murmurhash; + + // One can also hash ubyte data piecewise by instanciating a hasher and call + // the 'put' method. + const(ubyte)[] data1 = [1, 2, 3]; + const(ubyte)[] data2 = [4, 5, 6, 7]; + // The incoming data will be buffered and hashed element by element. + MurmurHash3!32 hasher; + hasher.put(data1); + hasher.put(data2); + // The call to 'finish' ensures: + // - the remaining bits are processed + // - the hash gets finalized + auto hashed = hasher.finish(); + assert(hashed == [181, 151, 88, 252]); +} + +@safe unittest +{ + import std.digest.murmurhash; + + // Using `putElements`, `putRemainder` and `finalize` you gain full + // control over which part of the algorithm to run. + // This allows for maximum throughput but needs extra care. + + // Data type must be the same as the hasher's element type: + // - uint for MurmurHash3!32 + // - uint[4] for MurmurHash3!(128, 32) + // - ulong[2] for MurmurHash3!(128, 64) + const(uint)[] data = [1, 2, 3, 4]; + // Note the hasher starts with 'Fast'. + MurmurHash3!32 hasher; + // Push as many array of elements as you need. The less calls the better. + hasher.putElements(data); + // Put remainder bytes if needed. This method can be called only once. + hasher.putRemainder(ubyte(1), ubyte(1), ubyte(1)); + // Call finalize to incorporate data length in the hash. + hasher.finalize(); + // Finally get the hashed value. + auto hashed = hasher.getBytes(); + assert(hashed == [188, 165, 108, 2]); +} + +@safe unittest +{ + import std.digest.murmurhash; + + ubyte[4] hashed = digest!(MurmurHash3!32)([1, 2, 3, 4]); + assert(hashed == [0, 173, 69, 68]); +} + +@safe unittest +{ + import std.digest.murmurhash; + + const(ubyte)[] data1 = [1, 2, 3]; + const(ubyte)[] data2 = [4, 5, 6, 7]; + // The incoming data will be buffered and hashed element by element. + MurmurHash3!32 hasher; + hasher.put(data1); + hasher.put(data2); + // The call to 'finish' ensures: + // - the remaining bits are processed + // - the hash gets finalized + auto hashed = hasher.finish(); + assert(hashed == [181, 151, 88, 252]); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_package.d b/libphobos/testsuite/libphobos.phobos/std_digest_package.d new file mode 100644 index 0000000000000000000000000000000000000000..330326c3fdecba9e7783e828e327ed67e18b2e23 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_package.d @@ -0,0 +1,492 @@ +@system unittest +{ + import std.digest; + + import std.digest.crc; + + //Simple example + char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog"); + assert(hexHash == "39A34F41"); + + //Simple example, using the API manually + CRC32 context = makeDigest!CRC32(); + context.put(cast(ubyte[])"The quick brown fox jumps over the lazy dog"); + ubyte[4] hash = context.finish(); + assert(toHexString(hash) == "39A34F41"); +} + +@system unittest +{ + import std.digest; + + //Generating the hashes of a file, idiomatic D way + import std.digest.crc, std.digest.md, std.digest.sha; + import std.stdio; + + // Digests a file and prints the result. + void digestFile(Hash)(string filename) + if (isDigest!Hash) + { + auto file = File(filename); + auto result = digest!Hash(file.byChunk(4096 * 1024)); + writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); + } + + void main(string[] args) + { + foreach (name; args[1 .. $]) + { + digestFile!MD5(name); + digestFile!SHA1(name); + digestFile!CRC32(name); + } + } +} + +@system unittest +{ + import std.digest; + + //Generating the hashes of a file using the template API + import std.digest.crc, std.digest.md, std.digest.sha; + import std.stdio; + // Digests a file and prints the result. + void digestFile(Hash)(ref Hash hash, string filename) + if (isDigest!Hash) + { + File file = File(filename); + + //As digests imlement OutputRange, we could use std.algorithm.copy + //Let's do it manually for now + foreach (buffer; file.byChunk(4096 * 1024)) + hash.put(buffer); + + auto result = hash.finish(); + writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); + } + + void uMain(string[] args) + { + MD5 md5; + SHA1 sha1; + CRC32 crc32; + + md5.start(); + sha1.start(); + crc32.start(); + + foreach (arg; args[1 .. $]) + { + digestFile(md5, arg); + digestFile(sha1, arg); + digestFile(crc32, arg); + } + } +} + +@system unittest +{ + import std.digest; + + import std.digest.crc, std.digest.md, std.digest.sha; + import std.stdio; + + // Digests a file and prints the result. + void digestFile(Digest hash, string filename) + { + File file = File(filename); + + //As digests implement OutputRange, we could use std.algorithm.copy + //Let's do it manually for now + foreach (buffer; file.byChunk(4096 * 1024)) + hash.put(buffer); + + ubyte[] result = hash.finish(); + writefln("%s (%s) = %s", typeid(hash).toString(), filename, toHexString(result)); + } + + void umain(string[] args) + { + auto md5 = new MD5Digest(); + auto sha1 = new SHA1Digest(); + auto crc32 = new CRC32Digest(); + + foreach (arg; args[1 .. $]) + { + digestFile(md5, arg); + digestFile(sha1, arg); + digestFile(crc32, arg); + } + } +} + +@system unittest +{ + import std.digest; + + //Using the OutputRange feature + import std.algorithm.mutation : copy; + import std.digest.md; + import std.range : repeat; + + auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); + auto ctx = makeDigest!MD5(); + copy(oneMillionRange, &ctx); //Note: You must pass a pointer to copy! + assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + static assert(isDigest!CRC32); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + void myFunction(T)() + if (isDigest!T) + { + T dig; + dig.start(); + auto result = dig.finish(); + } + myFunction!CRC32(); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + assert(is(DigestType!(CRC32) == ubyte[4])); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + CRC32 dig; + dig.start(); + DigestType!CRC32 result = dig.finish(); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc, std.digest.md; + assert(!hasPeek!(MD5)); + assert(hasPeek!CRC32); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + void myFunction(T)() + if (hasPeek!T) + { + T dig; + dig.start(); + auto result = dig.peek(); + } + myFunction!CRC32(); +} + +@system unittest +{ + import std.digest; + + import std.digest.hmac, std.digest.md; + static assert(hasBlockSize!MD5 && MD5.blockSize == 512); + static assert(hasBlockSize!(HMAC!MD5) && HMAC!MD5.blockSize == 512); +} + +@system unittest +{ + import std.digest; + + import std.digest.md; + import std.range : repeat; + auto testRange = repeat!ubyte(cast(ubyte)'a', 100); + auto md5 = digest!MD5(testRange); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc, std.digest.md, std.digest.sha; + auto md5 = digest!MD5( "The quick brown fox jumps over the lazy dog"); + auto sha1 = digest!SHA1( "The quick brown fox jumps over the lazy dog"); + auto crc32 = digest!CRC32("The quick brown fox jumps over the lazy dog"); + assert(toHexString(crc32) == "39A34F41"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); + assert(toHexString(crc32) == "39A34F41"); +} + +@system unittest +{ + import std.digest; + + import std.digest.md; + import std.range : repeat; + auto testRange = repeat!ubyte(cast(ubyte)'a', 100); + assert(hexDigest!MD5(testRange) == "36A92CC94A9E0FA21F625F8BFB007ADF"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + assert(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog") == "414FA339"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + assert(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog") == "414FA339"); +} + +@system unittest +{ + import std.digest; + + import std.digest.md; + auto md5 = makeDigest!MD5(); + md5.put(0); + assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); +} + +@system unittest +{ + import std.digest; + + //Using the OutputRange feature + import std.algorithm.mutation : copy; + import std.digest.md; + import std.range : repeat; + + auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); + auto ctx = new MD5Digest(); + copy(oneMillionRange, ctx); + assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc, std.digest.md, std.digest.sha; + ubyte[] md5 = (new MD5Digest()).digest("The quick brown fox jumps over the lazy dog"); + ubyte[] sha1 = (new SHA1Digest()).digest("The quick brown fox jumps over the lazy dog"); + ubyte[] crc32 = (new CRC32Digest()).digest("The quick brown fox jumps over the lazy dog"); + assert(crcHexString(crc32) == "414FA339"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); + assert(crcHexString(crc32) == "414FA339"); +} + +@system unittest +{ + import std.digest; + + void test(Digest dig) + { + dig.put(cast(ubyte) 0); //single ubyte + dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic + ubyte[10] buf; + dig.put(buf); //buffer + } +} + +@safe unittest +{ + import std.digest; + + import std.digest.crc : CRC32; + + auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); + assert(crc32.toHexString!(Order.decreasing) == "414FA339"); + assert(crc32.toHexString!(LetterCase.lower, Order.decreasing) == "414fa339"); +} + +@safe unittest +{ + import std.digest; + + import std.digest.crc; + //Test with template API: + auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); + //Lower case variant: + assert(toHexString!(LetterCase.lower)(crc32) == "39a34f41"); + //Usually CRCs are printed in this order, though: + assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); + assert(toHexString!(LetterCase.lower, Order.decreasing)(crc32) == "414fa339"); +} + +@safe unittest +{ + import std.digest; + + import std.digest.crc; + // With OOP API + auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); + //Usually CRCs are printed in this order, though: + assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); +} + +@system unittest +{ + import std.digest; + + import std.digest.md; + //Simple example + auto hash = new WrapperDigest!MD5(); + hash.put(cast(ubyte) 0); + auto result = hash.finish(); +} + +@system unittest +{ + import std.digest; + + //using a supplied buffer + import std.digest.md; + ubyte[16] buf; + auto hash = new WrapperDigest!MD5(); + hash.put(cast(ubyte) 0); + auto result = hash.finish(buf[]); + //The result is now in result (and in buf). If you pass a buffer which is bigger than + //necessary, result will have the correct length, but buf will still have it's original + //length +} + +@system pure unittest +{ + import std.digest; + + import std.digest.hmac : hmac; + import std.digest.sha : SHA1; + import std.string : representation; + + // a typical HMAC data integrity verification + auto secret = "A7GZIP6TAQA6OHM7KZ42KB9303CEY0MOV5DD6NTV".representation; + auto data = "data".representation; + + auto hex1 = data.hmac!SHA1(secret).toHexString; + auto hex2 = data.hmac!SHA1(secret).toHexString; + auto hex3 = "data1".representation.hmac!SHA1(secret).toHexString; + + assert( secureEqual(hex1[], hex2[])); + assert(!secureEqual(hex1[], hex3[])); +} + +@safe unittest +{ + import std.digest; + + assert(isHexString("0x0123456789ABCDEFabcdef")); + assert(isHexString("0123456789ABCDEFabcdef")); + assert(!isHexString("g")); + assert(!isHexString("#")); +} + +@safe unittest +{ + import std.digest; + + import std.range.primitives : ElementType, isForwardRange; + import std.traits : ReturnType; + + // The decoder implements a forward range. + static assert(isForwardRange!(ReturnType!(fromHexStringAsRange!string))); + static assert(isForwardRange!(ReturnType!(fromHexStringAsRange!wstring))); + static assert(isForwardRange!(ReturnType!(fromHexStringAsRange!dstring))); + + // The element type of the range is always `ubyte`. + static assert( + is(ElementType!(ReturnType!(fromHexStringAsRange!string)) == ubyte) + ); + static assert( + is(ElementType!(ReturnType!(fromHexStringAsRange!wstring)) == ubyte) + ); + static assert( + is(ElementType!(ReturnType!(fromHexStringAsRange!dstring)) == ubyte) + ); +} + +@safe unittest +{ + import std.digest; + + // Single byte + assert("0xff".fromHexString == [255]); + assert("0xff"w.fromHexString == [255]); + assert("0xff"d.fromHexString == [255]); + assert("0xC0".fromHexString == [192]); + assert("0x00".fromHexString == [0]); + + // Nothing + assert("".fromHexString == []); + assert(""w.fromHexString == []); + assert(""d.fromHexString == []); + + // Nothing but a prefix + assert("0x".fromHexString == []); + assert("0x"w.fromHexString == []); + assert("0x"d.fromHexString == []); + + // Half a byte + assert("0x1".fromHexString == [0x01]); + assert("0x1"w.fromHexString == [0x01]); + assert("0x1"d.fromHexString == [0x01]); + + // Mixed case is fine. + assert("0xAf".fromHexString == [0xAF]); + assert("0xaF".fromHexString == [0xAF]); + + // Multiple bytes + assert("0xfff".fromHexString == [0x0F, 0xFF]); + assert("0x123AaAa".fromHexString == [0x01, 0x23, 0xAA, 0xAA]); + assert("EBBBBF".fromHexString == [0xEB, 0xBB, 0xBF]); + + // md5 sum + assert("d41d8cd98f00b204e9800998ecf8427e".fromHexString == [ + 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, + 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E, + ]); +} + +@safe unittest +{ + import std.digest; + + // Cycle self-test + const ubyte[] initial = [0x00, 0x12, 0x34, 0xEB]; + assert(initial == initial.toHexString().fromHexString()); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_ripemd.d b/libphobos/testsuite/libphobos.phobos/std_digest_ripemd.d new file mode 100644 index 0000000000000000000000000000000000000000..582a21bd7219abe6a25369fb9db55c144c8ed825 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_ripemd.d @@ -0,0 +1,127 @@ +@safe unittest +{ + import std.digest.ripemd; + + //Template API + import std.digest.md; + + ubyte[20] hash = ripemd160Of("abc"); + assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); + + //Feeding data + ubyte[1024] data; + RIPEMD160 md; + md.start(); + md.put(data[]); + md.start(); //Start again + md.put(data[]); + hash = md.finish(); +} + +@safe unittest +{ + import std.digest.ripemd; + + //OOP API + import std.digest.md; + + auto md = new RIPEMD160Digest(); + ubyte[] hash = md.digest("abc"); + assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); + + //Feeding data + ubyte[1024] data; + md.put(data[]); + md.reset(); //Start again + md.put(data[]); + hash = md.finish(); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Simple example, hashing a string using ripemd160Of helper function + ubyte[20] hash = ripemd160Of("abc"); + //Let's get a hash string + assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Using the basic API + RIPEMD160 hash; + hash.start(); + ubyte[1024] data; + //Initialize data here... + hash.put(data); + ubyte[20] result = hash.finish(); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Let's use the template features: + void doSomething(T)(ref T hash) + if (isDigest!T) + { + hash.put(cast(ubyte) 0); + } + RIPEMD160 md; + md.start(); + doSomething(md); + assert(toHexString(md.finish()) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Simple example + RIPEMD160 hash; + hash.start(); + hash.put(cast(ubyte) 0); + ubyte[20] result = hash.finish(); + assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); +} + +@safe unittest +{ + import std.digest.ripemd; + + ubyte[20] hash = ripemd160Of("abc"); + assert(hash == digest!RIPEMD160("abc")); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Simple example, hashing a string using Digest.digest helper function + auto md = new RIPEMD160Digest(); + ubyte[] hash = md.digest("abc"); + //Let's get a hash string + assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); +} + +@system unittest +{ + import std.digest.ripemd; + + //Let's use the OOP features: + void test(Digest dig) + { + dig.put(cast(ubyte) 0); + } + auto md = new RIPEMD160Digest(); + test(md); + + //Let's use a custom buffer: + ubyte[20] buf; + ubyte[] result = md.finish(buf[]); + assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_sha.d b/libphobos/testsuite/libphobos.phobos/std_digest_sha.d new file mode 100644 index 0000000000000000000000000000000000000000..04339ef8ac5134e7cfedba17a95b6c53a0980b67 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_sha.d @@ -0,0 +1,163 @@ +@safe unittest +{ + import std.digest.sha; + + //Template API + import std.digest.sha; + + ubyte[20] hash1 = sha1Of("abc"); + assert(toHexString(hash1) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + ubyte[28] hash224 = sha224Of("abc"); + assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); + + //Feeding data + ubyte[1024] data; + SHA1 sha1; + sha1.start(); + sha1.put(data[]); + sha1.start(); //Start again + sha1.put(data[]); + hash1 = sha1.finish(); +} + +@safe unittest +{ + import std.digest.sha; + + //OOP API + import std.digest.sha; + + auto sha1 = new SHA1Digest(); + ubyte[] hash1 = sha1.digest("abc"); + assert(toHexString(hash1) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + auto sha224 = new SHA224Digest(); + ubyte[] hash224 = sha224.digest("abc"); + assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); + + //Feeding data + ubyte[1024] data; + sha1.put(data[]); + sha1.reset(); //Start again + sha1.put(data[]); + hash1 = sha1.finish(); +} + +@safe unittest +{ + import std.digest.sha; + + //Simple example + SHA1 hash; + hash.start(); + hash.put(cast(ubyte) 0); + ubyte[20] result = hash.finish(); + +} + +@safe unittest +{ + import std.digest.sha; + + //Simple example, hashing a string using sha1Of helper function + ubyte[20] hash = sha1Of("abc"); + //Let's get a hash string + assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + //The same, but using SHA-224 + ubyte[28] hash224 = sha224Of("abc"); + assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); +} + +@safe unittest +{ + import std.digest.sha; + + //Using the basic API + SHA1 hash; + hash.start(); + ubyte[1024] data; + //Initialize data here... + hash.put(data); + ubyte[20] result = hash.finish(); +} + +@safe unittest +{ + import std.digest.sha; + + //Let's use the template features: + //Note: When passing a SHA1 to a function, it must be passed by reference! + void doSomething(T)(ref T hash) + if (isDigest!T) + { + hash.put(cast(ubyte) 0); + } + SHA1 sha; + sha.start(); + doSomething(sha); + assert(toHexString(sha.finish()) == "5BA93C9DB0CFF93F52B521D7420E43F6EDA2784F"); +} + +@safe unittest +{ + import std.digest.sha; + + ubyte[20] hash = sha1Of("abc"); + assert(hash == digest!SHA1("abc")); + + ubyte[28] hash224 = sha224Of("abc"); + assert(hash224 == digest!SHA224("abc")); + + ubyte[32] hash256 = sha256Of("abc"); + assert(hash256 == digest!SHA256("abc")); + + ubyte[48] hash384 = sha384Of("abc"); + assert(hash384 == digest!SHA384("abc")); + + ubyte[64] hash512 = sha512Of("abc"); + assert(hash512 == digest!SHA512("abc")); + + ubyte[28] hash512_224 = sha512_224Of("abc"); + assert(hash512_224 == digest!SHA512_224("abc")); + + ubyte[32] hash512_256 = sha512_256Of("abc"); + assert(hash512_256 == digest!SHA512_256("abc")); +} + +@safe unittest +{ + import std.digest.sha; + + //Simple example, hashing a string using Digest.digest helper function + auto sha = new SHA1Digest(); + ubyte[] hash = sha.digest("abc"); + //Let's get a hash string + assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + //The same, but using SHA-224 + auto sha224 = new SHA224Digest(); + ubyte[] hash224 = sha224.digest("abc"); + //Let's get a hash string + assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); +} + +@system unittest +{ + import std.digest.sha; + + //Let's use the OOP features: + void test(Digest dig) + { + dig.put(cast(ubyte) 0); + } + auto sha = new SHA1Digest(); + test(sha); + + //Let's use a custom buffer: + ubyte[20] buf; + ubyte[] result = sha.finish(buf[]); + assert(toHexString(result) == "5BA93C9DB0CFF93F52B521D7420E43F6EDA2784F"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_encoding.d b/libphobos/testsuite/libphobos.phobos/std_encoding.d new file mode 100644 index 0000000000000000000000000000000000000000..15003e370c971db4a67e1637be64fff81a59a711 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_encoding.d @@ -0,0 +1,167 @@ +@safe unittest +{ + import std.encoding; + + assert(encodingName!(char) == "UTF-8"); + assert(encodingName!(wchar) == "UTF-16"); + assert(encodingName!(dchar) == "UTF-32"); + assert(encodingName!(AsciiChar) == "ASCII"); + assert(encodingName!(Latin1Char) == "ISO-8859-1"); + assert(encodingName!(Latin2Char) == "ISO-8859-2"); + assert(encodingName!(Windows1250Char) == "windows-1250"); + assert(encodingName!(Windows1251Char) == "windows-1251"); + assert(encodingName!(Windows1252Char) == "windows-1252"); +} + +@safe pure unittest +{ + import std.encoding; + + assert( canEncode!(Latin1Char)('A')); + assert( canEncode!(Latin2Char)('A')); + assert(!canEncode!(AsciiChar)('\u00A0')); + assert( canEncode!(Latin1Char)('\u00A0')); + assert( canEncode!(Latin2Char)('\u00A0')); + assert( canEncode!(Windows1250Char)('\u20AC')); + assert(!canEncode!(Windows1250Char)('\u20AD')); + assert(!canEncode!(Windows1250Char)('\uFFFD')); + assert( canEncode!(Windows1251Char)('\u0402')); + assert(!canEncode!(Windows1251Char)('\u20AD')); + assert(!canEncode!(Windows1251Char)('\uFFFD')); + assert( canEncode!(Windows1252Char)('\u20AC')); + assert(!canEncode!(Windows1252Char)('\u20AD')); + assert(!canEncode!(Windows1252Char)('\uFFFD')); + assert(!canEncode!(char)(cast(dchar) 0x110000)); +} + +@safe pure unittest +{ + import std.encoding; + + import std.algorithm.searching : find; + import std.utf : byDchar; + + assert("The quick brown fox" + .byDchar + .find!(x => !canEncode!AsciiChar(x)) + .empty); +} + +@system pure unittest +{ + import std.encoding; + + assert(!isValidCodeUnit(cast(char) 0xC0)); + assert(!isValidCodeUnit(cast(char) 0xFF)); + assert( isValidCodeUnit(cast(wchar) 0xD800)); + assert(!isValidCodeUnit(cast(dchar) 0xD800)); + assert(!isValidCodeUnit(cast(AsciiChar) 0xA0)); + assert( isValidCodeUnit(cast(Windows1250Char) 0x80)); + assert(!isValidCodeUnit(cast(Windows1250Char) 0x81)); + assert( isValidCodeUnit(cast(Windows1251Char) 0x80)); + assert(!isValidCodeUnit(cast(Windows1251Char) 0x98)); + assert( isValidCodeUnit(cast(Windows1252Char) 0x80)); + assert(!isValidCodeUnit(cast(Windows1252Char) 0x81)); +} + +@system pure unittest +{ + import std.encoding; + + assert( isValid("\u20AC100")); + assert(!isValid(cast(char[3])[167, 133, 175])); +} + +@system pure unittest +{ + import std.encoding; + + assert(sanitize("hello \xF0\x80world") == "hello \xEF\xBF\xBDworld"); +} + +@system pure unittest +{ + import std.encoding; + + assert(firstSequence("\u20AC1000") == "\u20AC".length); + assert(firstSequence("hel") == "h".length); +} + +@system pure unittest +{ + import std.encoding; + + assert(lastSequence("1000\u20AC") == "\u20AC".length); + assert(lastSequence("hellö") == "ö".length); +} + +@system pure unittest +{ + import std.encoding; + + assert(index("\u20AC100",1) == 3); + assert(index("hällo",2) == 3); +} + +@system unittest +{ + import std.encoding; + + string s = "hello"; + string t; + foreach (c;codePoints(s)) + { + t ~= cast(char) c; + } + assert(s == t); +} + +@system unittest +{ + import std.encoding; + + char[] a; + foreach (c;codeUnits!(char)(cast(dchar)'\u20AC')) + { + a ~= c; + } + assert(a.length == 3); + assert(a[0] == 0xE2); + assert(a[1] == 0x82); + assert(a[2] == 0xAC); +} + +@system pure unittest +{ + import std.encoding; + + wstring ws; + // transcode from UTF-8 to UTF-16 + transcode("hello world",ws); + assert(ws == "hello world"w); + + Latin1String ls; + // transcode from UTF-16 to ISO-8859-1 + transcode(ws, ls); + assert(ls == "hello world"); +} + +@system unittest +{ + import std.encoding; + + import std.format : format; + + auto ts = dchar(0x0000FEFF) ~ "Hello World"d; + + auto entry = getBOM(cast(ubyte[]) ts); + version (BigEndian) + { + assert(entry.schema == BOM.utf32be, format("%s", entry.schema)); + } + else + { + assert(entry.schema == BOM.utf32le, format("%s", entry.schema)); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_exception.d b/libphobos/testsuite/libphobos.phobos/std_exception.d new file mode 100644 index 0000000000000000000000000000000000000000..8f973208c1543bdad1259d8aa03f14c55597308e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_exception.d @@ -0,0 +1,543 @@ +@system unittest +{ + import std.exception; + + import core.stdc.stdlib : malloc, free; + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map, splitter; + import std.algorithm.searching : endsWith; + import std.conv : ConvException, to; + import std.range : front, retro; + + // use enforce like assert + int a = 3; + enforce(a > 2, "a needs to be higher than 2."); + + // enforce can throw a custom exception + enforce!ConvException(a > 2, "a needs to be higher than 2."); + + // enforce will return it's input + enum size = 42; + auto memory = enforce(malloc(size), "malloc failed")[0 .. size]; + scope(exit) free(memory.ptr); + + // collectException can be used to test for exceptions + Exception e = collectException("abc".to!int); + assert(e.file.endsWith("conv.d")); + + // and just for the exception message + string msg = collectExceptionMsg("abc".to!int); + assert(msg == "Unexpected 'a' when converting from type string to type int"); + + // assertThrown can be used to assert that an exception is thrown + assertThrown!ConvException("abc".to!int); + + // ifThrown can be used to provide a default value if an exception is thrown + assert("x".to!int().ifThrown(0) == 0); + + // handle is a more advanced version of ifThrown for ranges + auto r = "12,1337z32,54".splitter(',').map!(a => to!int(a)); + auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); + assert(h.equal([12, 0, 54])); + assertThrown!ConvException(h.retro.equal([54, 0, 12])); + + // basicExceptionCtors avoids the boilerplate when creating custom exceptions + static class MeaCulpa : Exception + { + mixin basicExceptionCtors; + } + e = collectException((){throw new MeaCulpa("diagnostic message");}()); + assert(e.msg == "diagnostic message"); + assert(e.file == __FILE__); + assert(e.line == __LINE__ - 3); + + // assumeWontThrow can be used to cast throwing code into `nothrow` + void exceptionFreeCode() nothrow + { + // auto-decoding only throws if an invalid UTF char is given + assumeWontThrow("abc".front); + } + + // assumeUnique can be used to cast mutable instance to an `immutable` one + // use with care + char[] str = " mutable".dup; + str[0 .. 2] = "im"; + immutable res = assumeUnique(str); + assert(res == "immutable"); +} + +@system unittest +{ + import std.exception; + + import core.exception : AssertError; + + import std.string; + assertNotThrown!StringException(enforce!StringException(true, "Error!")); + + //Exception is the default. + assertNotThrown(enforce!StringException(true, "Error!")); + + assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( + enforce!StringException(false, "Error!"))) == + `assertNotThrown failed: StringException was thrown: Error!`); +} + +@system unittest +{ + import std.exception; + + import core.exception : AssertError; + import std.string; + + assertThrown!StringException(enforce!StringException(false, "Error!")); + + //Exception is the default. + assertThrown(enforce!StringException(false, "Error!")); + + assert(collectExceptionMsg!AssertError(assertThrown!StringException( + enforce!StringException(true, "Error!"))) == + `assertThrown failed: No StringException was thrown.`); +} + +@system unittest +{ + import std.exception; + + import core.stdc.stdlib : malloc, free; + import std.conv : ConvException, to; + + // use enforce like assert + int a = 3; + enforce(a > 2, "a needs to be higher than 2."); + + // enforce can throw a custom exception + enforce!ConvException(a > 2, "a needs to be higher than 2."); + + // enforce will return it's input + enum size = 42; + auto memory = enforce(malloc(size), "malloc failed")[0 .. size]; + scope(exit) free(memory.ptr); +} + +@safe unittest +{ + import std.exception; + + assertNotThrown(enforce(true, new Exception("this should not be thrown"))); + assertThrown(enforce(false, new Exception("this should be thrown"))); +} + +@safe unittest +{ + import std.exception; + + assert(enforce(123) == 123); + + try + { + enforce(false, "error"); + assert(false); + } + catch (Exception e) + { + assert(e.msg == "error"); + assert(e.file == __FILE__); + assert(e.line == __LINE__-7); + } +} + +@safe unittest +{ + import std.exception; + + import std.conv : ConvException; + alias convEnforce = enforce!ConvException; + assertNotThrown(convEnforce(true)); + assertThrown!ConvException(convEnforce(false, "blah")); +} + +@system unittest +{ + import std.exception; + + import core.stdc.stdio : fclose, fgets, fopen; + import std.file : thisExePath; + import std.string : toStringz; + + auto f = fopen(thisExePath.toStringz, "r").errnoEnforce; + scope(exit) fclose(f); + char[100] buf; + auto line = fgets(buf.ptr, buf.length, f); + enforce(line !is null); // expect a non-empty line +} + +@system unittest +{ + import std.exception; + + int b; + int foo() { throw new Exception("blah"); } + assert(collectException(foo(), b)); + + version (D_NoBoundsChecks) {} + else + { + // check for out of bounds error + int[] a = new int[3]; + import core.exception : RangeError; + assert(collectException!RangeError(a[4], b)); + } +} + +@safe unittest +{ + import std.exception; + + int foo() { throw new Exception("blah"); } + assert(collectException(foo()).msg == "blah"); +} + +@safe unittest +{ + import std.exception; + + void throwFunc() { throw new Exception("My Message."); } + assert(collectExceptionMsg(throwFunc()) == "My Message."); + + void nothrowFunc() {} + assert(collectExceptionMsg(nothrowFunc()) is null); + + void throwEmptyFunc() { throw new Exception(""); } + assert(collectExceptionMsg(throwEmptyFunc()) == emptyExceptionMsg); +} + +@system unittest +{ + import std.exception; + + int[] arr = new int[1]; + auto arr1 = arr.assumeUnique; + static assert(is(typeof(arr1) == immutable(int)[])); + assert(arr == null); + assert(arr1 == [0]); +} + +@system unittest +{ + import std.exception; + + int[string] arr = ["a":1]; + auto arr1 = arr.assumeUnique; + static assert(is(typeof(arr1) == immutable(int[string]))); + assert(arr == null); + assert(arr1.keys == ["a"]); +} + +@safe unittest +{ + import std.exception; + + import std.math.algebraic : sqrt; + + // This function may throw. + int squareRoot(int x) + { + if (x < 0) + throw new Exception("Tried to take root of negative number"); + return cast(int) sqrt(cast(double) x); + } + + // This function never throws. + int computeLength(int x, int y) nothrow + { + // Since x*x + y*y is always positive, we can safely assume squareRoot + // won't throw, and use it to implement this nothrow function. If it + // does throw (e.g., if x*x + y*y overflows a 32-bit value), then the + // program will terminate. + return assumeWontThrow(squareRoot(x*x + y*y)); + } + + assert(computeLength(3, 4) == 5); +} + +@system unittest +{ + import std.exception; + + int i = 0; + int* p = null; + assert(!p.doesPointTo(i)); + p = &i; + assert( p.doesPointTo(i)); +} + +@system unittest +{ + import std.exception; + + struct S + { + int v; + int* p; + } + int i; + auto s = S(0, &i); + + // structs and unions "own" their members + // pointsTo will answer true if one of the members pointsTo. + assert(!s.doesPointTo(s.v)); //s.v is just v member of s, so not pointed. + assert( s.p.doesPointTo(i)); //i is pointed by s.p. + assert( s .doesPointTo(i)); //which means i is pointed by s itself. + + // Unions will behave exactly the same. Points to will check each "member" + // individually, even if they share the same memory +} + +@system unittest +{ + import std.exception; + + int i; + // trick the compiler when initializing slice + // https://issues.dlang.org/show_bug.cgi?id=18637 + int* p = &i; + int[] slice = [0, 1, 2, 3, 4]; + int[5] arr = [0, 1, 2, 3, 4]; + int*[] slicep = [p]; + int*[1] arrp = [&i]; + + // A slice points to all of its members: + assert( slice.doesPointTo(slice[3])); + assert(!slice[0 .. 2].doesPointTo(slice[3])); // Object 3 is outside of the + // slice [0 .. 2] + + // Note that a slice will not take into account what its members point to. + assert( slicep[0].doesPointTo(i)); + assert(!slicep .doesPointTo(i)); + + // static arrays are objects that own their members, just like structs: + assert(!arr.doesPointTo(arr[0])); // arr[0] is just a member of arr, so not + // pointed. + assert( arrp[0].doesPointTo(i)); // i is pointed by arrp[0]. + assert( arrp .doesPointTo(i)); // which means i is pointed by arrp + // itself. + + // Notice the difference between static and dynamic arrays: + assert(!arr .doesPointTo(arr[0])); + assert( arr[].doesPointTo(arr[0])); + assert( arrp .doesPointTo(i)); + assert(!arrp[].doesPointTo(i)); +} + +@system unittest +{ + import std.exception; + + class C + { + this(int* p){this.p = p;} + int* p; + } + int i; + C a = new C(&i); + C b = a; + + // Classes are a bit particular, as they are treated like simple pointers + // to a class payload. + assert( a.p.doesPointTo(i)); // a.p points to i. + assert(!a .doesPointTo(i)); // Yet a itself does not point i. + + //To check the class payload itself, iterate on its members: + () + { + import std.traits : Fields; + + foreach (index, _; Fields!C) + if (doesPointTo(a.tupleof[index], i)) + return; + assert(0); + }(); + + // To check if a class points a specific payload, a direct memmory check + // can be done: + auto aLoc = cast(ubyte[__traits(classInstanceSize, C)]*) a; + assert(b.doesPointTo(*aLoc)); // b points to where a is pointing +} + +@safe unittest +{ + import std.exception; + + import core.stdc.errno : EAGAIN; + auto ex = new ErrnoException("oh no", EAGAIN); + assert(ex.errno == EAGAIN); +} + +@safe unittest +{ + import std.exception; + + import core.stdc.errno : errno, EAGAIN; + + auto old = errno; + scope(exit) errno = old; + + // fake that errno got set by the callee + errno = EAGAIN; + auto ex = new ErrnoException("oh no"); + assert(ex.errno == EAGAIN); +} + +@safe unittest +{ + import std.exception; + + import std.conv : to; + assert("x".to!int.ifThrown(0) == 0); +} + +@safe unittest +{ + import std.exception; + + import std.conv : ConvException, to; + string s = "true"; + assert(s.to!int.ifThrown(cast(int) s.to!double) + .ifThrown(cast(int) s.to!bool) == 1); + + s = "2.0"; + assert(s.to!int.ifThrown(cast(int) s.to!double) + .ifThrown(cast(int) s.to!bool) == 2); + + // Respond differently to different types of errors + alias orFallback = (lazy a) => a.ifThrown!ConvException("not a number") + .ifThrown!Exception("number too small"); + + assert(orFallback(enforce("x".to!int < 1).to!string) == "not a number"); + assert(orFallback(enforce("2".to!int < 1).to!string) == "number too small"); +} + +@safe unittest +{ + import std.exception; + + // null and new Object have a common type(Object). + static assert(is(typeof(null.ifThrown(new Object())) == Object)); + static assert(is(typeof((new Object()).ifThrown(null)) == Object)); + + // 1 and new Object do not have a common type. + static assert(!__traits(compiles, 1.ifThrown(new Object()))); + static assert(!__traits(compiles, (new Object()).ifThrown(1))); +} + +@system unittest +{ + import std.exception; + + import std.format : format; + assert("%s".format.ifThrown!Exception(e => typeid(e).name) == "std.format.FormatException"); +} + +pure @safe unittest +{ + import std.exception; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map, splitter; + import std.conv : to, ConvException; + + auto s = "12,1337z32,54,2,7,9,1z,6,8"; + + // The next line composition will throw when iterated + // as some elements of the input do not convert to integer + auto r = s.splitter(',').map!(a => to!int(a)); + + // Substitute 0 for cases of ConvException + auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); + assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); +} + +pure @safe unittest +{ + import std.exception; + + import std.algorithm.comparison : equal; + import std.range : retro; + import std.utf : UTFException; + + auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit + + auto handled = str.handle!(UTFException, RangePrimitive.access, + (e, r) => ' '); // Replace invalid code points with spaces + + assert(handled.equal("hello world")); // `front` is handled, + assert(handled.retro.equal("dlrow olleh")); // as well as `back` +} + +pure @safe unittest +{ + import std.exception; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map, splitter; + import std.conv : to, ConvException; + + auto s = "12,1337z32,54,2,7,9,1z,6,8"; + + // The next line composition will throw when iterated + // as some elements of the input do not convert to integer + auto r = s.splitter(',').map!(a => to!int(a)); + + // Substitute 0 for cases of ConvException + auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); + assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); +} + +pure @safe unittest +{ + import std.exception; + + import std.algorithm.comparison : equal; + import std.range : retro; + import std.utf : UTFException; + + auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit + + auto handled = str.handle!(UTFException, RangePrimitive.access, + (e, r) => ' '); // Replace invalid code points with spaces + + assert(handled.equal("hello world")); // `front` is handled, + assert(handled.retro.equal("dlrow olleh")); // as well as `back` +} + +@safe unittest +{ + import std.exception; + + class MeaCulpa: Exception + { + /// + mixin basicExceptionCtors; + } + + try + throw new MeaCulpa("test"); + catch (MeaCulpa e) + { + assert(e.msg == "test"); + assert(e.file == __FILE__); + assert(e.line == __LINE__ - 5); + } +} + +@safe pure nothrow unittest +{ + import std.exception; + + class TestException : Exception { mixin basicExceptionCtors; } + auto e = new Exception("msg"); + auto te1 = new TestException("foo"); + auto te2 = new TestException("foo", e); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_affix_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_affix_allocator.d new file mode 100644 index 0000000000000000000000000000000000000000..6b99e4e51f2358891205d7d89000835da693882f --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_affix_allocator.d @@ -0,0 +1,14 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.affix_allocator; + + import std.experimental.allocator.mallocator : Mallocator; + // One word before and after each allocation. + alias A = AffixAllocator!(Mallocator, size_t, size_t); + auto b = A.instance.allocate(11); + A.instance.prefix(b) = 0xCAFE_BABE; + A.instance.suffix(b) = 0xDEAD_BEEF; + assert(A.instance.prefix(b) == 0xCAFE_BABE + && A.instance.suffix(b) == 0xDEAD_BEEF); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_aligned_block_list.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_aligned_block_list.d new file mode 100644 index 0000000000000000000000000000000000000000..b1d97226142b718f8a8384e4891ac677acc27eec --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_aligned_block_list.d @@ -0,0 +1,139 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.aligned_block_list; + + import std.experimental.allocator.building_blocks.ascending_page_allocator : AscendingPageAllocator; + import std.experimental.allocator.building_blocks.segregator : Segregator; + import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock; + import std.typecons : Ternary; + + /* + In this example we use 'AlignedBlockList' in conjunction with other allocators + in order to create a more complex allocator. + + The 'SuperAllocator' uses a 'Segregator' to distribute allocations to sub-allocators, + based on the requested size. + + Each sub-allocator is represented by an 'AlignedBlockList' of 'BitmappedBlocks'. + Each 'AlignedBlockList' draws memory from a root allocator which in this case is an 'AscendingPageAllocator' + + Such an allocator not only provides good performance, but also a low degree of memory fragmentation. + */ + alias SuperAllocator = Segregator!( + 32, + AlignedBlockList!(BitmappedBlock!32, AscendingPageAllocator*, 1 << 12), + Segregator!( + + 64, + AlignedBlockList!(BitmappedBlock!64, AscendingPageAllocator*, 1 << 12), + Segregator!( + + 128, + AlignedBlockList!(BitmappedBlock!128, AscendingPageAllocator*, 1 << 12), + AscendingPageAllocator* + ))); + + SuperAllocator a; + auto pageAlloc = AscendingPageAllocator(128 * 4096); + + // Set the parent allocator for all the sub allocators + a.allocatorForSize!256 = &pageAlloc; + a.allocatorForSize!128.parent = &pageAlloc; + a.allocatorForSize!64.parent = &pageAlloc; + a.allocatorForSize!32.parent = &pageAlloc; + + enum testNum = 10; + void[][testNum] buf; + + // Allocations of size 32 will go to the first 'AlignedBlockList' + foreach (j; 0 .. testNum) + { + buf[j] = a.allocate(32); + assert(buf[j].length == 32); + + // This is owned by the first 'AlignedBlockList' + assert(a.allocatorForSize!32.owns(buf[j]) == Ternary.yes); + } + + // Free the memory + foreach (j; 0 .. testNum) + assert(a.deallocate(buf[j])); + + // Allocations of size 64 will go to the second 'AlignedBlockList' + foreach (j; 0 .. testNum) + { + buf[j] = a.allocate(64); + assert(buf[j].length == 64); + + // This is owned by the second 'AlignedBlockList' + assert(a.allocatorForSize!64.owns(buf[j]) == Ternary.yes); + } + + // Free the memory + foreach (j; 0 .. testNum) + assert(a.deallocate(buf[j])); + + // Allocations of size 128 will go to the third 'AlignedBlockList' + foreach (j; 0 .. testNum) + { + buf[j] = a.allocate(128); + assert(buf[j].length == 128); + + // This is owned by the third 'AlignedBlockList' + assert(a.allocatorForSize!128.owns(buf[j]) == Ternary.yes); + } + + // Free the memory + foreach (j; 0 .. testNum) + assert(a.deallocate(buf[j])); + + // Allocations which exceed 128, will go to the 'AscendingPageAllocator*' + void[] b = a.allocate(256); + assert(b.length == 256); + a.deallocate(b); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.aligned_block_list; + + import std.experimental.allocator.building_blocks.region : SharedBorrowedRegion; + import std.experimental.allocator.building_blocks.ascending_page_allocator : SharedAscendingPageAllocator; + import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; + import core.thread : ThreadGroup; + + enum numThreads = 8; + enum size = 2048; + enum maxIter = 10; + + /* + In this example we use 'SharedAlignedBlockList' together with + 'SharedBorrowedRegion', in order to create a fast, thread-safe allocator. + */ + alias SuperAllocator = SharedAlignedBlockList!( + SharedBorrowedRegion!(1), + SharedAscendingPageAllocator, + 4096); + + SuperAllocator a; + // The 'SuperAllocator' will draw memory from a 'SharedAscendingPageAllocator' + a.parent = SharedAscendingPageAllocator(4096 * 1024); + + // Launch 'numThreads', each performing allocations + void fun() + { + foreach (i; 0 .. maxIter) + { + void[] b = a.allocate(size); + assert(b.length == size); + } + } + + auto tg = new ThreadGroup; + foreach (i; 0 .. numThreads) + { + tg.create(&fun); + } + tg.joinAll(); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_allocator_list.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_allocator_list.d new file mode 100644 index 0000000000000000000000000000000000000000..e43d9616ddabad15b3efe86d554e1382f69c3bf8 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_allocator_list.d @@ -0,0 +1,45 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.allocator_list; + + import std.algorithm.comparison : max; + import std.experimental.allocator.building_blocks.free_list : ContiguousFreeList; + import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; + import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.segregator : Segregator; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + + // Ouroboros allocator list based upon 4MB regions, fetched directly from + // mmap. All memory is released upon destruction. + alias A1 = AllocatorList!((n) => Region!MmapAllocator(max(n, 1024 * 4096)), + NullAllocator); + + // Allocator list based upon 4MB regions, fetched from the garbage + // collector. All memory is released upon destruction. + alias A2 = AllocatorList!((n) => Region!GCAllocator(max(n, 1024 * 4096))); + + // Ouroboros allocator list based upon 4MB regions, fetched from the garbage + // collector. Memory is left to the collector. + alias A3 = AllocatorList!( + (n) => Region!NullAllocator(new ubyte[max(n, 1024 * 4096)]), + NullAllocator); + + // Allocator list that creates one freelist for all objects + alias A4 = + Segregator!( + 64, AllocatorList!( + (n) => ContiguousFreeList!(NullAllocator, 0, 64)( + cast(ubyte[])(GCAllocator.instance.allocate(4096)))), + GCAllocator); + + A4 a; + auto small = a.allocate(64); + assert(small); + a.deallocate(small); + auto b1 = a.allocate(1024 * 8192); + assert(b1 !is null); // still works due to overdimensioning + b1 = a.allocate(1024 * 10); + assert(b1.length == 1024 * 10); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_ascending_page_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_ascending_page_allocator.d new file mode 100644 index 0000000000000000000000000000000000000000..086714dbd095cfd594c0ed470799497b7e9dd65d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_ascending_page_allocator.d @@ -0,0 +1,52 @@ +@system @nogc nothrow unittest +{ + import std.experimental.allocator.building_blocks.ascending_page_allocator; + + import core.memory : pageSize; + + size_t numPages = 100; + void[] buf; + void[] prevBuf = null; + AscendingPageAllocator a = AscendingPageAllocator(numPages * pageSize); + + foreach (i; 0 .. numPages) + { + // Allocation is rounded up to page size + buf = a.allocate(pageSize - 100); + assert(buf.length == pageSize - 100); + + // Allocations are served at increasing addresses + if (prevBuf) + assert(prevBuf.ptr + pageSize == buf.ptr); + + assert(a.deallocate(buf)); + prevBuf = buf; + } +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.ascending_page_allocator; + + import core.memory : pageSize; + import core.thread : ThreadGroup; + + enum numThreads = 100; + shared SharedAscendingPageAllocator a = SharedAscendingPageAllocator(pageSize * numThreads); + + void fun() + { + void[] b = a.allocate(pageSize); + assert(b.length == pageSize); + + assert(a.deallocate(b)); + } + + auto tg = new ThreadGroup; + foreach (i; 0 .. numThreads) + { + tg.create(&fun); + } + tg.joinAll(); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bitmapped_block.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bitmapped_block.d new file mode 100644 index 0000000000000000000000000000000000000000..e3a3865aa1836f79ef2f0cb9953efa30aa85b906 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bitmapped_block.d @@ -0,0 +1,139 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.bitmapped_block; + + // Create a block allocator on top of a 10KB stack region. + import std.experimental.allocator.building_blocks.region : InSituRegion; + import std.traits : hasMember; + InSituRegion!(10_240, 64) r; + auto a = BitmappedBlock!(64, 64)(cast(ubyte[])(r.allocateAll())); + static assert(hasMember!(InSituRegion!(10_240, 64), "allocateAll")); + const b = a.allocate(100); + assert(b.length == 100); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.bitmapped_block; + + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Flag, Yes; + + enum blockSize = 64; + enum numBlocks = 10; + + // The 'BitmappedBlock' is implicitly instantiated with Yes.multiblock + auto a = BitmappedBlock!(blockSize, 8, Mallocator, Yes.multiblock)(numBlocks * blockSize); + + // Instantiated with Yes.multiblock, can allocate more than one block at a time + void[] buf = a.allocate(2 * blockSize); + assert(buf.length == 2 * blockSize); + assert(a.deallocate(buf)); + + // Can also allocate less than one block + buf = a.allocate(blockSize / 2); + assert(buf.length == blockSize / 2); + + // Expands inside the same block + assert(a.expand(buf, blockSize / 2)); + assert(buf.length == blockSize); + + // If Yes.multiblock, can expand past the size of a single block + assert(a.expand(buf, 3 * blockSize)); + assert(buf.length == 4 * blockSize); + assert(a.deallocate(buf)); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.bitmapped_block; + + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Flag, No; + + enum blockSize = 64; + auto a = BitmappedBlock!(blockSize, 8, Mallocator, No.multiblock)(1024 * blockSize); + + // Since instantiated with No.multiblock, can only allocate at most the block size + void[] buf = a.allocate(blockSize + 1); + assert(buf is null); + + buf = a.allocate(blockSize); + assert(buf.length == blockSize); + assert(a.deallocate(buf)); + + // This is also fine, because it's less than the block size + buf = a.allocate(blockSize / 2); + assert(buf.length == blockSize / 2); + + // Can expand the buffer until its length is at most 64 + assert(a.expand(buf, blockSize / 2)); + assert(buf.length == blockSize); + + // Cannot expand anymore + assert(!a.expand(buf, 1)); + assert(a.deallocate(buf)); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.bitmapped_block; + + import std.experimental.allocator.mallocator : Mallocator; + import std.experimental.allocator.common : platformAlignment; + import std.typecons : Flag, Yes, No; + + // Create 'numThreads' threads, each allocating in parallel a chunk of memory + static void testAlloc(Allocator)(ref Allocator a, size_t allocSize) + { + import core.thread : ThreadGroup; + import std.algorithm.sorting : sort; + import core.internal.spinlock : SpinLock; + + SpinLock lock = SpinLock(SpinLock.Contention.brief); + enum numThreads = 10; + void[][numThreads] buf; + size_t count = 0; + + // Each threads allocates 'allocSize' + void fun() + { + void[] b = a.allocate(allocSize); + assert(b.length == allocSize); + + lock.lock(); + scope(exit) lock.unlock(); + + buf[count] = b; + count++; + } + + auto tg = new ThreadGroup; + foreach (i; 0 .. numThreads) + { + tg.create(&fun); + } + tg.joinAll(); + + // Sorting the allocations made by each thread, we expect the buffers to be + // adjacent inside the SharedBitmappedBlock + sort!((a, b) => a.ptr < b.ptr)(buf[0 .. numThreads]); + foreach (i; 0 .. numThreads - 1) + { + assert(buf[i].ptr + a.goodAllocSize(buf[i].length) <= buf[i + 1].ptr); + } + + // Deallocate everything + foreach (i; 0 .. numThreads) + { + assert(a.deallocate(buf[i])); + } + } + + enum blockSize = 64; + auto alloc1 = SharedBitmappedBlock!(blockSize, platformAlignment, Mallocator, Yes.multiblock)(1024 * 1024); + auto alloc2 = SharedBitmappedBlock!(blockSize, platformAlignment, Mallocator, No.multiblock)(1024 * 1024); + testAlloc(alloc1, 2 * blockSize); + testAlloc(alloc2, blockSize); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bucketizer.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bucketizer.d new file mode 100644 index 0000000000000000000000000000000000000000..b1282b48abdd838154229ef7f90f6c8c553ac17e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bucketizer.d @@ -0,0 +1,23 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.bucketizer; + + import std.algorithm.comparison : max; + import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.common : unbounded; + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Ternary; + Bucketizer!( + FreeList!( + AllocatorList!( + (size_t n) => Region!Mallocator(max(n, 1024 * 1024))), + 0, unbounded), + 65, 512, 64) a; + auto b = a.allocate(400); + assert(b.length == 400); + assert(a.owns(b) == Ternary.yes); + a.deallocate(b); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_fallback_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_fallback_allocator.d new file mode 100644 index 0000000000000000000000000000000000000000..6d89972266ffa25290b71291c86acf7fe5995054 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_fallback_allocator.d @@ -0,0 +1,16 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.fallback_allocator; + + import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.typecons : Ternary; + auto a = fallbackAllocator(Region!GCAllocator(1024), GCAllocator.instance); + auto b1 = a.allocate(1020); + assert(b1.length == 1020); + assert(a.primary.owns(b1) == Ternary.yes); + auto b2 = a.allocate(10); + assert(b2.length == 10); + assert(a.primary.owns(b2) == Ternary.no); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_free_list.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_free_list.d new file mode 100644 index 0000000000000000000000000000000000000000..d15e4e562f8a46dd5dbfbb027f7f3386727b1f23 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_free_list.d @@ -0,0 +1,45 @@ +@safe unittest +{ + import std.experimental.allocator.building_blocks.free_list; + + import std.experimental.allocator.building_blocks.allocator_list + : AllocatorList; + import std.experimental.allocator.gc_allocator : GCAllocator; + + import std.experimental.allocator.common : unbounded; + + alias ScalableFreeList = AllocatorList!((n) => + ContiguousFreeList!(GCAllocator, 0, unbounded)(4096) + ); +} + +@safe unittest +{ + import std.experimental.allocator.building_blocks.free_list; + + import std.experimental.allocator.common : chooseAtRuntime; + import std.experimental.allocator.mallocator : Mallocator; + + shared SharedFreeList!(Mallocator, chooseAtRuntime, chooseAtRuntime) a; + a.setBounds(64, 128); + assert(a.max == 128); + assert(a.min == 64); +} + +@safe unittest +{ + import std.experimental.allocator.building_blocks.free_list; + + import std.experimental.allocator.common : chooseAtRuntime; + import std.experimental.allocator.mallocator : Mallocator; + + shared SharedFreeList!(Mallocator, 50, 50, chooseAtRuntime) a; + // Set the maxSize first so setting the minSize doesn't throw + a.approxMaxLength = 128; + assert(a.approxMaxLength == 128); + a.approxMaxLength = 1024; + assert(a.approxMaxLength == 1024); + a.approxMaxLength = 1; + assert(a.approxMaxLength == 1); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_kernighan_ritchie.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_kernighan_ritchie.d new file mode 100644 index 0000000000000000000000000000000000000000..18e63b33577d82be6257fc925fe0eda0387e892d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_kernighan_ritchie.d @@ -0,0 +1,40 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.kernighan_ritchie; + + import std.experimental.allocator.gc_allocator : GCAllocator; + auto alloc = KRRegion!GCAllocator(1024 * 64); + const b1 = alloc.allocate(2048); + assert(b1.length == 2048); + const b2 = alloc.allocateAll; + assert(b2.length == 1024 * 62); + +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.kernighan_ritchie; + + import std.experimental.allocator.building_blocks.fallback_allocator + : fallbackAllocator; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.typecons : Ternary; + // KRRegion fronting a general-purpose allocator + align(KRRegion!().alignment) ubyte[1024 * 128] buf; + auto alloc = fallbackAllocator(KRRegion!()(buf), GCAllocator.instance); + auto b = alloc.allocate(100); + assert(b.length == 100); + assert((() pure nothrow @safe @nogc => alloc.primary.owns(b))() == Ternary.yes); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.kernighan_ritchie; + + import std.algorithm.comparison : max; + import std.experimental.allocator.building_blocks.allocator_list + : AllocatorList; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + AllocatorList!(n => KRRegion!MmapAllocator(max(n * 16, 1024 * 1024))) alloc; +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_quantizer.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_quantizer.d new file mode 100644 index 0000000000000000000000000000000000000000..deaae0e8c217738448f32e15bfeb7ca3d0e611bb --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_quantizer.d @@ -0,0 +1,23 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.quantizer; + + import std.experimental.allocator.building_blocks.free_tree : FreeTree; + import std.experimental.allocator.gc_allocator : GCAllocator; + + size_t roundUpToMultipleOf(size_t s, uint base) + { + auto rem = s % base; + return rem ? s + base - rem : s; + } + + // Quantize small allocations to a multiple of cache line, large ones to a + // multiple of page size + alias MyAlloc = Quantizer!( + FreeTree!GCAllocator, + n => roundUpToMultipleOf(n, n <= 16_384 ? 64 : 4096)); + MyAlloc alloc; + const buf = alloc.allocate(256); + assert(buf.ptr); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_region.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_region.d new file mode 100644 index 0000000000000000000000000000000000000000..8b4e2be9bc3a92fa90f75846bf74ffc5adde78f0 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_region.d @@ -0,0 +1,90 @@ +@system nothrow unittest +{ + import std.experimental.allocator.building_blocks.region; + + import std.algorithm.comparison : max; + import std.experimental.allocator.building_blocks.allocator_list + : AllocatorList; + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Ternary; + // Create a scalable list of regions. Each gets at least 1MB at a time by + // using malloc. + auto batchAllocator = AllocatorList!( + (size_t n) => Region!Mallocator(max(n, 1024 * 1024)) + )(); + assert(batchAllocator.empty == Ternary.yes); + auto b = batchAllocator.allocate(101); + assert(b.length == 101); + assert(batchAllocator.empty == Ternary.no); + // This will cause a second allocation + b = batchAllocator.allocate(2 * 1024 * 1024); + assert(b.length == 2 * 1024 * 1024); + // Destructor will free the memory +} + +@system nothrow @nogc unittest +{ + import std.experimental.allocator.building_blocks.region; + + import std.typecons : Ternary; + + ubyte[1024] store; + auto myRegion = BorrowedRegion!(1)(store[]); + + assert(myRegion.empty == Ternary.yes); + assert(myRegion.available == store.length); + + void[] b = myRegion.allocate(101); + + assert(b.length == 101); + assert(myRegion.empty == Ternary.no); + assert(myRegion.owns(b) == Ternary.yes); + assert(myRegion.available == store.length - b.length); + + void[] b2 = myRegion.allocate(256); + + // Can only free the most recent allocation + assert(myRegion.deallocate(b) == false); + assert(myRegion.deallocate(b2) == true); + + myRegion.deallocateAll(); + + assert(myRegion.empty == Ternary.yes); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.region; + + // 128KB region, allocated to x86's cache line + InSituRegion!(128 * 1024, 16) r1; + auto a1 = r1.allocate(101); + assert(a1.length == 101); + + // 128KB region, with fallback to the garbage collector. + import std.experimental.allocator.building_blocks.fallback_allocator + : FallbackAllocator; + import std.experimental.allocator.building_blocks.free_list + : FreeList; + import std.experimental.allocator.building_blocks.bitmapped_block + : BitmappedBlock; + import std.experimental.allocator.gc_allocator : GCAllocator; + FallbackAllocator!(InSituRegion!(128 * 1024), GCAllocator) r2; + const a2 = r2.allocate(102); + assert(a2.length == 102); + + // Reap with GC fallback. + InSituRegion!(128 * 1024, 8) tmp3; + FallbackAllocator!(BitmappedBlock!(64, 8), GCAllocator) r3; + r3.primary = BitmappedBlock!(64, 8)(cast(ubyte[]) (tmp3.allocateAll())); + const a3 = r3.allocate(103); + assert(a3.length == 103); + + // Reap/GC with a freelist for small objects up to 16 bytes. + InSituRegion!(128 * 1024, 64) tmp4; + FreeList!(FallbackAllocator!(BitmappedBlock!(64, 64), GCAllocator), 0, 16) r4; + r4.parent.primary = BitmappedBlock!(64, 64)(cast(ubyte[]) (tmp4.allocateAll())); + const a4 = r4.allocate(104); + assert(a4.length == 104); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_scoped_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_scoped_allocator.d new file mode 100644 index 0000000000000000000000000000000000000000..923f621ca62fde05c6837d44aa76d0859761f8d7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_scoped_allocator.d @@ -0,0 +1,13 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.scoped_allocator; + + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Ternary; + ScopedAllocator!Mallocator alloc; + assert(alloc.empty == Ternary.yes); + const b = alloc.allocate(10); + assert(b.length == 10); + assert(alloc.empty == Ternary.no); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_segregator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_segregator.d new file mode 100644 index 0000000000000000000000000000000000000000..49ee6344480aaabe97efa9fd5ad91af6d3c6f97e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_segregator.d @@ -0,0 +1,43 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.segregator; + + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mallocator : Mallocator; + alias A = + Segregator!( + 1024 * 4, + Segregator!( + 128, FreeList!(Mallocator, 0, 128), + GCAllocator), + Segregator!( + 1024 * 1024, Mallocator, + GCAllocator) + ); + A a; + auto b = a.allocate(200); + assert(b.length == 200); + a.deallocate(b); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.segregator; + + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mallocator : Mallocator; + alias A = + Segregator!( + 128, FreeList!(Mallocator, 0, 128), + 1024 * 4, GCAllocator, + 1024 * 1024, Mallocator, + GCAllocator + ); + A a; + auto b = a.allocate(201); + assert(b.length == 201); + a.deallocate(b); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_stats_collector.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_stats_collector.d new file mode 100644 index 0000000000000000000000000000000000000000..1fbed435e3f7a2217fba084ce6de5f11f67fe49d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_stats_collector.d @@ -0,0 +1,33 @@ +@safe unittest +{ + import std.experimental.allocator.building_blocks.stats_collector; + + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.building_blocks.free_list : FreeList; + alias Allocator = StatsCollector!(GCAllocator, Options.bytesUsed); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.stats_collector; + + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + alias Allocator = StatsCollector!(GCAllocator, Options.all, Options.all); + + Allocator alloc; + auto b = alloc.allocate(10); + alloc.reallocate(b, 20); + alloc.deallocate(b); + + import std.file : deleteme, remove; + import std.range : walkLength; + import std.stdio : File; + + auto f = deleteme ~ "-dlang.std.experimental.allocator.stats_collector.txt"; + scope(exit) remove(f); + Allocator.reportPerCallStatistics(File(f, "w")); + alloc.reportStatistics(File(f, "a")); + assert(File(f).byLine.walkLength == 24); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_common.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_common.d new file mode 100644 index 0000000000000000000000000000000000000000..4751c010552a1b175aa8c8ffad78bee62ef808d8 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_common.d @@ -0,0 +1,33 @@ +@safe @nogc nothrow pure unittest +{ + import std.experimental.allocator.common; + + import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; + import std.experimental.allocator.mallocator : Mallocator; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + static assert(isAllocator!NullAllocator); + static assert(isAllocator!Mallocator); + static assert(isAllocator!GCAllocator); + static assert(isAllocator!MmapAllocator); + static assert(!isAllocator!int); +} + +@safe @nogc nothrow pure unittest +{ + import std.experimental.allocator.common; + + import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; + import std.experimental.allocator.mallocator : Mallocator; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + struct S + { + mixin AllocatorState!NullAllocator n; + mixin AllocatorState!GCAllocator g; + mixin AllocatorState!Mallocator m; + mixin AllocatorState!MmapAllocator p; + } + static assert(S.sizeof == 1); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_gc_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_gc_allocator.d new file mode 100644 index 0000000000000000000000000000000000000000..a6615b77aa42a789159bce30a6314fd6b5c1a789 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_gc_allocator.d @@ -0,0 +1,10 @@ +pure @system unittest +{ + import std.experimental.allocator.gc_allocator; + + auto buffer = GCAllocator.instance.allocate(1024 * 1024 * 4); + // deallocate upon scope's end (alternatively: leave it to collection) + scope(exit) GCAllocator.instance.deallocate(buffer); + //... +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_mallocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_mallocator.d new file mode 100644 index 0000000000000000000000000000000000000000..76fb3ec253950e3eec91e2f998bca8fa7562479f --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_mallocator.d @@ -0,0 +1,19 @@ +@nogc @system nothrow unittest +{ + import std.experimental.allocator.mallocator; + + auto buffer = Mallocator.instance.allocate(1024 * 1024 * 4); + scope(exit) Mallocator.instance.deallocate(buffer); + //... +} + +pure @nogc @system nothrow unittest +{ + import std.experimental.allocator.mallocator; + + auto buffer = AlignedMallocator.instance.alignedAllocate(1024 * 1024 * 4, + 128); + scope(exit) AlignedMallocator.instance.deallocate(buffer); + //... +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_package.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_package.d new file mode 100644 index 0000000000000000000000000000000000000000..e19efc54c0d0bd2d8fc0c17e884ca0b5f4310ac4 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_package.d @@ -0,0 +1,263 @@ +@system unittest +{ + import std.experimental.allocator; + + // Install a new allocator that is faster for 128-byte allocations. + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + auto oldAllocator = theAllocator; + scope(exit) theAllocator = oldAllocator; + theAllocator = allocatorObject(FreeList!(GCAllocator, 128)()); + // Use the now changed allocator to allocate an array + const ubyte[] arr = theAllocator.makeArray!ubyte(128); + assert(arr.ptr); + //... +} + +@system unittest +{ + import std.experimental.allocator; + + // Dynamically allocate one integer + const int* p1 = theAllocator.make!int; + // It's implicitly initialized with its .init value + assert(*p1 == 0); + // Dynamically allocate one double, initialize to 42.5 + const double* p2 = theAllocator.make!double(42.5); + assert(*p2 == 42.5); + + // Dynamically allocate a struct + static struct Point + { + int x, y, z; + } + // Use the generated constructor taking field values in order + const Point* p = theAllocator.make!Point(1, 2); + assert(p.x == 1 && p.y == 2 && p.z == 0); + + // Dynamically allocate a class object + static class Customer + { + uint id = uint.max; + this() {} + this(uint id) { this.id = id; } + // ... + } + Customer cust = theAllocator.make!Customer; + assert(cust.id == uint.max); // default initialized + cust = theAllocator.make!Customer(42); + assert(cust.id == 42); + + // explicit passing of outer pointer + static class Outer + { + int x = 3; + class Inner + { + auto getX() { return x; } + } + } + auto outer = theAllocator.make!Outer(); + auto inner = theAllocator.make!(Outer.Inner)(outer); + assert(outer.x == inner.getX); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.algorithm.comparison : equal; + static void test(T)() + { + T[] a = theAllocator.makeArray!T(2); + assert(a.equal([0, 0])); + a = theAllocator.makeArray!T(3, 42); + assert(a.equal([42, 42, 42])); + import std.range : only; + a = theAllocator.makeArray!T(only(42, 43, 44)); + assert(a.equal([42, 43, 44])); + } + test!int(); + test!(shared int)(); + test!(const int)(); + test!(immutable int)(); +} + +@system unittest +{ + import std.experimental.allocator; + + auto arr = theAllocator.makeArray!int([1, 2, 3]); + assert(theAllocator.expandArray(arr, 2)); + assert(arr == [1, 2, 3, 0, 0]); + import std.range : only; + assert(theAllocator.expandArray(arr, only(4, 5))); + assert(arr == [1, 2, 3, 0, 0, 4, 5]); +} + +@system unittest +{ + import std.experimental.allocator; + + int[] a = theAllocator.makeArray!int(100, 42); + assert(a.length == 100); + assert(theAllocator.shrinkArray(a, 98)); + assert(a.length == 2); + assert(a == [42, 42]); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.experimental.allocator.mallocator : Mallocator; + + auto mArray = Mallocator.instance.makeMultidimensionalArray!int(2, 3, 6); + + // deallocate when exiting scope + scope(exit) + { + Mallocator.instance.disposeMultidimensionalArray(mArray); + } + + assert(mArray.length == 2); + foreach (lvl2Array; mArray) + { + assert(lvl2Array.length == 3); + foreach (lvl3Array; lvl2Array) + assert(lvl3Array.length == 6); + } +} + +@system unittest +{ + import std.experimental.allocator; + + struct TestAllocator + { + import std.experimental.allocator.common : platformAlignment; + import std.experimental.allocator.mallocator : Mallocator; + + alias allocator = Mallocator.instance; + + private static struct ByteRange + { + void* ptr; + size_t length; + } + + private ByteRange[] _allocations; + + enum uint alignment = platformAlignment; + + void[] allocate(size_t numBytes) + { + auto ret = allocator.allocate(numBytes); + _allocations ~= ByteRange(ret.ptr, ret.length); + return ret; + } + + bool deallocate(void[] bytes) + { + import std.algorithm.mutation : remove; + import std.algorithm.searching : canFind; + + bool pred(ByteRange other) + { return other.ptr == bytes.ptr && other.length == bytes.length; } + + assert(_allocations.canFind!pred); + + _allocations = _allocations.remove!pred; + return allocator.deallocate(bytes); + } + + ~this() + { + assert(!_allocations.length); + } + } + + TestAllocator allocator; + + auto mArray = allocator.makeMultidimensionalArray!int(2, 3, 5, 6, 7, 2); + + allocator.disposeMultidimensionalArray(mArray); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.experimental.allocator.mallocator : Mallocator; + + RCIAllocator a = allocatorObject(Mallocator.instance); + auto b = a.allocate(100); + assert(b.length == 100); + assert(a.deallocate(b)); + + // The in-situ region must be used by pointer + import std.experimental.allocator.building_blocks.region : InSituRegion; + auto r = InSituRegion!1024(); + a = allocatorObject(&r); + b = a.allocate(200); + assert(b.length == 200); + // In-situ regions can deallocate the last allocation + assert(a.deallocate(b)); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mallocator : Mallocator; + + static assert(!is(ThreadLocal!Mallocator)); + static assert(!is(ThreadLocal!GCAllocator)); + alias Allocator = ThreadLocal!(FreeList!(GCAllocator, 0, 8)); + auto b = Allocator.instance.allocate(5); + static assert(__traits(hasMember, Allocator, "allocate")); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; + import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock; + import std.experimental.allocator.building_blocks.segregator : Segregator; + import std.experimental.allocator.building_blocks.bucketizer : Bucketizer; + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + + /// Define an allocator bound to the built-in GC. + auto alloc = allocatorObject(GCAllocator.instance); + auto b = alloc.allocate(42); + assert(b.length == 42); + assert(alloc.deallocate(b)); + + import std.algorithm.comparison : max; + // Define an elaborate allocator and bind it to the class API. + alias FList = FreeList!(GCAllocator, 0, unbounded); + alias A = ThreadLocal!( + Segregator!( + 8, FreeList!(GCAllocator, 0, 8), + 128, Bucketizer!(FList, 1, 128, 16), + 256, Bucketizer!(FList, 129, 256, 32), + 512, Bucketizer!(FList, 257, 512, 64), + 1024, Bucketizer!(FList, 513, 1024, 128), + 2048, Bucketizer!(FList, 1025, 2048, 256), + 3584, Bucketizer!(FList, 2049, 3584, 512), + 4072 * 1024, AllocatorList!( + (n) => BitmappedBlock!(4096)(cast(ubyte[]) GCAllocator.instance.allocate( + max(n, 4072 * 1024)))), + GCAllocator + ) + ); + + auto alloc2 = allocatorObject(A.instance); + b = alloc2.allocate(101); + assert(alloc2.deallocate(b)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_showcase.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_showcase.d new file mode 100644 index 0000000000000000000000000000000000000000..3cbb19cda3b2601a2e46c2ebc89d00e4a6df653b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_showcase.d @@ -0,0 +1,22 @@ +@system unittest +{ + import std.experimental.allocator.showcase; + + StackFront!4096 a; + auto b = a.allocate(4000); + assert(b.length == 4000); + auto c = a.allocate(4000); + assert(c.length == 4000); + a.deallocate(b); + a.deallocate(c); +} + +@system unittest +{ + import std.experimental.allocator.showcase; + + auto alloc = mmapRegionList(1024 * 1024); + const b = alloc.allocate(100); + assert(b.length == 100); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_typed.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_typed.d new file mode 100644 index 0000000000000000000000000000000000000000..d9f0880144ad8d928e08fafc274401208b8bf927 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_typed.d @@ -0,0 +1,34 @@ +@system unittest +{ + import std.experimental.allocator.typed; + + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mallocator : Mallocator; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + alias MyAllocator = TypedAllocator!(GCAllocator, + AllocFlag.fixedSize | AllocFlag.threadLocal, Mallocator, + AllocFlag.fixedSize | AllocFlag.threadLocal + | AllocFlag.hasNoIndirections, + MmapAllocator, + ); + + MyAllocator a; + auto b = &a.allocatorFor!0(); + static assert(is(typeof(*b) == shared const(GCAllocator))); + enum f1 = AllocFlag.fixedSize | AllocFlag.threadLocal; + auto c = &a.allocatorFor!f1(); + static assert(is(typeof(*c) == Mallocator)); + enum f2 = AllocFlag.fixedSize | AllocFlag.threadLocal; + static assert(is(typeof(a.allocatorFor!f2()) == Mallocator)); + // Partial match + enum f3 = AllocFlag.threadLocal; + static assert(is(typeof(a.allocatorFor!f3()) == Mallocator)); + + int* p = a.make!int; + scope(exit) a.dispose(p); + int[] arr = a.makeArray!int(42); + scope(exit) a.dispose(arr); + assert(a.expandArray(arr, 3)); + assert(a.shrinkArray(arr, 4)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_file.d b/libphobos/testsuite/libphobos.phobos/std_file.d new file mode 100644 index 0000000000000000000000000000000000000000..49626d860dae44b53a9aec7c101a74d5096379cb --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_file.d @@ -0,0 +1,756 @@ +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + assertThrown!FileException("non.existing.file.".readText); +} + +@safe unittest +{ + import std.file; + + import std.utf : byChar; + scope(exit) + { + assert(exists(deleteme)); + remove(deleteme); + } + + std.file.write(deleteme, "1234"); // deleteme is the name of a temporary file + assert(read(deleteme, 2) == "12"); + assert(read(deleteme.byChar) == "1234"); + assert((cast(const(ubyte)[])read(deleteme)).length == 4); +} + +@safe unittest +{ + import std.file; + + write(deleteme, "abc"); // deleteme is the name of a temporary file + scope(exit) remove(deleteme); + string content = readText(deleteme); + assert(content == "abc"); +} + +@safe unittest +{ + import std.file; + + scope(exit) + { + assert(exists(deleteme)); + remove(deleteme); + } + + int[] a = [ 0, 1, 1, 2, 3, 5, 8 ]; + write(deleteme, a); // deleteme is the name of a temporary file + const bytes = read(deleteme); + const fileInts = () @trusted { return cast(int[]) bytes; }(); + assert(fileInts == a); +} + +@safe unittest +{ + import std.file; + + scope(exit) + { + assert(exists(deleteme)); + remove(deleteme); + } + + int[] a = [ 0, 1, 1, 2, 3, 5, 8 ]; + write(deleteme, a); // deleteme is the name of a temporary file + int[] b = [ 13, 21 ]; + append(deleteme, b); + const bytes = read(deleteme); + const fileInts = () @trusted { return cast(int[]) bytes; }(); + assert(fileInts == a ~ b); +} + +@safe unittest +{ + import std.file; + + auto t1 = deleteme, t2 = deleteme~"2"; + scope(exit) foreach (t; [t1, t2]) if (t.exists) t.remove(); + + t1.write("1"); + t1.rename(t2); + assert(t2.readText == "1"); + + t1.write("2"); + t1.rename(t2); + assert(t2.readText == "2"); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + deleteme.write("Hello"); + assert(deleteme.readText == "Hello"); + + deleteme.remove; + assertThrown!FileException(deleteme.readText); +} + +@safe unittest +{ + import std.file; + + scope(exit) deleteme.remove; + + // create a file of size 1 + write(deleteme, "a"); + assert(getSize(deleteme) == 1); + + // create a file of size 3 + write(deleteme, "abc"); + assert(getSize(deleteme) == 3); +} + +@safe unittest +{ + import std.file; + + import std.datetime : abs, SysTime; + + scope(exit) deleteme.remove; + write(deleteme, "a"); + + SysTime accessTime, modificationTime; + + getTimes(deleteme, accessTime, modificationTime); + + import std.datetime : Clock, seconds; + auto currTime = Clock.currTime(); + enum leeway = 5.seconds; + + auto diffAccess = accessTime - currTime; + auto diffModification = modificationTime - currTime; + assert(abs(diffAccess) <= leeway); + assert(abs(diffModification) <= leeway); +} + +@safe unittest +{ + import std.file; + + import std.datetime : DateTime, hnsecs, SysTime; + + scope(exit) deleteme.remove; + write(deleteme, "a"); + + SysTime accessTime = SysTime(DateTime(2010, 10, 4, 0, 0, 30)); + SysTime modificationTime = SysTime(DateTime(2018, 10, 4, 0, 0, 30)); + setTimes(deleteme, accessTime, modificationTime); + + SysTime accessTimeResolved, modificationTimeResolved; + getTimes(deleteme, accessTimeResolved, modificationTimeResolved); + + assert(accessTime == accessTimeResolved); + assert(modificationTime == modificationTimeResolved); +} + +@safe unittest +{ + import std.file; + + import std.datetime : abs, DateTime, hnsecs, SysTime; + scope(exit) deleteme.remove; + + import std.datetime : Clock, seconds; + auto currTime = Clock.currTime(); + enum leeway = 5.seconds; + deleteme.write("bb"); + assert(abs(deleteme.timeLastModified - currTime) <= leeway); +} + +@safe unittest +{ + import std.file; + + import std.datetime : SysTime; + + assert("file.does.not.exist".timeLastModified(SysTime.min) == SysTime.min); + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + scope(exit) source.remove, target.remove; + + source.write("."); + assert(target.timeLastModified(SysTime.min) < source.timeLastModified); + target.write("."); + assert(target.timeLastModified(SysTime.min) >= source.timeLastModified); +} + +@safe unittest +{ + import std.file; + + auto f = deleteme ~ "does.not.exist"; + assert(!f.exists); + + f.write("hello"); + assert(f.exists); + + f.remove; + assert(!f.exists); +} + +@safe unittest +{ + import std.file; + + assert(".".exists); + assert(!"this file does not exist".exists); + deleteme.write("a\n"); + scope(exit) deleteme.remove; + assert(deleteme.exists); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto f = deleteme ~ "file"; + scope(exit) f.remove; + + assert(!f.exists); + assertThrown!FileException(f.getAttributes); + + f.write("."); + auto attributes = f.getAttributes; + assert(!attributes.attrIsDir); + assert(attributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + scope(exit) dir.rmdir; + + assert(!dir.exists); + assertThrown!FileException(dir.getAttributes); + + dir.mkdir; + auto attributes = dir.getAttributes; + assert(attributes.attrIsDir); + assert(!attributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + + assert(!source.exists); + assertThrown!FileException(source.getLinkAttributes); + + // symlinking isn't available on Windows + version (Posix) + { + scope(exit) source.remove, target.remove; + + target.write("target"); + target.symlink(source); + assert(source.readText == "target"); + assert(source.isSymlink); + assert(source.getLinkAttributes.attrIsSymlink); + } +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto f = deleteme ~ "file"; + scope(exit) f.remove; + + assert(!f.exists); + assertThrown!FileException(f.getLinkAttributes); + + f.write("."); + auto attributes = f.getLinkAttributes; + assert(!attributes.attrIsDir); + assert(attributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + scope(exit) dir.rmdir; + + assert(!dir.exists); + assertThrown!FileException(dir.getLinkAttributes); + + dir.mkdir; + auto attributes = dir.getLinkAttributes; + assert(attributes.attrIsDir); + assert(!attributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + import std.conv : octal; + + auto f = deleteme ~ "file"; + version (Posix) + { + scope(exit) f.remove; + + assert(!f.exists); + assertThrown!FileException(f.setAttributes(octal!777)); + + f.write("."); + auto attributes = f.getAttributes; + assert(!attributes.attrIsDir); + assert(attributes.attrIsFile); + + f.setAttributes(octal!777); + attributes = f.getAttributes; + + assert((attributes & 1023) == octal!777); + } +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + import std.conv : octal; + + auto dir = deleteme ~ "dir"; + version (Posix) + { + scope(exit) dir.rmdir; + + assert(!dir.exists); + assertThrown!FileException(dir.setAttributes(octal!777)); + + dir.mkdir; + auto attributes = dir.getAttributes; + assert(attributes.attrIsDir); + assert(!attributes.attrIsFile); + + dir.setAttributes(octal!777); + attributes = dir.getAttributes; + + assert((attributes & 1023) == octal!777); + } +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + auto f = deleteme ~ "f"; + scope(exit) dir.rmdir, f.remove; + + assert(!dir.exists); + assertThrown!FileException(dir.isDir); + + dir.mkdir; + assert(dir.isDir); + + f.write("."); + assert(!f.isDir); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + auto f = deleteme ~ "f"; + scope(exit) dir.rmdir, f.remove; + + assert(!dir.exists); + assertThrown!FileException(dir.getAttributes.attrIsDir); + + dir.mkdir; + assert(dir.isDir); + assert(dir.getAttributes.attrIsDir); + + f.write("."); + assert(!f.isDir); + assert(!f.getAttributes.attrIsDir); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + auto f = deleteme ~ "f"; + scope(exit) dir.rmdir, f.remove; + + dir.mkdir; + assert(!dir.isFile); + + assert(!f.exists); + assertThrown!FileException(f.isFile); + + f.write("."); + assert(f.isFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + auto f = deleteme ~ "f"; + scope(exit) dir.rmdir, f.remove; + + dir.mkdir; + assert(!dir.isFile); + assert(!dir.getAttributes.attrIsFile); + + assert(!f.exists); + assertThrown!FileException(f.getAttributes.attrIsFile); + + f.write("."); + assert(f.isFile); + assert(f.getAttributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + + assert(!source.exists); + assertThrown!FileException(source.isSymlink); + + // symlinking isn't available on Windows + version (Posix) + { + scope(exit) source.remove, target.remove; + + target.write("target"); + target.symlink(source); + assert(source.readText == "target"); + assert(source.isSymlink); + assert(source.getLinkAttributes.attrIsSymlink); + } +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + + assert(!source.exists); + assertThrown!FileException(source.getLinkAttributes.attrIsSymlink); + + // symlinking isn't available on Windows + version (Posix) + { + scope(exit) source.remove, target.remove; + + target.write("target"); + target.symlink(source); + assert(source.readText == "target"); + assert(source.isSymlink); + assert(source.getLinkAttributes.attrIsSymlink); + } +} + +@system unittest +{ + import std.file; + + import std.algorithm.comparison : equal; + import std.algorithm.sorting : sort; + import std.array : array; + import std.path : buildPath; + + auto cwd = getcwd; + auto dir = deleteme ~ "dir"; + dir.mkdir; + scope(exit) cwd.chdir, dir.rmdirRecurse; + + dir.buildPath("a").write("."); + dir.chdir; // step into dir + "b".write("."); + assert(dirEntries(".", SpanMode.shallow).array.sort.equal( + [".".buildPath("a"), ".".buildPath("b")] + )); +} + +@safe unittest +{ + import std.file; + + import std.file : mkdir; + + auto dir = deleteme ~ "dir"; + scope(exit) dir.rmdir; + + dir.mkdir; + assert(dir.exists); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + assertThrown("a/b/c/d/e".mkdir); +} + +@safe unittest +{ + import std.file; + + import std.path : buildPath; + + auto dir = deleteme ~ "dir"; + scope(exit) dir.rmdirRecurse; + + dir.mkdir; + assert(dir.exists); + dir.mkdirRecurse; // does nothing + + // creates all parent directories as needed + auto nested = dir.buildPath("a", "b", "c"); + nested.mkdirRecurse; + assert(nested.exists); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + scope(exit) deleteme.remove; + deleteme.write("a"); + + // cannot make directory as it's already a file + assertThrown!FileException(deleteme.mkdirRecurse); +} + +@safe unittest +{ + import std.file; + + auto dir = deleteme ~ "dir"; + + dir.mkdir; + assert(dir.exists); + dir.rmdir; + assert(!dir.exists); +} + +@safe unittest +{ + import std.file; + + auto s = getcwd(); + assert(s.length); +} + +@safe unittest +{ + import std.file; + + import std.path : isAbsolute; + auto path = thisExePath(); + + assert(path.exists); + assert(path.isAbsolute); + assert(path.isFile); +} + +@safe unittest +{ + import std.file; + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + auto targetNonExistent = deleteme ~ "target2"; + + scope(exit) source.remove, target.remove, targetNonExistent.remove; + + source.write("source"); + target.write("target"); + + assert(target.readText == "target"); + + source.copy(target); + assert(target.readText == "source"); + + source.copy(targetNonExistent); + assert(targetNonExistent.readText == "source"); +} + +@system unittest +{ + import std.file; + + import std.path : buildPath; + + auto dir = deleteme.buildPath("a", "b", "c"); + + dir.mkdirRecurse; + assert(dir.exists); + + deleteme.rmdirRecurse; + assert(!dir.exists); + assert(!deleteme.exists); +} + +@system unittest +{ + import std.file; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + import std.algorithm.sorting : sort; + import std.array : array; + import std.path : buildPath, relativePath; + + auto root = deleteme ~ "root"; + scope(exit) root.rmdirRecurse; + root.mkdir; + + root.buildPath("animals").mkdir; + root.buildPath("animals", "cat").mkdir; + + alias removeRoot = (return scope e) => e.relativePath(root); + + assert(root.dirEntries(SpanMode.depth).map!removeRoot.equal( + [buildPath("animals", "cat"), "animals"])); + + assert(root.dirEntries(SpanMode.breadth).map!removeRoot.equal( + ["animals", buildPath("animals", "cat")])); + + root.buildPath("plants").mkdir; + + assert(root.dirEntries(SpanMode.shallow).array.sort.map!removeRoot.equal( + ["animals", "plants"])); +} + +@safe unittest +{ + import std.file; + + string[] listdir(string pathname) + { + import std.algorithm.iteration : map, filter; + import std.array : array; + import std.path : baseName; + + return dirEntries(pathname, SpanMode.shallow) + .filter!(a => a.isFile) + .map!((return a) => baseName(a.name)) + .array; + } + + // Can be safe only with -preview=dip1000 + @safe void main(string[] args) + { + import std.stdio : writefln; + + string[] files = listdir(args[1]); + writefln("%s", files); + } +} + +@system unittest +{ + import std.file; + + import std.typecons : tuple; + + scope(exit) + { + assert(exists(deleteme)); + remove(deleteme); + } + + write(deleteme, "12 12.25\n345 1.125"); // deleteme is the name of a temporary file + + // Load file; each line is an int followed by comma, whitespace and a + // double. + auto a = slurp!(int, double)(deleteme, "%s %s"); + assert(a.length == 2); + assert(a[0] == tuple(12, 12.25)); + assert(a[1] == tuple(345, 1.125)); +} + +@safe unittest +{ + import std.file; + + import std.ascii : letters; + import std.conv : to; + import std.path : buildPath; + import std.random : randomSample; + import std.utf : byCodeUnit; + + // random id with 20 letters + auto id = letters.byCodeUnit.randomSample(20).to!string; + auto myFile = tempDir.buildPath(id ~ "my_tmp_file"); + scope(exit) myFile.remove; + + myFile.write("hello"); + assert(myFile.readText == "hello"); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto space = getAvailableDiskSpace("."); + assert(space > 0); + + assertThrown!FileException(getAvailableDiskSpace("ThisFileDoesNotExist123123")); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_format_package.d b/libphobos/testsuite/libphobos.phobos/std_format_package.d new file mode 100644 index 0000000000000000000000000000000000000000..2287ff2e3f937af0f08a2ff5067b573e4497ffc9 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_format_package.d @@ -0,0 +1,139 @@ +@safe unittest +{ + import std.format; + + // Easiest way is to use `%s` everywhere: + assert(format("I got %s %s for %s euros.", 30, "eggs", 5.27) == "I got 30 eggs for 5.27 euros."); + + // Other format characters provide more control: + assert(format("I got %b %(%X%) for %f euros.", 30, "eggs", 5.27) == "I got 11110 65676773 for 5.270000 euros."); +} + +@safe unittest +{ + import std.format; + +/* +The trailing end of the sub-format string following the specifier for +each item is interpreted as the array delimiter, and is therefore +omitted following the last array item: + */ + assert(format("My items are %(%s %).", [1,2,3]) == "My items are 1 2 3."); + assert(format("My items are %(%s, %).", [1,2,3]) == "My items are 1, 2, 3."); + +/* +The "%|" delimiter specifier may be used to indicate where the +delimiter begins, so that the portion of the format string prior to +it will be retained in the last array element: + */ + assert(format("My items are %(-%s-%|, %).", [1,2,3]) == "My items are -1-, -2-, -3-."); + +/* +These compound format specifiers may be nested in the case of a +nested array argument: + */ + auto mat = [[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]; + + assert(format("%(%(%d %) - %)", mat), "1 2 3 - 4 5 6 - 7 8 9"); + assert(format("[%(%(%d %) - %)]", mat), "[1 2 3 - 4 5 6 - 7 8 9]"); + assert(format("[%([%(%d %)]%| - %)]", mat), "[1 2 3] - [4 5 6] - [7 8 9]"); + +/* +Strings and characters are escaped automatically inside compound +format specifiers. To avoid this behavior, use "%-(" instead of "%(": + */ + assert(format("My friends are %s.", ["John", "Nancy"]) == `My friends are ["John", "Nancy"].`); + assert(format("My friends are %(%s, %).", ["John", "Nancy"]) == `My friends are "John", "Nancy".`); + assert(format("My friends are %-(%s, %).", ["John", "Nancy"]) == `My friends are John, Nancy.`); +} + +@safe unittest +{ + import std.format; + + // Flags can be used to influence to outcome: + assert(format("%g != %+#g", 3.14, 3.14) == "3.14 != +3.14000"); + + // Width and precision help to arrange the formatted result: + assert(format(">%10.2f<", 1234.56789) == "> 1234.57<"); + + // Numbers can be grouped: + assert(format("%,4d", int.max) == "21,4748,3647"); + + // It's possible to specify the position of an argument: + assert(format("%3$s %1$s", 3, 17, 5) == "5 3"); +} + +@safe unittest +{ + import std.format; + + // Width as argument + assert(format(">%*s<", 10, "abc") == "> abc<"); + + // Precision as argument + assert(format(">%.*f<", 5, 123.2) == ">123.20000<"); + + // Grouping as argument + assert(format("%,*d", 1, int.max) == "2,1,4,7,4,8,3,6,4,7"); + + // Grouping separator as argument + assert(format("%,3?d", '_', int.max) == "2_147_483_647"); + + // All at once + assert(format("%*.*,*?d", 20, 15, 6, '/', int.max) == " 000/002147/483647"); +} + +@safe unittest +{ + import std.format; + + import std.exception : assertThrown; + + assertThrown!FormatException(format("%d", "foo")); +} + +@safe pure unittest +{ + import std.format; + + assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples."); + + assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %"); +} + +@safe pure unittest +{ + import std.format; + + auto s = format!"%s is %s"("Pi", 3.14); + assert(s == "Pi is 3.14"); + + // This line doesn't compile, because 3.14 cannot be formatted with %d: + // s = format!"%s is %d"("Pi", 3.14); +} + +@safe pure unittest +{ + import std.format; + + char[20] buf; + assert(sformat(buf[], "Here are %d %s.", 3, "apples") == "Here are 3 apples."); + + assert(buf[].sformat("Increase: %7.2f %%", 17.4285) == "Increase: 17.43 %"); +} + +@safe pure unittest +{ + import std.format; + + char[20] buf; + + assert(sformat!"Here are %d %s."(buf[], 3, "apples") == "Here are 3 apples."); + + // This line doesn't compile, because 3.14 cannot be formatted with %d: + // writeln(sformat!"Here are %d %s."(buf[], 3.14, "apples")); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_format_read.d b/libphobos/testsuite/libphobos.phobos/std_format_read.d new file mode 100644 index 0000000000000000000000000000000000000000..0beb307efb5de0c95a082e66cd52aaeba3726175 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_format_read.d @@ -0,0 +1,275 @@ +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + auto str = "false"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!bool(spec) == false); + + str = "1"; + spec = singleSpec("%d"); + assert(str.unformatValue!bool(spec) == true); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + auto str = "null"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!(typeof(null))(spec) == null); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + // signed decimal values + auto str = "123"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!int(spec) == 123); + + // hexadecimal values + str = "ABC"; + spec = singleSpec("%X"); + assert(str.unformatValue!int(spec) == 2748); + + // octal values + str = "11610"; + spec = singleSpec("%o"); + assert(str.unformatValue!int(spec) == 5000); + + // raw read, depends on endianess + str = "\x75\x01"; + spec = singleSpec("%r"); + auto result = str.unformatValue!short(spec); + assert(result == 373 /* little endian */ || result == 29953 /* big endian */ ); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + import std.math.operations : isClose; + + // natural notation + auto str = "123.456"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!double(spec).isClose(123.456)); + + // scientific notation + str = "1e17"; + spec = singleSpec("%e"); + assert(str.unformatValue!double(spec).isClose(1e17)); + + // raw read, depends on endianess + str = "\x40\x00\x00\xBF"; + spec = singleSpec("%r"); + auto result = str.unformatValue!float(spec); + assert(isClose(result, -0.5) /* little endian */ || isClose(result, 2.0) /* big endian */ ); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + // only the first character is read + auto str = "abc"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!char(spec) == 'a'); + + // using a numerical format character treats the read number as unicode code point + str = "65"; + spec = singleSpec("%d"); + assert(str.unformatValue!char(spec) == 'A'); + + str = "41"; + spec = singleSpec("%x"); + assert(str.unformatValue!char(spec) == 'A'); + + str = "10003"; + spec = singleSpec("%d"); + assert(str.unformatValue!dchar(spec) == '✓'); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + // string value + string str = "aaa"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!(dchar[])(spec) == "aaa"d); + + // fixed size array with characters + str = "aaa"; + spec = singleSpec("%s"); + dchar[3] ret = ['a', 'a', 'a']; + assert(str.unformatValue!(dchar[3])(spec) == ret); + + // dynamic array + str = "[1, 2, 3, 4]"; + spec = singleSpec("%s"); + assert(str.unformatValue!(int[])(spec) == [1, 2, 3, 4]); + + // fixed size array with integers + str = "[1, 2, 3, 4]"; + spec = singleSpec("%s"); + int[4] ret2 = [1, 2, 3, 4]; + assert(str.unformatValue!(int[4])(spec) == ret2); + + // compound specifiers can be used for more control + str = "1,2,3"; + spec = singleSpec("%(%s,%)"); + assert(str.unformatValue!(int[])(spec) == [1, 2, 3]); + + str = "cool"; + spec = singleSpec("%(%c%)"); + assert(str.unformatValue!(char[])(spec) == ['c', 'o', 'o', 'l']); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + // as single value + auto str = `["one": 1, "two": 2]`; + auto spec = singleSpec("%s"); + assert(str.unformatValue!(int[string])(spec) == ["one": 1, "two": 2]); + + // with compound specifier for more control + str = "1/1, 2/4, 3/9"; + spec = singleSpec("%(%d/%d%|, %)"); + assert(str.unformatValue!(int[int])(spec) == [1: 1, 2: 4, 3: 9]); +} + +@safe pure unittest +{ + import std.format.read; + + string object; + char cmp; + int value; + + assert(formattedRead("angle < 36", "%s %c %d", object, cmp, value) == 3); + assert(object == "angle"); + assert(cmp == '<'); + assert(value == 36); + + // reading may end early: + assert(formattedRead("length >", "%s %c %d", object, cmp, value) == 2); + assert(object == "length"); + assert(cmp == '>'); + // value is not changed: + assert(value == 36); +} + +@safe pure unittest +{ + import std.format.read; + + string a; + int b; + double c; + + assert("hello!124:34.5".formattedRead!"%s!%s:%s"(a, b, c) == 3); + assert(a == "hello"); + assert(b == 124); + assert(c == 34.5); +} + +@safe pure unittest +{ + import std.format.read; + + string item; + double amount; + + assert("orange: (12%) 15.25".formattedRead("%s: (%*d%%) %f", item, amount) == 2); + assert(item == "orange"); + assert(amount == 15.25); + + // can also be used with tuples + import std.typecons : Tuple; + + Tuple!(int, float) t; + char[] line = "1 7643 2.125".dup; + formattedRead(line, "%s %*u %s", t); + assert(t[0] == 1 && t[1] == 2.125); +} + +@safe pure unittest +{ + import std.format.read; + + import std.exception : assertThrown; + import std.format : FormatException; + import std.typecons : tuple; + + auto complete = "hello!34.5:124".formattedRead!(string, double, int)("%s!%s:%s"); + assert(complete == tuple("hello", 34.5, 124)); + + // reading ends early + assertThrown!FormatException("hello!34.5:".formattedRead!(string, double, int)("%s!%s:%s")); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format : FormatException; + import std.typecons : tuple; + + auto result = "orange: (12%) 15.25".formattedRead!(string, double)("%s: (%*d%%) %f"); + assert(result == tuple("orange", 15.25)); +} + +@safe pure unittest +{ + import std.format.read; + + import std.exception : assertThrown; + import std.format : FormatException; + import std.typecons : tuple; + + auto expected = tuple("hello", 124, 34.5); + auto result = "hello!124:34.5".formattedRead!("%s!%s:%s", string, int, double); + assert(result == expected); + + assertThrown!FormatException("hello!34.5:".formattedRead!("%s!%s:%s", string, double, int)); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format : FormatException; + import std.typecons : tuple; + + static assert(!__traits(compiles, "orange: (12%) 15.25".formattedRead!("%s: (%*d%%) %f", string, double))); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + string s = "42"; + auto spec = singleSpec("%s"); + assert(unformatValue!int(s, spec) == 42); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_format_spec.d b/libphobos/testsuite/libphobos.phobos/std_format_spec.d new file mode 100644 index 0000000000000000000000000000000000000000..a24c4779b8b5c1ec5c35e13d834ed92d068762fe --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_format_spec.d @@ -0,0 +1,43 @@ +@safe pure unittest +{ + import std.format.spec; + + import std.array : appender; + + auto a = appender!(string)(); + auto fmt = "Number: %6.4e\nString: %s"; + auto f = FormatSpec!char(fmt); + + assert(f.writeUpToNextSpec(a)); + + assert(a.data == "Number: "); + assert(f.trailing == "\nString: %s"); + assert(f.spec == 'e'); + assert(f.width == 6); + assert(f.precision == 4); + + assert(f.writeUpToNextSpec(a)); + + assert(a.data == "Number: \nString: "); + assert(f.trailing == ""); + assert(f.spec == 's'); + + assert(!f.writeUpToNextSpec(a)); + + assert(a.data == "Number: \nString: "); +} + +@safe pure unittest +{ + import std.format.spec; + + import std.array : appender; + import std.format.write : formatValue; + + auto spec = singleSpec("%10.3e"); + auto writer = appender!string(); + writer.formatValue(42.0, spec); + + assert(writer.data == " 4.200e+01"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_format_write.d b/libphobos/testsuite/libphobos.phobos/std_format_write.d new file mode 100644 index 0000000000000000000000000000000000000000..aacd7fb0990c187477537d7f582b125e0e675c2a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_format_write.d @@ -0,0 +1,421 @@ +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + formatValue(w1, true, spec1); + + assert(w1.data == "true"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%#x"); + formatValue(w2, true, spec2); + + assert(w2.data == "0x1"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w = appender!string(); + auto spec = singleSpec("%s"); + formatValue(w, null, spec); + + assert(w.data == "null"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%d"); + formatValue(w1, -1337, spec1); + + assert(w1.data == "-1337"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%x"); + formatValue(w2, -1337, spec2); + + assert(w2.data == "fffffac7"); +} + +@safe unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%.3f"); + formatValue(w1, 1337.7779, spec1); + + assert(w1.data == "1337.778"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%.3e"); + formatValue(w2, 1337.7779, spec2); + + assert(w2.data == "1.338e+03"); + + auto w3 = appender!string(); + auto spec3 = singleSpec("%.3g"); + formatValue(w3, 1337.7779, spec3); + + assert(w3.data == "1.34e+03"); + + auto w4 = appender!string(); + auto spec4 = singleSpec("%.3a"); + formatValue(w4, 1337.7779, spec4); + + assert(w4.data == "0x1.4e7p+10"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%c"); + formatValue(w1, 'ì', spec1); + + assert(w1.data == "ì"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%#x"); + formatValue(w2, 'ì', spec2); + + assert(w2.data == "0xec"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + formatValue(w1, "hello", spec1); + + assert(w1.data == "hello"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%(%#x%|/%)"); + formatValue(w2, "hello", spec2); + + assert(w2.data == "0x68/0x65/0x6c/0x6c/0x6f"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w = appender!string(); + auto spec = singleSpec("%s"); + int[2] two = [1, 2]; + formatValue(w, two, spec); + + assert(w.data == "[1, 2]"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + auto two = [1, 2]; + formatValue(w1, two, spec1); + + assert(w1.data == "[1, 2]"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%(%g%|, %)"); + auto consts = [3.1415926, 299792458, 6.67430e-11]; + formatValue(w2, consts, spec2); + + assert(w2.data == "3.14159, 2.99792e+08, 6.6743e-11"); + + // void[] is treated like ubyte[] + auto w3 = appender!string(); + auto spec3 = singleSpec("%s"); + void[] val = cast(void[]) cast(ubyte[])[1, 2, 3]; + formatValue(w3, val, spec3); + + assert(w3.data == "[1, 2, 3]"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto aa = [10:17.5, 20:9.99]; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + formatValue(w1, aa, spec1); + + assert(w1.data == "[10:17.5, 20:9.99]" || w1.data == "[20:9.99, 10:17.5]"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%(%x = %.0e%| # %)"); + formatValue(w2, aa, spec2); + + assert(w2.data == "a = 2e+01 # 14 = 1e+01" || w2.data == "14 = 1e+01 # a = 2e+01"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + enum A { first, second, third } + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + formatValue(w1, A.second, spec1); + + assert(w1.data == "second"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%d"); + formatValue(w2, A.second, spec2); + + assert(w2.data == "1"); + + // values of an enum that have no name are formatted with %s using a cast + A a = A.third; + a++; + + auto w3 = appender!string(); + auto spec3 = singleSpec("%s"); + formatValue(w3, a, spec3); + + assert(w3.data == "cast(A)3"); +} + +@safe unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : FormatSpec, singleSpec; + + // Using a `toString` with a writer + static struct Point1 + { + import std.range.primitives : isOutputRange, put; + + int x, y; + + void toString(W)(ref W writer, scope const ref FormatSpec!char f) + if (isOutputRange!(W, char)) + { + put(writer, "("); + formatValue(writer, x, f); + put(writer, ","); + formatValue(writer, y, f); + put(writer, ")"); + } + } + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + auto p1 = Point1(16, 11); + + formatValue(w1, p1, spec1); + assert(w1.data == "(16,11)"); + + // Using a `toString` with a sink + static struct Point2 + { + int x, y; + + void toString(scope void delegate(scope const(char)[]) @safe sink, + scope const FormatSpec!char fmt) const + { + sink("("); + sink.formatValue(x, fmt); + sink(","); + sink.formatValue(y, fmt); + sink(")"); + } + } + + auto w2 = appender!string(); + auto spec2 = singleSpec("%03d"); + auto p2 = Point2(16,11); + + formatValue(w2, p2, spec2); + assert(w2.data == "(016,011)"); + + // Using `string toString()` + static struct Point3 + { + int x, y; + + string toString() + { + import std.conv : to; + + return "(" ~ to!string(x) ~ "," ~ to!string(y) ~ ")"; + } + } + + auto w3 = appender!string(); + auto spec3 = singleSpec("%s"); // has to be %s + auto p3 = Point3(16,11); + + formatValue(w3, p3, spec3); + assert(w3.data == "(16,11)"); + + // without `toString` + static struct Point4 + { + int x, y; + } + + auto w4 = appender!string(); + auto spec4 = singleSpec("%s"); // has to be %s + auto p4 = Point4(16,11); + + formatValue(w4, p4, spec3); + assert(w4.data == "Point4(16, 11)"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + auto p1 = () @trusted { return cast(void*) 0xFFEECCAA; } (); + formatValue(w1, p1, spec1); + + assert(w1.data == "FFEECCAA"); + + // null pointers are printed as `"null"` when used with `%s` and as hexadecimal integer else + auto w2 = appender!string(); + auto spec2 = singleSpec("%s"); + auto p2 = () @trusted { return cast(void*) 0x00000000; } (); + formatValue(w2, p2, spec2); + + assert(w2.data == "null"); + + auto w3 = appender!string(); + auto spec3 = singleSpec("%x"); + formatValue(w3, p2, spec3); + + assert(w3.data == "0"); +} + +@safe unittest +{ + import std.format.write; + + import core.simd; // cannot be selective, because float4 might not be defined + import std.array : appender; + import std.format.spec : singleSpec; + + auto w = appender!string(); + auto spec = singleSpec("%s"); + + static if (is(float4)) + { + version (X86) {} + else + { + float4 f4; + f4.array[0] = 1; + f4.array[1] = 2; + f4.array[2] = 3; + f4.array[3] = 4; + + formatValue(w, f4, spec); + assert(w.data == "[1, 2, 3, 4]"); + } + } +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + + auto writer1 = appender!string(); + formattedWrite(writer1, "%s is the ultimate %s.", 42, "answer"); + assert(writer1[] == "42 is the ultimate answer."); + + auto writer2 = appender!string(); + formattedWrite(writer2, "Increase: %7.2f %%", 17.4285); + assert(writer2[] == "Increase: 17.43 %"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + + auto writer = appender!string(); + writer.formattedWrite!"%d is the ultimate %s."(42, "answer"); + assert(writer[] == "42 is the ultimate answer."); + + // This line doesn't compile, because 3.14 cannot be formatted with %d: + // writer.formattedWrite!"%d is the ultimate %s."(3.14, "answer"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto writer = appender!string(); + auto spec = singleSpec("%08b"); + writer.formatValue(42, spec); + assert(writer.data == "00101010"); + + spec = singleSpec("%2s"); + writer.formatValue('=', spec); + assert(writer.data == "00101010 ="); + + spec = singleSpec("%+14.6e"); + writer.formatValue(42.0, spec); + assert(writer.data == "00101010 = +4.200000e+01"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_functional.d b/libphobos/testsuite/libphobos.phobos/std_functional.d new file mode 100644 index 0000000000000000000000000000000000000000..3bfab45658ebe430520554fa3eb8440865007faa --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_functional.d @@ -0,0 +1,360 @@ +@safe unittest +{ + import std.functional; + + // Strings are compiled into functions: + alias isEven = unaryFun!("(a & 1) == 0"); + assert(isEven(2) && !isEven(1)); +} + +@safe unittest +{ + import std.functional; + + alias less = binaryFun!("a < b"); + assert(less(1, 2) && !less(2, 1)); + alias greater = binaryFun!("a > b"); + assert(!greater("1", "2") && greater("2", "1")); +} + +pure @safe @nogc nothrow unittest +{ + import std.functional; + + assert(lessThan(2, 3)); + assert(lessThan(2U, 3U)); + assert(lessThan(2, 3.0)); + assert(lessThan(-2, 3U)); + assert(lessThan(2, 3U)); + assert(!lessThan(3U, -2)); + assert(!lessThan(3U, 2)); + assert(!lessThan(0, 0)); + assert(!lessThan(0U, 0)); + assert(!lessThan(0, 0U)); +} + +@safe unittest +{ + import std.functional; + + assert(!greaterThan(2, 3)); + assert(!greaterThan(2U, 3U)); + assert(!greaterThan(2, 3.0)); + assert(!greaterThan(-2, 3U)); + assert(!greaterThan(2, 3U)); + assert(greaterThan(3U, -2)); + assert(greaterThan(3U, 2)); + assert(!greaterThan(0, 0)); + assert(!greaterThan(0U, 0)); + assert(!greaterThan(0, 0U)); +} + +@safe unittest +{ + import std.functional; + + assert(equalTo(0U, 0)); + assert(equalTo(0, 0U)); + assert(!equalTo(-1, ~0U)); +} + +@safe unittest +{ + import std.functional; + + alias gt = reverseArgs!(binaryFun!("a < b")); + assert(gt(2, 1) && !gt(1, 1)); +} + +@safe unittest +{ + import std.functional; + + int x = 42; + bool xyz(int a, int b) { return a * x < b / x; } + auto foo = &xyz; + foo(4, 5); + alias zyx = reverseArgs!(foo); + assert(zyx(5, 4) == foo(4, 5)); +} + +@safe unittest +{ + import std.functional; + + alias gt = reverseArgs!(binaryFun!("a < b")); + assert(gt(2, 1) && !gt(1, 1)); + int x = 42; + bool xyz(int a, int b) { return a * x < b / x; } + auto foo = &xyz; + foo(4, 5); + alias zyx = reverseArgs!(foo); + assert(zyx(5, 4) == foo(4, 5)); +} + +@safe unittest +{ + import std.functional; + + int abc(int a, int b, int c) { return a * b + c; } + alias cba = reverseArgs!abc; + assert(abc(91, 17, 32) == cba(32, 17, 91)); +} + +@safe unittest +{ + import std.functional; + + int a(int a) { return a * 2; } + alias _a = reverseArgs!a; + assert(a(2) == _a(2)); +} + +@safe unittest +{ + import std.functional; + + int b() { return 4; } + alias _b = reverseArgs!b; + assert(b() == _b()); +} + +@safe unittest +{ + import std.functional; + + import std.algorithm.searching : find; + import std.uni : isWhite; + string a = " Hello, world!"; + assert(find!(not!isWhite)(a) == "Hello, world!"); +} + +@safe unittest +{ + import std.functional; + + int fun(int a, int b) { return a + b; } + alias fun5 = partial!(fun, 5); + assert(fun5(6) == 11); + // Note that in most cases you'd use an alias instead of a value + // assignment. Using an alias allows you to partially evaluate template + // functions without committing to a particular type of the function. +} + +@safe unittest +{ + import std.functional; + + // Overloads are resolved when the partially applied function is called + // with the remaining arguments. + struct S + { + static char fun(int i, string s) { return s[i]; } + static int fun(int a, int b) { return a * b; } + } + alias fun3 = partial!(S.fun, 3); + assert(fun3("hello") == 'l'); + assert(fun3(10) == 30); +} + +pure @safe @nogc nothrow unittest +{ + import std.functional; + + int f(int x, int y, int z) + { + return x + y + z; + } + auto cf = curry!f; + auto cf1 = cf(1); + auto cf2 = cf(2); + + assert(cf1(2)(3) == f(1, 2, 3)); + assert(cf2(2)(3) == f(2, 2, 3)); +} + +pure @safe @nogc nothrow unittest +{ + import std.functional; + + //works with callable structs too + struct S + { + int w; + int opCall(int x, int y, int z) + { + return w + x + y + z; + } + } + + S s; + s.w = 5; + + auto cs = curry(s); + auto cs1 = cs(1); + auto cs2 = cs(2); + + assert(cs1(2)(3) == s(1, 2, 3)); + assert(cs1(2)(3) == (1 + 2 + 3 + 5)); + assert(cs2(2)(3) ==s(2, 2, 3)); +} + +@safe unittest +{ + import std.functional; + + import std.typecons : Tuple; + static bool f1(int a) { return a != 0; } + static int f2(int a) { return a / 2; } + auto x = adjoin!(f1, f2)(5); + assert(is(typeof(x) == Tuple!(bool, int))); + assert(x[0] == true && x[1] == 2); +} + +@safe unittest +{ + import std.functional; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + import std.array : split; + import std.conv : to; + + // First split a string in whitespace-separated tokens and then + // convert each token into an integer + assert(compose!(map!(to!(int)), split)("1 2 3").equal([1, 2, 3])); +} + +@safe unittest +{ + import std.functional; + + import std.conv : to; + string foo(int a) { return to!(string)(a); } + int bar(string a) { return to!(int)(a) + 1; } + double baz(int a) { return a + 0.5; } + assert(compose!(baz, bar, foo)(1) == 2.5); + assert(pipe!(foo, bar, baz)(1) == 2.5); + + assert(compose!(baz, `to!(int)(a) + 1`, foo)(1) == 2.5); + assert(compose!(baz, bar)("1"[]) == 2.5); + + assert(compose!(baz, bar)("1") == 2.5); + + assert(compose!(`a + 0.5`, `to!(int)(a) + 1`, foo)(1) == 2.5); +} + +@safe nothrow unittest +{ + import std.functional; + + ulong fib(ulong n) @safe nothrow + { + return n < 2 ? n : memoize!fib(n - 2) + memoize!fib(n - 1); + } + assert(fib(10) == 55); +} + +@safe unittest +{ + import std.functional; + + ulong fact(ulong n) @safe + { + return n < 2 ? 1 : n * memoize!fact(n - 1); + } + assert(fact(10) == 3628800); +} + +@safe unittest +{ + import std.functional; + + ulong factImpl(ulong n) @safe + { + return n < 2 ? 1 : n * factImpl(n - 1); + } + alias fact = memoize!factImpl; + assert(fact(10) == 3628800); +} + +@system unittest +{ + import std.functional; + + ulong fact(ulong n) + { + // Memoize no more than 8 values + return n < 2 ? 1 : n * memoize!(fact, 8)(n - 1); + } + assert(fact(8) == 40320); + // using more entries than maxSize will overwrite existing entries + assert(fact(10) == 3628800); +} + +@safe unittest +{ + import std.functional; + + static int inc(ref uint num) { + num++; + return 8675309; + } + + uint myNum = 0; + auto incMyNumDel = toDelegate(&inc); + auto returnVal = incMyNumDel(myNum); + assert(myNum == 1); +} + +@safe unittest +{ + import std.functional; + + import std.typecons : tuple; + + auto name = tuple("John", "Doe"); + string full = name.bind!((first, last) => first ~ " " ~ last); + assert(full == "John Doe"); +} + +@safe unittest +{ + import std.functional; + + import std.algorithm.comparison : min, max; + + struct Pair + { + int a; + int b; + } + + auto p = Pair(123, 456); + assert(p.bind!min == 123); // min(p.a, p.b) + assert(p.bind!max == 456); // max(p.a, p.b) +} + +@safe unittest +{ + import std.functional; + + import std.algorithm.iteration : map, filter; + import std.algorithm.comparison : equal; + import std.typecons : tuple; + + auto ages = [ + tuple("Alice", 35), + tuple("Bob", 64), + tuple("Carol", 21), + tuple("David", 39), + tuple("Eve", 50) + ]; + + auto overForty = ages + .filter!(bind!((name, age) => age > 40)) + .map!(bind!((name, age) => name)); + + assert(overForty.equal(["Bob", "Eve"])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_getopt.d b/libphobos/testsuite/libphobos.phobos/std_getopt.d new file mode 100644 index 0000000000000000000000000000000000000000..12d81f3878099a686a5b0297787e0022ffe6bb9e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_getopt.d @@ -0,0 +1,18 @@ +@safe unittest +{ + import std.getopt; + + auto args = ["prog", "--foo", "-b"]; + + bool foo; + bool bar; + auto rslt = getopt(args, "foo|f", "Some information about foo.", &foo, "bar|b", + "Some help message about bar.", &bar); + + if (rslt.helpWanted) + { + defaultGetoptPrinter("Some information about the program.", + rslt.options); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_int128.d b/libphobos/testsuite/libphobos.phobos/std_int128.d new file mode 100644 index 0000000000000000000000000000000000000000..71548fd124a7bb13f3d72dfa818c3cd808590f19 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_int128.d @@ -0,0 +1,128 @@ +@safe unittest +{ + import std.int128; + + const Int128 a = Int128(0xffff_ffff_ffff_ffffL, 0x0123_4567_89ab_cdefL); + assert(cast(long) a == 0x0123_4567_89ab_cdefL); + assert(cast(int) a == 0x89ab_cdef); + assert(cast(byte) a == cast(byte) 0xef); + +} + +@safe unittest +{ + import std.int128; + + const Int128 a = Int128(-1L << 60); + assert(cast(double) a == -(2.0 ^^ 60)); + assert(cast(double) (a * a) == 2.0 ^^ 120); + +} + +@safe unittest +{ + import std.int128; + + import std.format : format; + + assert(format("%s", Int128.max) == "170141183460469231731687303715884105727"); + assert(format("%s", Int128.min) == "-170141183460469231731687303715884105728"); + assert(format("%x", Int128.max) == "7fffffffffffffffffffffffffffffff"); + assert(format("%X", Int128.max) == "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + assert(format("%032X", Int128(123L)) == "0000000000000000000000000000007B"); + assert(format("%+ 40d", Int128(123L)) == " +123"); + assert(format("%+-40d", Int128(123L)) == "+123 "); + +} + +@safe unittest +{ + import std.int128; + + import std.conv : to; + + assert(to!wstring(Int128.max) == "170141183460469231731687303715884105727"w); + assert(to!dstring(Int128.max) == "170141183460469231731687303715884105727"d); + +} + +@safe pure nothrow @nogc unittest +{ + import std.int128; + + Int128 c = Int128(5, 6); + assert(c == c); + assert(c == +c); + assert(c == - -c); + assert(~c == Int128(~5, ~6)); + ++c; + assert(c == Int128(5, 7)); + assert(--c == Int128(5, 6)); + assert(!!c); + assert(!Int128()); + + assert(c + Int128(10, 20) == Int128(15, 26)); + assert(c - Int128(1, 2) == Int128(4, 4)); + assert(c * Int128(100, 2) == Int128(610, 12)); + assert(c / Int128(3, 2) == Int128(0, 1)); + assert(c % Int128(3, 2) == Int128(2, 4)); + assert((c & Int128(3, 2)) == Int128(1, 2)); + assert((c | Int128(3, 2)) == Int128(7, 6)); + assert((c ^ Int128(3, 2)) == Int128(6, 4)); + + assert(c + 15 == Int128(5, 21)); + assert(c - 15 == Int128(4, -9)); + assert(c * 15 == Int128(75, 90)); + assert(c / 15 == Int128(0, 6148914691236517205)); + assert(c % 15 == Int128(0, 11)); + assert((c & 15) == Int128(0, 6)); + assert((c | 15) == Int128(5, 15)); + assert((c ^ 15) == Int128(5, 9)); + + assert(15 + c == Int128(5, 21)); + assert(15 - c == Int128(-5, 9)); + assert(15 * c == Int128(75, 90)); + assert(15 / c == Int128(0, 0)); + assert(15 % c == Int128(0, 15)); + assert((15 & c) == Int128(0, 6)); + assert((15 | c) == Int128(5, 15)); + assert((15 ^ c) == Int128(5, 9)); + + assert(c << 1 == Int128(10, 12)); + assert(-c >> 1 == Int128(-3, 9223372036854775805)); + assert(-c >>> 1 == Int128(9223372036854775805, 9223372036854775805)); + + assert((c += 1) == Int128(5, 7)); + assert((c -= 1) == Int128(5, 6)); + assert((c += Int128(0, 1)) == Int128(5, 7)); + assert((c -= Int128(0, 1)) == Int128(5, 6)); + assert((c *= 2) == Int128(10, 12)); + assert((c /= 2) == Int128(5, 6)); + assert((c %= 2) == Int128()); + c += Int128(5, 6); + assert((c *= Int128(10, 20)) == Int128(160, 120)); + assert((c /= Int128(10, 20)) == Int128(0, 15)); + c += Int128(72, 0); + assert((c %= Int128(10, 20)) == Int128(1, -125)); + assert((c &= Int128(3, 20)) == Int128(1, 0)); + assert((c |= Int128(8, 2)) == Int128(9, 2)); + assert((c ^= Int128(8, 2)) == Int128(1, 0)); + c |= Int128(10, 5); + assert((c <<= 1) == Int128(11 * 2, 5 * 2)); + assert((c >>>= 1) == Int128(11, 5)); + c = Int128(long.min, long.min); + assert((c >>= 1) == Int128(long.min >> 1, cast(ulong) long.min >> 1)); + + assert(-Int128.min == Int128.min); + assert(Int128.max + 1 == Int128.min); + + c = Int128(5, 6); + assert(c < Int128(6, 5)); + assert(c > 10); + + c = Int128(-1UL); + assert(c == -1UL); + c = Int128(-1L); + assert(c == -1L); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_internal_cstring.d b/libphobos/testsuite/libphobos.phobos/std_internal_cstring.d new file mode 100644 index 0000000000000000000000000000000000000000..8cb8d6187d1889487288919677acfddea8351229 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_internal_cstring.d @@ -0,0 +1,47 @@ +@safe unittest +{ + import std.internal.cstring; + + version (Posix) + { + import core.stdc.stdlib : free; + import core.sys.posix.stdlib : setenv; + import std.exception : enforce; + + void setEnvironment(scope const(char)[] name, scope const(char)[] value) + { enforce(setenv(name.tempCString(), value.tempCString(), 1) != -1); } + } + + version (Windows) + { + import core.sys.windows.winbase : SetEnvironmentVariableW; + import std.exception : enforce; + + void setEnvironment(scope const(char)[] name, scope const(char)[] value) + { enforce(SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW())); } + } +} + +nothrow @nogc @system unittest +{ + import std.internal.cstring; + + import core.stdc.string; + + string str = "abc"; + + // Intended usage + assert(strlen(str.tempCString()) == 3); + + // Correct usage + auto tmp = str.tempCString(); + assert(strlen(tmp) == 3); // or `tmp.ptr`, or `tmp.buffPtr` + + // $(RED WARNING): $(RED Incorrect usage) + auto pInvalid1 = str.tempCString().ptr; + const char* pInvalid2 = str.tempCString(); + // Both pointers refer to invalid memory here as + // returned values aren't assigned to a variable and + // both primary expressions are ended. +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_internal_scopebuffer.d b/libphobos/testsuite/libphobos.phobos/std_internal_scopebuffer.d new file mode 100644 index 0000000000000000000000000000000000000000..adecde1f5029d750c5e79cc7a85b498fc2c71761 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_internal_scopebuffer.d @@ -0,0 +1,9 @@ +@system unittest +{ + import std.internal.scopebuffer; + + ubyte[10] tmpbuf = void; + auto sb = scopeBuffer(tmpbuf); + scope(exit) sb.free(); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_json.d b/libphobos/testsuite/libphobos.phobos/std_json.d new file mode 100644 index 0000000000000000000000000000000000000000..5d686fb18d4e1b61749e0cff285898c0fc99fc6e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_json.d @@ -0,0 +1,252 @@ +@system unittest +{ + import std.json; + + import std.conv : to; + + // parse a file or string of json into a usable structure + string s = `{ "language": "D", "rating": 3.5, "code": "42" }`; + JSONValue j = parseJSON(s); + // j and j["language"] return JSONValue, + // j["language"].str returns a string + assert(j["language"].str == "D"); + assert(j["rating"].floating == 3.5); + + // check a type + long x; + if (const(JSONValue)* code = "code" in j) + { + if (code.type() == JSONType.integer) + x = code.integer; + else + x = to!int(code.str); + } + + // create a json struct + JSONValue jj = [ "language": "D" ]; + // rating doesnt exist yet, so use .object to assign + jj.object["rating"] = JSONValue(3.5); + // create an array to assign to list + jj.object["list"] = JSONValue( ["a", "b", "c"] ); + // list already exists, so .object optional + jj["list"].array ~= JSONValue("D"); + + string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`; + assert(jj.toString == jjStr); +} + +@safe unittest +{ + import std.json; + + string s = "{ \"language\": \"D\" }"; + JSONValue j = parseJSON(s); + assert(j.type == JSONType.object); + assert(j["language"].type == JSONType.string); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = [ "language": "D" ]; + + // get value + assert(j["language"].str == "D"); + + // change existing key to new string + j["language"].str = "Perl"; + assert(j["language"].str == "Perl"); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = true; + assert(j.boolean == true); + + j.boolean = false; + assert(j.boolean == false); + + j.integer = 12; + import std.exception : assertThrown; + assertThrown!JSONException(j.boolean); + +} + +@safe unittest +{ + import std.json; + + import std.exception; + import std.conv; + string s = + `{ + "a": 123, + "b": 3.1415, + "c": "text", + "d": true, + "e": [1, 2, 3], + "f": { "a": 1 }, + "g": -45, + "h": ` ~ ulong.max.to!string ~ `, + }`; + + struct a { } + + immutable json = parseJSON(s); + assert(json["a"].get!double == 123.0); + assert(json["a"].get!int == 123); + assert(json["a"].get!uint == 123); + assert(json["b"].get!double == 3.1415); + assertThrown!JSONException(json["b"].get!int); + assert(json["c"].get!string == "text"); + assert(json["d"].get!bool == true); + assertNotThrown(json["e"].get!(JSONValue[])); + assertNotThrown(json["f"].get!(JSONValue[string])); + static assert(!__traits(compiles, json["a"].get!a)); + assertThrown!JSONException(json["e"].get!float); + assertThrown!JSONException(json["d"].get!(JSONValue[string])); + assertThrown!JSONException(json["f"].get!(JSONValue[])); + assert(json["g"].get!int == -45); + assertThrown!ConvException(json["g"].get!uint); + assert(json["h"].get!ulong == ulong.max); + assertThrown!ConvException(json["h"].get!uint); + assertNotThrown(json["h"].get!float); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( "a string" ); + j = JSONValue(42); + + j = JSONValue( [1, 2, 3] ); + assert(j.type == JSONType.array); + + j = JSONValue( ["language": "D"] ); + assert(j.type == JSONType.object); + +} + +@system unittest +{ + import std.json; + + JSONValue obj1 = JSONValue.emptyObject; + assert(obj1.type == JSONType.object); + obj1.object["a"] = JSONValue(1); + assert(obj1.object["a"] == JSONValue(1)); + + JSONValue obj2 = JSONValue.emptyObject; + assert("a" !in obj2.object); + obj2.object["b"] = JSONValue(5); + assert(obj1 != obj2); + +} + +@system unittest +{ + import std.json; + + JSONValue obj = JSONValue.emptyOrderedObject; + assert(obj.type == JSONType.object); + assert(obj.isOrdered); + obj["b"] = JSONValue(2); + obj["a"] = JSONValue(1); + assert(obj["a"] == JSONValue(1)); + assert(obj["b"] == JSONValue(2)); + + string[] keys; + foreach (string k, JSONValue v; obj) + keys ~= k; + assert(keys == ["b", "a"]); + +} + +@system unittest +{ + import std.json; + + JSONValue arr1 = JSONValue.emptyArray; + assert(arr1.type == JSONType.array); + assert(arr1.array.length == 0); + arr1.array ~= JSONValue("Hello"); + assert(arr1.array.length == 1); + assert(arr1.array[0] == JSONValue("Hello")); + + JSONValue arr2 = JSONValue.emptyArray; + assert(arr2.array.length == 0); + assert(arr1 != arr2); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( [42, 43, 44] ); + assert( j[0].integer == 42 ); + assert( j[1].integer == 43 ); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( ["language": "D"] ); + assert( j["language"].str == "D" ); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( ["language": "D"] ); + j["language"].str = "Perl"; + assert( j["language"].str == "Perl" ); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( ["Perl", "C"] ); + j[1].str = "D"; + assert( j[1].str == "D" ); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = [ "language": "D", "author": "walter" ]; + string a = ("author" in j).str; + *("author" in j) = "Walter"; + assert(j["author"].str == "Walter"); + +} + +@safe unittest +{ + import std.json; + + assert(JSONValue(10).opEquals(JSONValue(10.0))); + assert(JSONValue(10) != (JSONValue(10.5))); + + assert(JSONValue(1) != JSONValue(true)); + assert(JSONValue.emptyArray != JSONValue.emptyObject); + + assert(parseJSON(`{"a": 1, "b": 2}`).opEquals(parseJSON(`{"b": 2, "a": 1}`))); + +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_logger_core.d b/libphobos/testsuite/libphobos.phobos/std_logger_core.d new file mode 100644 index 0000000000000000000000000000000000000000..f8206db199ae673bba1546c76512db3d59192984 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_logger_core.d @@ -0,0 +1,22 @@ +@safe unittest +{ + import std.logger.core; + + auto nl1 = new StdForwardLogger(LogLevel.all); +} + +@system unittest +{ + import std.logger.core; + + import std.logger.filelogger : FileLogger; + import std.file : deleteme, remove; + Logger l = stdThreadLocalLog; + stdThreadLocalLog = new FileLogger(deleteme ~ "-someFile.log"); + scope(exit) remove(deleteme ~ "-someFile.log"); + + auto tempLog = stdThreadLocalLog; + stdThreadLocalLog = l; + destroy(tempLog); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_logger_nulllogger.d b/libphobos/testsuite/libphobos.phobos/std_logger_nulllogger.d new file mode 100644 index 0000000000000000000000000000000000000000..6c4444312f9079c11d5fbced692ca55cf613a03c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_logger_nulllogger.d @@ -0,0 +1,10 @@ +@safe unittest +{ + import std.logger.nulllogger; + + import std.logger.core : LogLevel; + auto nl1 = new NullLogger(LogLevel.all); + nl1.info("You will never read this."); + nl1.fatal("You will never read this, either and it will not throw"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_algebraic.d b/libphobos/testsuite/libphobos.phobos/std_math_algebraic.d new file mode 100644 index 0000000000000000000000000000000000000000..7b20a13ca26e02017b028cc48bdd5a0ab70cac5f --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_algebraic.d @@ -0,0 +1,163 @@ +@safe pure nothrow @nogc unittest +{ + import std.math.algebraic; + + import std.math.traits : isIdentical, isNaN; + + assert(isIdentical(abs(-0.0L), 0.0L)); + assert(isNaN(abs(real.nan))); + assert(abs(-real.infinity) == real.infinity); + assert(abs(-56) == 56); + assert(abs(2321312L) == 2321312L); + assert(abs(23u) == 23u); +} + +@safe unittest +{ + import std.math.algebraic; + + import std.math.traits : isIdentical; + + assert(isIdentical(fabs(0.0f), 0.0f)); + assert(isIdentical(fabs(-0.0f), 0.0f)); + assert(fabs(-10.0f) == 10.0f); + + assert(isIdentical(fabs(0.0), 0.0)); + assert(isIdentical(fabs(-0.0), 0.0)); + assert(fabs(-10.0) == 10.0); + + assert(isIdentical(fabs(0.0L), 0.0L)); + assert(isIdentical(fabs(-0.0L), 0.0L)); + assert(fabs(-10.0L) == 10.0L); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.algebraic; + + import std.math.operations : feqrel; + import std.math.traits : isNaN; + + assert(sqrt(2.0).feqrel(1.4142) > 16); + assert(sqrt(9.0).feqrel(3.0) > 16); + + assert(isNaN(sqrt(-1.0f))); + assert(isNaN(sqrt(-1.0))); + assert(isNaN(sqrt(-1.0L))); +} + +@safe unittest +{ + import std.math.algebraic; + + import std.math.operations : feqrel; + + assert(cbrt(1.0).feqrel(1.0) > 16); + assert(cbrt(27.0).feqrel(3.0) > 16); + assert(cbrt(15.625).feqrel(2.5) > 16); +} + +@safe unittest +{ + import std.math.algebraic; + + import std.math.operations : feqrel; + + assert(hypot(1.0, 1.0).feqrel(1.4142) > 16); + assert(hypot(3.0, 4.0).feqrel(5.0) > 16); + assert(hypot(real.infinity, 1.0L) == real.infinity); + assert(hypot(real.infinity, real.nan) == real.infinity); +} + +@safe unittest +{ + import std.math.algebraic; + + import std.math.operations : isClose; + + assert(isClose(hypot(1.0, 2.0, 2.0), 3.0)); + assert(isClose(hypot(2.0, 3.0, 6.0), 7.0)); + assert(isClose(hypot(1.0, 4.0, 8.0), 9.0)); +} + +@safe nothrow @nogc unittest +{ + import std.math.algebraic; + + real x = 3.1L; + static real[] pp = [56.1L, 32.7L, 6]; + + assert(poly(x, pp) == (56.1L + (32.7L + 6.0L * x) * x)); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.algebraic; + + assert(nextPow2(2) == 4); + assert(nextPow2(10) == 16); + assert(nextPow2(4000) == 4096); + + assert(nextPow2(-2) == -4); + assert(nextPow2(-10) == -16); + + assert(nextPow2(uint.max) == 0); + assert(nextPow2(uint.min) == 0); + assert(nextPow2(size_t.max) == 0); + assert(nextPow2(size_t.min) == 0); + + assert(nextPow2(int.max) == 0); + assert(nextPow2(int.min) == 0); + assert(nextPow2(long.max) == 0); + assert(nextPow2(long.min) == 0); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.algebraic; + + assert(nextPow2(2.1) == 4.0); + assert(nextPow2(-2.0) == -4.0); + assert(nextPow2(0.25) == 0.5); + assert(nextPow2(-4.0) == -8.0); + + assert(nextPow2(double.max) == 0.0); + assert(nextPow2(double.infinity) == double.infinity); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.algebraic; + + assert(truncPow2(3) == 2); + assert(truncPow2(4) == 4); + assert(truncPow2(10) == 8); + assert(truncPow2(4000) == 2048); + + assert(truncPow2(-5) == -4); + assert(truncPow2(-20) == -16); + + assert(truncPow2(uint.max) == int.max + 1); + assert(truncPow2(uint.min) == 0); + assert(truncPow2(ulong.max) == long.max + 1); + assert(truncPow2(ulong.min) == 0); + + assert(truncPow2(int.max) == (int.max / 2) + 1); + assert(truncPow2(int.min) == int.min); + assert(truncPow2(long.max) == (long.max / 2) + 1); + assert(truncPow2(long.min) == long.min); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.algebraic; + + assert(truncPow2(2.1) == 2.0); + assert(truncPow2(7.0) == 4.0); + assert(truncPow2(-1.9) == -1.0); + assert(truncPow2(0.24) == 0.125); + assert(truncPow2(-7.0) == -4.0); + + assert(truncPow2(double.infinity) == double.infinity); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_exponential.d b/libphobos/testsuite/libphobos.phobos/std_math_exponential.d new file mode 100644 index 0000000000000000000000000000000000000000..3ba0a828fa2ba6e0344f8bd4627d17a050138da9 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_exponential.d @@ -0,0 +1,279 @@ +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.operations : feqrel; + + assert(pow(2.0, 5) == 32.0); + assert(pow(1.5, 9).feqrel(38.4433) > 16); + assert(pow(real.nan, 2) is real.nan); + assert(pow(real.infinity, 2) == real.infinity); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + assert(pow(2, 3) == 8); + assert(pow(3, 2) == 9); + + assert(pow(2, 10) == 1_024); + assert(pow(2, 20) == 1_048_576); + assert(pow(2, 30) == 1_073_741_824); + + assert(pow(0, 0) == 1); + + assert(pow(1, -5) == 1); + assert(pow(1, -6) == 1); + assert(pow(-1, -5) == -1); + assert(pow(-1, -6) == 1); + + assert(pow(-2, 5) == -32); + assert(pow(-2, -5) == 0); + assert(pow(cast(double) -2, -5) == -0.03125); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + assert(pow(2, 5.0) == 32.0); + assert(pow(7, 3.0) == 343.0); + assert(pow(2, real.nan) is real.nan); + assert(pow(2, real.infinity) == real.infinity); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.operations : isClose; + + assert(isClose(pow(2.0, 3.0), 8.0)); + assert(isClose(pow(1.5, 10.0), 57.6650390625)); + + // square root of 9 + assert(isClose(pow(9.0, 0.5), 3.0)); + // 10th root of 1024 + assert(isClose(pow(1024.0, 0.1), 2.0)); + + assert(isClose(pow(-4.0, 3.0), -64.0)); + + // reciprocal of 4 ^^ 2 + assert(isClose(pow(4.0, -2.0), 0.0625)); + // reciprocal of (-2) ^^ 3 + assert(isClose(pow(-2.0, -3.0), -0.125)); + + assert(isClose(pow(-2.5, 3.0), -15.625)); + // reciprocal of 2.5 ^^ 3 + assert(isClose(pow(2.5, -3.0), 0.064)); + // reciprocal of (-2.5) ^^ 3 + assert(isClose(pow(-2.5, -3.0), -0.064)); + + // reciprocal of square root of 4 + assert(isClose(pow(4.0, -0.5), 0.5)); + + // per definition + assert(isClose(pow(0.0, 0.0), 1.0)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.operations : isClose; + + // the result is a complex number + // which cannot be represented as floating point number + import std.math.traits : isNaN; + assert(isNaN(pow(-2.5, -1.5))); + + // use the ^^-operator of std.complex instead + import std.complex : complex; + auto c1 = complex(-2.5, 0.0); + auto c2 = complex(-1.5, 0.0); + auto result = c1 ^^ c2; + // exact result apparently depends on `real` precision => increased tolerance + assert(isClose(result.re, -4.64705438e-17, 2e-4)); + assert(isClose(result.im, 2.52982e-1, 2e-4)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + assert(powmod(1U, 10U, 3U) == 1); + assert(powmod(3U, 2U, 6U) == 3); + assert(powmod(5U, 5U, 15U) == 5); + assert(powmod(2U, 3U, 5U) == 3); + assert(powmod(2U, 4U, 5U) == 1); + assert(powmod(2U, 5U, 5U) == 2); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.operations : feqrel; + import std.math.constants : E; + + assert(exp(0.0) == 1.0); + assert(exp(3.0).feqrel(E * E * E) > 16); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.traits : isIdentical; + import std.math.operations : feqrel; + + assert(isIdentical(expm1(0.0), 0.0)); + assert(expm1(1.0).feqrel(1.71828) > 16); + assert(expm1(2.0).feqrel(6.3890) > 16); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.traits : isIdentical; + import std.math.operations : feqrel; + + assert(isIdentical(exp2(0.0), 1.0)); + assert(exp2(2.0).feqrel(4.0) > 16); + assert(exp2(8.0).feqrel(256.0) > 16); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.operations : isClose; + + int exp; + real mantissa = frexp(123.456L, exp); + + assert(isClose(mantissa * pow(2.0L, cast(real) exp), 123.456L)); + + assert(frexp(-real.nan, exp) && exp == int.min); + assert(frexp(real.nan, exp) && exp == int.min); + assert(frexp(-real.infinity, exp) == -real.infinity && exp == int.min); + assert(frexp(real.infinity, exp) == real.infinity && exp == int.max); + assert(frexp(-0.0, exp) == -0.0 && exp == 0); + assert(frexp(0.0, exp) == 0.0 && exp == 0); +} + +@safe pure unittest +{ + import std.math.exponential; + + assert(ilogb(1) == 0); + assert(ilogb(3) == 1); + assert(ilogb(3.0) == 1); + assert(ilogb(100_000_000) == 26); + + assert(ilogb(0) == FP_ILOGB0); + assert(ilogb(0.0) == FP_ILOGB0); + assert(ilogb(double.nan) == FP_ILOGBNAN); + assert(ilogb(double.infinity) == int.max); +} + +@safe pure unittest +{ + import std.math.exponential; + + assert(ilogb(0) == FP_ILOGB0); + assert(ilogb(0.0) == FP_ILOGB0); + assert(ilogb(double.nan) == FP_ILOGBNAN); +} + +@nogc @safe pure nothrow unittest +{ + import std.math.exponential; + + import std.meta : AliasSeq; + static foreach (T; AliasSeq!(float, double, real)) + {{ + T r; + + r = ldexp(3.0L, 3); + assert(r == 24); + + r = ldexp(cast(T) 3.0, cast(int) 3); + assert(r == 24); + + T n = 3.0; + int exp = 3; + r = ldexp(n, exp); + assert(r == 24); + }} +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.operations : feqrel; + import std.math.constants : E; + + assert(feqrel(log(E), 1) >= real.mant_dig - 1); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.algebraic : fabs; + + assert(fabs(log10(1000.0L) - 3) < .000001); +} + +@safe pure unittest +{ + import std.math.exponential; + + import std.math.traits : isIdentical, isNaN; + import std.math.operations : feqrel; + + assert(isIdentical(log1p(0.0), 0.0)); + assert(log1p(1.0).feqrel(0.69314) > 16); + + assert(log1p(-1.0) == -real.infinity); + assert(isNaN(log1p(-2.0))); + assert(log1p(real.nan) is real.nan); + assert(log1p(-real.nan) is -real.nan); + assert(log1p(real.infinity) == real.infinity); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.operations : isClose; + + assert(isClose(log2(1024.0L), 10)); +} + +@safe @nogc nothrow unittest +{ + import std.math.exponential; + + assert(logb(1.0) == 0); + assert(logb(100.0) == 6); + + assert(logb(0.0) == -real.infinity); + assert(logb(real.infinity) == real.infinity); + assert(logb(-real.infinity) == real.infinity); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + assert(scalbn(0x1.2345678abcdefp0L, 999) == 0x1.2345678abcdefp999L); + assert(scalbn(-real.infinity, 5) == -real.infinity); + assert(scalbn(2.0,10) == 2048.0); + assert(scalbn(2048.0f,-10) == 2.0f); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_hardware.d b/libphobos/testsuite/libphobos.phobos/std_math_hardware.d new file mode 100644 index 0000000000000000000000000000000000000000..c88f59f104195c2a64dec4eef67db1f4d47afab1 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_hardware.d @@ -0,0 +1,18 @@ +@safe unittest +{ + import std.math.hardware; + + import std.math.rounding : lrint; + + FloatingPointControl fpctrl; + + fpctrl.rounding = FloatingPointControl.roundDown; + assert(lrint(1.5) == 1.0); + + fpctrl.rounding = FloatingPointControl.roundUp; + assert(lrint(1.4) == 2.0); + + fpctrl.rounding = FloatingPointControl.roundToNearest; + assert(lrint(1.5) == 2.0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_operations.d b/libphobos/testsuite/libphobos.phobos/std_math_operations.d new file mode 100644 index 0000000000000000000000000000000000000000..b0678f10c364de9002fcedf90263ebe0eea0dd99 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_operations.d @@ -0,0 +1,217 @@ +@safe @nogc pure nothrow unittest +{ + import std.math.operations; + + import std.math.traits : isNaN; + + real a = NaN(1_000_000); + assert(isNaN(a)); + assert(getNaNPayload(a) == 1_000_000); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.operations; + + import std.math.traits : isNaN; + + real a = NaN(1_000_000); + assert(isNaN(a)); + assert(getNaNPayload(a) == 1_000_000); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.operations; + + assert(nextUp(1.0 - 1.0e-6).feqrel(0.999999) > 16); + assert(nextUp(1.0 - real.epsilon).feqrel(1.0) > 16); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + assert( nextDown(1.0 + real.epsilon) == 1.0); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + import std.math.traits : isNaN; + + float a = 1; + assert(is(typeof(nextafter(a, a)) == float)); + assert(nextafter(a, a.infinity) > a); + assert(isNaN(nextafter(a, a.nan))); + assert(isNaN(nextafter(a.nan, a))); + + double b = 2; + assert(is(typeof(nextafter(b, b)) == double)); + assert(nextafter(b, b.infinity) > b); + assert(isNaN(nextafter(b, b.nan))); + assert(isNaN(nextafter(b.nan, b))); + + real c = 3; + assert(is(typeof(nextafter(c, c)) == real)); + assert(nextafter(c, c.infinity) > c); + assert(isNaN(nextafter(c, c.nan))); + assert(isNaN(nextafter(c.nan, c))); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + import std.math.traits : isNaN; + + assert(fdim(2.0, 0.0) == 2.0); + assert(fdim(-2.0, 0.0) == 0.0); + assert(fdim(real.infinity, 2.0) == real.infinity); + assert(isNaN(fdim(real.nan, 2.0))); + assert(isNaN(fdim(2.0, real.nan))); + assert(isNaN(fdim(real.nan, real.nan))); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + import std.meta : AliasSeq; + static foreach (F; AliasSeq!(float, double, real)) + { + assert(fmax(F(0.0), F(2.0)) == 2.0); + assert(fmax(F(-2.0), 0.0) == F(0.0)); + assert(fmax(F.infinity, F(2.0)) == F.infinity); + assert(fmax(F.nan, F(2.0)) == F(2.0)); + assert(fmax(F(2.0), F.nan) == F(2.0)); + } +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + import std.meta : AliasSeq; + static foreach (F; AliasSeq!(float, double, real)) + { + assert(fmin(F(0.0), F(2.0)) == 0.0); + assert(fmin(F(-2.0), F(0.0)) == -2.0); + assert(fmin(F.infinity, F(2.0)) == 2.0); + assert(fmin(F.nan, F(2.0)) == 2.0); + assert(fmin(F(2.0), F.nan) == 2.0); + } +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + assert(fma(0.0, 2.0, 2.0) == 2.0); + assert(fma(2.0, 2.0, 2.0) == 6.0); + assert(fma(real.infinity, 2.0, 2.0) == real.infinity); + assert(fma(real.nan, 2.0, 2.0) is real.nan); + assert(fma(2.0, 2.0, real.nan) is real.nan); +} + +@safe pure unittest +{ + import std.math.operations; + + assert(feqrel(2.0, 2.0) == 53); + assert(feqrel(2.0f, 2.0f) == 24); + assert(feqrel(2.0, double.nan) == 0); + + // Test that numbers are within n digits of each + // other by testing if feqrel > n * log2(10) + + // five digits + assert(feqrel(2.0, 2.00001) > 16); + // ten digits + assert(feqrel(2.0, 2.00000000001) > 33); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + assert(isClose(1.0,0.999_999_999)); + assert(isClose(0.001, 0.000_999_999_999)); + assert(isClose(1_000_000_000.0,999_999_999.0)); + + assert(isClose(17.123_456_789, 17.123_456_78)); + assert(!isClose(17.123_456_789, 17.123_45)); + + // use explicit 3rd parameter for less (or more) accuracy + assert(isClose(17.123_456_789, 17.123_45, 1e-6)); + assert(!isClose(17.123_456_789, 17.123_45, 1e-7)); + + // use 4th parameter when comparing close to zero + assert(!isClose(1e-100, 0.0)); + assert(isClose(1e-100, 0.0, 0.0, 1e-90)); + assert(!isClose(1e-10, -1e-10)); + assert(isClose(1e-10, -1e-10, 0.0, 1e-9)); + assert(!isClose(1e-300, 1e-298)); + assert(isClose(1e-300, 1e-298, 0.0, 1e-200)); + + // different default limits for different floating point types + assert(isClose(1.0f, 0.999_99f)); + assert(!isClose(1.0, 0.999_99)); + static if (real.sizeof > double.sizeof) + assert(!isClose(1.0L, 0.999_999_999L)); +} + +@safe pure nothrow unittest +{ + import std.math.operations; + + assert(isClose([1.0, 2.0, 3.0], [0.999_999_999, 2.000_000_001, 3.0])); + assert(!isClose([1.0, 2.0], [0.999_999_999, 2.000_000_001, 3.0])); + assert(!isClose([1.0, 2.0, 3.0], [0.999_999_999, 2.000_000_001])); + + assert(isClose([2.0, 1.999_999_999, 2.000_000_001], 2.0)); + assert(isClose(2.0, [2.0, 1.999_999_999, 2.000_000_001])); +} + +@safe unittest +{ + import std.math.operations; + + assert(cmp(-double.infinity, -double.max) < 0); + assert(cmp(-double.max, -100.0) < 0); + assert(cmp(-100.0, -0.5) < 0); + assert(cmp(-0.5, 0.0) < 0); + assert(cmp(0.0, 0.5) < 0); + assert(cmp(0.5, 100.0) < 0); + assert(cmp(100.0, double.max) < 0); + assert(cmp(double.max, double.infinity) < 0); + + assert(cmp(1.0, 1.0) == 0); +} + +@safe unittest +{ + import std.math.operations; + + assert(cmp(-0.0, +0.0) < 0); + assert(cmp(+0.0, -0.0) > 0); +} + +@safe unittest +{ + import std.math.operations; + + assert(cmp(-double.nan, -double.infinity) < 0); + assert(cmp(double.infinity, double.nan) < 0); + assert(cmp(-double.nan, double.nan) < 0); +} + +@safe unittest +{ + import std.math.operations; + + assert(cmp(NaN(10), NaN(20)) < 0); + assert(cmp(-NaN(20), -NaN(10)) < 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_remainder.d b/libphobos/testsuite/libphobos.phobos/std_math_remainder.d new file mode 100644 index 0000000000000000000000000000000000000000..114b5d546f3204823484c0a40bc604dce314c3ad --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_remainder.d @@ -0,0 +1,54 @@ +@safe unittest +{ + import std.math.remainder; + + import std.math.operations : feqrel; + import std.math.traits : isIdentical, isNaN; + + assert(isIdentical(fmod(0.0, 1.0), 0.0)); + assert(fmod(5.0, 3.0).feqrel(2.0) > 16); + assert(isNaN(fmod(5.0, 0.0))); +} + +@safe unittest +{ + import std.math.remainder; + + import std.math.operations : feqrel; + + real frac; + real intpart; + + frac = modf(3.14159, intpart); + assert(intpart.feqrel(3.0) > 16); + assert(frac.feqrel(0.14159) > 16); +} + +@safe @nogc nothrow unittest +{ + import std.math.remainder; + + import std.math.operations : feqrel; + import std.math.traits : isNaN; + + assert(remainder(5.1, 3.0).feqrel(-0.9) > 16); + assert(remainder(-5.1, 3.0).feqrel(0.9) > 16); + assert(remainder(0.0, 3.0) == 0.0); + + assert(isNaN(remainder(1.0, 0.0))); + assert(isNaN(remainder(-1.0, 0.0))); +} + +@safe @nogc nothrow unittest +{ + import std.math.remainder; + + import std.math.operations : feqrel; + + int n; + + assert(remquo(5.1, 3.0, n).feqrel(-0.9) > 16 && n == 2); + assert(remquo(-5.1, 3.0, n).feqrel(0.9) > 16 && n == -2); + assert(remquo(0.0, 3.0, n) == 0.0 && n == 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_rounding.d b/libphobos/testsuite/libphobos.phobos/std_math_rounding.d new file mode 100644 index 0000000000000000000000000000000000000000..8c8704550fd7c5191d931ae38b0758922638e734 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_rounding.d @@ -0,0 +1,171 @@ +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.traits : isNaN; + + assert(ceil(+123.456L) == +124); + assert(ceil(-123.456L) == -123); + assert(ceil(-1.234L) == -1); + assert(ceil(-0.123L) == 0); + assert(ceil(0.0L) == 0); + assert(ceil(+0.123L) == 1); + assert(ceil(+1.234L) == 2); + assert(ceil(real.infinity) == real.infinity); + assert(isNaN(ceil(real.nan))); + assert(isNaN(ceil(real.init))); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.traits : isNaN; + + assert(floor(+123.456L) == +123); + assert(floor(-123.456L) == -124); + assert(floor(+123.0L) == +123); + assert(floor(-124.0L) == -124); + assert(floor(-1.234L) == -2); + assert(floor(-0.123L) == -1); + assert(floor(0.0L) == 0); + assert(floor(+0.123L) == 0); + assert(floor(+1.234L) == 1); + assert(floor(real.infinity) == real.infinity); + assert(isNaN(floor(real.nan))); + assert(isNaN(floor(real.init))); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.operations : isClose; + + assert(isClose(12345.6789L.quantize(0.01L), 12345.68L)); + assert(isClose(12345.6789L.quantize!floor(0.01L), 12345.67L)); + assert(isClose(12345.6789L.quantize(22.0L), 12342.0L)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.operations : isClose; + import std.math.traits : isNaN; + + assert(isClose(12345.6789L.quantize(0), 12345.6789L)); + assert(12345.6789L.quantize(real.infinity).isNaN); + assert(12345.6789L.quantize(real.nan).isNaN); + assert(real.infinity.quantize(0.01L) == real.infinity); + assert(real.infinity.quantize(real.nan).isNaN); + assert(real.nan.quantize(0.01L).isNaN); + assert(real.nan.quantize(real.infinity).isNaN); + assert(real.nan.quantize(real.nan).isNaN); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.operations : isClose; + + assert(isClose(12345.6789L.quantize!10(-2), 12345.68L)); + assert(isClose(12345.6789L.quantize!(10, -2), 12345.68L)); + assert(isClose(12345.6789L.quantize!(10, floor)(-2), 12345.67L)); + assert(isClose(12345.6789L.quantize!(10, -2, floor), 12345.67L)); + + assert(isClose(12345.6789L.quantize!22(1), 12342.0L)); + assert(isClose(12345.6789L.quantize!22, 12342.0L)); +} + +@safe pure unittest +{ + import std.math.rounding; + + import std.math.traits : isNaN; + + assert(nearbyint(0.4) == 0); + assert(nearbyint(0.5) == 0); + assert(nearbyint(0.6) == 1); + assert(nearbyint(100.0) == 100); + + assert(isNaN(nearbyint(real.nan))); + assert(nearbyint(real.infinity) == real.infinity); + assert(nearbyint(-real.infinity) == -real.infinity); +} + +@safe unittest +{ + import std.math.rounding; + + import std.math.traits : isNaN; + + version (IeeeFlagsSupport) resetIeeeFlags(); + assert(rint(0.4) == 0); + version (GNU) { /* inexact bit not set with enabled optimizations */ } else + version (IeeeFlagsSupport) assert(ieeeFlags.inexact); + + assert(rint(0.5) == 0); + assert(rint(0.6) == 1); + assert(rint(100.0) == 100); + + assert(isNaN(rint(real.nan))); + assert(rint(real.infinity) == real.infinity); + assert(rint(-real.infinity) == -real.infinity); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + assert(lrint(4.5) == 4); + assert(lrint(5.5) == 6); + assert(lrint(-4.5) == -4); + assert(lrint(-5.5) == -6); + + assert(lrint(int.max - 0.5) == 2147483646L); + assert(lrint(int.max + 0.5) == 2147483648L); + assert(lrint(int.min - 0.5) == -2147483648L); + assert(lrint(int.min + 0.5) == -2147483648L); +} + +@safe nothrow @nogc unittest +{ + import std.math.rounding; + + assert(round(4.5) == 5); + assert(round(5.4) == 5); + assert(round(-4.5) == -5); + assert(round(-5.1) == -5); +} + +@safe nothrow @nogc unittest +{ + import std.math.rounding; + + assert(lround(0.49) == 0); + assert(lround(0.5) == 1); + assert(lround(1.5) == 2); +} + +@safe pure unittest +{ + import std.math.rounding; + + assert(trunc(0.01) == 0); + assert(trunc(0.49) == 0); + assert(trunc(0.5) == 0); + assert(trunc(1.5) == 1); +} + +@safe unittest +{ + import std.math.rounding; + + assert(rndtol(1.0) == 1L); + assert(rndtol(1.2) == 1L); + assert(rndtol(1.7) == 2L); + assert(rndtol(1.0001) == 1L); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_traits.d b/libphobos/testsuite/libphobos.phobos/std_math_traits.d new file mode 100644 index 0000000000000000000000000000000000000000..952de85c98d775f0f6fc86e26bdcc18b6f9322e7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_traits.d @@ -0,0 +1,189 @@ +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + assert( isNaN(float.init)); + assert( isNaN(-double.init)); + assert( isNaN(real.nan)); + assert( isNaN(-real.nan)); + assert(!isNaN(cast(float) 53.6)); + assert(!isNaN(cast(real)-53.6)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + assert( isFinite(1.23f)); + assert( isFinite(float.max)); + assert( isFinite(float.min_normal)); + assert(!isFinite(float.nan)); + assert(!isFinite(float.infinity)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + float f = 3; + double d = 500; + real e = 10e+48; + + assert(isNormal(f)); + assert(isNormal(d)); + assert(isNormal(e)); + f = d = e = 0; + assert(!isNormal(f)); + assert(!isNormal(d)); + assert(!isNormal(e)); + assert(!isNormal(real.infinity)); + assert(isNormal(-real.max)); + assert(!isNormal(real.min_normal/4)); + +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + import std.meta : AliasSeq; + + static foreach (T; AliasSeq!(float, double, real)) + {{ + T f; + for (f = 1.0; !isSubnormal(f); f /= 2) + assert(f != 0); + }} +} + +@nogc @safe pure nothrow unittest +{ + import std.math.traits; + + assert(!isInfinity(float.init)); + assert(!isInfinity(-float.init)); + assert(!isInfinity(float.nan)); + assert(!isInfinity(-float.nan)); + assert(isInfinity(float.infinity)); + assert(isInfinity(-float.infinity)); + assert(isInfinity(-1.0f / 0.0f)); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.traits; + + // We're forcing the CTFE to run by assigning the result of the function to an enum + enum test1 = isIdentical(1.0,1.0); + enum test2 = isIdentical(real.nan,real.nan); + enum test3 = isIdentical(real.infinity, real.infinity); + enum test4 = isIdentical(real.infinity, real.infinity); + enum test5 = isIdentical(0.0, 0.0); + + assert(test1); + assert(test2); + assert(test3); + assert(test4); + assert(test5); + + enum test6 = !isIdentical(0.0, -0.0); + enum test7 = !isIdentical(real.nan, -real.nan); + enum test8 = !isIdentical(real.infinity, -real.infinity); + + assert(test6); + assert(test7); + assert(test8); +} + +@nogc @safe pure nothrow unittest +{ + import std.math.traits; + + assert(!signbit(float.nan)); + assert(signbit(-float.nan)); + assert(!signbit(168.1234f)); + assert(signbit(-168.1234f)); + assert(!signbit(0.0f)); + assert(signbit(-0.0f)); + assert(signbit(-float.max)); + assert(!signbit(float.max)); + + assert(!signbit(double.nan)); + assert(signbit(-double.nan)); + assert(!signbit(168.1234)); + assert(signbit(-168.1234)); + assert(!signbit(0.0)); + assert(signbit(-0.0)); + assert(signbit(-double.max)); + assert(!signbit(double.max)); + + assert(!signbit(real.nan)); + assert(signbit(-real.nan)); + assert(!signbit(168.1234L)); + assert(signbit(-168.1234L)); + assert(!signbit(0.0L)); + assert(signbit(-0.0L)); + assert(signbit(-real.max)); + assert(!signbit(real.max)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + assert(copysign(1.0, 1.0) == 1.0); + assert(copysign(1.0, -0.0) == -1.0); + assert(copysign(1UL, -1.0) == -1.0); + assert(copysign(-1.0, -1.0) == -1.0); + + assert(copysign(real.infinity, -1.0) == -real.infinity); + assert(copysign(real.nan, 1.0) is real.nan); + assert(copysign(-real.nan, 1.0) is real.nan); + assert(copysign(real.nan, -1.0) is -real.nan); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + assert(sgn(168.1234) == 1); + assert(sgn(-168.1234) == -1); + assert(sgn(0.0) == 0); + assert(sgn(-0.0) == 0); +} + +@safe unittest +{ + import std.math.traits; + + import std.math.exponential : pow; + + assert( isPowerOf2(1.0L)); + assert( isPowerOf2(2.0L)); + assert( isPowerOf2(0.5L)); + assert( isPowerOf2(pow(2.0L, 96))); + assert( isPowerOf2(pow(2.0L, -77))); + + assert(!isPowerOf2(-2.0L)); + assert(!isPowerOf2(-0.5L)); + assert(!isPowerOf2(0.0L)); + assert(!isPowerOf2(4.315)); + assert(!isPowerOf2(1.0L / 3.0L)); + + assert(!isPowerOf2(real.nan)); + assert(!isPowerOf2(real.infinity)); +} + +@safe unittest +{ + import std.math.traits; + + assert( isPowerOf2(1)); + assert( isPowerOf2(2)); + assert( isPowerOf2(1uL << 63)); + + assert(!isPowerOf2(-4)); + assert(!isPowerOf2(0)); + assert(!isPowerOf2(1337u)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_trigonometry.d b/libphobos/testsuite/libphobos.phobos/std_math_trigonometry.d new file mode 100644 index 0000000000000000000000000000000000000000..88a43976e968665bb4970ab0cfc229386907d7c5 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_trigonometry.d @@ -0,0 +1,168 @@ +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + + assert(cos(0.0) == 1.0); + assert(cos(1.0).isClose(0.5403023059)); + assert(cos(3.0).isClose(-0.9899924966)); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.constants : PI; + import std.stdio : writefln; + + void someFunc() + { + real x = 30.0; + auto result = sin(x * (PI / 180)); // convert degrees to radians + writefln("The sine of %s degrees is %s", x, result); + } +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isIdentical; + import std.math.constants : PI; + import std.math.algebraic : sqrt; + + assert(isIdentical(tan(0.0), 0.0)); + assert(tan(PI).isClose(0, 0.0, 1e-10)); + assert(tan(PI / 3).isClose(sqrt(3.0))); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isNaN; + import std.math.constants : PI; + + assert(acos(0.0).isClose(1.570796327)); + assert(acos(0.5).isClose(PI / 3)); + assert(acos(PI).isNaN); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isIdentical, isNaN; + import std.math.constants : PI; + + assert(isIdentical(asin(0.0), 0.0)); + assert(asin(0.5).isClose(PI / 6)); + assert(asin(PI).isNaN); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isIdentical; + import std.math.constants : PI; + import std.math.algebraic : sqrt; + + assert(isIdentical(atan(0.0), 0.0)); + assert(atan(sqrt(3.0)).isClose(PI / 3)); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.constants : PI; + import std.math.algebraic : sqrt; + + assert(atan2(1.0, sqrt(3.0)).isClose(PI / 6)); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.constants : E; + import std.math.operations : isClose; + + assert(cosh(0.0) == 1.0); + assert(cosh(1.0).isClose((E + 1.0 / E) / 2)); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.constants : E; + import std.math.operations : isClose; + import std.math.traits : isIdentical; + + enum sinh1 = (E - 1.0 / E) / 2; + import std.meta : AliasSeq; + static foreach (F; AliasSeq!(float, double, real)) + { + assert(isIdentical(sinh(F(0.0)), F(0.0))); + assert(sinh(F(1.0)).isClose(F(sinh1))); + } +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isIdentical; + + assert(isIdentical(tanh(0.0), 0.0)); + assert(tanh(1.0).isClose(sinh(1.0) / cosh(1.0))); +} + +@safe @nogc nothrow unittest +{ + import std.math.trigonometry; + + import std.math.traits : isIdentical, isNaN; + + assert(isNaN(acosh(0.9))); + assert(isNaN(acosh(real.nan))); + assert(isIdentical(acosh(1.0), 0.0)); + assert(acosh(real.infinity) == real.infinity); + assert(isNaN(acosh(0.5))); +} + +@safe @nogc nothrow unittest +{ + import std.math.trigonometry; + + import std.math.traits : isIdentical, isNaN; + + assert(isIdentical(asinh(0.0), 0.0)); + assert(isIdentical(asinh(-0.0), -0.0)); + assert(asinh(real.infinity) == real.infinity); + assert(asinh(-real.infinity) == -real.infinity); + assert(isNaN(asinh(real.nan))); +} + +@safe @nogc nothrow unittest +{ + import std.math.trigonometry; + + import std.math.traits : isIdentical, isNaN; + + assert(isIdentical(atanh(0.0), 0.0)); + assert(isIdentical(atanh(-0.0),-0.0)); + assert(isNaN(atanh(real.nan))); + assert(isNaN(atanh(-real.infinity))); + assert(atanh(0.0) == 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_meta.d b/libphobos/testsuite/libphobos.phobos/std_meta.d new file mode 100644 index 0000000000000000000000000000000000000000..d5928462f1eda15f45405a89a153647cfcb5f43c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_meta.d @@ -0,0 +1,525 @@ +@safe unittest +{ + import std.meta; + + import std.meta; + alias TL = AliasSeq!(int, double); + + int foo(TL td) // same as int foo(int, double); + { + return td[0] + cast(int) td[1]; + } +} + +@safe unittest +{ + import std.meta; + + alias TL = AliasSeq!(int, double); + + alias Types = AliasSeq!(TL, char); + static assert(is(Types == AliasSeq!(int, double, char))); +} + +@safe unittest +{ + import std.meta; + + // Creates a compile-time sequence of function call expressions + // that each call `func` with the next variadic template argument + template Map(alias func, args...) + { + auto ref lazyItem() {return func(args[0]);} + + static if (args.length == 1) + { + alias Map = lazyItem; + } + else + { + // recurse + alias Map = AliasSeq!(lazyItem, Map!(func, args[1 .. $])); + } + } + + static void test(int a, int b) + { + assert(a == 4); + assert(b == 16); + } + + static int a = 2; + static int b = 4; + + test(Map!(i => i ^^ 2, a, b)); + assert(a == 2); + assert(b == 4); + + test(Map!((ref i) => i *= i, a, b)); + assert(a == 4); + assert(b == 16); + + static void testRef(ref int a, ref int b) + { + assert(a++ == 16); + assert(b++ == 256); + } + + testRef(Map!(function ref(ref i) => i *= i, a, b)); + assert(a == 17); + assert(b == 257); +} + +@safe unittest +{ + import std.meta; + + // Without Alias this would fail if Args[0] was e.g. a value and + // some logic would be needed to detect when to use enum instead + alias Head(Args...) = Alias!(Args[0]); + alias Tail(Args...) = Args[1 .. $]; + + alias Blah = AliasSeq!(3, int, "hello"); + static assert(Head!Blah == 3); + static assert(is(Head!(Tail!Blah) == int)); + static assert((Tail!Blah)[1] == "hello"); +} + +@safe unittest +{ + import std.meta; + + alias a = Alias!(123); + static assert(a == 123); + + enum abc = 1; + alias b = Alias!(abc); + static assert(b == 1); + + alias c = Alias!(3 + 4); + static assert(c == 7); + + alias concat = (s0, s1) => s0 ~ s1; + alias d = Alias!(concat("Hello", " World!")); + static assert(d == "Hello World!"); + + alias e = Alias!(int); + static assert(is(e == int)); + + alias f = Alias!(AliasSeq!(int)); + static assert(!is(typeof(f[0]))); //not an AliasSeq + static assert(is(f == int)); + + auto g = 6; + alias h = Alias!g; + ++h; + assert(g == 7); +} + +@safe unittest +{ + import std.meta; + + import std.stdio; + + void foo() + { + writefln("The index of long is %s", + staticIndexOf!(long, AliasSeq!(int, long, double))); + // prints: The index of long is 1 + } +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, double, char); + alias TL = Erase!(long, Types); + static assert(is(TL == AliasSeq!(int, double, char))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int); + static assert(is(EraseAll!(long, Types) == AliasSeq!(int, int))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int, float); + + alias TL = NoDuplicates!(Types); + static assert(is(TL == AliasSeq!(int, long, float))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int, float); + + alias TL = Replace!(long, char, Types); + static assert(is(TL == AliasSeq!(int, char, long, int, float))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int, float); + + alias TL = ReplaceAll!(long, char, Types); + static assert(is(TL == AliasSeq!(int, char, char, int, float))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int, float, byte, ubyte, short, ushort, uint); + + alias TL = Reverse!(Types); + static assert(is(TL == AliasSeq!(uint, ushort, short, ubyte, byte, float, int, long, long, int))); +} + +@safe unittest +{ + import std.meta; + + class A { } + class B : A { } + class C : B { } + alias Types = AliasSeq!(A, C, B); + + MostDerived!(Object, Types) x; // x is declared as type C + static assert(is(typeof(x) == C)); +} + +@safe unittest +{ + import std.meta; + + class A { } + class B : A { } + class C : B { } + alias Types = AliasSeq!(A, C, B); + + alias TL = DerivedToFront!(Types); + static assert(is(TL == AliasSeq!(C, B, A))); + + alias TL2 = DerivedToFront!(A, A, A, B, B, B, C, C, C); + static assert(is(TL2 == AliasSeq!(C, C, C, B, B, B, A, A, A))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : Unqual; + alias TL = staticMap!(Unqual, int, const int, immutable int, uint, ubyte, byte, short, ushort); + static assert(is(TL == AliasSeq!(int, int, int, uint, ubyte, byte, short, ushort))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isIntegral; + + static assert(!allSatisfy!(isIntegral, int, double)); + static assert( allSatisfy!(isIntegral, int, long)); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isIntegral; + + static assert(!anySatisfy!(isIntegral, string, double)); + static assert( anySatisfy!(isIntegral, int, double)); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isNarrowString, isUnsigned; + + alias Types1 = AliasSeq!(string, wstring, dchar[], char[], dstring, int); + alias TL1 = Filter!(isNarrowString, Types1); + static assert(is(TL1 == AliasSeq!(string, wstring, char[]))); + + alias Types2 = AliasSeq!(int, byte, ubyte, dstring, dchar, uint, ulong); + alias TL2 = Filter!(isUnsigned, Types2); + static assert(is(TL2 == AliasSeq!(ubyte, uint, ulong))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isPointer; + + alias isNoPointer = templateNot!isPointer; + static assert(!isNoPointer!(int*)); + static assert(allSatisfy!(isNoPointer, string, char, float)); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isNumeric, isUnsigned; + + alias storesNegativeNumbers = templateAnd!(isNumeric, templateNot!isUnsigned); + static assert(storesNegativeNumbers!int); + static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint); + + // An empty sequence of predicates always yields true. + alias alwaysTrue = templateAnd!(); + static assert(alwaysTrue!int); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isPointer, isUnsigned; + + alias isPtrOrUnsigned = templateOr!(isPointer, isUnsigned); + static assert( isPtrOrUnsigned!uint && isPtrOrUnsigned!(short*)); + static assert(!isPtrOrUnsigned!int && !isPtrOrUnsigned!(string)); + + // An empty sequence of predicates never yields true. + alias alwaysFalse = templateOr!(); + static assert(!alwaysFalse!int); +} + +@safe unittest +{ + import std.meta; + + import std.algorithm.iteration : map; + import std.algorithm.sorting : sort; + import std.string : capitalize; + + struct S + { + int a; + int c; + int b; + } + + alias capMembers = aliasSeqOf!([__traits(allMembers, S)].sort().map!capitalize()); + static assert(capMembers[0] == "A"); + static assert(capMembers[1] == "B"); + static assert(capMembers[2] == "C"); +} + +@safe unittest +{ + import std.meta; + + static immutable REF = [0, 1, 2, 3]; + foreach (I, V; aliasSeqOf!([0, 1, 2, 3])) + { + static assert(V == I); + static assert(V == REF[I]); + } +} + +@safe unittest +{ + import std.meta; + + // enum bool isImplicitlyConvertible(From, To) + import std.traits : isImplicitlyConvertible; + + static assert(allSatisfy!( + ApplyLeft!(isImplicitlyConvertible, ubyte), + short, ushort, int, uint, long, ulong)); + + static assert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short), + ubyte, string, short, float, int) == AliasSeq!(ubyte, short))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : hasMember, ifTestable; + + struct T1 + { + bool foo; + } + + struct T2 + { + struct Test + { + bool opCast(T : bool)() { return true; } + } + + Test foo; + } + + static assert(allSatisfy!(ApplyRight!(hasMember, "foo"), T1, T2)); + static assert(allSatisfy!(ApplyRight!(ifTestable, a => a.foo), T1, T2)); +} + +@safe unittest +{ + import std.meta; + + import std.traits : Largest; + + alias Types = AliasSeq!(byte, short, int, long); + + static assert(is(staticMap!(ApplyLeft!(Largest, short), Types) == + AliasSeq!(short, short, int, long))); + static assert(is(staticMap!(ApplyLeft!(Largest, int), Types) == + AliasSeq!(int, int, int, long))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : FunctionAttribute, SetFunctionAttributes; + + static void foo() @system; + static int bar(int) @system; + + alias SafeFunctions = AliasSeq!( + void function() @safe, + int function(int) @safe); + + static assert(is(staticMap!(ApplyRight!( + SetFunctionAttributes, "D", FunctionAttribute.safe), + typeof(&foo), typeof(&bar)) == SafeFunctions)); +} + +@safe unittest +{ + import std.meta; + + alias ImInt0 = Repeat!(0, int); + static assert(is(ImInt0 == AliasSeq!())); + + alias ImInt1 = Repeat!(1, immutable(int)); + static assert(is(ImInt1 == AliasSeq!(immutable(int)))); + + alias Real3 = Repeat!(3, real); + static assert(is(Real3 == AliasSeq!(real, real, real))); + + alias Real12 = Repeat!(4, Real3); + static assert(is(Real12 == AliasSeq!(real, real, real, real, real, real, + real, real, real, real, real, real))); + + alias Composite = AliasSeq!(uint, int); + alias Composite2 = Repeat!(2, Composite); + static assert(is(Composite2 == AliasSeq!(uint, int, uint, int))); + + alias ImInt10 = Repeat!(10, int); + static assert(is(ImInt10 == AliasSeq!(int, int, int, int, int, int, int, int, int, int))); + + alias Big = Repeat!(1_000_000, int); +} + +@safe unittest +{ + import std.meta; + + auto staticArray(T, size_t n)(Repeat!(n, T) elems) + { + T[n] a = [elems]; + return a; + } + + auto a = staticArray!(long, 3)(3, 1, 4); + assert(is(typeof(a) == long[3])); + assert(a == [3, 1, 4]); +} + +@safe unittest +{ + import std.meta; + + alias Nums = AliasSeq!(7, 2, 3, 23); + enum Comp(int N1, int N2) = N1 < N2; + static assert(AliasSeq!(2, 3, 7, 23) == staticSort!(Comp, Nums)); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(uint, short, ubyte, long, ulong); + enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1); + static assert(is(AliasSeq!(uint, ubyte, ulong, short, long) == staticSort!(Comp, + Types))); +} + +@safe unittest +{ + import std.meta; + + enum Comp(int N1, int N2) = N1 < N2; + static assert( staticIsSorted!(Comp, 2, 2)); + static assert( staticIsSorted!(Comp, 2, 3, 7, 23)); + static assert(!staticIsSorted!(Comp, 7, 2, 3, 23)); +} + +@safe unittest +{ + import std.meta; + + enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1); + static assert( staticIsSorted!(Comp, uint, ubyte, ulong, short, long)); + static assert(!staticIsSorted!(Comp, uint, short, ubyte, long, ulong)); +} + +@safe unittest +{ + import std.meta; + + static assert(is(Stride!(1, short, int, long) == AliasSeq!(short, int, long))); + static assert(is(Stride!(2, short, int, long) == AliasSeq!(short, long))); + static assert(is(Stride!(-1, short, int, long) == AliasSeq!(long, int, short))); + static assert(is(Stride!(-2, short, int, long) == AliasSeq!(long, short))); + + alias attribs = AliasSeq!(short, int, long, ushort, uint, ulong); + static assert(is(Stride!(3, attribs) == AliasSeq!(short, ushort))); + static assert(is(Stride!(3, attribs[1 .. $]) == AliasSeq!(int, uint))); + static assert(is(Stride!(-3, attribs) == AliasSeq!(ulong, long))); +} + +@safe unittest +{ + import std.meta; + + // ApplyRight combined with Instantiate can be used to apply various + // templates to the same parameters. + import std.string : leftJustify, center, rightJustify; + alias functions = staticMap!(ApplyRight!(Instantiate, string), + leftJustify, center, rightJustify); + string result = ""; + static foreach (f; functions) + { + { + auto x = &f; // not a template, but a function instantiation + result ~= x("hello", 7); + result ~= ";"; + } + } + + assert(result == "hello ; hello ; hello;"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_mmfile.d b/libphobos/testsuite/libphobos.phobos/std_mmfile.d new file mode 100644 index 0000000000000000000000000000000000000000..73f2291e136db9b9a8ed671bb3494ff6aea2d376 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_mmfile.d @@ -0,0 +1,43 @@ +@system unittest +{ + import std.mmfile; + + import std.file; + std.file.write(deleteme, "hello"); // deleteme is a temporary filename + scope(exit) remove(deleteme); + + // Use a scope class so the file will be closed at the end of this function + scope mmfile = new MmFile(deleteme); + + assert(mmfile.length == "hello".length); + + // Access file contents with the slice operator + // This is typed as `void[]`, so cast to `char[]` or `ubyte[]` to use it + const data = cast(const(char)[]) mmfile[]; + + // At this point, the file content may not have been read yet. + // In that case, the following memory access will intentionally + // trigger a page fault, causing the kernel to load the file contents + assert(data[0 .. 5] == "hello"); +} + +@system unittest +{ + import std.mmfile; + + import std.file; + scope(exit) remove(deleteme); + + scope mmfile = new MmFile(deleteme, MmFile.Mode.readWriteNew, 5, null); + assert(mmfile.length == 5); + + auto data = cast(ubyte[]) mmfile[]; + + // This write to memory will be reflected in the file contents + data[] = '\n'; + + mmfile.flush(); + + assert(std.file.read(deleteme) == "\n\n\n\n\n"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_numeric.d b/libphobos/testsuite/libphobos.phobos/std_numeric.d new file mode 100644 index 0000000000000000000000000000000000000000..e88b5e5b2d5f767de9611271dfd1b632c82b7a34 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_numeric.d @@ -0,0 +1,203 @@ +@safe unittest +{ + import std.numeric; + + import std.math.trigonometry : sin, cos; + + // Define a 16-bit floating point values + CustomFloat!16 x; // Using the number of bits + CustomFloat!(10, 5) y; // Using the precision and exponent width + CustomFloat!(10, 5,CustomFloatFlags.ieee) z; // Using the precision, exponent width and format flags + CustomFloat!(10, 5,CustomFloatFlags.ieee, 15) w; // Using the precision, exponent width, format flags and exponent offset bias + + // Use the 16-bit floats mostly like normal numbers + w = x*y - 1; + + // Functions calls require conversion + z = sin(+x) + cos(+y); // Use unary plus to concisely convert to a real + z = sin(x.get!float) + cos(y.get!float); // Or use get!T + z = sin(cast(float) x) + cos(cast(float) y); // Or use cast(T) to explicitly convert + + // Define a 8-bit custom float for storing probabilities + alias Probability = CustomFloat!(4, 4, CustomFloatFlags.ieee^CustomFloatFlags.probability^CustomFloatFlags.signed ); + auto p = Probability(0.5); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + + // Average numbers in an array + double avg(in double[] a) + { + if (a.length == 0) return 0; + FPTemporary!double result = 0; + foreach (e; a) result += e; + return result / a.length; + } + + auto a = [1.0, 2.0, 3.0]; + assert(isClose(avg(a), 2)); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + import std.math.trigonometry : cos; + + float f(float x) + { + return cos(x) - x*x*x; + } + auto x = secantMethod!(f)(0f, 1f); + assert(isClose(x, 0.865474)); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + + auto ret = findLocalMin((double x) => (x-4)^^2, -1e7, 1e7); + assert(ret.x.isClose(4.0)); + assert(ret.y.isClose(0.0, 0.0, 1e-10)); +} + +@safe unittest +{ + import std.numeric; + + double[] a = []; + assert(!normalize(a)); + a = [ 1.0, 3.0 ]; + assert(normalize(a)); + assert(a == [ 0.25, 0.75 ]); + assert(normalize!(typeof(a))(a, 50)); // a = [12.5, 37.5] + a = [ 0.0, 0.0 ]; + assert(!normalize(a)); + assert(a == [ 0.5, 0.5 ]); +} + +@safe unittest +{ + import std.numeric; + + import std.math.traits : isNaN; + + assert(sumOfLog2s(new double[0]) == 0); + assert(sumOfLog2s([0.0L]) == -real.infinity); + assert(sumOfLog2s([-0.0L]) == -real.infinity); + assert(sumOfLog2s([2.0L]) == 1); + assert(sumOfLog2s([-2.0L]).isNaN()); + assert(sumOfLog2s([real.nan]).isNaN()); + assert(sumOfLog2s([-real.nan]).isNaN()); + assert(sumOfLog2s([real.infinity]) == real.infinity); + assert(sumOfLog2s([-real.infinity]).isNaN()); + assert(sumOfLog2s([ 0.25, 0.25, 0.25, 0.125 ]) == -9); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + + double[] p = [ 0.0, 0, 0, 1 ]; + assert(kullbackLeiblerDivergence(p, p) == 0); + double[] p1 = [ 0.25, 0.25, 0.25, 0.25 ]; + assert(kullbackLeiblerDivergence(p1, p1) == 0); + assert(kullbackLeiblerDivergence(p, p1) == 2); + assert(kullbackLeiblerDivergence(p1, p) == double.infinity); + double[] p2 = [ 0.2, 0.2, 0.2, 0.4 ]; + assert(isClose(kullbackLeiblerDivergence(p1, p2), 0.0719281, 1e-5)); + assert(isClose(kullbackLeiblerDivergence(p2, p1), 0.0780719, 1e-5)); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + + double[] p = [ 0.0, 0, 0, 1 ]; + assert(jensenShannonDivergence(p, p) == 0); + double[] p1 = [ 0.25, 0.25, 0.25, 0.25 ]; + assert(jensenShannonDivergence(p1, p1) == 0); + assert(isClose(jensenShannonDivergence(p1, p), 0.548795, 1e-5)); + double[] p2 = [ 0.2, 0.2, 0.2, 0.4 ]; + assert(isClose(jensenShannonDivergence(p1, p2), 0.0186218, 1e-5)); + assert(isClose(jensenShannonDivergence(p2, p1), 0.0186218, 1e-5)); + assert(isClose(jensenShannonDivergence(p2, p1, 0.005), 0.00602366, 1e-5)); +} + +@system unittest +{ + import std.numeric; + + import std.math.operations : isClose; + import std.math.algebraic : sqrt; + + string[] s = ["Hello", "brave", "new", "world"]; + string[] t = ["Hello", "new", "world"]; + assert(gapWeightedSimilarity(s, s, 1) == 15); + assert(gapWeightedSimilarity(t, t, 1) == 7); + assert(gapWeightedSimilarity(s, t, 1) == 7); + assert(isClose(gapWeightedSimilarityNormalized(s, t, 1), + 7.0 / sqrt(15.0 * 7), 0.01)); +} + +@system unittest +{ + import std.numeric; + + string[] s = ["Hello", "brave", "new", "world"]; + string[] t = ["Hello", "new", "world"]; + auto simIter = gapWeightedSimilarityIncremental(s, t, 1.0); + assert(simIter.front == 3); // three 1-length matches + simIter.popFront(); + assert(simIter.front == 3); // three 2-length matches + simIter.popFront(); + assert(simIter.front == 1); // one 3-length match + simIter.popFront(); + assert(simIter.empty); // no more match +} + +@safe unittest +{ + import std.numeric; + + assert(gcd(2 * 5 * 7 * 7, 5 * 7 * 11) == 5 * 7); + const int a = 5 * 13 * 23 * 23, b = 13 * 59; + assert(gcd(a, b) == 13); +} + +@safe unittest +{ + import std.numeric; + + assert(lcm(1, 2) == 2); + assert(lcm(3, 4) == 12); + assert(lcm(5, 6) == 30); +} + +@safe pure @nogc unittest +{ + import std.numeric; + + ubyte[21] fac; + size_t idx = decimalToFactorial(2982, fac); + + assert(fac[0] == 4); + assert(fac[1] == 0); + assert(fac[2] == 4); + assert(fac[3] == 1); + assert(fac[4] == 0); + assert(fac[5] == 0); + assert(fac[6] == 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_outbuffer.d b/libphobos/testsuite/libphobos.phobos/std_outbuffer.d new file mode 100644 index 0000000000000000000000000000000000000000..fd0d9b7cf756112e0fd478b35e2e0358f31fde9a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_outbuffer.d @@ -0,0 +1,95 @@ +@safe unittest +{ + import std.outbuffer; + + OutBuffer buf = new OutBuffer(); + buf.write(cast(ubyte) 1); + buf.align2(); + assert(buf.toBytes() == "\x01\x00"); + buf.write(cast(ubyte) 2); + buf.align4(); + assert(buf.toBytes() == "\x01\x00\x02\x00"); + buf.write(cast(ubyte) 3); + buf.alignSize(8); + assert(buf.toBytes() == "\x01\x00\x02\x00\x03\x00\x00\x00"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer buf = new OutBuffer(); + buf.write(cast(ubyte) 1); + buf.align2(0x55); + assert(buf.toBytes() == "\x01\x55"); + buf.write(cast(ubyte) 2); + buf.align4(0x55); + assert(buf.toBytes() == "\x01\x55\x02\x55"); + buf.write(cast(ubyte) 3); + buf.alignSize(8, 0x55); + assert(buf.toBytes() == "\x01\x55\x02\x55\x03\x55\x55\x55"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer b = new OutBuffer(); + b.writef("a%sb", 16); + assert(b.toString() == "a16b"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer b = new OutBuffer(); + b.writef!"a%sb"(16); + assert(b.toString() == "a16b"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer b = new OutBuffer(); + b.writefln("a%sb", 16); + assert(b.toString() == "a16b\n"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer b = new OutBuffer(); + b.writefln!"a%sb"(16); + assert(b.toString() == "a16b\n"); + +} + +@safe unittest +{ + import std.outbuffer; + + import std.string : cmp; + + OutBuffer buf = new OutBuffer(); + + assert(buf.offset == 0); + buf.write("hello"); + buf.write(cast(byte) 0x20); + buf.write("world"); + buf.writef(" %d", 62665); + assert(cmp(buf.toString(), "hello world 62665") == 0); + + buf.clear(); + assert(cmp(buf.toString(), "") == 0); + buf.write("New data"); + assert(cmp(buf.toString(),"New data") == 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_package.d b/libphobos/testsuite/libphobos.phobos/std_package.d new file mode 100644 index 0000000000000000000000000000000000000000..46a4f866484cda49db46bafb05358ae9b76b254f --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_package.d @@ -0,0 +1,27 @@ +@safe unittest +{ + import std; + + import std; + + int len; + const r = 6.iota + .filter!(a => a % 2) // 1 3 5 + .map!(a => a * 2) // 2 6 10 + .tee!(_ => len++) + .substitute(6, -6) // 2 -6 10 + .sum + .reverseArgs!format("Sum: %d"); + + assert(len == 3); + assert(r == "Sum: 6"); +} + +@safe unittest +{ + import std; + + import std; + assert(10.iota.map!(a => pow(2, a)).sum == 1023); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_parallelism.d b/libphobos/testsuite/libphobos.phobos/std_parallelism.d new file mode 100644 index 0000000000000000000000000000000000000000..18418ac2a43ceb6a17405532245c8da3d655a779 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_parallelism.d @@ -0,0 +1,37 @@ +@system unittest +{ + import std.parallelism; + + import std.algorithm.iteration : map; + import std.math.operations : isClose; + import std.parallelism : taskPool; + import std.range : iota; + + // Parallel reduce can be combined with + // std.algorithm.iteration.map to interesting effect. + // The following example (thanks to Russel Winder) + // calculates pi by quadrature using + // std.algorithm.map and TaskPool.reduce. + // getTerm is evaluated in parallel as needed by + // TaskPool.reduce. + // + // Timings on an Intel i5-3450 quad core machine + // for n = 1_000_000_000: + // + // TaskPool.reduce: 1.067 s + // std.algorithm.reduce: 4.011 s + + enum n = 1_000_000; + enum delta = 1.0 / n; + + alias getTerm = (int i) + { + immutable x = ( i - 0.5 ) * delta; + return delta / ( 1.0 + x * x ) ; + }; + + immutable pi = 4.0 * taskPool.reduce!"a + b"(n.iota.map!getTerm); + + assert(pi.isClose(3.14159, 1e-5)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_path.d b/libphobos/testsuite/libphobos.phobos/std_path.d new file mode 100644 index 0000000000000000000000000000000000000000..33ca98755190dfddbe4a8f214bd384a9a7ecf61d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_path.d @@ -0,0 +1,611 @@ +@safe pure nothrow @nogc unittest +{ + import std.path; + + version (Windows) + { + assert( '/'.isDirSeparator); + assert( '\\'.isDirSeparator); + } + else + { + assert( '/'.isDirSeparator); + assert(!'\\'.isDirSeparator); + } +} + +@safe unittest +{ + import std.path; + + assert(baseName!(CaseSensitive.no)("dir/file.EXT", ".ext") == "file"); + assert(baseName!(CaseSensitive.yes)("dir/file.EXT", ".ext") != "file"); + + version (Posix) + assert(relativePath!(CaseSensitive.no)("/FOO/bar", "/foo/baz") == "../bar"); + else + assert(relativePath!(CaseSensitive.no)(`c:\FOO\bar`, `c:\foo\baz`) == `..\bar`); +} + +@safe unittest +{ + import std.path; + + assert(baseName("dir/file.ext") == "file.ext"); + assert(baseName("dir/file.ext", ".ext") == "file"); + assert(baseName("dir/file.ext", ".xyz") == "file.ext"); + assert(baseName("dir/filename", "name") == "file"); + assert(baseName("dir/subdir/") == "subdir"); + + version (Windows) + { + assert(baseName(`d:file.ext`) == "file.ext"); + assert(baseName(`d:\dir\file.ext`) == "file.ext"); + } +} + +@safe unittest +{ + import std.path; + + assert(dirName("") == "."); + assert(dirName("file"w) == "."); + assert(dirName("dir/"d) == "."); + assert(dirName("dir///") == "."); + assert(dirName("dir/file"w.dup) == "dir"); + assert(dirName("dir///file"d.dup) == "dir"); + assert(dirName("dir/subdir/") == "dir"); + assert(dirName("/dir/file"w) == "/dir"); + assert(dirName("/file"d) == "/"); + assert(dirName("/") == "/"); + assert(dirName("///") == "/"); + + version (Windows) + { + assert(dirName(`dir\`) == `.`); + assert(dirName(`dir\\\`) == `.`); + assert(dirName(`dir\file`) == `dir`); + assert(dirName(`dir\\\file`) == `dir`); + assert(dirName(`dir\subdir\`) == `dir`); + assert(dirName(`\dir\file`) == `\dir`); + assert(dirName(`\file`) == `\`); + assert(dirName(`\`) == `\`); + assert(dirName(`\\\`) == `\`); + assert(dirName(`d:`) == `d:`); + assert(dirName(`d:file`) == `d:`); + assert(dirName(`d:\`) == `d:\`); + assert(dirName(`d:\file`) == `d:\`); + assert(dirName(`d:\dir\file`) == `d:\dir`); + assert(dirName(`\\server\share\dir\file`) == `\\server\share\dir`); + assert(dirName(`\\server\share\file`) == `\\server\share`); + assert(dirName(`\\server\share\`) == `\\server\share`); + assert(dirName(`\\server\share`) == `\\server\share`); + } +} + +@safe unittest +{ + import std.path; + + assert(rootName("") is null); + assert(rootName("foo") is null); + assert(rootName("/") == "/"); + assert(rootName("/foo/bar") == "/"); + + version (Windows) + { + assert(rootName("d:foo") is null); + assert(rootName(`d:\foo`) == `d:\`); + assert(rootName(`\\server\share\foo`) == `\\server\share`); + assert(rootName(`\\server\share`) == `\\server\share`); + } +} + +@safe unittest +{ + import std.path; + + import std.range : empty; + version (Posix) assert(driveName("c:/foo").empty); + version (Windows) + { + assert(driveName(`dir\file`).empty); + assert(driveName(`d:file`) == "d:"); + assert(driveName(`d:\file`) == "d:"); + assert(driveName("d:") == "d:"); + assert(driveName(`\\server\share\file`) == `\\server\share`); + assert(driveName(`\\server\share\`) == `\\server\share`); + assert(driveName(`\\server\share`) == `\\server\share`); + + static assert(driveName(`d:\file`) == "d:"); + } +} + +@safe unittest +{ + import std.path; + + version (Windows) + { + assert(stripDrive(`d:\dir\file`) == `\dir\file`); + assert(stripDrive(`\\server\share\dir\file`) == `\dir\file`); + } +} + +@safe unittest +{ + import std.path; + + import std.range : empty; + assert(extension("file").empty); + assert(extension("file.") == "."); + assert(extension("file.ext"w) == ".ext"); + assert(extension("file.ext1.ext2"d) == ".ext2"); + assert(extension(".foo".dup).empty); + assert(extension(".foo.ext"w.dup) == ".ext"); + + static assert(extension("file").empty); + static assert(extension("file.ext") == ".ext"); +} + +@safe unittest +{ + import std.path; + + assert(stripExtension("file") == "file"); + assert(stripExtension("file.ext") == "file"); + assert(stripExtension("file.ext1.ext2") == "file.ext1"); + assert(stripExtension("file.") == "file"); + assert(stripExtension(".file") == ".file"); + assert(stripExtension(".file.ext") == ".file"); + assert(stripExtension("dir/file.ext") == "dir/file"); +} + +@safe unittest +{ + import std.path; + + assert(setExtension("file", "ext") == "file.ext"); + assert(setExtension("file"w, ".ext"w) == "file.ext"); + assert(setExtension("file."d, "ext"d) == "file.ext"); + assert(setExtension("file.", ".ext") == "file.ext"); + assert(setExtension("file.old"w, "new"w) == "file.new"); + assert(setExtension("file.old"d, ".new"d) == "file.new"); +} + +@safe unittest +{ + import std.path; + + import std.array; + assert(withExtension("file", "ext").array == "file.ext"); + assert(withExtension("file"w, ".ext"w).array == "file.ext"); + assert(withExtension("file.ext"w, ".").array == "file."); + + import std.utf : byChar, byWchar; + assert(withExtension("file".byChar, "ext").array == "file.ext"); + assert(withExtension("file"w.byWchar, ".ext"w).array == "file.ext"w); + assert(withExtension("file.ext"w.byWchar, ".").array == "file."w); +} + +@safe unittest +{ + import std.path; + + assert(defaultExtension("file", "ext") == "file.ext"); + assert(defaultExtension("file", ".ext") == "file.ext"); + assert(defaultExtension("file.", "ext") == "file."); + assert(defaultExtension("file.old", "new") == "file.old"); + assert(defaultExtension("file.old", ".new") == "file.old"); +} + +@safe unittest +{ + import std.path; + + import std.array; + assert(withDefaultExtension("file", "ext").array == "file.ext"); + assert(withDefaultExtension("file"w, ".ext").array == "file.ext"w); + assert(withDefaultExtension("file.", "ext").array == "file."); + assert(withDefaultExtension("file", "").array == "file."); + + import std.utf : byChar, byWchar; + assert(withDefaultExtension("file".byChar, "ext").array == "file.ext"); + assert(withDefaultExtension("file"w.byWchar, ".ext").array == "file.ext"w); + assert(withDefaultExtension("file.".byChar, "ext"d).array == "file."); + assert(withDefaultExtension("file".byChar, "").array == "file."); +} + +@safe unittest +{ + import std.path; + + version (Posix) + { + assert(buildPath("foo", "bar", "baz") == "foo/bar/baz"); + assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz"); + assert(buildPath("/foo", "/bar") == "/bar"); + } + + version (Windows) + { + assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`); + assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`); + assert(buildPath("foo", `d:\bar`) == `d:\bar`); + assert(buildPath("foo", `\bar`) == `\bar`); + assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`); + } +} + +@safe unittest +{ + import std.path; + + import std.array; + version (Posix) + { + assert(chainPath("foo", "bar", "baz").array == "foo/bar/baz"); + assert(chainPath("/foo/", "bar/baz").array == "/foo/bar/baz"); + assert(chainPath("/foo", "/bar").array == "/bar"); + } + + version (Windows) + { + assert(chainPath("foo", "bar", "baz").array == `foo\bar\baz`); + assert(chainPath(`c:\foo`, `bar\baz`).array == `c:\foo\bar\baz`); + assert(chainPath("foo", `d:\bar`).array == `d:\bar`); + assert(chainPath("foo", `\bar`).array == `\bar`); + assert(chainPath(`c:\foo`, `\bar`).array == `c:\bar`); + } + + import std.utf : byChar; + version (Posix) + { + assert(chainPath("foo", "bar", "baz").array == "foo/bar/baz"); + assert(chainPath("/foo/".byChar, "bar/baz").array == "/foo/bar/baz"); + assert(chainPath("/foo", "/bar".byChar).array == "/bar"); + } + + version (Windows) + { + assert(chainPath("foo", "bar", "baz").array == `foo\bar\baz`); + assert(chainPath(`c:\foo`.byChar, `bar\baz`).array == `c:\foo\bar\baz`); + assert(chainPath("foo", `d:\bar`).array == `d:\bar`); + assert(chainPath("foo", `\bar`.byChar).array == `\bar`); + assert(chainPath(`c:\foo`, `\bar`w).array == `c:\bar`); + } +} + +@safe unittest +{ + import std.path; + + assert(buildNormalizedPath("foo", "..") == "."); + + version (Posix) + { + assert(buildNormalizedPath("/foo/./bar/..//baz/") == "/foo/baz"); + assert(buildNormalizedPath("../foo/.") == "../foo"); + assert(buildNormalizedPath("/foo", "bar/baz/") == "/foo/bar/baz"); + assert(buildNormalizedPath("/foo", "/bar/..", "baz") == "/baz"); + assert(buildNormalizedPath("foo/./bar", "../../", "../baz") == "../baz"); + assert(buildNormalizedPath("/foo/./bar", "../../baz") == "/baz"); + } + + version (Windows) + { + assert(buildNormalizedPath(`c:\foo\.\bar/..\\baz\`) == `c:\foo\baz`); + assert(buildNormalizedPath(`..\foo\.`) == `..\foo`); + assert(buildNormalizedPath(`c:\foo`, `bar\baz\`) == `c:\foo\bar\baz`); + assert(buildNormalizedPath(`c:\foo`, `bar/..`) == `c:\foo`); + assert(buildNormalizedPath(`\\server\share\foo`, `..\bar`) == + `\\server\share\bar`); + } +} + +@safe unittest +{ + import std.path; + + import std.array; + assert(asNormalizedPath("foo/..").array == "."); + + version (Posix) + { + assert(asNormalizedPath("/foo/./bar/..//baz/").array == "/foo/baz"); + assert(asNormalizedPath("../foo/.").array == "../foo"); + assert(asNormalizedPath("/foo/bar/baz/").array == "/foo/bar/baz"); + assert(asNormalizedPath("/foo/./bar/../../baz").array == "/baz"); + } + + version (Windows) + { + assert(asNormalizedPath(`c:\foo\.\bar/..\\baz\`).array == `c:\foo\baz`); + assert(asNormalizedPath(`..\foo\.`).array == `..\foo`); + assert(asNormalizedPath(`c:\foo\bar\baz\`).array == `c:\foo\bar\baz`); + assert(asNormalizedPath(`c:\foo\bar/..`).array == `c:\foo`); + assert(asNormalizedPath(`\\server\share\foo\..\bar`).array == + `\\server\share\bar`); + } +} + +@safe unittest +{ + import std.path; + + import std.algorithm.comparison : equal; + import std.conv : to; + + assert(equal(pathSplitter("/"), ["/"])); + assert(equal(pathSplitter("/foo/bar"), ["/", "foo", "bar"])); + assert(equal(pathSplitter("foo/../bar//./"), ["foo", "..", "bar", "."])); + + version (Posix) + { + assert(equal(pathSplitter("//foo/bar"), ["/", "foo", "bar"])); + } + + version (Windows) + { + assert(equal(pathSplitter(`foo\..\bar\/.\`), ["foo", "..", "bar", "."])); + assert(equal(pathSplitter("c:"), ["c:"])); + assert(equal(pathSplitter(`c:\foo\bar`), [`c:\`, "foo", "bar"])); + assert(equal(pathSplitter(`c:foo\bar`), ["c:foo", "bar"])); + } +} + +@safe unittest +{ + import std.path; + + version (Posix) + { + assert( isRooted("/")); + assert( isRooted("/foo")); + assert(!isRooted("foo")); + assert(!isRooted("../foo")); + } + + version (Windows) + { + assert( isRooted(`\`)); + assert( isRooted(`\foo`)); + assert( isRooted(`d:\foo`)); + assert( isRooted(`\\foo\bar`)); + assert(!isRooted("foo")); + assert(!isRooted("d:foo")); + } +} + +@safe unittest +{ + import std.path; + + version (Posix) + { + assert(absolutePath("some/file", "/foo/bar") == "/foo/bar/some/file"); + assert(absolutePath("../file", "/foo/bar") == "/foo/bar/../file"); + assert(absolutePath("/some/file", "/foo/bar") == "/some/file"); + } + + version (Windows) + { + assert(absolutePath(`some\file`, `c:\foo\bar`) == `c:\foo\bar\some\file`); + assert(absolutePath(`..\file`, `c:\foo\bar`) == `c:\foo\bar\..\file`); + assert(absolutePath(`c:\some\file`, `c:\foo\bar`) == `c:\some\file`); + assert(absolutePath(`\`, `c:\`) == `c:\`); + assert(absolutePath(`\some\file`, `c:\foo\bar`) == `c:\some\file`); + } +} + +@system unittest +{ + import std.path; + + import std.array; + assert(asAbsolutePath(cast(string) null).array == ""); + version (Posix) + { + assert(asAbsolutePath("/foo").array == "/foo"); + } + version (Windows) + { + assert(asAbsolutePath("c:/foo").array == "c:/foo"); + } + asAbsolutePath("foo"); +} + +@safe unittest +{ + import std.path; + + assert(relativePath("foo") == "foo"); + + version (Posix) + { + assert(relativePath("foo", "/bar") == "foo"); + assert(relativePath("/foo/bar", "/foo/bar") == "."); + assert(relativePath("/foo/bar", "/foo/baz") == "../bar"); + assert(relativePath("/foo/bar/baz", "/foo/woo/wee") == "../../bar/baz"); + assert(relativePath("/foo/bar/baz", "/foo/bar") == "baz"); + } + version (Windows) + { + assert(relativePath("foo", `c:\bar`) == "foo"); + assert(relativePath(`c:\foo\bar`, `c:\foo\bar`) == "."); + assert(relativePath(`c:\foo\bar`, `c:\foo\baz`) == `..\bar`); + assert(relativePath(`c:\foo\bar\baz`, `c:\foo\woo\wee`) == `..\..\bar\baz`); + assert(relativePath(`c:\foo\bar\baz`, `c:\foo\bar`) == "baz"); + assert(relativePath(`c:\foo\bar`, `d:\foo`) == `c:\foo\bar`); + } +} + +@safe unittest +{ + import std.path; + + import std.array; + version (Posix) + { + assert(asRelativePath("foo", "/bar").array == "foo"); + assert(asRelativePath("/foo/bar", "/foo/bar").array == "."); + assert(asRelativePath("/foo/bar", "/foo/baz").array == "../bar"); + assert(asRelativePath("/foo/bar/baz", "/foo/woo/wee").array == "../../bar/baz"); + assert(asRelativePath("/foo/bar/baz", "/foo/bar").array == "baz"); + } + else version (Windows) + { + assert(asRelativePath("foo", `c:\bar`).array == "foo"); + assert(asRelativePath(`c:\foo\bar`, `c:\foo\bar`).array == "."); + assert(asRelativePath(`c:\foo\bar`, `c:\foo\baz`).array == `..\bar`); + assert(asRelativePath(`c:\foo\bar\baz`, `c:\foo\woo\wee`).array == `..\..\bar\baz`); + assert(asRelativePath(`c:/foo/bar/baz`, `c:\foo\woo\wee`).array == `..\..\bar\baz`); + assert(asRelativePath(`c:\foo\bar\baz`, `c:\foo\bar`).array == "baz"); + assert(asRelativePath(`c:\foo\bar`, `d:\foo`).array == `c:\foo\bar`); + assert(asRelativePath(`\\foo\bar`, `c:\foo`).array == `\\foo\bar`); + } + else + static assert(0); +} + +@safe unittest +{ + import std.path; + + assert(filenameCharCmp('a', 'a') == 0); + assert(filenameCharCmp('a', 'b') < 0); + assert(filenameCharCmp('b', 'a') > 0); + + version (linux) + { + // Same as calling filenameCharCmp!(CaseSensitive.yes)(a, b) + assert(filenameCharCmp('A', 'a') < 0); + assert(filenameCharCmp('a', 'A') > 0); + } + version (Windows) + { + // Same as calling filenameCharCmp!(CaseSensitive.no)(a, b) + assert(filenameCharCmp('a', 'A') == 0); + assert(filenameCharCmp('a', 'B') < 0); + assert(filenameCharCmp('A', 'b') < 0); + } +} + +@safe unittest +{ + import std.path; + + assert(filenameCmp("abc", "abc") == 0); + assert(filenameCmp("abc", "abd") < 0); + assert(filenameCmp("abc", "abb") > 0); + assert(filenameCmp("abc", "abcd") < 0); + assert(filenameCmp("abcd", "abc") > 0); + + version (linux) + { + // Same as calling filenameCmp!(CaseSensitive.yes)(filename1, filename2) + assert(filenameCmp("Abc", "abc") < 0); + assert(filenameCmp("abc", "Abc") > 0); + } + version (Windows) + { + // Same as calling filenameCmp!(CaseSensitive.no)(filename1, filename2) + assert(filenameCmp("Abc", "abc") == 0); + assert(filenameCmp("abc", "Abc") == 0); + assert(filenameCmp("Abc", "abD") < 0); + assert(filenameCmp("abc", "AbB") > 0); + } +} + +@safe @nogc unittest +{ + import std.path; + + assert(globMatch("foo.bar", "*")); + assert(globMatch("foo.bar", "*.*")); + assert(globMatch(`foo/foo\bar`, "f*b*r")); + assert(globMatch("foo.bar", "f???bar")); + assert(globMatch("foo.bar", "[fg]???bar")); + assert(globMatch("foo.bar", "[!gh]*bar")); + assert(globMatch("bar.fooz", "bar.{foo,bif}z")); + assert(globMatch("bar.bifz", "bar.{foo,bif}z")); + + version (Windows) + { + // Same as calling globMatch!(CaseSensitive.no)(path, pattern) + assert(globMatch("foo", "Foo")); + assert(globMatch("Goo.bar", "[fg]???bar")); + } + version (linux) + { + // Same as calling globMatch!(CaseSensitive.yes)(path, pattern) + assert(!globMatch("foo", "Foo")); + assert(!globMatch("Goo.bar", "[fg]???bar")); + } +} + +@safe pure @nogc nothrow unittest +{ + import std.path; + + import std.utf : byCodeUnit; + + assert(isValidFilename("hello.exe".byCodeUnit)); +} + +@safe pure @nogc nothrow unittest +{ + import std.path; + + assert(isValidPath("/foo/bar")); + assert(!isValidPath("/foo\0/bar")); + assert(isValidPath("/")); + assert(isValidPath("a")); + + version (Windows) + { + assert(isValidPath(`c:\`)); + assert(isValidPath(`c:\foo`)); + assert(isValidPath(`c:\foo\.\bar\\\..\`)); + assert(!isValidPath(`!:\foo`)); + assert(!isValidPath(`c::\foo`)); + assert(!isValidPath(`c:\foo?`)); + assert(!isValidPath(`c:\foo.`)); + + assert(isValidPath(`\\server\share`)); + assert(isValidPath(`\\server\share\foo`)); + assert(isValidPath(`\\server\share\\foo`)); + assert(!isValidPath(`\\\server\share\foo`)); + assert(!isValidPath(`\\server\\share\foo`)); + assert(!isValidPath(`\\ser*er\share\foo`)); + assert(!isValidPath(`\\server\sha?e\foo`)); + assert(!isValidPath(`\\server\share\|oo`)); + + assert(isValidPath(`\\?\<>:"?*|/\..\.`)); + assert(!isValidPath("\\\\?\\foo\0bar")); + + assert(!isValidPath(`\\.\PhysicalDisk1`)); + assert(!isValidPath(`\\`)); + } + + import std.utf : byCodeUnit; + assert(isValidPath("/foo/bar".byCodeUnit)); +} + +@safe unittest +{ + import std.path; + + version (Posix) + { + import std.process : environment; + + auto oldHome = environment["HOME"]; + scope(exit) environment["HOME"] = oldHome; + + environment["HOME"] = "dmd/test"; + assert(expandTilde("~/") == "dmd/test/"); + assert(expandTilde("~") == "dmd/test"); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_random.d b/libphobos/testsuite/libphobos.phobos/std_random.d new file mode 100644 index 0000000000000000000000000000000000000000..89147d3129554a41b12f7a77d84c2f470330c16e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_random.d @@ -0,0 +1,578 @@ +@safe unittest +{ + import std.random; + + import std.algorithm.comparison : among, equal; + import std.range : iota; + + // seed a random generator with a constant + auto rnd = Random(42); + + // Generate a uniformly-distributed integer in the range [0, 14] + // If no random generator is passed, the global `rndGen` would be used + auto i = uniform(0, 15, rnd); + assert(i >= 0 && i < 15); + + // Generate a uniformly-distributed real in the range [0, 100) + auto r = uniform(0.0L, 100.0L, rnd); + assert(r >= 0 && r < 100); + + // Sample from a custom type + enum Fruit { apple, mango, pear } + auto f = rnd.uniform!Fruit; + with(Fruit) + assert(f.among(apple, mango, pear)); + + // Generate a 32-bit random number + auto u = uniform!uint(rnd); + static assert(is(typeof(u) == uint)); + + // Generate a random number in the range in the range [0, 1) + auto u2 = uniform01(rnd); + assert(u2 >= 0 && u2 < 1); + + // Select an element randomly + auto el = 10.iota.choice(rnd); + assert(0 <= el && el < 10); + + // Throw a dice with custom proportions + // 0: 20%, 1: 10%, 2: 60% + auto val = rnd.dice(0.2, 0.1, 0.6); + assert(0 <= val && val <= 2); + + auto rnd2 = MinstdRand0(42); + + // Select a random subsample from a range + assert(10.iota.randomSample(3, rnd2).equal([7, 8, 9])); + + // Cover all elements in an array in random order + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(10.iota.randomCover(rnd2).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5])); + else + assert(10.iota.randomCover(rnd2).equal([4, 8, 7, 3, 5, 9, 2, 6, 0, 1])); + + // Shuffle an array + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([2, 0, 4, 5, 1])); + else + assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([4, 2, 5, 0, 1])); +} + +@safe unittest +{ + import std.random; + + struct NoRng + { + @property uint front() {return 0;} + @property bool empty() {return false;} + void popFront() {} + } + static assert(!isUniformRNG!(NoRng)); + + struct validRng + { + @property uint front() {return 0;} + @property bool empty() {return false;} + void popFront() {} + + enum isUniformRandom = true; + } + static assert(isUniformRNG!(validRng, uint)); + static assert(isUniformRNG!(validRng)); +} + +@safe unittest +{ + import std.random; + + struct validRng + { + @property uint front() {return 0;} + @property bool empty() {return false;} + void popFront() {} + + enum isUniformRandom = true; + } + static assert(!isSeedable!(validRng, uint)); + static assert(!isSeedable!(validRng)); + + struct seedRng + { + @property uint front() {return 0;} + @property bool empty() {return false;} + void popFront() {} + void seed(uint val){} + enum isUniformRandom = true; + } + static assert(isSeedable!(seedRng, uint)); + static assert(!isSeedable!(seedRng, ulong)); + static assert(isSeedable!(seedRng)); +} + +@safe unittest +{ + import std.random; + + alias CPP11LCG = LinearCongruentialEngine!(uint, 48271, 0, 2_147_483_647); + + // seed with a constant + auto rnd = CPP11LCG(42); + auto n = rnd.front; // same for each run + assert(n == 2027382); +} + +@safe unittest +{ + import std.random; + + // glibc's LCG + alias GLibcLCG = LinearCongruentialEngine!(uint, 1103515245, 12345, 2_147_483_648); + + // Seed with an unpredictable value + auto rnd = GLibcLCG(unpredictableSeed); + auto n = rnd.front; // different across runs +} + +@safe unittest +{ + import std.random; + + // Visual C++'s LCG + alias MSVCLCG = LinearCongruentialEngine!(uint, 214013, 2531011, 0); + + // seed with a constant + auto rnd = MSVCLCG(1); + auto n = rnd.front; // same for each run + assert(n == 2745024); +} + +@safe @nogc unittest +{ + import std.random; + + // seed with a constant + auto rnd0 = MinstdRand0(1); + auto n = rnd0.front; + // same for each run + assert(n == 16807); + + // Seed with an unpredictable value + rnd0.seed(unpredictableSeed); + n = rnd0.front; // different across runs +} + +@safe unittest +{ + import std.random; + + // seed with a constant + Mt19937 gen; + auto n = gen.front; // same for each run + assert(n == 3499211612); + + // Seed with an unpredictable value + gen.seed(unpredictableSeed); + n = gen.front; // different across runs +} + +@safe @nogc unittest +{ + import std.random; + + // seed with a constant + Mt19937 gen; + auto n = gen.front; // same for each run + assert(n == 3499211612); + + // Seed with an unpredictable value + gen.seed(unpredictableSeed); + n = gen.front; // different across runs +} + +@safe @nogc unittest +{ + import std.random; + + // Seed with a constant + auto gen = Mt19937_64(12345); + auto n = gen.front; // same for each run + assert(n == 6597103971274460346); + + // Seed with an unpredictable value + gen.seed(unpredictableSeed!ulong); + n = gen.front; // different across runs +} + +@safe unittest +{ + import std.random; + + alias Xorshift96 = XorshiftEngine!(uint, 96, 10, 5, 26); + auto rnd = Xorshift96(42); + auto num = rnd.front; // same for each run + assert(num == 2704588748); +} + +@safe @nogc unittest +{ + import std.random; + + // Seed with a constant + auto rnd = Xorshift(1); + auto num = rnd.front; // same for each run + assert(num == 1405313047); + + // Seed with an unpredictable value + rnd.seed(unpredictableSeed); + num = rnd.front; // different across rnd +} + +@safe @nogc unittest +{ + import std.random; + + auto rnd = Random(unpredictableSeed); + auto n = rnd.front; + static assert(is(typeof(n) == uint)); +} + +@safe nothrow @nogc unittest +{ + import std.random; + + import std.algorithm.iteration : sum; + import std.range : take; + auto rnd = rndGen; + assert(rnd.take(3).sum > 0); +} + +@safe unittest +{ + import std.random; + + auto rnd = Random(unpredictableSeed); + + // Generate an integer in [0, 1023] + auto a = uniform(0, 1024, rnd); + assert(0 <= a && a < 1024); + + // Generate a float in [0, 1) + auto b = uniform(0.0f, 1.0f, rnd); + assert(0 <= b && b < 1); + + // Generate a float in [0, 1] + b = uniform!"[]"(0.0f, 1.0f, rnd); + assert(0 <= b && b <= 1); + + // Generate a float in (0, 1) + b = uniform!"()"(0.0f, 1.0f, rnd); + assert(0 < b && b < 1); +} + +@safe unittest +{ + import std.random; + + import std.array : array; + import std.range : generate, takeExactly; + + int[] arr = generate!(() => uniform(0, 100)).takeExactly(10).array; + assert(arr.length == 10); + assert(arr[0] >= 0 && arr[0] < 100); +} + +@safe unittest +{ + import std.random; + + import std.conv : to; + import std.meta : AliasSeq; + import std.range.primitives : isForwardRange; + import std.traits : isIntegral, isSomeChar; + + auto gen = Mt19937(123_456_789); + static assert(isForwardRange!(typeof(gen))); + + auto a = uniform(0, 1024, gen); + assert(0 <= a && a <= 1024); + auto b = uniform(0.0f, 1.0f, gen); + assert(0 <= b && b < 1, to!string(b)); + auto c = uniform(0.0, 1.0); + assert(0 <= c && c < 1); + + static foreach (T; AliasSeq!(char, wchar, dchar, byte, ubyte, short, ushort, + int, uint, long, ulong, float, double, real)) + {{ + T lo = 0, hi = 100; + + // Try tests with each of the possible bounds + { + T init = uniform(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + { + T init = uniform!"[)"(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + { + T init = uniform!"(]"(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + { + T init = uniform!"()"(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + { + T init = uniform!"[]"(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + + /* Test case with closed boundaries covering whole range + * of integral type + */ + static if (isIntegral!T || isSomeChar!T) + { + foreach (immutable _; 0 .. 100) + { + auto u = uniform!"[]"(T.min, T.max); + static assert(is(typeof(u) == T)); + assert(T.min <= u, "Lower bound violation for uniform!\"[]\" with " ~ T.stringof); + assert(u <= T.max, "Upper bound violation for uniform!\"[]\" with " ~ T.stringof); + } + } + }} + + auto reproRng = Xorshift(239842); + + static foreach (T; AliasSeq!(char, wchar, dchar, byte, ubyte, short, + ushort, int, uint, long, ulong)) + {{ + T lo = T.min + 10, hi = T.max - 10; + T init = uniform(lo, hi, reproRng); + size_t i = 50; + while (--i && uniform(lo, hi, reproRng) == init) {} + assert(i > 0); + }} + + { + bool sawLB = false, sawUB = false; + foreach (i; 0 .. 50) + { + auto x = uniform!"[]"('a', 'd', reproRng); + if (x == 'a') sawLB = true; + if (x == 'd') sawUB = true; + assert('a' <= x && x <= 'd'); + } + assert(sawLB && sawUB); + } + + { + bool sawLB = false, sawUB = false; + foreach (i; 0 .. 50) + { + auto x = uniform('a', 'd', reproRng); + if (x == 'a') sawLB = true; + if (x == 'c') sawUB = true; + assert('a' <= x && x < 'd'); + } + assert(sawLB && sawUB); + } + + { + bool sawLB = false, sawUB = false; + foreach (i; 0 .. 50) + { + immutable int lo = -2, hi = 2; + auto x = uniform!"()"(lo, hi, reproRng); + if (x == (lo+1)) sawLB = true; + if (x == (hi-1)) sawUB = true; + assert(lo < x && x < hi); + } + assert(sawLB && sawUB); + } + + { + bool sawLB = false, sawUB = false; + foreach (i; 0 .. 50) + { + immutable ubyte lo = 0, hi = 5; + auto x = uniform(lo, hi, reproRng); + if (x == lo) sawLB = true; + if (x == (hi-1)) sawUB = true; + assert(lo <= x && x < hi); + } + assert(sawLB && sawUB); + } + + { + foreach (i; 0 .. 30) + { + assert(i == uniform(i, i+1, reproRng)); + } + } +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + + assert(rnd.uniform!ubyte == 102); + assert(rnd.uniform!ulong == 4838462006927449017); + + enum Fruit { apple, mango, pear } + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(rnd.uniform!Fruit == Fruit.mango); +} + +@safe @nogc unittest +{ + import std.random; + + import std.math.operations : feqrel; + + auto rnd = MinstdRand0(42); + + // Generate random numbers in the range in the range [0, 1) + auto u1 = uniform01(rnd); + assert(u1 >= 0 && u1 < 1); + + auto u2 = rnd.uniform01!float; + assert(u2 >= 0 && u2 < 1); + + // Confirm that the random values with the initial seed 42 are 0.000328707 and 0.524587 + assert(u1.feqrel(0.000328707) > 20); + assert(u2.feqrel(0.524587) > 20); +} + +@safe unittest +{ + import std.random; + + import std.algorithm.iteration : reduce; + import std.math.operations : isClose; + + auto a = uniformDistribution(5); + assert(a.length == 5); + assert(isClose(reduce!"a + b"(a), 1)); + + a = uniformDistribution(10, a); + assert(a.length == 10); + assert(isClose(reduce!"a + b"(a), 1)); +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + + auto elem = [1, 2, 3, 4, 5].choice(rnd); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(elem == 3); +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + + auto arr = [1, 2, 3, 4, 5].randomShuffle(rnd); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(arr == [3, 5, 2, 4, 1]); +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + + auto arr = [1, 2, 3, 4, 5, 6]; + arr = arr.dup.partialShuffle(1, rnd); + + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(arr == [2, 1, 3, 4, 5, 6]); // 1<->2 + + arr = arr.dup.partialShuffle(2, rnd); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(arr == [1, 4, 3, 2, 5, 6]); // 1<->2, 2<->4 + + arr = arr.dup.partialShuffle(3, rnd); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(arr == [5, 4, 6, 2, 1, 3]); // 1<->5, 2<->4, 3<->6 +} + +@safe unittest +{ + import std.random; + + auto d6 = 1 + dice(1, 1, 1, 1, 1, 1); // fair dice roll + auto d6b = 1 + dice(2, 1, 1, 1, 1, 1); // double the chance to roll '1' + + auto x = dice(0.5, 0.5); // x is 0 or 1 in equal proportions + auto y = dice(50, 50); // y is 0 or 1 in equal proportions + auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 20% of the time, + // and 2 10% of the time +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + auto z = rnd.dice(70, 20, 10); + assert(z == 0); + z = rnd.dice(30, 20, 40, 10); + assert(z == 2); +} + +@safe unittest +{ + import std.random; + + auto rnd = Xorshift(123_456_789); + auto i = dice(rnd, 0.0, 100.0); + assert(i == 1); + i = dice(rnd, 100.0, 0.0); + assert(i == 0); + + i = dice(100U, 0U); + assert(i == 0); +} + +@safe unittest +{ + import std.random; + + import std.algorithm.comparison : equal; + import std.range : iota; + auto rnd = MinstdRand0(42); + + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(10.iota.randomCover(rnd).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5])); +} + +@safe unittest +{ + import std.random; + + import std.algorithm.comparison : equal; + import std.range : iota; + auto rnd = MinstdRand0(42); + assert(10.iota.randomSample(3, rnd).equal([7, 8, 9])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_range_interfaces.d b/libphobos/testsuite/libphobos.phobos/std_range_interfaces.d new file mode 100644 index 0000000000000000000000000000000000000000..8d91401930c2bedc973b0ce3c44990fd040f10d2 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_range_interfaces.d @@ -0,0 +1,32 @@ +@safe unittest +{ + import std.range.interfaces; + + import std.algorithm.iteration : map; + import std.range : iota; + + void useRange(InputRange!int range) { + // Function body. + } + + // Create a range type. + auto squares = map!"a * a"(iota(10)); + + // Wrap it in an interface. + auto squaresWrapped = inputRangeObject(squares); + + // Use it. + useRange(squaresWrapped); +} + +@safe unittest +{ + import std.range.interfaces; + + import std.array; + auto app = appender!(uint[])(); + auto appWrapped = outputRangeObject!(uint, uint[])(app); + static assert(is(typeof(appWrapped) : OutputRange!(uint[]))); + static assert(is(typeof(appWrapped) : OutputRange!(uint))); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_range_package.d b/libphobos/testsuite/libphobos.phobos/std_range_package.d new file mode 100644 index 0000000000000000000000000000000000000000..03378ce3d668be11824e1b33142adfda68290ed2 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_range_package.d @@ -0,0 +1,1346 @@ +pure @safe nothrow @nogc unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[5] a = [ 1, 2, 3, 4, 5 ]; + int[5] b = [ 5, 4, 3, 2, 1 ]; + assert(equal(retro(a[]), b[])); + assert(retro(a[]).source is a[]); + assert(retro(retro(a[])) is a[]); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]; + assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][])); + assert(stride(stride(a, 2), 3) == stride(a, 6)); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] arr1 = [ 1, 2, 3, 4 ]; + int[] arr2 = [ 5, 6 ]; + int[] arr3 = [ 7 ]; + auto s = chain(arr1, arr2, arr3); + assert(s.length == 7); + assert(s[5] == 6); + assert(equal(s, [1, 2, 3, 4, 5, 6, 7][])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.sorting : sort; + + int[] arr1 = [5, 2, 8]; + int[] arr2 = [3, 7, 9]; + int[] arr3 = [1, 4, 6]; + + // in-place sorting across all of the arrays + auto s = arr1.chain(arr2, arr3).sort; + + assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9])); + assert(arr1.equal([1, 2, 3])); + assert(arr2.equal([4, 5, 6])); + assert(arr3.equal([7, 8, 9])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.utf : byChar, byCodeUnit; + + auto s1 = "string one"; + auto s2 = "string two"; + // s1 and s2 front is dchar because of auto-decoding + static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar)); + + auto r1 = s1.chain(s2); + // chains of ranges of the same character type give that same type + static assert(is(typeof(r1.front) == dchar)); + + auto s3 = "string three".byCodeUnit; + static assert(is(typeof(s3.front) == immutable char)); + auto r2 = s1.chain(s3); + // chaining ranges of mixed character types gives `dchar` + static assert(is(typeof(r2.front) == dchar)); + + // use byChar on character ranges to correctly convert them to UTF-8 + auto r3 = s1.byChar.chain(s3); + static assert(is(typeof(r3.front) == immutable char)); +} + +@safe nothrow pure @nogc unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter, map; + + auto data1 = only(1, 2, 3, 4).filter!(a => a != 3); + auto data2 = only(5, 6, 7, 8).map!(a => a + 1); + + // choose() is primarily useful when you need to select one of two ranges + // with different types at runtime. + static assert(!is(typeof(data1) == typeof(data2))); + + auto chooseRange(bool pickFirst) + { + // The returned range is a common wrapper type that can be used for + // returning or storing either range without running into a type error. + return choose(pickFirst, data1, data2); + + // Simply returning the chosen range without using choose() does not + // work, because map() and filter() return different types. + //return pickFirst ? data1 : data2; // does not compile + } + + auto result = chooseRange(true); + assert(result.equal(only(1, 2, 4))); + + result = chooseRange(false); + assert(result.equal(only(6, 7, 8, 9))); +} + +@safe nothrow pure @nogc unittest +{ + import std.range; + + auto test() + { + import std.algorithm.comparison : equal; + + int[4] sarr1 = [1, 2, 3, 4]; + int[2] sarr2 = [5, 6]; + int[1] sarr3 = [7]; + auto arr1 = sarr1[]; + auto arr2 = sarr2[]; + auto arr3 = sarr3[]; + + { + auto s = chooseAmong(0, arr1, arr2, arr3); + auto t = s.save; + assert(s.length == 4); + assert(s[2] == 3); + s.popFront(); + assert(equal(t, only(1, 2, 3, 4))); + } + { + auto s = chooseAmong(1, arr1, arr2, arr3); + assert(s.length == 2); + s.front = 8; + assert(equal(s, only(8, 6))); + } + { + auto s = chooseAmong(1, arr1, arr2, arr3); + assert(s.length == 2); + s[1] = 9; + assert(equal(s, only(8, 9))); + } + { + auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3]; + assert(s.length == 2); + assert(equal(s, only(2, 3))); + } + { + auto s = chooseAmong(0, arr1, arr2, arr3); + assert(s.length == 4); + assert(s.back == 4); + s.popBack(); + s.back = 5; + assert(equal(s, only(1, 2, 5))); + s.back = 3; + assert(equal(s, only(1, 2, 3))); + } + { + uint[5] foo = [1, 2, 3, 4, 5]; + uint[5] bar = [6, 7, 8, 9, 10]; + auto c = chooseAmong(1, foo[], bar[]); + assert(c[3] == 9); + c[3] = 42; + assert(c[3] == 42); + assert(c.moveFront() == 6); + assert(c.moveBack() == 10); + assert(c.moveAt(4) == 10); + } + { + import std.range : cycle; + auto s = chooseAmong(0, cycle(arr2), cycle(arr3)); + assert(isInfinite!(typeof(s))); + assert(!s.empty); + assert(s[100] == 8); + assert(s[101] == 9); + assert(s[0 .. 3].equal(only(8, 9, 8))); + } + return 0; + } + // works at runtime + auto a = test(); + // and at compile time + static b = test(); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] a = [ 1, 2, 3 ]; + int[] b = [ 10, 20, 30, 40 ]; + auto r = roundRobin(a, b); + assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + auto interleave(R, E)(R range, E element) + if ((isInputRange!R && hasLength!R) || isForwardRange!R) + { + static if (hasLength!R) + immutable len = range.length; + else + immutable len = range.save.walkLength; + + return roundRobin( + range, + element.repeat(len - 1) + ); + } + + assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[] a = [ 1, 2, 3, 4, 5 ]; + assert(equal(radial(a), [ 3, 4, 2, 5, 1 ])); + a = [ 1, 2, 3, 4 ]; + assert(equal(radial(a), [ 2, 3, 1, 4 ])); + + // If the left end is reached first, the remaining elements on the right + // are concatenated in order: + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ])); + + // If the right end is reached first, the remaining elements on the left + // are concatenated in reverse order: + assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; + auto s = take(arr1, 5); + assert(s.length == 5); + assert(s[4] == 5); + assert(equal(s, [ 1, 2, 3, 4, 5 ][])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] arr2 = [ 1, 2, 3 ]; + auto t = take(arr2, 5); + assert(t.length == 3); + assert(equal(t, [ 1, 2, 3 ])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + auto a = [ 1, 2, 3, 4, 5 ]; + + auto b = takeExactly(a, 3); + assert(equal(b, [1, 2, 3])); + static assert(is(typeof(b.length) == size_t)); + assert(b.length == 3); + assert(b.front == 1); + assert(b.back == 3); +} + +pure @safe nothrow unittest +{ + import std.range; + + auto s = takeOne([42, 43, 44]); + static assert(isRandomAccessRange!(typeof(s))); + assert(s.length == 1); + assert(!s.empty); + assert(s.front == 42); + s.front = 43; + assert(s.front == 43); + assert(s.back == 43); + assert(s[0] == 43); + s.popFront(); + assert(s.length == 0); + assert(s.empty); +} + +pure @safe nothrow @nogc unittest +{ + import std.range; + + auto range = takeNone!(int[])(); + assert(range.length == 0); + assert(range.empty); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.iteration : filter; + assert(takeNone([42, 27, 19]).empty); + assert(takeNone("dlang.org").empty); + assert(takeNone(filter!"true"([42, 27, 19])).empty); +} + +pure @safe nothrow unittest +{ + import std.range; + + // tail -c n + assert([1, 2, 3].tail(1) == [3]); + assert([1, 2, 3].tail(2) == [2, 3]); + assert([1, 2, 3].tail(3) == [1, 2, 3]); + assert([1, 2, 3].tail(4) == [1, 2, 3]); + assert([1, 2, 3].tail(0).length == 0); + + // tail --lines=n + import std.algorithm.comparison : equal; + import std.algorithm.iteration : joiner; + import std.exception : assumeWontThrow; + import std.string : lineSplitter; + assert("one\ntwo\nthree" + .lineSplitter + .tail(2) + .joiner("\n") + .equal("two\nthree") + .assumeWontThrow); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]); + assert("hello world".drop(6) == "world"); + assert("hello world".drop(50).empty); + assert("hello world".take(6).drop(3).equal("lo ")); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]); + assert("hello world".dropBack(6) == "hello"); + assert("hello world".dropBack(50).empty); + assert("hello world".drop(4).dropBack(4).equal("o w")); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filterBidirectional; + + auto a = [1, 2, 3]; + assert(a.dropExactly(2) == [3]); + assert(a.dropBackExactly(2) == [1]); + + string s = "日本語"; + assert(s.dropExactly(2) == "語"); + assert(s.dropBackExactly(2) == "æ—¥"); + + auto bd = filterBidirectional!"true"([1, 2, 3]); + assert(bd.dropExactly(2).equal([3])); + assert(bd.dropBackExactly(2).equal([1])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filterBidirectional; + import std.container.dlist : DList; + + auto dl = DList!int(9, 1, 2, 3, 9); + assert(dl[].dropOne().dropBackOne().equal([1, 2, 3])); + + auto a = [1, 2, 3]; + assert(a.dropOne() == [2, 3]); + assert(a.dropBackOne() == [1, 2]); + + string s = "日本語"; + import std.exception : assumeWontThrow; + assert(assumeWontThrow(s.dropOne() == "本語")); + assert(assumeWontThrow(s.dropBackOne() == "日本")); + + auto bd = filterBidirectional!"true"([1, 2, 3]); + assert(bd.dropOne().equal([2, 3])); + assert(bd.dropBackOne().equal([1, 2])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(5.repeat().take(4).equal([5, 5, 5, 5])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(5.repeat(4).equal([5, 5, 5, 5])); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + + int i = 1; + auto powersOfTwo = generate!(() => i *= 2)().take(10); + assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"())); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + //Returns a run-time delegate + auto infiniteIota(T)(T low, T high) + { + T i = high; + return (){if (i == high) i = low; return i++;}; + } + //adapted as a range. + assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1])); +} + +@safe unittest +{ + import std.range; + + import std.format : format; + import std.random : uniform; + + auto r = generate!(() => uniform(0, 6)).take(10); + format("%(%s %)", r); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.range : cycle, take; + + // Here we create an infinitive cyclic sequence from [1, 2] + // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then + // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1]) + // and compare them with the expected values for equality. + assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ])); +} + +@nogc nothrow pure @safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + + // pairwise sum + auto arr = only(0, 1, 2); + auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]"; + assert(part1.equal(only(1, 3))); +} + +nothrow pure @safe unittest +{ + import std.range; + + import std.conv : to; + + int[] a = [ 1, 2, 3 ]; + string[] b = [ "a", "b", "c" ]; + string[] result; + + foreach (tup; zip(a, b)) + { + result ~= tup[0].to!string ~ tup[1]; + } + + assert(result == [ "1a", "2b", "3c" ]); + + size_t idx = 0; + // unpacking tuple elements with foreach + foreach (e1, e2; zip(a, b)) + { + assert(e1 == a[idx]); + assert(e2 == b[idx]); + ++idx; + } +} + +nothrow pure @safe unittest +{ + import std.range; + + import std.algorithm.sorting : sort; + + int[] a = [ 1, 2, 3 ]; + string[] b = [ "a", "c", "b" ]; + zip(a, b).sort!((t1, t2) => t1[0] > t2[0]); + + assert(a == [ 3, 2, 1 ]); + // b is sorted according to a's sorting + assert(b == [ "b", "c", "a" ]); +} + +pure @safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.exception : assertThrown; + import std.range.primitives; + import std.typecons : tuple; + + auto a = [1, 2, 3]; + auto b = [4, 5, 6, 7]; + + auto shortest = zip(StoppingPolicy.shortest, a, b); + assert(shortest.equal([ + tuple(1, 4), + tuple(2, 5), + tuple(3, 6) + ])); + + auto longest = zip(StoppingPolicy.longest, a, b); + assert(longest.equal([ + tuple(1, 4), + tuple(2, 5), + tuple(3, 6), + tuple(0, 7) + ])); + + auto same = zip(StoppingPolicy.requireSameLength, a, b); + same.popFrontN(3); + assertThrown!Exception(same.popFront); +} + +pure @safe unittest +{ + import std.range; + + int[6] arr1 = [1,2,3,4,5,100]; + int[5] arr2 = [6,7,8,9,10]; + + foreach (ref a, b; lockstep(arr1[], arr2[])) + { + a += b; + } + + assert(arr1 == [7,9,11,13,15,100]); +} + +pure @safe unittest +{ + import std.range; + + int[3] arr1 = [1,2,3]; + int[3] arr2 = [4,5,6]; + + foreach (index, a, b; lockstep(arr1[], arr2[])) + { + assert(arr1[index] == a); + assert(arr2[index] == b); + } +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + // The Fibonacci numbers, using function in string form: + // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n] + auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); + assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])); + + // The factorials, using function in lambda form: + auto fac = recurrence!((a,n) => a[n-1] * n)(1); + assert(take(fac, 10).equal([ + 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 + ])); + + // The triangular numbers, using function in explicit form: + static size_t genTriangular(R)(R state, size_t n) + { + return state[n-1] + n; + } + auto tri = recurrence!genTriangular(0); + assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45])); +} + +pure @safe nothrow @nogc unittest +{ + import std.range; + + auto odds = sequence!("a[0] + n * a[1]")(1, 2); + assert(odds.front == 1); + odds.popFront(); + assert(odds.front == 3); + odds.popFront(); + assert(odds.front == 5); +} + +pure @safe nothrow @nogc unittest +{ + import std.range; + + auto tri = sequence!((a,n) => n*(n+1)/2)(); + + // Note random access + assert(tri[0] == 0); + assert(tri[3] == 6); + assert(tri[1] == 1); + assert(tri[4] == 10); + assert(tri[2] == 3); +} + +@safe nothrow @nogc unittest +{ + import std.range; + + import std.math.exponential : pow; + import std.math.rounding : round; + import std.math.algebraic : sqrt; + static ulong computeFib(S)(S state, size_t n) + { + // Binet's formula + return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) / + state[2])); + } + auto fib = sequence!computeFib( + (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio + (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio + sqrt(5.0)); + + // Note random access with [] operator + assert(fib[1] == 1); + assert(fib[4] == 5); + assert(fib[3] == 3); + assert(fib[2] == 2); + assert(fib[9] == 55); +} + +pure @safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.math.operations : isClose; + + auto r = iota(0, 10, 1); + assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); + assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); + assert(3 in r); + assert(r.contains(3)); //Same as above + assert(!(10 in r)); + assert(!(-8 in r)); + r = iota(0, 11, 3); + assert(equal(r, [0, 3, 6, 9])); + assert(r[2] == 6); + assert(!(2 in r)); + auto rf = iota(0.0, 0.5, 0.1); + assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4])); +} + +@safe pure unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.exception : assertThrown; + + auto arr = [[1, 2], [3, 4, 5]]; + + auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged); + assert(r1.equal([1, 3])); + + // throws on construction + assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged)); + + auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged); + assert(r2.equal([1, 3])); + + // either assuming or checking for equal lengths makes + // the result a random access range + assert(r2[0] == 1); + static assert(!__traits(compiles, r1[0])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[][] x = new int[][2]; + x[0] = [1, 2]; + x[1] = [3, 4]; + auto ror = frontTransversal(x); + assert(equal(ror, [ 1, 3 ][])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[][] x = new int[][2]; + x[0] = [1, 2]; + x[1] = [3, 4]; + auto ror = transversal(x, 1); + assert(equal(ror, [ 2, 4 ])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + int[][] y = [[1, 2, 3], [4, 5, 6]]; + auto z = y.front.walkLength.iota.map!(i => transversal(y, i)); + assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[][] ror = [ + [1, 2, 3], + [4, 5, 6] + ]; + auto xp = transposed(ror); + assert(equal!"a.equal(b)"(xp, [ + [1, 4], + [2, 5], + [3, 6] + ])); +} + +@safe unittest +{ + import std.range; + + int[][] x = new int[][2]; + x[0] = [1, 2]; + x[1] = [3, 4]; + auto tr = transposed(x); + int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ]; + uint i; + + foreach (e; tr) + { + assert(array(e) == witness[i++]); + } +} + +@safe unittest +{ + import std.range; + + auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); + assert(ind.physicalIndex(0) == 1); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto source = [1, 2, 3, 4, 5]; + auto indices = [4, 3, 1, 2, 0, 4]; + auto ind = indexed(source, indices); + assert(equal(ind, [5, 4, 2, 3, 1, 5])); + assert(equal(retro(ind), [5, 1, 3, 2, 4, 5])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + auto chunks = chunks(source, 4); + assert(chunks[0] == [1, 2, 3, 4]); + assert(chunks[1] == [5, 6, 7, 8]); + assert(chunks[2] == [9, 10]); + assert(chunks.back == chunks[2]); + assert(chunks.front == chunks[0]); + assert(chunks.length == 3); + assert(equal(retro(array(chunks)), array(retro(chunks)))); +} + +@system unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int i; + + // The generator doesn't save state, so it cannot be a forward range. + auto inputRange = generate!(() => ++i).take(10); + + // We can still process it in chunks, but it will be single-pass only. + auto chunked = inputRange.chunks(2); + + assert(chunked.front.equal([1, 2])); + assert(chunked.front.empty); // Iterating the chunk has consumed it + chunked.popFront; + assert(chunked.front.equal([3, 4])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + auto chunks = evenChunks(source, 3); + assert(chunks[0] == [1, 2, 3, 4]); + assert(chunks[1] == [5, 6, 7]); + assert(chunks[2] == [8, 9, 10]); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([0, 1, 2, 3].slide(2).equal!equal( + [[0, 1], [1, 2], [2, 3]] + )); + + assert(5.iota.slide(3).equal!equal( + [[0, 1, 2], [1, 2, 3], [2, 3, 4]] + )); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(6.iota.slide(1, 2).equal!equal( + [[0], [2], [4]] + )); + + assert(6.iota.slide(2, 4).equal!equal( + [[0, 1], [4, 5]] + )); + + assert(iota(7).slide(2, 2).equal!equal( + [[0, 1], [2, 3], [4, 5], [6]] + )); + + assert(iota(12).slide(2, 4).equal!equal( + [[0, 1], [4, 5], [8, 9]] + )); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(3.iota.slide!(No.withPartial)(4).empty); + assert(3.iota.slide!(Yes.withPartial)(4).equal!equal( + [[0, 1, 2]] + )); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.iteration : each; + + int[dstring] d; + "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++); + assert(d == ["AG"d: 2, "GA"d: 2]); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]])); + assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]])); + assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); + + assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); + assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); + assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter, joiner, map; + import std.algorithm.searching : findSplitBefore; + import std.uni : isUpper; + + assert(equal(only('♡'), "♡")); + assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); + + assert(only("one", "two", "three").joiner(" ").equal("one two three")); + + string title = "The D Programming Language"; + assert(title + .filter!isUpper // take the upper case letters + .map!only // make each letter its own range + .joiner(".") // join the ranges together lazily + .equal("T.D.P.L")); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.array : assocArray; + import std.range : enumerate; + + bool[int] aa = true.repeat(3).enumerate(-1).assocArray(); + assert(aa[-1]); + assert(aa[0]); + assert(aa[1]); +} + +@safe unittest +{ + import std.range; + + void func1(int a, int b); + void func2(int a, float b); + + static assert(isTwoWayCompatible!(func1, int, int)); + static assert(isTwoWayCompatible!(func1, short, int)); + static assert(!isTwoWayCompatible!(func2, int, float)); + + void func3(ref int a, ref int b); + static assert( isTwoWayCompatible!(func3, int, int)); + static assert(!isTwoWayCompatible!(func3, short, int)); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3); + assert(p1.equal([4, 5, 6, 7, 8, 9])); + + auto p2 = a.lowerBound!(SearchPolicy.gallop)(4); + assert(p2.equal([0, 1, 2, 3])); +} + +@safe pure unittest +{ + import std.range; + + // create a SortedRange, that's checked strictly + SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.sorting : sort; + int[3] data = [ 1, 2, 3 ]; + auto a = assumeSorted(data[]); + assert(a == sort!"a < b"(data[])); + int[] p = a.release(); + assert(p == [ 1, 2, 3 ]); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]); + auto p = a.lowerBound(4); + assert(equal(p, [ 0, 1, 2, 3 ])); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]); + auto p = a.upperBound(3); + assert(equal(p, [4, 4, 5, 6])); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; + auto r = a.assumeSorted.equalRange(3); + assert(equal(r, [ 3, 3, 3 ])); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; + auto r = assumeSorted(a).trisect(3); + assert(equal(r[0], [ 1, 2 ])); + assert(equal(r[1], [ 3, 3, 3 ])); + assert(equal(r[2], [ 4, 4, 5, 6 ])); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.sorting : sort; + auto a = [ 1, 2, 3, 42, 52, 64 ]; + auto r = assumeSorted(a); + assert(r.contains(3)); + assert(!(32 in r)); + auto r1 = sort!"a > b"(a); + assert(3 in r1); + assert(!r1.contains(32)); + assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.mutation : swap; + auto a = [ 1, 2, 3, 42, 52, 64 ]; + auto r = assumeSorted(a); + assert(r.contains(42)); + swap(a[3], a[5]); // illegal to break sortedness of original range + assert(!r.contains(42)); // passes although it shouldn't +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + static struct S { int i; } + static bool byI(A, B)(A a, B b) + { + static if (is(A == S)) + return a.i < b; + else + return a < b.i; + } + auto r = assumeSorted!byI([S(1), S(2), S(3)]); + auto lessThanTwo = r.lowerBound(2); + assert(equal(lessThanTwo, [S(1)])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + auto p = assumeSorted(a); + + assert(equal(p.lowerBound(4), [0, 1, 2, 3])); + assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4])); + assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5])); + assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6])); +} + +@system unittest +{ + import std.range; + + import std.algorithm.searching : find; + ubyte[] buffer = [1, 9, 45, 12, 22]; + auto found1 = find(buffer, 45); + assert(found1 == [45, 12, 22]); + assert(buffer == [1, 9, 45, 12, 22]); + + auto wrapped1 = refRange(&buffer); + auto found2 = find(wrapped1, 45); + assert(*found2.ptr == [45, 12, 22]); + assert(buffer == [45, 12, 22]); + + auto found3 = find(wrapped1.save, 22); + assert(*found3.ptr == [22]); + assert(buffer == [45, 12, 22]); + + string str = "hello world"; + auto wrappedStr = refRange(&str); + assert(str.front == 'h'); + str.popFrontN(5); + assert(str == " world"); + assert(wrappedStr.front == ' '); + assert(*wrappedStr.ptr == " world"); +} + +@system unittest +{ + import std.range; + + ubyte[] buffer1 = [1, 2, 3, 4, 5]; + ubyte[] buffer2 = [6, 7, 8, 9, 10]; + auto wrapped1 = refRange(&buffer1); + auto wrapped2 = refRange(&buffer2); + assert(wrapped1.ptr is &buffer1); + assert(wrapped2.ptr is &buffer2); + assert(wrapped1.ptr !is wrapped2.ptr); + assert(buffer1 != buffer2); + + wrapped1 = wrapped2; + + //Everything points to the same stuff as before. + assert(wrapped1.ptr is &buffer1); + assert(wrapped2.ptr is &buffer2); + assert(wrapped1.ptr !is wrapped2.ptr); + + //But buffer1 has changed due to the assignment. + assert(buffer1 == [6, 7, 8, 9, 10]); + assert(buffer2 == [6, 7, 8, 9, 10]); + + buffer2 = [11, 12, 13, 14, 15]; + + //Everything points to the same stuff as before. + assert(wrapped1.ptr is &buffer1); + assert(wrapped2.ptr is &buffer2); + assert(wrapped1.ptr !is wrapped2.ptr); + + //But buffer2 has changed due to the assignment. + assert(buffer1 == [6, 7, 8, 9, 10]); + assert(buffer2 == [11, 12, 13, 14, 15]); + + wrapped2 = null; + + //The pointer changed for wrapped2 but not wrapped1. + assert(wrapped1.ptr is &buffer1); + assert(wrapped2.ptr is null); + assert(wrapped1.ptr !is wrapped2.ptr); + + //buffer2 is not affected by the assignment. + assert(buffer1 == [6, 7, 8, 9, 10]); + assert(buffer2 == [11, 12, 13, 14, 15]); +} + +@safe pure unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.format : format; + + // 00000011 00001001 + ubyte[] arr = [3, 9]; + auto r = arr.bitwise; + + // iterate through it as with any other range + assert(format("%(%d%)", r) == "1100000010010000"); + assert(format("%(%d%)", r.retro).equal("1100000010010000".retro)); + + auto r2 = r[5 .. $]; + // set a bit + r[2] = 1; + assert(arr[0] == 7); + assert(r[5] == r2[0]); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.random : rndGen; + + auto rb = rndGen.bitwise; + static assert(isInfinite!(typeof(rb))); + + auto rb2 = rndGen.bitwise; + // Don't forget that structs are passed by value + assert(rb.take(10).equal(rb2.take(10))); +} + +@safe nothrow unittest +{ + import std.range; + + import std.algorithm.iteration : map; + import std.algorithm.mutation : copy; + [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded +} + +@safe unittest +{ + import std.range; + + import std.csv : csvNextToken; + + string line = "a,b,c"; + + // ignore the first column + line.csvNextToken(nullSink, ',', '"'); + line.popFront; + + // look at the second column + Appender!string app; + line.csvNextToken(app, ',', '"'); + assert(app.data == "b"); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter, map; + + // Sum values while copying + int[] values = [1, 4, 9, 16, 25]; + int sum = 0; + auto newValues = values.tee!(a => sum += a).array; + assert(equal(newValues, values)); + assert(sum == 1 + 4 + 9 + 16 + 25); + + // Count values that pass the first filter + int count = 0; + auto newValues4 = values.filter!(a => a < 10) + .tee!(a => count++) + .map!(a => a + 1) + .filter!(a => a < 10); + + //Fine, equal also evaluates any lazy ranges passed to it. + //count is not 3 until equal evaluates newValues4 + assert(equal(newValues4, [2, 5])); + assert(count == 3); +} + +@safe pure unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4])); + assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4])); + + assert("abc".padLeft('_', 6).equal("___abc")); +} + +@safe pure unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0])); + assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4])); + + assert("abc".padRight('_', 6).equal("abc___")); +} + +@safe unittest +{ + import std.range; + + import std.path : chainPath; + import std.range : chain; + + void someLibraryMethod(R)(R argument) + if (isSomeFiniteCharInputRange!R) + { + // implementation detail, would iterate over each character of argument + } + + someLibraryMethod("simple strings work"); + someLibraryMethod(chain("chained", " ", "strings", " ", "work")); + someLibraryMethod(chainPath("chained", "paths", "work")); + // you can also use custom structs implementing a char range +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_range_primitives.d b/libphobos/testsuite/libphobos.phobos/std_range_primitives.d new file mode 100644 index 0000000000000000000000000000000000000000..eb4bc267c8b40b16dc1efe97945b9691af7afac4 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_range_primitives.d @@ -0,0 +1,591 @@ +@safe unittest +{ + import std.range.primitives; + + struct A {} + struct B + { + void popFront(); + @property bool empty(); + @property int front(); + } + static assert(!isInputRange!A); + static assert( isInputRange!B); + static assert( isInputRange!(int[])); + static assert( isInputRange!(char[])); + static assert(!isInputRange!(char[4])); + static assert( isInputRange!(inout(int)[])); + static assert(!isInputRange!(int[], string)); + static assert( isInputRange!(int[], int)); + static assert( isInputRange!(int[], const int)); + static assert(!isInputRange!(int[], immutable int)); + + static assert(!isInputRange!(const(int)[], int)); + static assert( isInputRange!(const(int)[], const int)); + static assert(!isInputRange!(const(int)[], immutable int)); + + static assert(!isInputRange!(immutable(int)[], int)); + static assert( isInputRange!(immutable(int)[], const int)); + static assert( isInputRange!(immutable(int)[], immutable int)); + + static struct NotDefaultConstructible + { + @disable this(); + void popFront(); + @property bool empty(); + @property int front(); + } + static assert( isInputRange!NotDefaultConstructible); + + static struct NotDefaultConstructibleOrCopyable + { + @disable this(); + @disable this(this); + void popFront(); + @property bool empty(); + @property int front(); + } + static assert(isInputRange!NotDefaultConstructibleOrCopyable); + + static struct Frontless + { + void popFront(); + @property bool empty(); + } + static assert(!isInputRange!Frontless); + + static struct VoidFront + { + void popFront(); + @property bool empty(); + void front(); + } + static assert(!isInputRange!VoidFront); +} + +@safe pure unittest +{ + import std.range.primitives; + + import std.traits : isSomeChar; + + static struct A + { + string data; + + void put(C)(C c) + if (isSomeChar!C) + { + data ~= c; + } + } + static assert(isOutputRange!(A, char)); + + auto a = A(); + put(a, "Hello"); + assert(a.data == "Hello"); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + int[] a = [1, 2, 3], b = [10, 20]; + auto c = a; + put(a, b); + assert(c == [10, 20, 3]); + // at this point, a was advanced twice, so it only contains + // its last element while c represents the whole array + assert(a == [3]); +} + +@safe pure unittest +{ + import std.range.primitives; + + // the elements must be mutable, so using string or const(char)[] + // won't compile + char[] s1 = new char[13]; + auto r1 = s1; + put(r1, "Hello, World!"w); + assert(s1 == "Hello, World!"); +} + +@safe unittest +{ + import std.range.primitives; + + void myprint(scope const(char)[] s) { } + static assert(isOutputRange!(typeof(&myprint), char)); + + static assert( isOutputRange!(char[], char)); + static assert( isOutputRange!(dchar[], wchar)); + static assert( isOutputRange!(dchar[], dchar)); +} + +@safe unittest +{ + import std.range.primitives; + + static assert(!isForwardRange!(int)); + static assert( isForwardRange!(int[])); + static assert( isForwardRange!(inout(int)[])); + + static assert( isForwardRange!(int[], const int)); + static assert(!isForwardRange!(int[], immutable int)); + + static assert(!isForwardRange!(const(int)[], int)); + static assert( isForwardRange!(const(int)[], const int)); + static assert(!isForwardRange!(const(int)[], immutable int)); + + static assert(!isForwardRange!(immutable(int)[], int)); + static assert( isForwardRange!(immutable(int)[], const int)); + static assert( isForwardRange!(immutable(int)[], immutable int)); +} + +@safe unittest +{ + import std.range.primitives; + + alias R = int[]; + R r = [0,1]; + static assert(isForwardRange!R); // is forward range + r.popBack(); // can invoke popBack + auto t = r.back; // can get the back of the range + auto w = r.front; + static assert(is(typeof(t) == typeof(w))); // same type for front and back + + // Checking the element type + static assert( isBidirectionalRange!(int[], const int)); + static assert(!isBidirectionalRange!(int[], immutable int)); + + static assert(!isBidirectionalRange!(const(int)[], int)); + static assert( isBidirectionalRange!(const(int)[], const int)); + static assert(!isBidirectionalRange!(const(int)[], immutable int)); + + static assert(!isBidirectionalRange!(immutable(int)[], int)); + static assert( isBidirectionalRange!(immutable(int)[], const int)); + static assert( isBidirectionalRange!(immutable(int)[], immutable int)); +} + +@safe unittest +{ + import std.range.primitives; + + import std.traits : isAggregateType, isAutodecodableString; + + alias R = int[]; + + // range is finite and bidirectional or infinite and forward. + static assert(isBidirectionalRange!R || + isForwardRange!R && isInfinite!R); + + R r = [0,1]; + auto e = r[1]; // can index + auto f = r.front; + static assert(is(typeof(e) == typeof(f))); // same type for indexed and front + static assert(!(isAutodecodableString!R && !isAggregateType!R)); // narrow strings cannot be indexed as ranges + static assert(hasLength!R || isInfinite!R); // must have length or be infinite + + // $ must work as it does with arrays if opIndex works with $ + static if (is(typeof(r[$]))) + { + static assert(is(typeof(f) == typeof(r[$]))); + + // $ - 1 doesn't make sense with infinite ranges but needs to work + // with finite ones. + static if (!isInfinite!R) + static assert(is(typeof(f) == typeof(r[$ - 1]))); + } + + // Checking the element type + static assert( isRandomAccessRange!(int[], const int)); + static assert(!isRandomAccessRange!(int[], immutable int)); + + static assert(!isRandomAccessRange!(const(int)[], int)); + static assert( isRandomAccessRange!(const(int)[], const int)); + static assert(!isRandomAccessRange!(const(int)[], immutable int)); + + static assert(!isRandomAccessRange!(immutable(int)[], int)); + static assert( isRandomAccessRange!(immutable(int)[], const int)); + static assert( isRandomAccessRange!(immutable(int)[], immutable int)); +} + +@safe unittest +{ + import std.range.primitives; + + import std.algorithm.iteration : map; + import std.range : iota, repeat; + + static struct HasPostblit + { + this(this) {} + } + + auto nonMobile = map!"a"(repeat(HasPostblit.init)); + static assert(!hasMobileElements!(typeof(nonMobile))); + static assert( hasMobileElements!(int[])); + static assert( hasMobileElements!(inout(int)[])); + static assert( hasMobileElements!(typeof(iota(1000)))); + + static assert( hasMobileElements!( string)); + static assert( hasMobileElements!(dstring)); + static assert( hasMobileElements!( char[])); + static assert( hasMobileElements!(dchar[])); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : iota; + + // Standard arrays: returns the type of the elements of the array + static assert(is(ElementType!(int[]) == int)); + + // Accessing .front retrieves the decoded dchar + static assert(is(ElementType!(char[]) == dchar)); // rvalue + static assert(is(ElementType!(dchar[]) == dchar)); // lvalue + + // Ditto + static assert(is(ElementType!(string) == dchar)); + static assert(is(ElementType!(dstring) == immutable(dchar))); + + // For ranges it gets the type of .front. + auto range = iota(0, 10); + static assert(is(ElementType!(typeof(range)) == int)); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : iota; + // internally the range stores the encoded type + static assert(is(ElementEncodingType!(char[]) == char)); + + static assert(is(ElementEncodingType!(wstring) == immutable(wchar))); + + static assert(is(ElementEncodingType!(byte[]) == byte)); + + auto range = iota(0, 10); + static assert(is(ElementEncodingType!(typeof(range)) == int)); +} + +@safe unittest +{ + import std.range.primitives; + + static assert(!hasSwappableElements!(const int[])); + static assert(!hasSwappableElements!(const(int)[])); + static assert(!hasSwappableElements!(inout(int)[])); + static assert( hasSwappableElements!(int[])); + + static assert(!hasSwappableElements!( string)); + static assert(!hasSwappableElements!(dstring)); + static assert(!hasSwappableElements!( char[])); + static assert( hasSwappableElements!(dchar[])); +} + +@safe unittest +{ + import std.range.primitives; + + static assert(!hasAssignableElements!(const int[])); + static assert(!hasAssignableElements!(const(int)[])); + static assert( hasAssignableElements!(int[])); + static assert(!hasAssignableElements!(inout(int)[])); + + static assert(!hasAssignableElements!( string)); + static assert(!hasAssignableElements!(dstring)); + static assert(!hasAssignableElements!( char[])); + static assert( hasAssignableElements!(dchar[])); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : iota, chain; + + static assert( hasLvalueElements!(int[])); + static assert( hasLvalueElements!(const(int)[])); + static assert( hasLvalueElements!(inout(int)[])); + static assert( hasLvalueElements!(immutable(int)[])); + static assert(!hasLvalueElements!(typeof(iota(3)))); + + static assert(!hasLvalueElements!( string)); + static assert( hasLvalueElements!(dstring)); + static assert(!hasLvalueElements!( char[])); + static assert( hasLvalueElements!(dchar[])); + + auto c = chain([1, 2, 3], [4, 5, 6]); + static assert( hasLvalueElements!(typeof(c))); +} + +@safe unittest +{ + import std.range.primitives; + + static assert(!hasLength!(char[])); + static assert( hasLength!(int[])); + static assert( hasLength!(inout(int)[])); + + struct A { size_t length() { return 0; } } + struct B { @property size_t length() { return 0; } } + static assert( hasLength!(A)); + static assert( hasLength!(B)); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : Repeat; + static assert(!isInfinite!(int[])); + static assert( isInfinite!(Repeat!(int))); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : takeExactly; + static assert( hasSlicing!(int[])); + static assert( hasSlicing!(const(int)[])); + static assert(!hasSlicing!(const int[])); + static assert( hasSlicing!(inout(int)[])); + static assert(!hasSlicing!(inout int [])); + static assert( hasSlicing!(immutable(int)[])); + static assert(!hasSlicing!(immutable int[])); + static assert(!hasSlicing!string); + static assert( hasSlicing!dstring); + + enum rangeFuncs = "@property int front();" ~ + "void popFront();" ~ + "@property bool empty();" ~ + "@property auto save() { return this; }" ~ + "@property size_t length();"; + + struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); } + struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); } + struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); } + struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); } + static assert(!hasSlicing!(A)); + static assert( hasSlicing!(B)); + static assert( hasSlicing!(C)); + static assert(!hasSlicing!(D)); + + struct InfOnes + { + enum empty = false; + void popFront() {} + @property int front() { return 1; } + @property InfOnes save() { return this; } + auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); } + auto opSlice(size_t i, Dollar d) { return this; } + + struct Dollar {} + Dollar opDollar() const { return Dollar.init; } + } + + static assert(hasSlicing!InfOnes); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : iota; + + assert(10.iota.walkLength == 10); + // iota has a length function, and therefore the + // doesn't have to be walked, and the upTo + // parameter is ignored + assert(10.iota.walkLength(5) == 10); +} + +@safe unittest +{ + import std.range.primitives; + + int[] a = [ 1, 2, 3, 4, 5 ]; + a.popFrontN(2); + assert(a == [ 3, 4, 5 ]); + a.popFrontN(7); + assert(a == [ ]); +} + +@safe unittest +{ + import std.range.primitives; + + import std.algorithm.comparison : equal; + import std.range : iota; + auto LL = iota(1L, 7L); + auto r = popFrontN(LL, 2); + assert(equal(LL, [3L, 4L, 5L, 6L])); + assert(r == 2); +} + +@safe unittest +{ + import std.range.primitives; + + int[] a = [ 1, 2, 3, 4, 5 ]; + a.popBackN(2); + assert(a == [ 1, 2, 3 ]); + a.popBackN(7); + assert(a == [ ]); +} + +@safe unittest +{ + import std.range.primitives; + + import std.algorithm.comparison : equal; + import std.range : iota; + auto LL = iota(1L, 7L); + auto r = popBackN(LL, 2); + assert(equal(LL, [1L, 2L, 3L, 4L])); + assert(r == 2); +} + +@safe unittest +{ + import std.range.primitives; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filterBidirectional; + + auto a = [1, 2, 3]; + a.popFrontExactly(1); + assert(a == [2, 3]); + a.popBackExactly(1); + assert(a == [2]); + + string s = "日本語"; + s.popFrontExactly(1); + assert(s == "本語"); + s.popBackExactly(1); + assert(s == "本"); + + auto bd = filterBidirectional!"true"([1, 2, 3]); + bd.popFrontExactly(1); + assert(bd.equal([2, 3])); + bd.popBackExactly(1); + assert(bd.equal([2])); +} + +@safe unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + assert(moveFront(a) == 1); + assert(a.length == 3); + + // define a perfunctory input range + struct InputRange + { + enum bool empty = false; + enum int front = 7; + void popFront() {} + int moveFront() { return 43; } + } + InputRange r; + // calls r.moveFront + assert(moveFront(r) == 43); +} + +@safe unittest +{ + import std.range.primitives; + + struct TestRange + { + int payload = 5; + @property bool empty() { return false; } + @property TestRange save() { return this; } + @property ref int front() return { return payload; } + @property ref int back() return { return payload; } + void popFront() { } + void popBack() { } + } + static assert(isBidirectionalRange!TestRange); + TestRange r; + auto x = moveBack(r); + assert(x == 5); +} + +@safe unittest +{ + import std.range.primitives; + + auto a = [1,2,3,4]; + foreach (idx, it; a) + { + assert(it == moveAt(a, idx)); + } +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + assert(!a.empty); + assert(a[3 .. $].empty); + + int[string] b; + assert(b.empty); + b["zero"] = 0; + assert(!b.empty); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + auto b = a.save; + assert(b is a); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + a.popFront(); + assert(a == [ 2, 3 ]); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + a.popBack(); + assert(a == [ 1, 2 ]); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + int[] a = [ 1, 2, 3 ]; + assert(a.front == 1); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + int[] a = [ 1, 2, 3 ]; + assert(a.back == 3); + a.back += 4; + assert(a.back == 7); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_regex_package.d b/libphobos/testsuite/libphobos.phobos/std_regex_package.d new file mode 100644 index 0000000000000000000000000000000000000000..448c9db1aea91bd0d0483cec1e0bc29f401b3d43 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_regex_package.d @@ -0,0 +1,175 @@ +@system unittest +{ + import std.regex; + + void test(S)() + { + // multi-pattern regex example + S[] arr = [`([a-z]+):(\d+)`, `(\d+),\d+`]; + auto multi = regex(arr); // multi regex + S str = "abc:43 12,34"; + auto m = str.matchAll(multi); + assert(m.front.whichPattern == 1); + assert(m.front[1] == "abc"); + assert(m.front[2] == "43"); + m.popFront(); + assert(m.front.whichPattern == 2); + assert(m.front[1] == "12"); + } + + import std.meta : AliasSeq; + static foreach (C; AliasSeq!(string, wstring, dstring)) + // Test with const array of patterns - see https://issues.dlang.org/show_bug.cgi?id=20301 + static foreach (S; AliasSeq!(C, const C, immutable C)) + test!S(); +} + +@system unittest +{ + import std.regex; + + import std.regex; + assert(matchFirst("abc", "[0-9]+", "[a-z]+").whichPattern == 2); + +} + +@system unittest +{ + import std.regex; + + import std.range.primitives : popFrontN; + + auto c = matchFirst("@abc#", regex(`(\w)(\w)(\w)`)); + assert(c.pre == "@"); // Part of input preceding match + assert(c.post == "#"); // Immediately after match + assert(c.hit == c[0] && c.hit == "abc"); // The whole match + assert(c[2] == "b"); + assert(c.front == "abc"); + c.popFront(); + assert(c.front == "a"); + assert(c.back == "c"); + c.popBack(); + assert(c.back == "b"); + popFrontN(c, 2); + assert(c.empty); + + assert(!matchFirst("nothing", "something")); + + // Captures that are not matched will be null. + c = matchFirst("ac", regex(`a(b)?c`)); + assert(c); + assert(!c[1]); +} + +@system unittest +{ + import std.regex; + + assert(replaceFirst("noon", regex("n"), "[$&]") == "[n]oon"); +} + +@system unittest +{ + import std.regex; + + import std.conv : to; + string list = "#21 out of 46"; + string newList = replaceFirst!(cap => to!string(to!int(cap.hit)+1)) + (list, regex(`[0-9]+`)); + assert(newList == "#22 out of 46"); +} + +@system unittest +{ + import std.regex; + + import std.array; + string m1 = "first message\n"; + string m2 = "second message\n"; + auto result = appender!string(); + replaceFirstInto(result, m1, regex(`([a-z]+) message`), "$1"); + //equivalent of the above with user-defined callback + replaceFirstInto!(cap=>cap[1])(result, m2, regex(`([a-z]+) message`)); + assert(result.data == "first\nsecond\n"); +} + +@system unittest +{ + import std.regex; + + // insert comma as thousands delimiter + auto re = regex(r"(?<=\d)(?=(\d\d\d)+\b)","g"); + assert(replaceAll("12000 + 42100 = 54100", re, ",") == "12,000 + 42,100 = 54,100"); +} + +@system unittest +{ + import std.regex; + + string baz(Captures!(string) m) + { + import std.string : toUpper; + return toUpper(m.hit); + } + // Capitalize the letters 'a' and 'r': + auto s = replaceAll!(baz)("Strap a rocket engine on a chicken.", + regex("[ar]")); + assert(s == "StRAp A Rocket engine on A chicken."); +} + +@system unittest +{ + import std.regex; + + // insert comma as thousands delimiter in fifty randomly produced big numbers + import std.array, std.conv, std.random, std.range; + static re = regex(`(?<=\d)(?=(\d\d\d)+\b)`, "g"); + auto sink = appender!(char [])(); + enum ulong min = 10UL ^^ 10, max = 10UL ^^ 19; + foreach (i; 0 .. 50) + { + sink.clear(); + replaceAllInto(sink, text(uniform(min, max)), re, ","); + foreach (pos; iota(sink.data.length - 4, 0, -4)) + assert(sink.data[pos] == ','); + } +} + +@system unittest +{ + import std.regex; + + import std.algorithm.comparison : equal; + auto s1 = ", abc, de, fg, hi, "; + assert(equal(splitter(s1, regex(", *")), + ["", "abc", "de", "fg", "hi", ""])); +} + +@system unittest +{ + import std.regex; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + auto pattern = regex(`([\.,])`); + + assert("2003.04.05" + .splitter!(Yes.keepSeparators)(pattern) + .equal(["2003", ".", "04", ".", "05"])); + + assert(",1,2,3" + .splitter!(Yes.keepSeparators)(pattern) + .equal([",", "1", ",", "2", ",", "3"])); +} + +@system unittest +{ + import std.regex; + + import std.algorithm.comparison; + import std.regex; + string s = `This is {unfriendly} to *regex*`; + assert(s.escaper.equal(`This is \{unfriendly\} to \*regex\*`)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_signals.d b/libphobos/testsuite/libphobos.phobos/std_signals.d new file mode 100644 index 0000000000000000000000000000000000000000..255dbde7d754b3cab5c211871b9f7f0874e3920a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_signals.d @@ -0,0 +1,85 @@ +@system unittest +{ + import std.signals; + + import std.signals; + + int observedMessageCounter = 0; + + class Observer + { // our slot + void watch(string msg, int value) + { + switch (observedMessageCounter++) + { + case 0: + assert(msg == "setting new value"); + assert(value == 4); + break; + case 1: + assert(msg == "setting new value"); + assert(value == 6); + break; + default: + assert(0, "Unknown observation"); + } + } + } + + class Observer2 + { // our slot + void watch(string msg, int value) + { + } + } + + class Foo + { + int value() { return _value; } + + int value(int v) + { + if (v != _value) + { _value = v; + // call all the connected slots with the two parameters + emit("setting new value", v); + } + return v; + } + + // Mix in all the code we need to make Foo into a signal + mixin Signal!(string, int); + + private : + int _value; + } + + Foo a = new Foo; + Observer o = new Observer; + auto o2 = new Observer2; + auto o3 = new Observer2; + auto o4 = new Observer2; + auto o5 = new Observer2; + + a.value = 3; // should not call o.watch() + a.connect(&o.watch); // o.watch is the slot + a.connect(&o2.watch); + a.connect(&o3.watch); + a.connect(&o4.watch); + a.connect(&o5.watch); + a.value = 4; // should call o.watch() + a.disconnect(&o.watch); // o.watch is no longer a slot + a.disconnect(&o3.watch); + a.disconnect(&o5.watch); + a.disconnect(&o4.watch); + a.disconnect(&o2.watch); + a.value = 5; // so should not call o.watch() + a.connect(&o2.watch); + a.connect(&o.watch); // connect again + a.value = 6; // should call o.watch() + destroy(o); // destroying o should automatically disconnect it + a.value = 7; // should not call o.watch() + + assert(observedMessageCounter == 2); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_socket.d b/libphobos/testsuite/libphobos.phobos/std_socket.d new file mode 100644 index 0000000000000000000000000000000000000000..5a63193dc7cca87192d4c813638ed5f23e8f245b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_socket.d @@ -0,0 +1,66 @@ +@safe unittest +{ + import std.socket; + + InternetHost ih = new InternetHost; + + ih.getHostByAddr(0x7F_00_00_01); + assert(ih.addrList[0] == 0x7F_00_00_01); + ih.getHostByAddr("127.0.0.1"); + assert(ih.addrList[0] == 0x7F_00_00_01); + + if (!ih.getHostByName("www.digitalmars.com")) + return; // don't fail if not connected to internet + + assert(ih.addrList.length); + InternetAddress ia = new InternetAddress(ih.addrList[0], InternetAddress.PORT_ANY); + assert(ih.name == "www.digitalmars.com" || ih.name == "digitalmars.com", + ih.name); + + /* The following assert randomly fails in the test suite. + * https://issues.dlang.org/show_bug.cgi?id=22791 + * So just ignore it when it fails. + */ + //assert(ih.getHostByAddr(ih.addrList[0])); + if (ih.getHostByAddr(ih.addrList[0])) + { + string getHostNameFromInt = ih.name.dup; + + // This randomly fails in the compiler test suite + //assert(ih.getHostByAddr(ia.toAddrString())); + + if (ih.getHostByAddr(ia.toAddrString())) + { + string getHostNameFromStr = ih.name.dup; + assert(getHostNameFromInt == getHostNameFromStr); + } + } +} + +@system unittest +{ + import std.socket; + + auto addr1 = new InternetAddress("127.0.0.1", 80); + auto addr2 = new InternetAddress("127.0.0.2", 80); + + assert(addr1 == addr1); + assert(addr1 != addr2); + +} + +@safe unittest +{ + import std.socket; + + immutable ubyte[4] data = [1, 2, 3, 4]; + auto pair = socketPair(); + scope(exit) foreach (s; pair) s.close(); + + pair[0].send(data[]); + + auto buf = new ubyte[data.length]; + pair[1].receive(buf); + assert(buf == data); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_stdio.d b/libphobos/testsuite/libphobos.phobos/std_stdio.d new file mode 100644 index 0000000000000000000000000000000000000000..43b3cf6aa50d807c64d2053659cf350e6a298803 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_stdio.d @@ -0,0 +1,185 @@ +@system unittest +{ + import std.stdio; + + static import std.file; + + auto testFile = std.file.deleteme(); + std.file.write(testFile, "\r\n\n\r\n"); + scope(exit) std.file.remove(testFile); + + auto f = File(testFile, "r"); + auto buf = f.rawRead(new char[5]); + f.close(); + assert(buf == "\r\n\n\r\n"); + +} + +@system unittest +{ + import std.stdio; + + static import std.file; + + auto testFile = std.file.deleteme(); + auto f = File(testFile, "w"); + scope(exit) std.file.remove(testFile); + + f.rawWrite("\r\n\n\r\n"); + f.close(); + assert(std.file.read(testFile) == "\r\n\n\r\n"); + +} + +@system unittest +{ + import std.stdio; + + import std.conv : text; + static import std.file; + + auto testFile = std.file.deleteme(); + std.file.write(testFile, "abcdefghijklmnopqrstuvwqxyz"); + scope(exit) { std.file.remove(testFile); } + + auto f = File(testFile); + auto a = new ubyte[4]; + f.rawRead(a); + assert(f.tell == 4, text(f.tell)); + +} + +@system unittest +{ + import std.stdio; + + static import std.file; + + auto deleteme = std.file.deleteme(); + std.file.write(deleteme, "hello\nworld\ntrue\nfalse\n"); + scope(exit) std.file.remove(deleteme); + string s; + auto f = File(deleteme); + f.readf!"%s\n"(s); + assert(s == "hello", "["~s~"]"); + f.readf("%s\n", s); + assert(s == "world", "["~s~"]"); + + bool b1, b2; + f.readf("%s\n%s\n", b1, b2); + assert(b1 == true && b2 == false); + +} + +@system unittest +{ + import std.stdio; + + static import std.file; + import std.typecons : tuple; + + // prepare test file + auto testFile = std.file.deleteme(); + scope(failure) printf("Failed test at line %d\n", __LINE__); + std.file.write(testFile, "1 2\n4 1\n5 100"); + scope(exit) std.file.remove(testFile); + + File f = File(testFile); + scope(exit) f.close(); + + auto expected = [tuple(1, 2), tuple(4, 1), tuple(5, 100)]; + uint i; + foreach (e; f.byRecord!(int, int)("%s %s")) + { + assert(e == expected[i++]); + } + +} + +@safe unittest +{ + import std.stdio; + + static assert(isFileHandle!(FILE*)); + static assert(isFileHandle!(File)); +} + +@safe unittest +{ + import std.stdio; + + // Read stdin, sort lines, write to stdout + import std.algorithm.mutation : copy; + import std.algorithm.sorting : sort; + import std.array : array; + import std.typecons : Yes; + + void main() + { + stdin // read from stdin + .byLineCopy(Yes.keepTerminator) // copying each line + .array() // convert to array of lines + .sort() // sort the lines + .copy( // copy output of .sort to an OutputRange + stdout.lockingTextWriter()); // the OutputRange + } +} + +@safe unittest +{ + import std.stdio; + + void main() + { + stdout.writeln("Write a message to stdout."); + } +} + +@safe unittest +{ + import std.stdio; + + void main() + { + import std.algorithm.iteration : filter, map, sum; + import std.format : format; + import std.range : iota, tee; + + int len; + const r = 6.iota + .filter!(a => a % 2) // 1 3 5 + .map!(a => a * 2) // 2 6 10 + .tee!(_ => stdout.writefln("len: %d", len++)) + .sum; + + assert(r == 18); + } +} + +@safe unittest +{ + import std.stdio; + + void main() + { + import std.algorithm.mutation : copy; + import std.algorithm.iteration : map; + import std.format : format; + import std.range : iota; + + 10.iota + .map!(e => "N: %d".format(e)) + .copy(stdout.lockingTextWriter()); // the OutputRange + } +} + +@safe unittest +{ + import std.stdio; + + void main() + { + stderr.writeln("Write a message to stderr."); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_string.d b/libphobos/testsuite/libphobos.phobos/std_string.d new file mode 100644 index 0000000000000000000000000000000000000000..256b5a77287b291a867b20c1a235e64215dd0d29 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_string.d @@ -0,0 +1,892 @@ +@safe pure unittest +{ + import std.string; + + import std.exception : assertThrown; + auto bad = " a\n\tb\n c"; + assertThrown!StringException(bad.outdent); +} + +@system pure unittest +{ + import std.string; + + assert(fromStringz("foo\0"c.ptr) == "foo"c); + assert(fromStringz("foo\0"w.ptr) == "foo"w); + assert(fromStringz("foo\0"d.ptr) == "foo"d); + + assert(fromStringz("ç¦\0"c.ptr) == "ç¦"c); + assert(fromStringz("ç¦\0"w.ptr) == "ç¦"w); + assert(fromStringz("ç¦\0"d.ptr) == "ç¦"d); +} + +@nogc @safe pure nothrow unittest +{ + import std.string; + + struct C + { + char[32] name; + } + assert(C("foo\0"c).name.fromStringz() == "foo"c); + + struct W + { + wchar[32] name; + } + assert(W("foo\0"w).name.fromStringz() == "foo"w); + + struct D + { + dchar[32] name; + } + assert(D("foo\0"d).name.fromStringz() == "foo"d); +} + +pure nothrow @system unittest +{ + import std.string; + + import core.stdc.string : strlen; + import std.conv : to; + + auto p = toStringz("foo"); + assert(strlen(p) == 3); + const(char)[] foo = "abbzxyzzy"; + p = toStringz(foo[3 .. 5]); + assert(strlen(p) == 2); + + string test = ""; + p = toStringz(test); + assert(*p == 0); + + test = "\0"; + p = toStringz(test); + assert(*p == 0); + + test = "foo\0"; + p = toStringz(test); + assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0); + + const string test2 = ""; + p = toStringz(test2); + assert(*p == 0); + + assert(toStringz([]) is toStringz("")); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(indexOf(s, 'W') == 6); + assert(indexOf(s, 'Z') == -1); + assert(indexOf(s, 'w', No.caseSensitive) == 6); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(indexOf(s, 'W', 4) == 6); + assert(indexOf(s, 'Z', 100) == -1); + assert(indexOf(s, 'w', 3, No.caseSensitive) == 6); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(indexOf(s, "Wo", 4) == 6); + assert(indexOf(s, "Zo", 100) == -1); + assert(indexOf(s, "wo", 3, No.caseSensitive) == 6); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(indexOf(s, "Wo") == 6); + assert(indexOf(s, "Zo") == -1); + assert(indexOf(s, "wO", No.caseSensitive) == 6); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(lastIndexOf(s, 'l') == 9); + assert(lastIndexOf(s, 'Z') == -1); + assert(lastIndexOf(s, 'L', No.caseSensitive) == 9); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(lastIndexOf(s, 'l', 4) == 3); + assert(lastIndexOf(s, 'Z', 1337) == -1); + assert(lastIndexOf(s, 'L', 7, No.caseSensitive) == 3); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(lastIndexOf(s, "ll") == 2); + assert(lastIndexOf(s, "Zo") == -1); + assert(lastIndexOf(s, "lL", No.caseSensitive) == 2); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(lastIndexOf(s, "ll", 4) == 2); + assert(lastIndexOf(s, "Zo", 128) == -1); + assert(lastIndexOf(s, "lL", 3, No.caseSensitive) == -1); +} + +@safe pure unittest +{ + import std.string; + + import std.conv : to; + + ptrdiff_t i = "helloWorld".indexOfAny("Wr"); + assert(i == 5); + i = "öällo world".indexOfAny("lo "); + assert(i == 4, to!string(i)); +} + +@safe pure unittest +{ + import std.string; + + import std.conv : to; + + ptrdiff_t i = "helloWorld".indexOfAny("Wr", 4); + assert(i == 5); + + i = "Foo öällo world".indexOfAny("lh", 3); + assert(i == 8, to!string(i)); +} + +@safe pure unittest +{ + import std.string; + + ptrdiff_t i = "helloWorld".lastIndexOfAny("Wlo"); + assert(i == 8); + + i = "Foo öäöllo world".lastIndexOfAny("öF"); + assert(i == 8); +} + +@safe pure unittest +{ + import std.string; + + import std.conv : to; + + ptrdiff_t i = "helloWorld".lastIndexOfAny("Wlo", 4); + assert(i == 3); + + i = "Foo öäöllo world".lastIndexOfAny("öF", 3); + assert(i == 0); +} + +@safe pure unittest +{ + import std.string; + + assert(indexOfNeither("abba", "a", 2) == 2); + assert(indexOfNeither("def", "de", 1) == 2); + assert(indexOfNeither("dfefffg", "dfe", 4) == 6); +} + +@safe pure unittest +{ + import std.string; + + assert(indexOfNeither("def", "a") == 0); + assert(indexOfNeither("def", "de") == 2); + assert(indexOfNeither("dfefffg", "dfe") == 6); +} + +@safe pure unittest +{ + import std.string; + + assert(lastIndexOfNeither("abba", "a") == 2); + assert(lastIndexOfNeither("def", "f") == 1); +} + +@safe pure unittest +{ + import std.string; + + assert(lastIndexOfNeither("def", "rsa", 3) == -1); + assert(lastIndexOfNeither("abba", "a", 2) == 1); +} + +@safe pure unittest +{ + import std.string; + + string s = "hello"; + static assert(is(typeof(representation(s)) == immutable(ubyte)[])); + assert(representation(s) is cast(immutable(ubyte)[]) s); + assert(representation(s) == [0x68, 0x65, 0x6c, 0x6c, 0x6f]); +} + +pure @safe unittest +{ + import std.string; + + assert(capitalize("hello") == "Hello"); + assert(capitalize("World") == "World"); +} + +@safe pure nothrow unittest +{ + import std.string; + + string s = "Hello\nmy\rname\nis"; + assert(splitLines(s) == ["Hello", "my", "name", "is"]); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + + string s = "Hello\nmy\rname\nis"; + + /* notice the call to 'array' to turn the lazy range created by + lineSplitter comparable to the string[] created by splitLines. + */ + assert(lineSplitter(s).array == splitLines(s)); +} + +@nogc @safe pure unittest +{ + import std.string; + + auto s = "\rpeter\n\rpaul\r\njerry\u2028ice\u2029cream\n\nsunday\nmon\u2030day\n"; + auto lines = s.lineSplitter(); + static immutable witness = ["", "peter", "", "paul", "jerry", "ice", "cream", "", "sunday", "mon\u2030day"]; + uint i; + foreach (line; lines) + { + assert(line == witness[i++]); + } + assert(i == witness.length); +} + +nothrow @safe pure unittest +{ + import std.string; + + import std.uni : lineSep, paraSep; + assert(stripLeft(" hello world ") == + "hello world "); + assert(stripLeft("\n\t\v\rhello world\n\t\v\r") == + "hello world\n\t\v\r"); + assert(stripLeft(" \u2028hello world") == + "hello world"); + assert(stripLeft("hello world") == + "hello world"); + assert(stripLeft([lineSep] ~ "hello world" ~ lineSep) == + "hello world" ~ [lineSep]); + assert(stripLeft([paraSep] ~ "hello world" ~ paraSep) == + "hello world" ~ [paraSep]); + + import std.array : array; + import std.utf : byChar; + assert(stripLeft(" hello world "w.byChar).array == + "hello world "); + assert(stripLeft(" \u2022hello world ".byChar).array == + "\u2022hello world "); +} + +@safe pure unittest +{ + import std.string; + + assert(stripLeft(" hello world ", " ") == + "hello world "); + assert(stripLeft("xxxxxhello world ", "x") == + "hello world "); + assert(stripLeft("xxxyy hello world ", "xy ") == + "hello world "); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + import std.utf : byChar, byWchar, byDchar; + + assert(stripLeft(" xxxyy hello world "w.byChar, "xy ").array == + "hello world "); + + assert(stripLeft("\u2028\u2020hello world\u2028"w.byWchar, + "\u2028").array == "\u2020hello world\u2028"); + assert(stripLeft("\U00010001hello world"w.byWchar, " ").array == + "\U00010001hello world"w); + assert(stripLeft("\U00010001 xyhello world"d.byDchar, + "\U00010001 xy").array == "hello world"d); + + assert(stripLeft("\u2020hello"w, "\u2020"w) == "hello"w); + assert(stripLeft("\U00010001hello"d, "\U00010001"d) == "hello"d); + assert(stripLeft(" hello ", "") == " hello "); +} + +nothrow @safe pure unittest +{ + import std.string; + + import std.uni : lineSep, paraSep; + assert(stripRight(" hello world ") == + " hello world"); + assert(stripRight("\n\t\v\rhello world\n\t\v\r") == + "\n\t\v\rhello world"); + assert(stripRight("hello world") == + "hello world"); + assert(stripRight([lineSep] ~ "hello world" ~ lineSep) == + [lineSep] ~ "hello world"); + assert(stripRight([paraSep] ~ "hello world" ~ paraSep) == + [paraSep] ~ "hello world"); +} + +@safe pure unittest +{ + import std.string; + + assert(stripRight(" hello world ", "x") == + " hello world "); + assert(stripRight(" hello world ", " ") == + " hello world"); + assert(stripRight(" hello worldxy ", "xy ") == + " hello world"); +} + +@safe pure unittest +{ + import std.string; + + import std.uni : lineSep, paraSep; + assert(strip(" hello world ") == + "hello world"); + assert(strip("\n\t\v\rhello world\n\t\v\r") == + "hello world"); + assert(strip("hello world") == + "hello world"); + assert(strip([lineSep] ~ "hello world" ~ [lineSep]) == + "hello world"); + assert(strip([paraSep] ~ "hello world" ~ [paraSep]) == + "hello world"); +} + +@safe pure unittest +{ + import std.string; + + assert(strip(" hello world ", "x") == + " hello world "); + assert(strip(" hello world ", " ") == + "hello world"); + assert(strip(" xyxyhello worldxyxy ", "xy ") == + "hello world"); + assert(strip("\u2020hello\u2020"w, "\u2020"w) == "hello"w); + assert(strip("\U00010001hello\U00010001"d, "\U00010001"d) == "hello"d); + assert(strip(" hello ", "") == " hello "); +} + +@safe pure unittest +{ + import std.string; + + assert(strip("xxhelloyy", "x", "y") == "hello"); + assert(strip(" xyxyhello worldxyxyzz ", "xy ", "xyz ") == + "hello world"); + assert(strip("\u2020hello\u2028"w, "\u2020"w, "\u2028"w) == "hello"w); + assert(strip("\U00010001hello\U00010002"d, "\U00010001"d, "\U00010002"d) == + "hello"d); + assert(strip(" hello ", "", "") == " hello "); +} + +@safe pure unittest +{ + import std.string; + + import std.uni : lineSep, paraSep, nelSep; + import std.utf : decode; + assert(chomp(" hello world \n\r") == " hello world \n"); + assert(chomp(" hello world \r\n") == " hello world "); + assert(chomp(" hello world \f") == " hello world "); + assert(chomp(" hello world \v") == " hello world "); + assert(chomp(" hello world \n\n") == " hello world \n"); + assert(chomp(" hello world \n\n ") == " hello world \n\n "); + assert(chomp(" hello world \n\n" ~ [lineSep]) == " hello world \n\n"); + assert(chomp(" hello world \n\n" ~ [paraSep]) == " hello world \n\n"); + assert(chomp(" hello world \n\n" ~ [ nelSep]) == " hello world \n\n"); + assert(chomp(" hello world ") == " hello world "); + assert(chomp(" hello world") == " hello world"); + assert(chomp("") == ""); + + assert(chomp(" hello world", "orld") == " hello w"); + assert(chomp(" hello world", " he") == " hello world"); + assert(chomp("", "hello") == ""); + + // Don't decode pointlessly + assert(chomp("hello\xFE", "\r") == "hello\xFE"); +} + +@safe pure unittest +{ + import std.string; + + assert(chompPrefix("hello world", "he") == "llo world"); + assert(chompPrefix("hello world", "hello w") == "orld"); + assert(chompPrefix("hello world", " world") == "hello world"); + assert(chompPrefix("", "hello") == ""); +} + +@safe pure unittest +{ + import std.string; + + assert(chop("hello world") == "hello worl"); + assert(chop("hello world\n") == "hello world"); + assert(chop("hello world\r") == "hello world"); + assert(chop("hello world\n\r") == "hello world\n"); + assert(chop("hello world\r\n") == "hello world"); + assert(chop("Walter Bright") == "Walter Brigh"); + assert(chop("") == ""); +} + +@safe pure unittest +{ + import std.string; + + assert(leftJustify("hello", 7, 'X') == "helloXX"); + assert(leftJustify("hello", 2, 'X') == "hello"); + assert(leftJustify("hello", 9, 'X') == "helloXXXX"); +} + +@safe pure @nogc nothrow unittest +{ + import std.string; + + import std.algorithm.comparison : equal; + import std.utf : byChar; + assert(leftJustifier("hello", 2).equal("hello".byChar)); + assert(leftJustifier("hello", 7).equal("hello ".byChar)); + assert(leftJustifier("hello", 7, 'x').equal("helloxx".byChar)); +} + +@safe pure unittest +{ + import std.string; + + assert(rightJustify("hello", 7, 'X') == "XXhello"); + assert(rightJustify("hello", 2, 'X') == "hello"); + assert(rightJustify("hello", 9, 'X') == "XXXXhello"); +} + +@safe pure @nogc nothrow unittest +{ + import std.string; + + import std.algorithm.comparison : equal; + import std.utf : byChar; + assert(rightJustifier("hello", 2).equal("hello".byChar)); + assert(rightJustifier("hello", 7).equal(" hello".byChar)); + assert(rightJustifier("hello", 7, 'x').equal("xxhello".byChar)); +} + +@safe pure unittest +{ + import std.string; + + assert(center("hello", 7, 'X') == "XhelloX"); + assert(center("hello", 2, 'X') == "hello"); + assert(center("hello", 9, 'X') == "XXhelloXX"); +} + +@safe pure @nogc nothrow unittest +{ + import std.string; + + import std.algorithm.comparison : equal; + import std.utf : byChar; + assert(centerJustifier("hello", 2).equal("hello".byChar)); + assert(centerJustifier("hello", 8).equal(" hello ".byChar)); + assert(centerJustifier("hello", 7, 'x').equal("xhellox".byChar)); +} + +@safe pure unittest +{ + import std.string; + + assert(detab(" \n\tx", 9) == " \n x"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + + assert(detabber(" \n\tx", 9).array == " \n x"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + import std.utf : byChar, byWchar; + + assert(detabber(" \u2029\t".byChar, 9).array == " \u2029 "); + auto r = "hel\tx".byWchar.detabber(); + assert(r.front == 'h'); + auto s = r.save; + r.popFront(); + r.popFront(); + assert(r.front == 'l'); + assert(s.front == 'h'); +} + +@safe pure unittest +{ + import std.string; + + assert(entab(" x \n") == "\tx\n"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + assert(entabber(" x \n").array == "\tx\n"); +} + +@safe pure unittest +{ + import std.string; + + dchar[dchar] transTable1 = ['e' : '5', 'o' : '7', '5': 'q']; + assert(translate("hello world", transTable1) == "h5ll7 w7rld"); + + assert(translate("hello world", transTable1, "low") == "h5 rd"); + + string[dchar] transTable2 = ['e' : "5", 'o' : "orange"]; + assert(translate("hello world", transTable2) == "h5llorange worangerld"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : appender; + dchar[dchar] transTable1 = ['e' : '5', 'o' : '7', '5': 'q']; + auto buffer = appender!(dchar[])(); + translate("hello world", transTable1, null, buffer); + assert(buffer.data == "h5ll7 w7rld"); + + buffer.clear(); + translate("hello world", transTable1, "low", buffer); + assert(buffer.data == "h5 rd"); + + buffer.clear(); + string[dchar] transTable2 = ['e' : "5", 'o' : "orange"]; + translate("hello world", transTable2, null, buffer); + assert(buffer.data == "h5llorange worangerld"); +} + +@safe pure nothrow unittest +{ + import std.string; + + auto transTable1 = makeTrans("eo5", "57q"); + assert(translate("hello world", transTable1) == "h5ll7 w7rld"); + + assert(translate("hello world", transTable1, "low") == "h5 rd"); +} + +@safe pure nothrow unittest +{ + import std.string; + + auto transTable1 = makeTrans("eo5", "57q"); + assert(translate("hello world", transTable1) == "h5ll7 w7rld"); + + assert(translate("hello world", transTable1, "low") == "h5 rd"); +} + +@safe pure unittest +{ + import std.string; + + assert(translate("hello world", makeTransTable("hl", "q5")) == "qe55o wor5d"); + assert(translate("hello world", makeTransTable("12345", "67890")) == "hello world"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : appender; + auto buffer = appender!(char[])(); + auto transTable1 = makeTransTable("eo5", "57q"); + translate("hello world", transTable1, null, buffer); + assert(buffer.data == "h5ll7 w7rld"); + + buffer.clear(); + translate("hello world", transTable1, "low", buffer); + assert(buffer.data == "h5 rd"); +} + +@safe pure unittest +{ + import std.string; + + assert(succ("1") == "2"); + assert(succ("9") == "10"); + assert(succ("999") == "1000"); + assert(succ("zz99") == "aaa00"); +} + +@safe pure unittest +{ + import std.string; + + assert(tr("abcdef", "cd", "CD") == "abCDef"); + assert(tr("1st March, 2018", "March", "MAR", "s") == "1st MAR, 2018"); + assert(tr("abcdef", "ef", "", "d") == "abcd"); + assert(tr("14-Jul-87", "a-zA-Z", " ", "cs") == " Jul "); +} + +@safe @nogc pure nothrow unittest +{ + import std.string; + + assert(isNumeric("123")); + assert(isNumeric("123UL")); + assert(isNumeric("123L")); + assert(isNumeric("+123U")); + assert(isNumeric("-123L")); +} + +@safe @nogc pure nothrow unittest +{ + import std.string; + + assert(isNumeric("+123")); + assert(isNumeric("-123.01")); + assert(isNumeric("123.3e-10f")); + assert(isNumeric("123.3e-10fi")); + assert(isNumeric("123.3e-10L")); + + assert(isNumeric("nan")); + assert(isNumeric("nani")); + assert(isNumeric("-inf")); +} + +@safe @nogc pure nothrow unittest +{ + import std.string; + + assert(isNumeric("-123e-1+456.9e-10Li")); + assert(isNumeric("+123e+10+456i")); + assert(isNumeric("123+456")); +} + +@safe pure unittest +{ + import std.string; + + enum a = isNumeric("123.00E-5+1234.45E-12Li"); + enum b = isNumeric("12345xxxx890"); + + static assert( a); + static assert(!b); +} + +@safe unittest +{ + import std.string; + + assert(soundexer("Gauss") == "G200"); + assert(soundexer("Ghosh") == "G200"); + + assert(soundexer("Robert") == "R163"); + assert(soundexer("Rupert") == "R163"); + + assert(soundexer("0123^&^^**&^") == ['\0', '\0', '\0', '\0']); +} + +@safe unittest +{ + import std.string; + + assert(soundex("Gauss") == "G200"); + assert(soundex("Ghosh") == "G200"); + + assert(soundex("Robert") == "R163"); + assert(soundex("Rupert") == "R163"); + + assert(soundex("0123^&^^**&^") == null); +} + +@safe unittest +{ + import std.string; + + import std.string; + + static string[] list = [ "food", "foxy" ]; + auto abbrevs = abbrev(list); + assert(abbrevs == ["fox": "foxy", "food": "food", + "foxy": "foxy", "foo": "food"]); +} + +@safe pure unittest +{ + import std.string; + + import std.utf : byChar, byWchar, byDchar; + + assert(column("1234 ") == 5); + assert(column("1234 "w) == 5); + assert(column("1234 "d) == 5); + + assert(column("1234 ".byChar()) == 5); + assert(column("1234 "w.byWchar()) == 5); + assert(column("1234 "d.byDchar()) == 5); + + // Tab stops are set at 8 spaces by default; tab characters insert enough + // spaces to bring the column position to the next multiple of 8. + assert(column("\t") == 8); + assert(column("1\t") == 8); + assert(column("\t1") == 9); + assert(column("123\t") == 8); + + // Other tab widths are possible by specifying it explicitly: + assert(column("\t", 4) == 4); + assert(column("1\t", 4) == 4); + assert(column("\t1", 4) == 5); + assert(column("123\t", 4) == 4); + + // New lines reset the column number. + assert(column("abc\n") == 0); + assert(column("abc\n1") == 1); + assert(column("abcdefg\r1234") == 4); + assert(column("abc\u20281") == 1); + assert(column("abc\u20291") == 1); + assert(column("abc\u00851") == 1); + assert(column("abc\u00861") == 5); +} + +@safe pure unittest +{ + import std.string; + + assert(wrap("a short string", 7) == "a short\nstring\n"); + + // wrap will not break inside of a word, but at the next space + assert(wrap("a short string", 4) == "a\nshort\nstring\n"); + + assert(wrap("a short string", 7, "\t") == "\ta\nshort\nstring\n"); + assert(wrap("a short string", 7, "\t", " ") == "\ta\n short\n string\n"); +} + +@safe pure unittest +{ + import std.string; + + enum pretty = q{ + import std.stdio; + void main() { + writeln("Hello"); + } + }.outdent(); + + enum ugly = q{ +import std.stdio; +void main() { + writeln("Hello"); +} +}; + + assert(pretty == ugly); +} + +@safe pure unittest +{ + import std.string; + + auto str1 = [ + " void main()\n", + " {\n", + " test();\n", + " }\n" + ]; + auto str1Expected = [ + "void main()\n", + "{\n", + " test();\n", + "}\n" + ]; + assert(str1.outdent == str1Expected); + + auto str2 = [ + "void main()\n", + " {\n", + " test();\n", + " }\n" + ]; + assert(str2.outdent == str2); +} + +@safe pure unittest +{ + import std.string; + + string a = "Hölo World"; + immutable(ubyte)[] b = a.representation; + string c = b.assumeUTF; + + assert(c == "Hölo World"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_sumtype.d b/libphobos/testsuite/libphobos.phobos/std_sumtype.d new file mode 100644 index 0000000000000000000000000000000000000000..2a7eaf35f125d8df124c8b25e74a336842f1b428 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_sumtype.d @@ -0,0 +1,301 @@ +@safe unittest +{ + import std.sumtype; + + import std.math.operations : isClose; + + struct Fahrenheit { double degrees; } + struct Celsius { double degrees; } + struct Kelvin { double degrees; } + + alias Temperature = SumType!(Fahrenheit, Celsius, Kelvin); + + // Construct from any of the member types. + Temperature t1 = Fahrenheit(98.6); + Temperature t2 = Celsius(100); + Temperature t3 = Kelvin(273); + + // Use pattern matching to access the value. + Fahrenheit toFahrenheit(Temperature t) + { + return Fahrenheit( + t.match!( + (Fahrenheit f) => f.degrees, + (Celsius c) => c.degrees * 9.0/5 + 32, + (Kelvin k) => k.degrees * 9.0/5 - 459.4 + ) + ); + } + + assert(toFahrenheit(t1).degrees.isClose(98.6)); + assert(toFahrenheit(t2).degrees.isClose(212)); + assert(toFahrenheit(t3).degrees.isClose(32)); + + // Use ref to modify the value in place. + void freeze(ref Temperature t) + { + t.match!( + (ref Fahrenheit f) => f.degrees = 32, + (ref Celsius c) => c.degrees = 0, + (ref Kelvin k) => k.degrees = 273 + ); + } + + freeze(t1); + assert(toFahrenheit(t1).degrees.isClose(32)); + + // Use a catch-all handler to give a default result. + bool isFahrenheit(Temperature t) + { + return t.match!( + (Fahrenheit f) => true, + _ => false + ); + } + + assert(isFahrenheit(t1)); + assert(!isFahrenheit(t2)); + assert(!isFahrenheit(t3)); +} + +@safe unittest +{ + import std.sumtype; + + alias ExampleSumType = SumType!(int, string, double); + + ExampleSumType a = 123; + ExampleSumType b = "hello"; + ExampleSumType c = 3.14; + + assert(a.handle == "got an int"); + assert(b.handle == "got a string"); + assert(c.handle == "got a double"); +} + +@system unittest +{ + import std.sumtype; + + import std.functional : partial; + import std.traits : EnumMembers; + import std.typecons : Tuple; + + enum Op : string + { + Plus = "+", + Minus = "-", + Times = "*", + Div = "/" + } + + // An expression is either + // - a number, + // - a variable, or + // - a binary operation combining two sub-expressions. + alias Expr = SumType!( + double, + string, + Tuple!(Op, "op", This*, "lhs", This*, "rhs") + ); + + // Shorthand for Tuple!(Op, "op", Expr*, "lhs", Expr*, "rhs"), + // the Tuple type above with Expr substituted for This. + alias BinOp = Expr.Types[2]; + + // Factory function for number expressions + Expr* num(double value) + { + return new Expr(value); + } + + // Factory function for variable expressions + Expr* var(string name) + { + return new Expr(name); + } + + // Factory function for binary operation expressions + Expr* binOp(Op op, Expr* lhs, Expr* rhs) + { + return new Expr(BinOp(op, lhs, rhs)); + } + + // Convenience wrappers for creating BinOp expressions + alias sum = partial!(binOp, Op.Plus); + alias diff = partial!(binOp, Op.Minus); + alias prod = partial!(binOp, Op.Times); + alias quot = partial!(binOp, Op.Div); + + // Evaluate expr, looking up variables in env + double eval(Expr expr, double[string] env) + { + return expr.match!( + (double num) => num, + (string var) => env[var], + (BinOp bop) + { + double lhs = eval(*bop.lhs, env); + double rhs = eval(*bop.rhs, env); + final switch (bop.op) + { + static foreach (op; EnumMembers!Op) + { + case op: + return mixin("lhs" ~ op ~ "rhs"); + } + } + } + ); + } + + // Return a "pretty-printed" representation of expr + string pprint(Expr expr) + { + import std.format : format; + + return expr.match!( + (double num) => "%g".format(num), + (string var) => var, + (BinOp bop) => "(%s %s %s)".format( + pprint(*bop.lhs), + cast(string) bop.op, + pprint(*bop.rhs) + ) + ); + } + + Expr* myExpr = sum(var("a"), prod(num(2), var("b"))); + double[string] myEnv = ["a":3, "b":4, "c":7]; + + assert(eval(*myExpr, myEnv) == 11); + assert(pprint(*myExpr) == "(a + (2 * b))"); +} + +@safe unittest +{ + import std.sumtype; + + static struct ConvertsToSumType + { + SumType!int payload; + alias payload this; + } + + static struct ContainsSumType + { + SumType!int payload; + } + + assert(isSumType!(SumType!int)); + assert(isSumType!ConvertsToSumType); + assert(!isSumType!ContainsSumType); +} + +@safe unittest +{ + import std.sumtype; + + alias Number = SumType!(double, int); + + Number x; + + // Problem: because int implicitly converts to double, the double + // handler is used for both types, and the int handler never matches. + assert(!__traits(compiles, + x.match!( + (double d) => "got double", + (int n) => "got int" + ) + )); + + // Solution 1: put the handler for the "more specialized" type (in this + // case, int) before the handler for the type it converts to. + assert(__traits(compiles, + x.match!( + (int n) => "got int", + (double d) => "got double" + ) + )); + + // Solution 2: use a template that only accepts the exact type it's + // supposed to match, instead of any type that implicitly converts to it. + alias exactly(T, alias fun) = function (arg) + { + static assert(is(typeof(arg) == T)); + return fun(arg); + }; + + // Now, even if we put the double handler first, it will only be used for + // doubles, not ints. + assert(__traits(compiles, + x.match!( + exactly!(double, d => "got double"), + exactly!(int, n => "got int") + ) + )); +} + +@safe unittest +{ + import std.sumtype; + + struct Point2D { double x, y; } + struct Point3D { double x, y, z; } + + alias Point = SumType!(Point2D, Point3D); + + version (none) + { + // This function works, but the code is ugly and repetitive. + // It uses three separate calls to match! + @safe pure nothrow @nogc + bool sameDimensions(Point p1, Point p2) + { + return p1.match!( + (Point2D _) => p2.match!( + (Point2D _) => true, + _ => false + ), + (Point3D _) => p2.match!( + (Point3D _) => true, + _ => false + ) + ); + } + } + + // This version is much nicer. + @safe pure nothrow @nogc + bool sameDimensions(Point p1, Point p2) + { + alias doMatch = match!( + (Point2D _1, Point2D _2) => true, + (Point3D _1, Point3D _2) => true, + (_1, _2) => false + ); + + return doMatch(p1, p2); + } + + Point a = Point2D(1, 2); + Point b = Point2D(3, 4); + Point c = Point3D(5, 6, 7); + Point d = Point3D(8, 9, 0); + + assert( sameDimensions(a, b)); + assert( sameDimensions(c, d)); + assert(!sameDimensions(a, c)); + assert(!sameDimensions(d, b)); +} + +@safe unittest +{ + import std.sumtype; + + alias handleInt = (int i) => "got an int"; + + assert( canMatch!(handleInt, int)); + assert(!canMatch!(handleInt, string)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_traits.d b/libphobos/testsuite/libphobos.phobos/std_traits.d new file mode 100644 index 0000000000000000000000000000000000000000..a86892c26ab8cf4c0b8b6f6ec9b9b44ed7759d1f --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_traits.d @@ -0,0 +1,2419 @@ +@safe unittest +{ + import std.traits; + + static assert(is(InoutOf!(int) == inout int)); + static assert(is(InoutOf!(inout int) == inout int)); + static assert(is(InoutOf!(const int) == inout const int)); + static assert(is(InoutOf!(shared int) == inout shared int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(ConstOf!(int) == const int)); + static assert(is(ConstOf!(const int) == const int)); + static assert(is(ConstOf!(inout int) == const inout int)); + static assert(is(ConstOf!(shared int) == const shared int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(SharedOf!(int) == shared int)); + static assert(is(SharedOf!(shared int) == shared int)); + static assert(is(SharedOf!(inout int) == shared inout int)); + static assert(is(SharedOf!(immutable int) == shared immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(SharedInoutOf!(int) == shared inout int)); + static assert(is(SharedInoutOf!(int) == inout shared int)); + + static assert(is(SharedInoutOf!(const int) == shared inout const int)); + static assert(is(SharedInoutOf!(immutable int) == shared inout immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(SharedConstOf!(int) == shared const int)); + static assert(is(SharedConstOf!(int) == const shared int)); + + static assert(is(SharedConstOf!(inout int) == shared inout const int)); + // immutable variables are implicitly shared and const + static assert(is(SharedConstOf!(immutable int) == immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(SharedConstInoutOf!(int) == shared const inout int)); + static assert(is(SharedConstInoutOf!(int) == const shared inout int)); + static assert(is(SharedConstInoutOf!(inout int) == shared inout const int)); + // immutable variables are implicitly shared and const + static assert(is(SharedConstInoutOf!(immutable int) == immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(ImmutableOf!(int) == immutable int)); + static assert(is(ImmutableOf!(const int) == immutable int)); + static assert(is(ImmutableOf!(inout int) == immutable int)); + static assert(is(ImmutableOf!(shared int) == immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(__traits(isSame, QualifierOf!(shared const inout int), SharedConstInoutOf)); + static assert(__traits(isSame, QualifierOf!(immutable int), ImmutableOf)); + static assert(__traits(isSame, QualifierOf!(shared int), SharedOf)); + static assert(__traits(isSame, QualifierOf!(shared inout int), SharedInoutOf)); + import std.meta : Alias; + static assert(__traits(isSame, QualifierOf!(int), Alias)); +} + +@safe unittest +{ + import std.traits; + + static assert(packageName!packageName == "std"); +} + +@safe unittest +{ + import std.traits; + + static assert(packageName!moduleName == "std"); +} + +@safe unittest +{ + import std.traits; + + static assert(moduleName!moduleName == "std.traits"); +} + +@safe unittest +{ + import std.traits; + + static assert(fullyQualifiedName!fullyQualifiedName == "std.traits.fullyQualifiedName"); +} + +@safe unittest +{ + import std.traits; + + int foo(); + ReturnType!foo x; // x is declared as int +} + +@safe unittest +{ + import std.traits; + + int foo(int, long); + void bar(Parameters!foo); // declares void bar(int, long); + void abc(Parameters!foo[1]); // declares void abc(long); +} + +@safe unittest +{ + import std.traits; + + void foo(){} + static assert(arity!foo == 0); + void bar(uint){} + static assert(arity!bar == 1); + void variadicFoo(uint...){} + static assert(!__traits(compiles, arity!variadicFoo)); +} + +@safe unittest +{ + import std.traits; + + alias STC = ParameterStorageClass; // shorten the enum name + + void func(ref int ctx, out real result, in real param, void* ptr) + { + } + alias pstc = ParameterStorageClassTuple!func; + static assert(pstc.length == 4); // number of parameters + static assert(pstc[0] == STC.ref_); + static assert(pstc[1] == STC.out_); + version (none) + { + // TODO: When the DMD PR (dlang/dmd#11474) gets merged, + // remove the versioning and the second test + static assert(pstc[2] == STC.in_); + // This is the current behavior, before `in` is fixed to not be an alias + static assert(pstc[2] == STC.scope_); + } + static assert(pstc[3] == STC.none); +} + +@safe unittest +{ + import std.traits; + + static void func(ref int ctx, out real result); + + enum param1 = extractParameterStorageClassFlags!( + __traits(getParameterStorageClasses, func, 0) + ); + static assert(param1 == ParameterStorageClass.ref_); + + enum param2 = extractParameterStorageClassFlags!( + __traits(getParameterStorageClasses, func, 1) + ); + static assert(param2 == ParameterStorageClass.out_); + + enum param3 = extractParameterStorageClassFlags!( + __traits(getParameterStorageClasses, func, 0), + __traits(getParameterStorageClasses, func, 1) + ); + static assert(param3 == (ParameterStorageClass.ref_ | ParameterStorageClass.out_)); +} + +@safe unittest +{ + import std.traits; + + int foo(int num, string name, int); + static assert([ParameterIdentifierTuple!foo] == ["num", "name", ""]); +} + +@safe unittest +{ + import std.traits; + + int foo(int num, string name = "hello", int[] = [1,2,3], lazy int x = 0); + static assert(is(ParameterDefaults!foo[0] == void)); + static assert( ParameterDefaults!foo[1] == "hello"); + static assert( ParameterDefaults!foo[2] == [1,2,3]); + static assert( ParameterDefaults!foo[3] == 0); +} + +@safe unittest +{ + import std.traits; + + alias FA = FunctionAttribute; // shorten the enum name + + real func(real x) pure nothrow @safe + { + return x; + } + static assert(functionAttributes!func & FA.pure_); + static assert(functionAttributes!func & FA.safe); + static assert(!(functionAttributes!func & FA.trusted)); // not @trusted +} + +@safe unittest +{ + import std.traits; + + real func(real x) pure nothrow @safe; + static assert(hasFunctionAttributes!(func, "@safe", "pure")); + static assert(!hasFunctionAttributes!(func, "@trusted")); + + // for templates attributes are automatically inferred + bool myFunc(T)(T b) + { + return !b; + } + static assert(hasFunctionAttributes!(myFunc!bool, "@safe", "pure", "@nogc", "nothrow")); + static assert(!hasFunctionAttributes!(myFunc!bool, "shared")); +} + +@safe unittest +{ + import std.traits; + + @safe int add(int a, int b) {return a+b;} + @trusted int sub(int a, int b) {return a-b;} + @system int mul(int a, int b) {return a*b;} + + static assert( isSafe!add); + static assert( isSafe!sub); + static assert(!isSafe!mul); +} + +@safe unittest +{ + import std.traits; + + @safe int add(int a, int b) {return a+b;} + @trusted int sub(int a, int b) {return a-b;} + @system int mul(int a, int b) {return a*b;} + + static assert(!isUnsafe!add); + static assert(!isUnsafe!sub); + static assert( isUnsafe!mul); +} + +@safe unittest +{ + import std.traits; + + extern(D) void Dfunc() {} + extern(C) void Cfunc() {} + static assert(functionLinkage!Dfunc == "D"); + static assert(functionLinkage!Cfunc == "C"); + + string a = functionLinkage!Dfunc; + assert(a == "D"); + + auto fp = &Cfunc; + string b = functionLinkage!fp; + assert(b == "C"); +} + +@safe unittest +{ + import std.traits; + + void func() {} + static assert(variadicFunctionStyle!func == Variadic.no); + + extern(C) int printf(const char*, ...); + static assert(variadicFunctionStyle!printf == Variadic.c); +} + +@safe unittest +{ + import std.traits; + + class C + { + int value() @property => 0; + static string opCall() => "hi"; + } + static assert(is( typeof(C.value) == int )); + static assert(is( FunctionTypeOf!(C.value) == function )); + static assert(is( FunctionTypeOf!C == typeof(C.opCall) )); + + int function() fp; + alias IntFn = int(); + static assert(is( typeof(fp) == IntFn* )); + static assert(is( FunctionTypeOf!fp == IntFn )); +} + +@safe unittest +{ + import std.traits; + + alias ExternC(T) = SetFunctionAttributes!(T, "C", functionAttributes!T); + + auto assumePure(T)(T t) + if (isFunctionPointer!T || isDelegate!T) + { + enum attrs = functionAttributes!T | FunctionAttribute.pure_; + return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; + } + + int f() + { + import core.thread : getpid; + return getpid(); + } + + int g() pure @trusted + { + auto pureF = assumePure(&f); + return pureF(); + } + assert(g() > 0); +} + +@safe unittest +{ + import std.traits; + + class C + { + int outer; + } + static assert(!isInnerClass!C); + + class Outer1 + { + class Inner1 { } + class Inner2 + { + int outer; + } + } + static assert(isInnerClass!(Outer1.Inner1)); + static assert(!isInnerClass!(Outer1.Inner2)); + + static class Outer2 + { + static class Inner + { + int outer; + } + } + static assert(!isInnerClass!(Outer2.Inner)); +} + +@safe unittest +{ + import std.traits; + + static struct S { } + static assert(!isNested!S); + + int i; + struct NestedStruct { void f() { ++i; } } + static assert(isNested!NestedStruct); +} + +@safe unittest +{ + import std.traits; + + static struct S { } + + int i; + struct NS { void f() { ++i; } } + + static assert(!hasNested!(S[2])); + static assert(hasNested!(NS[2])); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + struct S { int x; float y; } + static assert(is(Fields!S == AliasSeq!(int, float))); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + struct S { int x; float y; } + static assert(FieldNameTuple!S == AliasSeq!("x", "y")); + static assert(FieldNameTuple!int == AliasSeq!""); +} + +@safe unittest +{ + import std.traits; + + struct S1 { int a; float b; } + struct S2 { char[] a; union { S1 b; S1 * c; } } + alias R = RepresentationTypeTuple!S2; + assert(R.length == 4 + && is(R[0] == char[]) && is(R[1] == int) + && is(R[2] == float) && is(R[3] == S1*)); +} + +@safe unittest +{ + import std.traits; + + struct S1 { int a; Object b; } + struct S2 { string a; } + struct S3 { int a; immutable Object b; } + struct S4 { float[3] vals; } + static assert( hasAliasing!S1); + static assert(!hasAliasing!S2); + static assert(!hasAliasing!S3); + static assert(!hasAliasing!S4); +} + +@safe unittest +{ + import std.traits; + + static assert( hasIndirections!(int[string])); + static assert( hasIndirections!(void delegate())); + static assert( hasIndirections!(void delegate() immutable)); + static assert( hasIndirections!(immutable(void delegate()))); + static assert( hasIndirections!(immutable(void delegate() immutable))); + + static assert(!hasIndirections!(void function())); + static assert( hasIndirections!(void*[1])); + static assert(!hasIndirections!(byte[1])); +} + +@safe unittest +{ + import std.traits; + + struct S1 { int a; Object b; } + struct S2 { string a; } + struct S3 { int a; immutable Object b; } + static assert( hasUnsharedAliasing!S1); + static assert(!hasUnsharedAliasing!S2); + static assert(!hasUnsharedAliasing!S3); + + struct S4 { int a; shared Object b; } + struct S5 { char[] a; } + struct S6 { shared char[] b; } + struct S7 { float[3] vals; } + static assert(!hasUnsharedAliasing!S4); + static assert( hasUnsharedAliasing!S5); + static assert(!hasUnsharedAliasing!S6); + static assert(!hasUnsharedAliasing!S7); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasElaborateCopyConstructor!int); + + static struct S1 { } + static struct S2 { this(this) {} } + static struct S3 { S2 field; } + static struct S4 { S3[1] field; } + static struct S5 { S3[] field; } + static struct S6 { S3[0] field; } + static struct S7 { @disable this(); S3 field; } + static assert(!hasElaborateCopyConstructor!S1); + static assert( hasElaborateCopyConstructor!S2); + static assert( hasElaborateCopyConstructor!(immutable S2)); + static assert( hasElaborateCopyConstructor!S3); + static assert( hasElaborateCopyConstructor!(S3[1])); + static assert(!hasElaborateCopyConstructor!(S3[0])); + static assert( hasElaborateCopyConstructor!S4); + static assert(!hasElaborateCopyConstructor!S5); + static assert(!hasElaborateCopyConstructor!S6); + static assert( hasElaborateCopyConstructor!S7); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasElaborateAssign!int); + + static struct S { void opAssign(S) {} } + static assert( hasElaborateAssign!S); + static assert(!hasElaborateAssign!(const(S))); + + static struct S1 { void opAssign(ref S1) {} } + static struct S2 { void opAssign(int) {} } + static struct S3 { S s; } + static assert( hasElaborateAssign!S1); + static assert(!hasElaborateAssign!S2); + static assert( hasElaborateAssign!S3); + static assert( hasElaborateAssign!(S3[1])); + static assert(!hasElaborateAssign!(S3[0])); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasElaborateDestructor!int); + + static struct S1 { } + static struct S2 { ~this() {} } + static struct S3 { S2 field; } + static struct S4 { S3[1] field; } + static struct S5 { S3[] field; } + static struct S6 { S3[0] field; } + static struct S7 { @disable this(); S3 field; } + static assert(!hasElaborateDestructor!S1); + static assert( hasElaborateDestructor!S2); + static assert( hasElaborateDestructor!(immutable S2)); + static assert( hasElaborateDestructor!S3); + static assert( hasElaborateDestructor!(S3[1])); + static assert(!hasElaborateDestructor!(S3[0])); + static assert( hasElaborateDestructor!S4); + static assert(!hasElaborateDestructor!S5); + static assert(!hasElaborateDestructor!S6); + static assert( hasElaborateDestructor!S7); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasElaborateMove!int); + + static struct S1 { } + static struct S2 { void opPostMove(ref S2) {} } + static struct S3 { void opPostMove(inout ref S3) inout {} } + static struct S4 { void opPostMove(const ref S4) {} } + static struct S5 { void opPostMove(S5) {} } + static struct S6 { void opPostMove(int) {} } + static struct S7 { S3[1] field; } + static struct S8 { S3[] field; } + static struct S9 { S3[0] field; } + static struct S10 { @disable this(); S3 field; } + static assert(!hasElaborateMove!S1); + static assert( hasElaborateMove!S2); + static assert( hasElaborateMove!S3); + static assert( hasElaborateMove!(immutable S3)); + static assert( hasElaborateMove!S4); + static assert(!hasElaborateMove!S5); + static assert(!hasElaborateMove!S6); + static assert( hasElaborateMove!S7); + static assert(!hasElaborateMove!S8); + static assert(!hasElaborateMove!S9); + static assert( hasElaborateMove!S10); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasMember!(int, "blah")); + struct S1 { int blah; } + struct S2 { int blah(){ return 0; } } + class C1 { int blah; } + class C2 { int blah(){ return 0; } } + static assert(hasMember!(S1, "blah")); + static assert(hasMember!(S2, "blah")); + static assert(hasMember!(C1, "blah")); + static assert(hasMember!(C2, "blah")); +} + +@safe unittest +{ + import std.traits; + + static struct S + { + static void sf() {} + void f() {} + + static int si; + int i; + } + + static assert( hasStaticMember!(S, "sf")); + static assert(!hasStaticMember!(S, "f")); + + static assert( hasStaticMember!(S, "si")); + static assert(!hasStaticMember!(S, "i")); + + static assert(!hasStaticMember!(S, "hello")); +} + +@safe unittest +{ + import std.traits; + + enum Sqrts : real + { + one = 1, + two = 1.41421, + three = 1.73205 + } + auto sqrts = [EnumMembers!Sqrts]; + assert(sqrts == [Sqrts.one, Sqrts.two, Sqrts.three]); +} + +@safe unittest +{ + import std.traits; + + // Returns i if e is the i-th enumerator of E. + static size_t rank(E)(E e) + if (is(E == enum)) + { + static foreach (i, member; EnumMembers!E) + { + if (e == member) + return i; + } + assert(0, "Not an enum member"); + } + + enum Mode + { + read = 1, + write = 2, + map = 4 + } + assert(rank(Mode.read) == 0); + assert(rank(Mode.write) == 1); + assert(rank(Mode.map) == 2); +} + +@safe unittest +{ + import std.traits; + + import std.conv : to; + class FooClass + { + string calledMethod; + void foo() @safe { calledMethod = "foo"; } + void bar() @safe { calledMethod = "bar"; } + void baz() @safe { calledMethod = "baz"; } + } + + enum FooEnum { foo, bar, baz } + + auto var = FooEnum.bar; + auto fooObj = new FooClass(); + s: final switch (var) + { + static foreach (member; EnumMembers!FooEnum) + { + case member: // Generate a case for each enum value. + // Call fooObj.{name of enum value}(). + __traits(getMember, fooObj, to!string(member))(); + break s; + } + } + // As we pass in FooEnum.bar, the bar() method gets called. + assert(fooObj.calledMethod == "bar"); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + interface I1 { } + interface I2 { } + interface I12 : I1, I2 { } + static assert(is(BaseTypeTuple!I12 == AliasSeq!(I1, I2))); + + interface I3 : I1 { } + interface I123 : I1, I2, I3 { } + static assert(is(BaseTypeTuple!I123 == AliasSeq!(I1, I2, I3))); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + class C1 { } + class C2 : C1 { } + class C3 : C2 { } + static assert(!BaseClassesTuple!Object.length); + static assert(is(BaseClassesTuple!C1 == AliasSeq!(Object))); + static assert(is(BaseClassesTuple!C2 == AliasSeq!(C1, Object))); + static assert(is(BaseClassesTuple!C3 == AliasSeq!(C2, C1, Object))); +} + +@safe unittest +{ + import std.traits; + + interface I1 {} + interface I2 {} + class A : I1, I2 {} + class B : A, I1 {} + class C : B {} + + alias TL = InterfacesTuple!C; + static assert(is(TL[0] == I1) && is(TL[1] == I2)); +} + +@safe unittest +{ + import std.traits; + + interface J1 {} + interface J2 {} + class B1 {} + class B2 : B1, J1, J2 {} + class B3 : B2, J1 {} + alias TL = TransitiveBaseTypeTuple!B3; + assert(TL.length == 5); + assert(is (TL[0] == B2)); + assert(is (TL[1] == B1)); + assert(is (TL[2] == Object)); + assert(is (TL[3] == J1)); + assert(is (TL[4] == J2)); + + assert(TransitiveBaseTypeTuple!Object.length == 0); +} + +@safe unittest +{ + import std.traits; + + interface I { I foo(); } + class B + { + real foo(real v) { return v; } + } + class C : B, I + { + override C foo() { return this; } // covariant overriding of I.foo() + } + alias foos = MemberFunctionsTuple!(C, "foo"); + static assert(foos.length == 2); + static assert(__traits(isSame, foos[0], C.foo)); + static assert(__traits(isSame, foos[1], B.foo)); +} + +@safe unittest +{ + import std.traits; + + struct Foo(T, U) {} + static assert(__traits(isSame, TemplateOf!(Foo!(int, real)), Foo)); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + struct Foo(T, U) {} + static assert(is(TemplateArgsOf!(Foo!(int, real)) == AliasSeq!(int, real))); +} + +@safe unittest +{ + import std.traits; + + class A { byte b; } + class B { long l; } + + // As class instance always has a hidden pointer + static assert(classInstanceAlignment!A == (void*).alignof); + static assert(classInstanceAlignment!B == long.alignof); +} + +@safe unittest +{ + import std.traits; + + alias X = CommonType!(int, long, short); + assert(is(X == long)); + alias Y = CommonType!(int, char[], short); + assert(is(Y == void)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(CommonType!(3) == int)); + static assert(is(CommonType!(double, 4, float) == double)); + static assert(is(CommonType!(string, char[]) == const(char)[])); + static assert(is(CommonType!(3, 3U) == uint)); + static assert(is(CommonType!(double, int) == double)); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + static assert(is(AllImplicitConversionTargets!(ulong) == AliasSeq!(long, float, double, real))); + static assert(is(AllImplicitConversionTargets!(int) == AliasSeq!(dchar, uint, long, ulong, float, double, real))); + static assert(is(AllImplicitConversionTargets!(float) == AliasSeq!(double, real))); + static assert(is(AllImplicitConversionTargets!(double) == AliasSeq!(float, real))); + + static assert(is(AllImplicitConversionTargets!(char) == + AliasSeq!(byte, ubyte, short, ushort, wchar, int, dchar, uint, long, + ulong, float, double, real) + )); + static assert(is(AllImplicitConversionTargets!(wchar) == AliasSeq!( + short, ushort, dchar, int, uint, long, ulong, float, double, real + ))); + static assert(is(AllImplicitConversionTargets!(dchar) == AliasSeq!( + int, uint, long, ulong, float, double, real + ))); + + static assert(is(AllImplicitConversionTargets!(string) == AliasSeq!(const(char)[]))); + static assert(is(AllImplicitConversionTargets!(int*) == AliasSeq!(void*))); + + interface A {} + interface B {} + class C : A, B {} + + static assert(is(AllImplicitConversionTargets!(C) == AliasSeq!(Object, A, B))); + static assert(is(AllImplicitConversionTargets!(const C) == AliasSeq!(const Object, const A, const B))); + static assert(is(AllImplicitConversionTargets!(immutable C) == AliasSeq!( + immutable Object, immutable A, immutable B + ))); + + interface I : A, B {} + + static assert(is(AllImplicitConversionTargets!(I) == AliasSeq!(A, B))); + static assert(is(AllImplicitConversionTargets!(const I) == AliasSeq!(const A, const B))); + static assert(is(AllImplicitConversionTargets!(immutable I) == AliasSeq!( + immutable A, immutable B + ))); +} + +@safe unittest +{ + import std.traits; + + static assert( isImplicitlyConvertible!(immutable(char), char)); + static assert( isImplicitlyConvertible!(const(char), char)); + static assert( isImplicitlyConvertible!(char, wchar)); + static assert(!isImplicitlyConvertible!(wchar, char)); + + static assert(!isImplicitlyConvertible!(const(ushort), ubyte)); + static assert(!isImplicitlyConvertible!(const(uint), ubyte)); + static assert(!isImplicitlyConvertible!(const(ulong), ubyte)); + + static assert(!isImplicitlyConvertible!(const(char)[], string)); + static assert( isImplicitlyConvertible!(string, const(char)[])); +} + +@safe unittest +{ + import std.traits; + + // Mutable and immmutable both convert to const... + static assert( isQualifierConvertible!(char, const(char))); + static assert( isQualifierConvertible!(immutable(char), const(char))); + // ...but const does not convert back to mutable or immutable + static assert(!isQualifierConvertible!(const(char), char)); + static assert(!isQualifierConvertible!(const(char), immutable(char))); +} + +@safe unittest +{ + import std.traits; + + static assert( isAssignable!(long, int)); + static assert(!isAssignable!(int, long)); + static assert( isAssignable!(const(char)[], string)); + static assert(!isAssignable!(string, char[])); + + // int is assignable to int + static assert( isAssignable!int); + + // immutable int is not assignable to immutable int + static assert(!isAssignable!(immutable int)); +} + +@safe unittest +{ + import std.traits; + + struct S1 + { + void opAssign(S1); + } + + struct S2 + { + void opAssign(ref S2); + } + + static assert( isRvalueAssignable!(long, int)); + static assert(!isRvalueAssignable!(int, long)); + static assert( isRvalueAssignable!S1); + static assert(!isRvalueAssignable!S2); +} + +@safe unittest +{ + import std.traits; + + struct S1 + { + void opAssign(S1); + } + + struct S2 + { + void opAssign(ref S2); + } + + static assert( isLvalueAssignable!(long, int)); + static assert(!isLvalueAssignable!(int, long)); + static assert( isLvalueAssignable!S1); + static assert( isLvalueAssignable!S2); +} + +@safe unittest +{ + import std.traits; + + interface I { I clone(); } + interface J { J clone(); } + class C : I + { + override C clone() // covariant overriding of I.clone() + { + return new C; + } + } + + // C.clone() can override I.clone(), indeed. + static assert(isCovariantWith!(typeof(C.clone), typeof(I.clone))); + + // C.clone() can't override J.clone(); the return type C is not implicitly + // convertible to J. + static assert(!isCovariantWith!(typeof(C.clone), typeof(J.clone))); +} + +@system unittest +{ + import std.traits; + + static int f(int); + static assert(is(typeof(f(rvalueOf!int)) == int)); +} + +@system unittest +{ + import std.traits; + + static bool f(ref int); + static assert(is(typeof(f(lvalueOf!int)) == bool)); +} + +@safe unittest +{ + import std.traits; + + static assert( isBoolean!bool); + enum EB : bool { a = true } + static assert( isBoolean!EB); + + struct SubTypeOfBool + { + bool val; + alias val this; + } + static assert(!isBoolean!(SubTypeOfBool)); +} + +@safe unittest +{ + import std.traits; + + static assert( + isIntegral!byte && + isIntegral!short && + isIntegral!int && + isIntegral!long && + isIntegral!(const(long)) && + isIntegral!(immutable(long)) + ); + + static assert( + !isIntegral!bool && + !isIntegral!char && + !isIntegral!double + ); + + // types which act as integral values do not pass + struct S + { + int val; + alias val this; + } + + static assert(!isIntegral!S); +} + +@safe unittest +{ + import std.traits; + + static assert( + isFloatingPoint!float && + isFloatingPoint!double && + isFloatingPoint!real && + isFloatingPoint!(const(real)) && + isFloatingPoint!(immutable(real)) + ); + + static assert(!isFloatingPoint!int); + + // types which act as floating point values do not pass + struct S + { + float val; + alias val this; + } + + static assert(!isFloatingPoint!S); +} + +@safe unittest +{ + import std.traits; + + static assert( + isNumeric!byte && + isNumeric!short && + isNumeric!int && + isNumeric!long && + isNumeric!float && + isNumeric!double && + isNumeric!real && + isNumeric!(const(real)) && + isNumeric!(immutable(real)) + ); + + static assert( + !isNumeric!void && + !isNumeric!bool && + !isNumeric!char && + !isNumeric!wchar && + !isNumeric!dchar + ); + + // types which act as numeric values do not pass + struct S + { + int val; + alias val this; + } + + static assert(!isNumeric!S); +} + +@safe unittest +{ + import std.traits; + + static assert(!isScalarType!void); + static assert( isScalarType!(immutable(byte))); + static assert( isScalarType!(immutable(ushort))); + static assert( isScalarType!(immutable(int))); + static assert( isScalarType!(ulong)); + static assert( isScalarType!(shared(float))); + static assert( isScalarType!(shared(const bool))); + static assert( isScalarType!(const(char))); + static assert( isScalarType!(wchar)); + static assert( isScalarType!(const(dchar))); + static assert( isScalarType!(const(double))); + static assert( isScalarType!(const(real))); +} + +@safe unittest +{ + import std.traits; + + static assert(isBasicType!void); + static assert(isBasicType!(const(void))); + static assert(isBasicType!(shared(void))); + static assert(isBasicType!(immutable(void))); + static assert(isBasicType!(shared const(void))); + static assert(isBasicType!(shared inout(void))); + static assert(isBasicType!(shared inout const(void))); + static assert(isBasicType!(inout(void))); + static assert(isBasicType!(inout const(void))); + static assert(isBasicType!(immutable(int))); + static assert(isBasicType!(shared(float))); + static assert(isBasicType!(shared(const bool))); + static assert(isBasicType!(const(dchar))); +} + +@safe unittest +{ + import std.traits; + + static assert( + isUnsigned!uint && + isUnsigned!ulong + ); + + static assert( + !isUnsigned!char && + !isUnsigned!int && + !isUnsigned!long && + !isUnsigned!char && + !isUnsigned!wchar && + !isUnsigned!dchar + ); +} + +@safe unittest +{ + import std.traits; + + static assert( + isSigned!int && + isSigned!long + ); + + static assert( + !isSigned!uint && + !isSigned!ulong + ); +} + +@safe unittest +{ + import std.traits; + + //Char types + static assert( isSomeChar!char); + static assert( isSomeChar!wchar); + static assert( isSomeChar!dchar); + static assert( isSomeChar!(typeof('c'))); + static assert( isSomeChar!(immutable char)); + static assert( isSomeChar!(const dchar)); + + //Non char types + static assert(!isSomeChar!int); + static assert(!isSomeChar!byte); + static assert(!isSomeChar!string); + static assert(!isSomeChar!wstring); + static assert(!isSomeChar!dstring); + static assert(!isSomeChar!(char[4])); +} + +@safe unittest +{ + import std.traits; + + //String types + static assert( isSomeString!string); + static assert( isSomeString!(wchar[])); + static assert( isSomeString!(dchar[])); + static assert( isSomeString!(typeof("aaa"))); + static assert( isSomeString!(const(char)[])); + + //Non string types + static assert(!isSomeString!int); + static assert(!isSomeString!(int[])); + static assert(!isSomeString!(byte[])); + static assert(!isSomeString!(typeof(null))); + static assert(!isSomeString!(char[4])); + + enum ES : string { a = "aaa", b = "bbb" } + static assert(!isSomeString!ES); + + static struct Stringish + { + string str; + alias str this; + } + static assert(!isSomeString!Stringish); +} + +@safe unittest +{ + import std.traits; + + static assert(isNarrowString!string); + static assert(isNarrowString!wstring); + static assert(isNarrowString!(char[])); + static assert(isNarrowString!(wchar[])); + + static assert(!isNarrowString!dstring); + static assert(!isNarrowString!(dchar[])); + + static assert(!isNarrowString!(typeof(null))); + static assert(!isNarrowString!(char[4])); + + enum ES : string { a = "aaa", b = "bbb" } + static assert(!isNarrowString!ES); + + static struct Stringish + { + string str; + alias str this; + } + static assert(!isNarrowString!Stringish); +} + +@safe unittest +{ + import std.traits; + + static assert(isOrderingComparable!int); + static assert(isOrderingComparable!string); + + static struct Foo {} + static assert(!isOrderingComparable!Foo); + + static struct Bar + { + int a; + auto opCmp(Bar b1) const { return a - b1.a; } + } + + Bar b1 = Bar(5); + Bar b2 = Bar(7); + assert(isOrderingComparable!Bar && b2 > b1); +} + +@safe unittest +{ + import std.traits; + + static struct AliasedString + { + string s; + alias s this; + } + + enum StringEnum { a = "foo" } + + assert(!isConvertibleToString!string); + assert(isConvertibleToString!AliasedString); + assert(isConvertibleToString!StringEnum); + assert(isConvertibleToString!(char[25])); + assert(!isConvertibleToString!(char[])); +} + +@safe unittest +{ + import std.traits; + + static struct Stringish + { + string s; + alias s this; + } + static assert(isAutodecodableString!wstring); + static assert(isAutodecodableString!Stringish); + static assert(!isAutodecodableString!dstring); + + enum E : const(char)[3] { X = "abc" } + enum F : const(char)[] { X = "abc" } + enum G : F { X = F.init } + + static assert(isAutodecodableString!(char[])); + static assert(!isAutodecodableString!(E)); + static assert(isAutodecodableString!(F)); + static assert(isAutodecodableString!(G)); + + struct Stringish2 + { + Stringish s; + alias s this; + } + + enum H : Stringish { X = Stringish() } + enum I : Stringish2 { X = Stringish2() } + + static assert(isAutodecodableString!(H)); + static assert(isAutodecodableString!(I)); + + static assert(!isAutodecodableString!(noreturn[])); + static assert(!isAutodecodableString!(immutable(noreturn)[])); +} + +@safe unittest +{ + import std.traits; + + static assert( isStaticArray!(int[3])); + static assert( isStaticArray!(const(int)[5])); + static assert( isStaticArray!(const(int)[][5])); + + static assert(!isStaticArray!(const(int)[])); + static assert(!isStaticArray!(immutable(int)[])); + static assert(!isStaticArray!(const(int)[4][])); + static assert(!isStaticArray!(int[])); + static assert(!isStaticArray!(int[char])); + static assert(!isStaticArray!(int[1][])); + static assert(!isStaticArray!(int[int])); + static assert(!isStaticArray!int); +} + +@safe unittest +{ + import std.traits; + + static assert( isDynamicArray!(int[])); + static assert( isDynamicArray!(string)); + static assert( isDynamicArray!(long[3][])); + + static assert(!isDynamicArray!(int[5])); + static assert(!isDynamicArray!(typeof(null))); +} + +@safe unittest +{ + import std.traits; + + static assert( isArray!(int[])); + static assert( isArray!(int[5])); + static assert( isArray!(string)); + + static assert(!isArray!uint); + static assert(!isArray!(uint[uint])); + static assert(!isArray!(typeof(null))); +} + +@safe unittest +{ + import std.traits; + + struct S; + + static assert( isAssociativeArray!(int[string])); + static assert( isAssociativeArray!(S[S])); + static assert(!isAssociativeArray!(string[])); + static assert(!isAssociativeArray!S); + static assert(!isAssociativeArray!(int[4])); +} + +@safe unittest +{ + import std.traits; + + class C; + union U; + struct S; + interface I; + + static assert( isBuiltinType!void); + static assert( isBuiltinType!string); + static assert( isBuiltinType!(int[])); + static assert( isBuiltinType!(C[string])); + static assert( isBuiltinType!(typeof(null))); + static assert(!isBuiltinType!C); + static assert(!isBuiltinType!U); + static assert(!isBuiltinType!S); + static assert(!isBuiltinType!I); + static assert(!isBuiltinType!(void delegate(int))); +} + +@safe unittest +{ + import std.traits; + + static if (is(__vector(float[4]))) + { + alias SimdVec = __vector(float[4]); + static assert(isSIMDVector!(__vector(float[4]))); + static assert(isSIMDVector!SimdVec); + } + static assert(!isSIMDVector!uint); + static assert(!isSIMDVector!(float[4])); +} + +@safe unittest +{ + import std.traits; + + void fun(); + + static assert( isPointer!(int*)); + static assert( isPointer!(int function())); + static assert(!isPointer!int); + static assert(!isPointer!string); + static assert(!isPointer!(typeof(null))); + static assert(!isPointer!(typeof(fun))); + static assert(!isPointer!(int delegate())); +} + +@safe unittest +{ + import std.traits; + + static assert(is(PointerTarget!(int*) == int)); + static assert(is(PointerTarget!(void*) == void)); +} + +@safe unittest +{ + import std.traits; + + class C {} + union U {} + struct S {} + interface I {} + + static assert( isAggregateType!C); + static assert( isAggregateType!U); + static assert( isAggregateType!S); + static assert( isAggregateType!I); + static assert(!isAggregateType!void); + static assert(!isAggregateType!string); + static assert(!isAggregateType!(int[])); + static assert(!isAggregateType!(C[string])); + static assert(!isAggregateType!(void delegate(int))); + + enum ES : S { a = S.init } + enum EC : C { a = C.init } + enum EI : I { a = I.init } + enum EU : U { a = U.init } + + static assert( isAggregateType!ES); + static assert( isAggregateType!EC); + static assert( isAggregateType!EI); + static assert( isAggregateType!EU); +} + +@safe unittest +{ + import std.traits; + + struct OpApply + { + int opApply(scope int delegate(ref uint) dg) { assert(0); } + } + + struct Range + { + @property uint front() { assert(0); } + void popFront() { assert(0); } + enum bool empty = false; + } + + static assert( isIterable!(uint[])); + static assert( isIterable!OpApply); + static assert( isIterable!(uint[string])); + static assert( isIterable!Range); + + static assert(!isIterable!uint); +} + +@safe unittest +{ + import std.traits; + + static assert( isMutable!int); + static assert( isMutable!string); + static assert( isMutable!(shared int)); + static assert( isMutable!(shared const(int)[])); + + static assert(!isMutable!(const int)); + static assert(!isMutable!(inout int)); + static assert(!isMutable!(shared(const int))); + static assert(!isMutable!(shared(inout int))); + static assert(!isMutable!(immutable string)); +} + +@safe unittest +{ + import std.traits; + + static struct Foo(T...) { } + static struct Bar(T...) { } + static struct Doo(T) { } + static struct ABC(int x) { } + static void fun(T)() { } + template templ(T) { } + + static assert(isInstanceOf!(Foo, Foo!int)); + static assert(!isInstanceOf!(Foo, Bar!int)); + static assert(!isInstanceOf!(Foo, int)); + static assert(isInstanceOf!(Doo, Doo!int)); + static assert(isInstanceOf!(ABC, ABC!1)); + static assert(!isInstanceOf!(Foo, Foo)); + static assert(isInstanceOf!(fun, fun!int)); + static assert(isInstanceOf!(templ, templ!int)); +} + +@safe unittest +{ + import std.traits; + + static struct A(T = void) + { + // doesn't work as expected, only accepts A when T = void + void func(B)(B b) + if (isInstanceOf!(A, B)) {} + + // correct behavior + void method(B)(B b) + if (isInstanceOf!(TemplateOf!(A), B)) {} + } + + A!(void) a1; + A!(void) a2; + A!(int) a3; + + static assert(!__traits(compiles, a1.func(a3))); + static assert( __traits(compiles, a1.method(a2))); + static assert( __traits(compiles, a1.method(a3))); +} + +@safe unittest +{ + import std.traits; + + static assert(isExpressions!(1, 2.0, "a")); + static assert(!isExpressions!(int, double, string)); + static assert(!isExpressions!(int, 2.0, "a")); +} + +@safe unittest +{ + import std.traits; + + static assert(isTypeTuple!(int, float, string)); + static assert(!isTypeTuple!(1, 2.0, "a")); + static assert(!isTypeTuple!(1, double, string)); +} + +@safe unittest +{ + import std.traits; + + static void foo() {} + void bar() {} + + auto fpfoo = &foo; + static assert( isFunctionPointer!fpfoo); + static assert( isFunctionPointer!(void function())); + + auto dgbar = &bar; + static assert(!isFunctionPointer!dgbar); + static assert(!isFunctionPointer!(void delegate())); + static assert(!isFunctionPointer!foo); + static assert(!isFunctionPointer!bar); + + static assert( isFunctionPointer!((int a) {})); +} + +@safe unittest +{ + import std.traits; + + static void sfunc() { } + int x; + void func() { x++; } + + int delegate() dg; + assert(isDelegate!dg); + assert(isDelegate!(int delegate())); + assert(isDelegate!(typeof(&func))); + + int function() fp; + assert(!isDelegate!fp); + assert(!isDelegate!(int function())); + assert(!isDelegate!(typeof(&sfunc))); +} + +@safe unittest +{ + import std.traits; + + static real func(ref int) { return 0; } + static void prop() @property { } + class C + { + real method(ref int) { return 0; } + real prop() @property { return 0; } + } + auto c = new C; + auto fp = &func; + auto dg = &c.method; + + static assert( isSomeFunction!func); + static assert( isSomeFunction!prop); + static assert( isSomeFunction!(C.method)); + static assert( isSomeFunction!(C.prop)); + static assert( isSomeFunction!(c.prop)); + static assert( isSomeFunction!fp); + static assert( isSomeFunction!dg); + + real val; + static assert(!isSomeFunction!int); + static assert(!isSomeFunction!val); +} + +@safe unittest +{ + import std.traits; + + void f() { } + int g(int x) { return x; } + + static assert( isCallable!f); + static assert( isCallable!g); + + class C { int opCall(int) { return 0; } } + auto c = new C; + struct S { static int opCall(int) { return 0; } } + interface I { real value() @property; } + + static assert( isCallable!c); + static assert( isCallable!(c.opCall)); + static assert( isCallable!S); + static assert( isCallable!(I.value)); + static assert( isCallable!((int a) { return a; })); + + static assert(!isCallable!I); +} + +@safe unittest +{ + import std.traits; + + void f()() { } + T g(T = int)(T x) { return x; } + struct S1 { static void opCall()() { } } + struct S2 { static T opCall(T = int)(T x) {return x; } } + + static assert( isCallable!f); + static assert( isCallable!g); + static assert( isCallable!S1); + static assert( isCallable!S2); +} + +@safe unittest +{ + import std.traits; + + static struct Wrapper + { + void f() { } + int f(int x) { return x; } + + void g()() { } + T g(T = int)(T x) { return x; } + } + + static assert(isCallable!(Wrapper.f)); + static assert(isCallable!(Wrapper.g)); +} + +@safe unittest +{ + import std.traits; + + struct S { void foo() { } } + class C { void foo() { } } + class AC { abstract void foo(); } + static assert(!isAbstractFunction!(int)); + static assert(!isAbstractFunction!(S.foo)); + static assert(!isAbstractFunction!(C.foo)); + static assert( isAbstractFunction!(AC.foo)); +} + +@safe unittest +{ + import std.traits; + + struct S { void bar() { } } + final class FC { void foo(); } + class C + { + void bar() { } + final void foo(); + } + static assert(!isFinalFunction!(int)); + static assert(!isFinalFunction!(S.bar)); + static assert( isFinalFunction!(FC.foo)); + static assert(!isFinalFunction!(C.bar)); + static assert( isFinalFunction!(C.foo)); +} + +@safe unittest +{ + import std.traits; + + static void f() {} + static void fun() + { + int i; + int f() { return i; } + + static assert(isNestedFunction!(f)); + } + + static assert(!isNestedFunction!f); +} + +@safe unittest +{ + import std.traits; + + struct S { } + class C { } + abstract class AC { } + static assert(!isAbstractClass!S); + static assert(!isAbstractClass!C); + static assert( isAbstractClass!AC); + C c; + static assert(!isAbstractClass!c); + AC ac; + static assert( isAbstractClass!ac); +} + +@safe unittest +{ + import std.traits; + + class C { } + abstract class AC { } + final class FC1 : C { } + final class FC2 { } + static assert(!isFinalClass!C); + static assert(!isFinalClass!AC); + static assert( isFinalClass!FC1); + static assert( isFinalClass!FC2); + C c; + static assert(!isFinalClass!c); + FC1 fc1; + static assert( isFinalClass!fc1); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unconst!int == int)); + static assert(is(Unconst!(const int) == int)); + static assert(is(Unconst!(immutable int) == int)); + static assert(is(Unconst!(shared int) == shared int)); + static assert(is(Unconst!(shared(const int)) == shared int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unshared!int == int)); + static assert(is(Unshared!(const int) == const int)); + static assert(is(Unshared!(immutable int) == immutable int)); + + static assert(is(Unshared!(shared int) == int)); + static assert(is(Unshared!(shared(const int)) == const int)); + + static assert(is(Unshared!(shared(int[])) == shared(int)[])); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unqual!int == int)); + static assert(is(Unqual!(const int) == int)); + static assert(is(Unqual!(immutable int) == int)); + static assert(is(Unqual!(shared int) == int)); + static assert(is(Unqual!(shared(const int)) == int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(CopyTypeQualifiers!(inout const real, int) == inout const int)); +} + +@safe unittest +{ + import std.traits; + + const(int) i; + CopyConstness!(typeof(i), float) f; + assert( is(typeof(f) == const float)); + + CopyConstness!(char, uint) u; + assert( is(typeof(u) == uint)); + + //The 'shared' qualifier will not be copied + assert(!is(CopyConstness!(shared bool, int) == shared int)); + + //But the constness will be + assert( is(CopyConstness!(shared const real, double) == const double)); + + //Careful, const(int)[] is a mutable array of const(int) + alias MutT = CopyConstness!(const(int)[], int); + assert(!is(MutT == const(int))); + + //Okay, const(int[]) applies to array and contained ints + alias CstT = CopyConstness!(const(int[]), int); + assert( is(CstT == const(int))); +} + +@safe unittest +{ + import std.traits; + + static assert(is(ForeachType!(uint[]) == uint)); + static assert(is(ForeachType!string == immutable(char))); + static assert(is(ForeachType!(string[string]) == string)); + static assert(is(ForeachType!(inout(int)[]) == inout(int))); +} + +@safe unittest +{ + import std.traits; + + enum E : real { a = 0 } // NOTE: explicit initialization to 0 required during Enum init deprecation cycle + enum F : E { a = E.a } + alias G = const(F); + static assert(is(OriginalType!E == real)); + static assert(is(OriginalType!F == real)); + static assert(is(OriginalType!G == const real)); +} + +@safe unittest +{ + import std.traits; + + alias Hash = int[string]; + static assert(is(KeyType!Hash == string)); + static assert(is(ValueType!Hash == int)); + KeyType!Hash str = "a"; // str is declared as string + ValueType!Hash num = 1; // num is declared as int +} + +@safe unittest +{ + import std.traits; + + alias Hash = int[string]; + static assert(is(KeyType!Hash == string)); + static assert(is(ValueType!Hash == int)); + KeyType!Hash str = "a"; // str is declared as string + ValueType!Hash num = 1; // num is declared as int +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unsigned!(int) == uint)); + static assert(is(Unsigned!(long) == ulong)); + static assert(is(Unsigned!(const short) == const ushort)); + static assert(is(Unsigned!(immutable byte) == immutable ubyte)); + static assert(is(Unsigned!(inout int) == inout uint)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unsigned!(uint) == uint)); + static assert(is(Unsigned!(const uint) == const uint)); + + static assert(is(Unsigned!(ubyte) == ubyte)); + static assert(is(Unsigned!(immutable uint) == immutable uint)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Largest!(uint, ubyte, ushort, real) == real)); + static assert(is(Largest!(ulong, double) == ulong)); + static assert(is(Largest!(double, ulong) == double)); + static assert(is(Largest!(uint, byte, double, short) == double)); + static if (is(ucent)) + static assert(is(Largest!(uint, ubyte, ucent, ushort) == ucent)); +} + +@safe unittest +{ + import std.traits; + + alias S1 = Signed!uint; + static assert(is(S1 == int)); + alias S2 = Signed!(const(uint)); + static assert(is(S2 == const(int))); + alias S3 = Signed!(immutable(uint)); + static assert(is(S3 == immutable(int))); + static if (is(ucent)) + { + alias S4 = Signed!ucent; + static assert(is(S4 == cent)); + } +} + +@safe unittest +{ + import std.traits; + + static assert(mostNegative!float == -float.max); + static assert(mostNegative!double == -double.max); + static assert(mostNegative!real == -real.max); + static assert(mostNegative!bool == false); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + static foreach (T; AliasSeq!(bool, byte, short, int, long)) + static assert(mostNegative!T == T.min); + + static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong, char, wchar, dchar)) + static assert(mostNegative!T == 0); +} + +@safe unittest +{ + import std.traits; + + ubyte a = 3, b = 5; + static assert(is(typeof(a * b) == Promoted!ubyte)); + static assert(is(Promoted!ubyte == int)); + + static assert(is(Promoted!(shared(bool)) == shared(int))); + static assert(is(Promoted!(const(int)) == const(int))); + static assert(is(Promoted!double == double)); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + alias TL = staticMap!(mangledName, int, const int, immutable int); + static assert(TL == AliasSeq!("i", "xi", "yi")); +} + +@safe unittest +{ + import std.traits; + + // can select types + static assert(is(Select!(true, int, long) == int)); + static assert(is(Select!(false, int, long) == long)); + static struct Foo {} + static assert(is(Select!(false, const(int), const(Foo)) == const(Foo))); + + // can select symbols + int a = 1; + int b = 2; + alias selA = Select!(true, a, b); + alias selB = Select!(false, a, b); + assert(selA == 1); + assert(selB == 2); + + // can select (compile-time) expressions + enum val = Select!(false, -4, 9 - 6); + static assert(val == 3); +} + +@safe unittest +{ + import std.traits; + + real run() { return 0; } + int fail() { assert(0); } + auto a = select!true(run(), fail()); + auto b = select!false(fail(), run()); + static assert(is(typeof(a) == real)); + static assert(is(typeof(b) == real)); +} + +@safe unittest +{ + import std.traits; + + enum E; + struct S {} + + @("alpha") int a; + static assert(hasUDA!(a, "alpha")); + static assert(!hasUDA!(a, S)); + static assert(!hasUDA!(a, E)); + + @(E) int b; + static assert(!hasUDA!(b, "alpha")); + static assert(!hasUDA!(b, S)); + static assert(hasUDA!(b, E)); + + @E int c; + static assert(!hasUDA!(c, "alpha")); + static assert(!hasUDA!(c, S)); + static assert(hasUDA!(c, E)); + + @(S, E) int d; + static assert(!hasUDA!(d, "alpha")); + static assert(hasUDA!(d, S)); + static assert(hasUDA!(d, E)); + + @S int e; + static assert(!hasUDA!(e, "alpha")); + static assert(hasUDA!(e, S)); + static assert(!hasUDA!(e, S())); + static assert(!hasUDA!(e, E)); + + @S() int f; + static assert(!hasUDA!(f, "alpha")); + static assert(hasUDA!(f, S)); + static assert(hasUDA!(f, S())); + static assert(!hasUDA!(f, E)); + + @(S, E, "alpha") int g; + static assert(hasUDA!(g, "alpha")); + static assert(hasUDA!(g, S)); + static assert(hasUDA!(g, E)); + + @(100) int h; + static assert(hasUDA!(h, 100)); + + struct Named { string name; } + + @Named("abc") int i; + static assert(hasUDA!(i, Named)); + static assert(hasUDA!(i, Named("abc"))); + static assert(!hasUDA!(i, Named("def"))); + + struct AttrT(T) + { + string name; + T value; + } + + @AttrT!int("answer", 42) int j; + static assert(hasUDA!(j, AttrT)); + static assert(hasUDA!(j, AttrT!int)); + static assert(!hasUDA!(j, AttrT!string)); + + @AttrT!string("hello", "world") int k; + static assert(hasUDA!(k, AttrT)); + static assert(!hasUDA!(k, AttrT!int)); + static assert(hasUDA!(k, AttrT!string)); + + struct FuncAttr(alias f) { alias func = f; } + static int fourtyTwo() { return 42; } + static size_t getLen(string s) { return s.length; } + + @FuncAttr!getLen int l; + static assert(hasUDA!(l, FuncAttr)); + static assert(!hasUDA!(l, FuncAttr!fourtyTwo)); + static assert(hasUDA!(l, FuncAttr!getLen)); + static assert(!hasUDA!(l, FuncAttr!fourtyTwo())); + static assert(!hasUDA!(l, FuncAttr!getLen())); + + @FuncAttr!getLen() int m; + static assert(hasUDA!(m, FuncAttr)); + static assert(!hasUDA!(m, FuncAttr!fourtyTwo)); + static assert(hasUDA!(m, FuncAttr!getLen)); + static assert(!hasUDA!(m, FuncAttr!fourtyTwo())); + static assert(hasUDA!(m, FuncAttr!getLen())); +} + +@safe unittest +{ + import std.traits; + + struct Attr + { + string name; + int value; + } + + @Attr("Answer", 42) int a; + static assert(getUDAs!(a, Attr).length == 1); + static assert(getUDAs!(a, Attr)[0].name == "Answer"); + static assert(getUDAs!(a, Attr)[0].value == 42); + + @(Attr("Answer", 42), "string", 9999) int b; + static assert(getUDAs!(b, Attr).length == 1); + static assert(getUDAs!(b, Attr)[0].name == "Answer"); + static assert(getUDAs!(b, Attr)[0].value == 42); + + @Attr("Answer", 42) @Attr("Pi", 3) int c; + static assert(getUDAs!(c, Attr).length == 2); + static assert(getUDAs!(c, Attr)[0].name == "Answer"); + static assert(getUDAs!(c, Attr)[0].value == 42); + static assert(getUDAs!(c, Attr)[1].name == "Pi"); + static assert(getUDAs!(c, Attr)[1].value == 3); + + static assert(getUDAs!(c, Attr("Answer", 42)).length == 1); + static assert(getUDAs!(c, Attr("Answer", 42))[0].name == "Answer"); + static assert(getUDAs!(c, Attr("Answer", 42))[0].value == 42); + + static assert(getUDAs!(c, Attr("Answer", 99)).length == 0); + + struct AttrT(T) + { + string name; + T value; + } + + @AttrT!uint("Answer", 42) @AttrT!int("Pi", 3) @AttrT int d; + static assert(getUDAs!(d, AttrT).length == 2); + static assert(getUDAs!(d, AttrT)[0].name == "Answer"); + static assert(getUDAs!(d, AttrT)[0].value == 42); + static assert(getUDAs!(d, AttrT)[1].name == "Pi"); + static assert(getUDAs!(d, AttrT)[1].value == 3); + + static assert(getUDAs!(d, AttrT!uint).length == 1); + static assert(getUDAs!(d, AttrT!uint)[0].name == "Answer"); + static assert(getUDAs!(d, AttrT!uint)[0].value == 42); + + static assert(getUDAs!(d, AttrT!int).length == 1); + static assert(getUDAs!(d, AttrT!int)[0].name == "Pi"); + static assert(getUDAs!(d, AttrT!int)[0].value == 3); + + struct SimpleAttr {} + + @SimpleAttr int e; + static assert(getUDAs!(e, SimpleAttr).length == 1); + static assert(is(getUDAs!(e, SimpleAttr)[0] == SimpleAttr)); + + @SimpleAttr() int f; + static assert(getUDAs!(f, SimpleAttr).length == 1); + static assert(is(typeof(getUDAs!(f, SimpleAttr)[0]) == SimpleAttr)); + + struct FuncAttr(alias f) { alias func = f; } + static int add42(int v) { return v + 42; } + static string concat(string l, string r) { return l ~ r; } + + @FuncAttr!add42 int g; + static assert(getUDAs!(g, FuncAttr).length == 1); + static assert(getUDAs!(g, FuncAttr)[0].func(5) == 47); + + static assert(getUDAs!(g, FuncAttr!add42).length == 1); + static assert(getUDAs!(g, FuncAttr!add42)[0].func(5) == 47); + + static assert(getUDAs!(g, FuncAttr!add42()).length == 0); + + static assert(getUDAs!(g, FuncAttr!concat).length == 0); + static assert(getUDAs!(g, FuncAttr!concat()).length == 0); + + @FuncAttr!add42() int h; + static assert(getUDAs!(h, FuncAttr).length == 1); + static assert(getUDAs!(h, FuncAttr)[0].func(5) == 47); + + static assert(getUDAs!(h, FuncAttr!add42).length == 1); + static assert(getUDAs!(h, FuncAttr!add42)[0].func(5) == 47); + + static assert(getUDAs!(h, FuncAttr!add42()).length == 1); + static assert(getUDAs!(h, FuncAttr!add42())[0].func(5) == 47); + + static assert(getUDAs!(h, FuncAttr!concat).length == 0); + static assert(getUDAs!(h, FuncAttr!concat()).length == 0); + + @("alpha") @(42) int i; + static assert(getUDAs!(i, "alpha").length == 1); + static assert(getUDAs!(i, "alpha")[0] == "alpha"); + + static assert(getUDAs!(i, 42).length == 1); + static assert(getUDAs!(i, 42)[0] == 42); + + static assert(getUDAs!(i, 'c').length == 0); +} + +@safe unittest +{ + import std.traits; + + enum Attr; + struct A + { + @Attr int a; + int b; + } + + static assert(getSymbolsByUDA!(A, Attr).length == 1); + static assert(hasUDA!(getSymbolsByUDA!(A, Attr)[0], Attr)); +} + +@safe unittest +{ + import std.traits; + + enum Attr; + + static struct A + { + @Attr int a; + int b; + @Attr void doStuff() {} + void doOtherStuff() {} + static struct Inner + { + // Not found by getSymbolsByUDA + @Attr int c; + } + } + + // Finds both variables and functions with the attribute, but + // doesn't include the variables and functions without it. + static assert(getSymbolsByUDA!(A, Attr).length == 2); + // Can access attributes on the symbols returned by getSymbolsByUDA. + static assert(hasUDA!(getSymbolsByUDA!(A, Attr)[0], Attr)); + static assert(hasUDA!(getSymbolsByUDA!(A, Attr)[1], Attr)); +} + +@safe unittest +{ + import std.traits; + + static struct UDA { string name; } + + static struct B + { + @UDA("X") + int x; + @UDA("Y") + int y; + @(100) + int z; + } + + // Finds both UDA attributes. + static assert(getSymbolsByUDA!(B, UDA).length == 2); + // Finds one `100` attribute. + static assert(getSymbolsByUDA!(B, 100).length == 1); + // Can get the value of the UDA from the return value + static assert(getUDAs!(getSymbolsByUDA!(B, UDA)[0], UDA)[0].name == "X"); +} + +@safe unittest +{ + import std.traits; + + static struct UDA { string name; } + + @UDA("A") + static struct C + { + @UDA("B") + int d; + } + + static assert(getSymbolsByUDA!(C, UDA).length == 2); + static assert(getSymbolsByUDA!(C, UDA)[0].stringof == "C"); + static assert(getSymbolsByUDA!(C, UDA)[1].stringof == "d"); +} + +@safe unittest +{ + import std.traits; + + static struct UDA { string name; } + + static struct D + { + int x; + } + + static assert(getSymbolsByUDA!(D, UDA).length == 0); +} + +@safe unittest +{ + import std.traits; + + static assert(allSameType!()); + static assert(allSameType!(int)); + static assert(allSameType!(int, int)); + static assert(allSameType!(int, int, int)); + static assert(allSameType!(float, float, float)); + static assert(!allSameType!(int, double)); + static assert(!allSameType!(int, float, double)); + static assert(!allSameType!(int, float, double, real)); + static assert(!allSameType!(short, int, float, double, real)); +} + +@safe unittest +{ + import std.traits; + + class C; + struct S1; + struct S2 + { + T opCast(T)() const; + } + + static assert( ifTestable!bool); + static assert( ifTestable!int); + static assert( ifTestable!(S1*)); + static assert( ifTestable!(typeof(null))); + static assert( ifTestable!(int[])); + static assert( ifTestable!(int[string])); + static assert( ifTestable!S2); + static assert( ifTestable!C); + static assert(!ifTestable!S1); +} + +@safe unittest +{ + import std.traits; + + struct S { + template Test() {} + } + class C {} + interface I {} + union U {} + static assert(isType!int); + static assert(isType!string); + static assert(isType!(int[int])); + static assert(isType!S); + static assert(isType!C); + static assert(isType!I); + static assert(isType!U); + + int n; + void func(){} + static assert(!isType!n); + static assert(!isType!func); + static assert(!isType!(S.Test)); + static assert(!isType!(S.Test!())); +} + +@safe unittest +{ + import std.traits; + + static void func(){} + static assert(isFunction!func); + + struct S + { + void func(){} + } + static assert(isFunction!(S.func)); +} + +@safe unittest +{ + import std.traits; + + class C + { + void nf() {} + static void sf() {} + final void ff() {} + } + final class FC { } + + static assert(!isFinal!(C)); + static assert( isFinal!(FC)); + + static assert(!isFinal!(C.nf)); + static assert(!isFinal!(C.sf)); + static assert( isFinal!(C.ff)); +} + +@safe unittest +{ + import std.traits; + + struct S1 {} // Fine. Can be copied + struct S2 { this(this) {}} // Fine. Can be copied + struct S3 {@disable this(this); } // Not fine. Copying is disabled. + struct S4 {S3 s;} // Not fine. A field has copying disabled. + + class C1 {} + + static assert( isCopyable!S1); + static assert( isCopyable!S2); + static assert(!isCopyable!S3); + static assert(!isCopyable!S4); + + static assert(isCopyable!C1); + static assert(isCopyable!int); + static assert(isCopyable!(int[])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_typecons.d b/libphobos/testsuite/libphobos.phobos/std_typecons.d new file mode 100644 index 0000000000000000000000000000000000000000..c8e43ac499aa506d12e678cd969bcd33be93dbc2 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_typecons.d @@ -0,0 +1,1931 @@ +@safe unittest +{ + import std.typecons; + + alias Coord = Tuple!(int, "x", int, "y", int, "z"); + Coord c; + c[1] = 1; // access by index + c.z = 1; // access by given name + assert(c == Coord(0, 1, 1)); + + // names can be omitted, types can be mixed + alias DictEntry = Tuple!(string, int); + auto dict = DictEntry("seven", 7); + + // element types can be inferred + assert(tuple(2, 3, 4)[1] == 3); + // type inference works with names too + auto tup = tuple!("x", "y", "z")(2, 3, 4); + assert(tup.y == 3); +} + +@safe unittest +{ + import std.typecons; + + class Widget + { + void foo() const @safe {} + } + const w1 = new Widget, w2 = new Widget; + w1.foo(); + // w1 = w2 would not work; can't rebind const object + + auto r = Rebindable!(const Widget)(w1); + // invoke method as if r were a Widget object + r.foo(); + // rebind r to refer to another object + r = w2; +} + +@safe unittest +{ + import std.typecons; + + struct S + { + int i; + this(int i){this.i = i;} + } + Unique!S produce() + { + // Construct a unique instance of S on the heap + Unique!S ut = new S(5); + // Implicit transfer of ownership + return ut; + } + // Borrow a unique resource by ref + void increment(ref Unique!S ur) + { + ur.i++; + } + void consume(Unique!S u2) + { + assert(u2.i == 6); + // Resource automatically deleted here + } + Unique!S u1; + assert(u1.isEmpty); + u1 = produce(); + assert(u1.i == 5); + increment(u1); + assert(u1.i == 6); + //consume(u1); // Error: u1 is not copyable + // Transfer ownership of the resource + consume(u1.release); + assert(u1.isEmpty); +} + +@safe unittest +{ + import std.typecons; + + import std.meta : AliasSeq; + alias Fields = Tuple!(int, "id", string, float); + static assert(is(Fields.Types == AliasSeq!(int, string, float))); + +} + +@safe unittest +{ + import std.typecons; + + import std.meta : AliasSeq; + alias Fields = Tuple!(int, "id", string, float); + static assert(Fields.fieldNames == AliasSeq!("id", "", "")); + +} + +@safe unittest +{ + import std.typecons; + + auto t1 = tuple(1, " hello ", 'a'); + assert(t1.toString() == `Tuple!(int, string, char)(1, " hello ", 'a')`); + + void takeSeveralTypes(int n, string s, bool b) + { + assert(n == 4 && s == "test" && b == false); + } + + auto t2 = tuple(4, "test", false); + //t.expand acting as a list of values + takeSeveralTypes(t2.expand); + +} + +@safe unittest +{ + import std.typecons; + + alias ISD = Tuple!(int, string, double); + auto tup = ISD(1, "test", 3.2); + assert(tup.toString() == `Tuple!(int, string, double)(1, "test", 3.2)`); + +} + +@safe unittest +{ + import std.typecons; + + int[2] ints; + Tuple!(int, int) t = ints; + +} + +@safe unittest +{ + import std.typecons; + + alias IntVec = Tuple!(int, int, int); + alias DubVec = Tuple!(double, double, double); + + IntVec iv = tuple(1, 1, 1); + + //Ok, int can implicitly convert to double + DubVec dv = iv; + //Error: double cannot implicitly convert to int + //IntVec iv2 = dv; + +} + +@safe unittest +{ + import std.typecons; + + Tuple!(int, string) t1 = tuple(1, "test"); + Tuple!(double, string) t2 = tuple(1.0, "test"); + //Ok, int can be compared with double and + //both have a value of 1 + assert(t1 == t2); + +} + +@safe unittest +{ + import std.typecons; + + auto tup1 = tuple(1, 1, 1); + auto tup2 = tuple(1, 100, 100); + assert(tup1 < tup2); + + //Only the first result matters for comparison + tup1[0] = 2; + assert(tup1 > tup2); + +} + +@safe unittest +{ + import std.typecons; + + auto t0 = tuple(4, "hello"); + + auto t0Named = t0.rename!("val", "tag"); + assert(t0Named.val == 4); + assert(t0Named.tag == "hello"); + + Tuple!(float, "dat", size_t[2], "pos") t1; + t1.pos = [2, 1]; + auto t1Named = t1.rename!"height"; + t1Named.height = 3.4f; + assert(t1Named.height == 3.4f); + assert(t1Named.pos == [2, 1]); + t1Named.rename!"altitude".altitude = 5; + assert(t1Named.height == 5); + + Tuple!(int, "a", int, int, "c") t2; + t2 = tuple(3,4,5); + auto t2Named = t2.rename!("", "b"); + // "a" no longer has a name + static assert(!__traits(hasMember, typeof(t2Named), "a")); + assert(t2Named[0] == 3); + assert(t2Named.b == 4); + assert(t2Named.c == 5); + + // not allowed to specify more names than the tuple has members + static assert(!__traits(compiles, t2.rename!("a","b","c","d"))); + + // use it in a range pipeline + import std.range : iota, zip; + import std.algorithm.iteration : map, sum; + auto res = zip(iota(1, 4), iota(10, 13)) + .map!(t => t.rename!("a", "b")) + .map!(t => t.a * t.b) + .sum; + assert(res == 68); + + const tup = Tuple!(int, "a", int, "b")(2, 3); + const renamed = tup.rename!("c", "d"); + assert(renamed.c + renamed.d == 5); + +} + +@safe unittest +{ + import std.typecons; + + //replacing names by their current name + + Tuple!(float, "dat", size_t[2], "pos") t1; + t1.pos = [2, 1]; + auto t1Named = t1.rename!(["dat": "height"]); + t1Named.height = 3.4; + assert(t1Named.pos == [2, 1]); + t1Named.rename!(["height": "altitude"]).altitude = 5; + assert(t1Named.height == 5); + + Tuple!(int, "a", int, "b") t2; + t2 = tuple(3, 4); + auto t2Named = t2.rename!(["a": "b", "b": "c"]); + assert(t2Named.b == 3); + assert(t2Named.c == 4); + + const t3 = Tuple!(int, "a", int, "b")(3, 4); + const t3Named = t3.rename!(["a": "b", "b": "c"]); + assert(t3Named.b == 3); + assert(t3Named.c == 4); + +} + +@system unittest +{ + import std.typecons; + + //replace names by their position + + Tuple!(float, "dat", size_t[2], "pos") t1; + t1.pos = [2, 1]; + auto t1Named = t1.rename!([0: "height"]); + t1Named.height = 3.4; + assert(t1Named.pos == [2, 1]); + t1Named.rename!([0: "altitude"]).altitude = 5; + assert(t1Named.height == 5); + + Tuple!(int, "a", int, "b", int, "c") t2; + t2 = tuple(3, 4, 5); + auto t2Named = t2.rename!([0: "c", 2: "a"]); + assert(t2Named.a == 5); + assert(t2Named.b == 4); + assert(t2Named.c == 3); + +} + +@safe unittest +{ + import std.typecons; + + Tuple!(int, string, float, double) a; + a[1] = "abc"; + a[2] = 4.5; + auto s = a.slice!(1, 3); + static assert(is(typeof(s) == Tuple!(string, float))); + assert(s[0] == "abc" && s[1] == 4.5); + + // https://issues.dlang.org/show_bug.cgi?id=15645 + Tuple!(int, short, bool, double) b; + static assert(!__traits(compiles, b.slice!(2, 4))); + +} + +@safe unittest +{ + import std.typecons; + + import std.format : format; + + Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ]; + + // Default format + assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`); + + // One Format for each individual component + assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10)) == `0x1 v 1.0000 w 0xa`); + assert(format( "%#x v %.4f w %#x" , tuple(1, 1.0, 10).expand) == `0x1 v 1.0000 w 0xa`); + + // One Format for all components + assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`); + + // Array of Tuples + assert(format("%(%(f(%d) = %.1f%); %)", tupList) == `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`); + +} + +@safe unittest +{ + import std.typecons; + + import std.exception : assertThrown; + import std.format : format, FormatException; + + // Error: %( %) missing. + assertThrown!FormatException( + format("%d, %f", tuple(1, 2.0)) == `1, 2.0` + ); + + // Error: %( %| %) missing. + assertThrown!FormatException( + format("%d", tuple(1, 2)) == `1, 2` + ); + + // Error: %d inadequate for double + assertThrown!FormatException( + format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0` + ); + +} + +@safe unittest +{ + import std.typecons; + + Tuple!(int, int) point; + // assign coordinates + point[0] = 5; + point[1] = 6; + // read coordinates + auto x = point[0]; + auto y = point[1]; +} + +@safe unittest +{ + import std.typecons; + + alias Entry = Tuple!(int, "index", string, "value"); + Entry e; + e.index = 4; + e.value = "Hello"; + assert(e[1] == "Hello"); + assert(e[0] == 4); +} + +@safe unittest +{ + import std.typecons; + + Tuple!(int, "x", int, "y") point1; + Tuple!(int, int) point2; + assert(!is(typeof(point1) == typeof(point2))); +} + +@safe unittest +{ + import std.typecons; + + import std.algorithm.iteration : sum; + import std.range : only; + auto t = tuple(1, 2); + assert(t.expand.only.sum == 3); +} + +@safe unittest +{ + import std.typecons; + + import std.meta : AliasSeq; + auto t = tuple(1, "2") ~ tuple(ushort(42), true); + static assert(is(t.Types == AliasSeq!(int, string, ushort, bool))); + assert(t[1] == "2"); + assert(t[2] == 42); + assert(t[3] == true); +} + +@safe unittest +{ + import std.typecons; + + auto tup = tuple(1, "2"); + assert(tup.reverse == tuple("2", 1)); +} + +@safe unittest +{ + import std.typecons; + + auto value = tuple(5, 6.7, "hello"); + assert(value[0] == 5); + assert(value[1] == 6.7); + assert(value[2] == "hello"); + + // Field names can be provided. + auto entry = tuple!("index", "value")(4, "Hello"); + assert(entry.index == 4); + assert(entry.value == "Hello"); +} + +@safe unittest +{ + import std.typecons; + + static assert(isTuple!(Tuple!())); + static assert(isTuple!(Tuple!(int))); + static assert(isTuple!(Tuple!(int, real, string))); + static assert(isTuple!(Tuple!(int, "x", real, "y"))); + static assert(isTuple!(Tuple!(int, Tuple!(real), string))); +} + +@safe unittest +{ + import std.typecons; + + class Widget { int x; int y() @safe const { return x; } } + const a = new Widget; + // Fine + a.y(); + // error! can't modify const a + // a.x = 5; + // error! can't modify const a + // a = new Widget; +} + +@safe unittest +{ + import std.typecons; + + class Widget { int x; int y() const @safe { return x; } } + auto a = Rebindable!(const Widget)(new Widget); + // Fine + a.y(); + // error! can't modify const a + // a.x = 5; + // Fine + a = new Widget; +} + +@safe unittest +{ + import std.typecons; + + import std.range.primitives : front, popFront; + + // simple version of std.algorithm.searching.maxElement + typeof(R.init.front) maxElement(R)(R r) + { + auto max = rebindable(r.front); + r.popFront; + foreach (e; r) + if (e > max) + max = e; // Rebindable allows const-correct reassignment + return max; + } + struct S + { + char[] arr; + alias arr this; // for comparison + } + // can't convert to mutable + const S cs; + static assert(!__traits(compiles, { S s = cs; })); + + alias CS = const S; + CS[] arr = [CS("harp"), CS("apple"), CS("pot")]; + CS ms = maxElement(arr); + assert(ms.arr == "pot"); +} + +@system unittest +{ + import std.typecons; + + static struct S + { + int* ptr; + } + S s = S(new int); + + const cs = s; + // Can't assign s.ptr to cs.ptr + static assert(!__traits(compiles, {s = cs;})); + + Rebindable!(const S) rs = s; + assert(rs.ptr is s.ptr); + // rs.ptr is const + static assert(!__traits(compiles, {rs.ptr = null;})); + + // Can't assign s.ptr to rs.ptr + static assert(!__traits(compiles, {s = rs;})); + + const S cs2 = rs; + // Rebind rs + rs = cs2; + rs = S(); + assert(rs.ptr is null); +} + +@system unittest +{ + import std.typecons; + + class C + { + int payload; + this(int p) { payload = p; } + } + const c = new C(1); + + auto c2 = c.rebindable; + assert(c2.payload == 1); + // passing Rebindable to rebindable + c2 = c2.rebindable; + + c2 = new C(2); + assert(c2.payload == 2); + + const c3 = c2.get; + assert(c3.payload == 2); +} + +@safe unittest +{ + import std.typecons; + + immutable struct S + { + int[] array; + } + auto s1 = [3].idup.rebindable; + s1 = [4].idup.rebindable; + assert(s1 == [4]); +} + +@system unittest +{ + import std.typecons; + + class C + { + int payload; + this(int p) { payload = p; } + } + const c = new C(1); + + auto c2 = c.rebindable; + assert(c2.payload == 1); + // passing Rebindable to rebindable + c2 = c2.rebindable; + assert(c2.payload == 1); +} + +@system unittest +{ + import std.typecons; + + class Data {} + + static shared(Data) a; + static UnqualRef!(shared Data) b; + + import core.thread; + + auto thread = new core.thread.Thread({ + a = new shared Data(); + b = new shared Data(); + }); + + thread.start(); + thread.join(); + + assert(a !is null); + assert(b is null); +} + +@safe unittest +{ + import std.typecons; + + struct Banner { + mixin(alignForSize!(byte[6], double)(["name", "height"])); + } +} + +@safe unittest +{ + import std.typecons; + + Nullable!int empty; + Nullable!int a = 42; + Nullable!int b = 42; + Nullable!int c = 27; + + assert(empty == empty); + assert(empty == Nullable!int.init); + assert(empty != a); + assert(empty != b); + assert(empty != c); + + assert(a == b); + assert(a != c); + + assert(empty != 42); + assert(a == 42); + assert(c != 42); + +} + +@safe unittest +{ + import std.typecons; + + Nullable!int ni; + assert(ni.isNull); + + ni = 0; + assert(!ni.isNull); + +} + +@safe unittest +{ + import std.typecons; + + Nullable!int ni = 0; + assert(!ni.isNull); + + ni.nullify(); + assert(ni.isNull); + +} + +@safe unittest +{ + import std.typecons; + + //Passes + Nullable!(int*) npi; + assert(npi.isNull); + + //Passes?! + npi = null; + assert(!npi.isNull); + +} + +@safe unittest +{ + import std.typecons; + + struct CustomerRecord + { + string name; + string address; + int customerNum; + } + + Nullable!CustomerRecord getByName(string name) + { + //A bunch of hairy stuff + + return Nullable!CustomerRecord.init; + } + + auto queryResult = getByName("Doe, John"); + if (!queryResult.isNull) + { + //Process Mr. Doe's customer record + auto address = queryResult.get.address; + auto customerNum = queryResult.get.customerNum; + + //Do some things with this customer's info + } + else + { + //Add the customer to the database + } +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + auto a = 42.nullable; + assert(!a.isNull); + assert(a.get == 42); + + a.nullify(); + assert(a.isNull); + assertThrown!Throwable(a.get); +} + +@safe unittest +{ + import std.typecons; + + import std.algorithm.iteration : each, joiner; + Nullable!int a = 42; + Nullable!int b; + // Add each value to an array + int[] arr; + a.each!((n) => arr ~= n); + assert(arr == [42]); + b.each!((n) => arr ~= n); + assert(arr == [42]); + // Take first value from an array of Nullables + Nullable!int[] c = new Nullable!int[](10); + c[7] = Nullable!int(42); + assert(c.joiner.front == 42); +} + +@safe unittest +{ + import std.typecons; + + Nullable!(int, -1) ni; + //Initialized to "null" state + assert(ni.isNull); + + ni = 0; + assert(!ni.isNull); +} + +@safe unittest +{ + import std.typecons; + + Nullable!(int, -1) ni = 0; + assert(!ni.isNull); + + ni = -1; + assert(ni.isNull); +} + +@system unittest +{ + import std.typecons; + + //Passes + enum nullVal = cast(int*) 0xCAFEBABE; + Nullable!(int*, nullVal) npi; + assert(npi.isNull); + + //Passes?! + npi = null; + assert(!npi.isNull); +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown, assertNotThrown; + + Nullable!(int, -1) ni; + //`get` is implicitly called. Will throw + //an error in non-release mode + assertThrown!Throwable(ni == 0); + + ni = 0; + assertNotThrown!Throwable(ni == 0); +} + +@safe unittest +{ + import std.typecons; + + Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle) + { + //Find the needle, returning -1 if not found + + return Nullable!(size_t, size_t.max).init; + } + + void sendLunchInvite(string name) + { + } + + //It's safer than C... + auto coworkers = ["Jane", "Jim", "Marry", "Fred"]; + auto pos = indexOf(coworkers, "Bob"); + if (!pos.isNull) + { + //Send Bob an invitation to lunch + sendLunchInvite(coworkers[pos]); + } + else + { + //Bob not found; report the error + } + + //And there's no overhead + static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof); +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + Nullable!(int, int.min) a; + assert(a.isNull); + assertThrown!Throwable(a.get); + a = 5; + assert(!a.isNull); + assert(a == 5); + static assert(a.sizeof == int.sizeof); +} + +@safe unittest +{ + import std.typecons; + + auto a = nullable!(int.min)(8); + assert(a == 8); + a.nullify(); + assert(a.isNull); +} + +nothrow pure @nogc @safe unittest +{ + import std.typecons; + + alias toFloat = i => cast(float) i; + + Nullable!int sample; + + // apply(null) results in a null `Nullable` of the function's return type. + Nullable!float f = sample.apply!toFloat; + assert(sample.isNull && f.isNull); + + sample = 3; + + // apply(non-null) calls the function and wraps the result in a `Nullable`. + f = sample.apply!toFloat; + assert(!sample.isNull && !f.isNull); + assert(f.get == 3.0f); +} + +nothrow pure @nogc @safe unittest +{ + import std.typecons; + + alias greaterThree = i => (i > 3) ? i.nullable : Nullable!(typeof(i)).init; + + Nullable!int sample; + + // when the function already returns a `Nullable`, that `Nullable` is not wrapped. + auto result = sample.apply!greaterThree; + assert(sample.isNull && result.isNull); + + // The function may decide to return a null `Nullable`. + sample = 3; + result = sample.apply!greaterThree; + assert(!sample.isNull && result.isNull); + + // Or it may return a value already wrapped in a `Nullable`. + sample = 4; + result = sample.apply!greaterThree; + assert(!sample.isNull && !result.isNull); + assert(result.get == 4); +} + +@safe unittest +{ + import std.typecons; + + NullableRef!int nr = new int(42); + assert(nr == 42); + + int* n = new int(1); + nr.bind(n); + assert(nr == 1); + +} + +@safe unittest +{ + import std.typecons; + + NullableRef!int nr; + assert(nr.isNull); + + int* n = new int(42); + nr.bind(n); + assert(!nr.isNull && nr == 42); + +} + +@safe unittest +{ + import std.typecons; + + NullableRef!int nr = new int(42); + assert(!nr.isNull); + + nr.nullify(); + assert(nr.isNull); + +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown, assertNotThrown; + + NullableRef!int nr; + assert(nr.isNull); + assertThrown!Throwable(nr = 42); + + nr.bind(new int(0)); + assert(!nr.isNull); + assertNotThrown!Throwable(nr = 42); + assert(nr == 42); + +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown, assertNotThrown; + + NullableRef!int nr; + //`get` is implicitly called. Will throw + //an error in non-release mode + assertThrown!Throwable(nr == 0); + + nr.bind(new int(0)); + assertNotThrown!Throwable(nr == 0); + +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + int x = 5, y = 7; + auto a = nullableRef(&x); + assert(!a.isNull); + assert(a == 5); + assert(x == 5); + a = 42; + assert(x == 42); + assert(!a.isNull); + assert(a == 42); + a.nullify(); + assert(x == 42); + assert(a.isNull); + assertThrown!Throwable(a.get); + assertThrown!Throwable(a = 71); + a.bind(&y); + assert(a == 7); + y = 135; + assert(a == 135); +} + +@system unittest +{ + import std.typecons; + + import std.math.traits : isNaN; + + static abstract class C + { + int m_value; + this(int v) { m_value = v; } + int value() @property { return m_value; } + + abstract real realValue() @property; + abstract void doSomething(); + } + + auto c = new BlackHole!C(42); + assert(c.value == 42); + + // Returns real.init which is NaN + assert(c.realValue.isNaN); + // Abstract functions are implemented as do-nothing + c.doSomething(); +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + static class C + { + abstract void notYetImplemented(); + } + + auto c = new WhiteHole!C; + assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + // nothrow + { + interface I_1 + { + void foo(); + void bar() nothrow; + } + auto o = new WhiteHole!I_1; + assertThrown!NotImplementedError(o.foo()); + assertThrown!NotImplementedError(o.bar()); + } + // doc example + { + static class C + { + abstract void notYetImplemented(); + } + + auto c = new WhiteHole!C; + try + { + c.notYetImplemented(); + assert(0); + } + catch (Error e) {} + } +} + +@system unittest +{ + import std.typecons; + + interface PackageSupplier + { + int foo(); + int bar(); + } + + static abstract class AbstractFallbackPackageSupplier : PackageSupplier + { + protected PackageSupplier default_, fallback; + + this(PackageSupplier default_, PackageSupplier fallback) + { + this.default_ = default_; + this.fallback = fallback; + } + + abstract int foo(); + abstract int bar(); + } + + template fallback(T, alias func) + { + import std.format : format; + // for all implemented methods: + // - try default first + // - only on a failure run & return fallback + enum fallback = q{ + try + { + return default_.%1$s(args); + } + catch (Exception) + { + return fallback.%1$s(args); + } + }.format(__traits(identifier, func)); + } + + // combines two classes and use the second one as fallback + alias FallbackPackageSupplier = AutoImplement!(AbstractFallbackPackageSupplier, fallback); + + class FailingPackageSupplier : PackageSupplier + { + int foo(){ throw new Exception("failure"); } + int bar(){ return 2;} + } + + class BackupPackageSupplier : PackageSupplier + { + int foo(){ return -1; } + int bar(){ return -1;} + } + + auto registry = new FallbackPackageSupplier(new FailingPackageSupplier(), new BackupPackageSupplier()); + + assert(registry.foo() == -1); + assert(registry.bar() == 2); +} + +@system unittest +{ + import std.typecons; + + alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction); + + interface I + { + int foo(); + string bar(); + } + + auto i = new BlackHole!I(); + // generateEmptyFunction returns the default value of the return type without doing anything + assert(i.foo == 0); + assert(i.bar is null); +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap); + + interface I + { + int foo(); + string bar(); + } + + auto i = new WhiteHole!I(); + // generateAssertTrap throws an exception for every unimplemented function of the interface + assertThrown!NotImplementedError(i.foo); + assertThrown!NotImplementedError(i.bar); +} + +@system unittest +{ + import std.typecons; + + interface Quack + { + int quack(); + @property int height(); + } + interface Flyer + { + @property int height(); + } + class Duck : Quack + { + int quack() { return 1; } + @property int height() { return 10; } + } + class Human + { + int quack() { return 2; } + @property int height() { return 20; } + } + + Duck d1 = new Duck(); + Human h1 = new Human(); + + interface Refleshable + { + int reflesh(); + } + + // does not have structural conformance + static assert(!__traits(compiles, d1.wrap!Refleshable)); + static assert(!__traits(compiles, h1.wrap!Refleshable)); + + // strict upcast + Quack qd = d1.wrap!Quack; + assert(qd is d1); + assert(qd.quack() == 1); // calls Duck.quack + // strict downcast + Duck d2 = qd.unwrap!Duck; + assert(d2 is d1); + + // structural upcast + Quack qh = h1.wrap!Quack; + assert(qh.quack() == 2); // calls Human.quack + // structural downcast + Human h2 = qh.unwrap!Human; + assert(h2 is h1); + + // structural upcast (two steps) + Quack qx = h1.wrap!Quack; // Human -> Quack + Flyer fx = qx.wrap!Flyer; // Quack -> Flyer + assert(fx.height == 20); // calls Human.height + // structural downcast (two steps) + Quack qy = fx.unwrap!Quack; // Flyer -> Quack + Human hy = qy.unwrap!Human; // Quack -> Human + assert(hy is h1); + // structural downcast (one step) + Human hz = fx.unwrap!Human; // Flyer -> Human + assert(hz is h1); +} + +@system unittest +{ + import std.typecons; + + import std.traits : FunctionAttribute, functionAttributes; + interface A { int run(); } + interface B { int stop(); @property int status(); } + class X + { + int run() { return 1; } + int stop() { return 2; } + @property int status() { return 3; } + } + + auto x = new X(); + auto ab = x.wrap!(A, B); + A a = ab; + B b = ab; + assert(a.run() == 1); + assert(b.stop() == 2); + assert(b.status == 3); + static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property); +} + +@system unittest +{ + import std.typecons; + + import core.exception : AssertError; + import std.exception : assertThrown; + + struct Foo + { + int a = 42; + } + + SafeRefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto; + SafeRefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto; + + assert(rcAuto.refCountedPayload.a == 42); + + assertThrown!AssertError(rcNoAuto.refCountedPayload); + rcNoAuto.refCountedStore.ensureInitialized; + assert(rcNoAuto.refCountedPayload.a == 42); +} + +pure @system nothrow @nogc unittest +{ + import std.typecons; + + // A pair of an `int` and a `size_t` - the latter being the + // reference count - will be dynamically allocated + auto rc1 = SafeRefCounted!int(5); + assert(rc1 == 5); + // No more allocation, add just one extra reference count + auto rc2 = rc1; + // Reference semantics + rc2 = 42; + assert(rc1 == 42); + // the pair will be freed when rc1 and rc2 go out of scope +} + +@safe pure nothrow unittest +{ + import std.typecons; + + auto rcInt = safeRefCounted(5); + assert(rcInt.borrow!(theInt => theInt) == 5); + auto sameInt = rcInt; + assert(sameInt.borrow!"a" == 5); + + // using `ref` in the function + auto arr = [0, 1, 2, 3, 4, 5, 6]; + sameInt.borrow!(ref (x) => arr[x]) = 10; + assert(arr == [0, 1, 2, 3, 4, 10, 6]); + + // modifying the payload via an alias + sameInt.borrow!"a*=2"; + assert(rcInt.borrow!"a" == 10); +} + +@system unittest +{ + import std.typecons; + + static struct File + { + static size_t nDestroyed; + string name; + @disable this(this); // not copyable + ~this() { name = null; ++nDestroyed; } + } + + auto file = File("name"); + assert(file.name == "name"); + // file cannot be copied and has unique ownership + static assert(!__traits(compiles, {auto file2 = file;})); + + assert(File.nDestroyed == 0); + + // make the file ref counted to share ownership + // Note: + // We write a compound statement (brace-delimited scope) in which all `SafeRefCounted!File` handles are created and deleted. + // This allows us to see (after the scope) what happens after all handles have been destroyed. + { + // We move the content of `file` to a separate (and heap-allocated) `File` object, + // managed-and-accessed via one-or-multiple (initially: one) `SafeRefCounted!File` objects ("handles"). + // This "moving": + // (1) invokes `file`'s destructor (=> `File.nDestroyed` is incremented from 0 to 1 and `file.name` becomes `null`); + // (2) overwrites `file` with `File.init` (=> `file.name` becomes `null`). + // It appears that writing `name = null;` in the destructor is redundant, + // but please note that (2) is only performed if `File` defines a destructor (or post-blit operator), + // and in the absence of the `nDestroyed` instrumentation there would have been no reason to define a destructor. + import std.algorithm.mutation : move; + auto rcFile = safeRefCounted(move(file)); + assert(rcFile.name == "name"); + assert(File.nDestroyed == 1); + assert(file.name == null); + + // We create another `SafeRefCounted!File` handle to the same separate `File` object. + // While any of the handles is still alive, the `File` object is kept alive (=> `File.nDestroyed` is not modified). + auto rcFile2 = rcFile; + assert(rcFile.refCountedStore.refCount == 2); + assert(File.nDestroyed == 1); + } + // The separate `File` object is deleted when the last `SafeRefCounted!File` handle is destroyed + // (i.e. at the closing brace of the compound statement above, which destroys both handles: `rcFile` and `rcFile2`) + // (=> `File.nDestroyed` is incremented again, from 1 to 2): + assert(File.nDestroyed == 2); +} + +@safe unittest +{ + import std.typecons; + + struct MyInt + { + private int value; + mixin Proxy!value; + + this(int n){ value = n; } + } + + MyInt n = 10; + + // Enable operations that original type has. + ++n; + assert(n == 11); + assert(n * 2 == 22); + + void func(int n) { } + + // Disable implicit conversions to original type. + //int x = n; + //func(n); +} + +@safe unittest +{ + import std.typecons; + + struct NewIntType + { + //Won't work; the literal '1' + //is an rvalue, not an lvalue + //mixin Proxy!1; + + //Okay, n is an lvalue + int n; + mixin Proxy!n; + + this(int n) { this.n = n; } + } + + NewIntType nit = 0; + nit++; + assert(nit == 1); + + + struct NewObjectType + { + Object obj; + //Ok, obj is an lvalue + mixin Proxy!obj; + + this (Object o) { obj = o; } + } + + NewObjectType not = new Object(); + assert(__traits(compiles, not.toHash())); +} + +@safe unittest +{ + import std.typecons; + + import std.math.traits : isInfinity; + + float f = 1.0; + assert(!f.isInfinity); + + struct NewFloat + { + float _; + mixin Proxy!_; + + this(float f) { _ = f; } + } + + NewFloat nf = 1.0f; + assert(!nf.isInfinity); +} + +@safe unittest +{ + import std.typecons; + + import std.conv : to; + + int i = 123; + auto td = Typedef!int(i); + assert(i.to!string == td.to!string); + +} + +@safe unittest +{ + import std.typecons; + + alias MyInt = Typedef!int; + MyInt foo = 10; + foo++; + assert(foo == 11); +} + +@safe unittest +{ + import std.typecons; + + alias MyIntInit = Typedef!(int, 42); + static assert(is(TypedefType!MyIntInit == int)); + static assert(MyIntInit() == 42); +} + +@safe unittest +{ + import std.typecons; + + alias MyInt = Typedef!int; + static void takeInt(int) {} + static void takeMyInt(MyInt) {} + + int i; + takeInt(i); // ok + static assert(!__traits(compiles, takeMyInt(i))); + + MyInt myInt; + static assert(!__traits(compiles, takeInt(myInt))); + takeMyInt(myInt); // ok +} + +@safe unittest +{ + import std.typecons; + + alias TypeInt1 = Typedef!int; + alias TypeInt2 = Typedef!int; + + // The two Typedefs are the same type. + static assert(is(TypeInt1 == TypeInt2)); + + alias MoneyEuros = Typedef!(float, float.init, "euros"); + alias MoneyDollars = Typedef!(float, float.init, "dollars"); + + // The two Typedefs are _not_ the same type. + static assert(!is(MoneyEuros == MoneyDollars)); +} + +@safe unittest +{ + import std.typecons; + + import std.conv : to; + + alias MyInt = Typedef!int; + static assert(is(TypedefType!MyInt == int)); + + /// Instantiating with a non-Typedef will return that type + static assert(is(TypedefType!int == int)); + + string num = "5"; + + // extract the needed type + MyInt myInt = MyInt( num.to!(TypedefType!MyInt) ); + assert(myInt == 5); + + // cast to the underlying type to get the value that's being wrapped + int x = cast(TypedefType!MyInt) myInt; + + alias MyIntInit = Typedef!(int, 42); + static assert(is(TypedefType!MyIntInit == int)); + static assert(MyIntInit() == 42); +} + +@system unittest +{ + import std.typecons; + + class A + { + int x; + this() {x = 0;} + this(int i){x = i;} + ~this() {} + } + + // Standard usage, constructing A on the stack + auto a1 = scoped!A(); + a1.x = 42; + + // Result of `scoped` call implicitly converts to a class reference + A aRef = a1; + assert(aRef.x == 42); + + // Scoped destruction + { + auto a2 = scoped!A(1); + assert(a2.x == 1); + aRef = a2; + // a2 is destroyed here, calling A's destructor + } + // aRef is now an invalid reference + + // Here the temporary scoped A is immediately destroyed. + // This means the reference is then invalid. + version (Bug) + { + // Wrong, should use `auto` + A invalid = scoped!A(); + } + + // Restrictions + version (Bug) + { + import std.algorithm.mutation : move; + auto invalid = a1.move; // illegal, scoped objects can't be moved + } + static assert(!is(typeof({ + auto e1 = a1; // illegal, scoped objects can't be copied + assert([a1][0].x == 42); // ditto + }))); + static assert(!is(typeof({ + alias ScopedObject = typeof(a1); + auto e2 = ScopedObject(); // illegal, must be built via scoped!A + auto e3 = ScopedObject(1); // ditto + }))); + + // Use with alias + alias makeScopedA = scoped!A; + auto a3 = makeScopedA(); + auto a4 = makeScopedA(1); + + // Use as member variable + struct B + { + typeof(scoped!A()) a; // note the trailing parentheses + + this(int i) + { + // construct member + a = scoped!A(i); + } + } + + // Stack-allocate + auto b1 = B(5); + aRef = b1.a; + assert(aRef.x == 5); + destroy(b1); // calls A's destructor for b1.a + // aRef is now an invalid reference + + // Heap-allocate + auto b2 = new B(6); + assert(b2.a.x == 6); + destroy(*b2); // calls A's destructor for b2.a +} + +@safe unittest +{ + import std.typecons; + + Flag!"abc" flag; + + assert(flag == Flag!"abc".no); + assert(flag == No.abc); + assert(!flag); + if (flag) assert(0); +} + +@safe unittest +{ + import std.typecons; + + auto flag = Yes.abc; + + assert(flag); + assert(flag == Yes.abc); + if (!flag) assert(0); + if (flag) {} else assert(0); +} + +@safe unittest +{ + import std.typecons; + + Flag!"abc" flag; + + assert(flag == Flag!"abc".no); + assert(flag == No.abc); + assert(!flag); + if (flag) assert(0); +} + +@safe unittest +{ + import std.typecons; + + auto flag = Yes.abc; + + assert(flag); + assert(flag == Yes.abc); + if (!flag) assert(0); + if (flag) {} else assert(0); +} + +@safe pure nothrow unittest +{ + import std.typecons; + + enum A + { + None, + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + D = 1 << 3, + } + + static assert(isBitFlagEnum!A); +} + +@safe pure nothrow unittest +{ + import std.typecons; + + enum B + { + A, + B, + C, + D // D == 3 + } + + static assert(!isBitFlagEnum!B); +} + +@safe pure nothrow unittest +{ + import std.typecons; + + enum C: double + { + A = 1 << 0, + B = 1 << 1 + } + + static assert(!isBitFlagEnum!C); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + A = 1 << 0, + } + + // A default constructed BitFlags has no value set + immutable BitFlags!Enum flags_empty; + assert(!flags_empty.A); + + // Value can be set with the | operator + immutable flags_A = flags_empty | Enum.A; + + // and tested using property access + assert(flags_A.A); + + // or the & operator + assert(flags_A & Enum.A); + // which commutes. + assert(Enum.A & flags_A); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + None, + A = 1 << 0, + B = 1 << 1, + C = 1 << 2 + } + + immutable BitFlags!Enum flags_empty; + assert(!(flags_empty & (Enum.A | Enum.B | Enum.C))); + assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C)); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + } + immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B); + immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C); + + // Use the ~ operator for subtracting flags + immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A); + assert(!flags_B.A && flags_B.B && !flags_B.C); + + // use & between BitFlags for intersection + assert(flags_B == (flags_BC & flags_AB)); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + A = 1 << 0, + B = 1 << 1, + } + + BitFlags!Enum flags_empty, temp, flags_AB; + flags_AB = Enum.A | Enum.B; + + temp |= flags_AB; + assert(temp == (flags_empty | flags_AB)); + + temp = flags_empty; + temp |= Enum.B; + assert(temp == (flags_empty | Enum.B)); + + temp = flags_empty; + temp &= flags_AB; + assert(temp == (flags_empty & flags_AB)); + + temp = flags_empty; + temp &= Enum.A; + assert(temp == (flags_empty & Enum.A)); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + A = 1 << 0, + B = 1 << 1, + } + + BitFlags!Enum flags; + + // BitFlags with no value set evaluate to false + assert(!flags); + + // BitFlags with at least one value set evaluate to true + flags |= Enum.A; + assert(flags); + + // This can be useful to check intersection between BitFlags + BitFlags!Enum flags_AB = Enum.A | Enum.B; + assert(flags & flags_AB); + assert(flags & Enum.A); + + // You can of course get you raw value out of flags + auto value = cast(int) flags; + assert(value == Enum.A); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum UnsafeEnum + { + A = 1, + B = 2, + C = 4, + BC = B|C + } + static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags; })); + BitFlags!(UnsafeEnum, Yes.unsafe) flags; + + // property access tests for exact match of unsafe enums + flags.B = true; + assert(!flags.BC); // only B + flags.C = true; + assert(flags.BC); // both B and C + flags.B = false; + assert(!flags.BC); // only C + + // property access sets all bits of unsafe enum group + flags = flags.init; + flags.BC = true; + assert(!flags.A && flags.B && flags.C); + flags.A = true; + flags.BC = false; + assert(flags.A && !flags.B && !flags.C); +} + +@safe unittest +{ + import std.typecons; + + static assert( + is(ReplaceType!(int, string, int[]) == string[]) && + is(ReplaceType!(int, string, int[int]) == string[string]) && + is(ReplaceType!(int, string, const(int)[]) == const(string)[]) && + is(ReplaceType!(int, string, Tuple!(int[], float)) + == Tuple!(string[], float)) + ); +} + +@safe unittest +{ + import std.typecons; + + import std.traits : isArray; + + static assert( + is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) && + is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) && + is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[])) + == Tuple!(string, int[])) + ); +} + +@safe @nogc nothrow pure unittest +{ + import std.typecons; + + Ternary a; + assert(a == Ternary.unknown); + + assert(~Ternary.yes == Ternary.no); + assert(~Ternary.no == Ternary.yes); + assert(~Ternary.unknown == Ternary.unknown); +} + +pure @system nothrow @nogc unittest +{ + import std.typecons; + + auto rc1 = RefCounted!int(5); + assert(rc1 == 5); + auto rc2 = rc1; + rc2 = 42; + assert(rc1 == 42); +} + +@system unittest +{ + import std.typecons; + + static struct File + { + static size_t nDestroyed; + string name; + @disable this(this); // not copyable + ~this() { name = null; ++nDestroyed; } + } + + auto file = File("name"); + assert(file.name == "name"); + static assert(!__traits(compiles, {auto file2 = file;})); + assert(File.nDestroyed == 0); + + { + import std.algorithm.mutation : move; + auto rcFile = refCounted(move(file)); + assert(rcFile.name == "name"); + assert(File.nDestroyed == 1); + assert(file.name == null); + + auto rcFile2 = rcFile; + assert(rcFile.refCountedStore.refCount == 2); + assert(File.nDestroyed == 1); + } + + assert(File.nDestroyed == 2); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_typetuple.d b/libphobos/testsuite/libphobos.phobos/std_typetuple.d new file mode 100644 index 0000000000000000000000000000000000000000..e5ccd7637a216059c3f1c6aea61ade121be868fc --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_typetuple.d @@ -0,0 +1,24 @@ +@safe unittest +{ + import std.typetuple; + + import std.typetuple; + alias TL = TypeTuple!(int, double); + + int foo(TL td) // same as int foo(int, double); + { + return td[0] + cast(int) td[1]; + } + assert(foo(1, 2.5) == 3); +} + +@safe unittest +{ + import std.typetuple; + + alias TL = TypeTuple!(int, double); + + alias Types = TypeTuple!(TL, char); + static assert(is(Types == TypeTuple!(int, double, char))); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_uni_package.d b/libphobos/testsuite/libphobos.phobos/std_uni_package.d new file mode 100644 index 0000000000000000000000000000000000000000..cdb3439c941c75b1941a08a6e98be6b17fc61d5d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_uni_package.d @@ -0,0 +1,547 @@ +pure @safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + + auto set = CodepointSet('a', 'z'+1, 'а', 'Ñ'+1); + foreach (v; 'a'..'z'+1) + assert(set[v]); + // Cyrillic lowercase interval + foreach (v; 'а'..'Ñ'+1) + assert(set[v]); + //specific order is not required, intervals may interesect + auto set2 = CodepointSet('а', 'Ñ'+1, 'a', 'd', 'b', 'z'+1); + //the same end result + assert(set2.byInterval.equal(set.byInterval)); + // test constructor this(Range)(Range intervals) + auto chessPiecesWhite = CodepointInterval(9812, 9818); + auto chessPiecesBlack = CodepointInterval(9818, 9824); + auto set3 = CodepointSet([chessPiecesWhite, chessPiecesBlack]); + foreach (v; 'â™”'..'♟'+1) + assert(set3[v]); + +} + +pure @safe unittest +{ + import std.uni; + + auto gothic = unicode.Gothic; + // Gothic letter ahsa + assert(gothic['\U00010330']); + // no ascii in Gothic obviously + assert(!gothic['$']); + +} + +pure @safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + import std.range : iota; + + auto lower = unicode.LowerCase; + auto upper = unicode.UpperCase; + auto ascii = unicode.ASCII; + + assert((lower & upper).empty); // no intersection + auto lowerASCII = lower & ascii; + assert(lowerASCII.byCodepoint.equal(iota('a', 'z'+1))); + // throw away all of the lowercase ASCII + assert((ascii - lower).length == 128 - 26); + + auto onlyOneOf = lower ~ ascii; + assert(!onlyOneOf['Δ']); // not ASCII and not lowercase + assert(onlyOneOf['$']); // ASCII and not lowercase + assert(!onlyOneOf['a']); // ASCII and lowercase + assert(onlyOneOf['Ñ']); // not ASCII but lowercase + + // throw away all cased letters from ASCII + auto noLetters = ascii - (lower | upper); + assert(noLetters.length == 128 - 26*2); + +} + +pure @safe unittest +{ + import std.uni; + + assert('Ñ' in unicode.Cyrillic); + assert(!('z' in unicode.Cyrillic)); + +} + +pure @safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + import std.range : iota; + + auto set = unicode.ASCII; + set.byCodepoint.equal(iota(0, 0x80)); + +} + +pure @safe unittest +{ + import std.uni; + + import std.conv : to; + import std.format : format; + import std.uni : unicode; + + // This was originally using Cyrillic script. + // Unfortunately this is a pretty active range for changes, + // and hence broke in an update. + // Therefore the range Basic latin was used instead as it + // unlikely to ever change. + + assert(unicode.InBasic_latin.to!string == "[0..128)"); + + // The specs '%s' and '%d' are equivalent to the to!string call above. + assert(format("%d", unicode.InBasic_latin) == unicode.InBasic_latin.to!string); + + assert(format("%#x", unicode.InBasic_latin) == "[0..0x80)"); + assert(format("%#X", unicode.InBasic_latin) == "[0..0X80)"); + +} + +pure @safe unittest +{ + import std.uni; + + CodepointSet someSet; + someSet.add('0', '5').add('A','Z'+1); + someSet.add('5', '9'+1); + assert(someSet['0']); + assert(someSet['5']); + assert(someSet['9']); + assert(someSet['Z']); + +} + +pure @safe unittest +{ + import std.uni; + + auto set = unicode.ASCII; + // union with the inverse gets all of the code points in the Unicode + assert((set | set.inverted).length == 0x110000); + // no intersection with the inverse + assert((set & set.inverted).empty); + +} + +pure @safe unittest +{ + import std.uni; + + CodepointSet emptySet; + assert(emptySet.length == 0); + assert(emptySet.empty); + +} + +pure @safe unittest +{ + import std.uni; + + string truth = "2² = 4"; + auto m = utfMatcher!char(unicode.Number); + assert(m.match(truth)); // '2' is a number all right + assert(truth == "² = 4"); // skips on match + assert(m.match(truth)); // so is the superscript '2' + assert(!m.match(truth)); // space is not a number + assert(truth == " = 4"); // unaffected on no match + assert(!m.skip(truth)); // same test ... + assert(truth == "= 4"); // but skips a codepoint regardless + assert(!m.test(truth)); // '=' is not a number + assert(truth == "= 4"); // test never affects argument + +} + +@safe unittest +{ + import std.uni; + + import std.exception : collectException; + auto ascii = unicode.ASCII; + assert(ascii['A']); + assert(ascii['~']); + assert(!ascii['\u00e0']); + // matching is case-insensitive + assert(ascii == unicode.ascII); + assert(!ascii['à ']); + // underscores, '-' and whitespace in names are ignored too + auto latin = unicode.in_latin1_Supplement; + assert(latin['à ']); + assert(!latin['$']); + // BTW Latin 1 Supplement is a block, hence "In" prefix + assert(latin == unicode("In Latin 1 Supplement")); + // run-time look up throws if no such set is found + assert(collectException(unicode("InCyrilliac"))); + +} + +@safe unittest +{ + import std.uni; + + // use .block for explicitness + assert(unicode.block.Greek_and_Coptic == unicode.InGreek_and_Coptic); + +} + +@safe unittest +{ + import std.uni; + + auto arabicScript = unicode.script.arabic; + auto arabicBlock = unicode.block.arabic; + // there is an intersection between script and block + assert(arabicBlock['Ø']); + assert(arabicScript['Ø']); + // but they are different + assert(arabicBlock != arabicScript); + assert(arabicBlock == unicode.inArabic); + assert(arabicScript == unicode.arabic); + +} + +@safe unittest +{ + import std.uni; + + // L here is syllable type not Letter as in unicode.L short-cut + auto leadingVowel = unicode.hangulSyllableType("L"); + // check that some leading vowels are present + foreach (vowel; '\u1110'..'\u115F') + assert(leadingVowel[vowel]); + assert(leadingVowel == unicode.hangulSyllableType.L); + +} + +@safe unittest +{ + import std.uni; + + import std.uni : unicode; + string pat = "[a-zA-Z0-9]hello"; + auto set = unicode.parseSet(pat); + // check some of the codepoints + assert(set['a'] && set['A'] && set['9']); + assert(pat == "hello"); + +} + +@safe unittest +{ + import std.uni; + + assert(graphemeStride(" ", 1) == 1); + // A + combing ring above + string city = "A\u030Arhus"; + size_t first = graphemeStride(city, 0); + assert(first == 3); //\u030A has 2 UTF-8 code units + assert(city[0 .. first] == "A\u030A"); + assert(city[first..$] == "rhus"); +} + +@safe pure unittest +{ + import std.uni; + + // Two Union Jacks of the Great Britain in each + string s = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7"; + wstring ws = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7"; + dstring ds = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7"; + + // String pop length in code units, not points. + assert(s.popGrapheme() == 8); + assert(ws.popGrapheme() == 4); + assert(ds.popGrapheme() == 2); + + assert(s == "\U0001F1EC\U0001F1E7"); + assert(ws == "\U0001F1EC\U0001F1E7"); + assert(ds == "\U0001F1EC\U0001F1E7"); + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter; + + // Also works for non-random access ranges as long as the + // character type is 32-bit. + auto testPiece = "\r\nhello!"d.filter!(x => !x.isAlpha); + // Windows-style line ending is two code points in a single grapheme. + assert(testPiece.popGrapheme() == 2); + assert(testPiece.equal("!"d)); +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + import std.range.primitives : walkLength; + import std.range : take, drop; + auto text = "noe\u0308l"; // noël using e + combining diaeresis + assert(text.walkLength == 5); // 5 code points + + auto gText = text.byGrapheme; + assert(gText.walkLength == 4); // 4 graphemes + + assert(gText.take(3).equal("noe\u0308".byGrapheme)); + assert(gText.drop(3).equal("l".byGrapheme)); +} + +@safe unittest +{ + import std.uni; + + import std.array : array; + import std.conv : text; + import std.range : retro; + + string s = "noe\u0308l"; // noël + + // reverse it and convert the result to a string + string reverse = s.byGrapheme + .array + .retro + .byCodePoint + .text; + + assert(reverse == "le\u0308on"); // lëon +} + +@safe unittest +{ + import std.uni; + + auto g = Grapheme("A\u0302"); + assert(g[0] == 'A'); + assert(g.valid); + g[1] = '~'; // ASCII tilda is not a combining mark + assert(g[1] == '~'); + assert(!g.valid); + +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + auto g = Grapheme("A"); + assert(g.valid); + g ~= '\u0301'; + assert(g[].equal("A\u0301")); + assert(g.valid); + g ~= "B"; + // not a valid grapheme cluster anymore + assert(!g.valid); + // still could be useful though + assert(g[].equal("A\u0301B")); + +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter; + import std.range : isRandomAccessRange; + + string bold = "ku\u0308hn"; + + // note that decodeGrapheme takes parameter by ref + auto first = decodeGrapheme(bold); + + assert(first.length == 1); + assert(first[0] == 'k'); + + // the next grapheme is 2 characters long + auto wideOne = decodeGrapheme(bold); + // slicing a grapheme yields a random-access range of dchar + assert(wideOne[].equal("u\u0308")); + assert(wideOne.length == 2); + static assert(isRandomAccessRange!(typeof(wideOne[]))); + + // all of the usual range manipulation is possible + assert(wideOne[].filter!isMark().equal("\u0308")); + + auto g = Grapheme("A"); + assert(g.valid); + g ~= '\u0301'; + assert(g[].equal("A\u0301")); + assert(g.valid); + g ~= "B"; + // not a valid grapheme cluster anymore + assert(!g.valid); + // still could be useful though + assert(g[].equal("A\u0301B")); +} + +@safe @nogc pure nothrow unittest +{ + import std.uni; + + assert(sicmp("ÐвгуÑÑ‚", "авгуÑТ") == 0); + // Greek also works as long as there is no 1:M mapping in sight + assert(sicmp("ΌΎ", "ÏŒÏ") == 0); + // things like the following won't get matched as equal + // Greek small letter iota with dialytika and tonos + assert(sicmp("Î", "\u03B9\u0308\u0301") != 0); + + // while icmp has no problem with that + assert(icmp("Î", "\u03B9\u0308\u0301") == 0); + assert(icmp("ΌΎ", "ÏŒÏ") == 0); +} + +@safe @nogc pure nothrow unittest +{ + import std.uni; + + assert(icmp("Rußland", "Russland") == 0); + assert(icmp("ᾩ -> \u1F70\u03B9", "\u1F61\u03B9 -> á¾²") == 0); +} + +@safe @nogc nothrow pure unittest +{ + import std.uni; + + import std.utf : byDchar; + + assert(icmp("Rußland".byDchar, "Russland".byDchar) == 0); + assert(icmp("ᾩ -> \u1F70\u03B9".byDchar, "\u1F61\u03B9 -> á¾²".byDchar) == 0); +} + +@safe unittest +{ + import std.uni; + + // shorten the code + alias CC = combiningClass; + + // combining tilda + assert(CC('\u0303') == 230); + // combining ring below + assert(CC('\u0325') == 220); + // the simple consequence is that "tilda" should be + // placed after a "ring below" in a sequence +} + +@safe unittest +{ + import std.uni; + + assert(compose('A','\u0308') == '\u00C4'); + assert(compose('A', 'B') == dchar.init); + assert(compose('C', '\u0301') == '\u0106'); + // note that the starter is the first one + // thus the following doesn't compose + assert(compose('\u0308', 'A') == dchar.init); +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + + assert(compose('A','\u0308') == '\u00C4'); + assert(compose('A', 'B') == dchar.init); + assert(compose('C', '\u0301') == '\u0106'); + // note that the starter is the first one + // thus the following doesn't compose + assert(compose('\u0308', 'A') == dchar.init); + + assert(decompose('Ĉ')[].equal("C\u0302")); + assert(decompose('D')[].equal("D")); + assert(decompose('\uD4DC')[].equal("\u1111\u1171\u11B7")); + assert(decompose!Compatibility('¹')[].equal("1")); +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + assert(decomposeHangul('\uD4DB')[].equal("\u1111\u1171\u11B6")); +} + +@safe unittest +{ + import std.uni; + + assert(composeJamo('\u1111', '\u1171', '\u11B6') == '\uD4DB'); + // leaving out T-vowel, or passing any codepoint + // that is not trailing consonant composes an LV-syllable + assert(composeJamo('\u1111', '\u1171') == '\uD4CC'); + assert(composeJamo('\u1111', '\u1171', ' ') == '\uD4CC'); + assert(composeJamo('\u1111', 'A') == dchar.init); + assert(composeJamo('A', '\u1171') == dchar.init); +} + +@safe pure unittest +{ + import std.uni; + + // any encoding works + wstring greet = "Hello world"; + assert(normalize(greet) is greet); // the same exact slice + + // An example of a character with all 4 forms being different: + // Greek upsilon with acute and hook symbol (code point 0x03D3) + assert(normalize!NFC("Ï“") == "\u03D3"); + assert(normalize!NFD("Ï“") == "\u03D2\u0301"); + assert(normalize!NFKC("Ï“") == "\u038E"); + assert(normalize!NFKD("Ï“") == "\u03A5\u0301"); +} + +@safe unittest +{ + import std.uni; + + // e.g. Cyrillic is always allowed, so is ASCII + assert(allowedIn!NFC('Ñ')); + assert(allowedIn!NFD('Ñ')); + assert(allowedIn!NFKC('Ñ')); + assert(allowedIn!NFKD('Ñ')); + assert(allowedIn!NFC('Z')); +} + +@safe pure unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + + assert("hEllo".asUpperCase.equal("HELLO")); +} + +@safe pure unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + + assert("hEllo".asCapitalized.equal("Hello")); +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.iteration : map; + import std.algorithm.mutation : copy; + import std.array : appender; + + auto abuf = appender!(char[])(); + "hello".map!toUpper.copy(abuf); + assert(abuf.data == "HELLO"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_uri.d b/libphobos/testsuite/libphobos.phobos/std_uri.d new file mode 100644 index 0000000000000000000000000000000000000000..5d57062c42ef24bce7cab3de592369286b693988 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_uri.d @@ -0,0 +1,71 @@ +@safe unittest +{ + import std.uri; + + import std.exception : assertThrown; + assertThrown!URIException("%ab".decode); +} + +@safe unittest +{ + import std.uri; + + assert("foo%20bar".decode == "foo bar"); + assert("%3C%3E.@.%E2%84%A2".decode == "<>.@.â„¢"); + assert("foo&/".decode == "foo&/"); + assert("!@#$&*(".decode == "!@#$&*("); +} + +@safe unittest +{ + import std.uri; + + assert("foo%2F%26".decodeComponent == "foo/&"); + assert("dl%C3%A4ng%20r%C3%B6cks".decodeComponent == "dläng röcks"); + assert("!%40%23%24%25%5E%26*(".decodeComponent == "!@#$%^&*("); +} + +@safe unittest +{ + import std.uri; + + assert("foo bar".encode == "foo%20bar"); + assert("<>.@.â„¢".encode == "%3C%3E.@.%E2%84%A2"); + assert("foo/#?a=1&b=2".encode == "foo/#?a=1&b=2"); + assert("dlang+rocks!".encode == "dlang+rocks!"); + assert("!@#$%^&*(".encode == "!@#$%25%5E&*("); +} + +@safe unittest +{ + import std.uri; + + assert("!@#$%^&*(".encodeComponent == "!%40%23%24%25%5E%26*("); + assert("<>.@.â„¢".encodeComponent == "%3C%3E.%40.%E2%84%A2"); + assert("foo/&".encodeComponent == "foo%2F%26"); + assert("dläng röcks".encodeComponent == "dl%C3%A4ng%20r%C3%B6cks"); + assert("dlang+rocks!".encodeComponent == "dlang%2Brocks!"); +} + +@safe pure unittest +{ + import std.uri; + + string s1 = "http://www.digitalmars.com/~fred/fredsRX.html#foo end!"; + assert(uriLength(s1) == 49); + string s2 = "no uri here"; + assert(uriLength(s2) == -1); + assert(uriLength("issue 14924") < 0); +} + +@safe pure unittest +{ + import std.uri; + + string s1 = "my.e-mail@www.example-domain.com with garbage added"; + assert(emailLength(s1) == 32); + string s2 = "no email address here"; + assert(emailLength(s2) == -1); + assert(emailLength("issue 14924") < 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_utf.d b/libphobos/testsuite/libphobos.phobos/std_utf.d new file mode 100644 index 0000000000000000000000000000000000000000..e758d488ae018e93735b308d119934470fff6129 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_utf.d @@ -0,0 +1,474 @@ +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + + char[4] buf; + assertThrown!UTFException(encode(buf, cast(dchar) 0xD800)); + assertThrown!UTFException(encode(buf, cast(dchar) 0xDBFF)); + assertThrown!UTFException(encode(buf, cast(dchar) 0xDC00)); + assertThrown!UTFException(encode(buf, cast(dchar) 0xDFFF)); + assertThrown!UTFException(encode(buf, cast(dchar) 0x110000)); +} + +@safe @nogc pure nothrow unittest +{ + import std.utf; + + assert( isValidDchar(cast(dchar) 0x41)); + assert( isValidDchar(cast(dchar) 0x00)); + assert(!isValidDchar(cast(dchar) 0xD800)); + assert(!isValidDchar(cast(dchar) 0x11FFFF)); +} + +@safe pure nothrow unittest +{ + import std.utf; + + assert( isValidCodepoint(cast(char) 0x40)); + assert(!isValidCodepoint(cast(char) 0x80)); + assert( isValidCodepoint(cast(wchar) 0x1234)); + assert(!isValidCodepoint(cast(wchar) 0xD800)); + assert( isValidCodepoint(cast(dchar) 0x0010FFFF)); + assert(!isValidCodepoint(cast(dchar) 0x12345678)); +} + +@safe unittest +{ + import std.utf; + + assert("a".stride == 1); + assert("λ".stride == 2); + assert("aλ".stride == 1); + assert("aλ".stride(1) == 2); + assert("ð·".stride == 4); +} + +@safe unittest +{ + import std.utf; + + assert("a".strideBack == 1); + assert("λ".strideBack == 2); + assert("aλ".strideBack == 2); + assert("aλ".strideBack(1) == 1); + assert("ð·".strideBack == 4); +} + +@safe unittest +{ + import std.utf; + + assert(toUCSindex(`hello world`, 7) == 7); + assert(toUCSindex(`hello world`w, 7) == 7); + assert(toUCSindex(`hello world`d, 7) == 7); + + assert(toUCSindex(`Ma Chérie`, 7) == 6); + assert(toUCSindex(`Ma Chérie`w, 7) == 7); + assert(toUCSindex(`Ma Chérie`d, 7) == 7); + + assert(toUCSindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`, 9) == 3); + assert(toUCSindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`w, 9) == 9); + assert(toUCSindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`d, 9) == 9); +} + +@safe unittest +{ + import std.utf; + + assert(toUTFindex(`hello world`, 7) == 7); + assert(toUTFindex(`hello world`w, 7) == 7); + assert(toUTFindex(`hello world`d, 7) == 7); + + assert(toUTFindex(`Ma Chérie`, 6) == 7); + assert(toUTFindex(`Ma Chérie`w, 7) == 7); + assert(toUTFindex(`Ma Chérie`d, 7) == 7); + + assert(toUTFindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`, 3) == 9); + assert(toUTFindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`w, 9) == 9); + assert(toUTFindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`d, 9) == 9); +} + +@safe pure unittest +{ + import std.utf; + + size_t i; + + assert("a".decode(i) == 'a' && i == 1); + i = 0; + assert("Ã¥".decode(i) == 'Ã¥' && i == 2); + i = 1; + assert("aÃ¥".decode(i) == 'Ã¥' && i == 3); + i = 0; + assert("Ã¥"w.decode(i) == 'Ã¥' && i == 1); + + // ë as a multi-code point grapheme + i = 0; + assert("e\u0308".decode(i) == 'e' && i == 1); + // ë as a single code point grapheme + i = 0; + assert("ë".decode(i) == 'ë' && i == 2); + i = 0; + assert("ë"w.decode(i) == 'ë' && i == 1); +} + +@safe pure unittest +{ + import std.utf; + + import std.range.primitives; + string str = "Hello, World!"; + + assert(str.decodeFront == 'H' && str == "ello, World!"); + str = "Ã¥"; + assert(str.decodeFront == 'Ã¥' && str.empty); + str = "Ã¥"; + size_t i; + assert(str.decodeFront(i) == 'Ã¥' && i == 2 && str.empty); +} + +@system pure unittest +{ + import std.utf; + + import std.range.primitives; + string str = "Hello, World!"; + + assert(str.decodeBack == '!' && str == "Hello, World"); + str = "Ã¥"; + assert(str.decodeBack == 'Ã¥' && str.empty); + str = "Ã¥"; + size_t i; + assert(str.decodeBack(i) == 'Ã¥' && i == 2 && str.empty); +} + +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + import std.typecons : Yes; + + char[4] buf; + + assert(encode(buf, '\u0000') == 1 && buf[0 .. 1] == "\u0000"); + assert(encode(buf, '\u007F') == 1 && buf[0 .. 1] == "\u007F"); + assert(encode(buf, '\u0080') == 2 && buf[0 .. 2] == "\u0080"); + assert(encode(buf, '\uE000') == 3 && buf[0 .. 3] == "\uE000"); + assert(encode(buf, 0xFFFE) == 3 && buf[0 .. 3] == "\xEF\xBF\xBE"); + assertThrown!UTFException(encode(buf, cast(dchar) 0x110000)); + + encode!(Yes.useReplacementDchar)(buf, cast(dchar) 0x110000); + auto slice = buf[]; + assert(slice.decodeFront == replacementDchar); +} + +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + import std.typecons : Yes; + + wchar[2] buf; + + assert(encode(buf, '\u0000') == 1 && buf[0 .. 1] == "\u0000"); + assert(encode(buf, '\uD7FF') == 1 && buf[0 .. 1] == "\uD7FF"); + assert(encode(buf, '\uE000') == 1 && buf[0 .. 1] == "\uE000"); + assert(encode(buf, '\U00010000') == 2 && buf[0 .. 2] == "\U00010000"); + assert(encode(buf, '\U0010FFFF') == 2 && buf[0 .. 2] == "\U0010FFFF"); + assertThrown!UTFException(encode(buf, cast(dchar) 0xD800)); + + encode!(Yes.useReplacementDchar)(buf, cast(dchar) 0x110000); + auto slice = buf[]; + assert(slice.decodeFront == replacementDchar); +} + +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + import std.typecons : Yes; + + dchar[1] buf; + + assert(encode(buf, '\u0000') == 1 && buf[0] == '\u0000'); + assert(encode(buf, '\uD7FF') == 1 && buf[0] == '\uD7FF'); + assert(encode(buf, '\uE000') == 1 && buf[0] == '\uE000'); + assert(encode(buf, '\U0010FFFF') == 1 && buf[0] == '\U0010FFFF'); + assertThrown!UTFException(encode(buf, cast(dchar) 0xD800)); + + encode!(Yes.useReplacementDchar)(buf, cast(dchar) 0x110000); + assert(buf[0] == replacementDchar); +} + +@safe unittest +{ + import std.utf; + + char[] s = "abcd".dup; + dchar d1 = 'a'; + dchar d2 = 'ø'; + + encode(s, d1); + assert(s.length == 5); + assert(s == "abcda"); + encode(s, d2); + assert(s.length == 7); + assert(s == "abcdaø"); +} + +@safe pure nothrow @nogc unittest +{ + import std.utf; + + assert(codeLength!char('a') == 1); + assert(codeLength!wchar('a') == 1); + assert(codeLength!dchar('a') == 1); + + assert(codeLength!char('\U0010FFFF') == 4); + assert(codeLength!wchar('\U0010FFFF') == 2); + assert(codeLength!dchar('\U0010FFFF') == 1); +} + +@safe unittest +{ + import std.utf; + + assert(codeLength!char("hello world") == + "hello world".length); + assert(codeLength!wchar("hello world") == + "hello world"w.length); + assert(codeLength!dchar("hello world") == + "hello world"d.length); + + assert(codeLength!char(`プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`) == + `プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`.length); + assert(codeLength!wchar(`プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`) == + `プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`w.length); + assert(codeLength!dchar(`プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`) == + `プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`d.length); + + string haystack = `Être sans la verité, ça, ce ne serait pas bien.`; + wstring needle = `Être sans la verité`; + assert(haystack[codeLength!char(needle) .. $] == + `, ça, ce ne serait pas bien.`); +} + +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + char[] a = [167, 133, 175]; + assertThrown!UTFException(validate(a)); +} + +@safe pure unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + + // The ö is represented by two UTF-8 code units + assert("Hellø"w.toUTF8.equal(['H', 'e', 'l', 'l', 0xC3, 0xB8])); + + // ð· is four code units in UTF-8 + assert("ð·"d.toUTF8.equal([0xF0, 0x90, 0x90, 0xB7])); +} + +@safe pure unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + + // these graphemes are two code units in UTF-16 and one in UTF-32 + assert("ð¤¢"d.length == 1); + assert("ð·"d.length == 1); + + assert("ð¤¢"d.toUTF16.equal([0xD852, 0xDF62])); + assert("ð·"d.toUTF16.equal([0xD801, 0xDC37])); +} + +@safe pure unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + + // these graphemes are two code units in UTF-16 and one in UTF-32 + assert("ð¤¢"w.length == 2); + assert("ð·"w.length == 2); + + assert("ð¤¢"w.toUTF32.equal([0x00024B62])); + assert("ð·"w.toUTF32.equal([0x00010437])); +} + +@safe pure unittest +{ + import std.utf; + + auto p1 = toUTFz!(char*)("hello world"); + auto p2 = toUTFz!(const(char)*)("hello world"); + auto p3 = toUTFz!(immutable(char)*)("hello world"); + auto p4 = toUTFz!(char*)("hello world"d); + auto p5 = toUTFz!(const(wchar)*)("hello world"); + auto p6 = toUTFz!(immutable(dchar)*)("hello world"w); +} + +@system unittest +{ + import std.utf; + + string str = "Hello, World!"; + const(wchar)* p = str.toUTF16z; + assert(p[str.length] == '\0'); +} + +@safe pure nothrow @nogc unittest +{ + import std.utf; + + assert(count("") == 0); + assert(count("a") == 1); + assert(count("abc") == 3); + assert(count("\u20AC100") == 4); +} + +@safe unittest +{ + import std.utf; + + import std.range.primitives; + import std.traits : isAutodecodableString; + + auto r = "Hello, World!".byCodeUnit(); + static assert(hasLength!(typeof(r))); + static assert(hasSlicing!(typeof(r))); + static assert(isRandomAccessRange!(typeof(r))); + static assert(is(ElementType!(typeof(r)) == immutable char)); + + // contrast with the range capabilities of standard strings (with or + // without autodecoding enabled). + auto s = "Hello, World!"; + static assert(isBidirectionalRange!(typeof(r))); + static if (isAutodecodableString!(typeof(s))) + { + // with autodecoding enabled, strings are non-random-access ranges of + // dchar. + static assert(is(ElementType!(typeof(s)) == dchar)); + static assert(!isRandomAccessRange!(typeof(s))); + static assert(!hasSlicing!(typeof(s))); + static assert(!hasLength!(typeof(s))); + } + else + { + // without autodecoding, strings are normal arrays. + static assert(is(ElementType!(typeof(s)) == immutable char)); + static assert(isRandomAccessRange!(typeof(s))); + static assert(hasSlicing!(typeof(s))); + static assert(hasLength!(typeof(s))); + } +} + +@safe unittest +{ + import std.utf; + + string noel1 = "noe\u0308l"; // noël using e + combining diaeresis + assert(noel1.byCodeUnit[2] != 'ë'); + assert(noel1.byCodeUnit[2] == 'e'); + + string noel2 = "no\u00EBl"; // noël using a precomposed ë character + // Because string is UTF-8, the code unit at index 2 is just + // the first of a sequence that encodes 'ë' + assert(noel2.byCodeUnit[2] != 'ë'); +} + +@safe unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + import std.range : popFrontN; + import std.traits : isAutodecodableString; + { + auto range = byCodeUnit("hello world"); + range.popFrontN(3); + assert(equal(range.save, "lo world")); + static if (isAutodecodableString!string) // only enabled with autodecoding + { + string str = range.source; + assert(str == "lo world"); + } + } + // source only exists if the range was wrapped + { + auto range = byCodeUnit("hello world"d); + static assert(!__traits(compiles, range.source)); + } +} + +@safe pure nothrow unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + + // hellö as a range of `char`s, which are UTF-8 + assert("hell\u00F6".byUTF!char().equal(['h', 'e', 'l', 'l', 0xC3, 0xB6])); + + // `wchar`s are able to hold the ö in a single element (UTF-16 code unit) + assert("hell\u00F6".byUTF!wchar().equal(['h', 'e', 'l', 'l', 'ö'])); + + // ð· is four code units in UTF-8, two in UTF-16, and one in UTF-32 + assert("ð·".byUTF!char().equal([0xF0, 0x90, 0x90, 0xB7])); + assert("ð·".byUTF!wchar().equal([0xD801, 0xDC37])); + assert("ð·".byUTF!dchar().equal([0x00010437])); +} + +@safe unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + import std.exception : assertThrown; + + assert("hello\xF0betty".byChar.byUTF!(dchar, UseReplacementDchar.yes).equal("hello\uFFFDetty")); + assertThrown!UTFException("hello\xF0betty".byChar.byUTF!(dchar, UseReplacementDchar.no).equal("hello betty")); +} + +@safe pure nothrow unittest +{ + import std.utf; + + import std.range.primitives; + wchar[] s = ['ă', 'î']; + + auto rc = s.byUTF!char; + static assert(isBidirectionalRange!(typeof(rc))); + assert(rc.back == 0xae); + rc.popBack; + assert(rc.back == 0xc3); + rc.popBack; + assert(rc.back == 0x83); + rc.popBack; + assert(rc.back == 0xc4); + + auto rw = s.byUTF!wchar; + static assert(isBidirectionalRange!(typeof(rw))); + assert(rw.back == 'î'); + rw.popBack; + assert(rw.back == 'ă'); + + auto rd = s.byUTF!dchar; + static assert(isBidirectionalRange!(typeof(rd))); + assert(rd.back == 'î'); + rd.popBack; + assert(rd.back == 'ă'); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_uuid.d b/libphobos/testsuite/libphobos.phobos/std_uuid.d new file mode 100644 index 0000000000000000000000000000000000000000..2486083cd26cb546f271b2ed87d6ca103181e75b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_uuid.d @@ -0,0 +1,252 @@ +@safe unittest +{ + import std.uuid; + + import std.uuid; + + UUID[] ids; + ids ~= randomUUID(); + ids ~= md5UUID("test.name.123"); + ids ~= sha1UUID("test.name.123"); + + foreach (entry; ids) + { + assert(entry.variant == UUID.Variant.rfc4122); + } + assert(ids[0].uuidVersion == UUID.Version.randomNumberBased); + assert(ids[1].toString() == "22390768-cced-325f-8f0f-cfeaa19d0ccd"); + assert(ids[1].data == [34, 57, 7, 104, 204, 237, 50, 95, 143, 15, 207, + 234, 161, 157, 12, 205]); + UUID id; + assert(id.empty); +} + +@safe pure unittest +{ + import std.uuid; + + enum ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; + auto uuid = UUID(data); + enum ctfe = UUID(data); + assert(uuid.data == data); + assert(ctfe.data == data); + +} + +@safe unittest +{ + import std.uuid; + + auto tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); + assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11, + 12,13,14,15]); + +} + +@safe pure unittest +{ + import std.uuid; + + auto id = UUID("8AB3060E-2cba-4f23-b74c-b52db3bdfb46"); + assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, + 181, 45, 179, 189, 251, 70]); + assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); + + //Can also be used in CTFE, for example as UUID literals: + enum ctfeID = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); + //here parsing is done at compile time, no runtime overhead! + +} + +@safe pure unittest +{ + import std.uuid; + + UUID id; + assert(id.empty); + id = UUID("00000000-0000-0000-0000-000000000001"); + assert(!id.empty); + +} + +@safe pure unittest +{ + import std.uuid; + + assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").variant + == UUID.Variant.rfc4122); + +} + +@safe unittest +{ + import std.uuid; + + assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").uuidVersion + == UUID.Version.randomNumberBased); + +} + +@safe unittest +{ + import std.uuid; + + immutable ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; + UUID u1; + UUID u2 = UUID(data); + u1.swap(u2); + + assert(u1 == UUID(data)); + assert(u2 == UUID.init); + +} + +@safe pure unittest +{ + import std.uuid; + + //compare UUIDs + assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init); + + //UUIDs in associative arrays: + int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1, + UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2, + UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3]; + + assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3); + + //UUIDS can be sorted: + import std.algorithm; + UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"), + UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"), + UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")]; + sort(ids); + +} + +@safe pure unittest +{ + import std.uuid; + + immutable str = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"; + auto id = UUID(str); + assert(id.toString() == str); + +} + +@safe unittest +{ + import std.uuid; + + UUID id; + assert(id.empty); + + id = randomUUID; + assert(!id.empty); + + id = UUID(cast(ubyte[16]) [138, 179, 6, 14, 44, 186, 79, + 35, 183, 76, 181, 45, 179, 189, 251, 70]); + assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); +} + +@safe unittest +{ + import std.uuid; + + //Use default UUID.init namespace + auto simpleID = md5UUID("test.uuid.any.string"); + + //use a name-based id as namespace + auto namespace = md5UUID("my.app"); + auto id = md5UUID("some-description", namespace); +} + +@safe unittest +{ + import std.uuid; + + //Use default UUID.init namespace + auto simpleID = sha1UUID("test.uuid.any.string"); + + //use a name-based id as namespace + auto namespace = sha1UUID("my.app"); + auto id = sha1UUID("some-description", namespace); +} + +@safe unittest +{ + import std.uuid; + + import std.random : Xorshift192, unpredictableSeed; + + //simple call + auto uuid = randomUUID(); + + //provide a custom RNG. Must be seeded manually. + Xorshift192 gen; + + gen.seed(unpredictableSeed); + auto uuid3 = randomUUID(gen); +} + +@safe unittest +{ + import std.uuid; + + auto id = parseUUID("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46"); + //no dashes + id = parseUUID("8ab3060e2cba4f23b74cb52db3bdfb46"); + //dashes at different positions + id = parseUUID("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46"); + //leading / trailing characters + id = parseUUID("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}"); + //unicode + id = parseUUID("ü8ab3060e2cba4f23b74cb52db3bdfb46ü"); + //multiple trailing/leading characters + id = parseUUID("///8ab3060e2cba4f23b74cb52db3bdfb46||"); + + //Can also be used in CTFE, for example as UUID literals: + enum ctfeID = parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); + //here parsing is done at compile time, no runtime overhead! +} + +@safe unittest +{ + import std.uuid; + + import std.algorithm; + import std.regex; + + string test = "Lorem ipsum dolor sit amet, consetetur "~ + "6ba7b814-9dad-11d1-80b4-00c04fd430c8 sadipscing \n"~ + "elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore \r\n"~ + "magna aliquyam erat, sed diam voluptua. "~ + "8ab3060e-2cba-4f23-b74c-b52db3bdfb46 At vero eos et accusam et "~ + "justo duo dolores et ea rebum."; + + auto r = regex(uuidRegex, "g"); + UUID[] found; + foreach (c; match(test, r)) + { + found ~= UUID(c.hit); + } + assert(found == [ + UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8"), + UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"), + ]); +} + +@safe unittest +{ + import std.uuid; + + import std.exception : collectException; + + const inputUUID = "this-is-an-invalid-uuid"; + auto ex = collectException!UUIDParsingException(UUID(inputUUID)); + assert(ex !is null); // check that exception was thrown + assert(ex.input == inputUUID); + assert(ex.position == 0); + assert(ex.reason == UUIDParsingException.Reason.tooLittle); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_variant.d b/libphobos/testsuite/libphobos.phobos/std_variant.d new file mode 100644 index 0000000000000000000000000000000000000000..374dd7852aa71b762b0f2e7fbf6483732a9f7b19 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_variant.d @@ -0,0 +1,291 @@ +@system unittest +{ + import std.variant; + + Variant a; // Must assign before use, otherwise exception ensues + // Initialize with an integer; make the type int + Variant b = 42; + assert(b.type == typeid(int)); + // Peek at the value + assert(b.peek!(int) !is null && *b.peek!(int) == 42); + // Automatically convert per language rules + auto x = b.get!(real); + + // Assign any other type, including other variants + a = b; + a = 3.14; + assert(a.type == typeid(double)); + // Implicit conversions work just as with built-in types + assert(a < b); + // Check for convertibility + assert(!a.convertsTo!(int)); // double not convertible to int + // Strings and all other arrays are supported + a = "now I'm a string"; + assert(a == "now I'm a string"); + + // can also assign arrays + a = new int[42]; + assert(a.length == 42); + a[5] = 7; + assert(a[5] == 7); + + // Can also assign class values + class Foo {} + auto foo = new Foo; + a = foo; + assert(*a.peek!(Foo) == foo); // and full type information is preserved +} + +@safe unittest +{ + import std.variant; + + struct Cat { int a, b, c; } + + align(1) struct S + { + long l; + ubyte b; + } + + align(1) struct T + { + ubyte b; + long l; + } + + static assert(maxSize!(int, long) == 8); + static assert(maxSize!(bool, byte) == 1); + static assert(maxSize!(bool, Cat) == 12); + static assert(maxSize!(char) == 1); + static assert(maxSize!(char, short, ubyte) == 2); + static assert(maxSize!(char, long, ubyte) == 8); + import std.algorithm.comparison : max; + static assert(maxSize!(long, S) == max(long.sizeof, S.sizeof)); + static assert(maxSize!(S, T) == max(S.sizeof, T.sizeof)); + static assert(maxSize!(int, ubyte[7]) == 7); + static assert(maxSize!(int, ubyte[3]) == 4); + static assert(maxSize!(int, int, ubyte[3]) == 4); + static assert(maxSize!(void, int, ubyte[3]) == 4); + static assert(maxSize!(void) == 1); +} + +@system unittest +{ + import std.variant; + + alias Var = VariantN!(maxSize!(int, double, string)); + + Var a; // Must assign before use, otherwise exception ensues + // Initialize with an integer; make the type int + Var b = 42; + assert(b.type == typeid(int)); + // Peek at the value + assert(b.peek!(int) !is null && *b.peek!(int) == 42); + // Automatically convert per language rules + auto x = b.get!(real); + + // Assign any other type, including other variants + a = b; + a = 3.14; + assert(a.type == typeid(double)); + // Implicit conversions work just as with built-in types + assert(a < b); + // Check for convertibility + assert(!a.convertsTo!(int)); // double not convertible to int + // Strings and all other arrays are supported + a = "now I'm a string"; + assert(a == "now I'm a string"); +} + +@system unittest +{ + import std.variant; + + alias Var = VariantN!(maxSize!(int[])); + + Var a = new int[42]; + assert(a.length == 42); + a[5] = 7; + assert(a[5] == 7); +} + +@system unittest +{ + import std.variant; + + alias Var = VariantN!(maxSize!(int*)); // classes are pointers + Var a; + + class Foo {} + auto foo = new Foo; + a = foo; + assert(*a.peek!(Foo) == foo); // and full type information is preserved +} + +@system unittest +{ + import std.variant; + + auto v = Algebraic!(int, double, string)(5); + assert(v.peek!(int)); + v = 3.14; + assert(v.peek!(double)); + // auto x = v.peek!(long); // won't compile, type long not allowed + // v = '1'; // won't compile, type char not allowed +} + +@system unittest +{ + import std.variant; + + import std.typecons : Tuple, tuple; + + // A tree is either a leaf or a branch of two other trees + alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*)); + Tree!int tree = tuple(new Tree!int(42), new Tree!int(43)); + Tree!int* right = tree.get!1[1]; + assert(*right == 43); + + // An object is a double, a string, or a hash of objects + alias Obj = Algebraic!(double, string, This[string]); + Obj obj = "hello"; + assert(obj.get!1 == "hello"); + obj = 42.0; + assert(obj.get!0 == 42); + obj = ["customer": Obj("John"), "paid": Obj(23.95)]; + assert(obj.get!2["customer"] == "John"); +} + +@system unittest +{ + import std.variant; + + Variant a; // Must assign before use, otherwise exception ensues + // Initialize with an integer; make the type int + Variant b = 42; + assert(b.type == typeid(int)); + // Peek at the value + assert(b.peek!(int) !is null && *b.peek!(int) == 42); + // Automatically convert per language rules + auto x = b.get!(real); + + // Assign any other type, including other variants + a = b; + a = 3.14; + assert(a.type == typeid(double)); + // Implicit conversions work just as with built-in types + assert(a < b); + // Check for convertibility + assert(!a.convertsTo!(int)); // double not convertible to int + // Strings and all other arrays are supported + a = "now I'm a string"; + assert(a == "now I'm a string"); +} + +@system unittest +{ + import std.variant; + + Variant a = new int[42]; + assert(a.length == 42); + a[5] = 7; + assert(a[5] == 7); +} + +@system unittest +{ + import std.variant; + + Variant a; + + class Foo {} + auto foo = new Foo; + a = foo; + assert(*a.peek!(Foo) == foo); // and full type information is preserved +} + +@system unittest +{ + import std.variant; + + auto a = variantArray(1, 3.14, "Hi!"); + assert(a[1] == 3.14); + auto b = Variant(a); // variant array as variant + assert(b[1] == 3.14); +} + +@system unittest +{ + import std.variant; + + import std.exception : assertThrown; + + Variant v; + + // uninitialized use + assertThrown!VariantException(v + 1); + assertThrown!VariantException(v.length); + + // .get with an incompatible target type + assertThrown!VariantException(Variant("a").get!int); + + // comparison between incompatible types + assertThrown!VariantException(Variant(3) < Variant("a")); +} + +@system unittest +{ + import std.variant; + + Algebraic!(int, string) variant; + + variant = 10; + assert(variant.visit!((string s) => cast(int) s.length, + (int i) => i)() + == 10); + variant = "string"; + assert(variant.visit!((int i) => i, + (string s) => cast(int) s.length)() + == 6); + + // Error function usage + Algebraic!(int, string) emptyVar; + auto rslt = emptyVar.visit!((string s) => cast(int) s.length, + (int i) => i, + () => -1)(); + assert(rslt == -1); + + // Generic function usage + Algebraic!(int, float, real) number = 2; + assert(number.visit!(x => x += 1) == 3); + + // Generic function for int/float with separate behavior for string + Algebraic!(int, float, string) something = 2; + assert(something.visit!((string s) => s.length, x => x) == 2); // generic + something = "asdf"; + assert(something.visit!((string s) => s.length, x => x) == 4); // string + + // Generic handler and empty handler + Algebraic!(int, float, real) empty2; + assert(empty2.visit!(x => x + 1, () => -1) == -1); +} + +@system unittest +{ + import std.variant; + + Algebraic!(int, string) variant; + + variant = 10; + auto which = -1; + variant.tryVisit!((int i) { which = 0; })(); + assert(which == 0); + + // Error function usage + variant = "test"; + variant.tryVisit!((int i) { which = 0; }, + () { which = -100; })(); + assert(which == -100); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_zlib.d b/libphobos/testsuite/libphobos.phobos/std_zlib.d new file mode 100644 index 0000000000000000000000000000000000000000..3cc9462b68980dbdff4b0b6aad02227683fdc135 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_zlib.d @@ -0,0 +1,29 @@ +@system unittest +{ + import std.zlib; + + static ubyte[] data = [1,2,3,4,5,6,7,8,9,10]; + + uint adler = adler32(0u, data); + assert(adler == 0xdc0037); +} + +@system unittest +{ + import std.zlib; + + // some random data + ubyte[1024] originalData = void; + + // append garbage data (or don't, this works in both cases) + auto compressedData = cast(ubyte[]) compress(originalData) ~ cast(ubyte[]) "whatever"; + + auto decompressor = new UnCompress(); + auto uncompressedData = decompressor.uncompress(compressedData); + + assert(uncompressedData[] == originalData[], + "The uncompressed and the original data differ"); + assert(decompressor.empty, "The UnCompressor reports not being done"); + +} +