Add hasElaborate traits

This commit is contained in:
Eugen Wissner 2017-08-25 14:50:15 +02:00
parent c9a4a2f651
commit 2c064eb05b
11 changed files with 313 additions and 12 deletions

View File

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

View File

@ -14,8 +14,8 @@
*/
module tanya.container.buffer;
import std.traits;
import tanya.memory;
import tanya.meta.trait;
version (unittest)
{

View File

@ -14,7 +14,7 @@
*/
module tanya.container.entry;
import std.traits;
import tanya.meta.trait;
import tanya.typecons;
package struct SEntry(T)

View File

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

View File

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

View File

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

View File

@ -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;
/**

View File

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

View File

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

View File

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

View File

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