From b8fa670c5a1e6e856ced5d1be7f04360e91e0c7d Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 25 Aug 2025 16:09:03 +0200 Subject: Merge os, middle and meta subpackages --- dub.json | 8 +- meta/dub.json | 13 - meta/tanya/meta/metafunction.d | 1662 --------------------------------- meta/tanya/meta/package.d | 22 - meta/tanya/meta/trait.d | 150 --- middle/dub.json | 5 - middle/tanya/memory/allocator.d | 4 +- middle/tanya/memory/lifetime.d | 7 +- middle/tanya/memory/smartref.d | 4 +- middle/tanya/meta.d | 920 ++++++++++++++++++ middle/tanya/os/error.d | 413 ++++++++ middle/tanya/os/package.d | 18 + os/dub.json | 17 - os/tanya/os/error.d | 413 -------- os/tanya/os/package.d | 18 - source/tanya/algorithm/iteration.d | 4 +- source/tanya/algorithm/mutation.d | 5 +- source/tanya/container/array.d | 4 +- source/tanya/container/buffer.d | 2 +- source/tanya/container/entry.d | 4 +- source/tanya/container/hashtable.d | 4 +- source/tanya/container/list.d | 4 +- source/tanya/container/set.d | 4 +- source/tanya/container/string.d | 4 +- source/tanya/conv.d | 5 +- source/tanya/format.d | 9 +- source/tanya/hash/lookup.d | 4 +- source/tanya/math/package.d | 434 +-------- source/tanya/net/iface.d | 4 +- source/tanya/net/inet.d | 4 +- source/tanya/net/ip.d | 4 +- source/tanya/range/adapter.d | 4 +- source/tanya/range/primitive.d | 4 +- source/tanya/test/assertion.d | 106 +++ source/tanya/test/package.d | 18 + source/tanya/test/stub.d | 397 ++++++++ test/dub.json | 17 - test/tanya/test/assertion.d | 106 --- test/tanya/test/package.d | 18 - test/tanya/test/stub.d | 397 -------- tests/tanya/math/tests/package.d | 13 - tests/tanya/memory/tests/smartref.d | 4 +- tests/tanya/meta/tests/metafunction.d | 30 - 43 files changed, 1920 insertions(+), 3367 deletions(-) delete mode 100644 meta/dub.json delete mode 100644 meta/tanya/meta/metafunction.d delete mode 100644 meta/tanya/meta/package.d delete mode 100644 meta/tanya/meta/trait.d create mode 100644 middle/tanya/meta.d create mode 100644 middle/tanya/os/error.d create mode 100644 middle/tanya/os/package.d delete mode 100644 os/dub.json delete mode 100644 os/tanya/os/error.d delete mode 100644 os/tanya/os/package.d create mode 100644 source/tanya/test/assertion.d create mode 100644 source/tanya/test/package.d create mode 100644 source/tanya/test/stub.d delete mode 100644 test/dub.json delete mode 100644 test/tanya/test/assertion.d delete mode 100644 test/tanya/test/package.d delete mode 100644 test/tanya/test/stub.d delete mode 100644 tests/tanya/meta/tests/metafunction.d diff --git a/dub.json b/dub.json index 0584081..2d03969 100644 --- a/dub.json +++ b/dub.json @@ -10,18 +10,12 @@ "targetType": "library", "dependencies": { - "tanya:meta": "*", - "tanya:os": "*", "tanya:middle": "*", - "tanya:test": "*", "mir-linux-kernel": "~>1.0.0" }, "subPackages": [ - "./meta", - "./os", - "./middle", - "./test" + "./middle" ], "configurations": [ diff --git a/meta/dub.json b/meta/dub.json deleted file mode 100644 index 4b7651b..0000000 --- a/meta/dub.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "meta", - "description": "Template metaprogramming", - "targetType": "library", - - "sourcePaths": [ - "." - ], - "importPaths": [ - "." - ], - "dflags-dmd": ["-dip1000"] -} diff --git a/meta/tanya/meta/metafunction.d b/meta/tanya/meta/metafunction.d deleted file mode 100644 index ef4acfb..0000000 --- a/meta/tanya/meta/metafunction.d +++ /dev/null @@ -1,1662 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * This module is suited for computations on template arguments, both types and - * values at compile time. - * - * It contains different algorithms for iterating, searching and modifying - * template arguments. - * - * Copyright: Eugene Wissner 2017-2025. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/metafunction.d, - * tanya/meta/metafunction.d) - */ -module tanya.meta.metafunction; - -import std.traits : Unqual, isInstanceOf, isMutable, isTypeTuple, isUnsigned, isSigned, isIntegral; -import std.meta : NoDuplicates; -import tanya.meta.trait; - -/** - * Finds the minimum value in $(D_PARAM Args) according to $(D_PARAM pred). - * - * $(D_PARAM Args) should contain at least one element. - * - * $(D_PARAM pred) can evaluate to: - * $(UL - * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means - * $(D_INLINECODE Args[0] < Args[1]).) - * $(LI $(D_KEYWORD int): a negative number means that - * $(D_INLINECODE Args[0] < Args[1]), a positive number that - * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) - * ) - * - * Params: - * pred = Template predicate. - * Args = Elements for which you want to find the minimum value. - * - * Returns: The minimum. - * - * See_Also: $(D_PSYMBOL isLess). - */ -template Min(alias pred, Args...) -if (Args.length > 0 && __traits(isTemplate, pred)) -{ - static if (Args.length == 1) - { - alias Min = Alias!(Args[0]); - } - else static if (isLess!(pred, Args[1], Args[0])) - { - alias Min = Min!(pred, Args[1], Args[2 .. $]); - } - else - { - alias Min = Min!(pred, Args[0], Args[2 .. $]); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - enum bool cmp(alias T, alias U) = T < U; - static assert(Min!(cmp, 8, 4, 5, 3, 13) == 3); - static assert(Min!(cmp, 8) == 8); -} - -/** - * Finds the maximum value in $(D_PARAM Args) according to $(D_PARAM pred). - * - * $(D_PARAM Args) should contain at least one element. - * - * $(D_PARAM pred) can evaluate to: - * $(UL - * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means - * $(D_INLINECODE Args[0] < Args[1]).) - * $(LI $(D_KEYWORD int): a negative number means that - * $(D_INLINECODE Args[0] < Args[1]), a positive number that - * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) - * ) - * - * Params: - * pred = Template predicate. - * Args = Elements for which you want to find the maximum value. - * - * Returns: The maximum. - * - * See_Also: $(D_PSYMBOL isLess). - */ -template Max(alias pred, Args...) -if (Args.length > 0 && __traits(isTemplate, pred)) -{ - static if (Args.length == 1) - { - alias Max = Alias!(Args[0]); - } - else static if (isGreater!(pred, Args[1], Args[0])) - { - alias Max = Max!(pred, Args[1], Args[2 .. $]); - } - else - { - alias Max = Max!(pred, Args[0], Args[2 .. $]); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - enum bool cmp(alias T, alias U) = T < U; - static assert(Max!(cmp, 8, 4, 5, 3, 13) == 13); - static assert(Max!(cmp, 8) == 8); -} - -/** - * Zips one or more $(D_PSYMBOL Pack)s with $(D_PARAM f). - * - * Given $(D_PARAM f) and tuples t1, t2, ..., tk, where tk[i] denotes the - * $(I i)-th element of the tuple $(I k)-th tuple, $(D_PSYMBOL ZipWith) - * produces a sequence: - * - * --- - * f(t1[0], t2[0], ... tk[0]), - * f(t1[1], t2[1], ... tk[1]), - * ... - * f(tk[0], tk[1], ... tk[i]), - * --- - * - * $(D_PSYMBOL ZipWith) begins with the first elements from $(D_PARAM Packs) - * and applies $(D_PARAM f) to them, then it takes the second - * ones and does the same, and so on. - * - * If not all argument tuples have the same length, $(D_PSYMBOL ZipWith) will - * zip only `n` elements from each tuple, where `n` is the length of the - * shortest tuple in the argument list. Remaining elements in the longer tuples - * are just ignored. - * - * Params: - * f = Some template that can be applied to the elements of - * $(D_PARAM Packs). - * Packs = $(D_PSYMBOL Pack) instances. - * - * Returns: A sequence, whose $(I i)-th element contains the $(I i)-th element - * from each of the $(D_PARAM Packs). - */ -template ZipWith(alias f, Packs...) -if (Packs.length > 0 - && __traits(isTemplate, f) - && (allSatisfy!(ApplyLeft!(isInstanceOf, Pack), Packs) - || allSatisfy!(ApplyLeft!(isInstanceOf, Tuple), Packs))) -{ - private template GetIth(size_t i, Args...) - { - static if ((Args.length == 0) || (Args[0].Seq.length <= i)) - { - alias GetIth = AliasSeq!(); - } - else - { - alias GetIth = AliasSeq!(Args[0].Seq[i], GetIth!(i, Args[1 .. $])); - } - } - private template Iterate(size_t i, Args...) - { - alias Pack = GetIth!(i, Args); - - static if (Pack.length < Packs.length) - { - alias Iterate = AliasSeq!(); - } - else - { - alias Iterate = AliasSeq!(f!Pack, Iterate!(i + 1, Args)); - } - } - alias ZipWith = Iterate!(0, Packs); -} - -/// -@nogc nothrow pure @safe unittest -{ - alias Result1 = ZipWith!(AliasSeq, Pack!(1, 2), Pack!(5, 6), Pack!(9, 10)); - static assert(Result1 == AliasSeq!(1, 5, 9, 2, 6, 10)); - - alias Result2 = ZipWith!(AliasSeq, Pack!(1, 2, 3), Pack!(4, 5)); - static assert(Result2 == AliasSeq!(1, 4, 2, 5)); - - alias Result3 = ZipWith!(AliasSeq, Pack!(), Pack!(4, 5)); - static assert(Result3.length == 0); -} - -/** - * Holds a typed sequence of template parameters. - * - * Different than $(D_PSYMBOL AliasSeq), $(D_PSYMBOL Pack) doesn't unpack - * its template parameters automatically. Consider: - * - * --- - * template A(Args...) - * { - * static assert(Args.length == 4); - * } - * - * alias AInstance = A!(AliasSeq!(int, uint), AliasSeq!(float, double)); - * --- - * - * Using $(D_PSYMBOL AliasSeq) template `A` gets 4 parameters instead of 2, - * because $(D_PSYMBOL AliasSeq) is just an alias for its template parameters. - * - * With $(D_PSYMBOL Pack) it is possible to pass distinguishable - * sequences of parameters to a template. So: - * - * --- - * template B(Args...) - * { - * static assert(Args.length == 2); - * } - * - * alias BInstance = B!(Pack!(int, uint), Pack!(float, double)); - * --- - * - * Params: - * Args = Elements of this $(D_PSYMBOL Pack). - * - * See_Also: $(D_PSYMBOL AliasSeq). - */ -struct Pack(Args...) -{ - /// Elements in this tuple as $(D_PSYMBOL AliasSeq). - alias Seq = Args; - - /// The length of the tuple. - enum size_t length = Args.length; - - alias Seq this; -} - -/// -@nogc nothrow pure @safe unittest -{ - alias A = Pack!short; - alias B = Pack!(3, 8, 9); - alias C = Pack!(A, B); - - static assert(C.length == 2); - - static assert(A.length == 1); - static assert(is(A.Seq == AliasSeq!short)); - static assert(B.length == 3); - static assert(B.Seq == AliasSeq!(3, 8, 9)); - - alias D = Pack!(); - static assert(D.length == 0); - static assert(is(D.Seq == AliasSeq!())); -} - -/** - * Unordered sequence of unique aliases. - * - * $(D_PARAM Args) can contain duplicates, but they will be filtered out, so - * $(D_PSYMBOL Set) contains only unique items. $(D_PSYMBOL isEqual) is used - * for determining if two items are equal. - * - * Params: - * Args = Elements of this $(D_PSYMBOL Set). - */ -struct Set(Args...) -{ - /// Elements in this set as $(D_PSYMBOL AliasSeq). - alias Seq = NoDuplicates!Args; - - /// The length of the set. - enum size_t length = Seq.length; - - alias Seq this; -} - -/// -@nogc nothrow pure @safe unittest -{ - alias S1 = Set!(int, 5, 5, int, 4); - static assert(S1.length == 3); -} - -/** - * Produces a $(D_PSYMBOL Set) containing all elements of the given - * $(D_PARAM Sets). - * - * Params: - * Sets = List of $(D_PSYMBOL Set) instances. - * - * Returns: Set-theoretic union of all $(D_PARAM Sets). - * - * See_Also: $(D_PSYMBOL Set). - */ -template Union(Sets...) -if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets)) -{ - private template Impl(Sets...) - { - static if (Sets.length == 0) - { - alias Impl = AliasSeq!(); - } - else - { - alias Impl = AliasSeq!(Sets[0].Seq, Impl!(Sets[1 .. $])); - } - } - alias Union = Set!(Impl!Sets); -} - -/// -@nogc nothrow pure @safe unittest -{ - alias S1 = Set!(2, 5, 8, 4); - alias S2 = Set!(3, 8, 4, 1); - static assert(Union!(S1, S2).Seq == AliasSeq!(2, 5, 8, 4, 3, 1)); -} - -/** - * Produces a $(D_PSYMBOL Set) that containing elements of - * $(D_INLINECODE Sets[0]) that are also elements of all other sets in - * $(D_PARAM Sets). - * - * Params: - * Sets = List of $(D_PSYMBOL Set) instances. - * - * Returns: Set-theoretic intersection of all $(D_PARAM Sets). - * - * See_Also: $(D_PSYMBOL Set). - */ -template Intersection(Sets...) -if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets)) -{ - private template Impl(Args...) - if (Args.length > 0) - { - alias Equal = ApplyLeft!(isEqual, Args[0]); - static if (Args.length == 1) - { - enum bool Impl = true; - } - else static if (!anySatisfy!(Equal, Args[1].Seq)) - { - enum bool Impl = false; - } - else - { - enum bool Impl = Impl!(Args[0], Args[2 .. $]); - } - } - - private enum bool FilterImpl(Args...) = Impl!(Args[0], Sets[1 .. $]); - - static if (Sets.length == 0) - { - alias Intersection = Set!(); - } - else - { - alias Intersection = Set!(Filter!(FilterImpl, Sets[0].Seq)); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - alias S1 = Set!(2, 5, 8, 4); - alias S2 = Set!(3, 8, 4, 1); - static assert(Intersection!(S1, S2).Seq == AliasSeq!(8, 4)); - - static assert(Intersection!(S1).Seq == AliasSeq!(2, 5, 8, 4)); - static assert(Intersection!().length == 0); -} - -/** - * Produces a $(D_PSYMBOL Set) that contains all elements of - * $(D_PARAM S1) that are not members of $(D_PARAM S2). - * - * Params: - * S1 = A $(D_PSYMBOL Set). - * S2 = A $(D_PSYMBOL Set). - * - * Returns: Set-theoretic difference of two sets $(D_PARAM S1) and - * $(D_PARAM S2). - * - * See_Also: $(D_PSYMBOL Set). - */ -template Difference(alias S1, alias S2) -if (isInstanceOf!(Set, S1) && isInstanceOf!(Set, S2)) -{ - private template Impl(Args...) - { - alias Equal = ApplyLeft!(isEqual, Args[0]); - enum bool Impl = !anySatisfy!(Equal, S2.Seq); - } - - static if (S1.length == 0) - { - alias Difference = Set!(); - } - else static if (S2.length == 1) - { - alias Difference = S1; - } - else - { - alias Difference = Set!(Filter!(Impl, S1.Seq)); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - alias S1 = Set!(2, 5, 8, 4); - alias S2 = Set!(3, 8, 4, 1); - static assert(Difference!(S1, S2).Seq == AliasSeq!(2, 5)); - static assert(Difference!(S2, S1).Seq == AliasSeq!(3, 1)); - static assert(Difference!(S1, Set!()).Seq == AliasSeq!(2, 5, 8, 4)); -} - -/** - * Tests whether $(D_INLINECODE Args[0]) is less than or equal to - * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). - * - * $(D_PARAM cmp) can evaluate to: - * $(UL - * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means - * $(D_INLINECODE Args[0] < Args[1]).) - * $(LI $(D_KEYWORD int): a negative number means that - * $(D_INLINECODE Args[0] < Args[1]), a positive number that - * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) - * ) - * - * Params: - * Args = Two aliases to compare for equality. - * - * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is less than or equal - * to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. - */ -template isLessEqual(alias cmp, Args...) -if (Args.length == 2 && __traits(isTemplate, cmp)) -{ - private enum result = cmp!(Args[1], Args[0]); - static if (is(typeof(result) == bool)) - { - enum bool isLessEqual = !result; - } - else - { - enum bool isLessEqual = result >= 0; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - enum bool boolCmp(T, U) = T.sizeof < U.sizeof; - static assert(isLessEqual!(boolCmp, byte, int)); - static assert(isLessEqual!(boolCmp, uint, int)); - static assert(!isLessEqual!(boolCmp, long, int)); - - enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; - static assert(isLessEqual!(intCmp, byte, int)); - static assert(isLessEqual!(intCmp, uint, int)); - static assert(!isLessEqual!(intCmp, long, int)); -} - -/** - * Tests whether $(D_INLINECODE Args[0]) is greater than or equal to - * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). - * - * $(D_PARAM cmp) can evaluate to: - * $(UL - * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means - * $(D_INLINECODE Args[0] < Args[1]).) - * $(LI $(D_KEYWORD int): a negative number means that - * $(D_INLINECODE Args[0] < Args[1]), a positive number that - * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) - * ) - * - * Params: - * Args = Two aliases to compare for equality. - * - * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is greater than or - * equal to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. - */ -template isGreaterEqual(alias cmp, Args...) -if (Args.length == 2 && __traits(isTemplate, cmp)) -{ - private enum result = cmp!Args; - static if (is(typeof(result) == bool)) - { - enum bool isGreaterEqual = !result; - } - else - { - enum bool isGreaterEqual = result >= 0; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - enum bool boolCmp(T, U) = T.sizeof < U.sizeof; - static assert(!isGreaterEqual!(boolCmp, byte, int)); - static assert(isGreaterEqual!(boolCmp, uint, int)); - static assert(isGreaterEqual!(boolCmp, long, int)); - - enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; - static assert(!isGreaterEqual!(intCmp, byte, int)); - static assert(isGreaterEqual!(intCmp, uint, int)); - static assert(isGreaterEqual!(intCmp, long, int)); -} - -/** - * Tests whether $(D_INLINECODE Args[0]) is less than - * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). - * - * $(D_PARAM cmp) can evaluate to: - * $(UL - * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means - * $(D_INLINECODE Args[0] < Args[1]).) - * $(LI $(D_KEYWORD int): a negative number means that - * $(D_INLINECODE Args[0] < Args[1]), a positive number that - * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) - * ) - * - * Params: - * Args = Two aliases to compare for equality. - * - * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is less than - * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. - */ -template isLess(alias cmp, Args...) -if (Args.length == 2 && __traits(isTemplate, cmp)) -{ - private enum result = cmp!Args; - static if (is(typeof(result) == bool)) - { - enum bool isLess = result; - } - else - { - enum bool isLess = result < 0; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - enum bool boolCmp(T, U) = T.sizeof < U.sizeof; - static assert(isLess!(boolCmp, byte, int)); - static assert(!isLess!(boolCmp, uint, int)); - static assert(!isLess!(boolCmp, long, int)); - - enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; - static assert(isLess!(intCmp, byte, int)); - static assert(!isLess!(intCmp, uint, int)); - static assert(!isLess!(intCmp, long, int)); -} - -/** - * Tests whether $(D_INLINECODE Args[0]) is greater than - * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). - * - * $(D_PARAM cmp) can evaluate to: - * $(UL - * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means - * $(D_INLINECODE Args[0] < Args[1]).) - * $(LI $(D_KEYWORD int): a negative number means that - * $(D_INLINECODE Args[0] < Args[1]), a positive number that - * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) - * ) - * - * Params: - * Args = Two aliases to compare for equality. - * - * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is greater than - * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. - */ -template isGreater(alias cmp, Args...) -if (Args.length == 2 && __traits(isTemplate, cmp)) -{ - private enum result = cmp!Args; - static if (is(typeof(result) == bool)) - { - enum bool isGreater = !result && cmp!(Args[1], Args[0]); - } - else - { - enum bool isGreater = result > 0; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - enum bool boolCmp(T, U) = T.sizeof < U.sizeof; - static assert(!isGreater!(boolCmp, byte, int)); - static assert(!isGreater!(boolCmp, uint, int)); - static assert(isGreater!(boolCmp, long, int)); - - enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; - static assert(!isGreater!(intCmp, byte, int)); - static assert(!isGreater!(intCmp, uint, int)); - static assert(isGreater!(intCmp, long, int)); -} - -/** - * Tests whether $(D_INLINECODE Args[0]) is equal to $(D_INLINECODE Args[1]). - * - * $(D_PSYMBOL isEqual) checks first if $(D_PARAM Args) can be compared directly. If not, they are compared as types: - * $(D_INLINECODE is(Args[0] == Args[1])). It it fails, the arguments are - * considered to be not equal. - * - * If two items cannot be compared (for example comparing a type with a - * number), they are considered not equal. - * - * Params: - * Args = Two aliases to compare for equality. - * - * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is equal to - * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. - */ -template isEqual(Args...) -if (Args.length == 2) -{ - static if ((is(typeof(Args[0] == Args[1])) && (Args[0] == Args[1])) - || (isTypeTuple!Args && is(Args[0] == Args[1])) - || __traits(isSame, Args[0], Args[1])) - { - enum bool isEqual = true; - } - else - { - enum bool isEqual = false; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(isEqual!(int, int)); - static assert(isEqual!(8, 8)); - static assert(!isEqual!(int, const(int))); - static assert(!isEqual!(5, int)); - static assert(!isEqual!(5, 8)); -} - -/** - * Tests whether $(D_INLINECODE Args[0]) isn't equal to - * $(D_INLINECODE Args[1]). - * - * $(D_PSYMBOL isNotEqual) checks first if $(D_PARAM Args) can be compared directly. If not, they are compared as types: - * $(D_INLINECODE is(Args[0] == Args[1])). It it fails, the arguments are - * considered to be not equal. - * - * Params: - * Args = Two aliases to compare for equality. - * - * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) isn't equal to - * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. - */ -template isNotEqual(Args...) -if (Args.length == 2) -{ - enum bool isNotEqual = !isEqual!Args; -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(!isNotEqual!(int, int)); - static assert(isNotEqual!(5, int)); - static assert(isNotEqual!(5, 8)); -} - -/** - * Instantiates the template $(D_PARAM T) with $(D_PARAM Args). - * - * Params: - * T = Template. - * Args = Template parameters. - * - * Returns: Instantiated template. - */ -alias Instantiate(alias T, Args...) = T!Args; - -/// -@nogc nothrow pure @safe unittest -{ - template Template(T) - { - alias Template = T; - } - alias Seq = AliasSeq!(Template, Template); - - alias Instance1 = Instantiate!(Seq[0], int); - static assert(is(Instance1 == int)); - - alias Instance2 = Instantiate!(Seq[1], float); - static assert(is(Instance2 == float)); -} - -/** - * Creates an alias for $(D_PARAM T). - * - * In contrast to the $(D_KEYWORD alias)-keyword $(D_PSYMBOL Alias) can alias - * any kind of D symbol that can be used as argument to template alias - * parameters. - * - * $(UL - * $(LI Types) - * $(LI Local and global names) - * $(LI Module names) - * $(LI Template names) - * $(LI Template instance names) - * $(LI Literals) - * ) - * - * Params: - * T = A symbol. - * - * Returns: An alias for $(D_PARAM T). - * - * See_Also: $(LINK2 https://dlang.org/spec/template.html#aliasparameters, - * Template Alias Parameters). - */ -alias Alias(alias T) = T; - -/// ditto -alias Alias(T) = T; - -/// -@nogc nothrow pure @safe unittest -{ - static assert(is(Alias!int)); - - static assert(is(typeof(Alias!5))); - static assert(is(typeof(Alias!(() {})))); - - int i; - static assert(is(typeof(Alias!i))); -} - -/** - * Holds a sequence of aliases. - * - * $(D_PSYMBOL AliasSeq) can be used to pass multiple parameters to a template - * at once. $(D_PSYMBOL AliasSeq) behaves as it were just $(D_PARAM Args). Note - * that because of this property, if multiple instances of - * $(D_PSYMBOL AliasSeq) are passed to a template, they are not distinguishable - * from each other and act as a single sequence. There is also no way to make - * $(D_PSYMBOL AliasSeq) nested, it always unpacks its elements. - * - * Params: - * Args = Symbol sequence. - * - * Returns: An alias for sequence $(D_PARAM Args). - * - * See_Also: $(D_PSYMBOL Alias). - */ -alias AliasSeq(Args...) = Args; - -/// -@nogc nothrow pure @safe unittest -{ - static assert(is(typeof({ alias T = AliasSeq!(short, 5); }))); - static assert(is(typeof({ alias T = AliasSeq!(int, short, 5); }))); - static assert(is(typeof({ alias T = AliasSeq!(() {}, short, 5); }))); - static assert(is(typeof({ alias T = AliasSeq!(); }))); - - static assert(AliasSeq!().length == 0); - static assert(AliasSeq!(int, short, 5).length == 3); - - alias A = AliasSeq!(short, float); - alias B = AliasSeq!(ushort, double); - alias C = AliasSeq!(A, B); - static assert(C.length == 4); -} - -/** - * Tests whether all the items of $(D_PARAM L) satisfy the condition - * $(D_PARAM F). - * - * $(D_PARAM F) is a template that accepts one parameter and returns a boolean, - * so $(D_INLINECODE F!([0]) && F!([1])) and so on, can be called. - * - * Params: - * F = Template predicate. - * L = List of items to test. - * - * Returns: $(D_KEYWORD true) if all the items of $(D_PARAM L) satisfy - * $(D_PARAM F), $(D_KEYWORD false) otherwise. - */ -enum bool allSatisfy(alias F, L...) = Filter!(templateNot!F, L).length == 0; - -/// -@nogc nothrow pure @safe unittest -{ - static assert(allSatisfy!(isSigned, int, short, byte, long)); - static assert(!allSatisfy!(isUnsigned, uint, ushort, float, ulong)); -} - -/** - * Tests whether any of the items of $(D_PARAM L) satisfy the condition - * $(D_PARAM F). - * - * $(D_PARAM F) is a template that accepts one parameter and returns a boolean, - * so $(D_INLINECODE F!([0]) && F!([1])) and so on, can be called. - * - * Params: - * F = Template predicate. - * L = List of items to test. - * - * Returns: $(D_KEYWORD true) if any of the items of $(D_PARAM L) satisfy - * $(D_PARAM F), $(D_KEYWORD false) otherwise. - */ -enum bool anySatisfy(alias F, L...) = Filter!(F, L).length != 0; - -/// -@nogc nothrow pure @safe unittest -{ - static assert(anySatisfy!(isSigned, int, short, byte, long)); - static assert(anySatisfy!(isUnsigned, uint, ushort, float, ulong)); - static assert(!anySatisfy!(isSigned, uint, ushort, ulong)); -} - -private template indexOf(Args...) -{ - static foreach (i, Arg; Args[1 .. $]) - { - static if (!is(typeof(indexOf) == ptrdiff_t) && isEqual!(Args[0], Arg)) - { - enum ptrdiff_t indexOf = i; - } - } - static if (!is(typeof(indexOf) == ptrdiff_t)) - { - enum ptrdiff_t indexOf = -1; - } -} - -/** - * Returns the index of the first occurrence of $(D_PARAM T) in $(D_PARAM L). - * `-1` is returned if $(D_PARAM T) is not found. - * - * Params: - * T = The item to search for. - * L = Symbol sequence. - * - * Returns: The index of the first occurrence of $(D_PARAM T) in $(D_PARAM L). - */ -template staticIndexOf(T, L...) -{ - enum ptrdiff_t staticIndexOf = indexOf!(T, L); -} - -/// ditto -template staticIndexOf(alias T, L...) -{ - enum ptrdiff_t staticIndexOf = indexOf!(T, L); -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(staticIndexOf!(int) == -1); - static assert(staticIndexOf!(int, int) == 0); - static assert(staticIndexOf!(int, float, double, int, real) == 2); - static assert(staticIndexOf!(3, () {}, uint, 5, 3) == 3); -} - -/** - * Looks for $(D_PARAM T) in $(D_PARAM L) and returns $(D_KEYWORD true) if it - * could be found and $(D_KEYWORD false) otherwise. - * - * Params: - * T = The item to search for. - * L = Symbol sequence. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM T) can be found in $(D_PARAM L), - * $(D_KEYWORD false) otherwise. - */ -enum bool canFind(T, L...) = staticIndexOf!(T, L) != -1; - -/// ditto -enum bool canFind(alias T, L...) = staticIndexOf!(T, L) != -1; - -/// -@nogc nothrow pure @safe unittest -{ - static assert(!canFind!(int)); - static assert(canFind!(int, int)); - static assert(canFind!(int, float, double, int, real)); - static assert(canFind!(3, () {}, uint, 5, 3)); -} - -/* - * Tests whether $(D_PARAM T) is a template. - * - * $(D_PSYMBOL isTemplate) isn't $(D_KEYWORD true) for template instances, - * since the latter already represent some type. Only not instantiated - * templates, i.e. that accept some template parameters, are considered - * templates. - * - * Params: - * T = A symbol. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a template, - * $(D_KEYWORD false) otherwise. - */ -private enum bool isTemplate(alias T) = __traits(isTemplate, T); - -/// -@nogc nothrow pure @safe unittest -{ - static struct S(T) - { - } - static assert(isTemplate!S); - static assert(!isTemplate!(S!int)); -} - -/** - * Combines multiple templates with logical AND. So $(D_PSYMBOL templateAnd) - * evaluates to $(D_INLINECODE Preds[0] && Preds[1] && Preds[2]) and so on. - * - * Empty $(D_PARAM Preds) evaluates to $(D_KEYWORD true). - * - * Params: - * Preds = Template predicates. - * - * Returns: The constructed template. - */ -template templateAnd(Preds...) -if (allSatisfy!(isTemplate, Preds)) -{ - template templateAnd(T...) - { - static if (Preds.length == 0) - { - enum bool templateAnd = true; - } - else static if (Instantiate!(Preds[0], T)) - { - alias templateAnd = Instantiate!(.templateAnd!(Preds[1 .. $]), T); - } - else - { - enum bool templateAnd = false; - } - } -} - -/// -@nogc nothrow pure @safe unittest -{ - alias isMutableInt = templateAnd!(isIntegral, isMutable); - static assert(isMutableInt!int); - static assert(!isMutableInt!(const int)); - static assert(!isMutableInt!float); - - alias alwaysTrue = templateAnd!(); - static assert(alwaysTrue!int); - - alias isIntegral = templateAnd!(.isIntegral); - static assert(isIntegral!int); - static assert(isIntegral!(const int)); - static assert(!isIntegral!float); -} - -/** - * Combines multiple templates with logical OR. So $(D_PSYMBOL templateOr) - * evaluates to $(D_INLINECODE Preds[0] || Preds[1] || Preds[2]) and so on. - * - * Empty $(D_PARAM Preds) evaluates to $(D_KEYWORD false). - * - * Params: - * Preds = Template predicates. - * - * Returns: The constructed template. - */ -template templateOr(Preds...) -if (allSatisfy!(isTemplate, Preds)) -{ - template templateOr(T...) - { - static if (Preds.length == 0) - { - enum bool templateOr = false; - } - else static if (Instantiate!(Preds[0], T)) - { - enum bool templateOr = true; - } - else - { - alias templateOr = Instantiate!(.templateOr!(Preds[1 .. $]), T); - } - } -} - -/// -@nogc nothrow pure @safe unittest -{ - alias isMutableOrInt = templateOr!(isIntegral, isMutable); - static assert(isMutableOrInt!int); - static assert(isMutableOrInt!(const int)); - static assert(isMutableOrInt!float); - static assert(!isMutableOrInt!(const float)); - - alias alwaysFalse = templateOr!(); - static assert(!alwaysFalse!int); - - alias isIntegral = templateOr!(.isIntegral); - static assert(isIntegral!int); - static assert(isIntegral!(const int)); - static assert(!isIntegral!float); -} - -/** - * Params: - * pred = Template predicate. - * - * Returns: Negated $(D_PARAM pred). - */ -template templateNot(alias pred) -if (__traits(isTemplate, pred)) -{ - enum bool templateNot(T...) = !pred!T; -} - -/// -@nogc nothrow pure @safe unittest -{ - alias isNotIntegral = templateNot!isIntegral; - static assert(!isNotIntegral!int); - static assert(isNotIntegral!(char[])); -} - -/** - * Tests whether $(D_PARAM L) is sorted in ascending order according to - * $(D_PARAM cmp). - * - * $(D_PARAM cmp) can evaluate to: - * $(UL - * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means - * $(D_INLINECODE a[i] < a[i + 1]).) - * $(LI $(D_KEYWORD int): a negative number means that - * $(D_INLINECODE a[i] < a[i + 1]), a positive number that - * $(D_INLINECODE a[i] > a[i + 1]), `0` if they equal.) - * ) - * - * Params: - * cmp = Sorting template predicate. - * L = Elements to be tested. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM L) is sorted, $(D_KEYWORD false) - * if not. - */ -template isSorted(alias cmp, L...) -if (__traits(isTemplate, cmp)) -{ - static if (L.length <= 1) - { - enum bool isSorted = true; - } - else - { - // `L` is sorted if the both halves and the boundary values are sorted. - enum bool isSorted = isLessEqual!(cmp, L[$ / 2 - 1], L[$ / 2]) - && isSorted!(cmp, L[0 .. $ / 2]) - && isSorted!(cmp, L[$ / 2 .. $]); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - enum cmp(T, U) = T.sizeof < U.sizeof; - static assert(isSorted!(cmp)); - static assert(isSorted!(cmp, byte)); - static assert(isSorted!(cmp, byte, ubyte, short, uint)); - static assert(!isSorted!(cmp, long, byte, ubyte, short, uint)); -} - -/** - * Params: - * T = A template. - * Args = The first arguments for $(D_PARAM T). - * - * Returns: $(D_PARAM T) with $(D_PARAM Args) applied to it as its first - * arguments. - */ -template ApplyLeft(alias T, Args...) -{ - alias ApplyLeft(U...) = T!(Args, U); -} - -/// -@nogc nothrow pure @safe unittest -{ - alias allAreIntegral = ApplyLeft!(allSatisfy, isIntegral); - static assert(allAreIntegral!(int, uint)); - static assert(!allAreIntegral!(int, float, uint)); -} - -/** - * Params: - * T = A template. - * Args = The last arguments for $(D_PARAM T). - * - * Returns: $(D_PARAM T) with $(D_PARAM Args) applied to it as itslast - * arguments. - */ -template ApplyRight(alias T, Args...) -{ - alias ApplyRight(U...) = T!(U, Args); -} - -/// -@nogc nothrow pure @safe unittest -{ - alias intIs = ApplyRight!(allSatisfy, int); - static assert(intIs!(isIntegral)); - static assert(!intIs!(isUnsigned)); -} - -/** - * Params: - * n = The number of times to repeat $(D_PARAM L). - * L = The sequence to be repeated. - * - * Returns: $(D_PARAM L) repeated $(D_PARAM n) times. - */ -template Repeat(size_t n, L...) -if (n > 0) -{ - static if (n == 1) - { - alias Repeat = L; - } - else - { - alias Repeat = AliasSeq!(L, Repeat!(n - 1, L)); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(is(Repeat!(1, uint, int) == AliasSeq!(uint, int))); - static assert(is(Repeat!(2, uint, int) == AliasSeq!(uint, int, uint, int))); - static assert(is(Repeat!(3) == AliasSeq!())); -} - -private template ReplaceOne(L...) -{ - static if (L.length == 2) - { - alias ReplaceOne = AliasSeq!(); - } - else static if (isEqual!(L[0], L[2])) - { - alias ReplaceOne = AliasSeq!(L[1], L[3 .. $]); - } - else - { - alias ReplaceOne = AliasSeq!(L[2], ReplaceOne!(L[0], L[1], L[3 .. $])); - } -} - -/** - * Replaces the first occurrence of $(D_PARAM T) in $(D_PARAM L) with - * $(D_PARAM U). - * - * Params: - * T = The symbol to be replaced. - * U = Replacement. - * L = List of symbols. - * - * Returns: $(D_PARAM L) with the first occurrence of $(D_PARAM T) replaced. - */ -template Replace(T, U, L...) -{ - alias Replace = ReplaceOne!(T, U, L); -} - -/// ditto -template Replace(alias T, U, L...) -{ - alias Replace = ReplaceOne!(T, U, L); -} - -/// ditto -template Replace(T, alias U, L...) -{ - alias Replace = ReplaceOne!(T, U, L); -} - -/// ditto -template Replace(alias T, alias U, L...) -{ - alias Replace = ReplaceOne!(T, U, L); -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(is(Replace!(int, uint, int) == AliasSeq!(uint))); - static assert(is(Replace!(int, uint, short, int, int, ushort) - == AliasSeq!(short, uint, int, ushort))); - - static assert(Replace!(5, 8, 1, 2, 5, 5) == AliasSeq!(1, 2, 8, 5)); -} - -private template ReplaceAllImpl(L...) -{ - static if (L.length == 2) - { - alias ReplaceAllImpl = AliasSeq!(); - } - else - { - private alias Rest = ReplaceAllImpl!(L[0], L[1], L[3 .. $]); - static if (isEqual!(L[0], L[2])) - { - alias ReplaceAllImpl = AliasSeq!(L[1], Rest); - } - else - { - alias ReplaceAllImpl = AliasSeq!(L[2], Rest); - } - } -} - -/** - * Replaces all occurrences of $(D_PARAM T) in $(D_PARAM L) with $(D_PARAM U). - * - * Params: - * T = The symbol to be replaced. - * U = Replacement. - * L = List of symbols. - * - * Returns: $(D_PARAM L) with all occurrences of $(D_PARAM T) replaced. - */ -template ReplaceAll(T, U, L...) -{ - alias ReplaceAll = ReplaceAllImpl!(T, U, L); -} - -/// ditto -template ReplaceAll(alias T, U, L...) -{ - alias ReplaceAll = ReplaceAllImpl!(T, U, L); -} - -/// ditto -template ReplaceAll(T, alias U, L...) -{ - alias ReplaceAll = ReplaceAllImpl!(T, U, L); -} - -/// ditto -template ReplaceAll(alias T, alias U, L...) -{ - alias ReplaceAll = ReplaceAllImpl!(T, U, L); -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(is(ReplaceAll!(int, uint, int) == AliasSeq!(uint))); - static assert(is(ReplaceAll!(int, uint, short, int, int, ushort) - == AliasSeq!(short, uint, uint, ushort))); - - static assert(ReplaceAll!(5, 8, 1, 2, 5, 5) == AliasSeq!(1, 2, 8, 8)); -} - -/** - * Params: - * L = List of symbols. - * - * Returns: $(D_PARAM L) with elements in reversed order. - */ -template Reverse(L...) -{ - static if (L.length == 0) - { - alias Reverse = AliasSeq!(); - } - else - { - alias Reverse = AliasSeq!(L[$ - 1], Reverse!(L[0 .. $ - 1])); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(is(Reverse!(byte, short, int) == AliasSeq!(int, short, byte))); -} - -/** - * Applies $(D_PARAM F) to all elements of $(D_PARAM T). - * - * Params: - * F = Template predicate. - * T = List of symbols. - * - * Returns: Elements $(D_PARAM T) after applying $(D_PARAM F) to them. - */ -template Map(alias F, T...) -if (__traits(isTemplate, F)) -{ - static if (T.length == 0) - { - alias Map = AliasSeq!(); - } - else - { - alias Map = AliasSeq!(F!(T[0]), Map!(F, T[1 .. $])); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(is(Map!(Unqual, const int, immutable short) - == AliasSeq!(int, short))); -} - -/** - * Sorts $(D_PARAM L) in ascending order according to $(D_PARAM cmp). - * - * $(D_PARAM cmp) can evaluate to: - * $(UL - * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means - * $(D_INLINECODE a[i] < a[i + 1]).) - * $(LI $(D_KEYWORD int): a negative number means that - * $(D_INLINECODE a[i] < a[i + 1]), a positive number that - * $(D_INLINECODE a[i] > a[i + 1]), `0` if they equal.) - * ) - * - * Merge sort is used to sort the arguments. - * - * Params: - * cmp = Sorting template predicate. - * L = Elements to be sorted. - * - * Returns: Elements of $(D_PARAM L) in ascending order. - * - * See_Also: $(LINK2 https://en.wikipedia.org/wiki/Merge_sort, Merge sort). - */ -template Sort(alias cmp, L...) -if (__traits(isTemplate, cmp)) -{ - private template merge(size_t A, size_t B) - { - static if (A + B == L.length) - { - alias merge = AliasSeq!(); - } - else static if (B >= Right.length - || (A < Left.length && isLessEqual!(cmp, Left[A], Right[B]))) - { - alias merge = AliasSeq!(Left[A], merge!(A + 1, B)); - } - else - { - alias merge = AliasSeq!(Right[B], merge!(A, B + 1)); - } - } - - static if (L.length <= 1) - { - alias Sort = L; - } - else - { - private alias Left = Sort!(cmp, L[0 .. $ / 2]); - private alias Right = Sort!(cmp, L[$ / 2 .. $]); - alias Sort = merge!(0, 0); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - enum cmp(T, U) = T.sizeof < U.sizeof; - static assert(is(Sort!(cmp, long, short, byte, int) - == AliasSeq!(byte, short, int, long))); -} - -@nogc nothrow pure @safe unittest -{ - enum cmp(int T, int U) = T - U; - static assert(Sort!(cmp, 5, 17, 9, 12, 2, 10, 14) - == AliasSeq!(2, 5, 9, 10, 12, 14, 17)); -} - -private enum bool DerivedToFrontCmp(A, B) = is(A : B); - -/** - * Returns $(D_PARAM L) sorted in such a way that the most derived types come - * first. - * - * Params: - * L = Type tuple. - * - * Returns: Sorted $(D_PARAM L). - */ -template DerivedToFront(L...) -{ - alias DerivedToFront = Sort!(DerivedToFrontCmp, L); -} - -/// -@nogc nothrow pure @safe unittest -{ - class A - { - } - class B : A - { - } - class C : B - { - } - static assert(is(DerivedToFront!(B, A, C) == AliasSeq!(C, B, A))); -} - -/** - * Returns the type from the type tuple $(D_PARAM L) that is most derived from - * $(D_PARAM T). - * - * Params: - * T = The type to compare to. - * L = Type tuple. - * - * Returns: The type most derived from $(D_PARAM T). - */ -template MostDerived(T, L...) -{ - static if (L.length == 0) - { - alias MostDerived = T; - } - else static if (is(T : L[0])) - { - alias MostDerived = MostDerived!(T, L[1 .. $]); - } - else - { - alias MostDerived = MostDerived!(L[0], L[1 .. $]); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - class A - { - } - class B : A - { - } - class C : B - { - } - static assert(is(MostDerived!(A, C, B) == C)); -} - -private template EraseOne(L...) -if (L.length > 0) -{ - static if (L.length == 1) - { - alias EraseOne = AliasSeq!(); - } - else static if (isEqual!(L[0 .. 2])) - { - alias EraseOne = AliasSeq!(L[2 .. $]); - } - else - { - alias EraseOne = AliasSeq!(L[1], EraseOne!(L[0], L[2 .. $])); - } -} - -/** - * Removes the first occurrence of $(D_PARAM T) from the alias sequence - * $(D_PARAL L). - * - * Params: - * T = The item to be removed. - * L = Alias sequence. - * - * Returns: $(D_PARAM L) with the first occurrence of $(D_PARAM T) removed. - */ -template Erase(T, L...) -{ - alias Erase = EraseOne!(T, L); -} - -/// ditto -template Erase(alias T, L...) -{ - alias Erase = EraseOne!(T, L); -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(is(Erase!(int, short, int, int, uint) == AliasSeq!(short, int, uint))); - static assert(is(Erase!(int, short, uint) == AliasSeq!(short, uint))); -} - -private template EraseAllImpl(L...) -{ - static if (L.length == 1) - { - alias EraseAllImpl = AliasSeq!(); - } - else static if (isEqual!(L[0 .. 2])) - { - alias EraseAllImpl = EraseAllImpl!(L[0], L[2 .. $]); - } - else - { - alias EraseAllImpl = AliasSeq!(L[1], EraseAllImpl!(L[0], L[2 .. $])); - } -} - -/** - * Removes all occurrences of $(D_PARAM T) from the alias sequence $(D_PARAL L). - * - * Params: - * T = The item to be removed. - * L = Alias sequence. - * - * Returns: $(D_PARAM L) with all occurrences of $(D_PARAM T) removed. - */ -template EraseAll(T, L...) -{ - alias EraseAll = EraseAllImpl!(T, L); -} - -/// ditto -template EraseAll(alias T, L...) -{ - alias EraseAll = EraseAllImpl!(T, L); -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(is(EraseAll!(int, short, int, int, uint) == AliasSeq!(short, uint))); - static assert(is(EraseAll!(int, short, uint) == AliasSeq!(short, uint))); - static assert(is(EraseAll!(int, int, int) == AliasSeq!())); -} - -/** - * Returns an alias sequence which contains only items that satisfy the - * condition $(D_PARAM pred). - * - * Params: - * pred = Template predicate. - * L = Alias sequence. - * - * Returns: $(D_PARAM L) filtered so that it contains only items that satisfy - * $(D_PARAM pred). - */ -template Filter(alias pred, L...) -if (__traits(isTemplate, pred)) -{ - static if (L.length == 0) - { - alias Filter = AliasSeq!(); - } - else static if (pred!(L[0])) - { - alias Filter = AliasSeq!(L[0], Filter!(pred, L[1 .. $])); - } - else - { - alias Filter = Filter!(pred, L[1 .. $]); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - alias Given = AliasSeq!(real, int, bool, uint); - static assert(is(Filter!(isIntegral, Given) == AliasSeq!(int, uint))); -} - -/** - * Attaches a numeric index to each element from $(D_PARAM Args). - * - * $(D_PSYMBOL EnumerateFrom) returns a sequence of tuples ($(D_PSYMBOL Pack)s) - * consisting of the index of each element and the element itself. - * - * Params: - * start = Enumeration initial value. - * Args = Enumerated sequence. - * - * See_Also: $(D_PSYMBOL Enumerate). - */ -template EnumerateFrom(size_t start, Args...) -{ - static if (Args.length == 0) - { - alias EnumerateFrom = AliasSeq!(); - } - else - { - alias EnumerateFrom = AliasSeq!(Pack!(start, Args[0]), EnumerateFrom!(start + 1, Args[1 .. $])); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(EnumerateFrom!(0, int, uint, bool).length == 3); -} - -/// -@nogc nothrow pure @safe unittest -{ - alias Expected = AliasSeq!(Pack!(cast(size_t) 0, int), - Pack!(cast(size_t) 1, uint)); - static assert(is(EnumerateFrom!(0, int, uint) == Expected)); -} - -/** - * Attaches a numeric index to each element from $(D_PARAM Args). - * - * $(D_PSYMBOL EnumerateFrom) returns a sequence of tuples ($(D_PSYMBOL Pack)s) - * consisting of the index of each element and the element itself. - * - * Params: - * Args = Enumerated sequence. - * - * See_Also: $(D_PSYMBOL EnumerateFrom). - */ -alias Enumerate(Args...) = EnumerateFrom!(0, Args); - -/// -@nogc nothrow pure @safe unittest -{ - alias Expected = AliasSeq!(Pack!(cast(size_t) 0, int), - Pack!(cast(size_t) 1, uint)); - static assert(is(Enumerate!(int, uint) == Expected)); -} diff --git a/meta/tanya/meta/package.d b/meta/tanya/meta/package.d deleted file mode 100644 index daf8d9e..0000000 --- a/meta/tanya/meta/package.d +++ /dev/null @@ -1,22 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Template metaprogramming. - * - * This package contains utilities to acquire type information at compile-time, - * to transform from one type to another. It has also different algorithms for - * iterating, searching and modifying template arguments. - * - * Copyright: Eugene Wissner 2017-2025. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/package.d, - * tanya/meta/package.d) - */ -module tanya.meta; - -public import tanya.meta.metafunction; -public import tanya.meta.trait; diff --git a/meta/tanya/meta/trait.d b/meta/tanya/meta/trait.d deleted file mode 100644 index 243c123..0000000 --- a/meta/tanya/meta/trait.d +++ /dev/null @@ -1,150 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Type traits. - * - * Templates in this module are used to obtain type information at compile - * time. - * - * Copyright: Eugene Wissner 2017-2025. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/trait.d, - * tanya/meta/trait.d) - */ -module tanya.meta.trait; - -import std.traits : OriginalType, Unqual, isStaticArray, isUnsigned; -import tanya.meta.metafunction; - -/** - * Determines whether $(D_PARAM T) is a wide string, i.e. consists of - * $(D_KEYWORD dchar). - * - * The character type of the string and the string itself can have any type - * qualifiers. - * - * Static $(D_KEYWORD dchar) arrays are not considered strings. - * - * Params: - * T = A type. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a wide string, - * $(D_KEYWORD false) otherwise. - */ -enum bool isWideString(T) = is(immutable T == immutable dchar[]); - -/// -@nogc nothrow pure @safe unittest -{ - static assert(isWideString!(dchar[])); - static assert(!isWideString!(char[])); - static assert(!isWideString!(wchar[])); - - static assert(isWideString!dstring); - static assert(!isWideString!string); - static assert(!isWideString!wstring); - - static assert(isWideString!(const dstring)); - static assert(!isWideString!(const string)); - static assert(!isWideString!(const wstring)); - - static assert(isWideString!(shared dstring)); - static assert(!isWideString!(shared string)); - static assert(!isWideString!(shared wstring)); - - static assert(isWideString!(const(dchar)[])); - static assert(isWideString!(inout(dchar)[])); - static assert(isWideString!(shared(const(dchar))[])); - static assert(isWideString!(shared(dchar)[])); - static assert(!isWideString!(dchar[10])); -} - -/* - * Tests whether $(D_PARAM T) is an interface. - * - * Params: - * T = A type. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an interface, - * $(D_KEYWORD false) otherwise. - */ -private enum bool isInterface(T) = is(T == interface); - -/** - * Determines whether $(D_PARAM T) is a polymorphic type, i.e. a - * $(D_KEYWORD class) or an $(D_KEYWORD interface). - * - * Params: - * T = A type. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a $(D_KEYWORD class) or an - * $(D_KEYWORD interface), $(D_KEYWORD false) otherwise. - */ -enum bool isPolymorphicType(T) = is(T == class) || is(T == interface); - -/// -@nogc nothrow pure @safe unittest -{ - interface I - { - } - static assert(isPolymorphicType!Object); - static assert(isPolymorphicType!I); - static assert(!isPolymorphicType!short); -} - -/** - * Returns the size in bytes of the state that needs to be allocated to hold an - * object of type $(D_PARAM T). - * - * There is a difference between the `.sizeof`-property and - * $(D_PSYMBOL stateSize) if $(D_PARAM T) is a class or an interface. - * `T.sizeof` is constant on the given architecture then and is the same as - * `size_t.sizeof` and `ptrdiff_t.sizeof`. This is because classes and - * interfaces are reference types and `.sizeof` returns the size of the - * reference which is the same as the size of a pointer. $(D_PSYMBOL stateSize) - * returns the size of the instance itself. - * - * The size of a dynamic array is `size_t.sizeof * 2` since a dynamic array - * stores its length and a data pointer. The size of the static arrays is - * calculated differently since they are value types. It is the array length - * multiplied by the element size. - * - * `stateSize!void` is `1` since $(D_KEYWORD void) is mostly used as a synonym - * for $(D_KEYWORD byte)/$(D_KEYWORD ubyte) in `void*`. - * - * Params: - * T = Object type. - * - * Returns: Size of an instance of type $(D_PARAM T). - */ -template stateSize(T) -{ - static if (isPolymorphicType!T) - { - enum size_t stateSize = __traits(classInstanceSize, T); - } - else - { - enum size_t stateSize = T.sizeof; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - static assert(stateSize!int == 4); - static assert(stateSize!bool == 1); - static assert(stateSize!(int[]) == (size_t.sizeof * 2)); - static assert(stateSize!(short[3]) == 6); - - static struct Empty - { - } - static assert(stateSize!Empty == 1); - static assert(stateSize!void == 1); -} diff --git a/middle/dub.json b/middle/dub.json index 0e91cd0..aef09d2 100644 --- a/middle/dub.json +++ b/middle/dub.json @@ -3,11 +3,6 @@ "description": "Runtime, middle-level utilities", "targetType": "library", - "dependencies": { - "tanya:meta": "*", - "tanya:os": "*" - }, - "dependencies-linux": { "mir-linux-kernel": "~>1.0.0" }, diff --git a/middle/tanya/memory/allocator.d b/middle/tanya/memory/allocator.d index 2acd044..30ef03b 100644 --- a/middle/tanya/memory/allocator.d +++ b/middle/tanya/memory/allocator.d @@ -17,9 +17,9 @@ */ module tanya.memory.allocator; -import std.traits : hasElaborateDestructor, isAssociativeArray, isArray; +import std.traits; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; /** * Abstract class implementing a basic allocator. diff --git a/middle/tanya/memory/lifetime.d b/middle/tanya/memory/lifetime.d index a5b98cd..aa9c7d1 100644 --- a/middle/tanya/memory/lifetime.d +++ b/middle/tanya/memory/lifetime.d @@ -14,11 +14,10 @@ */ module tanya.memory.lifetime; -import std.traits : isInnerClass, hasElaborateAssign, hasElaborateCopyConstructor, hasElaborateDestructor, - isAssignable, isNested, isAbstractClass, isAggregateType, isStaticArray; +import std.traits; +import std.meta : AliasSeq; import tanya.memory.allocator; -import tanya.meta.metafunction; -import tanya.meta.trait; +import tanya.meta; package(tanya) void destroyAllImpl(R, E)(R p) { diff --git a/middle/tanya/memory/smartref.d b/middle/tanya/memory/smartref.d index 59ac3af..6134a04 100644 --- a/middle/tanya/memory/smartref.d +++ b/middle/tanya/memory/smartref.d @@ -23,10 +23,10 @@ */ module tanya.memory.smartref; -import std.traits : isPointer, isAbstractClass, isAssociativeArray, isDynamicArray, isArray; +import std.traits; import tanya.memory.allocator; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; private template Payload(T) { diff --git a/middle/tanya/meta.d b/middle/tanya/meta.d new file mode 100644 index 0000000..909415e --- /dev/null +++ b/middle/tanya/meta.d @@ -0,0 +1,920 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Template metaprogramming. + * + * This package contains utilities to acquire type information at compile-time, + * to transform from one type to another. It has also different algorithms for + * iterating, searching and modifying template arguments. + * + * Copyright: Eugene Wissner 2017-2025. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/package.d, + * tanya/meta/package.d) + */ +module tanya.meta; + +import std.meta; +import std.traits; + +/** + * Determines whether $(D_PARAM T) is a wide string, i.e. consists of + * $(D_KEYWORD dchar). + * + * The character type of the string and the string itself can have any type + * qualifiers. + * + * Static $(D_KEYWORD dchar) arrays are not considered strings. + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a wide string, + * $(D_KEYWORD false) otherwise. + */ +enum bool isWideString(T) = is(immutable T == immutable dchar[]); + +/// +@nogc nothrow pure @safe unittest +{ + static assert(isWideString!(dchar[])); + static assert(!isWideString!(char[])); + static assert(!isWideString!(wchar[])); + + static assert(isWideString!dstring); + static assert(!isWideString!string); + static assert(!isWideString!wstring); + + static assert(isWideString!(const dstring)); + static assert(!isWideString!(const string)); + static assert(!isWideString!(const wstring)); + + static assert(isWideString!(shared dstring)); + static assert(!isWideString!(shared string)); + static assert(!isWideString!(shared wstring)); + + static assert(isWideString!(const(dchar)[])); + static assert(isWideString!(inout(dchar)[])); + static assert(isWideString!(shared(const(dchar))[])); + static assert(isWideString!(shared(dchar)[])); + static assert(!isWideString!(dchar[10])); +} + +/* + * Tests whether $(D_PARAM T) is an interface. + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an interface, + * $(D_KEYWORD false) otherwise. + */ +private enum bool isInterface(T) = is(T == interface); + +/** + * Determines whether $(D_PARAM T) is a polymorphic type, i.e. a + * $(D_KEYWORD class) or an $(D_KEYWORD interface). + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a $(D_KEYWORD class) or an + * $(D_KEYWORD interface), $(D_KEYWORD false) otherwise. + */ +enum bool isPolymorphicType(T) = is(T == class) || is(T == interface); + +/// +@nogc nothrow pure @safe unittest +{ + interface I + { + } + static assert(isPolymorphicType!Object); + static assert(isPolymorphicType!I); + static assert(!isPolymorphicType!short); +} + +/** + * Returns the size in bytes of the state that needs to be allocated to hold an + * object of type $(D_PARAM T). + * + * There is a difference between the `.sizeof`-property and + * $(D_PSYMBOL stateSize) if $(D_PARAM T) is a class or an interface. + * `T.sizeof` is constant on the given architecture then and is the same as + * `size_t.sizeof` and `ptrdiff_t.sizeof`. This is because classes and + * interfaces are reference types and `.sizeof` returns the size of the + * reference which is the same as the size of a pointer. $(D_PSYMBOL stateSize) + * returns the size of the instance itself. + * + * The size of a dynamic array is `size_t.sizeof * 2` since a dynamic array + * stores its length and a data pointer. The size of the static arrays is + * calculated differently since they are value types. It is the array length + * multiplied by the element size. + * + * `stateSize!void` is `1` since $(D_KEYWORD void) is mostly used as a synonym + * for $(D_KEYWORD byte)/$(D_KEYWORD ubyte) in `void*`. + * + * Params: + * T = Object type. + * + * Returns: Size of an instance of type $(D_PARAM T). + */ +template stateSize(T) +{ + static if (isPolymorphicType!T) + { + enum size_t stateSize = __traits(classInstanceSize, T); + } + else + { + enum size_t stateSize = T.sizeof; + } +} + +/// +@nogc nothrow pure @safe unittest +{ + static assert(stateSize!int == 4); + static assert(stateSize!bool == 1); + static assert(stateSize!(int[]) == (size_t.sizeof * 2)); + static assert(stateSize!(short[3]) == 6); + + static struct Empty + { + } + static assert(stateSize!Empty == 1); + static assert(stateSize!void == 1); +} + +/** + * Finds the minimum value in $(D_PARAM Args) according to $(D_PARAM pred). + * + * $(D_PARAM Args) should contain at least one element. + * + * $(D_PARAM pred) can evaluate to: + * $(UL + * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means + * $(D_INLINECODE Args[0] < Args[1]).) + * $(LI $(D_KEYWORD int): a negative number means that + * $(D_INLINECODE Args[0] < Args[1]), a positive number that + * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) + * ) + * + * Params: + * pred = Template predicate. + * Args = Elements for which you want to find the minimum value. + * + * Returns: The minimum. + * + * See_Also: $(D_PSYMBOL isLess). + */ +template Min(alias pred, Args...) +if (Args.length > 0 && __traits(isTemplate, pred)) +{ + static if (Args.length == 1) + { + alias Min = Alias!(Args[0]); + } + else static if (isLess!(pred, Args[1], Args[0])) + { + alias Min = Min!(pred, Args[1], Args[2 .. $]); + } + else + { + alias Min = Min!(pred, Args[0], Args[2 .. $]); + } +} + +/// +@nogc nothrow pure @safe unittest +{ + enum bool cmp(alias T, alias U) = T < U; + static assert(Min!(cmp, 8, 4, 5, 3, 13) == 3); + static assert(Min!(cmp, 8) == 8); +} + +/** + * Finds the maximum value in $(D_PARAM Args) according to $(D_PARAM pred). + * + * $(D_PARAM Args) should contain at least one element. + * + * $(D_PARAM pred) can evaluate to: + * $(UL + * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means + * $(D_INLINECODE Args[0] < Args[1]).) + * $(LI $(D_KEYWORD int): a negative number means that + * $(D_INLINECODE Args[0] < Args[1]), a positive number that + * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) + * ) + * + * Params: + * pred = Template predicate. + * Args = Elements for which you want to find the maximum value. + * + * Returns: The maximum. + * + * See_Also: $(D_PSYMBOL isLess). + */ +template Max(alias pred, Args...) +if (Args.length > 0 && __traits(isTemplate, pred)) +{ + static if (Args.length == 1) + { + alias Max = Alias!(Args[0]); + } + else static if (isGreater!(pred, Args[1], Args[0])) + { + alias Max = Max!(pred, Args[1], Args[2 .. $]); + } + else + { + alias Max = Max!(pred, Args[0], Args[2 .. $]); + } +} + +/// +@nogc nothrow pure @safe unittest +{ + enum bool cmp(alias T, alias U) = T < U; + static assert(Max!(cmp, 8, 4, 5, 3, 13) == 13); + static assert(Max!(cmp, 8) == 8); +} + +/** + * Zips one or more $(D_PSYMBOL Pack)s with $(D_PARAM f). + * + * Given $(D_PARAM f) and tuples t1, t2, ..., tk, where tk[i] denotes the + * $(I i)-th element of the tuple $(I k)-th tuple, $(D_PSYMBOL ZipWith) + * produces a sequence: + * + * --- + * f(t1[0], t2[0], ... tk[0]), + * f(t1[1], t2[1], ... tk[1]), + * ... + * f(tk[0], tk[1], ... tk[i]), + * --- + * + * $(D_PSYMBOL ZipWith) begins with the first elements from $(D_PARAM Packs) + * and applies $(D_PARAM f) to them, then it takes the second + * ones and does the same, and so on. + * + * If not all argument tuples have the same length, $(D_PSYMBOL ZipWith) will + * zip only `n` elements from each tuple, where `n` is the length of the + * shortest tuple in the argument list. Remaining elements in the longer tuples + * are just ignored. + * + * Params: + * f = Some template that can be applied to the elements of + * $(D_PARAM Packs). + * Packs = $(D_PSYMBOL Pack) instances. + * + * Returns: A sequence, whose $(I i)-th element contains the $(I i)-th element + * from each of the $(D_PARAM Packs). + */ +template ZipWith(alias f, Packs...) +if (Packs.length > 0 + && __traits(isTemplate, f) + && (allSatisfy!(ApplyLeft!(isInstanceOf, Pack), Packs) + || allSatisfy!(ApplyLeft!(isInstanceOf, Tuple), Packs))) +{ + private template GetIth(size_t i, Args...) + { + static if ((Args.length == 0) || (Args[0].Seq.length <= i)) + { + alias GetIth = AliasSeq!(); + } + else + { + alias GetIth = AliasSeq!(Args[0].Seq[i], GetIth!(i, Args[1 .. $])); + } + } + private template Iterate(size_t i, Args...) + { + alias Pack = GetIth!(i, Args); + + static if (Pack.length < Packs.length) + { + alias Iterate = AliasSeq!(); + } + else + { + alias Iterate = AliasSeq!(f!Pack, Iterate!(i + 1, Args)); + } + } + alias ZipWith = Iterate!(0, Packs); +} + +/// +@nogc nothrow pure @safe unittest +{ + alias Result1 = ZipWith!(AliasSeq, Pack!(1, 2), Pack!(5, 6), Pack!(9, 10)); + static assert(Result1 == AliasSeq!(1, 5, 9, 2, 6, 10)); + + alias Result2 = ZipWith!(AliasSeq, Pack!(1, 2, 3), Pack!(4, 5)); + static assert(Result2 == AliasSeq!(1, 4, 2, 5)); + + alias Result3 = ZipWith!(AliasSeq, Pack!(), Pack!(4, 5)); + static assert(Result3.length == 0); +} + +/** + * Holds a typed sequence of template parameters. + * + * Different than $(D_PSYMBOL AliasSeq), $(D_PSYMBOL Pack) doesn't unpack + * its template parameters automatically. Consider: + * + * --- + * template A(Args...) + * { + * static assert(Args.length == 4); + * } + * + * alias AInstance = A!(AliasSeq!(int, uint), AliasSeq!(float, double)); + * --- + * + * Using $(D_PSYMBOL AliasSeq) template `A` gets 4 parameters instead of 2, + * because $(D_PSYMBOL AliasSeq) is just an alias for its template parameters. + * + * With $(D_PSYMBOL Pack) it is possible to pass distinguishable + * sequences of parameters to a template. So: + * + * --- + * template B(Args...) + * { + * static assert(Args.length == 2); + * } + * + * alias BInstance = B!(Pack!(int, uint), Pack!(float, double)); + * --- + * + * Params: + * Args = Elements of this $(D_PSYMBOL Pack). + * + * See_Also: $(D_PSYMBOL AliasSeq). + */ +struct Pack(Args...) +{ + /// Elements in this tuple as $(D_PSYMBOL AliasSeq). + alias Seq = Args; + + /// The length of the tuple. + enum size_t length = Args.length; + + alias Seq this; +} + +/// +@nogc nothrow pure @safe unittest +{ + alias A = Pack!short; + alias B = Pack!(3, 8, 9); + alias C = Pack!(A, B); + + static assert(C.length == 2); + + static assert(A.length == 1); + static assert(is(A.Seq == AliasSeq!short)); + static assert(B.length == 3); + static assert(B.Seq == AliasSeq!(3, 8, 9)); + + alias D = Pack!(); + static assert(D.length == 0); + static assert(is(D.Seq == AliasSeq!())); +} + +/** + * Unordered sequence of unique aliases. + * + * $(D_PARAM Args) can contain duplicates, but they will be filtered out, so + * $(D_PSYMBOL Set) contains only unique items. $(D_PSYMBOL isEqual) is used + * for determining if two items are equal. + * + * Params: + * Args = Elements of this $(D_PSYMBOL Set). + */ +struct Set(Args...) +{ + /// Elements in this set as $(D_PSYMBOL AliasSeq). + alias Seq = NoDuplicates!Args; + + /// The length of the set. + enum size_t length = Seq.length; + + alias Seq this; +} + +/// +@nogc nothrow pure @safe unittest +{ + alias S1 = Set!(int, 5, 5, int, 4); + static assert(S1.length == 3); +} + +/** + * Produces a $(D_PSYMBOL Set) containing all elements of the given + * $(D_PARAM Sets). + * + * Params: + * Sets = List of $(D_PSYMBOL Set) instances. + * + * Returns: Set-theoretic union of all $(D_PARAM Sets). + * + * See_Also: $(D_PSYMBOL Set). + */ +template Union(Sets...) +if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets)) +{ + private template Impl(Sets...) + { + static if (Sets.length == 0) + { + alias Impl = AliasSeq!(); + } + else + { + alias Impl = AliasSeq!(Sets[0].Seq, Impl!(Sets[1 .. $])); + } + } + alias Union = Set!(Impl!Sets); +} + +/// +@nogc nothrow pure @safe unittest +{ + alias S1 = Set!(2, 5, 8, 4); + alias S2 = Set!(3, 8, 4, 1); + static assert(Union!(S1, S2).Seq == AliasSeq!(2, 5, 8, 4, 3, 1)); +} + +/** + * Produces a $(D_PSYMBOL Set) that containing elements of + * $(D_INLINECODE Sets[0]) that are also elements of all other sets in + * $(D_PARAM Sets). + * + * Params: + * Sets = List of $(D_PSYMBOL Set) instances. + * + * Returns: Set-theoretic intersection of all $(D_PARAM Sets). + * + * See_Also: $(D_PSYMBOL Set). + */ +template Intersection(Sets...) +if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets)) +{ + private template Impl(Args...) + if (Args.length > 0) + { + alias Equal = ApplyLeft!(isEqual, Args[0]); + static if (Args.length == 1) + { + enum bool Impl = true; + } + else static if (!anySatisfy!(Equal, Args[1].Seq)) + { + enum bool Impl = false; + } + else + { + enum bool Impl = Impl!(Args[0], Args[2 .. $]); + } + } + + private enum bool FilterImpl(Args...) = Impl!(Args[0], Sets[1 .. $]); + + static if (Sets.length == 0) + { + alias Intersection = Set!(); + } + else + { + alias Intersection = Set!(Filter!(FilterImpl, Sets[0].Seq)); + } +} + +/// +@nogc nothrow pure @safe unittest +{ + alias S1 = Set!(2, 5, 8, 4); + alias S2 = Set!(3, 8, 4, 1); + static assert(Intersection!(S1, S2).Seq == AliasSeq!(8, 4)); + + static assert(Intersection!(S1).Seq == AliasSeq!(2, 5, 8, 4)); + static assert(Intersection!().length == 0); +} + +/** + * Produces a $(D_PSYMBOL Set) that contains all elements of + * $(D_PARAM S1) that are not members of $(D_PARAM S2). + * + * Params: + * S1 = A $(D_PSYMBOL Set). + * S2 = A $(D_PSYMBOL Set). + * + * Returns: Set-theoretic difference of two sets $(D_PARAM S1) and + * $(D_PARAM S2). + * + * See_Also: $(D_PSYMBOL Set). + */ +template Difference(alias S1, alias S2) +if (isInstanceOf!(Set, S1) && isInstanceOf!(Set, S2)) +{ + private template Impl(Args...) + { + alias Equal = ApplyLeft!(isEqual, Args[0]); + enum bool Impl = !anySatisfy!(Equal, S2.Seq); + } + + static if (S1.length == 0) + { + alias Difference = Set!(); + } + else static if (S2.length == 1) + { + alias Difference = S1; + } + else + { + alias Difference = Set!(Filter!(Impl, S1.Seq)); + } +} + +/// +@nogc nothrow pure @safe unittest +{ + alias S1 = Set!(2, 5, 8, 4); + alias S2 = Set!(3, 8, 4, 1); + static assert(Difference!(S1, S2).Seq == AliasSeq!(2, 5)); + static assert(Difference!(S2, S1).Seq == AliasSeq!(3, 1)); + static assert(Difference!(S1, Set!()).Seq == AliasSeq!(2, 5, 8, 4)); +} + +/** + * Tests whether $(D_INLINECODE Args[0]) is less than or equal to + * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). + * + * $(D_PARAM cmp) can evaluate to: + * $(UL + * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means + * $(D_INLINECODE Args[0] < Args[1]).) + * $(LI $(D_KEYWORD int): a negative number means that + * $(D_INLINECODE Args[0] < Args[1]), a positive number that + * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) + * ) + * + * Params: + * Args = Two aliases to compare for equality. + * + * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is less than or equal + * to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. + */ +template isLessEqual(alias cmp, Args...) +if (Args.length == 2 && __traits(isTemplate, cmp)) +{ + private enum result = cmp!(Args[1], Args[0]); + static if (is(typeof(result) == bool)) + { + enum bool isLessEqual = !result; + } + else + { + enum bool isLessEqual = result >= 0; + } +} + +/// +@nogc nothrow pure @safe unittest +{ + enum bool boolCmp(T, U) = T.sizeof < U.sizeof; + static assert(isLessEqual!(boolCmp, byte, int)); + static assert(isLessEqual!(boolCmp, uint, int)); + static assert(!isLessEqual!(boolCmp, long, int)); + + enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; + static assert(isLessEqual!(intCmp, byte, int)); + static assert(isLessEqual!(intCmp, uint, int)); + static assert(!isLessEqual!(intCmp, long, int)); +} + +/** + * Tests whether $(D_INLINECODE Args[0]) is greater than or equal to + * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). + * + * $(D_PARAM cmp) can evaluate to: + * $(UL + * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means + * $(D_INLINECODE Args[0] < Args[1]).) + * $(LI $(D_KEYWORD int): a negative number means that + * $(D_INLINECODE Args[0] < Args[1]), a positive number that + * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) + * ) + * + * Params: + * Args = Two aliases to compare for equality. + * + * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is greater than or + * equal to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. + */ +template isGreaterEqual(alias cmp, Args...) +if (Args.length == 2 && __traits(isTemplate, cmp)) +{ + private enum result = cmp!Args; + static if (is(typeof(result) == bool)) + { + enum bool isGreaterEqual = !result; + } + else + { + enum bool isGreaterEqual = result >= 0; + } +} + +/// +@nogc nothrow pure @safe unittest +{ + enum bool boolCmp(T, U) = T.sizeof < U.sizeof; + static assert(!isGreaterEqual!(boolCmp, byte, int)); + static assert(isGreaterEqual!(boolCmp, uint, int)); + static assert(isGreaterEqual!(boolCmp, long, int)); + + enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; + static assert(!isGreaterEqual!(intCmp, byte, int)); + static assert(isGreaterEqual!(intCmp, uint, int)); + static assert(isGreaterEqual!(intCmp, long, int)); +} + +/** + * Tests whether $(D_INLINECODE Args[0]) is less than + * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). + * + * $(D_PARAM cmp) can evaluate to: + * $(UL + * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means + * $(D_INLINECODE Args[0] < Args[1]).) + * $(LI $(D_KEYWORD int): a negative number means that + * $(D_INLINECODE Args[0] < Args[1]), a positive number that + * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) + * ) + * + * Params: + * Args = Two aliases to compare for equality. + * + * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is less than + * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. + */ +template isLess(alias cmp, Args...) +if (Args.length == 2 && __traits(isTemplate, cmp)) +{ + private enum result = cmp!Args; + static if (is(typeof(result) == bool)) + { + enum bool isLess = result; + } + else + { + enum bool isLess = result < 0; + } +} + +/// +@nogc nothrow pure @safe unittest +{ + enum bool boolCmp(T, U) = T.sizeof < U.sizeof; + static assert(isLess!(boolCmp, byte, int)); + static assert(!isLess!(boolCmp, uint, int)); + static assert(!isLess!(boolCmp, long, int)); + + enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; + static assert(isLess!(intCmp, byte, int)); + static assert(!isLess!(intCmp, uint, int)); + static assert(!isLess!(intCmp, long, int)); +} + +/** + * Tests whether $(D_INLINECODE Args[0]) is greater than + * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). + * + * $(D_PARAM cmp) can evaluate to: + * $(UL + * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means + * $(D_INLINECODE Args[0] < Args[1]).) + * $(LI $(D_KEYWORD int): a negative number means that + * $(D_INLINECODE Args[0] < Args[1]), a positive number that + * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) + * ) + * + * Params: + * Args = Two aliases to compare for equality. + * + * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is greater than + * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. + */ +template isGreater(alias cmp, Args...) +if (Args.length == 2 && __traits(isTemplate, cmp)) +{ + private enum result = cmp!Args; + static if (is(typeof(result) == bool)) + { + enum bool isGreater = !result && cmp!(Args[1], Args[0]); + } + else + { + enum bool isGreater = result > 0; + } +} + +/// +@nogc nothrow pure @safe unittest +{ + enum bool boolCmp(T, U) = T.sizeof < U.sizeof; + static assert(!isGreater!(boolCmp, byte, int)); + static assert(!isGreater!(boolCmp, uint, int)); + static assert(isGreater!(boolCmp, long, int)); + + enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; + static assert(!isGreater!(intCmp, byte, int)); + static assert(!isGreater!(intCmp, uint, int)); + static assert(isGreater!(intCmp, long, int)); +} + +/** + * Tests whether $(D_INLINECODE Args[0]) is equal to $(D_INLINECODE Args[1]). + * + * $(D_PSYMBOL isEqual) checks first if $(D_PARAM Args) can be compared directly. If not, they are compared as types: + * $(D_INLINECODE is(Args[0] == Args[1])). It it fails, the arguments are + * considered to be not equal. + * + * If two items cannot be compared (for example comparing a type with a + * number), they are considered not equal. + * + * Params: + * Args = Two aliases to compare for equality. + * + * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is equal to + * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. + */ +template isEqual(Args...) +if (Args.length == 2) +{ + static if ((is(typeof(Args[0] == Args[1])) && (Args[0] == Args[1])) + || (isTypeTuple!Args && is(Args[0] == Args[1])) + || __traits(isSame, Args[0], Args[1])) + { + enum bool isEqual = true; + } + else + { + enum bool isEqual = false; + } +} + +/// +@nogc nothrow pure @safe unittest +{ + static assert(isEqual!(int, int)); + static assert(isEqual!(8, 8)); + static assert(!isEqual!(int, const(int))); + static assert(!isEqual!(5, int)); + static assert(!isEqual!(5, 8)); +} + +/** + * Tests whether $(D_INLINECODE Args[0]) isn't equal to + * $(D_INLINECODE Args[1]). + * + * $(D_PSYMBOL isNotEqual) checks first if $(D_PARAM Args) can be compared directly. If not, they are compared as types: + * $(D_INLINECODE is(Args[0] == Args[1])). It it fails, the arguments are + * considered to be not equal. + * + * Params: + * Args = Two aliases to compare for equality. + * + * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) isn't equal to + * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. + */ +template isNotEqual(Args...) +if (Args.length == 2) +{ + enum bool isNotEqual = !isEqual!Args; +} + +/// +@nogc nothrow pure @safe unittest +{ + static assert(!isNotEqual!(int, int)); + static assert(isNotEqual!(5, int)); + static assert(isNotEqual!(5, 8)); +} + +/** + * Looks for $(D_PARAM T) in $(D_PARAM L) and returns $(D_KEYWORD true) if it + * could be found and $(D_KEYWORD false) otherwise. + * + * Params: + * T = The item to search for. + * L = Symbol sequence. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) can be found in $(D_PARAM L), + * $(D_KEYWORD false) otherwise. + */ +enum bool canFind(T, L...) = staticIndexOf!(T, L) != -1; + +/// ditto +enum bool canFind(alias T, L...) = staticIndexOf!(T, L) != -1; + +/// +@nogc nothrow pure @safe unittest +{ + static assert(!canFind!(int)); + static assert(canFind!(int, int)); + static assert(canFind!(int, float, double, int, real)); + static assert(canFind!(3, () {}, uint, 5, 3)); +} + +/* + * Tests whether $(D_PARAM T) is a template. + * + * $(D_PSYMBOL isTemplate) isn't $(D_KEYWORD true) for template instances, + * since the latter already represent some type. Only not instantiated + * templates, i.e. that accept some template parameters, are considered + * templates. + * + * Params: + * T = A symbol. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a template, + * $(D_KEYWORD false) otherwise. + */ +enum bool isTemplate(alias T) = __traits(isTemplate, T); + +/// +@nogc nothrow pure @safe unittest +{ + static struct S(T) + { + } + static assert(isTemplate!S); + static assert(!isTemplate!(S!int)); +} + +/** + * Attaches a numeric index to each element from $(D_PARAM Args). + * + * $(D_PSYMBOL EnumerateFrom) returns a sequence of tuples ($(D_PSYMBOL Pack)s) + * consisting of the index of each element and the element itself. + * + * Params: + * start = Enumeration initial value. + * Args = Enumerated sequence. + * + * See_Also: $(D_PSYMBOL Enumerate). + */ +template EnumerateFrom(size_t start, Args...) +{ + static if (Args.length == 0) + { + alias EnumerateFrom = AliasSeq!(); + } + else + { + alias EnumerateFrom = AliasSeq!(Pack!(start, Args[0]), EnumerateFrom!(start + 1, Args[1 .. $])); + } +} + +/// +@nogc nothrow pure @safe unittest +{ + static assert(EnumerateFrom!(0, int, uint, bool).length == 3); +} + +/// +@nogc nothrow pure @safe unittest +{ + alias Expected = AliasSeq!(Pack!(cast(size_t) 0, int), + Pack!(cast(size_t) 1, uint)); + static assert(is(EnumerateFrom!(0, int, uint) == Expected)); +} + +/** + * Attaches a numeric index to each element from $(D_PARAM Args). + * + * $(D_PSYMBOL EnumerateFrom) returns a sequence of tuples ($(D_PSYMBOL Pack)s) + * consisting of the index of each element and the element itself. + * + * Params: + * Args = Enumerated sequence. + * + * See_Also: $(D_PSYMBOL EnumerateFrom). + */ +alias Enumerate(Args...) = EnumerateFrom!(0, Args); + +/// +@nogc nothrow pure @safe unittest +{ + alias Expected = AliasSeq!(Pack!(cast(size_t) 0, int), + Pack!(cast(size_t) 1, uint)); + static assert(is(Enumerate!(int, uint) == Expected)); +} diff --git a/middle/tanya/os/error.d b/middle/tanya/os/error.d new file mode 100644 index 0000000..733ff46 --- /dev/null +++ b/middle/tanya/os/error.d @@ -0,0 +1,413 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This module provides a portable way of using operating system error codes. + * + * Copyright: Eugene Wissner 2017-2025. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/os/tanya/os/error.d, + * tanya/os/error.d) + */ +module tanya.os.error; + +import tanya.meta; + +// Socket API error. +private template SAError(int posix, int wsa = posix) +{ + version (Windows) + { + enum SAError = 10000 + wsa; + } + else + { + alias SAError = posix; + } +} + +// Error for Windows and Posix separately. +private template NativeError(int posix, int win) +{ + version (Windows) + { + alias NativeError = win; + } + else + { + alias NativeError = posix; + } +} + +version (Windows) +{ + private enum eProtocolError = -71; +} +else version (OpenBSD) +{ + private enum eProtocolError = -71; +} +else +{ + private enum eProtocolError = 71; +} + +/** + * System error code. + */ +struct ErrorCode +{ + /** + * Error code numbers. + */ + enum ErrorNo : int + { + /// The operation completed successfully. + success = 0, + + /// Operation not permitted. + noPermission = NativeError!(1, 5), + + /// Interrupted system call. + interrupted = SAError!4, + + /// Bad file descriptor. + badDescriptor = SAError!9, + + /// An operation on a non-blocking socket would block. + wouldBlock = SAError!(11, 35), + + /// Out of memory. + noMemory = NativeError!(12, 14), + + /// Access denied. + accessDenied = SAError!13, + + /// An invalid pointer address detected. + fault = SAError!14, + + /// No such device. + noSuchDevice = NativeError!(19, 20), + + /// An invalid argument was supplied. + invalidArgument = SAError!22, + + /// The limit on the number of open file descriptors. + tooManyDescriptors = NativeError!(23, 331), + + /// The limit on the number of open file descriptors. + noDescriptors = SAError!24, + + /// Broken pipe. + brokenPipe = NativeError!(32, 109), + + /// The name was too long. + nameTooLong = SAError!(36, 63), + + /// A socket operation was attempted on a non-socket. + notSocket = SAError!(88, 38), + + /// Protocol error. + protocolError = eProtocolError, + + /// Message too long. + messageTooLong = SAError!(90, 40), + + /// Wrong protocol type for socket. + wrongProtocolType = SAError!(91, 41), + + /// Protocol not available. + noProtocolOption = SAError!(92, 42), + + /// The protocol is not implemented or has not been configured. + protocolNotSupported = SAError!(93, 43), + + /// The support for the specified socket type does not exist in this + /// address family. + socketNotSupported = SAError!(94, 44), + + /// The address family is no supported by the protocol family. + operationNotSupported = SAError!(95, 45), + + /// Address family specified is not supported. + addressFamilyNotSupported = SAError!(97, 47), + + /// Address already in use. + addressInUse = SAError!(98, 48), + + /// The network is not available. + networkDown = SAError!(100, 50), + + /// No route to host. + networkUnreachable = SAError!(101, 51), + + /// Network dropped connection because of reset. + networkReset = SAError!(102, 52), + + /// The connection has been aborted. + connectionAborted = SAError!(103, 53), + + /// Connection reset by peer. + connectionReset = SAError!(104, 54), + + /// No free buffer space is available for a socket operation. + noBufferSpace = SAError!(105, 55), + + /// Transport endpoint is already connected. + alreadyConnected = SAError!(106, 56), + + /// Transport endpoint is not connected. + notConnected = SAError!(107, 57), + + /// Cannot send after transport endpoint shutdown. + shutdown = SAError!(108, 58), + + /// The connection attempt timed out, or the connected host has failed + /// to respond. + timedOut = SAError!(110, 60), + + /// Connection refused. + connectionRefused = SAError!(111, 61), + + /// Host is down. + hostDown = SAError!(112, 64), + + /// No route to host. + hostUnreachable = SAError!(113, 65), + + /// Operation already in progress. + alreadyStarted = SAError!(114, 37), + + /// Operation now in progress. + inProgress = SAError!(115, 36), + + /// Operation cancelled. + cancelled = SAError!(125, 103), + } + + /** + * Error descriptions. + */ + private enum ErrorStr : string + { + success = "The operation completed successfully", + noPermission = "Operation not permitted", + interrupted = "Interrupted system call", + badDescriptor = "Bad file descriptor", + wouldBlock = "An operation on a non-blocking socket would block", + noMemory = "Out of memory", + accessDenied = "Access denied", + fault = "An invalid pointer address detected", + noSuchDevice = "No such device", + invalidArgument = "An invalid argument was supplied", + tooManyDescriptors = "The limit on the number of open file descriptors", + noDescriptors = "The limit on the number of open file descriptors", + brokenPipe = "Broken pipe", + nameTooLong = "The name was too long", + notSocket = "A socket operation was attempted on a non-socket", + protocolError = "Protocol error", + messageTooLong = "Message too long", + wrongProtocolType = "Wrong protocol type for socket", + noProtocolOption = "Protocol not available", + protocolNotSupported = "The protocol is not implemented or has not been configured", + socketNotSupported = "Socket type not supported", + operationNotSupported = "The address family is no supported by the protocol family", + addressFamilyNotSupported = "Address family specified is not supported", + addressInUse = "Address already in use", + networkDown = "The network is not available", + networkUnreachable = "No route to host", + networkReset = "Network dropped connection because of reset", + connectionAborted = "The connection has been aborted", + connectionReset = "Connection reset by peer", + noBufferSpace = "No free buffer space is available for a socket operation", + alreadyConnected = "Transport endpoint is already connected", + notConnected = "Transport endpoint is not connected", + shutdown = "Cannot send after transport endpoint shutdown", + timedOut = "Operation timed out", + connectionRefused = "Connection refused", + hostDown = "Host is down", + hostUnreachable = "No route to host", + alreadyStarted = "Operation already in progress", + inProgress = "Operation now in progress", + cancelled = "Operation cancelled", + } + + /** + * Constructor. + * + * Params: + * value = Numeric error code. + */ + this(const ErrorNo value) @nogc nothrow pure @safe + { + this.value_ = value; + } + + /// + @nogc nothrow pure @safe unittest + { + ErrorCode ec; + assert(ec == ErrorCode.success); + + ec = ErrorCode.fault; + assert(ec == ErrorCode.fault); + } + + /** + * Resets this $(D_PSYMBOL ErrorCode) to default + * ($(D_PSYMBOL ErrorCode.success)). + */ + void reset() @nogc nothrow pure @safe + { + this.value_ = ErrorNo.success; + } + + /// + @nogc nothrow pure @safe unittest + { + auto ec = ErrorCode(ErrorCode.fault); + assert(ec == ErrorCode.fault); + + ec.reset(); + assert(ec == ErrorCode.success); + } + + /** + * Returns: Numeric error code. + */ + ErrorNo opCast(T : ErrorNo)() const + { + return this.value_; + } + + /// ditto + ErrorNo opCast(T : int)() const + { + return this.value_; + } + + /// + @nogc nothrow pure @safe unittest + { + ErrorCode ec = ErrorCode.fault; + auto errorNo = cast(ErrorCode.ErrorNo) ec; + + assert(errorNo == ErrorCode.fault); + static assert(is(typeof(cast(int) ec))); + } + + /** + * Assigns another error code or error code number. + * + * Params: + * that = Numeric error code. + * + * Returns: $(D_KEYWORD this). + */ + ref ErrorCode opAssign(const ErrorNo that) return @nogc nothrow pure @safe + { + this.value_ = that; + return this; + } + + /// ditto + ref ErrorCode opAssign(const ErrorCode that) return @nogc nothrow pure @safe + { + this.value_ = that.value_; + return this; + } + + /// + @nogc nothrow pure @safe unittest + { + ErrorCode ec; + assert(ec == ErrorCode.success); + + ec = ErrorCode.fault; + assert(ec == ErrorCode.fault); + } + + /// + @nogc nothrow pure @safe unittest + { + auto ec1 = ErrorCode(ErrorCode.fault); + ErrorCode ec2; + assert(ec2 == ErrorCode.success); + + ec2 = ec1; + assert(ec1 == ec2); + } + + /** + * Equality with another error code or error code number. + * + * Params: + * that = Numeric error code. + * + * Returns: Whether $(D_KEYWORD this) and $(D_PARAM that) are equal. + */ + bool opEquals(const ErrorNo that) const @nogc nothrow pure @safe + { + return this.value_ == that; + } + + /// ditto + bool opEquals(const ErrorCode that) const @nogc nothrow pure @safe + { + return this.value_ == that.value_; + } + + /// + @nogc nothrow pure @safe unittest + { + ErrorCode ec1 = ErrorCode.fault; + ErrorCode ec2 = ErrorCode.accessDenied; + + assert(ec1 != ec2); + assert(ec1 != ErrorCode.accessDenied); + assert(ErrorCode.fault != ec2); + } + + /// + @nogc nothrow pure @safe unittest + { + ErrorCode ec1 = ErrorCode.fault; + ErrorCode ec2 = ErrorCode.fault; + + assert(ec1 == ec2); + assert(ec1 == ErrorCode.fault); + assert(ErrorCode.fault == ec2); + } + + /** + * Returns string describing the error number. If a description for a + * specific error number is not available, returns $(D_KEYWORD null). + * + * Returns: String describing the error number. + */ + string toString() const @nogc nothrow pure @safe + { + foreach (e; __traits(allMembers, ErrorNo)) + { + if (__traits(getMember, ErrorNo, e) == this.value_) + { + return __traits(getMember, ErrorStr, e); + } + } + return null; + } + + /// + @nogc nothrow pure @safe unittest + { + ErrorCode ec = ErrorCode.fault; + assert(ec.toString() == "An invalid pointer address detected"); + } + + private ErrorNo value_ = ErrorNo.success; + + alias ErrorNo this; +} diff --git a/middle/tanya/os/package.d b/middle/tanya/os/package.d new file mode 100644 index 0000000..9b81c18 --- /dev/null +++ b/middle/tanya/os/package.d @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This package provides platform-independent interfaces to operating system + * functionality. + * + * Copyright: Eugene Wissner 2017-2025. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/os/tanya/os/package.d, + * tanya/os/package.d) + */ +module tanya.os; + +public import tanya.os.error; diff --git a/os/dub.json b/os/dub.json deleted file mode 100644 index 18fe17a..0000000 --- a/os/dub.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "os", - "description": "Platform-independent interfaces to operating system functionality", - "targetType": "library", - - "dependencies": { - "tanya:meta": "*" - }, - - "sourcePaths": [ - "." - ], - "importPaths": [ - "." - ], - "dflags-dmd": ["-dip1000"] -} diff --git a/os/tanya/os/error.d b/os/tanya/os/error.d deleted file mode 100644 index 3268a8a..0000000 --- a/os/tanya/os/error.d +++ /dev/null @@ -1,413 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * This module provides a portable way of using operating system error codes. - * - * Copyright: Eugene Wissner 2017-2025. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/os/tanya/os/error.d, - * tanya/os/error.d) - */ -module tanya.os.error; - -import tanya.meta.trait; - -// Socket API error. -private template SAError(int posix, int wsa = posix) -{ - version (Windows) - { - enum SAError = 10000 + wsa; - } - else - { - alias SAError = posix; - } -} - -// Error for Windows and Posix separately. -private template NativeError(int posix, int win) -{ - version (Windows) - { - alias NativeError = win; - } - else - { - alias NativeError = posix; - } -} - -version (Windows) -{ - private enum eProtocolError = -71; -} -else version (OpenBSD) -{ - private enum eProtocolError = -71; -} -else -{ - private enum eProtocolError = 71; -} - -/** - * System error code. - */ -struct ErrorCode -{ - /** - * Error code numbers. - */ - enum ErrorNo : int - { - /// The operation completed successfully. - success = 0, - - /// Operation not permitted. - noPermission = NativeError!(1, 5), - - /// Interrupted system call. - interrupted = SAError!4, - - /// Bad file descriptor. - badDescriptor = SAError!9, - - /// An operation on a non-blocking socket would block. - wouldBlock = SAError!(11, 35), - - /// Out of memory. - noMemory = NativeError!(12, 14), - - /// Access denied. - accessDenied = SAError!13, - - /// An invalid pointer address detected. - fault = SAError!14, - - /// No such device. - noSuchDevice = NativeError!(19, 20), - - /// An invalid argument was supplied. - invalidArgument = SAError!22, - - /// The limit on the number of open file descriptors. - tooManyDescriptors = NativeError!(23, 331), - - /// The limit on the number of open file descriptors. - noDescriptors = SAError!24, - - /// Broken pipe. - brokenPipe = NativeError!(32, 109), - - /// The name was too long. - nameTooLong = SAError!(36, 63), - - /// A socket operation was attempted on a non-socket. - notSocket = SAError!(88, 38), - - /// Protocol error. - protocolError = eProtocolError, - - /// Message too long. - messageTooLong = SAError!(90, 40), - - /// Wrong protocol type for socket. - wrongProtocolType = SAError!(91, 41), - - /// Protocol not available. - noProtocolOption = SAError!(92, 42), - - /// The protocol is not implemented or has not been configured. - protocolNotSupported = SAError!(93, 43), - - /// The support for the specified socket type does not exist in this - /// address family. - socketNotSupported = SAError!(94, 44), - - /// The address family is no supported by the protocol family. - operationNotSupported = SAError!(95, 45), - - /// Address family specified is not supported. - addressFamilyNotSupported = SAError!(97, 47), - - /// Address already in use. - addressInUse = SAError!(98, 48), - - /// The network is not available. - networkDown = SAError!(100, 50), - - /// No route to host. - networkUnreachable = SAError!(101, 51), - - /// Network dropped connection because of reset. - networkReset = SAError!(102, 52), - - /// The connection has been aborted. - connectionAborted = SAError!(103, 53), - - /// Connection reset by peer. - connectionReset = SAError!(104, 54), - - /// No free buffer space is available for a socket operation. - noBufferSpace = SAError!(105, 55), - - /// Transport endpoint is already connected. - alreadyConnected = SAError!(106, 56), - - /// Transport endpoint is not connected. - notConnected = SAError!(107, 57), - - /// Cannot send after transport endpoint shutdown. - shutdown = SAError!(108, 58), - - /// The connection attempt timed out, or the connected host has failed - /// to respond. - timedOut = SAError!(110, 60), - - /// Connection refused. - connectionRefused = SAError!(111, 61), - - /// Host is down. - hostDown = SAError!(112, 64), - - /// No route to host. - hostUnreachable = SAError!(113, 65), - - /// Operation already in progress. - alreadyStarted = SAError!(114, 37), - - /// Operation now in progress. - inProgress = SAError!(115, 36), - - /// Operation cancelled. - cancelled = SAError!(125, 103), - } - - /** - * Error descriptions. - */ - private enum ErrorStr : string - { - success = "The operation completed successfully", - noPermission = "Operation not permitted", - interrupted = "Interrupted system call", - badDescriptor = "Bad file descriptor", - wouldBlock = "An operation on a non-blocking socket would block", - noMemory = "Out of memory", - accessDenied = "Access denied", - fault = "An invalid pointer address detected", - noSuchDevice = "No such device", - invalidArgument = "An invalid argument was supplied", - tooManyDescriptors = "The limit on the number of open file descriptors", - noDescriptors = "The limit on the number of open file descriptors", - brokenPipe = "Broken pipe", - nameTooLong = "The name was too long", - notSocket = "A socket operation was attempted on a non-socket", - protocolError = "Protocol error", - messageTooLong = "Message too long", - wrongProtocolType = "Wrong protocol type for socket", - noProtocolOption = "Protocol not available", - protocolNotSupported = "The protocol is not implemented or has not been configured", - socketNotSupported = "Socket type not supported", - operationNotSupported = "The address family is no supported by the protocol family", - addressFamilyNotSupported = "Address family specified is not supported", - addressInUse = "Address already in use", - networkDown = "The network is not available", - networkUnreachable = "No route to host", - networkReset = "Network dropped connection because of reset", - connectionAborted = "The connection has been aborted", - connectionReset = "Connection reset by peer", - noBufferSpace = "No free buffer space is available for a socket operation", - alreadyConnected = "Transport endpoint is already connected", - notConnected = "Transport endpoint is not connected", - shutdown = "Cannot send after transport endpoint shutdown", - timedOut = "Operation timed out", - connectionRefused = "Connection refused", - hostDown = "Host is down", - hostUnreachable = "No route to host", - alreadyStarted = "Operation already in progress", - inProgress = "Operation now in progress", - cancelled = "Operation cancelled", - } - - /** - * Constructor. - * - * Params: - * value = Numeric error code. - */ - this(const ErrorNo value) @nogc nothrow pure @safe - { - this.value_ = value; - } - - /// - @nogc nothrow pure @safe unittest - { - ErrorCode ec; - assert(ec == ErrorCode.success); - - ec = ErrorCode.fault; - assert(ec == ErrorCode.fault); - } - - /** - * Resets this $(D_PSYMBOL ErrorCode) to default - * ($(D_PSYMBOL ErrorCode.success)). - */ - void reset() @nogc nothrow pure @safe - { - this.value_ = ErrorNo.success; - } - - /// - @nogc nothrow pure @safe unittest - { - auto ec = ErrorCode(ErrorCode.fault); - assert(ec == ErrorCode.fault); - - ec.reset(); - assert(ec == ErrorCode.success); - } - - /** - * Returns: Numeric error code. - */ - ErrorNo opCast(T : ErrorNo)() const - { - return this.value_; - } - - /// ditto - ErrorNo opCast(T : int)() const - { - return this.value_; - } - - /// - @nogc nothrow pure @safe unittest - { - ErrorCode ec = ErrorCode.fault; - auto errorNo = cast(ErrorCode.ErrorNo) ec; - - assert(errorNo == ErrorCode.fault); - static assert(is(typeof(cast(int) ec))); - } - - /** - * Assigns another error code or error code number. - * - * Params: - * that = Numeric error code. - * - * Returns: $(D_KEYWORD this). - */ - ref ErrorCode opAssign(const ErrorNo that) return @nogc nothrow pure @safe - { - this.value_ = that; - return this; - } - - /// ditto - ref ErrorCode opAssign(const ErrorCode that) return @nogc nothrow pure @safe - { - this.value_ = that.value_; - return this; - } - - /// - @nogc nothrow pure @safe unittest - { - ErrorCode ec; - assert(ec == ErrorCode.success); - - ec = ErrorCode.fault; - assert(ec == ErrorCode.fault); - } - - /// - @nogc nothrow pure @safe unittest - { - auto ec1 = ErrorCode(ErrorCode.fault); - ErrorCode ec2; - assert(ec2 == ErrorCode.success); - - ec2 = ec1; - assert(ec1 == ec2); - } - - /** - * Equality with another error code or error code number. - * - * Params: - * that = Numeric error code. - * - * Returns: Whether $(D_KEYWORD this) and $(D_PARAM that) are equal. - */ - bool opEquals(const ErrorNo that) const @nogc nothrow pure @safe - { - return this.value_ == that; - } - - /// ditto - bool opEquals(const ErrorCode that) const @nogc nothrow pure @safe - { - return this.value_ == that.value_; - } - - /// - @nogc nothrow pure @safe unittest - { - ErrorCode ec1 = ErrorCode.fault; - ErrorCode ec2 = ErrorCode.accessDenied; - - assert(ec1 != ec2); - assert(ec1 != ErrorCode.accessDenied); - assert(ErrorCode.fault != ec2); - } - - /// - @nogc nothrow pure @safe unittest - { - ErrorCode ec1 = ErrorCode.fault; - ErrorCode ec2 = ErrorCode.fault; - - assert(ec1 == ec2); - assert(ec1 == ErrorCode.fault); - assert(ErrorCode.fault == ec2); - } - - /** - * Returns string describing the error number. If a description for a - * specific error number is not available, returns $(D_KEYWORD null). - * - * Returns: String describing the error number. - */ - string toString() const @nogc nothrow pure @safe - { - foreach (e; __traits(allMembers, ErrorNo)) - { - if (__traits(getMember, ErrorNo, e) == this.value_) - { - return __traits(getMember, ErrorStr, e); - } - } - return null; - } - - /// - @nogc nothrow pure @safe unittest - { - ErrorCode ec = ErrorCode.fault; - assert(ec.toString() == "An invalid pointer address detected"); - } - - private ErrorNo value_ = ErrorNo.success; - - alias ErrorNo this; -} diff --git a/os/tanya/os/package.d b/os/tanya/os/package.d deleted file mode 100644 index 9b81c18..0000000 --- a/os/tanya/os/package.d +++ /dev/null @@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * This package provides platform-independent interfaces to operating system - * functionality. - * - * Copyright: Eugene Wissner 2017-2025. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/os/tanya/os/package.d, - * tanya/os/package.d) - */ -module tanya.os; - -public import tanya.os.error; diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d index 41c5f8b..df1027d 100644 --- a/source/tanya/algorithm/iteration.d +++ b/source/tanya/algorithm/iteration.d @@ -20,10 +20,10 @@ */ module tanya.algorithm.iteration; -import std.traits : Unqual, isMutable; +import std.traits; import std.typecons; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; import tanya.range; private struct SingletonByValue(E) diff --git a/source/tanya/algorithm/mutation.d b/source/tanya/algorithm/mutation.d index e1e7c22..1a1bb56 100644 --- a/source/tanya/algorithm/mutation.d +++ b/source/tanya/algorithm/mutation.d @@ -14,11 +14,10 @@ */ module tanya.algorithm.mutation; -import std.traits : Unqual, hasElaborateAssign, hasElaborateCopyConstructor, hasElaborateDestructor, isAssignable, - isDynamicArray; +import std.traits; static import tanya.memory.lifetime; static import tanya.memory.op; -import tanya.meta.trait; +import tanya.meta; import tanya.range; /** diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d index b3b3455..b6c9c5d 100644 --- a/source/tanya/container/array.d +++ b/source/tanya/container/array.d @@ -18,11 +18,11 @@ import core.checkedint; import std.algorithm.comparison; import std.algorithm.iteration; import std.algorithm.mutation : bringToFront; -import std.traits : PointerTarget, Unqual, hasElaborateDestructor, isImplicitlyConvertible, isCopyable; +import std.traits; import tanya.algorithm.mutation; import tanya.memory.allocator; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; import tanya.range; /** diff --git a/source/tanya/container/buffer.d b/source/tanya/container/buffer.d index 35d83a5..ec8cbf0 100644 --- a/source/tanya/container/buffer.d +++ b/source/tanya/container/buffer.d @@ -16,7 +16,7 @@ module tanya.container.buffer; import std.traits : isScalarType; import tanya.memory.allocator; -import tanya.meta.trait; +import tanya.meta; version (unittest) { diff --git a/source/tanya/container/entry.d b/source/tanya/container/entry.d index 52b3e6a..c4d74c2 100644 --- a/source/tanya/container/entry.d +++ b/source/tanya/container/entry.d @@ -14,11 +14,11 @@ */ module tanya.container.entry; -import std.traits : Unqual, hasElaborateDestructor; +import std.traits; import tanya.container.array; import tanya.memory.allocator; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; package struct SEntry(T) { diff --git a/source/tanya/container/hashtable.d b/source/tanya/container/hashtable.d index d74783c..5e9a4e4 100644 --- a/source/tanya/container/hashtable.d +++ b/source/tanya/container/hashtable.d @@ -15,14 +15,14 @@ module tanya.container.hashtable; import std.algorithm.iteration; -import std.traits : CopyConstness, Unqual, ifTestable, isMutable; +import std.traits; import tanya.algorithm.mutation; import tanya.container.array; import tanya.container.entry; import tanya.hash.lookup; import tanya.memory.allocator; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; import tanya.range.primitive; /** diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d index 23af88d..ddef391 100644 --- a/source/tanya/container/list.d +++ b/source/tanya/container/list.d @@ -17,11 +17,11 @@ module tanya.container.list; import std.algorithm.comparison; import std.algorithm.iteration; -import std.traits : Unqual, isImplicitlyConvertible, isCopyable; +import std.traits; import tanya.container.entry; import tanya.memory.allocator; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; import tanya.range.array; import tanya.range.primitive; diff --git a/source/tanya/container/set.d b/source/tanya/container/set.d index 67fc66a..5a4f64c 100644 --- a/source/tanya/container/set.d +++ b/source/tanya/container/set.d @@ -15,13 +15,13 @@ */ module tanya.container.set; -import std.traits : CopyConstness, Unqual, ifTestable, isImplicitlyConvertible, isMutable; +import std.traits; import tanya.container.array; import tanya.container.entry; import tanya.hash.lookup; import tanya.memory.allocator; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; import tanya.range.primitive; /** diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d index 71328f2..10db553 100644 --- a/source/tanya/container/string.d +++ b/source/tanya/container/string.d @@ -28,12 +28,12 @@ module tanya.container.string; import std.algorithm.comparison; import std.algorithm.mutation : bringToFront; -import std.traits : CopyConstness, Unqual, isInstanceOf, isSomeChar, isNarrowString; +import std.traits; import tanya.algorithm.mutation; import tanya.hash.lookup; import tanya.memory.allocator; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; import tanya.range.array; import tanya.range.primitive; diff --git a/source/tanya/conv.d b/source/tanya/conv.d index 8f46bd3..3a75d62 100644 --- a/source/tanya/conv.d +++ b/source/tanya/conv.d @@ -14,11 +14,10 @@ */ module tanya.conv; -import std.traits : Unsigned, isNumeric, Largest, Unqual, EnumMembers, isFloatingPoint, isSomeChar, isSigned, - isUnsigned, isIntegral, isSomeString; +import std.traits; import tanya.container.string; import tanya.memory.allocator; -import tanya.meta.trait; +import tanya.meta; import tanya.range; /** diff --git a/source/tanya/format.d b/source/tanya/format.d index 0b031d1..089ed49 100644 --- a/source/tanya/format.d +++ b/source/tanya/format.d @@ -49,12 +49,13 @@ module tanya.format; import std.algorithm.comparison; import std.ascii; -import std.traits : Unqual, isPointer, isSomeChar, isFloatingPoint, isSomeFunction, isIntegral, isSomeString; +import std.math : signbit; +import std.meta; +import std.traits; import tanya.container.string; import tanya.math; static import tanya.memory.op; -import tanya.meta.metafunction; -import tanya.meta.trait; +import tanya.meta; import tanya.range; // Returns the last part of buffer with converted number. @@ -1952,7 +1953,7 @@ private const(char)[] real2String(double value, const FloatBits!double bits = { value }; exponent = (bits.integral >> 52) & 0x7ff; - sign = signBit(value); + sign = !!signbit(value); if (sign) { value = -value; diff --git a/source/tanya/hash/lookup.d b/source/tanya/hash/lookup.d index 706cca5..eb26caa 100644 --- a/source/tanya/hash/lookup.d +++ b/source/tanya/hash/lookup.d @@ -14,8 +14,8 @@ */ module tanya.hash.lookup; -import std.traits : isScalarType, isPointer, isSomeChar, isArray, isIntegral, isBoolean; -import tanya.meta.trait; +import std.traits; +import tanya.meta; import tanya.range.primitive; private struct Hasher diff --git a/source/tanya/math/package.d b/source/tanya/math/package.d index ef0592e..66923b6 100644 --- a/source/tanya/math/package.d +++ b/source/tanya/math/package.d @@ -22,8 +22,8 @@ module tanya.math; import std.math; -import std.traits : Unqual, isFloatingPoint; -import tanya.meta.trait; +import std.traits; +import tanya.meta; /// Floating-point number precisions according to IEEE-754. enum IEEEPrecision : ubyte @@ -113,433 +113,3 @@ package(tanya) union FloatBits(F) static assert(false, "Unsupported IEEE 754 floating point precision"); } } - -/** - * Floating-point number classifications. - */ -enum FloatingPointClass : ubyte -{ - /** - * Not a Number. - * - * See_Also: $(D_PSYMBOL isNaN). - */ - nan, - - /// Zero. - zero, - - /** - * Infinity. - * - * See_Also: $(D_PSYMBOL isInfinity). - */ - infinite, - - /** - * Denormalized number. - * - * See_Also: $(D_PSYMBOL isSubnormal). - */ - subnormal, - - /** - * Normalized number. - * - * See_Also: $(D_PSYMBOL isNormal). - */ - normal, -} - -/** - * Returns whether $(D_PARAM x) is a NaN, zero, infinity, subnormal or - * normalized number. - * - * This function doesn't distinguish between negative and positive infinity, - * negative and positive NaN or negative and positive zero. - * - * Params: - * F = Type of the floating point number. - * x = Floating point number. - * - * Returns: Classification of $(D_PARAM x). - */ -FloatingPointClass classify(F)(F x) -if (isFloatingPoint!F) -{ - if (x == 0) - { - return FloatingPointClass.zero; - } - FloatBits!F bits; - bits.floating = abs(x); - - static if (ieeePrecision!F == IEEEPrecision.single) - { - if (bits.integral > bits.expMask) - { - return FloatingPointClass.nan; - } - else if (bits.integral == bits.expMask) - { - return FloatingPointClass.infinite; - } - else if (bits.integral < (1 << 23)) - { - return FloatingPointClass.subnormal; - } - } - else static if (ieeePrecision!F == IEEEPrecision.double_) - { - if (bits.integral > bits.expMask) - { - return FloatingPointClass.nan; - } - else if (bits.integral == bits.expMask) - { - return FloatingPointClass.infinite; - } - else if (bits.integral < (1L << 52)) - { - return FloatingPointClass.subnormal; - } - } - else static if (ieeePrecision!F == IEEEPrecision.doubleExtended) - { - if (bits.exp == bits.expMask) - { - if ((bits.mantissa & bits.mantissaMask) == 0) - { - return FloatingPointClass.infinite; - } - else - { - return FloatingPointClass.nan; - } - } - else if (bits.exp == 0) - { - return FloatingPointClass.subnormal; - } - else if (bits.mantissa < (1L << 63)) // "Unnormal". - { - return FloatingPointClass.nan; - } - } - - return FloatingPointClass.normal; -} - -/// -@nogc nothrow pure @safe unittest -{ - assert(classify(0.0) == FloatingPointClass.zero); - assert(classify(double.nan) == FloatingPointClass.nan); - assert(classify(double.infinity) == FloatingPointClass.infinite); - assert(classify(-double.infinity) == FloatingPointClass.infinite); - assert(classify(1.4) == FloatingPointClass.normal); - assert(classify(1.11254e-307 / 10) == FloatingPointClass.subnormal); - - assert(classify(0.0f) == FloatingPointClass.zero); - assert(classify(float.nan) == FloatingPointClass.nan); - assert(classify(float.infinity) == FloatingPointClass.infinite); - assert(classify(-float.infinity) == FloatingPointClass.infinite); - assert(classify(0.3) == FloatingPointClass.normal); - assert(classify(5.87747e-38f / 10) == FloatingPointClass.subnormal); - - assert(classify(0.0L) == FloatingPointClass.zero); - assert(classify(real.nan) == FloatingPointClass.nan); - assert(classify(real.infinity) == FloatingPointClass.infinite); - assert(classify(-real.infinity) == FloatingPointClass.infinite); -} - -/** - * Determines whether $(D_PARAM x) is a finite number. - * - * Params: - * F = Type of the floating point number. - * x = Floating point number. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM x) is a finite number, - * $(D_KEYWORD false) otherwise. - * - * See_Also: $(D_PSYMBOL isInfinity). - */ -bool isFinite(F)(F x) -if (isFloatingPoint!F) -{ - FloatBits!F bits; - static if (ieeePrecision!F == IEEEPrecision.single - || ieeePrecision!F == IEEEPrecision.double_) - { - bits.floating = x; - bits.integral &= bits.expMask; - return bits.integral != bits.expMask; - } - else static if (ieeePrecision!F == IEEEPrecision.doubleExtended) - { - bits.floating = abs(x); - return (bits.exp != bits.expMask) - && (bits.exp == 0 || bits.mantissa >= (1L << 63)); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - assert(!isFinite(float.infinity)); - assert(!isFinite(-double.infinity)); - assert(isFinite(0.0)); - assert(!isFinite(float.nan)); - assert(isFinite(5.87747e-38f / 10)); - assert(isFinite(1.11254e-307 / 10)); - assert(isFinite(0.5)); -} - -/** - * Determines whether $(D_PARAM x) is $(B n)ot $(B a) $(B n)umber (NaN). - * - * Params: - * F = Type of the floating point number. - * x = Floating point number. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM x) is not a number, - * $(D_KEYWORD false) otherwise. - */ -bool isNaN(F)(F x) -if (isFloatingPoint!F) -{ - FloatBits!F bits; - bits.floating = abs(x); - - static if (ieeePrecision!F == IEEEPrecision.single - || ieeePrecision!F == IEEEPrecision.double_) - { - return bits.integral > bits.expMask; - } - else static if (ieeePrecision!F == IEEEPrecision.doubleExtended) - { - const maskedMantissa = bits.mantissa & bits.mantissaMask; - if ((bits.exp == bits.expMask && maskedMantissa != 0) - || ((bits.exp != 0) && (bits.mantissa < (1L << 63)))) - { - return true; - } - return false; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - assert(isNaN(float.init)); - assert(isNaN(double.init)); - assert(isNaN(real.init)); -} - -/** - * Determines whether $(D_PARAM x) is a positive or negative infinity. - * - * Params: - * F = Type of the floating point number. - * x = Floating point number. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM x) is infinity, $(D_KEYWORD false) - * otherwise. - * - * See_Also: $(D_PSYMBOL isFinite). - */ -bool isInfinity(F)(F x) -if (isFloatingPoint!F) -{ - FloatBits!F bits; - bits.floating = abs(x); - static if (ieeePrecision!F == IEEEPrecision.single - || ieeePrecision!F == IEEEPrecision.double_) - { - return bits.integral == bits.expMask; - } - else static if (ieeePrecision!F == IEEEPrecision.doubleExtended) - { - return (bits.exp == bits.expMask) - && ((bits.mantissa & bits.mantissaMask) == 0); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - assert(isInfinity(float.infinity)); - assert(isInfinity(-float.infinity)); - assert(isInfinity(double.infinity)); - assert(isInfinity(-double.infinity)); - assert(isInfinity(real.infinity)); - assert(isInfinity(-real.infinity)); -} - -/** - * Determines whether $(D_PARAM x) is a denormilized number or not. - * - * Denormalized number is a number between `0` and `1` that cannot be - * represented as - * - *
- * m*2e
- * 
- * - * where $(I m) is the mantissa and $(I e) is an exponent that fits into the - * exponent field of the type $(D_PARAM F). - * - * `0` is neither normalized nor denormalized. - * - * Params: - * F = Type of the floating point number. - * x = Floating point number. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM x) is a denormilized number, - * $(D_KEYWORD false) otherwise. - * - * See_Also: $(D_PSYMBOL isNormal). - */ -bool isSubnormal(F)(F x) -if (isFloatingPoint!F) -{ - FloatBits!F bits; - bits.floating = abs(x); - static if (ieeePrecision!F == IEEEPrecision.single) - { - return bits.integral < (1 << 23) && bits.integral > 0; - } - else static if (ieeePrecision!F == IEEEPrecision.double_) - { - return bits.integral < (1L << 52) && bits.integral > 0; - } - else static if (ieeePrecision!F == IEEEPrecision.doubleExtended) - { - return bits.exp == 0 && bits.mantissa != 0; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - assert(!isSubnormal(0.0f)); - assert(!isSubnormal(float.nan)); - assert(!isSubnormal(float.infinity)); - assert(!isSubnormal(0.3f)); - assert(isSubnormal(5.87747e-38f / 10)); - - assert(!isSubnormal(0.0)); - assert(!isSubnormal(double.nan)); - assert(!isSubnormal(double.infinity)); - assert(!isSubnormal(1.4)); - assert(isSubnormal(1.11254e-307 / 10)); - - assert(!isSubnormal(0.0L)); - assert(!isSubnormal(real.nan)); - assert(!isSubnormal(real.infinity)); -} - -/** - * Determines whether $(D_PARAM x) is a normilized number or not. - * - * Normalized number is a number that can be represented as - * - *
- * m*2e
- * 
- * - * where $(I m) is the mantissa and $(I e) is an exponent that fits into the - * exponent field of the type $(D_PARAM F). - * - * `0` is neither normalized nor denormalized. - * - * Params: - * F = Type of the floating point number. - * x = Floating point number. - * - * Returns: $(D_KEYWORD true) if $(D_PARAM x) is a normilized number, - * $(D_KEYWORD false) otherwise. - * - * See_Also: $(D_PSYMBOL isSubnormal). - */ -bool isNormal(F)(F x) -if (isFloatingPoint!F) -{ - static if (ieeePrecision!F == IEEEPrecision.single - || ieeePrecision!F == IEEEPrecision.double_) - { - FloatBits!F bits; - bits.floating = x; - bits.integral &= bits.expMask; - return bits.integral != 0 && bits.integral != bits.expMask; - } - else static if (ieeePrecision!F == IEEEPrecision.doubleExtended) - { - return classify(x) == FloatingPointClass.normal; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - assert(!isNormal(0.0f)); - assert(!isNormal(float.nan)); - assert(!isNormal(float.infinity)); - assert(isNormal(0.3f)); - assert(!isNormal(5.87747e-38f / 10)); - - assert(!isNormal(0.0)); - assert(!isNormal(double.nan)); - assert(!isNormal(double.infinity)); - assert(isNormal(1.4)); - assert(!isNormal(1.11254e-307 / 10)); - - assert(!isNormal(0.0L)); - assert(!isNormal(real.nan)); - assert(!isNormal(real.infinity)); -} - -/** - * Determines whether the sign bit of $(D_PARAM x) is set or not. - * - * If the sign bit, $(D_PARAM x) is a negative number, otherwise positive. - * - * Params: - * F = Type of the floating point number. - * x = Floating point number. - * - * Returns: $(D_KEYWORD true) if the sign bit of $(D_PARAM x) is set, - * $(D_KEYWORD false) otherwise. - */ -bool signBit(F)(F x) -if (isFloatingPoint!F) -{ - FloatBits!F bits; - bits.floating = x; - static if (ieeePrecision!F == IEEEPrecision.single) - { - return (bits.integral & (1 << 31)) != 0; - } - else static if (ieeePrecision!F == IEEEPrecision.double_) - { - return (bits.integral & (1L << 63)) != 0; - } - else static if (ieeePrecision!F == IEEEPrecision.doubleExtended) - { - return (bits.exp & (1 << 15)) != 0; - } -} - -/// -@nogc nothrow pure @safe unittest -{ - assert(signBit(-1.0f)); - assert(!signBit(1.0f)); - - assert(signBit(-1.0)); - assert(!signBit(1.0)); - - assert(signBit(-1.0L)); - assert(!signBit(1.0L)); -} diff --git a/source/tanya/net/iface.d b/source/tanya/net/iface.d index 8443cb4..c910b29 100644 --- a/source/tanya/net/iface.d +++ b/source/tanya/net/iface.d @@ -14,10 +14,10 @@ */ module tanya.net.iface; -import std.traits : Unqual; +import std.traits; import tanya.algorithm.mutation; import tanya.container.string; -import tanya.meta.trait; +import tanya.meta; import tanya.range; version (Windows) diff --git a/source/tanya/net/inet.d b/source/tanya/net/inet.d index 314a90c..141fd77 100644 --- a/source/tanya/net/inet.d +++ b/source/tanya/net/inet.d @@ -14,8 +14,8 @@ */ module tanya.net.inet; -import std.traits : Unqual, isUnsigned; -import tanya.meta.trait; +import std.traits; +import tanya.meta; import tanya.range; /** diff --git a/source/tanya/net/ip.d b/source/tanya/net/ip.d index 73ef23d..87268bd 100644 --- a/source/tanya/net/ip.d +++ b/source/tanya/net/ip.d @@ -18,14 +18,14 @@ import std.algorithm.comparison; import std.ascii; import std.sumtype; import std.typecons; -import std.traits : Unqual; +import std.traits; import tanya.algorithm.iteration; import tanya.algorithm.mutation; import tanya.container.string; import tanya.conv; import tanya.format; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; import tanya.net.iface; import tanya.net.inet; import tanya.range; diff --git a/source/tanya/range/adapter.d b/source/tanya/range/adapter.d index d30b24c..287e868 100644 --- a/source/tanya/range/adapter.d +++ b/source/tanya/range/adapter.d @@ -14,10 +14,10 @@ */ module tanya.range.adapter; -import std.traits : hasMember, isArray; +import std.traits; import tanya.algorithm.mutation; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; import tanya.range; private mixin template InserterCtor() diff --git a/source/tanya/range/primitive.d b/source/tanya/range/primitive.d index aa8c0cf..d8abe3d 100644 --- a/source/tanya/range/primitive.d +++ b/source/tanya/range/primitive.d @@ -15,9 +15,9 @@ module tanya.range.primitive; import std.algorithm.comparison; -import std.traits : FunctionAttribute, ReturnType, hasElaborateCopyConstructor, functionAttributes; +import std.traits; import tanya.memory.lifetime; -import tanya.meta.trait; +import tanya.meta; import tanya.range.array; /** diff --git a/source/tanya/test/assertion.d b/source/tanya/test/assertion.d new file mode 100644 index 0000000..9b146c8 --- /dev/null +++ b/source/tanya/test/assertion.d @@ -0,0 +1,106 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Additional assertions. + * + * This module provides functions that assert whether a given expression + * satisfies some complex condition, that can't be tested with + * $(D_KEYWORD assert) in a single line. Internally all the functions + * just evaluate the expression and call $(D_KEYWORD assert). + * + * The functions can cause segmentation fault if the module is compiled + * in production mode and the condition fails. + * + * Copyright: Eugene Wissner 2017-2025. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/assertion.d, + * tanya/test/assertion.d) + */ +module tanya.test.assertion; + +import std.traits; +import tanya.memory.allocator; +import tanya.meta; + +/** + * Asserts whether the function $(D_PARAM expr) throws an exception of type + * $(D_PARAM E). If it does, the exception is catched and properly destroyed. + * If it doesn't, an assertion error is thrown. If the exception doesn't match + * $(D_PARAM E) type, it isn't catched and escapes. + * + * Params: + * E = Expected exception type. + * T = Throwing function type. + * Args = Argument types of the throwing function. + * expr = Throwing function. + * args = Arguments for $(D_PARAM expr). + */ +void assertThrown(E : Exception, T, Args...)(T expr, auto ref Args args) +if (isSomeFunction!T) +{ + try + { + cast(void) expr(args); + assert(false, "Expected exception not thrown"); + } + catch (E exception) + { + defaultAllocator.dispose(exception); + } +} + +/// +@nogc nothrow pure @safe unittest +{ + // If you want to test that an expression throws, you can wrap it into an + // arrow function. + static struct CtorThrows + { + this(int i) @nogc pure @safe + { + throw defaultAllocator.make!Exception(); + } + } + assertThrown!Exception(() => CtorThrows(8)); +} + +/** + * Asserts that the function $(D_PARAM expr) doesn't throw. + * + * If it does, the thrown exception is catched, properly destroyed and an + * assertion error is thrown instead. + * + * Params: + * T = Tested function type. + * Args = Argument types of $(D_PARAM expr). + * expr = Tested function. + * args = Arguments for $(D_PARAM expr). + */ +void assertNotThrown(T, Args...)(T expr, auto ref Args args) +if (isSomeFunction!T) +{ + try + { + cast(void) expr(args); + } + catch (Exception exception) + { + defaultAllocator.dispose(exception); + assert(false, "Unexpected exception thrown"); + } +} + +/// +@nogc nothrow pure @safe unittest +{ + // If you want to test that an expression doesn't throw, you can wrap it + // into an arrow function. + static struct S + { + } + assertNotThrown(() => S()); +} diff --git a/source/tanya/test/package.d b/source/tanya/test/package.d new file mode 100644 index 0000000..f316ddf --- /dev/null +++ b/source/tanya/test/package.d @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Test suite for $(D_KEYWORD unittest)-blocks. + * + * Copyright: Eugene Wissner 2017-2025. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/package.d, + * tanya/test/package.d) + */ +module tanya.test; + +public import tanya.test.assertion; +public import tanya.test.stub; diff --git a/source/tanya/test/stub.d b/source/tanya/test/stub.d new file mode 100644 index 0000000..1741bbb --- /dev/null +++ b/source/tanya/test/stub.d @@ -0,0 +1,397 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Range and generic type generators. + * + * Copyright: Eugene Wissner 2018-2025. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/stub.d, + * tanya/test/stub.d) + */ +module tanya.test.stub; + +/** + * Attribute signalizing that the generated range should contain the given + * number of elements. + * + * $(D_PSYMBOL Count) should be always specified with some value and not as a + * type, so $(D_INLINECODE Count(1)) instead just $(D_INLINECODE Count), + * otherwise you can just omit $(D_PSYMBOL Count) and it will default to 0. + * + * $(D_PSYMBOL Count) doesn't generate `.length` property - use + * $(D_PSYMBOL Length) for that. + * + * If neither $(D_PSYMBOL Length) nor $(D_PSYMBOL Infinite) is given, + * $(D_ILNINECODE Count(0)) is assumed. + * + * This attribute conflicts with $(D_PSYMBOL Infinite) and $(D_PSYMBOL Length). + */ +struct Count +{ + /// Original range length. + size_t count = 0; + + @disable this(); + + /** + * Constructs the attribute with the given length. + * + * Params: + * count = Original range length. + */ + this(size_t count) @nogc nothrow pure @safe + { + this.count = count; + } +} + +/** + * Attribute signalizing that the generated range should be infinite. + * + * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Length). + */ +struct Infinite +{ +} + +/** + * Generates `.length` property for the range. + * + * The length of the range can be specified as a constructor argument, + * otherwise it is 0. + * + * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Infinite). + */ +struct Length +{ + /// Original range length. + size_t length = 0; +} + +/** + * Attribute signalizing that the generated range should return values by + * reference. + * + * This atribute affects the return values of `.front`, `.back` and `[]`. + */ +struct WithLvalueElements +{ +} + +/** + * Generates an input range. + * + * Params: + * E = Element type. + */ +mixin template InputRangeStub(E = int) +{ + import std.traits : hasUDA, getUDAs; + import std.meta : Alias; + + /* + * Aliases for the attribute lookups to access them faster + */ + private enum bool infinite = hasUDA!(typeof(this), Infinite); + private enum bool withLvalueElements = hasUDA!(typeof(this), + WithLvalueElements); + private alias Count = getUDAs!(typeof(this), .Count); + private alias Length = getUDAs!(typeof(this), .Length); + + static if (Count.length != 0) + { + private enum size_t count = Count[0].count; + + static assert (!infinite, + "Range cannot have count and be infinite at the same time"); + static assert (Length.length == 0, + "Range cannot have count and length at the same time"); + } + else static if (Length.length != 0) + { + private enum size_t count = Length[0]().length; + + static assert (!infinite, + "Range cannot have length and be infinite at the same time"); + } + else static if (!infinite) + { + private enum size_t count = 0; + } + + /* + * Member generation + */ + static if (infinite) + { + enum bool empty = false; + } + else + { + private size_t length_ = count; + + @property bool empty() const @nogc nothrow pure @safe + { + return this.length_ == 0; + } + } + + static if (withLvalueElements) + { + private E* element; // Pointer to enable range copying in save() + } + + void popFront() @nogc nothrow pure @safe + in + { + assert(!empty); + } + do + { + static if (!infinite) + { + --this.length_; + } + } + + static if (withLvalueElements) + { + ref E front() @nogc nothrow pure @safe + in + { + assert(!empty); + } + do + { + return *this.element; + } + } + else + { + E front() @nogc nothrow pure @safe + in + { + assert(!empty); + } + do + { + return E.init; + } + } + + static if (Length.length != 0) + { + size_t length() const @nogc nothrow pure @safe + { + return this.length_; + } + } +} + +/** + * Generates a forward range. + * + * This mixin includes input range primitives as well, but can be combined with + * $(D_PSYMBOL RandomAccessRangeStub). + * + * Params: + * E = Element type. + */ +mixin template ForwardRangeStub(E = int) +{ + static if (!is(typeof(this.InputRangeMixin) == void)) + { + mixin InputRangeStub!E InputRangeMixin; + } + + auto save() @nogc nothrow pure @safe + { + return this; + } +} + +/** + * Generates a bidirectional range. + * + * This mixin includes forward range primitives as well, but can be combined with + * $(D_PSYMBOL RandomAccessRangeStub). + * + * Params: + * E = Element type. + */ +mixin template BidirectionalRangeStub(E = int) +{ + mixin ForwardRangeStub!E; + + void popBack() @nogc nothrow pure @safe + in + { + assert(!empty); + } + do + { + static if (!infinite) + { + --this.length_; + } + } + + static if (withLvalueElements) + { + ref E back() @nogc nothrow pure @safe + in + { + assert(!empty); + } + do + { + return *this.element; + } + } + else + { + E back() @nogc nothrow pure @safe + in + { + assert(!empty); + } + do + { + return E.init; + } + } +} + +/** + * Generates a random-access range. + * + * This mixin includes input range primitives as well, but can be combined with + * $(D_PSYMBOL ForwardRangeStub) or $(D_PSYMBOL BidirectionalRangeStub). + * + * Note that a random-access range also requires $(D_PSYMBOL Length) or + * $(D_PARAM Infinite) by definition. + * + * Params: + * E = Element type. + */ +mixin template RandomAccessRangeStub(E = int) +{ + static if (!is(typeof(this.InputRangeMixin) == void)) + { + mixin InputRangeStub!E InputRangeMixin; + } + + static if (withLvalueElements) + { + ref E opIndex(size_t) @nogc nothrow pure @safe + { + return *this.element; + } + } + else + { + E opIndex(size_t) @nogc nothrow pure @safe + { + return E.init; + } + } +} + +/** + * Struct with a disabled postblit constructor. + * + * $(D_PSYMBOL NonCopyable) can be used as an attribute for + * $(D_PSYMBOL StructStub) or as a standalone type. + */ +struct NonCopyable +{ + @disable this(this); +} + +/** + * Struct with an elaborate destructor. + * + * $(D_PSYMBOL WithDtor) can be used as an attribute for + * $(D_PSYMBOL StructStub) or as a standalone type. + * + * When used as a standalone object the constructor of $(D_PSYMBOL WithDtor) + * accepts an additional `counter` argument, which is incremented by the + * destructor. $(D_PSYMBOL WithDtor) stores a pointer to the passed variable, + * so the variable can be investigated after the struct isn't available + * anymore. + */ +struct WithDtor +{ + size_t* counter; + + this(ref size_t counter) @nogc nothrow pure @trusted + { + this.counter = &counter; + } + + ~this() @nogc nothrow pure @safe + { + if (this.counter !is null) + { + ++*this.counter; + } + } +} + +/** + * Struct supporting hashing. + * + * $(D_PSYMBOL Hashable) can be used as an attribute for + * $(D_PSYMBOL StructStub) or as a standalone type. + * + * The constructor accepts an additional parameter, which is returned by the + * `toHash()`-function. `0U` is returned if no hash value is given. + */ +struct Hashable +{ + size_t hash; + + size_t toHash() const @nogc nothrow pure @safe + { + return this.hash; + } +} + +/** + * Generates a $(D_KEYWORD struct) with common functionality. + * + * To specify the needed functionality use user-defined attributes on the + * $(D_KEYWORD struct) $(D_PSYMBOL StructStub) is mixed in. + * + * Supported attributes are: $(D_PSYMBOL NonCopyable), $(D_PSYMBOL Hashable), + * $(D_PSYMBOL WithDtor). + */ +mixin template StructStub() +{ + import std.traits : hasUDA, getUDAs; + + static if (hasUDA!(typeof(this), NonCopyable)) + { + @disable this(this); + } + + private alias Hashable = getUDAs!(typeof(this), .Hashable); + static if (Hashable.length > 0) + { + size_t toHash() const @nogc nothrow pure @safe + { + return Hashable[0]().hash; + } + } + + static if (hasUDA!(typeof(this), WithDtor)) + { + ~this() @nogc nothrow pure @safe + { + } + } +} diff --git a/test/dub.json b/test/dub.json deleted file mode 100644 index c988bd0..0000000 --- a/test/dub.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "test", - "description": "Test suite for unittest-blocks", - "targetType": "library", - - "dependencies": { - "tanya:middle": "*" - }, - - "sourcePaths": [ - "." - ], - "importPaths": [ - "." - ], - "dflags-dmd": ["-dip1000"] -} diff --git a/test/tanya/test/assertion.d b/test/tanya/test/assertion.d deleted file mode 100644 index 919194f..0000000 --- a/test/tanya/test/assertion.d +++ /dev/null @@ -1,106 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Additional assertions. - * - * This module provides functions that assert whether a given expression - * satisfies some complex condition, that can't be tested with - * $(D_KEYWORD assert) in a single line. Internally all the functions - * just evaluate the expression and call $(D_KEYWORD assert). - * - * The functions can cause segmentation fault if the module is compiled - * in production mode and the condition fails. - * - * Copyright: Eugene Wissner 2017-2025. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/assertion.d, - * tanya/test/assertion.d) - */ -module tanya.test.assertion; - -import std.traits : isSomeFunction; -import tanya.memory.allocator; -import tanya.meta.trait; - -/** - * Asserts whether the function $(D_PARAM expr) throws an exception of type - * $(D_PARAM E). If it does, the exception is catched and properly destroyed. - * If it doesn't, an assertion error is thrown. If the exception doesn't match - * $(D_PARAM E) type, it isn't catched and escapes. - * - * Params: - * E = Expected exception type. - * T = Throwing function type. - * Args = Argument types of the throwing function. - * expr = Throwing function. - * args = Arguments for $(D_PARAM expr). - */ -void assertThrown(E : Exception, T, Args...)(T expr, auto ref Args args) -if (isSomeFunction!T) -{ - try - { - cast(void) expr(args); - assert(false, "Expected exception not thrown"); - } - catch (E exception) - { - defaultAllocator.dispose(exception); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - // If you want to test that an expression throws, you can wrap it into an - // arrow function. - static struct CtorThrows - { - this(int i) @nogc pure @safe - { - throw defaultAllocator.make!Exception(); - } - } - assertThrown!Exception(() => CtorThrows(8)); -} - -/** - * Asserts that the function $(D_PARAM expr) doesn't throw. - * - * If it does, the thrown exception is catched, properly destroyed and an - * assertion error is thrown instead. - * - * Params: - * T = Tested function type. - * Args = Argument types of $(D_PARAM expr). - * expr = Tested function. - * args = Arguments for $(D_PARAM expr). - */ -void assertNotThrown(T, Args...)(T expr, auto ref Args args) -if (isSomeFunction!T) -{ - try - { - cast(void) expr(args); - } - catch (Exception exception) - { - defaultAllocator.dispose(exception); - assert(false, "Unexpected exception thrown"); - } -} - -/// -@nogc nothrow pure @safe unittest -{ - // If you want to test that an expression doesn't throw, you can wrap it - // into an arrow function. - static struct S - { - } - assertNotThrown(() => S()); -} diff --git a/test/tanya/test/package.d b/test/tanya/test/package.d deleted file mode 100644 index f316ddf..0000000 --- a/test/tanya/test/package.d +++ /dev/null @@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test suite for $(D_KEYWORD unittest)-blocks. - * - * Copyright: Eugene Wissner 2017-2025. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/package.d, - * tanya/test/package.d) - */ -module tanya.test; - -public import tanya.test.assertion; -public import tanya.test.stub; diff --git a/test/tanya/test/stub.d b/test/tanya/test/stub.d deleted file mode 100644 index fca2d96..0000000 --- a/test/tanya/test/stub.d +++ /dev/null @@ -1,397 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Range and generic type generators. - * - * Copyright: Eugene Wissner 2018-2025. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/stub.d, - * tanya/test/stub.d) - */ -module tanya.test.stub; - -/** - * Attribute signalizing that the generated range should contain the given - * number of elements. - * - * $(D_PSYMBOL Count) should be always specified with some value and not as a - * type, so $(D_INLINECODE Count(1)) instead just $(D_INLINECODE Count), - * otherwise you can just omit $(D_PSYMBOL Count) and it will default to 0. - * - * $(D_PSYMBOL Count) doesn't generate `.length` property - use - * $(D_PSYMBOL Length) for that. - * - * If neither $(D_PSYMBOL Length) nor $(D_PSYMBOL Infinite) is given, - * $(D_ILNINECODE Count(0)) is assumed. - * - * This attribute conflicts with $(D_PSYMBOL Infinite) and $(D_PSYMBOL Length). - */ -struct Count -{ - /// Original range length. - size_t count = 0; - - @disable this(); - - /** - * Constructs the attribute with the given length. - * - * Params: - * count = Original range length. - */ - this(size_t count) @nogc nothrow pure @safe - { - this.count = count; - } -} - -/** - * Attribute signalizing that the generated range should be infinite. - * - * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Length). - */ -struct Infinite -{ -} - -/** - * Generates `.length` property for the range. - * - * The length of the range can be specified as a constructor argument, - * otherwise it is 0. - * - * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Infinite). - */ -struct Length -{ - /// Original range length. - size_t length = 0; -} - -/** - * Attribute signalizing that the generated range should return values by - * reference. - * - * This atribute affects the return values of `.front`, `.back` and `[]`. - */ -struct WithLvalueElements -{ -} - -/** - * Generates an input range. - * - * Params: - * E = Element type. - */ -mixin template InputRangeStub(E = int) -{ - import std.traits : hasUDA, getUDAs; - import tanya.meta.metafunction : Alias; - - /* - * Aliases for the attribute lookups to access them faster - */ - private enum bool infinite = hasUDA!(typeof(this), Infinite); - private enum bool withLvalueElements = hasUDA!(typeof(this), - WithLvalueElements); - private alias Count = getUDAs!(typeof(this), .Count); - private alias Length = getUDAs!(typeof(this), .Length); - - static if (Count.length != 0) - { - private enum size_t count = Count[0].count; - - static assert (!infinite, - "Range cannot have count and be infinite at the same time"); - static assert (Length.length == 0, - "Range cannot have count and length at the same time"); - } - else static if (Length.length != 0) - { - private enum size_t count = Length[0]().length; - - static assert (!infinite, - "Range cannot have length and be infinite at the same time"); - } - else static if (!infinite) - { - private enum size_t count = 0; - } - - /* - * Member generation - */ - static if (infinite) - { - enum bool empty = false; - } - else - { - private size_t length_ = count; - - @property bool empty() const @nogc nothrow pure @safe - { - return this.length_ == 0; - } - } - - static if (withLvalueElements) - { - private E* element; // Pointer to enable range copying in save() - } - - void popFront() @nogc nothrow pure @safe - in - { - assert(!empty); - } - do - { - static if (!infinite) - { - --this.length_; - } - } - - static if (withLvalueElements) - { - ref E front() @nogc nothrow pure @safe - in - { - assert(!empty); - } - do - { - return *this.element; - } - } - else - { - E front() @nogc nothrow pure @safe - in - { - assert(!empty); - } - do - { - return E.init; - } - } - - static if (Length.length != 0) - { - size_t length() const @nogc nothrow pure @safe - { - return this.length_; - } - } -} - -/** - * Generates a forward range. - * - * This mixin includes input range primitives as well, but can be combined with - * $(D_PSYMBOL RandomAccessRangeStub). - * - * Params: - * E = Element type. - */ -mixin template ForwardRangeStub(E = int) -{ - static if (!is(typeof(this.InputRangeMixin) == void)) - { - mixin InputRangeStub!E InputRangeMixin; - } - - auto save() @nogc nothrow pure @safe - { - return this; - } -} - -/** - * Generates a bidirectional range. - * - * This mixin includes forward range primitives as well, but can be combined with - * $(D_PSYMBOL RandomAccessRangeStub). - * - * Params: - * E = Element type. - */ -mixin template BidirectionalRangeStub(E = int) -{ - mixin ForwardRangeStub!E; - - void popBack() @nogc nothrow pure @safe - in - { - assert(!empty); - } - do - { - static if (!infinite) - { - --this.length_; - } - } - - static if (withLvalueElements) - { - ref E back() @nogc nothrow pure @safe - in - { - assert(!empty); - } - do - { - return *this.element; - } - } - else - { - E back() @nogc nothrow pure @safe - in - { - assert(!empty); - } - do - { - return E.init; - } - } -} - -/** - * Generates a random-access range. - * - * This mixin includes input range primitives as well, but can be combined with - * $(D_PSYMBOL ForwardRangeStub) or $(D_PSYMBOL BidirectionalRangeStub). - * - * Note that a random-access range also requires $(D_PSYMBOL Length) or - * $(D_PARAM Infinite) by definition. - * - * Params: - * E = Element type. - */ -mixin template RandomAccessRangeStub(E = int) -{ - static if (!is(typeof(this.InputRangeMixin) == void)) - { - mixin InputRangeStub!E InputRangeMixin; - } - - static if (withLvalueElements) - { - ref E opIndex(size_t) @nogc nothrow pure @safe - { - return *this.element; - } - } - else - { - E opIndex(size_t) @nogc nothrow pure @safe - { - return E.init; - } - } -} - -/** - * Struct with a disabled postblit constructor. - * - * $(D_PSYMBOL NonCopyable) can be used as an attribute for - * $(D_PSYMBOL StructStub) or as a standalone type. - */ -struct NonCopyable -{ - @disable this(this); -} - -/** - * Struct with an elaborate destructor. - * - * $(D_PSYMBOL WithDtor) can be used as an attribute for - * $(D_PSYMBOL StructStub) or as a standalone type. - * - * When used as a standalone object the constructor of $(D_PSYMBOL WithDtor) - * accepts an additional `counter` argument, which is incremented by the - * destructor. $(D_PSYMBOL WithDtor) stores a pointer to the passed variable, - * so the variable can be investigated after the struct isn't available - * anymore. - */ -struct WithDtor -{ - size_t* counter; - - this(ref size_t counter) @nogc nothrow pure @trusted - { - this.counter = &counter; - } - - ~this() @nogc nothrow pure @safe - { - if (this.counter !is null) - { - ++*this.counter; - } - } -} - -/** - * Struct supporting hashing. - * - * $(D_PSYMBOL Hashable) can be used as an attribute for - * $(D_PSYMBOL StructStub) or as a standalone type. - * - * The constructor accepts an additional parameter, which is returned by the - * `toHash()`-function. `0U` is returned if no hash value is given. - */ -struct Hashable -{ - size_t hash; - - size_t toHash() const @nogc nothrow pure @safe - { - return this.hash; - } -} - -/** - * Generates a $(D_KEYWORD struct) with common functionality. - * - * To specify the needed functionality use user-defined attributes on the - * $(D_KEYWORD struct) $(D_PSYMBOL StructStub) is mixed in. - * - * Supported attributes are: $(D_PSYMBOL NonCopyable), $(D_PSYMBOL Hashable), - * $(D_PSYMBOL WithDtor). - */ -mixin template StructStub() -{ - import std.traits : hasUDA, getUDAs; - - static if (hasUDA!(typeof(this), NonCopyable)) - { - @disable this(this); - } - - private alias Hashable = getUDAs!(typeof(this), .Hashable); - static if (Hashable.length > 0) - { - size_t toHash() const @nogc nothrow pure @safe - { - return Hashable[0]().hash; - } - } - - static if (hasUDA!(typeof(this), WithDtor)) - { - ~this() @nogc nothrow pure @safe - { - } - } -} diff --git a/tests/tanya/math/tests/package.d b/tests/tanya/math/tests/package.d index fe10efd..2fc47ef 100644 --- a/tests/tanya/math/tests/package.d +++ b/tests/tanya/math/tests/package.d @@ -4,16 +4,3 @@ module tanya.math.tests; import tanya.math; - -static if (ieeePrecision!float == IEEEPrecision.doubleExtended) -@nogc nothrow pure @safe unittest -{ - assert(classify(1.68105e-10) == FloatingPointClass.normal); - assert(classify(1.68105e-4932L) == FloatingPointClass.subnormal); - - // Emulate unnormals, because they aren't generated anymore since i386 - FloatBits!real unnormal; - unnormal.exp = 0x123; - unnormal.mantissa = 0x1; - assert(classify(unnormal) == FloatingPointClass.subnormal); -} diff --git a/tests/tanya/memory/tests/smartref.d b/tests/tanya/memory/tests/smartref.d index 25d7d8f..52d4904 100644 --- a/tests/tanya/memory/tests/smartref.d +++ b/tests/tanya/memory/tests/smartref.d @@ -3,10 +3,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ module tanya.memory.tests.smartref; -import std.traits : ReturnType; +import std.traits; import tanya.memory.allocator; import tanya.memory.smartref; -import tanya.meta.trait; +import tanya.meta; import tanya.test.stub; @nogc @system unittest diff --git a/tests/tanya/meta/tests/metafunction.d b/tests/tanya/meta/tests/metafunction.d deleted file mode 100644 index 586e60d..0000000 --- a/tests/tanya/meta/tests/metafunction.d +++ /dev/null @@ -1,30 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -module tanya.meta.tests.metafunction; - -import tanya.meta.metafunction; - -@nogc nothrow pure @safe unittest -{ - enum cmp(int x, int y) = x - y; - static assert(isSorted!(cmp)); - static assert(isSorted!(cmp, 1)); - static assert(isSorted!(cmp, 1, 2, 2)); - static assert(isSorted!(cmp, 1, 2, 2, 4)); - static assert(isSorted!(cmp, 1, 2, 2, 4, 8)); - static assert(!isSorted!(cmp, 32, 2, 2, 4, 8)); - static assert(isSorted!(cmp, 32, 32)); -} - -@nogc nothrow pure @safe unittest -{ - enum cmp(int x, int y) = x < y; - static assert(isSorted!(cmp)); - static assert(isSorted!(cmp, 1)); - static assert(isSorted!(cmp, 1, 2, 2)); - static assert(isSorted!(cmp, 1, 2, 2, 4)); - static assert(isSorted!(cmp, 1, 2, 2, 4, 8)); - static assert(!isSorted!(cmp, 32, 2, 2, 4, 8)); - static assert(isSorted!(cmp, 32, 32)); -} -- cgit v1.2.3