Add traits for working with UDAs

This commit is contained in:
Eugen Wissner 2017-09-03 00:00:43 +02:00
parent 34b79ad46e
commit d38e33593e
3 changed files with 247 additions and 6 deletions

View File

@ -1589,12 +1589,19 @@ pure nothrow @safe @nogc unittest
template Select(bool cond, T...)
if (T.length == 2)
{
static if (condition)
static if (cond)
{
alias Select = L[0];
alias Select = T[0];
}
else
{
alias Select = L[1];
alias Select = T[1];
}
}
///
pure nothrow @safe @nogc unittest
{
static assert(is(Select!(true, int, float) == int));
static assert(is(Select!(false, int, float) == float));
}

View File

@ -378,7 +378,7 @@ version (TanyaPhobos)
isAssociativeArray,
isBuiltinType,
isAggregateType,
isType,
getUDAs,
isNarrowString,
isSomeString,
mostNegative,
@ -415,7 +415,9 @@ version (TanyaPhobos)
hasElaborateAssign,
EnumMembers,
classInstanceAlignment,
ifTestable;
ifTestable,
isTypeTuple,
isExpressions;
}
else:
@ -968,9 +970,11 @@ pure nothrow @safe @nogc unittest
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a type,
* $(D_KEYWORD false) otherwise.
*/
deprecated("Use isTypeTuple instead")
enum bool isType(alias T) = is(T);
/// Ditto.
deprecated("Use isTypeTuple instead")
enum bool isType(T) = true;
///
@ -1275,6 +1279,79 @@ pure nothrow @safe @nogc unittest
static assert(!isAbstractClass!E);
}
/**
* Determines whether $(D_PARAM Args) contains only types.
*
* Params:
* Args = Alias sequence.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM Args) consists only of types,
* $(D_KEYWORD false) otherwise.
*/
enum bool isTypeTuple(Args...) = allSatisfy!(isType, Args);
///
pure nothrow @safe @nogc unittest
{
static assert(isTypeTuple!(int, uint, Object));
static assert(isTypeTuple!());
static assert(!isTypeTuple!(int, 8, Object));
static assert(!isTypeTuple!(5, 8, 2));
}
/**
* Tells whether $(D_PARAM Args) contains only expressions.
*
* An expression is determined by applying $(D_KEYWORD typeof) to an argument:
*
* ---
* static if (is(typeof(Args[i])))
* {
* // Args[i] is an expression.
* }
* else
* {
* // Args[i] is not an expression.
* }
* ---
*
* Params:
* Args = Alias sequence.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM Args) consists only of expressions,
* $(D_KEYWORD false) otherwise.
*/
template isExpressions(Args...)
{
static if (Args.length == 0)
{
enum bool isExpressions = true;
}
else static if (is(typeof(Args[0]) U))
{
enum bool isExpressions = !is(U == void)
&& isExpressions!(Args[1 .. $]);
}
else
{
enum bool isExpressions = false;
}
}
///
pure nothrow @safe @nogc unittest
{
static assert(isExpressions!(5, 8, 2));
static assert(isExpressions!());
static assert(!isExpressions!(int, uint, Object));
static assert(!isExpressions!(int, 8, Object));
template T(U)
{
}
static assert(!isExpressions!T);
}
/**
* Determines whether $(D_PARAM T) is a final class.
*
@ -1854,7 +1931,6 @@ pure nothrow @safe @nogc unittest
{
}
static assert(isInstanceOf!(T, T!int));
}
/**
@ -2727,3 +2803,126 @@ pure nothrow @safe @nogc unittest
}
static assert(ifTestable!S2);
}
/**
* Returns a compile-time tuple of user-defined attributes (UDA) attached to
* $(D_PARAM symbol).
*
* $(D_PARAM symbol) can be:
*
* $(DL
* $(DT Template)
* $(DD The attribute is matched if it is an instance of the template
* $(D_PARAM attr).)
* $(DT Type)
* $(DD The attribute is matched if it its type is $(D_PARAM attr).)
* $(DT Expression)
* $(DD The attribute is matched if it equals to $(D_PARAM attr).)
* )
*
* If $(D_PARAM attr) isn't given, all user-defined attributes of
* $(D_PARAM symbol) are returned.
*
* Params:
* symbol = A symbol.
* attr = User-defined attribute.
*
* Returns: A tuple of user-defined attributes attached to $(D_PARAM symbol)
* and matching $(D_PARAM attr).
*
* See_Also: $(LINK2 https://dlang.org/spec/attribute.html#uda,
* User Defined Attributes).
*/
template getUDAs(alias symbol, alias attr)
{
private template FindUDA(T...)
{
static if (T.length == 0)
{
alias FindUDA = AliasSeq!();
}
else static if ((isType!attr && is(TypeOf!(T[0]) == attr))
|| (is(typeof(T[0] == attr)) && (T[0] == attr))
|| isInstanceOf!(attr, TypeOf!(T[0])))
{
alias FindUDA = AliasSeq!(T[0], FindUDA!(T[1 .. $]));
}
else
{
alias FindUDA = FindUDA!(T[1 .. $]);
}
}
alias getUDAs = FindUDA!(__traits(getAttributes, symbol));
}
///
alias getUDAs(alias symbol) = AliasSeq!(__traits(getAttributes, symbol));
///
pure nothrow @safe @nogc unittest
{
struct Attr
{
int i;
}
@Attr int a;
static assert(getUDAs!(a, Attr).length == 1);
@Attr(8) int b;
static assert(getUDAs!(b, Attr).length == 1);
static assert(getUDAs!(b, Attr)[0].i == 8);
static assert(getUDAs!(b, Attr(8)).length == 1);
static assert(getUDAs!(b, Attr(7)).length == 0);
@("string", 5) int c;
static assert(getUDAs!(c, "string").length == 1);
static assert(getUDAs!(c, 5).length == 1);
static assert(getUDAs!(c, "String").length == 0);
static assert(getUDAs!(c, 4).length == 0);
struct T(U)
{
enum U s = 7;
U i;
}
@T!int @T!int(8) int d;
static assert(getUDAs!(d, T).length == 2);
static assert(getUDAs!(d, T)[0].s == 7);
static assert(getUDAs!(d, T)[1].i == 8);
@T int e;
static assert(getUDAs!(e, T).length == 0);
}
/**
* Determines whether $(D_PARAM symbol) has user-defined attribute
* $(D_PARAM attr) attached to it.
*
* Params:
* symbol = A symbol.
* attr = User-defined attribute.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM symbol) has user-defined attribute
* $(D_PARAM attr), $(D_KEYWORD false) otherwise.
*
* See_Also: $(LINK2 https://dlang.org/spec/attribute.html#uda,
* User Defined Attributes).
*/
template hasUDA(alias symbol, alias attr)
{
enum bool hasUDA = getUDAs!(symbol, attr).length != 0;
}
///
pure nothrow @safe @nogc unittest
{
struct Attr1
{
}
struct Attr2
{
}
@Attr1 int a;
static assert(hasUDA!(a, Attr1));
static assert(!hasUDA!(a, Attr2));
}

View File

@ -850,3 +850,38 @@ pure nothrow @safe @nogc unittest
alias SharedInoutConstOf = QualifierOf!(shared inout const int);
static assert(is(SharedInoutConstOf!uint == shared inout const uint));
}
/**
* Determines the type of $(D_PARAM T). If $(D_PARAM T) is already a type,
* $(D_PSYMBOL TypeOf) aliases itself to $(D_PARAM T).
*
* $(D_PSYMBOL TypeOf) evaluates to $(D_KEYWORD void) for template arguments.
*
* The symbols that don't have a type and aren't types cannot be used as
* arguments to $(D_PSYMBOL TypeOf).
*
* Params:
* T = Expression, type or template.
*
* Returns: The type of $(D_PARAM T).
*/
alias TypeOf(T) = T;
/// Ditto.
template TypeOf(alias T)
if (isExpressions!T || isTemplate!T)
{
alias TypeOf = typeof(T);
}
///
pure nothrow @safe @nogc unittest
{
struct S(T)
{
}
static assert(is(TypeOf!S == void));
static assert(is(TypeOf!int == int));
static assert(is(TypeOf!true == bool));
static assert(!is(TypeOf!(tanya.meta)));
}