libphobos: Generate test files for phobos testsuite

Extracts all public unittests from libphobos/src and emits them as
standalone tests in the testsuite using the tests_extractor script.

Compiling every module in the Phobos library with unittests included is
computationally expensive, and these tests are now only ran when
GCC_TEST_RUN_EXPENSIVE is not empty.

When instead just compiling the unittests and linking in the module
under test, this has been observed to reduce the time spent running the
testsuite by more than half.

libphobos/ChangeLog:

	* testsuite/libphobos.phobos/shared/phobos-shared.exp: Require
	is-effective-target run_expensive_tests.
	* testsuite/libphobos.phobos/static/phobos-static.exp: Likewise.
	* testsuite/libphobos.phobos/phobos.exp: New test.
	* testsuite/libphobos.phobos/std_algorithm_comparison.d: New test.
	* testsuite/libphobos.phobos/std_algorithm_iteration.d: New test.
	* testsuite/libphobos.phobos/std_algorithm_mutation.d: New test.
	* testsuite/libphobos.phobos/std_algorithm_searching.d: New test.
	* testsuite/libphobos.phobos/std_algorithm_setops.d: New test.
	* testsuite/libphobos.phobos/std_algorithm_sorting.d: New test.
	* testsuite/libphobos.phobos/std_array.d: New test.
	* testsuite/libphobos.phobos/std_ascii.d: New test.
	* testsuite/libphobos.phobos/std_base64.d: New test.
	* testsuite/libphobos.phobos/std_bigint.d: New test.
	* testsuite/libphobos.phobos/std_bitmanip.d: New test.
	* testsuite/libphobos.phobos/std_checkedint.d: New test.
	* testsuite/libphobos.phobos/std_complex.d: New test.
	* testsuite/libphobos.phobos/std_concurrency.d: New test.
	* testsuite/libphobos.phobos/std_container_array.d: New test.
	* testsuite/libphobos.phobos/std_container_binaryheap.d: New test.
	* testsuite/libphobos.phobos/std_container_dlist.d: New test.
	* testsuite/libphobos.phobos/std_container_rbtree.d: New test.
	* testsuite/libphobos.phobos/std_container_slist.d: New test.
	* testsuite/libphobos.phobos/std_container_util.d: New test.
	* testsuite/libphobos.phobos/std_conv.d: New test.
	* testsuite/libphobos.phobos/std_csv.d: New test.
	* testsuite/libphobos.phobos/std_datetime_date.d: New test.
	* testsuite/libphobos.phobos/std_datetime_interval.d: New test.
	* testsuite/libphobos.phobos/std_datetime_package.d: New test.
	* testsuite/libphobos.phobos/std_datetime_stopwatch.d: New test.
	* testsuite/libphobos.phobos/std_datetime_systime.d: New test.
	* testsuite/libphobos.phobos/std_datetime_timezone.d: New test.
	* testsuite/libphobos.phobos/std_demangle.d: New test.
	* testsuite/libphobos.phobos/std_digest_crc.d: New test.
	* testsuite/libphobos.phobos/std_digest_hmac.d: New test.
	* testsuite/libphobos.phobos/std_digest_md.d: New test.
	* testsuite/libphobos.phobos/std_digest_murmurhash.d: New test.
	* testsuite/libphobos.phobos/std_digest_package.d: New test.
	* testsuite/libphobos.phobos/std_digest_ripemd.d: New test.
	* testsuite/libphobos.phobos/std_digest_sha.d: New test.
	* testsuite/libphobos.phobos/std_encoding.d: New test.
	* testsuite/libphobos.phobos/std_exception.d: New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_affix_allocator.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_aligned_block_list.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_allocator_list.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_ascending_page_allocator.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bitmapped_block.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bucketizer.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_fallback_allocator.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_free_list.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_kernighan_ritchie.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_quantizer.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_region.d: New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_scoped_allocator.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_segregator.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_stats_collector.d:
	New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_common.d: New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_gc_allocator.d: New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_mallocator.d: New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_package.d: New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_showcase.d: New test.
	* testsuite/libphobos.phobos/std_experimental_allocator_typed.d: New test.
	* testsuite/libphobos.phobos/std_file.d: New test.
	* testsuite/libphobos.phobos/std_format_package.d: New test.
	* testsuite/libphobos.phobos/std_format_read.d: New test.
	* testsuite/libphobos.phobos/std_format_spec.d: New test.
	* testsuite/libphobos.phobos/std_format_write.d: New test.
	* testsuite/libphobos.phobos/std_functional.d: New test.
	* testsuite/libphobos.phobos/std_getopt.d: New test.
	* testsuite/libphobos.phobos/std_int128.d: New test.
	* testsuite/libphobos.phobos/std_internal_cstring.d: New test.
	* testsuite/libphobos.phobos/std_internal_scopebuffer.d: New test.
	* testsuite/libphobos.phobos/std_json.d: New test.
	* testsuite/libphobos.phobos/std_logger_core.d: New test.
	* testsuite/libphobos.phobos/std_logger_nulllogger.d: New test.
	* testsuite/libphobos.phobos/std_math_algebraic.d: New test.
	* testsuite/libphobos.phobos/std_math_exponential.d: New test.
	* testsuite/libphobos.phobos/std_math_hardware.d: New test.
	* testsuite/libphobos.phobos/std_math_operations.d: New test.
	* testsuite/libphobos.phobos/std_math_remainder.d: New test.
	* testsuite/libphobos.phobos/std_math_rounding.d: New test.
	* testsuite/libphobos.phobos/std_math_traits.d: New test.
	* testsuite/libphobos.phobos/std_math_trigonometry.d: New test.
	* testsuite/libphobos.phobos/std_meta.d: New test.
	* testsuite/libphobos.phobos/std_mmfile.d: New test.
	* testsuite/libphobos.phobos/std_numeric.d: New test.
	* testsuite/libphobos.phobos/std_outbuffer.d: New test.
	* testsuite/libphobos.phobos/std_package.d: New test.
	* testsuite/libphobos.phobos/std_parallelism.d: New test.
	* testsuite/libphobos.phobos/std_path.d: New test.
	* testsuite/libphobos.phobos/std_random.d: New test.
	* testsuite/libphobos.phobos/std_range_interfaces.d: New test.
	* testsuite/libphobos.phobos/std_range_package.d: New test.
	* testsuite/libphobos.phobos/std_range_primitives.d: New test.
	* testsuite/libphobos.phobos/std_regex_package.d: New test.
	* testsuite/libphobos.phobos/std_signals.d: New test.
	* testsuite/libphobos.phobos/std_socket.d: New test.
	* testsuite/libphobos.phobos/std_stdio.d: New test.
	* testsuite/libphobos.phobos/std_string.d: New test.
	* testsuite/libphobos.phobos/std_sumtype.d: New test.
	* testsuite/libphobos.phobos/std_traits.d: New test.
	* testsuite/libphobos.phobos/std_typecons.d: New test.
	* testsuite/libphobos.phobos/std_typetuple.d: New test.
	* testsuite/libphobos.phobos/std_uni_package.d: New test.
	* testsuite/libphobos.phobos/std_uri.d: New test.
	* testsuite/libphobos.phobos/std_utf.d: New test.
	* testsuite/libphobos.phobos/std_uuid.d: New test.
	* testsuite/libphobos.phobos/std_variant.d: New test.
	* testsuite/libphobos.phobos/std_zlib.d: New test.
This commit is contained in:
Iain Buclaw 2025-02-25 21:01:23 +01:00
parent ff43f9853d
commit c2ece13931
108 changed files with 29861 additions and 0 deletions

View file

@ -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

View file

@ -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"]]]

View file

@ -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"]]]

View file

@ -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")));
}

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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('á') == 'á');
}

View file

@ -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"));
}

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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"));
}

View file

@ -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");
}

View file

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

View file

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

View file

@ -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");
}

View file

@ -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
}

View file

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

View file

@ -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");
}
}

View file

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

View file

@ -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)
}

View file

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

View file

@ -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");
}

View file

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

View file

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

View file

@ -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");
}

View file

@ -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");
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
//...
}

View file

@ -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);
//...
}

View file

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

View file

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

View file

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

View file

@ -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"));
}

View file

@ -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"));
}

View file

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

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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"]));
}

View file

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

View file

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

View file

@ -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.
}

View file

@ -0,0 +1,9 @@
@system unittest
{
import std.internal.scopebuffer;
ubyte[10] tmpbuf = void;
auto sb = scopeBuffer(tmpbuf);
scope(exit) sb.free();
}

View file

@ -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}`)));
}

View file

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

View file

@ -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");
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;");
}

View file

@ -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");
}

View file

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

View file

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

View file

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

View file

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

View file

@ -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");
}
}

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -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\*`));
}

View file

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

View file

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

View file

@ -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.");
}
}

View file

@ -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");
}

View file

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

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more