Add metafunctions
This commit is contained in:
parent
e8dd6e3217
commit
9355c54163
208
source/tanya/meta/metafunction.d
Normal file
208
source/tanya/meta/metafunction.d
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This module contains functions that manipulate template type lists as well
|
||||||
|
* as algorithms to perform arbitrary compile-time computations.
|
||||||
|
*
|
||||||
|
* Copyright: Eugene Wissner 2017.
|
||||||
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
|
* Mozilla Public License, v. 2.0).
|
||||||
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
|
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/meta/metafunction.d,
|
||||||
|
* tanya/meta/metafunction.d)
|
||||||
|
*/
|
||||||
|
module tanya.meta.metafunction;
|
||||||
|
|
||||||
|
version (unittest)
|
||||||
|
{
|
||||||
|
import std.traits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an alias for $(D_PARAM T).
|
||||||
|
*
|
||||||
|
* In contrast to the $(D_KEYWORD alias)-keyword $(D_PSYMBOL Alias) can alias
|
||||||
|
* any kind of D symbol that can be used as argument to template alias
|
||||||
|
* parameters.
|
||||||
|
*
|
||||||
|
* $(UL
|
||||||
|
* $(LI Types)
|
||||||
|
* $(LI Local and global names)
|
||||||
|
* $(LI Module names)
|
||||||
|
* $(LI Template names)
|
||||||
|
* $(LI Template instance names)
|
||||||
|
* $(LI Literals)
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* T = A symbol.
|
||||||
|
*
|
||||||
|
* Returns: An alias for $(D_PARAM T).
|
||||||
|
*
|
||||||
|
* See_Also: $(LINK2 https://dlang.org/spec/template.html#aliasparameters,
|
||||||
|
* Template Alias Parameters).
|
||||||
|
*/
|
||||||
|
alias Alias(alias T) = T;
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
alias Alias(T) = T;
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
static assert(is(Alias!int));
|
||||||
|
|
||||||
|
static assert(is(typeof(Alias!5)));
|
||||||
|
static assert(is(typeof(Alias!(() {}))));
|
||||||
|
|
||||||
|
int i;
|
||||||
|
static assert(is(typeof(Alias!i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* Args = List of symbols.
|
||||||
|
*
|
||||||
|
* Returns: An alias for sequence $(D_PARAM Args).
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL Alias).
|
||||||
|
*/
|
||||||
|
alias AliasSeq(Args...) = Args;
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
static assert(is(typeof({ alias T = AliasSeq!(short, 5); })));
|
||||||
|
static assert(is(typeof({ alias T = AliasSeq!(int, short, 5); })));
|
||||||
|
static assert(is(typeof({ alias T = AliasSeq!(() {}, short, 5); })));
|
||||||
|
static assert(is(typeof({ alias T = AliasSeq!(); })));
|
||||||
|
|
||||||
|
static assert(AliasSeq!().length == 0);
|
||||||
|
static assert(AliasSeq!(int, short, 5).length == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether all the items of $(D_PARAM L) satisfy the condition
|
||||||
|
* $(D_PARAM F).
|
||||||
|
*
|
||||||
|
* $(D_PARAM F) is a template that accepts one parameter and returns a boolean,
|
||||||
|
* so $(D_INLINECODE F!([0]) && F!([1])) and so on, can be called.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* F = Template predicate.
|
||||||
|
* L = List of items to test.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD true) if all the items of $(D_PARAM L) satisfy
|
||||||
|
* $(D_PARAM F), $(D_KEYWORD false) otherwise.
|
||||||
|
*/
|
||||||
|
template allSatisfy(alias F, L...)
|
||||||
|
{
|
||||||
|
static if (L.length == 0)
|
||||||
|
{
|
||||||
|
enum bool allSatisfy = true;
|
||||||
|
}
|
||||||
|
else static if (F!(L[0]))
|
||||||
|
{
|
||||||
|
enum bool allSatisfy = allSatisfy!(F, L[1 .. $]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum bool allSatisfy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
static assert(allSatisfy!(isSigned, int, short, byte, long));
|
||||||
|
static assert(!allSatisfy!(isUnsigned, uint, ushort, float, ulong));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether any of the items of $(D_PARAM L) satisfy the condition
|
||||||
|
* $(D_PARAM F).
|
||||||
|
*
|
||||||
|
* $(D_PARAM F) is a template that accepts one parameter and returns a boolean,
|
||||||
|
* so $(D_INLINECODE F!([0]) && F!([1])) and so on, can be called.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* F = Template predicate.
|
||||||
|
* L = List of items to test.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD true) if any of the items of $(D_PARAM L) satisfy
|
||||||
|
* $(D_PARAM F), $(D_KEYWORD false) otherwise.
|
||||||
|
*/
|
||||||
|
template anySatisfy(alias F, L...)
|
||||||
|
{
|
||||||
|
static if (L.length == 0)
|
||||||
|
{
|
||||||
|
enum bool anySatisfy = false;
|
||||||
|
}
|
||||||
|
else static if (F!(L[0]))
|
||||||
|
{
|
||||||
|
enum bool anySatisfy = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum bool anySatisfy = anySatisfy!(F, L[1 .. $]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
static assert(anySatisfy!(isSigned, int, short, byte, long));
|
||||||
|
static assert(anySatisfy!(isUnsigned, uint, ushort, float, ulong));
|
||||||
|
static assert(!anySatisfy!(isSigned, uint, ushort, ulong));
|
||||||
|
}
|
||||||
|
|
||||||
|
private template indexOf(ptrdiff_t i, Args...)
|
||||||
|
if (Args.length > 0)
|
||||||
|
{
|
||||||
|
static if (Args.length == 1)
|
||||||
|
{
|
||||||
|
enum ptrdiff_t indexOf = -1;
|
||||||
|
}
|
||||||
|
else static if (is(Args[0] == Args[1])
|
||||||
|
|| (is(typeof(Args[0] == Args[1])) && (Args[0] == Args[1])))
|
||||||
|
{
|
||||||
|
enum ptrdiff_t indexOf = i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum ptrdiff_t indexOf = indexOf!(i + 1,
|
||||||
|
AliasSeq!(Args[0], Args[2 .. $]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the first occurrence of $(D_PARAM T) in $(D_PARAM L).
|
||||||
|
* `-1` is returned if $(D_PARAM T) is not found.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* T = The type to search for.
|
||||||
|
* L = Type list.
|
||||||
|
*
|
||||||
|
* Returns: The index of the first occurence of $(D_PARAM T) in $(D_PARAM L).
|
||||||
|
*/
|
||||||
|
template staticIndexOf(T, L...)
|
||||||
|
{
|
||||||
|
enum ptrdiff_t staticIndexOf = indexOf!(0, AliasSeq!(T, L));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
template staticIndexOf(alias T, L...)
|
||||||
|
{
|
||||||
|
enum ptrdiff_t staticIndexOf = indexOf!(0, AliasSeq!(T, L));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
static assert(staticIndexOf!(int) == -1);
|
||||||
|
static assert(staticIndexOf!(int, int) == 0);
|
||||||
|
static assert(staticIndexOf!(int, float, double, int, real) == 2);
|
||||||
|
static assert(staticIndexOf!(3, () {}, uint, 5, 3) == 3);
|
||||||
|
}
|
@ -14,5 +14,6 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.meta;
|
module tanya.meta;
|
||||||
|
|
||||||
|
public import tanya.meta.metafunction;
|
||||||
public import tanya.meta.traits;
|
public import tanya.meta.traits;
|
||||||
public import tanya.meta.transform;
|
public import tanya.meta.transform;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.meta.traits;
|
module tanya.meta.traits;
|
||||||
|
|
||||||
|
import tanya.meta.metafunction;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -966,14 +967,13 @@ pure nothrow @safe @nogc unittest
|
|||||||
* Abstract class is a class marked as such or a class that has any abstract
|
* Abstract class is a class marked as such or a class that has any abstract
|
||||||
* methods or doesn't implement all methods of abstract base classes.
|
* methods or doesn't implement all methods of abstract base classes.
|
||||||
*
|
*
|
||||||
* For all non-classes $(D_INLINECODE isAbstractClass!T) evaluates to
|
|
||||||
* $(D_KEYWORD false).
|
|
||||||
*
|
|
||||||
* Params:
|
* Params:
|
||||||
* T = A type.
|
* T = A type.
|
||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is an abstract class,
|
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is an abstract class,
|
||||||
* $(D_KEYWORD false) otherwise.
|
* $(D_KEYWORD false) otherwise.
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL isAbstractFunction).
|
||||||
*/
|
*/
|
||||||
enum bool isAbstractClass(T) = __traits(isAbstractClass, T);
|
enum bool isAbstractClass(T) = __traits(isAbstractClass, T);
|
||||||
|
|
||||||
@ -1004,20 +1004,18 @@ pure nothrow @safe @nogc unittest
|
|||||||
static assert(isAbstractClass!C);
|
static assert(isAbstractClass!C);
|
||||||
static assert(isAbstractClass!D);
|
static assert(isAbstractClass!D);
|
||||||
static assert(!isAbstractClass!E);
|
static assert(!isAbstractClass!E);
|
||||||
static assert(!isAbstractClass!int);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether $(D_PARAM T) is a final class.
|
* Determines whether $(D_PARAM T) is a final class.
|
||||||
*
|
*
|
||||||
* For all non-classes $(D_INLINECODE isFinalClass!T) evaluates to
|
|
||||||
* $(D_KEYWORD false).
|
|
||||||
*
|
|
||||||
* Params:
|
* Params:
|
||||||
* T = A type.
|
* T = A type.
|
||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a final class,
|
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a final class,
|
||||||
* $(D_KEYWORD false) otherwise.
|
* $(D_KEYWORD false) otherwise.
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL isFinalFunction).
|
||||||
*/
|
*/
|
||||||
enum bool isFinalClass(T) = __traits(isFinalClass, T);
|
enum bool isFinalClass(T) = __traits(isFinalClass, T);
|
||||||
|
|
||||||
@ -1038,20 +1036,15 @@ pure nothrow @safe @nogc unittest
|
|||||||
/**
|
/**
|
||||||
* Determines whether $(D_PARAM T) is an abstract method.
|
* Determines whether $(D_PARAM T) is an abstract method.
|
||||||
*
|
*
|
||||||
* For all non-methods $(D_INLINECODE isAbstractFunction!T) evaluates to
|
|
||||||
* $(D_KEYWORD false).
|
|
||||||
*
|
|
||||||
* Params:
|
* Params:
|
||||||
* F = A symbol.
|
* F = A symbol.
|
||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD true) if $(D_PARAM F) is an abstract method,
|
* Returns: $(D_KEYWORD true) if $(D_PARAM F) is an abstract method,
|
||||||
* $(D_KEYWORD false) otherwise.
|
* $(D_KEYWORD false) otherwise.
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL isAbstractClass).
|
||||||
*/
|
*/
|
||||||
template isAbstractFunction(F...)
|
enum bool isAbstractFunction(alias F) = __traits(isAbstractFunction, F);
|
||||||
if (F.length == 1)
|
|
||||||
{
|
|
||||||
enum bool isAbstractFunction = __traits(isAbstractFunction, F[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
pure nothrow @safe @nogc unittest
|
||||||
@ -1075,26 +1068,20 @@ pure nothrow @safe @nogc unittest
|
|||||||
static assert(!isAbstractFunction!(A.func));
|
static assert(!isAbstractFunction!(A.func));
|
||||||
static assert(isAbstractFunction!(B.func));
|
static assert(isAbstractFunction!(B.func));
|
||||||
static assert(!isAbstractFunction!(C.func));
|
static assert(!isAbstractFunction!(C.func));
|
||||||
static assert(!isAbstractFunction!int);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether $(D_PARAM T) is a final method.
|
* Determines whether $(D_PARAM T) is a final method.
|
||||||
*
|
*
|
||||||
* For all non-methods $(D_INLINECODE isFinalFunction!T) evaluates to
|
|
||||||
* $(D_KEYWORD false).
|
|
||||||
*
|
|
||||||
* Params:
|
* Params:
|
||||||
* F = A symbol.
|
* F = A symbol.
|
||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD true) if $(D_PARAM F) is a final method,
|
* Returns: $(D_KEYWORD true) if $(D_PARAM F) is a final method,
|
||||||
* $(D_KEYWORD false) otherwise.
|
* $(D_KEYWORD false) otherwise.
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL isFinalClass).
|
||||||
*/
|
*/
|
||||||
template isFinalFunction(F...)
|
enum bool isFinalFunction(alias F) = __traits(isFinalFunction, F);
|
||||||
if (F.length == 1)
|
|
||||||
{
|
|
||||||
enum bool isFinalFunction = __traits(isFinalFunction, F[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
pure nothrow @safe @nogc unittest
|
||||||
@ -1111,7 +1098,6 @@ pure nothrow @safe @nogc unittest
|
|||||||
|
|
||||||
static assert(isFinalFunction!(A.finalFunc));
|
static assert(isFinalFunction!(A.finalFunc));
|
||||||
static assert(!isFinalFunction!(A.virtualFunc));
|
static assert(!isFinalFunction!(A.virtualFunc));
|
||||||
static assert(!isFinalFunction!int);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1252,7 +1238,7 @@ template isFunction(F...)
|
|||||||
if (F.length == 1)
|
if (F.length == 1)
|
||||||
{
|
{
|
||||||
static if (is(F[0] == function)
|
static if (is(F[0] == function)
|
||||||
|| is(typeof(&F[0]) U == delegate)
|
|| is(typeof(&F[0]) T == delegate)
|
||||||
|| (is(typeof(&F[0]) T : T*) && is(T == function)))
|
|| (is(typeof(&F[0]) T : T*) && is(T == function)))
|
||||||
{
|
{
|
||||||
enum bool isFunction = true;
|
enum bool isFunction = true;
|
||||||
@ -1348,7 +1334,8 @@ pure nothrow @safe @nogc unittest
|
|||||||
template isCallable(F...)
|
template isCallable(F...)
|
||||||
if (F.length == 1)
|
if (F.length == 1)
|
||||||
{
|
{
|
||||||
static if (isSomeFunction!F || (is(typeof(F[0].opCall) U) && isFunction!U))
|
static if (isSomeFunction!F
|
||||||
|
|| (is(typeof(F[0].opCall)) && isFunction!(F[0].opCall)))
|
||||||
{
|
{
|
||||||
enum bool isCallable = true;
|
enum bool isCallable = true;
|
||||||
}
|
}
|
||||||
@ -1384,6 +1371,20 @@ pure nothrow @safe @nogc unittest
|
|||||||
static assert(!isCallable!I);
|
static assert(!isCallable!I);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
struct S
|
||||||
|
{
|
||||||
|
@property int opCall()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S s;
|
||||||
|
static assert(isCallable!S);
|
||||||
|
static assert(isCallable!s);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* T = Aggregate type.
|
* T = Aggregate type.
|
||||||
@ -1403,8 +1404,304 @@ pure nothrow @safe @nogc unittest
|
|||||||
void member2()
|
void member2()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
static int member3;
|
||||||
|
static void member4()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static assert(hasMember!(S, "member1"));
|
static assert(hasMember!(S, "member1"));
|
||||||
static assert(hasMember!(S, "member2"));
|
static assert(hasMember!(S, "member2"));
|
||||||
static assert(!hasMember!(S, "member3"));
|
static assert(hasMember!(S, "member3"));
|
||||||
|
static assert(hasMember!(S, "member4"));
|
||||||
|
static assert(!hasMember!(S, "member6"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* T = Aggregate type.
|
||||||
|
* member = Symbol name.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD true) if $(D_PARAM member) is a static method of
|
||||||
|
* $(D_PARAM T), $(D_KEYWORD false) otherwise.
|
||||||
|
*/
|
||||||
|
template hasStaticMember(T, string member)
|
||||||
|
{
|
||||||
|
static if (hasMember!(T, member))
|
||||||
|
{
|
||||||
|
alias Member = Alias!(__traits(getMember, T, member));
|
||||||
|
|
||||||
|
static if (__traits(isStaticFunction, Member)
|
||||||
|
|| (!isFunction!Member && is(typeof(&Member))))
|
||||||
|
{
|
||||||
|
enum bool hasStaticMember = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum bool hasStaticMember = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum bool hasStaticMember = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
struct S
|
||||||
|
{
|
||||||
|
int member1;
|
||||||
|
void member2()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static int member3;
|
||||||
|
static void member4()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static void function() member5;
|
||||||
|
}
|
||||||
|
static assert(!hasStaticMember!(S, "member1"));
|
||||||
|
static assert(!hasStaticMember!(S, "member2"));
|
||||||
|
static assert(hasStaticMember!(S, "member3"));
|
||||||
|
static assert(hasStaticMember!(S, "member4"));
|
||||||
|
static assert(hasStaticMember!(S, "member5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether $(D_PARAM T) is mutable, i.e. has one of the following
|
||||||
|
* qualifiers or a combination of them:
|
||||||
|
*
|
||||||
|
* $(UL
|
||||||
|
* $(LI $(D_KEYWORD const))
|
||||||
|
* $(LI $(D_KEYWORD immutable))
|
||||||
|
* $(LI $(D_KEYWORD const))
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* T = A type.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is mutable,
|
||||||
|
* $(D_KEYWORD false) otherwise.
|
||||||
|
*/
|
||||||
|
template isMutable(T)
|
||||||
|
{
|
||||||
|
static if (is(T U == const U)
|
||||||
|
|| is(T U == inout U)
|
||||||
|
|| is(T U == inout const U)
|
||||||
|
|| is(T U == immutable U)
|
||||||
|
|| is(T U == shared const U)
|
||||||
|
|| is(T U == shared inout U)
|
||||||
|
|| is(T U == shared inout const U))
|
||||||
|
{
|
||||||
|
enum bool isMutable = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum bool isMutable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
struct S
|
||||||
|
{
|
||||||
|
void method()
|
||||||
|
{
|
||||||
|
static assert(isMutable!(typeof(this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void method() inout
|
||||||
|
{
|
||||||
|
static assert(!isMutable!(typeof(this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void immMethod() const
|
||||||
|
{
|
||||||
|
static assert(!isMutable!(typeof(this)));
|
||||||
|
}
|
||||||
|
void immMethod() immutable
|
||||||
|
{
|
||||||
|
static assert(!isMutable!(typeof(this)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POD (Plain Old Data) is a $(D_KEYWORD struct) without constructors,
|
||||||
|
* destructors and member functions.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* T = A type.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a POD type,
|
||||||
|
* $(D_KEYWORD false) otherwise.
|
||||||
|
*/
|
||||||
|
enum bool isPOD(T) = __traits(isPOD, T);
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
struct S1
|
||||||
|
{
|
||||||
|
void method()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(!isPOD!S1);
|
||||||
|
|
||||||
|
struct S2
|
||||||
|
{
|
||||||
|
void function() val; // Function pointer, not a member function.
|
||||||
|
}
|
||||||
|
static assert(isPOD!S2);
|
||||||
|
|
||||||
|
struct S3
|
||||||
|
{
|
||||||
|
this(this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(!isPOD!S3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* T = $(D_KEYWORD class), $(D_KEYWORD struct) or $(D_KEYWORD union) type.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD true) if the argument is a nested type which internally
|
||||||
|
* stores a context pointer, $(D_KEYWORD false) otherwise.
|
||||||
|
*/
|
||||||
|
template isNested(T)
|
||||||
|
if (is(T == class) || is(T == struct) || is(T == union))
|
||||||
|
{
|
||||||
|
enum bool isNested = __traits(isNested, T);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe unittest
|
||||||
|
{
|
||||||
|
static struct S
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static assert(!isNested!S);
|
||||||
|
|
||||||
|
class C
|
||||||
|
{
|
||||||
|
void method()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(isNested!C);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* T = A function.
|
||||||
|
*
|
||||||
|
* Returns $(D_KEYWORD true) if the $(D_PARAM T) is a nested function,
|
||||||
|
* $(D_KEYWORD false) otherwise.
|
||||||
|
*/
|
||||||
|
enum bool isNestedFunction(alias F) = __traits(isNested, F);
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
void func()
|
||||||
|
{
|
||||||
|
void nestedFunc()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static assert(isNestedFunction!nestedFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* F = A function.
|
||||||
|
*
|
||||||
|
* Returns: Type of the function $(D_PARAM F).
|
||||||
|
*/
|
||||||
|
template FunctionTypeOf(F...)
|
||||||
|
if (F.length == 1 && isCallable!F)
|
||||||
|
{
|
||||||
|
static if ((is(typeof(F[0]) T : T*) && is(T == function))
|
||||||
|
|| (is(F[0] T : T*) && is(T == function))
|
||||||
|
|| is(F[0] T == delegate)
|
||||||
|
|| is(typeof(F[0]) T == delegate)
|
||||||
|
|| is(F[0] T == function)
|
||||||
|
|| is(typeof(&F[0]) T == delegate)
|
||||||
|
|| (is(typeof(&F[0]) T : T*) && is(T == function)))
|
||||||
|
{
|
||||||
|
alias FunctionTypeOf = T;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alias FunctionTypeOf = FunctionTypeOf!(F[0].opCall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
static assert(is(FunctionTypeOf!(void function()) == function));
|
||||||
|
static assert(is(FunctionTypeOf!(() {}) == function));
|
||||||
|
}
|
||||||
|
|
||||||
|
private pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
static assert(is(FunctionTypeOf!(void delegate()) == function));
|
||||||
|
|
||||||
|
static void staticFunc()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
auto functionPointer = &staticFunc;
|
||||||
|
static assert(is(FunctionTypeOf!staticFunc == function));
|
||||||
|
static assert(is(FunctionTypeOf!functionPointer == function));
|
||||||
|
|
||||||
|
void func()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
auto dg = &func;
|
||||||
|
static assert(is(FunctionTypeOf!func == function));
|
||||||
|
static assert(is(FunctionTypeOf!dg == function));
|
||||||
|
|
||||||
|
interface I
|
||||||
|
{
|
||||||
|
@property int prop();
|
||||||
|
}
|
||||||
|
static assert(is(FunctionTypeOf!(I.prop) == function));
|
||||||
|
|
||||||
|
struct S
|
||||||
|
{
|
||||||
|
void opCall()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class C
|
||||||
|
{
|
||||||
|
static void opCall()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S s;
|
||||||
|
|
||||||
|
static assert(is(FunctionTypeOf!s == function));
|
||||||
|
static assert(is(FunctionTypeOf!C == function));
|
||||||
|
static assert(is(FunctionTypeOf!S == function));
|
||||||
|
}
|
||||||
|
|
||||||
|
private pure nothrow @safe @nogc unittest
|
||||||
|
{
|
||||||
|
struct S2
|
||||||
|
{
|
||||||
|
@property int opCall()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S2 s2;
|
||||||
|
static assert(is(FunctionTypeOf!S2 == function));
|
||||||
|
static assert(is(FunctionTypeOf!s2 == function));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user