diff --git a/Makefile b/Makefile index f8fe1c62f7b..89704a431ee 100644 --- a/Makefile +++ b/Makefile @@ -128,10 +128,6 @@ ifeq (,$(findstring win,$(OS))) ifneq (osx,$(OS)) NODEFAULTLIB += -L-lpthread -L-lm endif -else - ifeq ($(MODEL),32omf) - CPPFLAGS := -DNO_snprintf - endif endif # Set CC, CC_OUTFILEFLAG and CFLAGS unless using importC @@ -142,9 +138,6 @@ ifneq ($(USE_IMPORTC),1) ifeq ($(OS),win32wine) CC := wine dmc.exe CFLAGS := $(if $(findstring $(BUILD),debug),-g,-O) - else ifeq ($(MODEL),32omf) - CC := dmc - CFLAGS := $(if $(findstring $(BUILD),debug),-g,-O) else ifeq ($(OS),windows) CC := cl CC_OUTFILEFLAG := /Fo @@ -202,9 +195,7 @@ ifeq (,$(findstring win,$(OS))) SONAME:=libphobos2.so.$(MAJOR).$(MINOR) LIBSO:=$(ROOT)/$(SONAME).$(PATCH) else - ifeq ($(MODEL),32omf) - LIB:=phobos.lib - else ifeq ($(MODEL),32) + ifeq ($(MODEL),32) LIB:=phobos32mscoff.lib else LIB:=phobos$(MODEL).lib diff --git a/changelog/std.process.Config.preExecDelegate.dd b/changelog/std.process.Config.preExecDelegate.dd new file mode 100644 index 00000000000..393d26cf0b9 --- /dev/null +++ b/changelog/std.process.Config.preExecDelegate.dd @@ -0,0 +1,25 @@ +Add `std.process.Config.preExecDelegate` + +$(LINK2 $(ROOT_DIR)phobos/std_process.html#.Config.preExecDelegate, `std.process.Config.preExecDelegate`) +is just like +$(LINK2 $(ROOT_DIR)phobos/std_process.html#.Config.preExecFunction, `std.process.Config.preExecFunction`), +but can capture an environment, for example: + +------- +import core.sys.linux.sys.prctl : PR_SET_PDEATHSIG, prctl; +import std.process : Config, execute; + +void runProgram(int pdeathsig) +{ + execute( + ["program"], + config: Config( + preExecDelegate: () @trusted => + prctl(PR_SET_PDEATHSIG, pdeathsig, 0, 0, 0) != -1, + ), + ); +} +------- + +`preExecFunction` is retained for backwards compatibility. If both +`preExecFunction` and `preExecDelegate` are given, both are called. diff --git a/dub.sdl b/dub.sdl index 721781a544f..516e5968293 100644 --- a/dub.sdl +++ b/dub.sdl @@ -6,7 +6,7 @@ copyright "Copyright © 1999-2024, The D Language Foundation" configuration "library" { targetType "staticLibrary" - sourcePaths "lib" + sourcePaths "phobos" targetPath "generated-lib" #excludedSourceFiles "unittest.d" "test/**" "std/**" "tools/**" "etc/**" } @@ -14,7 +14,7 @@ configuration "library" { configuration "unittest" { dflags "-main" targetType "executable" - sourcePaths "lib" + sourcePaths "phobos" targetPath "generated-lib" #excludedSourceFiles "unittest.d" "test/**" "std/**" "tools/**" "etc/**" } diff --git a/lib/package.d b/lib/package.d deleted file mode 100644 index cff4c95fe77..00000000000 --- a/lib/package.d +++ /dev/null @@ -1,3 +0,0 @@ -module lib; - -public import lib.sys; diff --git a/lib/sys/meta.d b/lib/sys/meta.d deleted file mode 100644 index 0f359ac5750..00000000000 --- a/lib/sys/meta.d +++ /dev/null @@ -1,149 +0,0 @@ -// Written in the D programming language -/++ - Templates to manipulate - $(DDSUBLINK spec/template, variadic-templates, template parameter sequences) - (also known as $(I alias sequences)). - - Some operations on alias sequences are built into the language, - such as `S[i]`, which accesses the element at index `i` in the - sequence. `S[low .. high]` returns a new alias - sequence that is a slice of the old one. - - For more information, see - $(DDLINK ctarguments, Compile-time Sequences, Compile-time Sequences). - - $(SCRIPT inhibitQuickIndex = 1;) - $(DIVC quickindex, - $(BOOKTABLE , - $(TR $(TH Category) $(TH Templates)) - $(TR $(TD Building blocks) $(TD - $(LREF Alias) - $(LREF AliasSeq) - )) - ) - - References: - Based on ideas in Table 3.1 from - $(LINK2 http://amazon.com/exec/obidos/ASIN/0201704315/ref=ase_classicempire/102-2957199-2585768, - Modern C++ Design), - Andrei Alexandrescu (Addison-Wesley Professional, 2001) - - Copyright: Copyright The D Language Foundation 2005 - 2024. - License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). - Authors: $(HTTP digitalmars.com, Walter Bright), - $(HTTP klickverbot.at, David Nadlinger) - $(HTTP jmdavisprog.com, Jonathan M Davis) - Source: $(PHOBOSSRC lib/sys/meta) -+/ -module lib.sys.meta; - -/++ - Creates a sequence of zero or more aliases. This is most commonly - used as template parameters or arguments. - +/ -alias AliasSeq(TList...) = TList; - -/// -@safe unittest -{ - alias TL = AliasSeq!(int, double); - - int foo(TL td) // same as int foo(int, double); - { - return td[0] + cast(int) td[1]; - } -} - -/// -@safe unittest -{ - alias TL = AliasSeq!(int, double); - - alias Types = AliasSeq!(TL, char); - static assert(is(Types == AliasSeq!(int, double, char))); -} - -/// -@safe unittest -{ - static char foo(size_t i, string str) - { - return str[i]; - } - - alias vars = AliasSeq!(2, "dlang"); - - assert(foo(vars) == 'a'); -} - -/++ - Allows aliasing of any single symbol, type or compile-time expression. - - Not everything can be directly aliased. An alias cannot be declared - of - for example - a literal: - --- - alias a = 4; //Error - --- - With this template any single entity can be aliased: - --- - alias b = Alias!4; //OK - --- - See_Also: - To alias more than one thing at once, use $(LREF AliasSeq). - +/ -alias Alias(alias a) = a; - -/// Ditto -alias Alias(T) = T; - -/// -@safe unittest -{ - // Without Alias this would fail if Args[0] were e.g. a value and - // some logic would be needed to detect when to use enum instead - alias Head(Args...) = Alias!(Args[0]); - alias Tail(Args...) = Args[1 .. $]; - - alias Blah = AliasSeq!(3, int, "hello"); - static assert(Head!Blah == 3); - static assert(is(Head!(Tail!Blah) == int)); - static assert((Tail!Blah)[1] == "hello"); -} - -/// -@safe unittest -{ - { - alias a = Alias!123; - static assert(a == 123); - } - { - enum e = 1; - alias a = Alias!e; - static assert(a == 1); - } - { - alias a = Alias!(3 + 4); - static assert(a == 7); - } - { - alias concat = (s0, s1) => s0 ~ s1; - alias a = Alias!(concat("Hello", " World!")); - static assert(a == "Hello World!"); - } - { - alias A = Alias!int; - static assert(is(A == int)); - } - { - alias A = Alias!(AliasSeq!int); - static assert(!is(typeof(A[0]))); //not an AliasSeq - static assert(is(A == int)); - } - { - auto i = 6; - alias a = Alias!i; - ++a; - assert(i == 7); - } -} diff --git a/lib/sys/package.d b/lib/sys/package.d deleted file mode 100644 index 04c8903b17c..00000000000 --- a/lib/sys/package.d +++ /dev/null @@ -1,4 +0,0 @@ -module lib.sys; - -public import lib.sys.compiler; -public import lib.sys.system; diff --git a/lib/sys/compiler.d b/phobos/sys/compiler.d similarity index 96% rename from lib/sys/compiler.d rename to phobos/sys/compiler.d index 88bf362de0a..8181c9e3f10 100644 --- a/lib/sys/compiler.d +++ b/phobos/sys/compiler.d @@ -6,14 +6,14 @@ * Copyright: Copyright The D Language Foundation 2000 - 2011. * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(HTTP digitalmars.com, Walter Bright), Alex Rønne Petersen - * Source: $(PHOBOSSRC std/compiler.d) + * Source: $(PHOBOSSRC phobos/sys/compiler.d) */ /* Copyright The D Language Foundation 2000 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ -module lib.sys.compiler; +module phobos.sys.compiler; immutable { diff --git a/phobos/sys/meta.d b/phobos/sys/meta.d new file mode 100644 index 00000000000..1c31b67a72f --- /dev/null +++ b/phobos/sys/meta.d @@ -0,0 +1,1255 @@ +// Written in the D programming language +/++ + Templates to manipulate + $(DDSUBLINK spec/template, variadic-templates, template parameter sequences) + (also known as $(I alias sequences)). + + Some operations on alias sequences are built into the language, + such as `S[i]`, which accesses the element at index `i` in the + sequence. `S[low .. high]` returns a new alias + sequence that is a slice of the old one. + + For more information, see + $(DDLINK ctarguments, Compile-time Sequences, Compile-time Sequences). + + One thing that should be noted is that while the templates provided in this + module can be extremely useful, they generally should not be used with lists + of values. The language uses alias sequences for a variety of things + (including both parameter lists and argument lists), so they can contain + types, symbols, values, or a mixture of them all. The ability to manipulate + types and symbols within alias sequences is vital, because that's really + the only way to do it. However, because D has CTFE (Compile-Time Function + Evaluation), making it possible to call many functions at compile time, if + code needs to be able to manipulate values at compile-time, CTFE is + typically much more efficient and easier to do. Instantiating a bunch of + templates to manipulate values is incredibly inefficient in comparison. + + So, while many of the templates in this module will work with values simply + because alias sequences can contain values, most code should restrict + itself to using them for operating on types or symbols - i.e. the stuff + where CTFE can't be used. That being said, there will be times when one can + be used to feed into the other. E.G. + --- + alias Types = AliasSeq!(int, byte, ulong, int[10]); + + enum Sizeof(T) = T.sizeof; + + alias sizesAsAliasSeq = Map!(Sizeof, Types); + static assert(sizesAsAliasSeq == AliasSeq!(4, 1, 8, 40)); + + enum size_t[] sizes = [sizesAsAliasSeq]; + static assert(sizes == [4, 1, 8, 40]); + --- + + Just be aware that if CTFE can be used for a particular task, it's better to + use CTFE than to manipulate alias sequences with the kind of templates + provided by this module. + + $(SCRIPT inhibitQuickIndex = 1;) + $(DIVC quickindex, + $(BOOKTABLE , + $(TR $(TH Category) $(TH Templates)) + $(TR $(TD Building blocks) $(TD + $(LREF Alias) + $(LREF AliasSeq) + )) + $(TR $(TD Alias sequence filtering) $(TD + $(LREF Filter) + $(LREF Stride) + $(LREF Unique) + )) + $(TR $(TD Alias sequence transformation) $(TD + $(LREF Map) + $(LREF Reverse) + )) + $(TR $(TD Alias sequence searching) $(TD + $(LREF all) + $(LREF any) + $(LREF indexOf) + )) + $(TR $(TD Template predicates) $(TD + $(LREF And) + $(LREF Not) + $(LREF Or) + )) + $(TR $(TD Template instantiation) $(TD + $(LREF ApplyLeft) + $(LREF ApplyRight) + $(LREF Instantiate) + )) + ) + + References: + Based on ideas in Table 3.1 from + $(LINK2 http://amazon.com/exec/obidos/ASIN/0201704315/ref=ase_classicempire/102-2957199-2585768, + Modern C++ Design), + Andrei Alexandrescu (Addison-Wesley Professional, 2001) + + Copyright: Copyright The D Language Foundation 2005 - 2024. + License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). + Authors: $(HTTP digitalmars.com, Walter Bright), + $(HTTP klickverbot.at, David Nadlinger) + $(HTTP jmdavisprog.com, Jonathan M Davis) + Source: $(PHOBOSSRC phobos/sys/meta) ++/ +module phobos.sys.meta; + +// Example for converting types to values from module documentation. +@safe unittest +{ + alias Types = AliasSeq!(int, byte, ulong, int[10]); + + enum Sizeof(T) = T.sizeof; + + alias sizesAsAliasSeq = Map!(Sizeof, Types); + static assert(sizesAsAliasSeq == AliasSeq!(4, 1, 8, 40)); + + enum size_t[] sizes = [sizesAsAliasSeq]; + static assert(sizes == [4, 1, 8, 40]); +} + +/++ + Creates a sequence of zero or more aliases. This is most commonly + used as template parameters or arguments. + +/ +alias AliasSeq(TList...) = TList; + +/// +@safe unittest +{ + alias TL = AliasSeq!(int, double); + + int foo(TL td) // same as int foo(int, double); + { + return td[0] + cast(int) td[1]; + } +} + +/// +@safe unittest +{ + alias TL = AliasSeq!(int, double); + + alias Types = AliasSeq!(TL, char); + static assert(is(Types == AliasSeq!(int, double, char))); +} + +/// +@safe unittest +{ + static char foo(size_t i, string str) + { + return str[i]; + } + + alias vars = AliasSeq!(2, "dlang"); + + assert(foo(vars) == 'a'); +} + +/++ + Allows aliasing of any single symbol, type or compile-time expression. + + Not everything can be directly aliased. An alias cannot be declared + of - for example - a literal: + --- + alias a = 4; //Error + --- + With this template any single entity can be aliased: + --- + alias b = Alias!4; //OK + --- + See_Also: + To alias more than one thing at once, use $(LREF AliasSeq). + +/ +alias Alias(alias a) = a; + +/// Ditto +alias Alias(T) = T; + +/// +@safe unittest +{ + // Without Alias this would fail if Args[0] were e.g. a value and + // some logic would be needed to detect when to use enum instead. + alias Head(Args...) = Alias!(Args[0]); + alias Tail(Args...) = Args[1 .. $]; + + alias Blah = AliasSeq!(3, int, "hello"); + static assert(Head!Blah == 3); + static assert(is(Head!(Tail!Blah) == int)); + static assert((Tail!Blah)[1] == "hello"); +} + +/// +@safe unittest +{ + { + alias a = Alias!123; + static assert(a == 123); + } + { + enum e = 1; + alias a = Alias!e; + static assert(a == 1); + } + { + alias a = Alias!(3 + 4); + static assert(a == 7); + } + { + alias concat = (s0, s1) => s0 ~ s1; + alias a = Alias!(concat("Hello", " World!")); + static assert(a == "Hello World!"); + } + { + alias A = Alias!int; + static assert(is(A == int)); + } + { + alias A = Alias!(AliasSeq!int); + static assert(!is(typeof(A[0]))); // An Alias is not an AliasSeq. + static assert(is(A == int)); + } + { + auto i = 6; + alias a = Alias!i; + ++a; + assert(i == 7); + } +} + +/++ + Filters an $(D AliasSeq) using the given template predicate. + + The result is an $(D AliasSeq) that contains only the elements which satisfy + the predicate. + +/ +template Filter(alias Pred, Args...) +{ + alias Filter = AliasSeq!(); + static foreach (Arg; Args) + { + static if (Pred!Arg) + Filter = AliasSeq!(Filter, Arg); + } +} + +/// +@safe unittest +{ + import phobos.sys.traits : isDynamicArray, isPointer, isUnsignedInteger; + + alias Types = AliasSeq!(string, int, int[], bool[], ulong, double, ubyte); + + static assert(is(Filter!(isDynamicArray, Types) == + AliasSeq!(string, int[], bool[]))); + + static assert(is(Filter!(isUnsignedInteger, Types) == + AliasSeq!(ulong, ubyte))); + + static assert(is(Filter!(isPointer, Types) == AliasSeq!())); +} + +/++ + Evaluates to an $(LREF AliasSeq) which only contains every nth element from + the $(LREF AliasSeq) that was passed in, where $(D n) is stepSize. + + So, if stepSize is $(D 2), then the result contains every other element from + the original. If stepSize is $(D 3), then the result contains every third + element from the original. Etc. + + If stepSize is negative, then the result is equivalent to using + $(LREF Reverse) on the given $(LREF AliasSeq) and then using Stride on it + with the absolute value of that stepSize. + + If stepSize is positive, then the first element in the original + $(LREF AliasSeq) is the first element in the result, whereas if stepSize is + negative, then the last element in the original is the first element in the + result. Each subsequent element is then the element at the index of the + previous element plus stepSize. + +/ +template Stride(int stepSize, Args...) +if (stepSize != 0) +{ + alias Stride = AliasSeq!(); + static if (stepSize > 0) + { + static foreach (i; 0 .. (Args.length + stepSize - 1) / stepSize) + Stride = AliasSeq!(Stride, Args[i * stepSize]); + } + else + { + static foreach (i; 0 .. (Args.length - stepSize - 1) / -stepSize) + Stride = AliasSeq!(Stride, Args[$ - 1 + i * stepSize]); + } +} + +/// +@safe unittest +{ + static assert(is(Stride!(1, short, int, long) == AliasSeq!(short, int, long))); + static assert(is(Stride!(2, short, int, long) == AliasSeq!(short, long))); + static assert(is(Stride!(3, short, int, long) == AliasSeq!short)); + static assert(is(Stride!(100, short, int, long) == AliasSeq!short)); + + static assert(is(Stride!(-1, short, int, long) == AliasSeq!(long, int, short))); + static assert(is(Stride!(-2, short, int, long) == AliasSeq!(long, short))); + static assert(is(Stride!(-3, short, int, long) == AliasSeq!long)); + static assert(is(Stride!(-100, short, int, long) == AliasSeq!long)); + + alias Types = AliasSeq!(short, int, long, ushort, uint, ulong); + static assert(is(Stride!(3, Types) == AliasSeq!(short, ushort))); + static assert(is(Stride!(3, Types[1 .. $]) == AliasSeq!(int, uint))); + static assert(is(Stride!(-3, Types) == AliasSeq!(ulong, long))); + + static assert(is(Stride!(-2, Types) == Stride!(2, Reverse!Types))); + + static assert(is(Stride!1 == AliasSeq!())); + static assert(is(Stride!100 == AliasSeq!())); +} + +@safe unittest +{ + static assert(!__traits(compiles, Stride!(0, int))); + + alias Types = AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, + char, wchar, dchar, float, double, real, Object); + alias Types2 = AliasSeq!(bool, ubyte, ushort, uint, ulong, wchar, float, real); + alias Types3 = AliasSeq!(bool, short, uint, char, float, Object); + alias Types4 = AliasSeq!(bool, ushort, ulong, float); + alias Types5 = AliasSeq!(bool, int, wchar, Object); + alias Types6 = AliasSeq!(bool, uint, float); + alias Types7 = AliasSeq!(bool, long, real); + alias Types8 = AliasSeq!(bool, ulong); + alias Types9 = AliasSeq!(bool, char); + alias Types10 = AliasSeq!(bool, wchar); + + static assert(is(Stride!(1, Types) == Types)); + static assert(is(Stride!(2, Types) == Types2)); + static assert(is(Stride!(3, Types) == Types3)); + static assert(is(Stride!(4, Types) == Types4)); + static assert(is(Stride!(5, Types) == Types5)); + static assert(is(Stride!(6, Types) == Types6)); + static assert(is(Stride!(7, Types) == Types7)); + static assert(is(Stride!(8, Types) == Types8)); + static assert(is(Stride!(9, Types) == Types9)); + static assert(is(Stride!(10, Types) == Types10)); + + static assert(is(Stride!(-1, Types) == Reverse!Types)); + static assert(is(Stride!(-2, Types) == Stride!(2, Reverse!Types))); + static assert(is(Stride!(-3, Types) == Stride!(3, Reverse!Types))); + static assert(is(Stride!(-4, Types) == Stride!(4, Reverse!Types))); + static assert(is(Stride!(-5, Types) == Stride!(5, Reverse!Types))); + static assert(is(Stride!(-6, Types) == Stride!(6, Reverse!Types))); + static assert(is(Stride!(-7, Types) == Stride!(7, Reverse!Types))); + static assert(is(Stride!(-8, Types) == Stride!(8, Reverse!Types))); + static assert(is(Stride!(-9, Types) == Stride!(9, Reverse!Types))); + static assert(is(Stride!(-10, Types) == Stride!(10, Reverse!Types))); +} + +/++ + Evaluates to an $(LREF AliasSeq) which contains no duplicate elements. + + Unique takes a binary template predicate that it uses to compare elements + for equality. If the predicate is $(D true) when an element in the given + $(LREF AliasSeq) is compared with an element with a lower index, then that + element is not included in the result (so if any elements in the + $(LREF AliasSeq) are considered equal per the predicate, then only the + first one is included in the result). + + Note that the binary predicate must be partially instantiable, e.g. + --- + alias PartialCmp = Cmp!(Args[0]); + enum same = PartialCmp!(Args[1]); + --- + Otherwise, it won't work. + + See_Also: + $(REF isSameSymbol, phobos, sys, traits) + $(REF isSameType, phobos, sys, traits) + +/ +template Unique(alias Cmp, Args...) +{ + alias Unique = AliasSeq!(); + static foreach (i, Arg; Args) + { + static if (i == 0) + Unique = AliasSeq!Arg; + else + Unique = AppendIfUnique!(Cmp, Unique, Arg); + } +} + +// Unfortunately, this can't be done in-place in Unique, because then we get +// errors about reassigning Unique after reading it. +private template AppendIfUnique(alias Cmp, Args...) +{ + static if (indexOf!(Cmp!(Args[$ - 1]), Args[0 .. $ - 1]) == -1) + alias AppendIfUnique = Args; + else + alias AppendIfUnique = Args[0 .. $ - 1]; +} + +/// +@safe unittest +{ + import phobos.sys.traits : isSameType; + + alias Types1 = AliasSeq!(int, long, long, int, int, float, int); + + static assert(is(Unique!(isSameType, Types1) == + AliasSeq!(int, long, float))); + + alias Types2 = AliasSeq!(byte, ubyte, short, ushort, int, uint); + static assert(is(Unique!(isSameType, Types2) == Types2)); + + // Empty AliasSeq. + static assert(Unique!isSameType.length == 0); + + // An AliasSeq with a single element works as well. + static assert(Unique!(isSameType, int).length == 1); +} + +/// +@safe unittest +{ + import phobos.sys.traits : isSameSymbol; + + int i; + string s; + real r; + alias Symbols = AliasSeq!(i, s, i, i, s, r, r, i); + + alias Result = Unique!(isSameSymbol, Symbols); + static assert(Result.length == 3); + static assert(__traits(isSame, Result[0], i)); + static assert(__traits(isSame, Result[1], s)); + static assert(__traits(isSame, Result[2], r)); + + // Comparing AliasSeqs for equality with is expressions only works + // if they only contain types. + static assert(!is(Symbols == Result)); +} + +/// +@safe unittest +{ + alias Types = AliasSeq!(int, uint, long, string, short, int*, ushort); + + template sameSize(T) + { + enum sameSize(U) = T.sizeof == U.sizeof; + } + static assert(is(Unique!(sameSize, Types) == + AliasSeq!(int, long, string, short))); + + // The predicate must be partially instantiable. + enum sameSize_fails(T, U) = T.sizeof == U.sizeof; + static assert(!__traits(compiles, Unique!(sameSize_fails, Types))); +} + +/++ + Map takes a template and applies it to every element in the given + $(D AliasSeq), resulting in an $(D AliasSeq) with the transformed elements. + + So, it's equivalent to + `AliasSeq!(Fun!(Args[0]), Fun!(Args[1]), ..., Fun!(Args[$ - 1]))`. + +/ +template Map(alias Fun, Args...) +{ + alias Map = AliasSeq!(); + static foreach (Arg; Args) + Map = AliasSeq!(Map, Fun!Arg); +} + +/// +@safe unittest +{ + import phobos.sys.traits : Unqualified; + + // empty + alias Empty = Map!Unqualified; + static assert(Empty.length == 0); + + // single + alias Single = Map!(Unqualified, const int); + static assert(is(Single == AliasSeq!int)); + + // several + alias Several = Map!(Unqualified, int, const int, immutable int, uint, + ubyte, byte, short, ushort, const long); + static assert(is(Several == AliasSeq!(int, int, int, uint, + ubyte, byte, short, ushort, long))); + + alias ToDynamicArray(T) = T[]; + + alias Arrays = Map!(ToDynamicArray, int, const ubyte, string); + static assert(is(Arrays == AliasSeq!(int[], const(ubyte)[], string[]))); +} + +// @@@ BUG @@@ The test below exposes failure of the straightforward use. +// See @adamdruppe's comment to https://github.com/dlang/phobos/pull/8039 +@safe unittest +{ + template id(alias what) + { + enum id = __traits(identifier, what); + } + + enum A { a } + static assert(Map!(id, A.a) == AliasSeq!"a"); +} + +// regression test for https://issues.dlang.org/show_bug.cgi?id=21088 +@system unittest // typeid opEquals is @system +{ + enum getTypeId(T) = typeid(T); + alias A = Map!(getTypeId, int); + + assert(A == typeid(int)); +} + +/++ + Takes an $(D AliasSeq) and result in an $(D AliasSeq) where the order of + the elements has been reversed. + +/ +template Reverse(Args...) +{ + alias Reverse = AliasSeq!(); + static foreach_reverse (Arg; Args) + Reverse = AliasSeq!(Reverse, Arg); +} + +/// +@safe unittest +{ + static assert(is(Reverse!(int, byte, long, string) == + AliasSeq!(string, long, byte, int))); + + alias Types = AliasSeq!(int, long, long, int, float, + ubyte, short, ushort, uint); + static assert(is(Reverse!Types == AliasSeq!(uint, ushort, short, ubyte, + float, int, long, long, int))); + + static assert(is(Reverse!() == AliasSeq!())); +} + +/++ + Whether the given template predicate is $(D true) for all of the elements in + the given $(D AliasSeq). + + Evaluation is $(I not) short-circuited if a $(D false) result is + encountered; the template predicate must be instantiable with all the + elements. + +/ +version (StdDdoc) template all(alias Pred, Args...) +{ + import core.internal.traits : allSatisfy; + alias all = allSatisfy!(Pred, Args); +} +else +{ + import core.internal.traits : allSatisfy; + alias all = allSatisfy; +} + +/// +@safe unittest +{ + import phobos.sys.traits : isDynamicArray, isInteger; + + static assert(!all!(isInteger, int, double)); + static assert( all!(isInteger, int, long)); + + alias Types = AliasSeq!(string, int[], bool[]); + + static assert( all!(isDynamicArray, Types)); + static assert(!all!(isInteger, Types)); + + static assert( all!isInteger); +} + +/++ + Whether the given template predicate is $(D true) for any of the elements in + the given $(D AliasSeq). + + Evaluation is $(I not) short-circuited if a $(D true) result is + encountered; the template predicate must be instantiable with all the + elements. + +/ +version (StdDdoc) template any(alias Pred, Args...) +{ + import core.internal.traits : anySatisfy; + alias any = anySatisfy!(Pred, Args); +} +else +{ + import core.internal.traits : anySatisfy; + alias any = anySatisfy; +} + +/// +@safe unittest +{ + import phobos.sys.traits : isDynamicArray, isInteger; + + static assert(!any!(isInteger, string, double)); + static assert( any!(isInteger, int, double)); + + alias Types = AliasSeq!(string, int[], bool[], real, bool); + + static assert( any!(isDynamicArray, Types)); + static assert(!any!(isInteger, Types)); + + static assert(!any!isInteger); +} + +/++ + Evaluates to the index of the first element where $(D Pred!(Args[i])) is + $(D true). + + If $(D Pred!(Args[i])) is not $(D true) for any elements, then the result + is $(D -1). + + Evaluation is $(I not) short-circuited if a $(D true) result is + encountered; the template predicate must be instantiable with all the + elements. + +/ +template indexOf(alias Pred, Args...) +{ + enum ptrdiff_t indexOf = + { + static foreach (i; 0 .. Args.length) + { + static if (Pred!(Args[i])) + return i; + } + return -1; + }(); +} + +/// +@safe unittest +{ + import phobos.sys.traits : isInteger, isSameSymbol, isSameType; + + alias Types1 = AliasSeq!(string, int, long, char[], ubyte, int); + alias Types2 = AliasSeq!(float, double, int[], char[], void); + + static assert(indexOf!(isInteger, Types1) == 1); + static assert(indexOf!(isInteger, Types2) == -1); + + static assert(indexOf!(isSameType!ubyte, Types1) == 4); + static assert(indexOf!(isSameType!ubyte, Types2) == -1); + + int i; + int j; + string s; + int foo() { return 0; } + alias Symbols = AliasSeq!(i, j, foo); + static assert(indexOf!(isSameSymbol!j, Symbols) == 1); + static assert(indexOf!(isSameSymbol!s, Symbols) == -1); + + // Empty AliasSeq. + static assert(indexOf!isInteger == -1); + + // The predicate does not compile with all of the arguments, + // so indexOf does not compile. + static assert(!__traits(compiles, indexOf!(isSameType!int, long, int, 42))); +} + +unittest +{ + import phobos.sys.traits : isSameType; + + static assert(indexOf!(isSameType!int, short, int, long) >= 0); + static assert(indexOf!(isSameType!string, short, int, long) < 0); + + // This is to verify that we don't accidentally end up with the type of + // the result differing based on whether it's -1 or not. Not specifying the + // type at all in indexOf results in -1 being int on all systems and the + // other results being whatever size_t is (ulong on most systems at this + // point), which does generally work, but being explicit with the type + // avoids any subtle issues that might come from the type of the result + // varying based on whether the item is found or not. + static assert(is(typeof(indexOf!(isSameType!int, short, int, long)) == + typeof(indexOf!(isSameType!string, short, int, long)))); + + static assert(indexOf!(isSameType!string, string, string, string, string) == 0); + static assert(indexOf!(isSameType!string, int, string, string, string) == 1); + static assert(indexOf!(isSameType!string, int, int, string, string) == 2); + static assert(indexOf!(isSameType!string, int, int, int, string) == 3); + static assert(indexOf!(isSameType!string, int, int, int, int) == -1); +} + +/++ + Combines multiple template predicates into a single template predicate using + logical AND - i.e. for the resulting predicate to be $(D true) with a + particular argument, all of the predicates must be $(D true) with that + argument. + + Evaluation is $(I not) short-circuited if a $(D false) result is + encountered; the template predicate must be instantiable with all the + elements. + + See_Also: + $(LREF Not) + $(LREF Or) + +/ +template And(Preds...) +{ + enum And(Args...) = + { + static foreach (Pred; Preds) + { + static if (!Pred!Args) + return false; + } + return true; + }(); +} + +/// +@safe unittest +{ + import phobos.sys.traits : isNumeric; + + template isSameSize(size_t size) + { + enum isSameSize(T) = T.sizeof == size; + } + + alias is32BitNumeric = And!(isNumeric, isSameSize!4); + + static assert(!is32BitNumeric!short); + static assert( is32BitNumeric!int); + static assert(!is32BitNumeric!long); + static assert( is32BitNumeric!float); + static assert(!is32BitNumeric!double); + static assert(!is32BitNumeric!(int*)); + + // An empty sequence of predicates always yields true. + alias alwaysTrue = And!(); + static assert(alwaysTrue!int); +} + +/++ + Predicates with multiple parameters are also supported. However, the number + of parameters must match. + +/ +@safe unittest +{ + import phobos.sys.traits : isImplicitlyConvertible, isInteger, isSameType; + + alias isOnlyImplicitlyConvertible + = And!(Not!isSameType, isImplicitlyConvertible); + + static assert( isOnlyImplicitlyConvertible!(int, long)); + static assert(!isOnlyImplicitlyConvertible!(int, int)); + static assert(!isOnlyImplicitlyConvertible!(long, int)); + + static assert( isOnlyImplicitlyConvertible!(string, const(char)[])); + static assert(!isOnlyImplicitlyConvertible!(string, string)); + static assert(!isOnlyImplicitlyConvertible!(const(char)[], string)); + + // Mismatched numbers of parameters. + alias doesNotWork = And!(isInteger, isImplicitlyConvertible); + static assert(!__traits(compiles, doesNotWork!int)); + static assert(!__traits(compiles, doesNotWork!(int, long))); +} + +@safe unittest +{ + enum testAlways(Args...) = true; + enum testNever(Args...) = false; + + static assert( Instantiate!(And!(testAlways, testAlways, testAlways), int)); + static assert(!Instantiate!(And!(testAlways, testAlways, testNever), int)); + static assert(!Instantiate!(And!(testAlways, testNever, testNever), int)); + static assert(!Instantiate!(And!(testNever, testNever, testNever), int)); + static assert(!Instantiate!(And!(testNever, testNever, testAlways), int)); + static assert(!Instantiate!(And!(testNever, testAlways, testAlways), int)); + + static assert( Instantiate!(And!(testAlways, testAlways), int)); + static assert(!Instantiate!(And!(testAlways, testNever), int)); + static assert(!Instantiate!(And!(testNever, testAlways), int)); + static assert(!Instantiate!(And!(testNever, testNever), int)); + + static assert( Instantiate!(And!testAlways, int)); + static assert(!Instantiate!(And!testNever, int)); + + // No short-circuiting. + import phobos.sys.traits : isEqual, isFloatingPoint; + static assert(!Instantiate!(And!isFloatingPoint, int)); + static assert(!__traits(compiles, Instantiate!(And!(isFloatingPoint, isEqual), int))); +} + +/++ + Evaluates to a template predicate which negates the given predicate. + + See_Also: + $(LREF And) + $(LREF Or) + +/ +template Not(alias Pred) +{ + enum Not(Args...) = !Pred!Args; +} + +/// +@safe unittest +{ + import phobos.sys.traits : isDynamicArray, isPointer; + + alias isNotPointer = Not!isPointer; + static assert( isNotPointer!int); + static assert(!isNotPointer!(int*)); + static assert( all!(isNotPointer, string, char, float)); + + static assert(!all!(Not!isDynamicArray, string, char[], int[], long)); + static assert( any!(Not!isDynamicArray, string, char[], int[], long)); +} + +/++ + Predicates with multiple parameters are also supported. + +/ +@safe unittest +{ + import phobos.sys.traits : isImplicitlyConvertible, isInteger; + + alias notImplicitlyConvertible = Not!isImplicitlyConvertible; + + static assert( notImplicitlyConvertible!(long, int)); + static assert(!notImplicitlyConvertible!(int, long)); + + static assert( notImplicitlyConvertible!(const(char)[], string)); + static assert(!notImplicitlyConvertible!(string, const(char)[])); +} + +/++ + Combines multiple template predicates into a single template predicate using + logical OR - i.e. for the resulting predicate to be $(D true) with a + particular argument, at least one of the predicates must be $(D true) with + that argument. + + Evaluation is $(I not) short-circuited if a $(D true) result is + encountered; the template predicate must be instantiable with all the + elements. + + See_Also: + $(LREF And) + $(LREF Not) + +/ +template Or(Preds...) +{ + enum Or(Args...) = + { + static foreach (Pred; Preds) + { + static if (Pred!Args) + return true; + } + return false; + }(); +} + +/// +@safe unittest +{ + import phobos.sys.traits : isFloatingPoint, isSignedInteger; + + alias isSignedNumeric = Or!(isFloatingPoint, isSignedInteger); + + static assert( isSignedNumeric!short); + static assert( isSignedNumeric!long); + static assert( isSignedNumeric!double); + static assert(!isSignedNumeric!uint); + static assert(!isSignedNumeric!ulong); + static assert(!isSignedNumeric!string); + static assert(!isSignedNumeric!(int*)); + + // An empty sequence of predicates always yields false. + alias alwaysFalse = Or!(); + static assert(!alwaysFalse!int); +} + +/++ + Predicates with multiple parameters are also supported. However, the number + of parameters must match. + +/ +@safe unittest +{ + import phobos.sys.traits : isImplicitlyConvertible, isInteger; + + enum isSameSize(T, U) = T.sizeof == U.sizeof; + alias convertibleOrSameSize = Or!(isImplicitlyConvertible, isSameSize); + + static assert( convertibleOrSameSize!(int, int)); + static assert( convertibleOrSameSize!(int, long)); + static assert(!convertibleOrSameSize!(long, int)); + + static assert( convertibleOrSameSize!(int, float)); + static assert( convertibleOrSameSize!(float, int)); + static assert(!convertibleOrSameSize!(double, int)); + static assert(!convertibleOrSameSize!(float, long)); + + static assert( convertibleOrSameSize!(int*, string*)); + + // Mismatched numbers of parameters. + alias doesNotWork = Or!(isInteger, isImplicitlyConvertible); + static assert(!__traits(compiles, doesNotWork!int)); + static assert(!__traits(compiles, doesNotWork!(int, long))); +} + +@safe unittest +{ + enum testAlways(Args...) = true; + enum testNever(Args...) = false; + + static assert( Instantiate!(Or!(testAlways, testAlways, testAlways), int)); + static assert( Instantiate!(Or!(testAlways, testAlways, testNever), int)); + static assert( Instantiate!(Or!(testAlways, testNever, testNever), int)); + static assert(!Instantiate!(Or!(testNever, testNever, testNever), int)); + + static assert( Instantiate!(Or!(testAlways, testAlways), int)); + static assert( Instantiate!(Or!(testAlways, testNever), int)); + static assert( Instantiate!(Or!(testNever, testAlways), int)); + static assert(!Instantiate!(Or!(testNever, testNever), int)); + + static assert( Instantiate!(Or!testAlways, int)); + static assert(!Instantiate!(Or!testNever, int)); + + static assert(Instantiate!(Or!testAlways, int)); + static assert(Instantiate!(Or!testAlways, Map)); + static assert(Instantiate!(Or!testAlways, int, Map)); + + // No short-circuiting. + import phobos.sys.traits : isEqual, isInteger; + static assert( Instantiate!(Or!isInteger, int)); + static assert(!__traits(compiles, Instantiate!(Or!(isInteger, isEqual), int))); +} + +/++ + Instantiates the given template with the given arguments and evaluates to + the result of that template. + + This is used to work around some syntactic limitations that D has with + regards to instantiating templates. Essentially, D requires a name for a + template when instantiating it (be it the name of the template itself or an + alias to the template), which causes problems when you don't have that. + + Specifically, if the template is within an $(LREF AliasSeq) - e.g. + $(D Templates[0]!Args) - or it's the result of another template - e.g + $(D Foo!Bar!Baz) - the instantiation is illegal. This leaves two ways to + solve the problem. The first is to create an alias, e.g. + --- + alias Template = Templates[0]; + enum result = Template!Args; + + alias Partial = Foo!Bar; + alias T = Partial!Baz; + --- + The second is to use Instantiate, e.g. + --- + enum result = Instantiate!(Templates[0], Args); + + alias T = Instiantiate!(Foo!Bar, Baz); + --- + + Of course, the downside to this is that it adds an additional template + instantiation, but it avoids creating an alias just to be able to + instantiate a template. So, whether it makes sense to use Instantiate + instead of an alias naturally depends on the situation, but without it, + we'd be forced to create aliases even in situations where that's + problematic. + + See_Also: + $(LREF ApplyLeft) + $(LREF ApplyRight) + +/ +alias Instantiate(alias Template, Args...) = Template!Args; + +/// +@safe unittest +{ + import phobos.sys.traits : ConstOf, isImplicitlyConvertible, isSameType, isInteger; + + alias Templates = AliasSeq!(isImplicitlyConvertible!int, + isSameType!string, + isInteger, + ConstOf); + + // Templates[0]!long does not compile, because the compiler can't parse it. + + static assert( Instantiate!(Templates[0], long)); + static assert(!Instantiate!(Templates[0], string)); + + static assert(!Instantiate!(Templates[1], long)); + static assert( Instantiate!(Templates[1], string)); + + static assert( Instantiate!(Templates[2], long)); + static assert(!Instantiate!(Templates[2], string)); + + static assert(is(Instantiate!(Templates[3], int) == const int)); + static assert(is(Instantiate!(Templates[3], double) == const double)); +} + +/// +@safe unittest +{ + template hasMember(string member) + { + enum hasMember(T) = __traits(hasMember, T, member); + } + + struct S + { + int foo; + } + + // hasMember!"foo"!S does not compile, + // because having multiple ! arguments is not allowed. + + static assert( Instantiate!(hasMember!"foo", S)); + static assert(!Instantiate!(hasMember!"bar", S)); +} + +/++ + Instantiate also allows us to do template instantations via templates that + take other templates as arguments. + +/ +@safe unittest +{ + import phobos.sys.traits : isInteger, isNumeric, isUnsignedInteger; + + alias Results = Map!(ApplyRight!(Instantiate, int), + isInteger, isNumeric, isUnsignedInteger); + + static assert([Results] == [true, true, false]); +} + +/++ + ApplyLeft does a + $(LINK2 http://en.wikipedia.org/wiki/Partial_application, partial application) + of its arguments, providing a way to bind a set of arguments to the given + template while delaying actually instantiating that template until the full + set of arguments is provided. The "Left" in the name indicates that the + initial arguments are one the left-hand side of the argument list + when the given template is instantiated. + + Essentially, ApplyLeft results in a template that stores Template and Args, + and when that intermediate template is instantiated in turn, it instantiates + Template with Args on the left-hand side of the arguments to Template and + with the arguments to the intermediate template on the right-hand side - + i.e. Args is applied to the left when instantiating Template. + + So, if you have + --- + alias Intermediate = ApplyLeft!(MyTemplate, Arg1, Arg2); + alias Result = Intermediate!(ArgA, ArgB); + --- + then that is equivalent to + --- + alias Result = MyTemplate!(Arg1, Arg2, ArgA, ArgB); + --- + with the difference being that you have an intermediate template which can + be stored or passed to other templates (e.g. as a template predicate). + + The only difference between ApplyLeft and $(LREF ApplyRight) is whether + Args is on the left-hand or the right-hand side of the arguments given to + Template when it's instantiated. + + Note that in many cases, the need for ApplyLeft can be eliminated by making + it so that Template can be partially instantiated. E.G. + --- + enum isSameType(T, U) = is(T == U); + + template isSameType(T) + { + enum isSameType(U) = is(T == U); + } + --- + makes it so that both of these work + --- + enum result1 = isSameType!(int, long); + + alias Intermediate = isSameType!int; + enum result2 = Intermediate!long; + --- + whereas if only the two argument version is provided, then ApplyLeft would + be required for the second use case. + --- + enum result1 = isSameType!(int, long); + + alias Intermediate = ApplyLeft!(isSameType, int); + enum result2 = Intermediate!long; + --- + + See_Also: + $(LREF ApplyRight) + $(LREF Instantiate) + +/ +template ApplyLeft(alias Template, Args...) +{ + alias ApplyLeft(Right...) = Template!(Args, Right); +} + +/// +@safe unittest +{ + { + alias Intermediate = ApplyLeft!(AliasSeq, ubyte, ushort, uint); + alias Result = Intermediate!(char, wchar, dchar); + static assert(is(Result == AliasSeq!(ubyte, ushort, uint, char, wchar, dchar))); + } + { + enum isImplicitlyConvertible(T, U) = is(T : U); + + // i.e. isImplicitlyConvertible!(ubyte, T) is what all is checking for + // with each element in the AliasSeq. + static assert(all!(ApplyLeft!(isImplicitlyConvertible, ubyte), + short, ushort, int, uint, long, ulong)); + } + { + enum hasMember(T, string member) = __traits(hasMember, T, member); + + struct S + { + bool foo; + int bar; + string baz; + } + + static assert(all!(ApplyLeft!(hasMember, S), "foo", "bar", "baz")); + } + { + // Either set of arguments can be empty, since the first set is just + // stored to be applied later, and then when the intermediate template + // is instantiated, they're all applied to the given template in the + // requested order. However, whether the code compiles when + // instantiating the intermediate template depends on what kinds of + // arguments the given template requires. + + alias Intermediate1 = ApplyLeft!AliasSeq; + static assert(Intermediate1!().length == 0); + + enum isSameSize(T, U) = T.sizeof == U.sizeof; + + alias Intermediate2 = ApplyLeft!(isSameSize, int); + static assert(Intermediate2!uint); + + alias Intermediate3 = ApplyLeft!(isSameSize, int, uint); + static assert(Intermediate3!()); + + alias Intermediate4 = ApplyLeft!(isSameSize); + static assert(Intermediate4!(int, uint)); + + // isSameSize requires two arguments + alias Intermediate5 = ApplyLeft!isSameSize; + static assert(!__traits(compiles, Intermediate5!())); + static assert(!__traits(compiles, Intermediate5!int)); + static assert(!__traits(compiles, Intermediate5!(int, long, string))); + } +} + +/++ + ApplyRight does a + $(LINK2 http://en.wikipedia.org/wiki/Partial_application, partial application) + of its arguments, providing a way to bind a set of arguments to the given + template while delaying actually instantiating that template until the full + set of arguments is provided. The "Right" in the name indicates that the + initial arguments are one the right-hand side of the argument list + when the given template is instantiated. + + Essentially, ApplyRight results in a template that stores Template and + Args, and when that intermediate template is instantiated in turn, it + instantiates Template with the arguments to the intermediate template on + the left-hand side and with Args on the right-hand side - i.e. Args is + applied to the right when instantiating Template. + + So, if you have + --- + alias Intermediate = ApplyRight!(MyTemplate, Arg1, Arg2); + alias Result = Intermediate!(ArgA, ArgB); + --- + then that is equivalent to + --- + alias Result = MyTemplate!(ArgA, ArgB, Arg1, Arg2); + --- + with the difference being that you have an intermediate template which can + be stored or passed to other templates (e.g. as a template predicate). + + The only difference between $(LREF ApplyLeft) and ApplyRight is whether + Args is on the left-hand or the right-hand side of the arguments given to + Template when it's instantiated. + + See_Also: + $(LREF ApplyLeft) + $(LREF Instantiate) + +/ +template ApplyRight(alias Template, Args...) +{ + alias ApplyRight(Left...) = Template!(Left, Args); +} + +/// +@safe unittest +{ + { + alias Intermediate = ApplyRight!(AliasSeq, ubyte, ushort, uint); + alias Result = Intermediate!(char, wchar, dchar); + static assert(is(Result == AliasSeq!(char, wchar, dchar, ubyte, ushort, uint))); + } + { + enum isImplicitlyConvertible(T, U) = is(T : U); + + // i.e. isImplicitlyConvertible!(T, short) is what Filter is checking + // for with each element in the AliasSeq. + static assert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short), + ubyte, string, short, float, int) == + AliasSeq!(ubyte, short))); + } + { + enum hasMember(T, string member) = __traits(hasMember, T, member); + + struct S1 + { + bool foo; + } + + struct S2 + { + int foo() { return 42; } + } + + static assert(all!(ApplyRight!(hasMember, "foo"), S1, S2)); + } + { + // Either set of arguments can be empty, since the first set is just + // stored to be applied later, and then when the intermediate template + // is instantiated, they're all applied to the given template in the + // requested order. However, whether the code compiles when + // instantiating the intermediate template depends on what kinds of + // arguments the given template requires. + + alias Intermediate1 = ApplyRight!AliasSeq; + static assert(Intermediate1!().length == 0); + + enum isSameSize(T, U) = T.sizeof == U.sizeof; + + alias Intermediate2 = ApplyRight!(isSameSize, int); + static assert(Intermediate2!uint); + + alias Intermediate3 = ApplyRight!(isSameSize, int, uint); + static assert(Intermediate3!()); + + alias Intermediate4 = ApplyRight!(isSameSize); + static assert(Intermediate4!(int, uint)); + + // isSameSize requires two arguments + alias Intermediate5 = ApplyRight!isSameSize; + static assert(!__traits(compiles, Intermediate5!())); + static assert(!__traits(compiles, Intermediate5!int)); + } +} diff --git a/lib/sys/system.d b/phobos/sys/system.d similarity index 98% rename from lib/sys/system.d rename to phobos/sys/system.d index 7e5a15cfe89..538db6d70c8 100644 --- a/lib/sys/system.d +++ b/phobos/sys/system.d @@ -7,9 +7,9 @@ * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(HTTP digitalmars.com, Walter Bright) and $(HTTP jmdavisprog.com, Jonathan M Davis) - * Source: $(PHOBOSSRC std/system.d) + * Source: $(PHOBOSSRC phobos/sys/system.d) */ -module lib.sys.system; +module phobos.sys.system; immutable { diff --git a/phobos/sys/traits.d b/phobos/sys/traits.d new file mode 100644 index 00000000000..595dc7a15b6 --- /dev/null +++ b/phobos/sys/traits.d @@ -0,0 +1,4002 @@ +// Written in the D programming language +/++ + Templates which extract information about types and symbols at compile time. + + In the context of phobos.sys.traits, a "trait" is a template which provides + information about a type or symbol. Most traits evaluate to + $(D true) or $(D false), telling the code using it whether the given + arguments match / have that specific trait (e.g. whether the given type is + a dynamic array or whether the given function is $(D @safe)). However, some + traits may provide other kinds of information about a type (e.g. the trait + could evaluate to the base type for an enum type, or it could strip + $(D const) from the type to provide the mutable version of that type). + + These traits are then used primarily in template constraints so that they + can test that the template arguments meet the criteria required by those + templates, though they can be useful in a variety of compile-time contexts + (e.g. the condition of a $(D static if)). + + Note that unless otherwise specified, the isXXXX and hasXXX traits in this + module are checking for exact matches, so base types (e.g. with enums) and + other implicit conversions do not factor into whether such traits are true + or false. The type itself is being checked, not what it can be converted + to. + + This is because these traits are often used in templated constraints, and + having a type pass a template constraint based on an implicit conversion + but then not have the implicit conversion actually take place (which it + won't unless the template does something to force it internally) can lead + to either compilation errors or subtle behavioral differences - and even + when the conversion is done explicitly within a templated function, since + it's not done at the call site, it can still lead to subtle bugs in some + cases (e.g. if slicing a static array is involved). + + So, it's typically best to be explicit and clear about a template constraint + accepting any kind of implicit conversion rather than having it buried in a + trait where programmers stand a good chance of using the trait without + realizing that enums might pass based on their base type - or that a type + might pass based on some other implicit conversion. + + Regardless of what a trait is testing for, the documentation strives to be + $(I very) clear about what the trait does, and of course, the names do try + to make it clear as well - though obviously, only so much information can + be put into a name, and some folks will misintrepret some symbols no matter + how well they're named. So, please be sure that you clearly understand what + these traits do when using them, since messing up template constraints can + unfortunately be a great way to introduce subtle bugs into your program. + Either way, of course, unit tests are your friends. + + $(SCRIPT inhibitQuickIndex = 1;) + + $(BOOKTABLE , + $(TR $(TH Category) $(TH Templates)) + $(TR $(TD Categories of types) $(TD + $(LREF isAggregateType) + $(LREF isDynamicArray) + $(LREF isFloatingPoint) + $(LREF isInstantiationOf) + $(LREF isInteger) + $(LREF isNumeric) + $(LREF isPointer) + $(LREF isSignedInteger) + $(LREF isStaticArray) + $(LREF isUnsignedInteger) + )) + $(TR $(TD Aggregate Type traits) $(TD + $(LREF EnumMembers) + )) + $(TR $(TD Traits testing for type conversions) $(TD + $(LREF isImplicitlyConvertible) + $(LREF isQualifierConvertible) + )) + $(TR $(TD Traits for comparisons) $(TD + $(LREF isEqual) + $(LREF isSameSymbol) + $(LREF isSameType) + )) + $(TR $(TD Aggregate Type Traits) $(TD + $(LREF FieldNames) + $(LREF FieldSymbols) + $(LREF FieldTypes) + )) + $(TR $(TD General Types) $(TD + $(LREF KeyType) + $(LREF OriginalType) + $(LREF ValueType) + )) + $(TR $(TD Traits for removing type qualfiers) $(TD + $(LREF Unconst) + $(LREF Unshared) + $(LREF Unqualified) + )) + $(TR $(TD Type Constructors) $(TD + $(LREF ConstOf) + $(LREF ImmutableOf) + $(LREF InoutOf) + $(LREF SharedOf) + )) + $(TR $(TD Misc) $(TD + $(LREF lvalueOf) + $(LREF rvalueOf) + )) + ) + + Copyright: Copyright The D Language Foundation 2005 - 2024. + License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). + Authors: $(HTTP jmdavisprog.com, Jonathan M Davis) + $(HTTP digitalmars.com, Walter Bright), + Tomasz Stachowiak (`isExpressions`), + $(HTTP erdani.org, Andrei Alexandrescu), + Shin Fujishiro, + $(HTTP octarineparrot.com, Robert Clipsham), + $(HTTP klickverbot.at, David Nadlinger), + Kenji Hara, + Shoichi Kato + Source: $(PHOBOSSRC phobos/sys/traits) ++/ +module phobos.sys.traits; + +/++ + Whether the given type is an "aggregate type" - i.e. a struct, class, + interface, or union. + +/ +enum isAggregateType(T) = is(T == struct) || is(T == class) || is(T == interface) || is(T == union); + +@safe unittest +{ + struct S {} + class C {} + interface I {} + union U {} + + static assert( isAggregateType!S); + static assert( isAggregateType!C); + static assert( isAggregateType!I); + static assert( isAggregateType!U); + static assert( isAggregateType!(const S)); + static assert( isAggregateType!(shared C)); + + static assert(!isAggregateType!int); + static assert(!isAggregateType!string); + static assert(!isAggregateType!(S*)); + static assert(!isAggregateType!(C[])); + static assert(!isAggregateType!(I[string])); +} + +/++ + Whether the given type is a dynamic array (or what is sometimes referred to + as a slice, since a dynamic array in D is a slice of memory). + + Note that this does not include implicit conversions or enum types. The + type itself must be a dynamic array. + + Remember that D's dynamic arrays are essentially: + --- + struct DynamicArray(T) + { + size_t length; + T* ptr; + } + --- + where $(D ptr) points to the first element in the array, and $(D length) is + the number of elements in the array. + + A dynamic array is not a pointer (unlike arrays in C/C++), and its elements + do not live inside the dynamic array itself. The dynamic array is simply a + slice of memory and does not own or manage its own memory. It can be a + slice of any piece of memory, including GC-allocated memory, the stack, + malloc-ed memory, etc. (with what kind of memory it is of course being + determined by how the dynamic array was created in the first place) + - though if you do any operations on it which end up requiring allocation + (e.g. appending to it if it doesn't have the capacity to expand in-place, + which it won't if it isn't a slice of GC-allocated memory), then that + reallocation will result in the dynamic array being a slice of newly + allocated, GC-backed memory (regardless of what it was a slice of before), + since it's the GC that deals with those allocations. + + As long as code just accesses the elements or members of the dynamic array + - or reduces its length so that it's a smaller slice - it will continue to + point to whatever block of memory it pointed to originally. And because the + GC makes sure that appending to a dynamic array does not stomp on the + memory of any other dynamic arrays, appending to a dynamic array will not + affect any other dynamic array which is a slice of that same block of + memory whether a reallocation occurs or not. + + Regardless, since what allocated the memory that the dynamic array is a + slice of is irrevelant to the type of the dynamic array, whether a given + type is a dynamic array has nothing to do with the kind of memory that's + backing it. A dynamic array which is a slice of a static array of $(D int) + is the the same type as a dynamic array of $(D int) allocated with $(D new) + - i.e. both are $(D int[]). So, this trait will not tell you anything about + what kind of memory a dynamic array is a slice of. It just tells you + whether the type is a dynamic array or not. + + If for some reason, it matters for a function what kind of memory backs one + of its parameters which is a dynamic array, or it needs to be made clear + whether the function will possibly cause that dynamic array to be + reallocated, then that needs to be indicated by the documentation and + cannot be enforced with a template constraint. A template constraint can + enforce that a type used with a template meets certain criteria (e.g. that + it's a dynamic array), but it cannot enforce anything about how the + template actually uses the type. + + However, it $(D is) possible to enforce that a function doesn't use any + operations on a dynamic array which might cause it to be reallocated by + marking that function as $(D @nogc). + + In most cases though, code can be written to not care what kind of memory + backs a dynamic array, because none of the operations on a dynamic array + actually care what kind of memory it's a slice of. It mostly just matters + when you need to track the lifetime of the memory, because it wasn't + allocated by the GC, or when it matters whether a dynamic array could be + reallocated or not (e.g. because the code needs to have that dynamic array + continue to point to the same block of memory). + + See_Also: + $(LREF isPointer) + $(LREF isStaticArray) + $(DDSUBLINK spec/arrays, , The language spec for arrays) + +/ +enum isDynamicArray(T) = is(T == U[], U); + +/// +@safe unittest +{ + // Some types which are dynamic arrays. + static assert( isDynamicArray!(int[])); + static assert( isDynamicArray!(const int[])); + static assert( isDynamicArray!(inout int[])); + static assert( isDynamicArray!(shared(int)[])); + static assert( isDynamicArray!string); + + static assert( isDynamicArray!(typeof([1, 2, 3]))); + static assert( isDynamicArray!(typeof("dlang"))); + + int[] arr; + static assert( isDynamicArray!(typeof(arr))); + + // Some types which aren't dynamic arrays. + static assert(!isDynamicArray!int); + static assert(!isDynamicArray!(int*)); + static assert(!isDynamicArray!real); + + static struct S + { + int[] arr; + } + static assert(!isDynamicArray!S); + + // The struct itself isn't considered a dynamic array, + // but its member variable is when checked directly. + static assert( isDynamicArray!(typeof(S.arr))); + + // Static arrays. + static assert(!isDynamicArray!(int[5])); + static assert(!isDynamicArray!(const(int)[5])); + + int[2] sArr = [42, 97]; + static assert(!isDynamicArray!(typeof(sArr))); + + // While a static array is not a dynamic array, + // a slice of a static array is a dynamic array. + static assert( isDynamicArray!(typeof(sArr[]))); + + // Dynamic array of static arrays. + static assert( isDynamicArray!(long[3][])); + + // Static array of dynamic arrays. + static assert(!isDynamicArray!(long[][3])); + + // Associative array. + static assert(!isDynamicArray!(int[string])); + + // While typeof(null) gets treated as void[] in some contexts, it is + // distinct from void[] and is not considered to be a dynamic array. + static assert(!isDynamicArray!(typeof(null))); + + // However, naturally, if null is cast to a dynamic array, it's a + // dynamic array, since the cast forces the type. + static assert( isDynamicArray!(typeof(cast(int[]) null))); + + enum E : int[] + { + a = [1, 2, 3], + } + + // Enums do not count. + static assert(!isDynamicArray!E); + + static struct AliasThis + { + int[] arr; + alias this = arr; + } + + // Other implicit conversions do not count. + static assert(!isDynamicArray!AliasThis); +} + +@safe unittest +{ + import phobos.sys.meta : Alias, AliasSeq; + + static struct AliasThis(T) + { + T member; + alias this = member; + } + + foreach (Q; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf)) + { + foreach (T; AliasSeq!(int[], char[], string, long[3][], double[string][])) + { + enum E : Q!T { a = Q!T.init } + + static assert( isDynamicArray!(Q!T)); + static assert(!isDynamicArray!E); + static assert(!isDynamicArray!(AliasThis!(Q!T))); + } + + foreach (T; AliasSeq!(int, int[51], int[][2], + char[][int][11], immutable char[13u], + const(real)[1], const(real)[1][1], void[0])) + { + enum E : Q!T { a = Q!T.init } + + static assert(!isDynamicArray!(Q!T)); + static assert(!isDynamicArray!E); + static assert(!isDynamicArray!(AliasThis!(Q!T))); + } + } +} + +/++ + Whether type $(D T) is a static array. + + Note that this does not include implicit conversions or enum types. The + type itself must be a static array. This is in contrast to + $(D __traits(isStaticArray, T)) which is true for enums (but not for other + implict conversions to static arrays). + + As explained in the module documentation, traits like this one are not true + for enums (unlike most of the $(D __traits) traits) in order to avoid + testing for implicit conversions by default with template constraints, + since that tends to lead to subtle bugs when the code isn't carefully + written to take implicit conversions into account. + + See also: + $(DDSUBLINK spec/traits, isStaticArray, $(D __traits(isStaticArray, T))) + $(DDSUBLINK spec/arrays, , The language spec for arrays) + +/ +enum isStaticArray(T) = is(T == U[n], U, size_t n); + +/// +@safe unittest +{ + // Some types which are static arrays. + static assert( isStaticArray!(int[12])); + static assert( isStaticArray!(const int[42])); + static assert( isStaticArray!(inout int[0])); + static assert( isStaticArray!(shared(int)[907])); + static assert( isStaticArray!(immutable(char)[5])); + + // D doesn't have static array literals, but you get the same effect + // by casting a dynamic array literal to a static array, and of course, + // the result is typed as a static array. + static assert( isStaticArray!(typeof(cast(int[3]) [1, 2, 3]))); + + int[2] sArr = [1, 2]; + static assert( isStaticArray!(typeof(sArr))); + + // Some types which are not static arrays. + static assert(!isStaticArray!int); + static assert(!isStaticArray!(int*)); + static assert(!isStaticArray!real); + + static struct S + { + int[4] arr; + } + static assert(!isStaticArray!S); + + // The struct itself isn't considered a static array, + // but its member variable is when checked directly. + static assert( isStaticArray!(typeof(S.arr))); + + // Dynamic arrays. + static assert(!isStaticArray!(int[])); + static assert(!isStaticArray!(const(int)[])); + static assert(!isStaticArray!string); + + int[] arr; + static assert(!isStaticArray!(typeof(arr))); + + // A slice of a static array is of course not a static array, + // because it's a dynamic array. + static assert(!isStaticArray!(typeof(sArr[]))); + + // Static array of dynamic arrays. + static assert( isStaticArray!(long[][3])); + + // Dynamic array of static arrays. + static assert(!isStaticArray!(long[3][])); + + // Associative array. + static assert(!isStaticArray!(int[string])); + + // Of course, null is not considered to be a static array. + static assert(!isStaticArray!(typeof(null))); + + enum E : int[3] + { + a = [1, 2, 3], + } + + // Enums do not count. + static assert(!isStaticArray!E); + + // This is where isStaticArray differs from __traits(isStaticArray, ...) + static assert( __traits(isStaticArray, E)); + + static struct AliasThis + { + int[] arr; + alias this = arr; + } + + // Other implicit conversions do not count. + static assert(!isStaticArray!AliasThis); + + static assert(!__traits(isStaticArray, AliasThis)); +} + +@safe unittest +{ + import phobos.sys.meta : Alias, AliasSeq; + + static struct AliasThis(T) + { + T member; + alias this = member; + } + + foreach (Q; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf)) + { + foreach (T; AliasSeq!(int[51], int[][2], + char[][int][11], immutable char[13u], + const(real)[1], const(real)[1][1], void[0])) + { + enum E : Q!T { a = Q!T.init, } + + static assert( isStaticArray!(Q!T)); + static assert(!isStaticArray!E); + static assert(!isStaticArray!(AliasThis!(Q!T))); + } + + foreach (T; AliasSeq!(int, int[], char[], string, long[3][], double[string][])) + { + enum E : Q!T { a = Q!T.init, } + + static assert(!isStaticArray!(Q!T)); + static assert(!isStaticArray!E); + static assert(!isStaticArray!(AliasThis!(Q!T))); + } + } +} + +/++ + Whether the given type is one of the built-in integer types, ignoring all + qualifiers. + + $(TABLE + $(TR $(TH Integer Types)) + $(TR $(TD byte)) + $(TR $(TD ubyte)) + $(TR $(TD short)) + $(TR $(TD ushort)) + $(TR $(TD int)) + $(TR $(TD uint)) + $(TR $(TD long)) + $(TR $(TD ulong)) + ) + + Note that this does not include implicit conversions or enum types. The + type itself must be one of the built-in integer types. + + This trait does have some similarities with $(D __traits(isIntegral, T)), + but $(D isIntegral) accepts a $(I lot) more types than isInteger does. + isInteger is specifically for testing for the built-in integer types, + whereas $(D isIntegral) tests for a whole set of types that are vaguely + integer-like (including $(D bool), the three built-in character types, and + some of the vector types from core.simd). So, for most code, isInteger is + going to be more appropriate, but obviously, it depends on what the code is + trying to do. + + See also: + $(DDSUBLINK spec/traits, isIntegral, $(D __traits(isIntegral, T))) + $(LREF isFloatingPoint) + $(LREF isSignedInteger) + $(LREF isNumeric) + $(LREF isUnsignedInteger) + +/ +enum isInteger(T) = is(immutable T == immutable byte) || + is(immutable T == immutable ubyte) || + is(immutable T == immutable short) || + is(immutable T == immutable ushort) || + is(immutable T == immutable int) || + is(immutable T == immutable uint) || + is(immutable T == immutable long) || + is(immutable T == immutable ulong); + +/// +@safe unittest +{ + // Some types which are integer types. + static assert( isInteger!byte); + static assert( isInteger!ubyte); + static assert( isInteger!short); + static assert( isInteger!ushort); + static assert( isInteger!int); + static assert( isInteger!uint); + static assert( isInteger!long); + static assert( isInteger!ulong); + + static assert( isInteger!(const ubyte)); + static assert( isInteger!(immutable short)); + static assert( isInteger!(inout int)); + static assert( isInteger!(shared uint)); + static assert( isInteger!(const shared ulong)); + + static assert( isInteger!(typeof(42))); + static assert( isInteger!(typeof(1234567890L))); + + int i; + static assert( isInteger!(typeof(i))); + + // Some types which aren't integer types. + static assert(!isInteger!bool); + static assert(!isInteger!char); + static assert(!isInteger!wchar); + static assert(!isInteger!dchar); + static assert(!isInteger!(int[])); + static assert(!isInteger!(ubyte[4])); + static assert(!isInteger!(int*)); + static assert(!isInteger!double); + static assert(!isInteger!string); + + static struct S + { + int i; + } + static assert(!isInteger!S); + + // The struct itself isn't considered an integer, + // but its member variable is when checked directly. + static assert( isInteger!(typeof(S.i))); + + enum E : int + { + a = 42 + } + + // Enums do not count. + static assert(!isInteger!E); + + static struct AliasThis + { + int i; + alias this = i; + } + + // Other implicit conversions do not count. + static assert(!isInteger!AliasThis); +} + +@safe unittest +{ + import phobos.sys.meta : Alias, AliasSeq; + + static struct AliasThis(T) + { + T member; + alias this = member; + } + + // The actual core.simd types available vary from system to system, so we + // have to be a bit creative here. The reason that we're testing these types + // is because __traits(isIntegral, T) accepts them, but isInteger is not + // supposed to. + template SIMDTypes() + { + import core.simd; + + alias SIMDTypes = AliasSeq!(); + static if (is(ubyte16)) + SIMDTypes = AliasSeq!(SIMDTypes, ubyte16); + static if (is(int4)) + SIMDTypes = AliasSeq!(SIMDTypes, int4); + static if (is(double2)) + SIMDTypes = AliasSeq!(SIMDTypes, double2); + static if (is(void16)) + SIMDTypes = AliasSeq!(SIMDTypes, void16); + } + + foreach (Q; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf)) + { + foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) + { + enum E : Q!T { a = Q!T.init } + + static assert( isInteger!(Q!T)); + static assert(!isInteger!E); + static assert(!isInteger!(AliasThis!(Q!T))); + } + + foreach (T; AliasSeq!(bool, char, wchar, dchar, float, double, real, SIMDTypes!(), + int[], ubyte[8], dchar[], void[], long*)) + { + enum E : Q!T { a = Q!T.init } + + static assert(!isInteger!(Q!T)); + static assert(!isInteger!E); + static assert(!isInteger!(AliasThis!(Q!T))); + } + } +} + +/++ + Whether the given type is one of the built-in signed integer types, ignoring + all qualifiers. + + $(TABLE + $(TR $(TH Signed Integer Types)) + $(TR $(TD byte)) + $(TR $(TD short)) + $(TR $(TD int)) + $(TR $(TD long)) + ) + + Note that this does not include implicit conversions or enum types. The + type itself must be one of the built-in signed integer types. + + See also: + $(LREF isFloatingPoint) + $(LREF isInteger) + $(LREF isNumeric) + $(LREF isUnsignedInteger) + +/ +enum isSignedInteger(T) = is(immutable T == immutable byte) || + is(immutable T == immutable short) || + is(immutable T == immutable int) || + is(immutable T == immutable long); + +/// +@safe unittest +{ + // Some types which are signed integer types. + static assert( isSignedInteger!byte); + static assert( isSignedInteger!short); + static assert( isSignedInteger!int); + static assert( isSignedInteger!long); + + static assert( isSignedInteger!(const byte)); + static assert( isSignedInteger!(immutable short)); + static assert( isSignedInteger!(inout int)); + static assert( isSignedInteger!(shared int)); + static assert( isSignedInteger!(const shared long)); + + static assert( isSignedInteger!(typeof(42))); + static assert( isSignedInteger!(typeof(1234567890L))); + + int i; + static assert( isSignedInteger!(typeof(i))); + + // Some types which aren't signed integer types. + static assert(!isSignedInteger!ubyte); + static assert(!isSignedInteger!ushort); + static assert(!isSignedInteger!uint); + static assert(!isSignedInteger!ulong); + + static assert(!isSignedInteger!bool); + static assert(!isSignedInteger!char); + static assert(!isSignedInteger!wchar); + static assert(!isSignedInteger!dchar); + static assert(!isSignedInteger!(int[])); + static assert(!isSignedInteger!(ubyte[4])); + static assert(!isSignedInteger!(int*)); + static assert(!isSignedInteger!double); + static assert(!isSignedInteger!string); + + static struct S + { + int i; + } + static assert(!isSignedInteger!S); + + // The struct itself isn't considered a signed integer, + // but its member variable is when checked directly. + static assert( isSignedInteger!(typeof(S.i))); + + enum E : int + { + a = 42 + } + + // Enums do not count. + static assert(!isSignedInteger!E); + + static struct AliasThis + { + int i; + alias this = i; + } + + // Other implicit conversions do not count. + static assert(!isSignedInteger!AliasThis); +} + +@safe unittest +{ + import phobos.sys.meta : Alias, AliasSeq; + + static struct AliasThis(T) + { + T member; + alias this = member; + } + + // The actual core.simd types available vary from system to system, so we + // have to be a bit creative here. The reason that we're testing these types + // is because __traits(isIntegral, T) accepts them, but isSignedInteger is + // not supposed to. + template SIMDTypes() + { + import core.simd; + + alias SIMDTypes = AliasSeq!(); + static if (is(ubyte16)) + SIMDTypes = AliasSeq!(SIMDTypes, ubyte16); + static if (is(int4)) + SIMDTypes = AliasSeq!(SIMDTypes, int4); + static if (is(double2)) + SIMDTypes = AliasSeq!(SIMDTypes, double2); + static if (is(void16)) + SIMDTypes = AliasSeq!(SIMDTypes, void16); + } + + foreach (Q; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf)) + { + foreach (T; AliasSeq!(byte, short, int, long)) + { + enum E : Q!T { a = Q!T.init } + + static assert( isSignedInteger!(Q!T)); + static assert(!isSignedInteger!E); + static assert(!isSignedInteger!(AliasThis!(Q!T))); + } + + foreach (T; AliasSeq!(ubyte, ushort, uint, ulong, + bool, char, wchar, dchar, float, double, real, SIMDTypes!(), + int[], ubyte[8], dchar[], void[], long*)) + { + enum E : Q!T { a = Q!T.init } + + static assert(!isSignedInteger!(Q!T)); + static assert(!isSignedInteger!E); + static assert(!isSignedInteger!(AliasThis!(Q!T))); + } + } +} + +/++ + Whether the given type is one of the built-in unsigned integer types, + ignoring all qualifiers. + + $(TABLE + $(TR $(TH Integer Types)) + $(TR $(TD ubyte)) + $(TR $(TD ushort)) + $(TR $(TD uint)) + $(TR $(TD ulong)) + ) + + Note that this does not include implicit conversions or enum types. The + type itself must be one of the built-in unsigned integer types. + + This trait does have some similarities with $(D __traits(isUnsigned, T)), + but $(D isUnsigned) accepts a $(I lot) more types than isUnsignedInteger + does. isUnsignedInteger is specifically for testing for the built-in + unsigned integer types, whereas $(D isUnsigned) tests for a whole set of + types that are unsigned and vaguely integer-like (including $(D bool), the + three built-in character types, and some of the vector types from + core.simd). So, for most code, isUnsignedInteger is going to be more + appropriate, but obviously, it depends on what the code is trying to do. + + See also: + $(DDSUBLINK spec/traits, isUnsigned, $(D __traits(isUnsigned, T))) + $(LREF isFloatingPoint) + $(LREF isInteger) + $(LREF isSignedInteger) + $(LREF isNumeric) + +/ +enum isUnsignedInteger(T) = is(immutable T == immutable ubyte) || + is(immutable T == immutable ushort) || + is(immutable T == immutable uint) || + is(immutable T == immutable ulong); + +/// +@safe unittest +{ + // Some types which are unsigned integer types. + static assert( isUnsignedInteger!ubyte); + static assert( isUnsignedInteger!ushort); + static assert( isUnsignedInteger!uint); + static assert( isUnsignedInteger!ulong); + + static assert( isUnsignedInteger!(const ubyte)); + static assert( isUnsignedInteger!(immutable ushort)); + static assert( isUnsignedInteger!(inout uint)); + static assert( isUnsignedInteger!(shared uint)); + static assert( isUnsignedInteger!(const shared ulong)); + + static assert( isUnsignedInteger!(typeof(42u))); + static assert( isUnsignedInteger!(typeof(1234567890UL))); + + uint u; + static assert( isUnsignedInteger!(typeof(u))); + + // Some types which aren't unsigned integer types. + static assert(!isUnsignedInteger!byte); + static assert(!isUnsignedInteger!short); + static assert(!isUnsignedInteger!int); + static assert(!isUnsignedInteger!long); + + static assert(!isUnsignedInteger!bool); + static assert(!isUnsignedInteger!char); + static assert(!isUnsignedInteger!wchar); + static assert(!isUnsignedInteger!dchar); + static assert(!isUnsignedInteger!(int[])); + static assert(!isUnsignedInteger!(ubyte[4])); + static assert(!isUnsignedInteger!(int*)); + static assert(!isUnsignedInteger!double); + static assert(!isUnsignedInteger!string); + + static struct S + { + uint u; + } + static assert(!isUnsignedInteger!S); + + // The struct itself isn't considered an unsigned integer, + // but its member variable is when checked directly. + static assert( isUnsignedInteger!(typeof(S.u))); + + enum E : uint + { + a = 42 + } + + // Enums do not count. + static assert(!isUnsignedInteger!E); + + static struct AliasThis + { + uint u; + alias this = u; + } + + // Other implicit conversions do not count. + static assert(!isUnsignedInteger!AliasThis); +} + +@safe unittest +{ + import phobos.sys.meta : Alias, AliasSeq; + + static struct AliasThis(T) + { + T member; + alias this = member; + } + + // The actual core.simd types available vary from system to system, so we + // have to be a bit creative here. The reason that we're testing these types + // is because __traits(isIntegral, T) and __traits(isUnsigned, T) accept + // them, but isUnsignedInteger is not supposed to. + template SIMDTypes() + { + import core.simd; + + alias SIMDTypes = AliasSeq!(); + static if (is(ubyte16)) + SIMDTypes = AliasSeq!(SIMDTypes, ubyte16); + static if (is(int4)) + SIMDTypes = AliasSeq!(SIMDTypes, int4); + static if (is(double2)) + SIMDTypes = AliasSeq!(SIMDTypes, double2); + static if (is(void16)) + SIMDTypes = AliasSeq!(SIMDTypes, void16); + } + + foreach (Q; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf)) + { + foreach (T; AliasSeq!(ubyte, ushort, uint, ulong)) + { + enum E : Q!T { a = Q!T.init } + + static assert( isUnsignedInteger!(Q!T)); + static assert(!isUnsignedInteger!E); + static assert(!isUnsignedInteger!(AliasThis!(Q!T))); + } + + foreach (T; AliasSeq!(byte, short, int, long, + bool, char, wchar, dchar, float, double, real, SIMDTypes!(), + int[], ubyte[8], dchar[], void[], long*)) + { + enum E : Q!T { a = Q!T.init } + + static assert(!isUnsignedInteger!(Q!T)); + static assert(!isUnsignedInteger!E); + static assert(!isUnsignedInteger!(AliasThis!(Q!T))); + } + } +} + +/++ + Whether the given type is one of the built-in floating-point types, ignoring + all qualifiers. + + $(TABLE + $(TR $(TH Floating-Point Types)) + $(TR $(TD float)) + $(TR $(TD double)) + $(TR $(TD real)) + ) + + Note that this does not include implicit conversions or enum types. The + type itself must be one of the built-in floating-point types. + + This trait does have some similarities with $(D __traits(isFloating, T)), + but $(D isFloating) accepts more types than isFloatingPoint does. + isFloatingPoint is specifically for testing for the built-in floating-point + types, whereas $(D isFloating) tests for a whole set of types that are + vaguely float-like (including enums with a base type which is a + floating-point type and some of the vector types from core.simd). So, for + most code, isFloatingPoint is going to be more appropriate, but obviously, + it depends on what the code is trying to do. + + See also: + $(DDSUBLINK spec/traits, isFloating, $(D __traits(isFloating, T))) + $(LREF isInteger) + $(LREF isSignedInteger) + $(LREF isNumeric) + $(LREF isUnsignedInteger) + +/ +enum isFloatingPoint(T) = is(immutable T == immutable float) || + is(immutable T == immutable double) || + is(immutable T == immutable real); + +/// +@safe unittest +{ + // Some types which are floating-point types. + static assert( isFloatingPoint!float); + static assert( isFloatingPoint!double); + static assert( isFloatingPoint!real); + + static assert( isFloatingPoint!(const float)); + static assert( isFloatingPoint!(immutable float)); + static assert( isFloatingPoint!(inout double)); + static assert( isFloatingPoint!(shared double)); + static assert( isFloatingPoint!(const shared real)); + + static assert( isFloatingPoint!(typeof(42.0))); + static assert( isFloatingPoint!(typeof(42f))); + static assert( isFloatingPoint!(typeof(1e5))); + static assert( isFloatingPoint!(typeof(97.4L))); + + double d; + static assert( isFloatingPoint!(typeof(d))); + + // Some types which aren't floating-point types. + static assert(!isFloatingPoint!bool); + static assert(!isFloatingPoint!char); + static assert(!isFloatingPoint!dchar); + static assert(!isFloatingPoint!int); + static assert(!isFloatingPoint!long); + static assert(!isFloatingPoint!(float[])); + static assert(!isFloatingPoint!(double[4])); + static assert(!isFloatingPoint!(real*)); + static assert(!isFloatingPoint!string); + + static struct S + { + double d; + } + static assert(!isFloatingPoint!S); + + // The struct itself isn't considered a floating-point type, + // but its member variable is when checked directly. + static assert( isFloatingPoint!(typeof(S.d))); + + enum E : double + { + a = 12.34 + } + + // Enums do not count. + static assert(!isFloatingPoint!E); + + static struct AliasThis + { + double d; + alias this = d; + } + + // Other implicit conversions do not count. + static assert(!isFloatingPoint!AliasThis); +} + +@safe unittest +{ + import phobos.sys.meta : Alias, AliasSeq; + + static struct AliasThis(T) + { + T member; + alias this = member; + } + + // The actual core.simd types available vary from system to system, so we + // have to be a bit creative here. The reason that we're testing these types + // is because __traits(isFloating, T) accepts them, but isFloatingPoint is + // not supposed to. + template SIMDTypes() + { + import core.simd; + + alias SIMDTypes = AliasSeq!(); + static if (is(int4)) + SIMDTypes = AliasSeq!(SIMDTypes, int4); + static if (is(double2)) + SIMDTypes = AliasSeq!(SIMDTypes, double2); + static if (is(void16)) + SIMDTypes = AliasSeq!(SIMDTypes, void16); + } + + foreach (Q; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf)) + { + foreach (T; AliasSeq!(float, double, real)) + { + enum E : Q!T { a = Q!T.init } + + static assert( isFloatingPoint!(Q!T)); + static assert(!isFloatingPoint!E); + static assert(!isFloatingPoint!(AliasThis!(Q!T))); + } + + foreach (T; AliasSeq!(bool, char, wchar, dchar, byte, ubyte, short, ushort, + int, uint, long, ulong, SIMDTypes!(), + int[], float[8], real[], void[], double*)) + { + enum E : Q!T { a = Q!T.init } + + static assert(!isFloatingPoint!(Q!T)); + static assert(!isFloatingPoint!E); + static assert(!isFloatingPoint!(AliasThis!(Q!T))); + } + } +} + +/++ + Whether the given type is one of the built-in numeric types, ignoring all + qualifiers. It's equivalent to $(D isInteger!T || isFloatingPoint!T), but + it only involves a single template instantation instead of two. + + $(TABLE + $(TR $(TH Numeric Types)) + $(TR $(TD byte)) + $(TR $(TD ubyte)) + $(TR $(TD short)) + $(TR $(TD ushort)) + $(TR $(TD int)) + $(TR $(TD uint)) + $(TR $(TD long)) + $(TR $(TD ulong)) + $(TR $(TD float)) + $(TR $(TD double)) + $(TR $(TD real)) + ) + + Note that this does not include implicit conversions or enum types. The + type itself must be one of the built-in numeric types. + + See_Also: + $(LREF isFloatingPoint) + $(LREF isInteger) + $(LREF isSignedInteger) + $(LREF isUnsignedInteger) + +/ +enum isNumeric(T) = is(immutable T == immutable byte) || + is(immutable T == immutable ubyte) || + is(immutable T == immutable short) || + is(immutable T == immutable ushort) || + is(immutable T == immutable int) || + is(immutable T == immutable uint) || + is(immutable T == immutable long) || + is(immutable T == immutable ulong) || + is(immutable T == immutable float) || + is(immutable T == immutable double) || + is(immutable T == immutable real); + +/// +@safe unittest +{ + // Some types which are numeric types. + static assert( isNumeric!byte); + static assert( isNumeric!ubyte); + static assert( isNumeric!short); + static assert( isNumeric!ushort); + static assert( isNumeric!int); + static assert( isNumeric!uint); + static assert( isNumeric!long); + static assert( isNumeric!ulong); + static assert( isNumeric!float); + static assert( isNumeric!double); + static assert( isNumeric!real); + + static assert( isNumeric!(const short)); + static assert( isNumeric!(immutable int)); + static assert( isNumeric!(inout uint)); + static assert( isNumeric!(shared long)); + static assert( isNumeric!(const shared real)); + + static assert( isNumeric!(typeof(42))); + static assert( isNumeric!(typeof(1234657890L))); + static assert( isNumeric!(typeof(42.0))); + static assert( isNumeric!(typeof(42f))); + static assert( isNumeric!(typeof(1e5))); + static assert( isNumeric!(typeof(97.4L))); + + int i; + static assert( isNumeric!(typeof(i))); + + // Some types which aren't numeric types. + static assert(!isNumeric!bool); + static assert(!isNumeric!char); + static assert(!isNumeric!dchar); + static assert(!isNumeric!(int[])); + static assert(!isNumeric!(double[4])); + static assert(!isNumeric!(real*)); + static assert(!isNumeric!string); + + static struct S + { + int i; + } + static assert(!isNumeric!S); + + // The struct itself isn't considered a numeric type, + // but its member variable is when checked directly. + static assert( isNumeric!(typeof(S.i))); + + enum E : int + { + a = 42 + } + + // Enums do not count. + static assert(!isNumeric!E); + + static struct AliasThis + { + int i; + alias this = i; + } + + // Other implicit conversions do not count. + static assert(!isNumeric!AliasThis); +} + +@safe unittest +{ + import phobos.sys.meta : Alias, AliasSeq; + + static struct AliasThis(T) + { + T member; + alias this = member; + } + + // The actual core.simd types available vary from system to system, so we + // have to be a bit creative here. The reason that we're testing these types + // is because __traits(isInteger, T) and __traits(isFloating, T) accept + // them, but isNumeric is not supposed to. + template SIMDTypes() + { + import core.simd; + + alias SIMDTypes = AliasSeq!(); + static if (is(int4)) + SIMDTypes = AliasSeq!(SIMDTypes, int4); + static if (is(double2)) + SIMDTypes = AliasSeq!(SIMDTypes, double2); + static if (is(void16)) + SIMDTypes = AliasSeq!(SIMDTypes, void16); + } + + foreach (Q; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf)) + { + foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real)) + { + enum E : Q!T { a = Q!T.init } + + static assert( isNumeric!(Q!T)); + static assert(!isNumeric!E); + static assert(!isNumeric!(AliasThis!(Q!T))); + } + + foreach (T; AliasSeq!(bool, char, wchar, dchar, SIMDTypes!(), + int[], float[8], real[], void[], double*)) + { + enum E : Q!T { a = Q!T.init } + + static assert(!isNumeric!(Q!T)); + static assert(!isNumeric!E); + static assert(!isNumeric!(AliasThis!(Q!T))); + } + } +} + +/++ + Whether the given type is a pointer. + + Note that this does not include implicit conversions or enum types. The + type itself must be a pointer. + + Also, remember that unlike C/C++, D's arrays are not pointers. Rather, a + dynamic array in D is a slice of memory which has a member which is a + pointer to its first element and another member which is the length of the + array as $(D size_t). So, a dynamic array / slice has a $(D ptr) member + which is a pointer, but the dynamic array itself is not a pointer. + + See_Also: + $(LREF isDynamicArray) + +/ +enum isPointer(T) = is(T == U*, U); + +/// +@system unittest +{ + // Some types which are pointers. + static assert( isPointer!(bool*)); + static assert( isPointer!(int*)); + static assert( isPointer!(int**)); + static assert( isPointer!(real*)); + static assert( isPointer!(string*)); + + static assert( isPointer!(const int*)); + static assert( isPointer!(immutable int*)); + static assert( isPointer!(inout int*)); + static assert( isPointer!(shared int*)); + static assert( isPointer!(const shared int*)); + + static assert( isPointer!(typeof("foobar".ptr))); + + int* ptr; + static assert( isPointer!(typeof(ptr))); + + int i; + static assert( isPointer!(typeof(&i))); + + // Some types which aren't pointers. + static assert(!isPointer!bool); + static assert(!isPointer!int); + static assert(!isPointer!dchar); + static assert(!isPointer!(int[])); + static assert(!isPointer!(double[4])); + static assert(!isPointer!string); + + static struct S + { + int* ptr; + } + static assert(!isPointer!S); + + // The struct itself isn't considered a numeric type, + // but its member variable is when checked directly. + static assert( isPointer!(typeof(S.ptr))); + + enum E : immutable(char*) + { + a = "foobar".ptr + } + + // Enums do not count. + static assert(!isPointer!E); + + static struct AliasThis + { + int* ptr; + alias this = ptr; + } + + // Other implicit conversions do not count. + static assert(!isPointer!AliasThis); +} + +@safe unittest +{ + import phobos.sys.meta : Alias, AliasSeq; + + static struct AliasThis(T) + { + T member; + alias this = member; + } + + static struct S + { + int i; + } + + foreach (Q; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf)) + { + foreach (T; AliasSeq!(long*, S*, S**, S***, double[]*)) + { + enum E : Q!T { a = Q!T.init } + + static assert( isPointer!(Q!T)); + static assert(!isPointer!E); + static assert(!isPointer!(AliasThis!(Q!T))); + } + + foreach (T; AliasSeq!(bool, char, wchar, dchar, byte, int, uint, long, + int[], float[8], real[], void[])) + { + enum E : Q!T { a = Q!T.init } + + static assert(!isPointer!(Q!T)); + static assert(!isPointer!E); + static assert(!isPointer!(AliasThis!(Q!T))); + } + } +} + +/++ + Evaluates to $(D true) if the given type or symbol is an instantiation of + the given template. + + The overload which takes $(D T) operates on types and indicates whether an + aggregate type (i.e. struct, class, interface, or union) is an + instantiation of the given template. + + The overload which takes $(D Symbol) operates on function templates, + because unlike with aggregate types, the type of a function does not retain + the fact that it was instantiated from a template. So, for functions, it's + necessary to pass the function itself as a symbol rather than pass the type + of the function. + + The overload which takes $(D Symbol) also works with templates which are + not types or functions. + + The single-argument overload makes it so that it can be partially + instantiated with the first argument, which will often be necessary with + template predicates. + +/ +template isInstantiationOf(alias Template, T) +if (__traits(isTemplate, Template)) +{ + enum isInstantiationOf = is(T == Template!Args, Args...); +} + +/++ Ditto +/ +template isInstantiationOf(alias Template, alias Symbol) +if (__traits(isTemplate, Template)) +{ + enum impl(alias T : Template!Args, Args...) = true; + enum impl(alias T) = false; + enum isInstantiationOf = impl!Symbol; +} + +/++ Ditto +/ +template isInstantiationOf(alias Template) +if (__traits(isTemplate, Template)) +{ + enum isInstantiationOf(T) = is(T == Template!Args, Args...); + + template isInstantiationOf(alias Symbol) + { + enum impl(alias T : Template!Args, Args...) = true; + enum impl(alias T) = false; + enum isInstantiationOf = impl!Symbol; + } +} + +/// Examples of templated types. +@safe unittest +{ + static struct S(T) {} + static class C(T) {} + + static assert( isInstantiationOf!(S, S!int)); + static assert( isInstantiationOf!(S, S!int)); + static assert( isInstantiationOf!(S, S!string)); + static assert( isInstantiationOf!(S, const S!string)); + static assert( isInstantiationOf!(S, shared S!string)); + static assert(!isInstantiationOf!(S, int)); + static assert(!isInstantiationOf!(S, C!int)); + static assert(!isInstantiationOf!(S, C!string)); + static assert(!isInstantiationOf!(S, C!(S!int))); + + static assert( isInstantiationOf!(C, C!int)); + static assert( isInstantiationOf!(C, C!string)); + static assert( isInstantiationOf!(C, const C!string)); + static assert( isInstantiationOf!(C, shared C!string)); + static assert(!isInstantiationOf!(C, int)); + static assert(!isInstantiationOf!(C, S!int)); + static assert(!isInstantiationOf!(C, S!string)); + static assert(!isInstantiationOf!(C, S!(C!int))); + + static struct Variadic(T...) {} + + static assert( isInstantiationOf!(Variadic, Variadic!())); + static assert( isInstantiationOf!(Variadic, Variadic!int)); + static assert( isInstantiationOf!(Variadic, Variadic!(int, string))); + static assert( isInstantiationOf!(Variadic, Variadic!(int, string, int))); + static assert( isInstantiationOf!(Variadic, const Variadic!(int, short))); + static assert( isInstantiationOf!(Variadic, shared Variadic!(int, short))); + static assert(!isInstantiationOf!(Variadic, int)); + static assert(!isInstantiationOf!(Variadic, S!int)); + static assert(!isInstantiationOf!(Variadic, C!int)); + + static struct ValueArg(int i) {} + static assert( isInstantiationOf!(ValueArg, ValueArg!42)); + static assert( isInstantiationOf!(ValueArg, ValueArg!256)); + static assert( isInstantiationOf!(ValueArg, const ValueArg!1024)); + static assert( isInstantiationOf!(ValueArg, shared ValueArg!1024)); + static assert(!isInstantiationOf!(ValueArg, int)); + static assert(!isInstantiationOf!(ValueArg, S!int)); + + int i; + + static struct AliasArg(alias Symbol) {} + static assert( isInstantiationOf!(AliasArg, AliasArg!42)); + static assert( isInstantiationOf!(AliasArg, AliasArg!int)); + static assert( isInstantiationOf!(AliasArg, AliasArg!i)); + static assert( isInstantiationOf!(AliasArg, const AliasArg!i)); + static assert( isInstantiationOf!(AliasArg, shared AliasArg!i)); + static assert(!isInstantiationOf!(AliasArg, int)); + static assert(!isInstantiationOf!(AliasArg, S!int)); + + // An uninstantiated template is not an instance of any template, + // not even itself. + static assert(!isInstantiationOf!(S, S)); + static assert(!isInstantiationOf!(S, C)); + static assert(!isInstantiationOf!(C, C)); + static assert(!isInstantiationOf!(C, S)); + + // Variables of a templated type are not considered instantiations of that + // type. For templated types, the overload which takes a type must be used. + S!int s; + C!string c; + static assert(!isInstantiationOf!(S, s)); + static assert(!isInstantiationOf!(C, c)); +} + +// Examples of templated functions. +@safe unittest +{ + static int foo(T...)() { return 42; } + static void bar(T...)(T var) {} + static void baz(T)(T var) {} + static bool frobozz(alias pred)(int) { return true; } + + static assert( isInstantiationOf!(foo, foo!int)); + static assert( isInstantiationOf!(foo, foo!string)); + static assert( isInstantiationOf!(foo, foo!(int, string))); + static assert(!isInstantiationOf!(foo, bar!int)); + static assert(!isInstantiationOf!(foo, bar!string)); + static assert(!isInstantiationOf!(foo, bar!(int, string))); + + static assert( isInstantiationOf!(bar, bar!int)); + static assert( isInstantiationOf!(bar, bar!string)); + static assert( isInstantiationOf!(bar, bar!(int, string))); + static assert(!isInstantiationOf!(bar, foo!int)); + static assert(!isInstantiationOf!(bar, foo!string)); + static assert(!isInstantiationOf!(bar, foo!(int, string))); + + static assert( isInstantiationOf!(baz, baz!int)); + static assert( isInstantiationOf!(baz, baz!string)); + static assert(!isInstantiationOf!(baz, foo!(int, string))); + + static assert( isInstantiationOf!(frobozz, frobozz!(a => a))); + static assert( isInstantiationOf!(frobozz, frobozz!(a => a > 2))); + static assert(!isInstantiationOf!(frobozz, baz!int)); + + // Unfortunately, the function type is not considered an instantiation of + // the template, because that information is not part of the type, unlike + // with templated structs or classes. + static assert(!isInstantiationOf!(foo, typeof(foo!int))); + static assert(!isInstantiationOf!(bar, typeof(bar!int))); +} + +// Examples of templates which aren't types or functions. +@safe unittest +{ + template SingleArg(T) {} + template Variadic(T...) {} + template ValueArg(string s) {} + template Alias(alias symbol) {} + + static assert( isInstantiationOf!(SingleArg, SingleArg!int)); + static assert( isInstantiationOf!(SingleArg, SingleArg!string)); + static assert(!isInstantiationOf!(SingleArg, int)); + static assert(!isInstantiationOf!(SingleArg, Variadic!int)); + + static assert( isInstantiationOf!(Variadic, Variadic!())); + static assert( isInstantiationOf!(Variadic, Variadic!int)); + static assert( isInstantiationOf!(Variadic, Variadic!string)); + static assert( isInstantiationOf!(Variadic, Variadic!(short, int, long))); + static assert(!isInstantiationOf!(Variadic, int)); + static assert(!isInstantiationOf!(Variadic, SingleArg!int)); + + static assert( isInstantiationOf!(ValueArg, ValueArg!"dlang")); + static assert( isInstantiationOf!(ValueArg, ValueArg!"foobar")); + static assert(!isInstantiationOf!(ValueArg, string)); + static assert(!isInstantiationOf!(ValueArg, Variadic!string)); + + int i; + + static assert( isInstantiationOf!(Alias, Alias!int)); + static assert( isInstantiationOf!(Alias, Alias!42)); + static assert( isInstantiationOf!(Alias, Alias!i)); + static assert(!isInstantiationOf!(Alias, int)); + static assert(!isInstantiationOf!(Alias, SingleArg!int)); +} + +/// Examples of partial instantation. +@safe unittest +{ + static struct SingleArg(T) {} + static struct Variadic(T...) {} + + alias isSingleArg = isInstantiationOf!SingleArg; + alias isVariadic = isInstantiationOf!Variadic; + + static assert( isSingleArg!(SingleArg!int)); + static assert( isSingleArg!(const SingleArg!int)); + static assert(!isSingleArg!int); + static assert(!isSingleArg!(Variadic!int)); + + static assert( isVariadic!(Variadic!())); + static assert( isVariadic!(Variadic!int)); + static assert( isVariadic!(shared Variadic!int)); + static assert( isVariadic!(Variadic!(int, string))); + static assert(!isVariadic!int); + static assert(!isVariadic!(SingleArg!int)); + + T foo(T)(T t) { return t; } + T likeFoo(T)(T t) { return t; } + bool bar(alias pred)(int i) { return pred(i); } + + alias isFoo = isInstantiationOf!foo; + alias isBar = isInstantiationOf!bar; + + static assert( isFoo!(foo!int)); + static assert( isFoo!(foo!string)); + static assert(!isFoo!int); + static assert(!isFoo!(likeFoo!int)); + static assert(!isFoo!(bar!(a => true))); + + static assert( isBar!(bar!(a => true))); + static assert( isBar!(bar!(a => a > 2))); + static assert(!isBar!int); + static assert(!isBar!(foo!int)); + static assert(!isBar!(likeFoo!int)); +} + +/++ + Evaluates to an $(D AliasSeq) containing the members of an enum type. + + The elements of the $(D AliasSeq) are in the same order as they are in the + enum declaration. + + An enum can have multiple members with the same value, so if code needs the + enum values to be unique (e.g. if it's generating a switch statement from + them), then $(REF Unique, phobos, sys, meta) can be used to filter out the + duplicate values - e.g. $(D Unique!(isEqual, EnumMembers!E)). + +/ +template EnumMembers(E) +if (is(E == enum)) +{ + import phobos.sys.meta : AliasSeq; + + alias EnumMembers = AliasSeq!(); + static foreach (member; __traits(allMembers, E)) + EnumMembers = AliasSeq!(EnumMembers, __traits(getMember, E, member)); +} + +/// Create an array of enum values. +@safe unittest +{ + enum Sqrts : real + { + one = 1, + two = 1.41421, + three = 1.73205 + } + auto sqrts = [EnumMembers!Sqrts]; + assert(sqrts == [Sqrts.one, Sqrts.two, Sqrts.three]); +} + +/++ + A generic function $(D rank(v)) in the following example uses this template + for finding a member $(D e) in an enum type $(D E). + +/ +@safe unittest +{ + // Returns i if e is the i-th member of E. + static size_t rank(E)(E e) + if (is(E == enum)) + { + static foreach (i, member; EnumMembers!E) + { + if (e == member) + return i; + } + assert(0, "Not an enum member"); + } + + enum Mode + { + read = 1, + write = 2, + map = 4 + } + assert(rank(Mode.read) == 0); + assert(rank(Mode.write) == 1); + assert(rank(Mode.map) == 2); +} + +/// Use EnumMembers to generate a switch statement using static foreach. +@safe unittest +{ + static class Foo + { + string calledMethod; + void foo() @safe { calledMethod = "foo"; } + void bar() @safe { calledMethod = "bar"; } + void baz() @safe { calledMethod = "baz"; } + } + + enum FuncName : string { foo = "foo", bar = "bar", baz = "baz" } + + auto foo = new Foo; + + s: final switch (FuncName.bar) + { + static foreach (member; EnumMembers!FuncName) + { + // Generate a case for each enum value. + case member: + { + // Call foo.{enum value}(). + __traits(getMember, foo, member)(); + break s; + } + } + } + + // Since we passed FuncName.bar to the switch statement, the bar member + // function was called. + assert(foo.calledMethod == "bar"); +} + +@safe unittest +{ + { + enum A { a } + static assert([EnumMembers!A] == [A.a]); + enum B { a, b, c, d, e } + static assert([EnumMembers!B] == [B.a, B.b, B.c, B.d, B.e]); + } + { + enum A : string { a = "alpha", b = "beta" } + static assert([EnumMembers!A] == [A.a, A.b]); + + static struct S + { + int value; + int opCmp(S rhs) const nothrow { return value - rhs.value; } + } + enum B : S { a = S(1), b = S(2), c = S(3) } + static assert([EnumMembers!B] == [B.a, B.b, B.c]); + } + { + enum A { a = 0, b = 0, c = 1, d = 1, e } + static assert([EnumMembers!A] == [A.a, A.b, A.c, A.d, A.e]); + } + { + enum E { member, a = 0, b = 0 } + + static assert(__traits(isSame, EnumMembers!E[0], E.member)); + static assert(__traits(isSame, EnumMembers!E[1], E.a)); + static assert(__traits(isSame, EnumMembers!E[2], E.b)); + + static assert(__traits(identifier, EnumMembers!E[0]) == "member"); + static assert(__traits(identifier, EnumMembers!E[1]) == "a"); + static assert(__traits(identifier, EnumMembers!E[2]) == "b"); + } +} + +// https://issues.dlang.org/show_bug.cgi?id=14561: huge enums +@safe unittest +{ + static string genEnum() + { + string result = "enum TLAs {"; + foreach (c0; '0' .. '2' + 1) + { + foreach (c1; '0' .. '9' + 1) + { + foreach (c2; '0' .. '9' + 1) + { + foreach (c3; '0' .. '9' + 1) + { + result ~= '_'; + result ~= c0; + result ~= c1; + result ~= c2; + result ~= c3; + result ~= ','; + } + } + } + } + result ~= '}'; + return result; + } + mixin(genEnum); + static assert(EnumMembers!TLAs[0] == TLAs._0000); + static assert(EnumMembers!TLAs[$ - 1] == TLAs._2999); +} + +/++ + Whether the type $(D From) is implicitly convertible to the type $(D To). + + Note that template constraints should be very careful about when they test + for implicit conversions and in general should prefer to either test for an + exact set of types or for types which compile with a particular piece of + code rather than being designed to accept any type which implicitly converts + to a particular type. + + This is because having a type pass a template constraint based on an + implicit conversion but then not have the implicit conversion actually take + place (which it won't unless the template does something to force it + internally) can lead to either compilation errors or subtle behavioral + differences - and even when the conversion is done explicitly within a + templated function, since it's not done at the call site, it can still lead + to subtle bugs in some cases (e.g. if slicing a static array is involved). + + For situations where code needs to verify that a type is implicitly + convertible based solely on its qualifiers, $(LREF isQualifierConvertible) + would be a more appropriate choice than isImplicitlyConvertible. + + Given how trivial the $(D is) expression for isImplicitlyConvertible is - + $(D is(To : From)) - this trait is provided primarily so that it can be + used in conjunction with templates that use a template predicate (such as + many of the templates in phobos.sys.meta). + + The single-argument overload makes it so that it can be partially + instantiated with the first argument, which will often be necessary with + template predicates. + + See_Also: + $(DDSUBLINK dlang.org/spec/type, implicit-conversions, Spec on implicit conversions) + $(DDSUBLINK spec/const3, implicit_qualifier_conversions, Spec for implicit qualifier conversions) + $(LREF isQualifierConvertible) + +/ +enum isImplicitlyConvertible(From, To) = is(From : To); + +/++ Ditto +/ +template isImplicitlyConvertible(From) +{ + enum isImplicitlyConvertible(To) = is(From : To); +} + +/// +@safe unittest +{ + static assert( isImplicitlyConvertible!(byte, long)); + static assert( isImplicitlyConvertible!(ushort, long)); + static assert( isImplicitlyConvertible!(int, long)); + static assert( isImplicitlyConvertible!(long, long)); + static assert( isImplicitlyConvertible!(ulong, long)); + + static assert( isImplicitlyConvertible!(ubyte, int)); + static assert( isImplicitlyConvertible!(short, int)); + static assert( isImplicitlyConvertible!(int, int)); + static assert( isImplicitlyConvertible!(uint, int)); + static assert(!isImplicitlyConvertible!(long, int)); + static assert(!isImplicitlyConvertible!(ulong, int)); + + static assert(!isImplicitlyConvertible!(int, string)); + static assert(!isImplicitlyConvertible!(int, int[])); + static assert(!isImplicitlyConvertible!(int, int*)); + + static assert(!isImplicitlyConvertible!(string, int)); + static assert(!isImplicitlyConvertible!(int[], int)); + static assert(!isImplicitlyConvertible!(int*, int)); + + // For better or worse, bool and the built-in character types will + // implicitly convert to integer or floating-point types if the target type + // is large enough. Sometimes, this is desirable, whereas at other times, + // it can have very surprising results, so it's one reason why code should + // be very careful when testing for implicit conversions. + static assert( isImplicitlyConvertible!(bool, int)); + static assert( isImplicitlyConvertible!(char, int)); + static assert( isImplicitlyConvertible!(wchar, int)); + static assert( isImplicitlyConvertible!(dchar, int)); + + static assert( isImplicitlyConvertible!(bool, ubyte)); + static assert( isImplicitlyConvertible!(char, ubyte)); + static assert(!isImplicitlyConvertible!(wchar, ubyte)); + static assert(!isImplicitlyConvertible!(dchar, ubyte)); + + static assert( isImplicitlyConvertible!(bool, double)); + static assert( isImplicitlyConvertible!(char, double)); + static assert( isImplicitlyConvertible!(wchar, double)); + static assert( isImplicitlyConvertible!(dchar, double)); + + // Value types can be implicitly converted regardless of their qualifiers + // thanks to the fact that they're copied. + static assert( isImplicitlyConvertible!(int, int)); + static assert( isImplicitlyConvertible!(const int, int)); + static assert( isImplicitlyConvertible!(immutable int, int)); + static assert( isImplicitlyConvertible!(inout int, int)); + + static assert( isImplicitlyConvertible!(int, const int)); + static assert( isImplicitlyConvertible!(int, immutable int)); + static assert( isImplicitlyConvertible!(int, inout int)); + + // Reference types are far more restrictive about which implicit conversions + // they allow, because qualifiers in D are transitive. + static assert( isImplicitlyConvertible!(int*, int*)); + static assert(!isImplicitlyConvertible!(const int*, int*)); + static assert(!isImplicitlyConvertible!(immutable int*, int*)); + + static assert( isImplicitlyConvertible!(int*, const int*)); + static assert( isImplicitlyConvertible!(const int*, const int*)); + static assert( isImplicitlyConvertible!(immutable int*, const int*)); + + static assert(!isImplicitlyConvertible!(int*, immutable int*)); + static assert(!isImplicitlyConvertible!(const int*, immutable int*)); + static assert( isImplicitlyConvertible!(immutable int*, immutable int*)); + + // Note that inout gets a bit weird, since it's only used with function + // parameters, and it's a stand-in for whatever mutability qualifiers the + // type actually has. So, a function parameter that's inout accepts any + // mutability, but you can't actually implicitly convert to inout, because + // it's unknown within the function what the actual mutability of the type + // is. It will differ depending on the function arguments of a specific + // call to that function, so the same code has to work with all combinations + // of mutability qualifiers. + static assert(!isImplicitlyConvertible!(int*, inout int*)); + static assert(!isImplicitlyConvertible!(const int*, inout int*)); + static assert(!isImplicitlyConvertible!(immutable int*, inout int*)); + static assert( isImplicitlyConvertible!(inout int*, inout int*)); + + static assert(!isImplicitlyConvertible!(inout int*, int*)); + static assert( isImplicitlyConvertible!(inout int*, const int*)); + static assert(!isImplicitlyConvertible!(inout int*, immutable int*)); + + // Enums implicitly convert to their base type. + enum E : int + { + a = 42 + } + static assert( isImplicitlyConvertible!(E, int)); + static assert( isImplicitlyConvertible!(E, long)); + static assert(!isImplicitlyConvertible!(E, int[])); + + // Structs only implicit convert to another type via declaring an + // alias this. + static struct S + { + int i; + } + static assert(!isImplicitlyConvertible!(S, int)); + static assert(!isImplicitlyConvertible!(S, long)); + static assert(!isImplicitlyConvertible!(S, string)); + + static struct AliasThis + { + int i; + alias this = i; + } + static assert( isImplicitlyConvertible!(AliasThis, int)); + static assert( isImplicitlyConvertible!(AliasThis, long)); + static assert(!isImplicitlyConvertible!(AliasThis, string)); + + static struct AliasThis2 + { + AliasThis at; + alias this = at; + } + static assert( isImplicitlyConvertible!(AliasThis2, AliasThis)); + static assert( isImplicitlyConvertible!(AliasThis2, int)); + static assert( isImplicitlyConvertible!(AliasThis2, long)); + static assert(!isImplicitlyConvertible!(AliasThis2, string)); + + static struct AliasThis3 + { + AliasThis2 at; + alias this = at; + } + static assert( isImplicitlyConvertible!(AliasThis3, AliasThis2)); + static assert( isImplicitlyConvertible!(AliasThis3, AliasThis)); + static assert( isImplicitlyConvertible!(AliasThis3, int)); + static assert( isImplicitlyConvertible!(AliasThis3, long)); + static assert(!isImplicitlyConvertible!(AliasThis3, string)); + + // D does not support implicit conversions via construction. + static struct Cons + { + this(int i) + { + this.i = i; + } + + int i; + } + static assert(!isImplicitlyConvertible!(int, Cons)); + + // Classes support implicit conversion based on their class and + // interface hierarchies. + static interface I1 {} + static class Base : I1 {} + + static interface I2 {} + static class Foo : Base, I2 {} + + static class Bar : Base {} + + static assert( isImplicitlyConvertible!(Base, Base)); + static assert(!isImplicitlyConvertible!(Base, Foo)); + static assert(!isImplicitlyConvertible!(Base, Bar)); + static assert( isImplicitlyConvertible!(Base, I1)); + static assert(!isImplicitlyConvertible!(Base, I2)); + + static assert( isImplicitlyConvertible!(Foo, Base)); + static assert( isImplicitlyConvertible!(Foo, Foo)); + static assert(!isImplicitlyConvertible!(Foo, Bar)); + static assert( isImplicitlyConvertible!(Foo, I1)); + static assert( isImplicitlyConvertible!(Foo, I2)); + + static assert( isImplicitlyConvertible!(Bar, Base)); + static assert(!isImplicitlyConvertible!(Bar, Foo)); + static assert( isImplicitlyConvertible!(Bar, Bar)); + static assert( isImplicitlyConvertible!(Bar, I1)); + static assert(!isImplicitlyConvertible!(Bar, I2)); + + static assert(!isImplicitlyConvertible!(I1, Base)); + static assert(!isImplicitlyConvertible!(I1, Foo)); + static assert(!isImplicitlyConvertible!(I1, Bar)); + static assert( isImplicitlyConvertible!(I1, I1)); + static assert(!isImplicitlyConvertible!(I1, I2)); + + static assert(!isImplicitlyConvertible!(I2, Base)); + static assert(!isImplicitlyConvertible!(I2, Foo)); + static assert(!isImplicitlyConvertible!(I2, Bar)); + static assert(!isImplicitlyConvertible!(I2, I1)); + static assert( isImplicitlyConvertible!(I2, I2)); + + // Note that arrays are not implicitly convertible even when their elements + // are implicitly convertible. + static assert(!isImplicitlyConvertible!(ubyte[], uint[])); + static assert(!isImplicitlyConvertible!(Foo[], Base[])); + static assert(!isImplicitlyConvertible!(Bar[], Base[])); + + // However, like with pointers, dynamic arrays are convertible based on + // constness. + static assert( isImplicitlyConvertible!(Base[], const Base[])); + static assert( isImplicitlyConvertible!(Base[], const(Base)[])); + static assert(!isImplicitlyConvertible!(Base[], immutable(Base)[])); + static assert(!isImplicitlyConvertible!(const Base[], immutable Base[])); + static assert( isImplicitlyConvertible!(const Base[], const Base[])); + static assert(!isImplicitlyConvertible!(const Base[], immutable Base[])); +} + +/++ + isImplicitlyConvertible can be used with partial instantiation so that it + can be passed to a template which takes a unary predicate. + +/ +@safe unittest +{ + import phobos.sys.meta : AliasSeq, all, indexOf; + + // byte is implicitly convertible to byte, short, int, and long. + static assert(all!(isImplicitlyConvertible!byte, short, int, long)); + + // const(char)[] at index 2 is the first type in the AliasSeq which string + // can be implicitly converted to. + alias Types = AliasSeq!(int, char[], const(char)[], string, int*); + static assert(indexOf!(isImplicitlyConvertible!string, Types) == 2); +} + +/++ + Whether $(D From) is + $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) + to $(D To). + + This is testing whether $(D From) and $(D To) are the same type - minus the + qualifiers - and whether the qualifiers on $(D From) can be implicitly + converted to the qualifiers on $(D To). No other implicit conversions are + taken into account. + + For instance, $(D const int*) is not implicitly convertible to $(D int*), + because that would violate $(D const). That means that $(D const) is not + qualifier convertible to mutable. And as such, $(I any) $(D const) type + is not qualifier convertible to a mutable type even if it's implicitly + convertible. E.G. $(D const int) is implicitly convertible to $(D int), + because it can be copied to avoid violating $(D const), but it's still not + qualifier convertible, because $(D const) types in general cannot be + implicitly converted to mutable. + + The exact types being tested matter, because they need to be the same + (minus the qualifiers) in order to be considered convertible, but beyond + that, all that matters for the conversion is whether those qualifers would + be convertible regardless of which types they were on. So, if you're having + trouble picturing whether $(D From) would be qualifier convertible to + $(D To), then consider which conversions would be allowed from $(D From[]) + to $(D To[]) (and remember that dynamic arrays are only implicitly + convertible based on their qualifers). + + The $(DDSUBLINK spec/const3, implicit_qualifier_conversions, spec) provides + a table of which qualifiers can be implcitly converted to which other + qualifers (and of course, there a bunch of examples below). + + So, isQualifierConvertible can be used in a case like + $(D isQualifierConvertible!(ReturnType!(typeof(foo(bar))), const char), + which would be testing that the return type of $(D foo(bar)) was $(D char), + $(D const char), or $(D immutable char) (since those are the only types + which are qualifier convertible to $(D const char)). + + This is in contrast to + $(D isImplicitlyConvertible!(ReturnType!(typeof(foo(bar))), const char), + which would be $(D true) for $(I any) type which was implicitly convertible + to $(D const char) rather than just $(D char), $(D const char), and + $(D immutable char). + + The single-argument overload makes it so that it can be partially + instantiated with the first argument, which will often be necessary with + template predicates. + + See_Also: + $(DDSUBLINK spec/const3, implicit_qualifier_conversions, Spec for implicit qualifier conversions) + $(LREF isImplicitlyConvertible) + +/ +enum isQualifierConvertible(From, To) = is(immutable From == immutable To) && is(From* : To*); + +/++ Ditto +/ +template isQualifierConvertible(From) +{ + enum isQualifierConvertible(To) = is(immutable From == immutable To) && is(From* : To*); +} + +/// +@safe unittest +{ + // i.e. char* -> const char* + static assert( isQualifierConvertible!(char, const char)); + + // i.e. const char* -> char* + static assert(!isQualifierConvertible!(const char, char)); + + static assert( isQualifierConvertible!(int, int)); + static assert( isQualifierConvertible!(int, const int)); + static assert(!isQualifierConvertible!(int, immutable int)); + + static assert(!isQualifierConvertible!(const int, int)); + static assert( isQualifierConvertible!(const int, const int)); + static assert(!isQualifierConvertible!(const int, immutable int)); + + static assert(!isQualifierConvertible!(immutable int, int)); + static assert( isQualifierConvertible!(immutable int, const int)); + static assert( isQualifierConvertible!(immutable int, immutable int)); + + // Note that inout gets a bit weird, since it's only used with function + // parameters, and it's a stand-in for whatever mutability qualifiers the + // type actually has. So, a function parameter that's inout accepts any + // mutability, but you can't actually implicitly convert to inout, because + // it's unknown within the function what the actual mutability of the type + // is. It will differ depending on the function arguments of a specific + // call to that function, so the same code has to work with all combinations + // of mutability qualifiers. + static assert(!isQualifierConvertible!(int, inout int)); + static assert(!isQualifierConvertible!(const int, inout int)); + static assert(!isQualifierConvertible!(immutable int, inout int)); + static assert( isQualifierConvertible!(inout int, inout int)); + + static assert(!isQualifierConvertible!(inout int, int)); + static assert( isQualifierConvertible!(inout int, const int)); + static assert(!isQualifierConvertible!(inout int, immutable int)); + + // shared is of course also a qualifier. + static assert(!isQualifierConvertible!(int, shared int)); + static assert(!isQualifierConvertible!(int, const shared int)); + static assert(!isQualifierConvertible!(const int, shared int)); + static assert(!isQualifierConvertible!(const int, const shared int)); + static assert(!isQualifierConvertible!(immutable int, shared int)); + static assert( isQualifierConvertible!(immutable int, const shared int)); + + static assert(!isQualifierConvertible!(shared int, int)); + static assert(!isQualifierConvertible!(shared int, const int)); + static assert(!isQualifierConvertible!(shared int, immutable int)); + static assert( isQualifierConvertible!(shared int, shared int)); + static assert( isQualifierConvertible!(shared int, const shared int)); + + static assert(!isQualifierConvertible!(const shared int, int)); + static assert(!isQualifierConvertible!(const shared int, const int)); + static assert(!isQualifierConvertible!(const shared int, immutable int)); + static assert(!isQualifierConvertible!(const shared int, shared int)); + static assert( isQualifierConvertible!(const shared int, const shared int)); + + // Implicit conversions don't count unless they're based purely on + // qualifiers. + enum E : int + { + a = 1 + } + + static assert(!isQualifierConvertible!(E, int)); + static assert(!isQualifierConvertible!(E, const int)); + static assert( isQualifierConvertible!(E, E)); + static assert( isQualifierConvertible!(E, const E)); + static assert(!isQualifierConvertible!(E, immutable E)); + + static struct AliasThis + { + int i; + alias this = i; + } + + static assert(!isQualifierConvertible!(AliasThis, int)); + static assert(!isQualifierConvertible!(AliasThis, const int)); + static assert( isQualifierConvertible!(AliasThis, AliasThis)); + static assert( isQualifierConvertible!(AliasThis, const AliasThis)); + static assert(!isQualifierConvertible!(AliasThis, immutable AliasThis)); + + // The qualifiers are irrelevant if the types aren't the same when + // stripped of all qualifers. + static assert(!isQualifierConvertible!(int, long)); + static assert(!isQualifierConvertible!(int, const long)); + static assert(!isQualifierConvertible!(string, const(ubyte)[])); +} + +/++ + isQualifierConvertible can be used with partial instantiation so that it + can be passed to a template which takes a unary predicate. + +/ +@safe unittest +{ + import phobos.sys.meta : AliasSeq, all, indexOf; + + // byte is qualifier convertible to byte and const byte. + static assert(all!(isQualifierConvertible!byte, byte, const byte)); + + // const(char[]) at index 2 is the first type in the AliasSeq which string + // is qualifier convertible to. + alias Types = AliasSeq!(int, char[], const(char[]), string, int*); + static assert(indexOf!(isQualifierConvertible!string, Types) == 2); +} + +@safe unittest +{ + import phobos.sys.meta : AliasSeq; + + alias Types = AliasSeq!(int, const int, shared int, inout int, const shared int, + const inout int, inout shared int, const inout shared int, immutable int); + + // https://dlang.org/spec/const3.html#implicit_qualifier_conversions + enum _ = 0; + static immutable bool[Types.length][Types.length] conversions = [ + // m c s i cs ci is cis im + [1, 1, _, _, _, _, _, _, _], // mutable + [_, 1, _, _, _, _, _, _, _], // const + [_, _, 1, _, 1, _, _, _, _], // shared + [_, 1, _, 1, _, 1, _, _, _], // inout + [_, _, _, _, 1, _, _, _, _], // const shared + [_, 1, _, _, _, 1, _, _, _], // const inout + [_, _, _, _, 1, _, 1, 1, _], // inout shared + [_, _, _, _, 1, _, _, 1, _], // const inout shared + [_, 1, _, _, 1, 1, _, 1, 1], // immutable + ]; + + foreach (i, From; Types) + { + foreach (j, To; Types) + { + static assert(isQualifierConvertible!(From, To) == conversions[i][j], + "`isQualifierConvertible!(" ~ From.stringof ~ ", " ~ To.stringof ~ ")`" ~ + " should be `" ~ (conversions[i][j] ? "true`" : "false`")); + } + } +} + +/++ + Whether the given values are equal per $(D ==). + + All this does is $(D lhs == rhs) but in an eponymous template, so most code + shouldn't use it. It's intended to be used in conjunction with templates + that take a template predicate - such as those in phobos.sys.meta. + + The single-argument overload makes it so that it can be partially + instantiated with the first argument, which will often be necessary with + template predicates. + + Note that in most cases, even when comparing values at compile time, using + isEqual makes no sense, because you can use CTFE to just compare two values + (or expressions which evaluate to values), but in rare cases where you need + to compare symbols in an $(D AliasSeq) by value with a template predicate + while still leaving them as symbols in an $(D AliasSeq), then isEqual would + be needed. + + A prime example of this would be $(D Unique!(isEqual, EnumMembers!MyEnum)), + which results in an $(D AliasSeq) containing the list of members of + $(D MyEnum) but without any duplicate values (e.g. to use when doing code + generation to create a final switch). + + Alternatively, code such as $(D [EnumMembers!MyEnum].sort().unique()) could + be used to get a dynamic array of the enum members with no duplicate values + via CTFE, thus avoiding the need for template predicates or anything from + phobos.sys.meta. However, you then have a dynamic array of enum values + rather than an $(D AliasSeq) of symbols for those enum members, which + affects what you can do with type introspection. So, which approach is + better depends on what the code needs to do with the enum members. + + In general, however, if code doesn't need an $(D AliasSeq), and an array of + values will do the trick, then it's more efficient to operate on an array of + values with CTFE and avoid using isEqual or other templates to operate on + the values as an $(D AliasSeq). + + See_Also: + $(LREF isSameSymbol) + $(LREF isSameType) + +/ +enum isEqual(alias lhs, alias rhs) = lhs == rhs; + +/++ Ditto +/ +template isEqual(alias lhs) +{ + enum isEqual(alias rhs) = lhs == rhs; +} + +/// It acts just like ==, but it's a template. +@safe unittest +{ + enum a = 42; + + static assert( isEqual!(a, 42)); + static assert( isEqual!(20, 10 + 10)); + + static assert(!isEqual!(a, 120)); + static assert(!isEqual!(77, 19 * 7 + 2)); + + // b cannot be read at compile time, so it won't work with isEqual. + int b = 99; + static assert(!__traits(compiles, isEqual!(b, 99))); +} + +/++ + Comparing some of the differences between an $(D AliasSeq) of enum members + and an array of enum values created from an $(D AliasSeq) of enum members. + +/ +@safe unittest +{ + import phobos.sys.meta : AliasSeq, Unique; + + enum E + { + a = 0, + b = 22, + c = 33, + d = 0, + e = 256, + f = 33, + g = 7 + } + + alias uniqueMembers = Unique!(isEqual, EnumMembers!E); + static assert(uniqueMembers.length == 5); + + static assert(__traits(isSame, uniqueMembers[0], E.a)); + static assert(__traits(isSame, uniqueMembers[1], E.b)); + static assert(__traits(isSame, uniqueMembers[2], E.c)); + static assert(__traits(isSame, uniqueMembers[3], E.e)); + static assert(__traits(isSame, uniqueMembers[4], E.g)); + + static assert(__traits(identifier, uniqueMembers[0]) == "a"); + static assert(__traits(identifier, uniqueMembers[1]) == "b"); + static assert(__traits(identifier, uniqueMembers[2]) == "c"); + static assert(__traits(identifier, uniqueMembers[3]) == "e"); + static assert(__traits(identifier, uniqueMembers[4]) == "g"); + + // Same value but different symbol. + static assert(uniqueMembers[0] == E.d); + static assert(!__traits(isSame, uniqueMembers[0], E.d)); + + // is expressions compare types, not symbols or values, and these AliasSeqs + // contain the list of symbols for the enum members, not types, so the is + // expression evaluates to false even though the symbols are the same. + static assert(!is(uniqueMembers == AliasSeq!(E.a, E.b, E.c, E.e, E.g))); + + // Once the members are converted to an array, the types are the same, and + // the values are the same, but the symbols are not the same. Instead of + // being the symbols E.a, E.b, etc., they're just values with the type E + // which match the values of E.a, E.b, etc. + enum arr = [uniqueMembers]; + static assert(is(typeof(arr) == E[])); + + static assert(arr == [E.a, E.b, E.c, E.e, E.g]); + static assert(arr == [E.d, E.b, E.f, E.e, E.g]); + + static assert(!__traits(isSame, arr[0], E.a)); + static assert(!__traits(isSame, arr[1], E.b)); + static assert(!__traits(isSame, arr[2], E.c)); + static assert(!__traits(isSame, arr[3], E.e)); + static assert(!__traits(isSame, arr[4], E.g)); + + // Since arr[0] is just a value of type E, it's no longer the symbol, E.a, + // even though its type is E, and its value is the same as that of E.a. And + // unlike the actual members of an enum, an element of an array does not + // have an identifier, so __traits(identifier, ...) doesn't work with it. + static assert(!__traits(compiles, __traits(identifier, arr[0]))); + + // Similarly, once an enum member from the AliasSeq is assigned to a + // variable, __traits(identifer, ...) operates on the variable, not the + // symbol from the AliasSeq or the value of the variable. + auto var = uniqueMembers[0]; + static assert(__traits(identifier, var) == "var"); + + // The same with a manifest constant. + enum constant = uniqueMembers[0]; + static assert(__traits(identifier, constant) == "constant"); +} + +/++ + Whether the given symbols are the same symbol. + + All this does is $(D __traits(isSame, lhs, rhs)), so most code shouldn't + use it. It's intended to be used in conjunction with templates that take a + template predicate - such as those in phobos.sys.meta. + + The single-argument overload makes it so that it can be partially + instantiated with the first argument, which will often be necessary with + template predicates. + + See_Also: + $(DDSUBLINK spec/traits, isSame, $(D __traits(isSame, lhs, rhs))) + $(LREF isEqual) + $(LREF isSameType) + +/ +enum isSameSymbol(alias lhs, alias rhs) = __traits(isSame, lhs, rhs); + +/++ Ditto +/ +template isSameSymbol(alias lhs) +{ + enum isSameSymbol(alias rhs) = __traits(isSame, lhs, rhs); +} + +/// +@safe unittest +{ + int i; + int j; + real r; + + static assert( isSameSymbol!(i, i)); + static assert(!isSameSymbol!(i, j)); + static assert(!isSameSymbol!(i, r)); + + static assert(!isSameSymbol!(j, i)); + static assert( isSameSymbol!(j, j)); + static assert(!isSameSymbol!(j, r)); + + static assert(!isSameSymbol!(r, i)); + static assert(!isSameSymbol!(r, j)); + static assert( isSameSymbol!(r, r)); + + auto foo() { return 0; } + auto bar() { return 0; } + + static assert( isSameSymbol!(foo, foo)); + static assert(!isSameSymbol!(foo, bar)); + static assert(!isSameSymbol!(foo, i)); + + static assert(!isSameSymbol!(bar, foo)); + static assert( isSameSymbol!(bar, bar)); + static assert(!isSameSymbol!(bar, i)); + + // Types are symbols too. However, in most cases, they should be compared + // as types, not symbols (be it with is expressions or with isSameType), + // because the results aren't consistent between scalar types and + // user-defined types with regards to type qualifiers when they're compared + // as symbols. + static assert( isSameSymbol!(double, double)); + static assert(!isSameSymbol!(double, const double)); + static assert(!isSameSymbol!(double, int)); + static assert( isSameSymbol!(Object, Object)); + static assert( isSameSymbol!(Object, const Object)); + + static assert(!isSameSymbol!(i, int)); + static assert( isSameSymbol!(typeof(i), int)); + + // Lambdas can be compared with __traits(isSame, ...), + // so they can be compared with isSameSymbol. + static assert( isSameSymbol!(a => a + 42, a => a + 42)); + static assert(!isSameSymbol!(a => a + 42, a => a + 99)); + + // Partial instantiation allows it to be used with templates that expect + // a predicate that takes only a single argument. + import phobos.sys.meta : AliasSeq, indexOf; + alias Types = AliasSeq!(i, j, r, int, long, foo); + static assert(indexOf!(isSameSymbol!j, Types) == 1); + static assert(indexOf!(isSameSymbol!int, Types) == 3); + static assert(indexOf!(isSameSymbol!bar, Types) == -1); +} + +/++ + Whether the given types are the same type. + + All this does is $(D is(T == U)), so most code shouldn't use it. It's + intended to be used in conjunction with templates that take a template + predicate - such as those in phobos.sys.meta. + + The single-argument overload makes it so that it can be partially + instantiated with the first argument, which will often be necessary with + template predicates. + + See_Also: + $(LREF isEqual) + $(LREF isSameSymbol) + +/ +enum isSameType(T, U) = is(T == U); + +/++ Ditto +/ +template isSameType(T) +{ + enum isSameType(U) = is(T == U); +} + +/// +@safe unittest +{ + static assert( isSameType!(long, long)); + static assert(!isSameType!(long, const long)); + static assert(!isSameType!(long, string)); + static assert( isSameType!(string, string)); + + int i; + real r; + static assert( isSameType!(int, typeof(i))); + static assert(!isSameType!(int, typeof(r))); + + static assert(!isSameType!(real, typeof(i))); + static assert( isSameType!(real, typeof(r))); + + // Partial instantiation allows it to be used with templates that expect + // a predicate that takes only a single argument. + import phobos.sys.meta : AliasSeq, indexOf; + alias Types = AliasSeq!(float, string, int, double); + static assert(indexOf!(isSameType!int, Types) == 2); +} + +/++ + Evaluates to an $(D AliasSeq) of the names (as $(D string)s) of the member + variables of an aggregate type (i.e. a struct, class, interface, or union). + + These are fields which take up memory space within an instance of the type + (i.e. not enums / manifest constants, since they don't take up memory + space, and not static member variables, since they don't take up memory + space within an instance). + + Hidden fields (like the virtual function table pointer or the context + pointer for nested types) are not included. + + For classes, only the direct member variables are included and not those + of any base classes. + + For interfaces, the result of FieldNames is always empty, because + interfaces cannot have member variables. However, because interfaces are + aggregate types, they work with FieldNames for consistency so that code + that's written to work on aggregate types doesn't have to worry about + whether it's dealing with an interface. + + See_Also: + $(LREF FieldSymbols) + $(LREF FieldTypes) + $(DDSUBLINK spec/struct.html, struct_instance_properties, $(D tupleof)) + +/ +template FieldNames(T) +if (isAggregateType!T) +{ + import phobos.sys.meta : AliasSeq; + + static if (is(T == struct) && __traits(isNested, T)) + private alias Fields = AliasSeq!(T.tupleof[0 .. $ - 1]); + else + private alias Fields = T.tupleof; + + alias FieldNames = AliasSeq!(); + static foreach (Field; Fields) + FieldNames = AliasSeq!(FieldNames, Field.stringof); +} + +/// +@safe unittest +{ + import phobos.sys.meta : AliasSeq; + + struct S + { + int x; + float y; + } + static assert(FieldNames!S == AliasSeq!("x", "y")); + + // Since the AliasSeq contains values, all of which are of the same type, + // it can be used to create a dynamic array, which would be more + // efficient than operating on an AliasSeq in the cases where an + // AliasSeq is not necessary. + static assert([FieldNames!S] == ["x", "y"]); + + class C + { + // static variables are not included. + static int var; + + // Manifest constants are not included. + enum lang = "dlang"; + + // Functions are not included, even if they're @property functions. + @property int foo() { return 42; } + + string s; + int i; + int[] arr; + } + static assert(FieldNames!C == AliasSeq!("s", "i", "arr")); + + static assert([FieldNames!C] == ["s", "i", "arr"]); + + // Only direct member variables are included. Member variables from any base + // classes are not. + class D : C + { + real r; + } + static assert(FieldNames!D == AliasSeq!"r"); + + static assert([FieldNames!D] == ["r"]); + + // FieldNames will always be empty for an interface, since it's not legal + // for interfaces to have member variables. + interface I + { + } + static assert(FieldNames!I.length == 0); + + union U + { + int i; + double d; + long l; + S s; + } + static assert(FieldNames!U == AliasSeq!("i", "d", "l", "s")); + + static assert([FieldNames!U] == ["i", "d", "l", "s"]);; + + // FieldNames only operates on aggregate types. + static assert(!__traits(compiles, FieldNames!int)); + static assert(!__traits(compiles, FieldNames!(S*))); + static assert(!__traits(compiles, FieldNames!(C[]))); +} + +@safe unittest +{ + import phobos.sys.meta : AliasSeq; + + { + static struct S0 {} + static assert(FieldNames!S0.length == 0); + + static struct S1 { int a; } + static assert(FieldNames!S1 == AliasSeq!"a"); + + static struct S2 { int a; string b; } + static assert(FieldNames!S2 == AliasSeq!("a", "b")); + + static struct S3 { int a; string b; real c; } + static assert(FieldNames!S3 == AliasSeq!("a", "b", "c")); + } + { + int i; + struct S0 { void foo() { i = 0; }} + static assert(FieldNames!S0.length == 0); + static assert(__traits(isNested, S0)); + + struct S1 { int a; void foo() { i = 0; } } + static assert(FieldNames!S1 == AliasSeq!"a"); + static assert(__traits(isNested, S1)); + + struct S2 { int a; string b; void foo() { i = 0; } } + static assert(FieldNames!S2 == AliasSeq!("a", "b")); + static assert(__traits(isNested, S2)); + + struct S3 { int a; string b; real c; void foo() { i = 0; } } + static assert(FieldNames!S3 == AliasSeq!("a", "b", "c")); + static assert(__traits(isNested, S3)); + } + { + static class C0 {} + static assert(FieldNames!C0.length == 0); + + static class C1 { int a; } + static assert(FieldNames!C1 == AliasSeq!"a"); + + static class C2 { int a; string b; } + static assert(FieldNames!C2 == AliasSeq!("a", "b")); + + static class C3 { int a; string b; real c; } + static assert(FieldNames!C3 == AliasSeq!("a", "b", "c")); + + static class D0 : C3 {} + static assert(FieldNames!D0.length == 0); + + static class D1 : C3 { bool x; } + static assert(FieldNames!D1 == AliasSeq!"x"); + + static class D2 : C3 { bool x; int* y; } + static assert(FieldNames!D2 == AliasSeq!("x", "y")); + + static class D3 : C3 { bool x; int* y; short[] z; } + static assert(FieldNames!D3 == AliasSeq!("x", "y", "z")); + } + { + int i; + class C0 { void foo() { i = 0; }} + static assert(FieldNames!C0.length == 0); + static assert(__traits(isNested, C0)); + + class C1 { int a; void foo() { i = 0; } } + static assert(FieldNames!C1 == AliasSeq!"a"); + static assert(__traits(isNested, C1)); + + class C2 { int a; string b; void foo() { i = 0; } } + static assert(FieldNames!C2 == AliasSeq!("a", "b")); + static assert(__traits(isNested, C2)); + + class C3 { int a; string b; real c; void foo() { i = 0; } } + static assert(FieldNames!C3 == AliasSeq!("a", "b", "c")); + static assert(__traits(isNested, C3)); + + class D0 : C3 {} + static assert(FieldNames!D0.length == 0); + static assert(__traits(isNested, D0)); + + class D1 : C3 { bool x; } + static assert(FieldNames!D1 == AliasSeq!"x"); + static assert(__traits(isNested, D1)); + + class D2 : C3 { bool x; int* y; } + static assert(FieldNames!D2 == AliasSeq!("x", "y")); + static assert(__traits(isNested, D2)); + + class D3 : C3 { bool x; int* y; short[] z; } + static assert(FieldNames!D3 == AliasSeq!("x", "y", "z")); + static assert(__traits(isNested, D3)); + } + { + static union U0 {} + static assert(FieldNames!U0.length == 0); + + static union U1 { int a; } + static assert(FieldNames!U1 == AliasSeq!"a"); + + static union U2 { int a; string b; } + static assert(FieldNames!U2 == AliasSeq!("a", "b")); + + static union U3 { int a; string b; real c; } + static assert(FieldNames!U3 == AliasSeq!("a", "b", "c")); + } + { + static struct S + { + enum e = 42; + static str = "foobar"; + + string name() { return "foo"; } + + int[] arr; + + struct Inner1 { int i; } + + static struct Inner2 { long gnol; } + + union { int a; string b; } + + alias Foo = Inner1; + } + + static assert(FieldNames!S == AliasSeq!("arr", "a", "b")); + static assert(FieldNames!(const S) == AliasSeq!("arr", "a", "b")); + static assert(FieldNames!(S.Inner1) == AliasSeq!"i"); + static assert(FieldNames!(S.Inner2) == AliasSeq!"gnol"); + } +} + +/++ + Evaluates to an $(D AliasSeq) of the symbols for the member variables of an + aggregate type (i.e. a struct, class, interface, or union). + + These are fields which take up memory space within an instance of the type + (i.e. not enums / manifest constants, since they don't take up memory + space, and not static member variables, since they don't take up memory + space within an instance). + + Hidden fields (like the virtual function table pointer or the context + pointer for nested types) are not included. + + For classes, only the direct member variables are included and not those + of any base classes. + + For interfaces, the result of FieldSymbols is always empty, because + interfaces cannot have member variables. However, because interfaces are + aggregate types, they work with FieldSymbols for consistency so that code + that's written to work on aggregate types doesn't have to worry about + whether it's dealing with an interface. + + In most cases, $(D FieldSymbols!T) has the same result as $(D T.tupleof). + The difference is that for nested structs with a context pointer, + $(D T.tupleof) includes the context pointer, whereas $(D FieldSymbols!T) + does not. For non-nested structs, and for classes, interfaces, and unions, + $(D FieldSymbols!T) and $(D T.tupleof) are the same. + + So, for most cases, $(D T.tupleof) is sufficient and avoids instantiating + an additional template, but FieldSymbols is provided so that the code that + needs to avoid including context pointers in the list of fields can do so + without the programmer having to figure how to do that correctly. It also + provides a template that's equivalent to what $(LREF FieldNames) and + $(LREF FieldTypes) do in terms of which fields it gives (the difference of + course then being whether you get the symbols, names, or types for the + fields), whereas the behavior for $(D tupleof) is subtly different. + + See_Also: + $(LREF FieldNames) + $(LREF FieldTypes) + $(DDSUBLINK spec/struct.html, struct_instance_properties, $(D tupleof)) + $(DDSUBLINK spec/traits, isNested, $(D __traits(isNested, ...))). + $(DDSUBLINK spec/traits, isSame, $(D __traits(isSame, ...))). + +/ +template FieldSymbols(T) +if (isAggregateType!T) +{ + static if (is(T == struct) && __traits(isNested, T)) + { + import phobos.sys.meta : AliasSeq; + alias FieldSymbols = AliasSeq!(T.tupleof[0 .. $ - 1]); + } + else + alias FieldSymbols = T.tupleof; +} + +/// +@safe unittest +{ + import phobos.sys.meta : AliasSeq; + + struct S + { + int x; + float y; + } + static assert(__traits(isSame, FieldSymbols!S, AliasSeq!(S.x, S.y))); + + // FieldSymbols!S and S.tupleof are the same, because S is not nested. + static assert(__traits(isSame, FieldSymbols!S, S.tupleof)); + + // Note that type qualifiers _should_ be passed on to the result, but due + // to https://issues.dlang.org/show_bug.cgi?id=24516, they aren't. + // FieldTypes does not have this problem, because it aliases the types + // rather than the symbols, so if you need the types from the symbols, you + // should use either FieldTypes or tupleof until the compiler bug has been + // fixed (and if you use tupleof, you need to avoid aliasing the result + // before getting the types from it). + static assert(is(typeof(FieldSymbols!S[0]) == int)); + + // These currently fail when they shouldn't: + //static assert(is(typeof(FieldSymbols!(const S)[0]) == const int)); + //static assert(is(typeof(FieldSymbols!(shared S)[0]) == shared int)); + + class C + { + // static variables are not included. + static int var; + + // Manifest constants are not included. + enum lang = "dlang"; + + // Functions are not included, even if they're @property functions. + @property int foo() { return 42; } + + string s; + int i; + int[] arr; + } + static assert(__traits(isSame, FieldSymbols!C, AliasSeq!(C.s, C.i, C.arr))); + + // FieldSymbols!C and C.tupleof have the same symbols, because they are + // always the same for classes. + static assert(__traits(isSame, FieldSymbols!C, C.tupleof)); + + // Only direct member variables are included. Member variables from any base + // classes are not. + class D : C + { + real r; + } + static assert(__traits(isSame, FieldSymbols!D, AliasSeq!(D.r))); + static assert(__traits(isSame, FieldSymbols!D, D.tupleof)); + + // FieldSymbols will always be empty for an interface, since it's not legal + // for interfaces to have member variables. + interface I + { + } + static assert(FieldSymbols!I.length == 0); + static assert(I.tupleof.length == 0); + + union U + { + int i; + double d; + long l; + S s; + } + static assert(__traits(isSame, FieldSymbols!U, AliasSeq!(U.i, U.d, U.l, U.s))); + + // FieldSymbols!C and C.tupleof have the same symbols, because they are + // always the same for unions. + static assert(__traits(isSame, FieldSymbols!U, U.tupleof)); + + // FieldSymbols only operates on aggregate types. + static assert(!__traits(compiles, FieldSymbols!int)); + static assert(!__traits(compiles, FieldSymbols!(S*))); + static assert(!__traits(compiles, FieldSymbols!(C[]))); +} + +/// Some examples with nested types. +@safe unittest +{ + import phobos.sys.meta : AliasSeq; + + int outside; + + struct S + { + long l; + string s; + + void foo() { outside = 2; } + } + static assert(__traits(isNested, S)); + static assert(__traits(isSame, FieldSymbols!S, AliasSeq!(S.l, S.s))); + + // FieldSymbols!S and S.tupleof are not the same, because S is nested, and + // the context pointer to the outer scope is included in S.tupleof, whereas + // it is excluded from FieldSymbols!S. + static assert(__traits(isSame, S.tupleof[0 .. $ - 1], AliasSeq!(S.l, S.s))); + static assert(S.tupleof[$ - 1].stringof == "this"); + + class C + { + bool b; + int* ptr; + + void foo() { outside = 7; } + } + static assert(__traits(isNested, C)); + static assert(__traits(isSame, FieldSymbols!C, AliasSeq!(C.b, C.ptr))); + + // FieldSymbols!C and C.tupleof have the same symbols, because they are + // always the same for classes. No context pointer is provided as part of + // tupleof for nested classes. + static assert(__traits(isSame, FieldSymbols!C, C.tupleof)); + + // __traits(isNested, ...) is never true for interfaces or unions, since + // they cannot have a context pointer to an outer scope. So, tupleof and + // FieldSymbols will always be the same for interfaces and unions. +} + +@safe unittest +{ + import phobos.sys.meta : AliasSeq; + + { + static struct S0 {} + static assert(FieldSymbols!S0.length == 0); + + static struct S1 { int a; } + static assert(__traits(isSame, FieldSymbols!S1, AliasSeq!(S1.a))); + + static struct S2 { int a; string b; } + static assert(__traits(isSame, FieldSymbols!S2, AliasSeq!(S2.a, S2.b))); + + static struct S3 { int a; string b; real c; } + static assert(__traits(isSame, FieldSymbols!S3, AliasSeq!(S3.a, S3.b, S3.c))); + } + { + int i; + struct S0 { void foo() { i = 0; }} + static assert(FieldSymbols!S0.length == 0); + static assert(__traits(isNested, S0)); + + struct S1 { int a; void foo() { i = 0; } } + static assert(__traits(isSame, FieldSymbols!S1, AliasSeq!(S1.a))); + static assert(__traits(isNested, S1)); + + struct S2 { int a; string b; void foo() { i = 0; } } + static assert(__traits(isSame, FieldSymbols!S2, AliasSeq!(S2.a, S2.b))); + static assert(__traits(isNested, S2)); + + struct S3 { int a; string b; real c; void foo() { i = 0; } } + static assert(__traits(isSame, FieldSymbols!S3, AliasSeq!(S3.a, S3.b, S3.c))); + static assert(__traits(isNested, S3)); + } + { + static class C0 {} + static assert(FieldSymbols!C0.length == 0); + + static class C1 { int a; } + static assert(__traits(isSame, FieldSymbols!C1, AliasSeq!(C1.a))); + + static class C2 { int a; string b; } + static assert(__traits(isSame, FieldSymbols!C2, AliasSeq!(C2.a, C2.b))); + + static class C3 { int a; string b; real c; } + static assert(__traits(isSame, FieldSymbols!C3, AliasSeq!(C3.a, C3.b, C3.c))); + + static class D0 : C3 {} + static assert(FieldSymbols!D0.length == 0); + + static class D1 : C3 { bool x; } + static assert(__traits(isSame, FieldSymbols!D1, AliasSeq!(D1.x))); + + static class D2 : C3 { bool x; int* y; } + static assert(__traits(isSame, FieldSymbols!D2, AliasSeq!(D2.x, D2.y))); + + static class D3 : C3 { bool x; int* y; short[] z; } + static assert(__traits(isSame, FieldSymbols!D3, AliasSeq!(D3.x, D3.y, D3.z))); + } + { + int i; + class C0 { void foo() { i = 0; }} + static assert(FieldSymbols!C0.length == 0); + static assert(__traits(isNested, C0)); + + class C1 { int a; void foo() { i = 0; } } + static assert(__traits(isSame, FieldSymbols!C1, AliasSeq!(C1.a))); + static assert(__traits(isNested, C1)); + + class C2 { int a; string b; void foo() { i = 0; } } + static assert(__traits(isSame, FieldSymbols!C2, AliasSeq!(C2.a, C2.b))); + static assert(__traits(isNested, C2)); + + class C3 { int a; string b; real c; void foo() { i = 0; } } + static assert(__traits(isSame, FieldSymbols!C3, AliasSeq!(C3.a, C3.b, C3.c))); + static assert(__traits(isNested, C3)); + + class D0 : C3 {} + static assert(FieldSymbols!D0.length == 0); + static assert(__traits(isNested, D0)); + + class D1 : C3 { bool x; } + static assert(__traits(isSame, FieldSymbols!D1, AliasSeq!(D1.x))); + static assert(__traits(isNested, D1)); + + class D2 : C3 { bool x; int* y; } + static assert(__traits(isSame, FieldSymbols!D2, AliasSeq!(D2.x, D2.y))); + static assert(__traits(isNested, D2)); + + class D3 : C3 { bool x; int* y; short[] z; } + static assert(__traits(isSame, FieldSymbols!D3, AliasSeq!(D3.x, D3.y, D3.z))); + static assert(__traits(isNested, D3)); + } + { + static union U0 {} + static assert(FieldSymbols!U0.length == 0); + + static union U1 { int a; } + static assert(__traits(isSame, FieldSymbols!U1, AliasSeq!(U1.a))); + + static union U2 { int a; string b; } + static assert(__traits(isSame, FieldSymbols!U2, AliasSeq!(U2.a, U2.b))); + + static union U3 { int a; string b; real c; } + static assert(__traits(isSame, FieldSymbols!U3, AliasSeq!(U3.a, U3.b, U3.c))); + } + { + static struct S + { + enum e = 42; + static str = "foobar"; + + string name() { return "foo"; } + + int[] arr; + + struct Inner1 { int i; } + + static struct Inner2 { long gnol; } + + union { int a; string b; } + + alias Foo = Inner1; + } + + static assert(__traits(isSame, FieldSymbols!S, AliasSeq!(S.arr, S.a, S.b))); + static assert(__traits(isSame, FieldSymbols!(const S), AliasSeq!(S.arr, S.a, S.b))); + static assert(__traits(isSame, FieldSymbols!(S.Inner1), AliasSeq!(S.Inner1.i))); + static assert(__traits(isSame, FieldSymbols!(S.Inner2), AliasSeq!(S.Inner2.gnol))); + } +} + +/++ + Evaluates to an $(D AliasSeq) of the types of the member variables of an + aggregate type (i.e. a struct, class, interface, or union). + + These are fields which take up memory space within an instance of the type + (i.e. not enums / manifest constants, since they don't take up memory + space, and not static member variables, since they don't take up memory + space within an instance). + + Hidden fields (like the virtual function table pointer or the context + pointer for nested types) are not included. + + For classes, only the direct member variables are included and not those + of any base classes. + + For interfaces, the result of FieldTypes is always empty, because + interfaces cannot have member variables. However, because interfaces are + aggregate types, they work with FieldTypes for consistency so that code + that's written to work on aggregate types doesn't have to worry about + whether it's dealing with an interface. + + See_Also: + $(LREF FieldNames) + $(LREF FieldSymbols) + $(DDSUBLINK spec/struct.html, struct_instance_properties, $(D tupleof)) + +/ +template FieldTypes(T) +if (isAggregateType!T) +{ + static if (is(T == struct) && __traits(isNested, T)) + alias FieldTypes = typeof(T.tupleof[0 .. $ - 1]); + else + alias FieldTypes = typeof(T.tupleof); +} + +/// +@safe unittest +{ + import phobos.sys.meta : AliasSeq; + + struct S + { + int x; + float y; + } + static assert(is(FieldTypes!S == AliasSeq!(int, float))); + + // Type qualifers will be passed on to the result. + static assert(is(FieldTypes!(const S) == AliasSeq!(const int, const float))); + static assert(is(FieldTypes!(shared S) == AliasSeq!(shared int, shared float))); + + class C + { + // static variables are not included. + static int var; + + // Manifest constants are not included. + enum lang = "dlang"; + + // Functions are not included, even if they're @property functions. + @property int foo() { return 42; } + + string s; + int i; + int[] arr; + } + static assert(is(FieldTypes!C == AliasSeq!(string, int, int[]))); + + // Only direct member variables are included. Member variables from any base + // classes are not. + class D : C + { + real r; + } + static assert(is(FieldTypes!D == AliasSeq!real)); + + // FieldTypes will always be empty for an interface, since it's not legal + // for interfaces to have member variables. + interface I + { + } + static assert(FieldTypes!I.length == 0); + + union U + { + int i; + double d; + long l; + S s; + } + static assert(is(FieldTypes!U == AliasSeq!(int, double, long, S))); + + // FieldTypes only operates on aggregate types. + static assert(!__traits(compiles, FieldTypes!int)); + static assert(!__traits(compiles, FieldTypes!(S*))); + static assert(!__traits(compiles, FieldTypes!(C[]))); +} + +@safe unittest +{ + import phobos.sys.meta : AliasSeq; + + { + static struct S0 {} + static assert(FieldTypes!S0.length == 0); + + static struct S1 { int a; } + static assert(is(FieldTypes!S1 == AliasSeq!int)); + + static struct S2 { int a; string b; } + static assert(is(FieldTypes!S2 == AliasSeq!(int, string))); + + static struct S3 { int a; string b; real c; } + static assert(is(FieldTypes!S3 == AliasSeq!(int, string, real))); + } + { + int i; + struct S0 { void foo() { i = 0; }} + static assert(FieldTypes!S0.length == 0); + static assert(__traits(isNested, S0)); + + struct S1 { int a; void foo() { i = 0; } } + static assert(is(FieldTypes!S1 == AliasSeq!int)); + static assert(__traits(isNested, S1)); + + struct S2 { int a; string b; void foo() { i = 0; } } + static assert(is(FieldTypes!S2 == AliasSeq!(int, string))); + static assert(__traits(isNested, S2)); + + struct S3 { int a; string b; real c; void foo() { i = 0; } } + static assert(is(FieldTypes!S3 == AliasSeq!(int, string, real))); + static assert(__traits(isNested, S3)); + } + { + static class C0 {} + static assert(FieldTypes!C0.length == 0); + + static class C1 { int a; } + static assert(is(FieldTypes!C1 == AliasSeq!int)); + + static class C2 { int a; string b; } + static assert(is(FieldTypes!C2 == AliasSeq!(int, string))); + + static class C3 { int a; string b; real c; } + static assert(is(FieldTypes!C3 == AliasSeq!(int, string, real))); + + static class D0 : C3 {} + static assert(FieldTypes!D0.length == 0); + + static class D1 : C3 { bool x; } + static assert(is(FieldTypes!D1 == AliasSeq!bool)); + + static class D2 : C3 { bool x; int* y; } + static assert(is(FieldTypes!D2 == AliasSeq!(bool, int*))); + + static class D3 : C3 { bool x; int* y; short[] z; } + static assert(is(FieldTypes!D3 == AliasSeq!(bool, int*, short[]))); + } + { + int i; + class C0 { void foo() { i = 0; }} + static assert(FieldTypes!C0.length == 0); + static assert(__traits(isNested, C0)); + + class C1 { int a; void foo() { i = 0; } } + static assert(is(FieldTypes!C1 == AliasSeq!int)); + static assert(__traits(isNested, C1)); + + class C2 { int a; string b; void foo() { i = 0; } } + static assert(is(FieldTypes!C2 == AliasSeq!(int, string))); + static assert(__traits(isNested, C2)); + + class C3 { int a; string b; real c; void foo() { i = 0; } } + static assert(is(FieldTypes!C3 == AliasSeq!(int, string, real))); + static assert(__traits(isNested, C3)); + + class D0 : C3 {} + static assert(FieldTypes!D0.length == 0); + static assert(__traits(isNested, D0)); + + class D1 : C3 { bool x; } + static assert(is(FieldTypes!D1 == AliasSeq!bool)); + static assert(__traits(isNested, D1)); + + class D2 : C3 { bool x; int* y; } + static assert(is(FieldTypes!D2 == AliasSeq!(bool, int*))); + static assert(__traits(isNested, D2)); + + class D3 : C3 { bool x; int* y; short[] z; } + static assert(is(FieldTypes!D3 == AliasSeq!(bool, int*, short[]))); + static assert(__traits(isNested, D3)); + } + { + static union U0 {} + static assert(FieldTypes!U0.length == 0); + + static union U1 { int a; } + static assert(is(FieldTypes!U1 == AliasSeq!int)); + + static union U2 { int a; string b; } + static assert(is(FieldTypes!U2 == AliasSeq!(int, string))); + + static union U3 { int a; string b; real c; } + static assert(is(FieldTypes!U3 == AliasSeq!(int, string, real))); + } + { + static struct S + { + enum e = 42; + static str = "foobar"; + + string name() { return "foo"; } + + int[] arr; + + struct Inner1 { int i; } + + static struct Inner2 { long gnol; } + + union { int a; string b; } + + alias Foo = Inner1; + } + + static assert(is(FieldTypes!S == AliasSeq!(int[], int, string))); + static assert(is(FieldTypes!(const S) == AliasSeq!(const(int[]), const int, const string))); + static assert(is(FieldTypes!(S.Inner1) == AliasSeq!int)); + static assert(is(FieldTypes!(S.Inner2) == AliasSeq!long)); + } +} + +/++ + Takes a type which is an associative array and evaluates to the type of the + keys in that associative array. + + See_Also: + $(LREF ValueType) + +/ +alias KeyType(V : V[K], K) = K; + +/// +@safe unittest +{ + static assert(is(KeyType!(int[string]) == string)); + static assert(is(KeyType!(string[int]) == int)); + + static assert(is(KeyType!(string[const int]) == const int)); + static assert(is(KeyType!(const int[string]) == string)); + + struct S + { + int i; + } + + string[S] aa1; + static assert(is(KeyType!(typeof(aa1)) == S)); + + S[string] aa2; + static assert(is(KeyType!(typeof(aa2)) == string)); + + KeyType!(typeof(aa1)) key1 = S(42); + KeyType!(typeof(aa2)) key2 = "foo"; + + // Key types with indirections have their inner layers treated as const + // by the compiler, because the values of keys can't change, or the hash + // value could change, putting the associative array in an invalid state. + static assert(is(KeyType!(bool[string[]]) == const(string)[])); + static assert(is(KeyType!(bool[int*]) == const(int)*)); + + // If the given type is not an AA, then KeyType won't compile. + static assert(!__traits(compiles, KeyType!int)); + static assert(!__traits(compiles, KeyType!(int[]))); +} + +/++ + Takes a type which is an associative array and evaluates to the type of the + values in that associative array. + + See_Also: + $(LREF KeyType) + +/ +alias ValueType(V : V[K], K) = V; + +/// +@safe unittest +{ + static assert(is(ValueType!(int[string]) == int)); + static assert(is(ValueType!(string[int]) == string)); + + static assert(is(ValueType!(string[const int]) == string)); + static assert(is(ValueType!(const int[string]) == const int)); + + struct S + { + int i; + } + + string[S] aa1; + static assert(is(ValueType!(typeof(aa1)) == string)); + + S[string] aa2; + static assert(is(ValueType!(typeof(aa2)) == S)); + + ValueType!(typeof(aa1)) value1 = "foo"; + ValueType!(typeof(aa2)) value2 = S(42); + + // If the given type is not an AA, then ValueType won't compile. + static assert(!__traits(compiles, ValueType!int)); + static assert(!__traits(compiles, ValueType!(int[]))); +} + +/++ + Evaluates to the original / ultimate base type of an enum type - or for + non-enum types, it evaluates to the type that it's given. + + If the base type of the given enum type is not an enum, then the result of + OriginalType is its direct base type. However, if the base type of the + given enum is also an enum, then OriginalType gives the ultimate base type + - that is, it keeps getting the base type for each succesive enum in the + chain until it gets to a base type that isn't an enum, and that's the + result. So, the result will never be an enum type. + + If the given type has any qualifiers, the result will have those same + qualifiers. + +/ +version (StdDdoc) template OriginalType(T) +{ + import core.internal.traits : CoreOriginalType = OriginalType; + alias OriginalType = CoreOriginalType!T; +} +else +{ + import core.internal.traits : CoreOriginalType = OriginalType; + alias OriginalType = CoreOriginalType; +} + +/// +@safe unittest +{ + enum E { a, b, c } + static assert(is(OriginalType!E == int)); + + enum F : E { x = E.a } + static assert(is(OriginalType!F == int)); + + enum G : F { y = F.x } + static assert(is(OriginalType!G == int)); + static assert(is(OriginalType!(const G) == const int)); + static assert(is(OriginalType!(immutable G) == immutable int)); + static assert(is(OriginalType!(shared G) == shared int)); + + enum C : char { a = 'a', b = 'b' } + static assert(is(OriginalType!C == char)); + + enum D : string { d = "dlang" } + static assert(is(OriginalType!D == string)); + + static assert(is(OriginalType!int == int)); + static assert(is(OriginalType!(const long) == const long)); + static assert(is(OriginalType!string == string)); + + // OriginalType gets the base type of enums and for all other types gives + // the same type back. It does nothing special for other types - like + // classes - where one could talk about the type having a base type. + class Base {} + class Derived : Base {} + static assert(is(OriginalType!Base == Base)); + static assert(is(OriginalType!Derived == Derived)); +} + +/++ + Removes the outer layer of $(D const), $(D inout), or $(D immutable) + from type $(D T). + + If none of those qualifiers have been applied to the outer layer of + type $(D T), then the result is $(D T). + + For the built-in scalar types (that is $(D bool), the character types, and + the numeric types), they only have one layer, so $(D const U) simply becomes + $(D U). + + Where the layers come in is pointers and arrays. $(D const(U*)) becomes + $(D const(U)*), and $(D const(U[])), becomes $(D const(U)[]). So, a pointer + goes from being fully $(D const) to being a mutable pointer to $(D const), + and a dynamic array goes from being fully $(D const) to being a mutable + dynamic array of $(D const) elements. And if there are multiple layers of + pointers or arrays, it's just that outer layer which is affected - e.g. + $(D const(U**)) would become $(D const(U*)*). + + For user-defined types, the effect is that $(D const U) becomes $(D U), and + how that affects member variables depends on the type of the member + variable. If a member variable is explicitly marked with any mutability + qualifiers, then it will continue to have those qualifiers even after + Unconst has stripped all mutability qualifiers from the containing type. + However, if a mutability qualifier was on the member variable only because + the containing type had that qualifier, then when Unconst removes the + qualifier from the containing type, it is removed from the member variable + as well. + + Also, Unconst has no effect on what a templated type is instantiated + with, so if a templated type is instantiated with a template argument which + has a mutability qualifier, the template instantiation will not change. + +/ +version (StdDdoc) template Unconst(T) +{ + import core.internal.traits : CoreUnconst = Unconst; + alias Unconst = CoreUnconst!T; +} +else +{ + import core.internal.traits : CoreUnconst = Unconst; + alias Unconst = CoreUnconst; +} + +/// +@safe unittest +{ + static assert(is(Unconst!( int) == int)); + static assert(is(Unconst!( const int) == int)); + static assert(is(Unconst!( inout int) == int)); + static assert(is(Unconst!( inout const int) == int)); + static assert(is(Unconst!(shared int) == shared int)); + static assert(is(Unconst!(shared const int) == shared int)); + static assert(is(Unconst!(shared inout int) == shared int)); + static assert(is(Unconst!(shared inout const int) == shared int)); + static assert(is(Unconst!( immutable int) == int)); + + // Only the outer layer of immutable is removed. + // immutable(int[]) -> immutable(int)[] + alias ImmIntArr = immutable(int[]); + static assert(is(Unconst!ImmIntArr == immutable(int)[])); + + // Only the outer layer of const is removed. + // immutable(int*) -> immutable(int)* + alias ConstIntPtr = const(int*); + static assert(is(Unconst!ConstIntPtr == const(int)*)); + + // const(int)* -> const(int)* + alias PtrToConstInt = const(int)*; + static assert(is(Unconst!PtrToConstInt == const(int)*)); + + static struct S + { + int* ptr; + const int* cPtr; + shared int* sPtr; + } + + const S s; + static assert(is(typeof(s) == const S)); + static assert(is(typeof(typeof(s).ptr) == const int*)); + static assert(is(typeof(typeof(s).cPtr) == const int*)); + static assert(is(typeof(typeof(s).sPtr) == const shared int*)); + + // For user-defined types, all mutability qualifiers that are applied to + // member variables only because the containing type has them are removed, + // but the ones that are directly on those member variables remain. + + // const S -> S + static assert(is(Unconst!(typeof(s)) == S)); + static assert(is(typeof(Unconst!(typeof(s)).ptr) == int*)); + static assert(is(typeof(Unconst!(typeof(s)).cPtr) == const int*)); + static assert(is(typeof(Unconst!(typeof(s)).sPtr) == shared int*)); + + static struct Foo(T) + { + T* ptr; + } + + // The qualifier on the type is removed, but the qualifier on the template + // argument is not. + static assert(is(Unconst!(const(Foo!(const int))) == Foo!(const int))); + static assert(is(Unconst!(Foo!(const int)) == Foo!(const int))); + static assert(is(Unconst!(const(Foo!int)) == Foo!int)); +} + +/++ + Removes the outer layer of $(D shared) from type $(D T). + + If $(D shared) has not been applied to the outer layer of type $(D T), then + the result is $(D T). + + Note that while $(D immutable) is implicitly $(D shared), it is unaffected + by Unshared. Only explicit $(D shared) is removed. + + For the built-in scalar types (that is $(D bool), the character types, and + the numeric types), they only have one layer, so $(D shared U) simply + becomes $(D U). + + Where the layers come in is pointers and arrays. $(D shared(U*)) becomes + $(D shared(U)*), and $(D shared(U[])), becomes $(D shared(U)[]). So, a + pointer goes from being fully $(D shared) to being a mutable pointer to + $(D shared), and a dynamic array goes from being fully $(D shared) to being + a mutable dynamic array of $(D shared) elements. And if there are multiple + layers of pointers or arrays, it's just that outer layer which is affected + - e.g. $(D shared(U**)) would become $(D shared(U*)*). + + For user-defined types, the effect is that $(D shared U) becomes $(D U), + and how that affects member variables depends on the type of the member + variable. If a member variable is explicitly marked with $(D shared), then + it will continue to be $(D shared) even after Unshared has stripped + $(D shared) from the containing type. However, if $(D shared) was on the + member variable only because the containing type was $(D shared), then when + Unshared removes the qualifier from the containing type, it is removed from + the member variable as well. + + Also, Unshared has no effect on what a templated type is instantiated + with, so if a templated type is instantiated with a template argument which + has a type qualifier, the template instantiation will not change. + +/ +template Unshared(T) +{ + static if (is(T == shared U, U)) + alias Unshared = U; + else + alias Unshared = T; +} + +/// +@safe unittest +{ + static assert(is(Unshared!( int) == int)); + static assert(is(Unshared!( const int) == const int)); + static assert(is(Unshared!( inout int) == inout int)); + static assert(is(Unshared!( inout const int) == inout const int)); + static assert(is(Unshared!(shared int) == int)); + static assert(is(Unshared!(shared const int) == const int)); + static assert(is(Unshared!(shared inout int) == inout int)); + static assert(is(Unshared!(shared inout const int) == inout const int)); + static assert(is(Unshared!( immutable int) == immutable int)); + + // Only the outer layer of shared is removed. + // shared(int[]) -> shared(int)[] + alias SharedIntArr = shared(int[]); + static assert(is(Unshared!SharedIntArr == shared(int)[])); + + // Only the outer layer of shared is removed. + // shared(int*) -> shared(int)* + alias SharedIntPtr = shared(int*); + static assert(is(Unshared!SharedIntPtr == shared(int)*)); + + // shared(int)* -> shared(int)* + alias PtrToSharedInt = shared(int)*; + static assert(is(Unshared!PtrToSharedInt == shared(int)*)); + + // immutable is unaffected + alias ImmutableArr = immutable(int[]); + static assert(is(Unshared!ImmutableArr == immutable(int[]))); + + static struct S + { + int* ptr; + const int* cPtr; + shared int* sPtr; + } + + shared S s; + static assert(is(typeof(s) == shared S)); + static assert(is(typeof(typeof(s).ptr) == shared int*)); + static assert(is(typeof(typeof(s).cPtr) == const shared int*)); + static assert(is(typeof(typeof(s).sPtr) == shared int*)); + + // For user-defined types, if shared is applied to a member variable only + // because the containing type is shared, then shared is removed from that + // member variable, but if the member variable is directly marked as shared, + // then it continues to be shared. + + // shared S -> S + static assert(is(Unshared!(typeof(s)) == S)); + static assert(is(typeof(Unshared!(typeof(s)).ptr) == int*)); + static assert(is(typeof(Unshared!(typeof(s)).cPtr) == const int*)); + static assert(is(typeof(Unshared!(typeof(s)).sPtr) == shared int*)); + + static struct Foo(T) + { + T* ptr; + } + + // The qualifier on the type is removed, but the qualifier on the template + // argument is not. + static assert(is(Unshared!(shared(Foo!(shared int))) == Foo!(shared int))); + static assert(is(Unshared!(Foo!(shared int)) == Foo!(shared int))); + static assert(is(Unshared!(shared(Foo!int)) == Foo!int)); +} + +/++ + Removes the outer layer of all type qualifiers from type $(D T) - this + includes $(D shared). + + If no type qualifiers have been applied to the outer layer of type $(D T), + then the result is $(D T). + + For the built-in scalar types (that is $(D bool), the character types, and + the numeric types), they only have one layer, so $(D const U) simply becomes + $(D U). + + Where the layers come in is pointers and arrays. $(D const(U*)) becomes + $(D const(U)*), and $(D const(U[])), becomes $(D const(U)[]). So, a pointer + goes from being fully $(D const) to being a mutable pointer to $(D const), + and a dynamic array goes from being fully $(D const) to being a mutable + dynamic array of $(D const) elements. And if there are multiple layers of + pointers or arrays, it's just that outer layer which is affected - e.g. + $(D shared(U**)) would become $(D shared(U*)*). + + For user-defined types, the effect is that $(D const U) becomes $(D U), and + how that affects member variables depends on the type of the member + variable. If a member variable is explicitly marked with any qualifiers, + then it will continue to have those qualifiers even after Unqualified has + stripped all qualifiers from the containing type. However, if a qualifier + was on the member variable only because the containing type had that + qualifier, then when Unqualified removes the qualifier from the containing + type, it is removed from the member variable as well. + + Also, Unqualified has no effect on what a templated type is instantiated + with, so if a templated type is instantiated with a template argument which + has a type qualifier, the template instantiation will not change. + + Note that in most cases, $(LREF Unconst) or $(LREF Unshared) should be used + rather than Unqualified, because in most cases, code is not designed to + work with $(D shared) and thus doing type checks which remove $(D shared) + will allow $(D shared) types to pass template constraints when they won't + actually work with the code. And when code is designed to work with + $(D shared), it's often the case that the type checks need to take + $(D const) into account in order to avoid accidentally mutating $(D const) + data and violating the type system. + + In particular, historically, a lot of D code has used + $(REF Unqual, std, traits) (which is equivalent to phobos.sys.traits' + Unqualified) when the programmer's intent was to remove $(D const), and + $(D shared) wasn't actually considered at all. And in such cases, the code + really should use $(LREF Unconst) instead. + + But of course, if a template constraint or $(D static if) really needs to + strip off both the mutability qualifiers and $(D shared) for what it's + testing for, then that's what Unqualified is for. It's just that it's best + practice to use $(LREF Unconst) when it's not clear that $(D shared) should + be removed as well. + +/ +version (StdDdoc) template Unqualified(T) +{ + import core.internal.traits : CoreUnqualified = Unqual; + alias Unqualified = CoreUnqualified!(T); +} +else +{ + import core.internal.traits : CoreUnqualified = Unqual; + alias Unqualified = CoreUnqualified; +} + +/// +@safe unittest +{ + static assert(is(Unqualified!( int) == int)); + static assert(is(Unqualified!( const int) == int)); + static assert(is(Unqualified!( inout int) == int)); + static assert(is(Unqualified!( inout const int) == int)); + static assert(is(Unqualified!(shared int) == int)); + static assert(is(Unqualified!(shared const int) == int)); + static assert(is(Unqualified!(shared inout int) == int)); + static assert(is(Unqualified!(shared inout const int) == int)); + static assert(is(Unqualified!( immutable int) == int)); + + // Only the outer layer of immutable is removed. + // immutable(int[]) -> immutable(int)[] + alias ImmIntArr = immutable(int[]); + static assert(is(Unqualified!ImmIntArr == immutable(int)[])); + + // Only the outer layer of const is removed. + // const(int*) -> const(int)* + alias ConstIntPtr = const(int*); + static assert(is(Unqualified!ConstIntPtr == const(int)*)); + + // const(int)* -> const(int)* + alias PtrToConstInt = const(int)*; + static assert(is(Unqualified!PtrToConstInt == const(int)*)); + + // Only the outer layer of shared is removed. + // shared(int*) -> shared(int)* + alias SharedIntPtr = shared(int*); + static assert(is(Unqualified!SharedIntPtr == shared(int)*)); + + // shared(int)* -> shared(int)* + alias PtrToSharedInt = shared(int)*; + static assert(is(Unqualified!PtrToSharedInt == shared(int)*)); + + // Both const and shared are removed from the outer layer. + // shared const int[] -> shared(const(int))[] + alias SharedConstIntArr = shared const(int[]); + static assert(is(Unqualified!SharedConstIntArr == shared(const(int))[])); + + static struct S + { + int* ptr; + const int* cPtr; + shared int* sPtr; + } + + shared const S s; + static assert(is(typeof(s) == shared const S)); + static assert(is(typeof(typeof(s).ptr) == shared const int*)); + static assert(is(typeof(typeof(s).cPtr) == shared const int*)); + static assert(is(typeof(typeof(s).sPtr) == shared const int*)); + + // For user-defined types, all qualifiers that are applied to member + // variables only because the containing type has them are removed, but the + // ones that are directly on those member variables remain. + + // shared const S -> S + static assert(is(Unqualified!(typeof(s)) == S)); + static assert(is(typeof(Unqualified!(typeof(s)).ptr) == int*)); + static assert(is(typeof(Unqualified!(typeof(s)).cPtr) == const int*)); + static assert(is(typeof(Unqualified!(typeof(s)).sPtr) == shared int*)); + + static struct Foo(T) + { + T* ptr; + } + + // The qualifiers on the type are removed, but the qualifiers on the + // template argument are not. + static assert(is(Unqualified!(const(Foo!(const int))) == Foo!(const int))); + static assert(is(Unqualified!(Foo!(const int)) == Foo!(const int))); + static assert(is(Unqualified!(const(Foo!int)) == Foo!int)); +} + +/++ + Applies $(D const) to the given type. + + This is primarily useful in conjunction with templates that take a template + predicate (such as many of the templates in phobos.sys.meta), since while in + most cases, you can simply do $(D const T) or $(D const(T)) to make $(D T) + $(D const), with something like $(REF Map, phobos, sys, meta), you need to + pass a template to be applied. + + See_Also: + $(LREF ImmutableOf) + $(LREF InoutOf) + $(LREF SharedOf) + +/ +alias ConstOf(T) = const T; + +/// +@safe unittest +{ + static assert(is(ConstOf!int == const int)); + static assert(is(ConstOf!(const int) == const int)); + static assert(is(ConstOf!(inout int) == inout const int)); + static assert(is(ConstOf!(shared int) == const shared int)); + + // Note that const has no effect on immutable. + static assert(is(ConstOf!(immutable int) == immutable int)); + + import phobos.sys.meta : AliasSeq, Map; + + alias Types = AliasSeq!(int, long, + bool*, ubyte[], + string, immutable(string)); + alias WithConst = Map!(ConstOf, Types); + static assert(is(WithConst == + AliasSeq!(const int, const long, + const(bool*), const(ubyte[]), + const(string), immutable(string)))); +} + +/++ + Applies $(D immutable) to the given type. + + This is primarily useful in conjunction with templates that take a template + predicate (such as many of the templates in phobos.sys.meta), since while in + most cases, you can simply do $(D immutable T) or $(D immutable(T)) to make + $(D T) $(D immutable), with something like $(REF Map, phobos, sys, meta), + you need to pass a template to be applied. + + See_Also: + $(LREF ConstOf) + $(LREF InoutOf) + $(LREF SharedOf) + +/ +alias ImmutableOf(T) = immutable T; + +/// +@safe unittest +{ + static assert(is(ImmutableOf!int == immutable int)); + + // Note that immutable overrides const and inout. + static assert(is(ImmutableOf!(const int) == immutable int)); + static assert(is(ImmutableOf!(inout int) == immutable int)); + + // Note that immutable overrides shared, since immutable is implicitly + // shared. + static assert(is(ImmutableOf!(shared int) == immutable int)); + + static assert(is(ImmutableOf!(immutable int) == immutable int)); + + import phobos.sys.meta : AliasSeq, Map; + + alias Types = AliasSeq!(int, long, + bool*, ubyte[], + string, immutable(string)); + alias WithImmutable = Map!(ImmutableOf, Types); + static assert(is(WithImmutable == + AliasSeq!(immutable int, immutable long, + immutable(bool*), immutable(ubyte[]), + immutable(string), immutable(string)))); +} + +/++ + Applies $(D inout) to the given type. + + This is primarily useful in conjunction with templates that take a template + predicate (such as many of the templates in phobos.sys.meta), since while in + most cases, you can simply do $(D inout T) or $(D inout(T)) to make $(D T) + $(D inout), with something like $(REF Map, phobos, sys, meta), you need to + pass a template to be applied. + + See_Also: + $(LREF ConstOf) + $(LREF ImmutableOf) + $(LREF SharedOf) + +/ +alias InoutOf(T) = inout T; + +/// +@safe unittest +{ + static assert(is(InoutOf!int == inout int)); + static assert(is(InoutOf!(const int) == inout const int)); + static assert(is(InoutOf!(inout int) == inout int)); + static assert(is(InoutOf!(shared int) == inout shared int)); + + // Note that inout has no effect on immutable. + static assert(is(InoutOf!(immutable int) == immutable int)); + + import phobos.sys.meta : AliasSeq, Map; + + alias Types = AliasSeq!(int, long, + bool*, ubyte[], + string, immutable(string)); + alias WithInout = Map!(InoutOf, Types); + static assert(is(WithInout == + AliasSeq!(inout int, inout long, + inout(bool*), inout(ubyte[]), + inout(string), immutable(string)))); +} + +/++ + Applies $(D shared) to the given type. + + This is primarily useful in conjunction with templates that take a template + predicate (such as many of the templates in phobos.sys.meta), since while in + most cases, you can simply do $(D shared T) or $(D shared(T)) to make $(D T) + $(D shared), with something like $(REF Map, phobos, sys, meta), you need to + pass a template to be applied. + + See_Also: + $(LREF ConstOf) + $(LREF ImmutableOf) + $(LREF InoutOf) + +/ +alias SharedOf(T) = shared T; + +/// +@safe unittest +{ + static assert(is(SharedOf!int == shared int)); + static assert(is(SharedOf!(const int) == const shared int)); + static assert(is(SharedOf!(inout int) == inout shared int)); + static assert(is(SharedOf!(shared int) == shared int)); + + // Note that shared has no effect on immutable, since immutable is + // implicitly shared. + static assert(is(SharedOf!(immutable int) == immutable int)); + + import phobos.sys.meta : AliasSeq, Map; + + alias Types = AliasSeq!(int, long, + bool*, ubyte[], + string, immutable(string)); + alias WithShared = Map!(SharedOf, Types); + static assert(is(WithShared == + AliasSeq!(shared int, shared long, + shared(bool*), shared(ubyte[]), + shared(string), immutable(string)))); +} + +// Needed for rvalueOf/lvalueOf because +// "inout on return means inout must be on a parameter as well" +private struct __InoutWorkaroundStruct {} + +/++ + Creates an lvalue or rvalue of type T to be used in conjunction with + $(D is(typeof(...))) or + $(DDSUBLINK spec/traits, compiles, $(D __traits(compiles, ...))). + + The idea is that some traits or other forms of conditional compilation need + to verify that a particular piece of code compiles with an rvalue or an + lvalue of a specific type, and these $(D @property) functions allow you to + get an rvalue or lvalue of a specific type to use within an expression that + is then tested to see whether it compiles. + + They're $(D @property) functions so that using $(D typeof) on them gives + the return type rather than the type of the function. + + Note that these functions are $(I not) defined, so if they're actually used + outside of type introspection, they'll result in linker errors. They're + entirely for testing that a particular piece of code compiles with an rvalue + or lvalue of the given type. + + The $(D __InoutWorkaroundStruct) parameter is entirely to make it so that + these work when the given type has the $(D inout) qualifier, since the + language requires that a function that returns an $(D inout) type also have + an $(D inout) type as a parameter. It should just be ignored. + +/ +@property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init); + +/++ Ditto +/ +@property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init); + +/// +@safe unittest +{ + static int foo(int); + static assert(is(typeof(foo(lvalueOf!int)) == int)); + static assert(is(typeof(foo(rvalueOf!int)) == int)); + + static bool bar(ref int); + static assert(is(typeof(bar(lvalueOf!int)) == bool)); + static assert(!is(typeof(bar(rvalueOf!int)))); + + static assert( is(typeof({ lvalueOf!int = 42; }))); + static assert(!is(typeof({ rvalueOf!int = 42; }))); + + static struct S {} + static assert( is(typeof({ lvalueOf!S = S.init; }))); + static assert(!is(typeof({ rvalueOf!S = S.init; }))); + + static struct NoAssign + { + @disable void opAssign(ref NoAssign); + } + static assert(!is(typeof({ lvalueOf!NoAssign = NoAssign.init; }))); + static assert(!is(typeof({ rvalueOf!NoAssign = NoAssign.init; }))); +} + +@system unittest +{ + import phobos.sys.meta : AliasSeq; + + void needLvalue(T)(ref T); + static struct S {} + int i; + struct Nested { void f() { ++i; } } + + static foreach (T; AliasSeq!(int, const int, immutable int, inout int, string, S, Nested, Object)) + { + static assert(!__traits(compiles, needLvalue(rvalueOf!T))); + static assert( __traits(compiles, needLvalue(lvalueOf!T))); + static assert(is(typeof(rvalueOf!T) == T)); + static assert(is(typeof(lvalueOf!T) == T)); + } + + static assert(!__traits(compiles, rvalueOf!int = 1)); + static assert( __traits(compiles, lvalueOf!byte = 127)); + static assert(!__traits(compiles, lvalueOf!byte = 128)); +} diff --git a/std/algorithm/searching.d b/std/algorithm/searching.d index 465723c16ed..2d89dea3f1c 100644 --- a/std/algorithm/searching.d +++ b/std/algorithm/searching.d @@ -22,8 +22,9 @@ $(T2 boyerMooreFinder, $(T2 canFind, `canFind("hello world", "or")` returns `true`.) $(T2 count, - Counts elements that are equal to a specified value or satisfy a - predicate. `count([1, 2, 1], 1)` returns `2` and + Counts all elements or elements matching a predicate, specific element or sub-range.$(BR) + `count([1, 2, 1])` returns `3`, + `count([1, 2, 1], 1)` returns `2` and `count!"a < 0"([1, -3, 0])` returns `1`.) $(T2 countUntil, `countUntil(a, b)` returns the number of steps taken in `a` to @@ -605,34 +606,29 @@ if (isNarrowString!R1 && isNarrowString!R2) // count /** -The first version counts the number of elements `x` in `r` for -which `pred(x, value)` is `true`. `pred` defaults to +Counts matches of `needle` in `haystack`. + +The first overload counts each element `e` in `haystack` for +which `pred(e, needle)` is `true`. `pred` defaults to equality. Performs $(BIGOH haystack.length) evaluations of `pred`. -The second version returns the number of times `needle` occurs in -`haystack`. Throws an exception if `needle.empty`, as the _count +The second overload counts the number of times `needle` was matched in +`haystack`. `pred` compares elements in each range. +Throws an exception if `needle.empty` is `true`, as the _count of the empty range in any range would be infinite. Overlapped counts -are not considered, for example `count("aaa", "aa")` is `1`, not +are *not* considered, for example `count("aaa", "aa")` is `1`, not `2`. -The third version counts the elements for which `pred(x)` is $(D -true). Performs $(BIGOH haystack.length) evaluations of `pred`. - -The fourth version counts the number of elements in a range. It is -an optimization for the third version: if the given range has the -`length` property the count is returned right away, otherwise -performs $(BIGOH haystack.length) to walk the range. - Note: Regardless of the overload, `count` will not accept infinite ranges for `haystack`. Params: - pred = The predicate to evaluate. + pred = The predicate to compare elements. haystack = The range to _count. - needle = The element or sub-range to _count in the `haystack`. + needle = The element or sub-range to _count in `haystack`. Returns: - The number of positions in the `haystack` for which `pred` returned true. + The number of matches in `haystack`. */ size_t count(alias pred = "a == b", Range, E)(Range haystack, E needle) if (isInputRange!Range && !isInfinite!Range && @@ -645,21 +641,22 @@ if (isInputRange!Range && !isInfinite!Range && /// @safe unittest { - import std.uni : toLower; - // count elements in range int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; - assert(count(a) == 9); assert(count(a, 2) == 3); assert(count!("a > b")(a, 2) == 5); +} + +/// +@safe unittest +{ + import std.uni : toLower; // count range in range assert(count("abcadfabf", "ab") == 2); assert(count("ababab", "abab") == 1); assert(count("ababab", "abx") == 0); // fuzzy count range in range assert(count!((a, b) => toLower(a) == toLower(b))("AbcAdFaBf", "ab") == 2); - // count predicate in range - assert(count!("a > 1")(a) == 8); } @safe unittest @@ -711,7 +708,24 @@ if (isForwardRange!R1 && !isInfinite!R1 && } } -/// Ditto +/** +Counts all elements or elements satisfying a predicate in `haystack`. + +The first overload counts each element `e` in `haystack` for which `pred(e)` is $(D +true). Performs $(BIGOH haystack.length) evaluations of `pred`. + +The second overload counts the number of elements in a range. +If the given range has the `length` property, +that is returned right away, otherwise +performs $(BIGOH haystack.length) to walk the range. + +Params: + pred = Optional predicate to find elements. + haystack = The range to _count. + +Returns: + The number of elements in `haystack` (for which `pred` returned true). +*/ size_t count(alias pred, R)(R haystack) if (isInputRange!R && !isInfinite!R && is(typeof(unaryFun!pred(haystack.front)))) @@ -723,6 +737,16 @@ if (isInputRange!R && !isInfinite!R && return result; } +/// +@safe unittest +{ + // count elements in range + int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; + assert(count(a) == 9); + // count predicate in range + assert(count!("a > 2")(a) == 5); +} + /// Ditto size_t count(R)(R haystack) if (isInputRange!R && !isInfinite!R) diff --git a/std/algorithm/setops.d b/std/algorithm/setops.d index cc6f5b77db7..363bd16a0f9 100644 --- a/std/algorithm/setops.d +++ b/std/algorithm/setops.d @@ -8,7 +8,7 @@ $(LREF setIntersection), $(LREF setSymmetricDifference) expect a range of sorted ranges as input. All algorithms are generalized to accept as input not only sets but also -$(HTTP https://en.wikipedia.org/wiki/Multiset, multisets). Each algorithm +$(LINK2 https://en.wikipedia.org/wiki/Multiset, multisets). Each algorithm documents behaviour in the presence of duplicated inputs. $(SCRIPT inhibitQuickIndex = 1;) diff --git a/std/bitmanip.d b/std/bitmanip.d index c9813e35476..de2ff318f4e 100644 --- a/std/bitmanip.d +++ b/std/bitmanip.d @@ -164,8 +164,7 @@ private template createStorageAndFields(Ts...) alias StoreType = ulong; else { - import std.conv : to; - static assert(false, "Field widths must sum to 8, 16, 32, or 64, not " ~ to!string(Size)); + static assert(false, "Field widths must sum to 8, 16, 32, or 64, not " ~ Size.stringof); alias StoreType = ulong; // just to avoid another error msg } @@ -2959,10 +2958,10 @@ if (__traits(isIntegral, T)) Unqual!T result; version (LittleEndian) foreach_reverse (b; array) - result = cast(Unqual!T) ((result << 8) | b); + result = cast() cast(T) ((result << 8) | b); else foreach (b; array) - result = cast(Unqual!T) ((result << 8) | b); + result = cast() cast(T) ((result << 8) | b); return cast(T) result; } @@ -2977,7 +2976,7 @@ if (__traits(isIntegral, T)) foreach (i; 0 .. T.sizeof) { result[i] = cast(ubyte) tmp; - tmp = cast(Unqual!T) (tmp >>> 8); + tmp = cast() cast(T) (tmp >>> 8); } } else @@ -2985,7 +2984,7 @@ if (__traits(isIntegral, T)) foreach_reverse (i; 0 .. T.sizeof) { result[i] = cast(ubyte) tmp; - tmp = cast(Unqual!T) (tmp >>> 8); + tmp = cast()(T) (tmp >>> 8); } } return result; @@ -3274,7 +3273,7 @@ if (canSwapEndianness!T && n == T.sizeof) assert(c == littleEndianToNative!dchar(swappedC)); } -private T endianToNativeImpl(bool swap, T, size_t n)(ubyte[n] val) @nogc nothrow pure @safe +private T endianToNativeImpl(bool swap, T, size_t n)(ubyte[n] val) @nogc nothrow pure @trusted if (__traits(isIntegral, T) && n == T.sizeof) { if (!__ctfe) diff --git a/std/conv.d b/std/conv.d index 5d02df08bf9..3aa73c68bf1 100644 --- a/std/conv.d +++ b/std/conv.d @@ -5250,7 +5250,7 @@ if (isIntegral!T && isOutputRange!(W, char)) auto unsigned(T)(T x) if (isIntegral!T) { - return cast(Unqual!(Unsigned!T))x; + return cast() cast(Unsigned!T) x; } /// @@ -5271,7 +5271,7 @@ if (isSomeChar!T) { // All characters are unsigned static assert(T.min == 0, T.stringof ~ ".min must be zero"); - return cast(Unqual!T) x; + return cast() x; } @safe unittest @@ -5328,7 +5328,7 @@ if (isSomeChar!T) auto signed(T)(T x) if (isIntegral!T) { - return cast(Unqual!(Signed!T))x; + return cast() cast(Signed!T) x; } /// diff --git a/std/csv.d b/std/csv.d index 7f5c2b24c01..9ee9b5d5baf 100644 --- a/std/csv.d +++ b/std/csv.d @@ -175,6 +175,16 @@ class CSVException : Exception assert(ex.toString == "(Row: 1, Col: 2) Unexpected 'b' when converting from type string to type int"); } +// https://issues.dlang.org/show_bug.cgi?id=24478 +@safe unittest +{ + import std.exception : collectException; + import std.algorithm.searching : count; + string text = "A, B\n1, 2, 3"; + auto ex = collectException!CSVException(csvReader!(string[string])(text, null).count); + assert(ex.toString == "(Row: 1, Col: 3) row contains more values than header"); +} + @safe pure unittest { import std.string; @@ -1179,7 +1189,10 @@ public: { for (; !recordRange.empty; recordRange.popFront()) { - aa[header[_input.col-1]] = recordRange.front; + const i = _input.col - 1; + if (i >= header.length) + throw new CSVException("row contains more values than header", _input.row, _input.col); + aa[header[i]] = recordRange.front; } } catch (ConvException e) diff --git a/std/file.d b/std/file.d index 5b8925d5eb4..1db779bdf8e 100644 --- a/std/file.d +++ b/std/file.d @@ -1083,6 +1083,7 @@ private void removeImpl(scope const(char)[] name, scope const(FSChar)* namez) @t @safe unittest { import std.exception : collectExceptionMsg, assertThrown; + import std.algorithm.searching : startsWith; string filename = null; // e.g. as returned by File.tmpfile.name @@ -1090,12 +1091,10 @@ private void removeImpl(scope const(char)[] name, scope const(FSChar)* namez) @t { // exact exception message is OS-dependent auto msg = filename.remove.collectExceptionMsg!FileException; - assert("Failed to remove file (null): Bad address" == msg, msg); + assert(msg.startsWith("Failed to remove file (null):"), msg); } else version (Windows) { - import std.algorithm.searching : startsWith; - // don't test exact message on windows, it's language dependent auto msg = filename.remove.collectExceptionMsg!FileException; assert(msg.startsWith("(null):"), msg); diff --git a/std/internal/math/biguintcore.d b/std/internal/math/biguintcore.d index d5c4768f064..9df6bb22274 100644 --- a/std/internal/math/biguintcore.d +++ b/std/internal/math/biguintcore.d @@ -2241,31 +2241,6 @@ do return carry; } -// result = left - right -// returns carry (0 or 1) -BigDigit subSimple(BigDigit [] result,const(BigDigit) [] left, - const(BigDigit) [] right) pure nothrow -in -{ - assert(result.length == left.length, - "result and left must be of the same length"); - assert(left.length >= right.length, - "left must be longer or of equal length to right"); - assert(right.length > 0, "right must not be empty"); -} -do -{ - BigDigit carry = multibyteSub(result[0 .. right.length], - left[0 .. right.length], right, 0); - if (right.length < left.length) - { - result[right.length .. left.length] = left[right.length .. $]; - carry = multibyteIncrementAssign!('-')(result[right.length..$], carry); - } //else if (result.length == left.length+1) { result[$-1] = carry; carry=0; } - return carry; -} - - /* result = result - right * Returns carry = 1 if result was less than right. */ diff --git a/std/internal/unicode_comp.d b/std/internal/unicode_comp.d index 646aeeb3af0..28b2e0d26b9 100644 --- a/std/internal/unicode_comp.d +++ b/std/internal/unicode_comp.d @@ -7,11 +7,11 @@ import std.internal.unicode_tables; static if (size_t.sizeof == 4) { //10144 bytes -enum combiningClassTrieEntries = TrieEntry!(ubyte, 8, 8, 5)(cast(immutable size_t[]) x" +enum combiningClassTrieEntries = TrieEntry!(ubyte, 8, 8, 5)(x" 0000000000000040000005C0", -cast(immutable size_t[]) x" +x" 0000010000000B00000010A0", -cast(immutable size_t[]) x" +x" 020201000402030206020205090807020000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -226,11 +226,11 @@ E600E6E6E6E600E600E6E6E600000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000", ); enum composeIdxMask = (1 << 11) - 1, composeCntShift = 11; -enum compositionJumpTrieEntries = TrieEntry!(ushort, 12, 9)(cast(immutable size_t[]) x" +enum compositionJumpTrieEntries = TrieEntry!(ushort, 12, 9)(x" 0000000000000800", -cast(immutable size_t[]) x" +x" 0000100000002600", -cast(immutable size_t[]) x" +x" 00010000000300020005000400070006000700080007000700090007000A0007000C000B000700070007000700070007 0007000D0007000700070007000700070007000700070007000700070007000700070007000700070007000700070007 000700070007000700070007000700070007000700070007000700070007000700070007000700070007000700070007 @@ -919,11 +919,11 @@ return t[]; static if (size_t.sizeof == 8) { //10144 bytes -enum combiningClassTrieEntries = TrieEntry!(ubyte, 8, 8, 5)(cast(immutable size_t[]) x" +enum combiningClassTrieEntries = TrieEntry!(ubyte, 8, 8, 5)(x" 0000000000000000000000000000002000000000000002E0", -cast(immutable size_t[]) x" +x" 00000000000001000000000000000B0000000000000010A0", -cast(immutable size_t[]) x" +x" 040203020202010009080702060202050000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -1138,11 +1138,11 @@ E6E6E6E600000000000000000007E6E6000000000000000000000000000000000000000000000000 00000000000000000000000000000000", ); enum composeIdxMask = (1 << 11) - 1, composeCntShift = 11; -enum compositionJumpTrieEntries = TrieEntry!(ushort, 12, 9)(cast(immutable size_t[]) x" +enum compositionJumpTrieEntries = TrieEntry!(ushort, 12, 9)(x" 00000000000000000000000000000400", -cast(immutable size_t[]) x" +x" 00000000000010000000000000002600", -cast(immutable size_t[]) x" +x" 000300020001000000070006000500040007000700070008000A00070009000700070007000C000B0007000700070007 000700070007000D00070007000700070007000700070007000700070007000700070007000700070007000700070007 000700070007000700070007000700070007000700070007000700070007000700070007000700070007000700070007 diff --git a/std/internal/unicode_decomp.d b/std/internal/unicode_decomp.d index 6016f3dee23..d596d48c3ee 100644 --- a/std/internal/unicode_decomp.d +++ b/std/internal/unicode_decomp.d @@ -19,11 +19,11 @@ import std.internal.unicode_tables; static if (size_t.sizeof == 4) { //23488 bytes -enum compatMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)(cast(immutable size_t[]) x" +enum compatMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)(x" 000000000000004000000540", -cast(immutable size_t[]) x" +x" 0000010000000A0000002360", -cast(immutable size_t[]) x" +x" 020201000402030202020205070602020202020208020202000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -516,11 +516,11 @@ cast(immutable size_t[]) x" 00000000000000000000000000000000", ); //12544 bytes -enum canonMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)(cast(immutable size_t[]) x" +enum canonMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)(x" 000000000000004000000440", -cast(immutable size_t[]) x" +x" 000001000000080000001000", -cast(immutable size_t[]) x" +x" 020201000302020202020204020502020202020206020202000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -1636,11 +1636,11 @@ return t[]; static if (size_t.sizeof == 8) { //23488 bytes -enum compatMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)(cast(immutable size_t[]) x" +enum compatMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)(x" 0000000000000000000000000000002000000000000002A0", -cast(immutable size_t[]) x" +x" 00000000000001000000000000000A000000000000002360", -cast(immutable size_t[]) x" +x" 040203020202010007060202020202050802020202020202000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -2133,11 +2133,11 @@ cast(immutable size_t[]) x" 00000000000000000000000000000000", ); //12544 bytes -enum canonMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)(cast(immutable size_t[]) x" +enum canonMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)(x" 000000000000000000000000000000200000000000000220", -cast(immutable size_t[]) x" +x" 000000000000010000000000000008000000000000001000", -cast(immutable size_t[]) x" +x" 030202020202010002050202020202040602020202020202000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/std/internal/unicode_grapheme.d b/std/internal/unicode_grapheme.d index d33e987de2c..ba80e188a80 100644 --- a/std/internal/unicode_grapheme.d +++ b/std/internal/unicode_grapheme.d @@ -19,11 +19,11 @@ package(std): static if (size_t.sizeof == 4) { //832 bytes -enum hangulLVTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum hangulLVTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000004000000080", -cast(immutable size_t[]) x" +x" 000001000000008000000A00", -cast(immutable size_t[]) x" +x" 000000000002010000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -44,11 +44,11 @@ cast(immutable size_t[]) x" 00000000000000000000000000000000", ); //832 bytes -enum hangulLVTTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum hangulLVTTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000004000000080", -cast(immutable size_t[]) x" +x" 000001000000008000000A00", -cast(immutable size_t[]) x" +x" 000000000002010000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -69,11 +69,11 @@ FEFFFFFFFFEFFFFFFFFEFFFFFFFFEFFFFFFFFEFF0000000F00000000000000000000000000000000 00000000000000000000000000000000", ); //896 bytes -enum prependTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum prependTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000004000000080", -cast(immutable size_t[]) x" +x" 000001000000008000000C00", -cast(immutable size_t[]) x" +x" 010101000101010101010102010101010101010101010101010101010101010101010101010101010101010101010101 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 010101010101010101010101010101010101010101010101010101010101010101010101010101010000000000000000 @@ -95,11 +95,11 @@ cast(immutable size_t[]) x" 0000000000000000000000000000000000000000000000000000000000000000", ); //1280 bytes -enum controlTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum controlTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000000D0", -cast(immutable size_t[]) x" +x" 000001000000012000000E00", -cast(immutable size_t[]) x" +x" 020201000302020202020402020605020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020702020202020202020202020202020202020202020000000000000000 @@ -129,11 +129,11 @@ FFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000 0000000000000000000000000000000000000000000000000000000000000000", ); //1856 bytes -enum spacingMarkTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum spacingMarkTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000000B0", -cast(immutable size_t[]) x" +x" 00000100000000E000002400", -cast(immutable size_t[]) x" +x" 010101000101020104010103010501010101010101010101010101010101010101010101010101010101010101010101 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 010101010101010101010101010101010101010101010101010101010101010101010101010101010000000000000000 @@ -175,11 +175,11 @@ cast(immutable size_t[]) x" 0000000000000000000000000000000000000000000000000000000000000000", ); //3488 bytes -enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000004000000110", -cast(immutable size_t[]) x" +x" 00000100000001A000004B00", -cast(immutable size_t[]) x" +x" 0202010004020302070206050A0908020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020B02020202020202020202020202020202020202020000000000000000 @@ -255,11 +255,11 @@ FFFFFFFFF87FFFFFFFFFFFFF00201FFFF80000100000FFFE0000000000000000F9FFFF7F000007DB 0000000000000000000000000000000000000000000000000000000000000000", ); //1344 bytes -enum Extended_PictographicTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum Extended_PictographicTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000004000000090", -cast(immutable size_t[]) x" +x" 00000100000000A000001800", -cast(immutable size_t[]) x" +x" 020201000202020202020202030202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -296,11 +296,11 @@ FFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFF000000000000000000000000000000000000000000000000 static if (size_t.sizeof == 8) { //832 bytes -enum hangulLVTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum hangulLVTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000040", -cast(immutable size_t[]) x" +x" 000000000000010000000000000000800000000000000A00", -cast(immutable size_t[]) x" +x" 000201000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -321,11 +321,11 @@ cast(immutable size_t[]) x" 00000000000000000000000000000000", ); //832 bytes -enum hangulLVTTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum hangulLVTTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000040", -cast(immutable size_t[]) x" +x" 000000000000010000000000000000800000000000000A00", -cast(immutable size_t[]) x" +x" 000201000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -346,11 +346,11 @@ FFEFFFFFFEFFFFFFFFFFEFFFFFFEFFFF0000000FFFFFFEFF00000000000000000000000000000000 00000000000000000000000000000000", ); //896 bytes -enum prependTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum prependTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000040", -cast(immutable size_t[]) x" +x" 000000000000010000000000000000800000000000000C00", -cast(immutable size_t[]) x" +x" 010101010101010001010101010101020101010101010101010101010101010101010101010101010101010101010101 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 010101010101010101010101010101010101010101010101010101010101010101010101010101010000000000000000 @@ -372,11 +372,11 @@ cast(immutable size_t[]) x" 0000000000000000000000000000000000000000000000000000000000000000", ); //1280 bytes -enum controlTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum controlTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000068", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001200000000000000E00", -cast(immutable size_t[]) x" +x" 030202020202010002060502020204020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020207020202020202020202020202020202020000000000000000 @@ -406,11 +406,11 @@ FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000", ); //1856 bytes -enum spacingMarkTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum spacingMarkTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000058", -cast(immutable size_t[]) x" +x" 000000000000010000000000000000E00000000000002400", -cast(immutable size_t[]) x" +x" 010102010101010001050101040101030101010101010101010101010101010101010101010101010101010101010101 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 010101010101010101010101010101010101010101010101010101010101010101010101010101010000000000000000 @@ -452,11 +452,11 @@ C0300000000000080000000000000002000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000", ); //3488 bytes -enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000088", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001A00000000000004B00", -cast(immutable size_t[]) x" +x" 04020302020201000A090802070206050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 02020202020202020202020202020202020202020202020B020202020202020202020202020202020000000000000000 @@ -532,11 +532,11 @@ F87FFFFFFFFFFFFF00201FFFFFFFFFFF0000FFFEF80000100000000000000000000007DBF9FFFF7F 0000000000000000000000000000000000000000000000000000000000000000", ); //1344 bytes -enum Extended_PictographicTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum Extended_PictographicTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000048", -cast(immutable size_t[]) x" +x" 000000000000010000000000000000A00000000000001800", -cast(immutable size_t[]) x" +x" 020202020202010003020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 diff --git a/std/internal/unicode_norm.d b/std/internal/unicode_norm.d index c103c254d7e..bc51c8cd610 100644 --- a/std/internal/unicode_norm.d +++ b/std/internal/unicode_norm.d @@ -19,11 +19,11 @@ package(std): static if (size_t.sizeof == 4) { //1728 bytes -enum nfcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum nfcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000000C0", -cast(immutable size_t[]) x" +x" 000001000000010000001E00", -cast(immutable size_t[]) x" +x" 020201000302020202020204020502020202020206020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -62,11 +62,11 @@ FFFFFFFFFFFFFFFF03FFFFFF00000000A00000005F7FFC0000007FDB000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ); //2048 bytes -enum nfdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum nfdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000000E0", -cast(immutable size_t[]) x" +x" 000001000000014000002400", -cast(immutable size_t[]) x" +x" 020201000504030202020206020702020202020208020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -112,11 +112,11 @@ A00000005F7FFC0000007FDB00000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000", ); //2848 bytes -enum nfkcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum nfkcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000000E0", -cast(immutable size_t[]) x" +x" 000001000000014000003D00", -cast(immutable size_t[]) x" +x" 020201000402030202020205070602020202020208020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -179,11 +179,11 @@ FFFF07FFFFFF7FFF0000FFFF00001C0000010000000000000000000000000000FFFF00070FFFFFFF 00000000000000000000000000000000", ); //2944 bytes -enum nfkdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum nfkdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000000F0", -cast(immutable size_t[]) x" +x" 000001000000016000003E00", -cast(immutable size_t[]) x" +x" 020201000504030202020206080702020202020209020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -254,11 +254,11 @@ FFFF07FFFFFF7FFF0000FFFF00001C0000010000000000000000000000000000FFFF00070FFFFFFF static if (size_t.sizeof == 8) { //1728 bytes -enum nfcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum nfcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000060", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001000000000000001E00", -cast(immutable size_t[]) x" +x" 030202020202010002050202020202040602020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -297,11 +297,11 @@ FFFFFFFFFFFFFFFF0000000003FFFFFF5F7FFC00A00000000000000000007FDB0000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ); //2048 bytes -enum nfdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum nfdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000070", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001400000000000002400", -cast(immutable size_t[]) x" +x" 050403020202010002070202020202060802020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -347,11 +347,11 @@ F8000000000000000000000000000001000000003FFFFFFF00000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000", ); //2848 bytes -enum nfkcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum nfkcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000070", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001400000000000003D00", -cast(immutable size_t[]) x" +x" 040203020202010007060202020202050802020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -414,11 +414,11 @@ FFFF7FFFFFFF07FF00001C000000FFFF000000000001000000000000000000000FFFFFFFFFFF0007 00000000000000000000000000000000", ); //2944 bytes -enum nfkdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum nfkdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000078", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001600000000000003E00", -cast(immutable size_t[]) x" +x" 050403020202010008070202020202060902020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 diff --git a/std/internal/unicode_tables.d b/std/internal/unicode_tables.d index cc0225b1a51..a686e389171 100644 --- a/std/internal/unicode_tables.d +++ b/std/internal/unicode_tables.d @@ -75,7 +75,7 @@ struct TrieEntry(T...) SCE simpleCaseTable(size_t i) { -static immutable uint[] t = cast(immutable uint[]) x" +static immutable uint[] t = x" 0201E90B0211E92D0201E9110211E93302000496021004970200A7220210A72302001F7902101FF902001F4402101F4C 0200015A0210015B020010FD02101CBD02016E4C02116E6C02001E3802101E390201E9210211E94302001F2302101F2B 020001A0021001A1030003A3031003C2032003C3020004DC021004DD02002CA602102CA70200017B0210017C0201E906 @@ -329,7 +329,7 @@ return SCE(t[i]); } @property FCE fullCaseTable(size_t index) nothrow @nogc @safe pure { -static immutable ulong[] t = cast(immutable ulong[]) x" +static immutable ulong[] t = x" 001E90B000000021001E92D0000001210010CAE0000000210010CEE00000012100004960000000210000497000000121 001E911000000021001E933000000121000A722000000021000A7230000001210001F790000000210001FF9000000121 0001F440000000210001F4C000000121000015A000000021000015B00000012100010FD0000000210001CBD000000121 @@ -2285,11 +2285,11 @@ bool isHangT(dchar ch) @safe pure nothrow @nogc static if (size_t.sizeof == 4) { //2080 bytes -enum lowerCaseTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum lowerCaseTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000000E0", -cast(immutable size_t[]) x" +x" 000001000000014000002500", -cast(immutable size_t[]) x" +x" 020201000402030206020205080702020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -2336,11 +2336,11 @@ FFFFFFC0FC000000000FFFFFFFFFC000000000FF0FFFFFFCFFC000000000FFFFFFFFFC000000003F 00000000000000000000000000000000", ); //1856 bytes -enum upperCaseTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum upperCaseTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000000E0", -cast(immutable size_t[]) x" +x" 000001000000014000001E00", -cast(immutable size_t[]) x" +x" 020201000402030206020205080702020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -2382,11 +2382,11 @@ F0000000001FFFFFFFC0000000007FFFFFFF0000000001FF0000040000000000FFFFFFFF00000003 0000000000000000000000000000000000000000000000000000000000000000", ); //11648 bytes -enum simpleCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum simpleCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000004000000280", -cast(immutable size_t[]) x" +x" 0000010000000480000011C0", -cast(immutable size_t[]) x" +x" 020201000402030206020205070202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -2632,11 +2632,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //11648 bytes -enum fullCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum fullCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000004000000280", -cast(immutable size_t[]) x" +x" 0000010000000480000011C0", -cast(immutable size_t[]) x" +x" 020201000402030206020205070202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -2882,11 +2882,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //5600 bytes -enum alphaTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum alphaTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000001A0", -cast(immutable size_t[]) x" +x" 00000100000002C000007B00", -cast(immutable size_t[]) x" +x" 03020100060504030A0908070E0D0C0B0303030311100F03141413121414141414141414141414141414141414141414 141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414 141414141414141414141414141414141414141414141414141414141414141414141414141414140000000000000000 @@ -3006,11 +3006,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF 0000000000000000000000000000000000000000000000000000000000000000", ); //3392 bytes -enum markTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum markTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000004000000110", -cast(immutable size_t[]) x" +x" 00000100000001A000004800", -cast(immutable size_t[]) x" +x" 0202010004020302070206050A0908020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020B02020202020202020202020202020202020202020000000000000000 @@ -3084,11 +3084,11 @@ F9FFFF7F000007DB0000000000000000000080000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000", ); //2848 bytes -enum numberTrieEntries = TrieEntry!(bool, 8, 6, 7)(cast(immutable size_t[]) x" +enum numberTrieEntries = TrieEntry!(bool, 8, 6, 7)(x" 0000000000000040000001A0", -cast(immutable size_t[]) x" +x" 00000100000002C000002500", -cast(immutable size_t[]) x" +x" 020201000402030207020605090802020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -3151,11 +3151,11 @@ FFFFFFFF001EEFFF0000000000000000FFFFFFFE3FFFBFFF000000000000000000001FFF00000000 00000000000000000000000003FF0000", ); //3360 bytes -enum punctuationTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum punctuationTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000004000000100", -cast(immutable size_t[]) x" +x" 000001000000018000004900", -cast(immutable size_t[]) x" +x" 0202010004020302070206050A0908020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -3228,11 +3228,11 @@ E8003600000000000000000000003C000000000000000000001000000000000000003FFF00000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ); //3424 bytes -enum symbolTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum symbolTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000004000000100", -cast(immutable size_t[]) x" +x" 000001000000018000004B00", -cast(immutable size_t[]) x" +x" 0302010005030403070303060A0908030303030303030303030303030303030303030303030303030303030303030303 030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303 030303030303030303030303030303030303030303030303030303030303030303030303030303030000000000000000 @@ -3307,11 +3307,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFF000007FF000000000000000000000000 00000000000000000000000000000000", ); //6080 bytes -enum graphicalTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum graphicalTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000040000001A0", -cast(immutable size_t[]) x" +x" 00000100000002C000008A00", -cast(immutable size_t[]) x" +x" 0202010005040302090807060D0C0B0A02020202100F0E02131312111313131313131313131313131313131313131313 131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313 131313131313131313131313131313131313131413131313131313131313131313131313131313130000000000000000 @@ -3441,11 +3441,11 @@ FFFFFFFF0000FFFF0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 0000000000000000000000000000000000000000000000000000000000000000", ); //4824 bytes -enum nonCharacterTrieEntries = TrieEntry!(bool, 7, 4, 4, 6)(cast(immutable size_t[]) x" +enum nonCharacterTrieEntries = TrieEntry!(bool, 7, 4, 4, 6)(x" 00000000000000200000009800000298", -cast(immutable size_t[]) x" +x" 00000080000000F000000400000043C0", -cast(immutable size_t[]) x" +x" 0302010007060504090801010B0B0B0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B 0B0B0B0B0B0B0B0B0B0B0B0C0D0101010D01010100000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000010000000300020005000400070006 @@ -3552,11 +3552,11 @@ enum MAX_SIMPLE_LOWER = 1433; enum MAX_SIMPLE_UPPER = 1450; enum MAX_SIMPLE_TITLE = 1454; //10496 bytes -enum toUpperIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toUpperIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000004000000280", -cast(immutable size_t[]) x" +x" 000001000000048000000F80", -cast(immutable size_t[]) x" +x" 020201000402030206020205070202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -3778,11 +3778,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //10112 bytes -enum toLowerIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toLowerIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000004000000280", -cast(immutable size_t[]) x" +x" 000001000000048000000EC0", -cast(immutable size_t[]) x" +x" 020201000402030206020205070202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -3996,11 +3996,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //10496 bytes -enum toTitleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toTitleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000004000000280", -cast(immutable size_t[]) x" +x" 000001000000048000000F80", -cast(immutable size_t[]) x" +x" 020201000402030206020205070202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -4222,11 +4222,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //10368 bytes -enum toUpperSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toUpperSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000004000000280", -cast(immutable size_t[]) x" +x" 000001000000048000000F40", -cast(immutable size_t[]) x" +x" 020201000402030206020205070202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -4445,11 +4445,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //9856 bytes -enum toLowerSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toLowerSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000004000000280", -cast(immutable size_t[]) x" +x" 000001000000048000000E40", -cast(immutable size_t[]) x" +x" 020201000402030206020205070202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -4658,11 +4658,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //10368 bytes -enum toTitleSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toTitleSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000004000000280", -cast(immutable size_t[]) x" +x" 000001000000048000000F40", -cast(immutable size_t[]) x" +x" 020201000402030206020205070202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -4882,7 +4882,7 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ); immutable(uint)[] toUpperTable() nothrow @nogc pure @safe { static immutable uint[] t = -cast(immutable uint[]) x" +x" 0000004100000042000000430000004400000045000000460000004700000048000000490000004A0000004B0000004C 0000004D0000004E0000004F000000500000005100000052000000530000005400000055000000560000005700000058 000000590000005A0000039C000000C0000000C1000000C2000000C3000000C4000000C5000000C6000000C7000000C8 @@ -5027,7 +5027,7 @@ return t; } immutable(uint)[] toLowerTable() nothrow @nogc pure @safe { static immutable uint[] t = -cast(immutable uint[]) x" +x" 0000006100000062000000630000006400000065000000660000006700000068000000690000006A0000006B0000006C 0000006D0000006E0000006F000000700000007100000072000000730000007400000075000000760000007700000078 000000790000007A000000E0000000E1000000E2000000E3000000E4000000E5000000E6000000E7000000E8000000E9 @@ -5161,7 +5161,7 @@ return t; } immutable(uint)[] toTitleTable() nothrow @nogc pure @safe { static immutable uint[] t = -cast(immutable uint[]) x" +x" 0000004100000042000000430000004400000045000000460000004700000048000000490000004A0000004B0000004C 0000004D0000004E0000004F000000500000005100000052000000530000005400000055000000560000005700000058 000000590000005A0000039C000000C0000000C1000000C2000000C3000000C4000000C5000000C6000000C7000000C8 @@ -5307,11 +5307,11 @@ return t; static if (size_t.sizeof == 8) { //2080 bytes -enum lowerCaseTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum lowerCaseTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000070", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001400000000000002500", -cast(immutable size_t[]) x" +x" 040203020202010008070202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -5358,11 +5358,11 @@ FFFFFFFC00000000000000000000000F000000000000000000000000000000000000000000000000 00000000000000000000000000000000", ); //1856 bytes -enum upperCaseTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum upperCaseTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000070", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001400000000000001E00", -cast(immutable size_t[]) x" +x" 040203020202010008070202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -5404,11 +5404,11 @@ FFF0000003FFFFFFFFFFFF0000003FFF003FDE64D0000003000003FFFFFF00007B0000001FDFE7B0 0000000000000000000000000000000000000000000000000000000000000000", ); //11648 bytes -enum simpleCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum simpleCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000000000000000000000200000000000000140", -cast(immutable size_t[]) x" +x" 0000000000000100000000000000048000000000000011C0", -cast(immutable size_t[]) x" +x" 040203020202010007020202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -5654,11 +5654,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //11648 bytes -enum fullCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum fullCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000000000000000000000200000000000000140", -cast(immutable size_t[]) x" +x" 0000000000000100000000000000048000000000000011C0", -cast(immutable size_t[]) x" +x" 040203020202010007020202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -5904,11 +5904,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //5600 bytes -enum alphaTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum alphaTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000000000000000000002000000000000000D0", -cast(immutable size_t[]) x" +x" 000000000000010000000000000002C00000000000007B00", -cast(immutable size_t[]) x" +x" 06050403030201000E0D0C0B0A09080711100F0303030303141414141414131214141414141414141414141414141414 141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414 141414141414141414141414141414141414141414141414141414141414141414141414141414140000000000000000 @@ -6028,11 +6028,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFF 0000000000000000000000000000000000000000000000000000000000000000", ); //3392 bytes -enum markTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum markTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000088", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001A00000000000004800", -cast(immutable size_t[]) x" +x" 04020302020201000A090802070206050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 02020202020202020202020202020202020202020202020B020202020202020202020202020202020000000000000000 @@ -6106,11 +6106,11 @@ B47E00000000000000000000000000BF0000000000FB7C0000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000", ); //2848 bytes -enum numberTrieEntries = TrieEntry!(bool, 8, 6, 7)(cast(immutable size_t[]) x" +enum numberTrieEntries = TrieEntry!(bool, 8, 6, 7)(x" 0000000000000000000000000000002000000000000000D0", -cast(immutable size_t[]) x" +x" 000000000000010000000000000002C00000000000002500", -cast(immutable size_t[]) x" +x" 040203020202010009080202070206050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -6173,11 +6173,11 @@ FFFE0000000003FF0000000000000000000003FF000000000000000000000000003F000000000000 000000000000000003FF000000000000", ); //3360 bytes -enum punctuationTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum punctuationTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000080", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001800000000000004900", -cast(immutable size_t[]) x" +x" 04020302020201000A090802070206050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020000000000000000 @@ -6250,11 +6250,11 @@ FE000000000000000000000000000000000000001E00000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", ); //3424 bytes -enum symbolTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum symbolTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 000000000000000000000000000000200000000000000080", -cast(immutable size_t[]) x" +x" 000000000000010000000000000001800000000000004B00", -cast(immutable size_t[]) x" +x" 05030403030201000A090803070303060303030303030303030303030303030303030303030303030303030303030303 030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303 030303030303030303030303030303030303030303030303030303030303030303030303030303030000000000000000 @@ -6329,11 +6329,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFF00000000000007FF0000000000000000 00000000000000000000000000000000", ); //6080 bytes -enum graphicalTrieEntries = TrieEntry!(bool, 8, 5, 8)(cast(immutable size_t[]) x" +enum graphicalTrieEntries = TrieEntry!(bool, 8, 5, 8)(x" 0000000000000000000000000000002000000000000000D0", -cast(immutable size_t[]) x" +x" 000000000000010000000000000002C00000000000008A00", -cast(immutable size_t[]) x" +x" 05040302020201000D0C0B0A09080706100F0E0202020202131313131313121113131313131313131313131313131313 131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313 131313131313131313131313131313131313131313131314131313131313131313131313131313130000000000000000 @@ -6463,11 +6463,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFF07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 0000000000000000000000000000000000000000000000000000000000000000", ); //4824 bytes -enum nonCharacterTrieEntries = TrieEntry!(bool, 7, 4, 4, 6)(cast(immutable size_t[]) x" +enum nonCharacterTrieEntries = TrieEntry!(bool, 7, 4, 4, 6)(x" 00000000000000000000000000000010000000000000004C000000000000014C", -cast(immutable size_t[]) x" +x" 000000000000008000000000000000F0000000000000040000000000000043C0", -cast(immutable size_t[]) x" +x" 07060504030201000B0B0B0A090801010B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B 0B0B0B0B0B0B0B0B0D0101010B0B0B0C000000000D010101000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000030002000100000007000600050004 @@ -6574,11 +6574,11 @@ enum MAX_SIMPLE_LOWER = 1433; enum MAX_SIMPLE_UPPER = 1450; enum MAX_SIMPLE_TITLE = 1454; //10496 bytes -enum toUpperIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toUpperIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000000000000000000000200000000000000140", -cast(immutable size_t[]) x" +x" 000000000000010000000000000004800000000000000F80", -cast(immutable size_t[]) x" +x" 040203020202010007020202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -6800,11 +6800,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //10112 bytes -enum toLowerIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toLowerIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000000000000000000000200000000000000140", -cast(immutable size_t[]) x" +x" 000000000000010000000000000004800000000000000EC0", -cast(immutable size_t[]) x" +x" 040203020202010007020202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -7018,11 +7018,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //10496 bytes -enum toTitleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toTitleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000000000000000000000200000000000000140", -cast(immutable size_t[]) x" +x" 000000000000010000000000000004800000000000000F80", -cast(immutable size_t[]) x" +x" 040203020202010007020202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -7244,11 +7244,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //10368 bytes -enum toUpperSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toUpperSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000000000000000000000200000000000000140", -cast(immutable size_t[]) x" +x" 000000000000010000000000000004800000000000000F40", -cast(immutable size_t[]) x" +x" 040203020202010007020202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -7467,11 +7467,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //9856 bytes -enum toLowerSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toLowerSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000000000000000000000200000000000000140", -cast(immutable size_t[]) x" +x" 000000000000010000000000000004800000000000000E40", -cast(immutable size_t[]) x" +x" 040203020202010007020202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -7680,11 +7680,11 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ); //10368 bytes -enum toTitleSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(cast(immutable size_t[]) x" +enum toTitleSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)(x" 000000000000000000000000000000200000000000000140", -cast(immutable size_t[]) x" +x" 000000000000010000000000000004800000000000000F40", -cast(immutable size_t[]) x" +x" 040203020202010007020202060202050202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202 @@ -7904,7 +7904,7 @@ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ); immutable(uint)[] toUpperTable() nothrow @nogc pure @safe { static immutable uint[] t = -cast(immutable uint[]) x" +x" 0000004100000042000000430000004400000045000000460000004700000048000000490000004A0000004B0000004C 0000004D0000004E0000004F000000500000005100000052000000530000005400000055000000560000005700000058 000000590000005A0000039C000000C0000000C1000000C2000000C3000000C4000000C5000000C6000000C7000000C8 @@ -8049,7 +8049,7 @@ return t; } immutable(uint)[] toLowerTable() nothrow @nogc pure @safe { static immutable uint[] t = -cast(immutable uint[]) x" +x" 0000006100000062000000630000006400000065000000660000006700000068000000690000006A0000006B0000006C 0000006D0000006E0000006F000000700000007100000072000000730000007400000075000000760000007700000078 000000790000007A000000E0000000E1000000E2000000E3000000E4000000E5000000E6000000E7000000E8000000E9 @@ -8183,7 +8183,7 @@ return t; } immutable(uint)[] toTitleTable() nothrow @nogc pure @safe { static immutable uint[] t = -cast(immutable uint[]) x" +x" 0000004100000042000000430000004400000045000000460000004700000048000000490000004A0000004B0000004C 0000004D0000004E0000004F000000500000005100000052000000530000005400000055000000560000005700000058 000000590000005A0000039C000000C0000000C1000000C2000000C3000000C4000000C5000000C6000000C7000000C8 diff --git a/std/math/algebraic.d b/std/math/algebraic.d index fd305231d08..cfb88c89f75 100644 --- a/std/math/algebraic.d +++ b/std/math/algebraic.d @@ -974,9 +974,9 @@ private T powIntegralImpl(PowType type, T)(T val) else { static if (isSigned!T) - return cast(Unqual!T) (val < 0 ? -(T(1) << bsr(0 - val) + type) : T(1) << bsr(val) + type); + return cast() cast(T) (val < 0 ? -(T(1) << bsr(0 - val) + type) : T(1) << bsr(val) + type); else - return cast(Unqual!T) (T(1) << bsr(val) + type); + return cast() cast(T) (T(1) << bsr(val) + type); } } diff --git a/std/math/hardware.d b/std/math/hardware.d index f474ea90373..501245ba90b 100644 --- a/std/math/hardware.d +++ b/std/math/hardware.d @@ -165,7 +165,7 @@ private: uint result = void; asm pure nothrow @nogc { - "movfcsr2gr %0,$r2" : "=r" (result); + "movfcsr2gr %0, $fcsr2" : "=r" (result); } return result & EXCEPTIONS_MASK; } @@ -203,7 +203,7 @@ private: { asm nothrow @nogc { - "movgr2fcsr $r2,$r0"; + "movgr2fcsr $fcsr2,$r0"; } } else @@ -883,7 +883,7 @@ private: ControlState cont; asm pure nothrow @nogc { - "movfcsr2gr %0,$r0" : "=r" (cont); + "movfcsr2gr %0, $fcsr0" : "=r" (cont); } cont &= (roundingMask | allExceptions); return cont; @@ -933,7 +933,7 @@ private: { asm nothrow @nogc { - "movgr2fcsr $r0,%0" : + "movgr2fcsr $fcsr0,%0" : : "r" (newState & (roundingMask | allExceptions)); } } diff --git a/std/net/isemail.d b/std/net/isemail.d index 12a29fe44c9..2234f3590ca 100644 --- a/std/net/isemail.d +++ b/std/net/isemail.d @@ -111,8 +111,9 @@ if (isSomeChar!(Char)) auto endOrDie = false; auto crlfCount = int.min; // int.min == not defined - foreach (ref i, e ; email) + for (size_t i; i < email.length; i++) { + auto e = email[i]; token = email.get(i, e); switch (context) diff --git a/std/path.d b/std/path.d index 449235a6820..a45865a9f18 100644 --- a/std/path.d +++ b/std/path.d @@ -2732,6 +2732,9 @@ else version (Posix) The function allocates memory if and only if it gets to the third stage of this algorithm. + Note that `absolutePath` will not normalize `..` segments. + Use `buildNormalizedPath(absolutePath(path))` if that is desired. + Params: path = the relative path to transform base = the base directory of the relative path @@ -2815,6 +2818,9 @@ string absolutePath(return scope const string path, lazy string base = getcwd()) which allocates memory.) ) + Note that `asAbsolutePath` will not normalize `..` segments. + Use `asNormalizedPath(asAbsolutePath(path))` if that is desired. + Params: path = the relative path to transform @@ -3391,7 +3397,7 @@ do else { C[] pattmp; - foreach (ref pi; 0 .. pattern.length) + for (size_t pi = 0; pi < pattern.length; pi++) { const pc = pattern[pi]; switch (pc) diff --git a/std/process.d b/std/process.d index 494910f3535..325689ba51d 100644 --- a/std/process.d +++ b/std/process.d @@ -1102,6 +1102,14 @@ private Pid spawnProcessPosix(scope const(char[])[] args, } } + if (config.preExecDelegate !is null) + { + if (config.preExecDelegate() != true) + { + abortOnError(forkPipeOut, InternalError.preExec, .errno); + } + } + // Execute program. core.sys.posix.unistd.execve(argz[0], argz.ptr, envz); @@ -1187,7 +1195,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args, errorMsg = "Failed to allocate memory"; break; case InternalError.preExec: - errorMsg = "Failed to execute preExecFunction"; + errorMsg = "Failed to execute preExecFunction or preExecDelegate"; break; case InternalError.noerror: assert(false); @@ -1271,6 +1279,29 @@ version (Posix) assert(received); } +version (Posix) +@system unittest +{ + __gshared int j; + foreach (i; 0 .. 3) + { + auto config = Config( + preExecFunction: function() @trusted { + j = 1; + return true; + }, + preExecDelegate: delegate() @trusted { + // j should now be 1, as preExecFunction is called before + // preExecDelegate is. + _Exit(i + j); + return true; + }, + ); + auto pid = spawnProcess(["false"], config: config); + assert(wait(pid) == i + 1); + } +} + /* Implementation of spawnProcess() for Windows. @@ -2186,13 +2217,30 @@ struct Config Please note that the code in this function must only use async-signal-safe functions.) + If $(LREF preExecDelegate) is also set, it is called last. + On Windows, this member is not available. */ bool function() nothrow @nogc @safe preExecFunction; + + /** + A delegate that is called before `exec` in $(LREF spawnProcess). + It returns `true` if succeeded and otherwise returns `false`. + + $(RED Warning: + Please note that the code in this function must only use + async-signal-safe functions.) + + If $(LREF preExecFunction) is also set, it is called first. + + On Windows, this member is not available. + */ + bool delegate() nothrow @nogc @safe preExecDelegate; } else version (Posix) { bool function() nothrow @nogc @safe preExecFunction; + bool delegate() nothrow @nogc @safe preExecDelegate; } } diff --git a/std/range/package.d b/std/range/package.d index 9f530418a85..995bf1e6c9b 100644 --- a/std/range/package.d +++ b/std/range/package.d @@ -1734,7 +1734,7 @@ pure @safe unittest assert(range.array == [S(5), S(6)]); } -/// https://issues.dlang.org/show_bug.cgi?id=24064 +// https://issues.dlang.org/show_bug.cgi?id=24064 pure @safe nothrow unittest { import std.algorithm.comparison : equal; @@ -1767,7 +1767,7 @@ pure @safe nothrow @nogc unittest } } -/// https://issues.dlang.org/show_bug.cgi?id=24243 +// https://issues.dlang.org/show_bug.cgi?id=24243 pure @safe nothrow unittest { import std.algorithm.iteration : filter; @@ -1959,7 +1959,7 @@ private struct ChooseResult(Ranges...) this(this) { actOnChosen!((ref r) { - static if (hasElaborateCopyConstructor!(typeof(r))) r.__postblit(); + static if (hasElaborateCopyConstructor!(typeof(r))) r.__xpostblit(); })(this); } @@ -2254,6 +2254,29 @@ pure @safe nothrow unittest assert(chosen2.front.v == 4); } +// https://issues.dlang.org/show_bug.cgi?id=15708 +@safe unittest +{ + static struct HasPostblit + { + this(this) {} + } + + static struct Range + { + bool empty; + int front; + void popFront() {} + HasPostblit member; + } + + Range range; + int[] arr; + + auto chosen = choose(true, range, arr); + auto copy = chosen; +} + /** Choose one of multiple ranges at runtime. diff --git a/std/socket.d b/std/socket.d index 4052479f9ca..e86a51fe2df 100644 --- a/std/socket.d +++ b/std/socket.d @@ -1116,7 +1116,7 @@ Address[] getAddress(scope const(char)[] hostname, ushort port) // test via gethostbyname auto getaddrinfoPointerBackup = getaddrinfoPointer; cast() getaddrinfoPointer = null; - scope(exit) cast() getaddrinfoPointer = getaddrinfoPointerBackup; + scope(exit) () @trusted { cast() getaddrinfoPointer = getaddrinfoPointerBackup; }(); addresses = getAddress("63.105.9.61"); assert(addresses.length && addresses[0].toAddrString() == "63.105.9.61"); @@ -1196,7 +1196,7 @@ Address parseAddress(scope const(char)[] hostaddr, ushort port) // test via inet_addr auto getaddrinfoPointerBackup = getaddrinfoPointer; cast() getaddrinfoPointer = null; - scope(exit) cast() getaddrinfoPointer = getaddrinfoPointerBackup; + scope(exit) () @trusted { cast() getaddrinfoPointer = getaddrinfoPointerBackup; }(); address = parseAddress("63.105.9.61"); assert(address.toAddrString() == "63.105.9.61"); @@ -1698,7 +1698,7 @@ public: // test reverse lookup, via gethostbyaddr auto getnameinfoPointerBackup = getnameinfoPointer; cast() getnameinfoPointer = null; - scope(exit) cast() getnameinfoPointer = getnameinfoPointerBackup; + scope(exit) () @trusted { cast() getnameinfoPointer = getnameinfoPointerBackup; }(); assert(ia.toHostNameString() == "digitalmars.com"); } @@ -1716,7 +1716,7 @@ public: // test failing reverse lookup, via gethostbyaddr auto getnameinfoPointerBackup = getnameinfoPointer; cast() getnameinfoPointer = null; - scope(exit) cast() getnameinfoPointer = getnameinfoPointerBackup; + scope(exit) () @trusted { cast() getnameinfoPointer = getnameinfoPointerBackup; }(); assert(ia.toHostNameString() is null); } @@ -1925,7 +1925,7 @@ version (StdDdoc) * auto abstractAddr = new UnixAddress("\0/tmp/dbus-OtHLWmCLPR"); * --- * - * See_Also: $(HTTP http://man7.org/linux/man-pages/man7/unix.7.html, UNIX(7)) + * See_Also: $(HTTP man7.org/linux/man-pages/man7/unix.7.html, UNIX(7)) */ class UnixAddress: Address { diff --git a/std/sumtype.d b/std/sumtype.d index 4e76156b1cb..80ce73d6a75 100644 --- a/std/sumtype.d +++ b/std/sumtype.d @@ -1988,7 +1988,7 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...) ? "template" : typeof(handler).stringof ) ~ "` " ~ - "never matches" + "never matches. Perhaps the handler failed to compile" ); } diff --git a/std/traits.d b/std/traits.d index 2e7a4f6a30b..5ed37a1f418 100644 --- a/std/traits.d +++ b/std/traits.d @@ -2181,7 +2181,7 @@ if (isCallable!func) /** -Get the function type from a callable object `func`. +Get the function type from a callable object `func`, or from a function pointer/delegate type. Using builtin `typeof` on a property function yields the types of the property value, not of the property function itself. Still, @@ -2229,10 +2229,17 @@ if (isCallable!func) { class C { - int value() @property { return 0; } + int value() @property => 0; + static string opCall() => "hi"; } static assert(is( typeof(C.value) == int )); static assert(is( FunctionTypeOf!(C.value) == function )); + static assert(is( FunctionTypeOf!C == typeof(C.opCall) )); + + int function() fp; + alias IntFn = int(); + static assert(is( typeof(fp) == IntFn* )); + static assert(is( FunctionTypeOf!fp == IntFn )); } @system unittest diff --git a/std/typecons.d b/std/typecons.d index 460cd427ed0..f5b48468a80 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -980,7 +980,7 @@ if (distinctFieldNames!(Specs)) { import std.algorithm.mutation : swap; - static if (is(R : Tuple!Types) && !__traits(isRef, rhs) && isTuple!R) + static if (is(R == Tuple!Types) && !__traits(isRef, rhs) && isTuple!R) { if (__ctfe) { diff --git a/std/utf.d b/std/utf.d index 3eef5cbcc03..c0cd3863b32 100644 --- a/std/utf.d +++ b/std/utf.d @@ -328,7 +328,7 @@ Returns: bool isValidCodepoint(Char)(Char c) if (isSomeChar!Char) { - alias UChar = Unqual!Char; + alias UChar = typeof(cast() c); static if (is(UChar == char)) { return c <= 0x7F; @@ -1418,8 +1418,8 @@ do } else { - alias Char = Unqual!(ElementType!S); - Char[4] codeUnits; + alias Char = typeof(cast() ElementType!S.init); + Char[4] codeUnits = void; S tmp = str.save; for (size_t i = numCodeUnits; i > 0; ) { @@ -2821,7 +2821,7 @@ if (isSomeChar!C) size_t codeLength(C, InputRange)(InputRange input) if (isSomeFiniteCharInputRange!InputRange) { - alias EncType = Unqual!(ElementEncodingType!InputRange); + alias EncType = typeof(cast() ElementEncodingType!InputRange.init); static if (isSomeString!InputRange && is(EncType == C) && is(typeof(input.length))) return input.length; else @@ -3089,7 +3089,8 @@ private T toUTFImpl(T, S)(scope S s) static if (is(S == C[], C) || hasLength!S) app.reserve(s.length); - foreach (c; s.byUTF!(Unqual!(ElementEncodingType!T))) + ElementEncodingType!T e = void; + foreach (c; s.byUTF!(typeof(cast() ElementEncodingType!T.init))) app.put(c); return app.data; @@ -3168,10 +3169,10 @@ if (is(immutable typeof(*P.init) == typeof(str[0]))) return trustedPtr(); } - alias C = Unqual!(ElementEncodingType!S); + alias C = typeof(cast() ElementEncodingType!S.init); //If the P is mutable, then we have to make a copy. - static if (is(Unqual!(typeof(*P.init)) == typeof(*P.init))) + static if (is(typeof(cast() *P.init) == typeof(*P.init))) { return toUTFzImpl!(P, const(C)[])(cast(const(C)[])str); } @@ -3203,13 +3204,15 @@ private P toUTFzImpl(P, S)(return scope S str) @safe pure if (is(typeof(str[0]) C) && is(immutable typeof(*P.init) == immutable C) && !is(C == immutable)) //C[] or const(C)[] -> C*, const(C)*, or immutable(C)* { - alias InChar = typeof(str[0]); - alias OutChar = typeof(*P.init); + alias InChar = typeof(str[0]); + alias UInChar = typeof(cast() str[0]); // unqualified version of InChar + alias OutChar = typeof(*P.init); + alias UOutChar = typeof(cast() *P.init); // unqualified version //const(C)[] -> const(C)* or //C[] -> C* or const(C)* - static if (( is(const(Unqual!InChar) == InChar) && is(const(Unqual!OutChar) == OutChar)) || - (!is(const(Unqual!InChar) == InChar) && !is(immutable(Unqual!OutChar) == OutChar))) + static if (( is(const(UInChar) == InChar) && is( const(UOutChar) == OutChar)) || + (!is(const(UInChar) == InChar) && !is(immutable(UOutChar) == OutChar))) { if (!__ctfe) { @@ -3228,7 +3231,7 @@ if (is(typeof(str[0]) C) && is(immutable typeof(*P.init) == immutable C) && !is( else { import std.array : uninitializedArray; - auto copy = uninitializedArray!(Unqual!OutChar[])(str.length + 1); + auto copy = uninitializedArray!(UOutChar[])(str.length + 1); copy[0 .. $ - 1] = str[]; copy[$ - 1] = '\0'; diff --git a/std/uuid.d b/std/uuid.d index dec2a1c276d..b8cac6ecdd7 100644 --- a/std/uuid.d +++ b/std/uuid.d @@ -1207,7 +1207,7 @@ public struct UUID * randomGen = uniform RNG * See_Also: $(REF isUniformRNG, std,random) */ -@safe UUID randomUUID() +@nogc nothrow @safe UUID randomUUID() { import std.random : rndGen; // A PRNG with fewer than `n` bytes of state cannot produce diff --git a/std/variant.d b/std/variant.d index 41cd4848b12..f7832104d70 100644 --- a/std/variant.d +++ b/std/variant.d @@ -382,7 +382,7 @@ private: static if (isStaticArray!A && isDynamicArray!T) { auto this_ = (*src)[]; - emplaceRef(*cast(Unqual!T*) zat, cast(Unqual!T) this_); + emplaceRef(*cast(Unqual!T*) zat, cast() cast(T) this_); } else { diff --git a/tools/unicode_table_generator.d b/tools/unicode_table_generator.d index fd74589c388..0bbe80f608d 100644 --- a/tools/unicode_table_generator.d +++ b/tools/unicode_table_generator.d @@ -898,7 +898,7 @@ void writeCaseFolding(File sink) writeln("SCE simpleCaseTable(size_t i)"); writeln("{"); - writef("static immutable uint[] t = cast(immutable uint[]) x\""); + writef("static immutable uint[] t = x\""); foreach (i, v; simpleTable) { if (i % 12 == 0) writeln(); @@ -915,7 +915,7 @@ void writeCaseFolding(File sink) writeln("}"); writeln("@property FCE fullCaseTable(size_t index) nothrow @nogc @safe pure"); writeln("{"); - writef("static immutable ulong[] t = cast(immutable ulong[]) x\""); + writef("static immutable ulong[] t = x\""); int[4] maxS = 0; foreach (i, v; fullTable) { @@ -1162,7 +1162,7 @@ void writeFunctions(File sink) void writeUintArray(T:dchar)(File sink, const T[] tab) { size_t lineCount = 1; - sink.write("cast(immutable uint[]) x\""); + sink.write("x\""); foreach (i, elem; tab) { if ((i % 12) == 0) @@ -1461,7 +1461,7 @@ void storeTrie(T, O)(T trie, O sink) import std.format.write : formattedWrite; void store(size_t[] arr) { - formattedWrite(sink, "cast(immutable size_t[]) x\""); + formattedWrite(sink, "x\""); foreach (i; 0 .. arr.length) { static if (size_t.sizeof == 8)