diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d index f884314..a13ec1e 100644 --- a/source/tanya/container/array.d +++ b/source/tanya/container/array.d @@ -21,8 +21,9 @@ import std.algorithm.mutation; import std.conv; import std.range.primitives; import std.meta; -import std.traits; import tanya.memory; +import tanya.meta.trait; +import tanya.meta.transform; /** * Random-access range for the $(D_PSYMBOL Array). diff --git a/source/tanya/container/buffer.d b/source/tanya/container/buffer.d index b78d971..e29e739 100644 --- a/source/tanya/container/buffer.d +++ b/source/tanya/container/buffer.d @@ -14,8 +14,8 @@ */ module tanya.container.buffer; -import std.traits; import tanya.memory; +import tanya.meta.trait; version (unittest) { diff --git a/source/tanya/container/entry.d b/source/tanya/container/entry.d index 1aea478..75edbe8 100644 --- a/source/tanya/container/entry.d +++ b/source/tanya/container/entry.d @@ -14,7 +14,7 @@ */ module tanya.container.entry; -import std.traits; +import tanya.meta.trait; import tanya.typecons; package struct SEntry(T) diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d index fc87ee4..97228ab 100644 --- a/source/tanya/container/list.d +++ b/source/tanya/container/list.d @@ -18,9 +18,9 @@ import std.algorithm.comparison; import std.algorithm.mutation; import std.algorithm.searching; import std.range.primitives; -import std.traits; import tanya.container.entry; import tanya.memory; +import tanya.meta.trait; /** * Forward range for the $(D_PSYMBOL SList). diff --git a/source/tanya/container/queue.d b/source/tanya/container/queue.d index d9b5609..2b07a6a 100644 --- a/source/tanya/container/queue.d +++ b/source/tanya/container/queue.d @@ -15,10 +15,10 @@ module tanya.container.queue; import core.exception; -import std.traits; import std.algorithm.mutation; import tanya.container.entry; import tanya.memory; +import tanya.meta.trait; /** * FIFO queue. diff --git a/source/tanya/container/set.d b/source/tanya/container/set.d index 15ce7a4..1c5e559 100644 --- a/source/tanya/container/set.d +++ b/source/tanya/container/set.d @@ -16,10 +16,11 @@ module tanya.container.set; import std.algorithm.mutation; -import std.traits; import tanya.container; import tanya.container.entry; import tanya.memory; +import tanya.meta.trait; +import tanya.meta.transform; /** * Bidirectional range that iterates over the $(D_PSYMBOL Set)'s values. diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d index 68c258b..6918e29 100644 --- a/source/tanya/container/string.d +++ b/source/tanya/container/string.d @@ -32,8 +32,9 @@ import std.algorithm.mutation; import std.algorithm.searching; import std.range : isInfinite, isInputRange, ElementEncodingType, hasLength, popFrontN, empty; -import std.traits; import tanya.memory; +import tanya.meta.trait; +import tanya.meta.transform; import tanya.range.array; /** diff --git a/source/tanya/format/conv.d b/source/tanya/format/conv.d index 77b84e3..ac5754a 100644 --- a/source/tanya/format/conv.d +++ b/source/tanya/format/conv.d @@ -14,10 +14,11 @@ */ module tanya.format.conv; -import std.traits; import tanya.container.string; import tanya.memory; import tanya.memory.op; +import tanya.meta.trait; +import tanya.meta.transform; /** * Thrown if a type conversion fails. diff --git a/source/tanya/memory/package.d b/source/tanya/memory/package.d index 385aff9..fcb7dfa 100644 --- a/source/tanya/memory/package.d +++ b/source/tanya/memory/package.d @@ -19,9 +19,9 @@ import std.algorithm.iteration; import std.algorithm.mutation; import std.conv; import std.range; -import std.traits; public import tanya.memory.allocator; import tanya.memory.mmappool; +import tanya.meta.trait; /** * The mixin generates common methods for classes and structs using diff --git a/source/tanya/memory/smartref.d b/source/tanya/memory/smartref.d index 4883109..e33abcd 100644 --- a/source/tanya/memory/smartref.d +++ b/source/tanya/memory/smartref.d @@ -22,8 +22,8 @@ import std.algorithm.comparison; import std.algorithm.mutation; import std.conv; import std.range; -import std.traits; import tanya.memory; +import tanya.meta.trait; private template Payload(T) { diff --git a/source/tanya/meta/trait.d b/source/tanya/meta/trait.d index b4d4367..d6e2114 100644 --- a/source/tanya/meta/trait.d +++ b/source/tanya/meta/trait.d @@ -195,7 +195,7 @@ pure nothrow @safe @nogc unittest * T = A type. * * Returns: Size of the type $(D_PARAM T). - */ + */ enum size_t sizeOf(T) = T.sizeof; /// @@ -391,7 +391,12 @@ version (TanyaPhobos) TemplateArgsOf, Parameters, ParameterIdentifierTuple, - functionAttributes; + functionAttributes, + ParameterDefaults, + hasElaborateDestructor, + hasElaborateCopyConstructor, + hasElaborateAssign, + EnumMembers; } else: @@ -2330,3 +2335,295 @@ pure nothrow @safe @nogc unittest static assert((functionAttributes!func1 & FunctionAttribute.trusted) == 0); static assert((functionAttributes!func1 & FunctionAttribute.return_) == 0); } + +/** + * Returns a tuple with default values of the parameters to $(D_PARAM F). + * + * If a parameter doesn't have a default value, $(D_KEYWORD void) is returned. + * + * Params: + * F = A function. + * + * Returns: Default values of the parameters to $(D_PARAM F). + */ +template ParameterDefaults(F...) +if (isCallable!F) +{ + static if (is(FunctionTypeOf!F T == __parameters)) + { + private template GetDefault(size_t i) + { + static if (i == T.length) + { + alias GetDefault = AliasSeq!(); + } + else + { + enum getDefault(T[i .. i + 1] name) + { + return name[0]; + } + static if (is(typeof(getDefault()))) + { + alias Default = Alias!(getDefault()); + } + else + { + alias Default = void; + } + alias GetDefault = AliasSeq!(Default, GetDefault!(i + 1)); + } + } + + alias ParameterDefaults = GetDefault!0; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + void func1(int k, uint b = 5, int[] = [1, 2]); + alias Defaults = ParameterDefaults!func1; + static assert(is(Defaults[0] == void)); + static assert(Defaults[1 .. 3] == AliasSeq!(5, [1, 2])); +} + +/** + * Determines whether $(D_PARAM T) has an elaborate destructor. + * + * Only $(D_KEYWORD struct)s and static arrays of $(D_KEYWORD struct)s with the + * length greater than`0` can have elaborate destructors, for all other types + * $(D_PSYMBOL hasElaborateDestructor) evaluates to $(D_KEYWORD false). + * + * An elaborate destructor is an explicitly defined destructor or one generated + * by the compiler. The compiler generates a destructor for a + * $(D_KEYWORD struct) if it has members with an elaborate destructor. + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) has an elaborate destructor, + * $(D_KEYWORD false) otherwise. + */ +template hasElaborateDestructor(T) +{ + static if (is(T E : E[L], size_t L)) + { + enum bool hasElaborateDestructor = L > 0 && hasElaborateDestructor!E; + } + else + { + enum bool hasElaborateDestructor = is(T == struct) + && hasMember!(T, "__xdtor"); + } +} + +/// +pure nothrow @safe @nogc unittest +{ + class C + { + ~this() + { + } + } + static assert(!hasElaborateDestructor!C); + + static struct S + { + ~this() + { + } + } + static struct S1 + { + S s; + } + static struct S2 + { + } + static assert(hasElaborateDestructor!S); // Explicit destructor. + static assert(hasElaborateDestructor!S1); // Compiler-generated destructor. + static assert(!hasElaborateDestructor!S2); // No destructor. + + static assert(hasElaborateDestructor!(S[1])); + static assert(!hasElaborateDestructor!(S[0])); +} + +/** + * Determines whether $(D_PARAM T) has an elaborate postblit constructor. + * + * Only $(D_KEYWORD struct)s and static arrays of $(D_KEYWORD struct)s with the + * length greater than`0` can have elaborate postblit constructors, for all + * other types $(D_PSYMBOL hasElaborateCopyConstructor) evaluates to + * $(D_KEYWORD false). + * + * An elaborate postblit constructor is an explicitly defined postblit + * constructor or one generated by the compiler. The compiler generates a + * postblit constructor for a + * $(D_KEYWORD struct) if it has members with an elaborate postblit + * constructor. + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) has an elaborate postblit + * constructor, $(D_KEYWORD false) otherwise. + */ +template hasElaborateCopyConstructor(T) +{ + static if (is(T E : E[L], size_t L)) + { + enum bool hasElaborateCopyConstructor = L > 0 + && hasElaborateCopyConstructor!E; + } + else + { + enum bool hasElaborateCopyConstructor = is(T == struct) + && hasMember!(T, "__xpostblit"); + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(!hasElaborateCopyConstructor!int); + + static struct S + { + this(this) + { + } + } + static struct S1 + { + S s; + } + static struct S2 + { + } + static assert(hasElaborateCopyConstructor!S); // Explicit destructor. + static assert(hasElaborateCopyConstructor!S1); // Compiler-generated destructor. + static assert(!hasElaborateCopyConstructor!S2); // No destructor. + static assert(hasElaborateCopyConstructor!(S[1])); + static assert(!hasElaborateCopyConstructor!(S[0])); +} + +/** + * Determines whether $(D_PARAM T) has an elaborate assign. + * + * Only $(D_KEYWORD struct)s and static arrays of $(D_KEYWORD struct)s with the + * length greater than`0` can have an elaborate assign, for all + * other types $(D_PSYMBOL hasElaborateAssign) evaluates to $(D_KEYWORD false). + * + * An elaborate assign is defined with $(D_INLINECODE opAssign(typeof(this))) + * or $(D_INLINECODE opAssign(ref typeof(this))). An elaborate assign can be + * generated for a $(D_KEYWORD struct) by the compiler if one of the members of + * this $(D_KEYWORD struct) has an elaborate assign. + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) has an elaborate assign, + * $(D_KEYWORD false) otherwise. + */ +template hasElaborateAssign(T) +{ + static if (is(T E : E[L], size_t L)) + { + enum bool hasElaborateAssign = L > 0 && hasElaborateAssign!E; + } + else static if (is(T == struct)) + { + private enum bool valueAssign = is(typeof({ T.init.opAssign(T()); })); + enum bool hasElaborateAssign = valueAssign || is(typeof({ + T s; + s.opAssign(s); + })); + } + else + { + enum bool hasElaborateAssign = false; + } +} + +pure nothrow @safe @nogc unittest +{ + static assert(!hasElaborateAssign!int); + + static struct S1 + { + void opAssign(S1) + { + } + } + static struct S2 + { + void opAssign(int) + { + } + } + static struct S3 + { + S1 s; + alias s this; + } + static assert(hasElaborateAssign!S1); + static assert(!hasElaborateAssign!(const S1)); + static assert(hasElaborateAssign!(S1[1])); + static assert(!hasElaborateAssign!(S1[0])); + static assert(!hasElaborateAssign!S2); + static assert(hasElaborateAssign!S3); + + static struct S4 + { + void opAssign(S4) + { + } + @disable this(this); + } + static assert(hasElaborateAssign!S4); +} + +/** + * Returns all members of $(D_KEYWORD enum) $(D_PARAM T). + * + * The members of $(D_PARAM T) are typed as $(D_PARAM T), not as a base type + * of the enum. + * + * $(D_PARAM EnumMembers) returns all members of $(D_PARAM T), also if there + * are some duplicates. + * + * Params: + * T = A $(D_KEYWORD enum). + * + * Returns: All members of $(D_PARAM T). + */ +template EnumMembers(T) +if (is(T == enum)) +{ + private template getEnumMembers(Args...) + { + static if (Args.length == 1) + { + enum T getEnumMembers = __traits(getMember, T, Args[0]); + } + else + { + alias getEnumMembers = AliasSeq!(__traits(getMember, T, Args[0]), getEnumMembers!(Args[1 .. $])); + } + } + alias EnumMembers = getEnumMembers!(__traits(allMembers, T)); +} + +/// +pure nothrow @nogc @safe unittest +{ + enum E : int + { + one, + two, + three, + } + static assert([E.one, E.two, E.three] == [ EnumMembers!E ]); +}