Add hasElaborate traits
This commit is contained in:
		| @@ -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). | ||||
|   | ||||
| @@ -14,8 +14,8 @@ | ||||
|  */ | ||||
| module tanya.container.buffer; | ||||
|  | ||||
| import std.traits; | ||||
| import tanya.memory; | ||||
| import tanya.meta.trait; | ||||
|  | ||||
| version (unittest) | ||||
| { | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
|  */ | ||||
| module tanya.container.entry; | ||||
|  | ||||
| import std.traits; | ||||
| import tanya.meta.trait; | ||||
| import tanya.typecons; | ||||
|  | ||||
| package struct SEntry(T) | ||||
|   | ||||
| @@ -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). | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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) | ||||
| { | ||||
|   | ||||
| @@ -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 ]); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user