Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

6405 lines (5633 sloc) 201.091 kb
// Written in the D programming language.
/**
* Templates which extract information about types and symbols at compile time.
*
* $(SCRIPT inhibitQuickIndex = 1;)
*
* $(DIVC quickindex,
* $(BOOKTABLE ,
* $(TR $(TH Category) $(TH Templates))
* $(TR $(TD Symbol Name _traits) $(TD
* $(LREF fullyQualifiedName)
* $(LREF moduleName)
* $(LREF packageName)
* ))
* $(TR $(TD Function _traits) $(TD
* $(LREF arity)
* $(LREF functionAttributes)
* $(LREF functionLinkage)
* $(LREF FunctionTypeOf)
* $(LREF isSafe)
* $(LREF isUnsafe)
* $(LREF ParameterDefaults)
* $(LREF ParameterIdentifierTuple)
* $(LREF ParameterStorageClassTuple)
* $(LREF Parameters)
* $(LREF ReturnType)
* $(LREF SetFunctionAttributes)
* $(LREF variadicFunctionStyle)
* ))
* $(TR $(TD Aggregate Type _traits) $(TD
* $(LREF BaseClassesTuple)
* $(LREF BaseTypeTuple)
* $(LREF classInstanceAlignment)
* $(LREF EnumMembers)
* $(LREF FieldNameTuple)
* $(LREF Fields)
* $(LREF hasAliasing)
* $(LREF hasElaborateAssign)
* $(LREF hasElaborateCopyConstructor)
* $(LREF hasElaborateDestructor)
* $(LREF hasIndirections)
* $(LREF hasMember)
* $(LREF hasNested)
* $(LREF hasUnsharedAliasing)
* $(LREF InterfacesTuple)
* $(LREF isNested)
* $(LREF MemberFunctionsTuple)
* $(LREF RepresentationTypeTuple)
* $(LREF TemplateArgsOf)
* $(LREF TemplateOf)
* $(LREF TransitiveBaseTypeTuple)
* ))
* $(TR $(TD Type Conversion) $(TD
* $(LREF CommonType)
* $(LREF ImplicitConversionTargets)
* $(LREF isAssignable)
* $(LREF isCovariantWith)
* $(LREF isImplicitlyConvertible)
* ))
* <!--$(TR $(TD SomethingTypeOf) $(TD
* $(LREF BooleanTypeOf)
* $(LREF IntegralTypeOf)
* $(LREF FloatingPointTypeOf)
* $(LREF NumericTypeOf)
* $(LREF UnsignedTypeOf)
* $(LREF SignedTypeOf)
* $(LREF CharTypeOf)
* $(LREF StaticArrayTypeOf)
* $(LREF DynamicArrayTypeOf)
* $(LREF ArrayTypeOf)
* $(LREF StringTypeOf)
* $(LREF AssocArrayTypeOf)
* $(LREF BuiltinTypeOf)
* ))-->
* $(TR $(TD Categories of types) $(TD
* $(LREF isAggregateType)
* $(LREF isArray)
* $(LREF isAssociativeArray)
* $(LREF isBasicType)
* $(LREF isBoolean)
* $(LREF isBuiltinType)
* $(LREF isDynamicArray)
* $(LREF isFloatingPoint)
* $(LREF isIntegral)
* $(LREF isNarrowString)
* $(LREF isNumeric)
* $(LREF isPointer)
* $(LREF isScalarType)
* $(LREF isSigned)
* $(LREF isSomeChar)
* $(LREF isSomeString)
* $(LREF isStaticArray)
* $(LREF isUnsigned)
* ))
* $(TR $(TD Type behaviours) $(TD
* $(LREF isAbstractClass)
* $(LREF isAbstractFunction)
* $(LREF isCallable)
* $(LREF isDelegate)
* $(LREF isExpressions)
* $(LREF isFinalClass)
* $(LREF isFinalFunction)
* $(LREF isFunctionPointer)
* $(LREF isInstanceOf)
* $(LREF isIterable)
* $(LREF isMutable)
* $(LREF isSomeFunction)
* $(LREF isTypeTuple)
* ))
* $(TR $(TD General Types) $(TD
* $(LREF ForeachType)
* $(LREF KeyType)
* $(LREF Largest)
* $(LREF mostNegative)
* $(LREF OriginalType)
* $(LREF PointerTarget)
* $(LREF Signed)
* $(LREF Unqual)
* $(LREF Unsigned)
* $(LREF ValueType)
* ))
* $(TR $(TD Misc) $(TD
* $(LREF mangledName)
* $(LREF Select)
* $(LREF select)
* ))
* )
* )
*
* Macros:
* WIKI = Phobos/StdTraits
*
* Copyright: Copyright Digital Mars 2005 - 2009.
* License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: $(WEB digitalmars.com, Walter Bright),
* Tomasz Stachowiak ($(D isExpressions)),
* $(WEB erdani.org, Andrei Alexandrescu),
* Shin Fujishiro,
* $(WEB octarineparrot.com, Robert Clipsham),
* $(WEB klickverbot.at, David Nadlinger),
* Kenji Hara,
* Shoichi Kato
* Source: $(PHOBOSSRC std/_traits.d)
*/
/* Copyright Digital Mars 2005 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module std.traits;
import std.typetuple;
///////////////////////////////////////////////////////////////////////////////
// Functions
///////////////////////////////////////////////////////////////////////////////
// Petit demangler
// (this or similar thing will eventually go to std.demangle if necessary
// ctfe stuffs are available)
private
{
struct Demangle(T)
{
T value; // extracted information
string rest;
}
/* Demangles mstr as the storage class part of Argument. */
Demangle!uint demangleParameterStorageClass(string mstr)
{
uint pstc = 0; // parameter storage class
// Argument --> Argument2 | M Argument2
if (mstr.length > 0 && mstr[0] == 'M')
{
pstc |= ParameterStorageClass.scope_;
mstr = mstr[1 .. $];
}
// Argument2 --> Type | J Type | K Type | L Type
ParameterStorageClass stc2;
switch (mstr.length ? mstr[0] : char.init)
{
case 'J': stc2 = ParameterStorageClass.out_; break;
case 'K': stc2 = ParameterStorageClass.ref_; break;
case 'L': stc2 = ParameterStorageClass.lazy_; break;
case 'N': if (mstr.length >= 2 && mstr[1] == 'k')
stc2 = ParameterStorageClass.return_;
break;
default : break;
}
if (stc2 != ParameterStorageClass.init)
{
pstc |= stc2;
mstr = mstr[1 .. $];
if (stc2 & ParameterStorageClass.return_)
mstr = mstr[1 .. $];
}
return Demangle!uint(pstc, mstr);
}
/* Demangles mstr as FuncAttrs. */
Demangle!uint demangleFunctionAttributes(string mstr)
{
enum LOOKUP_ATTRIBUTE =
[
'a': FunctionAttribute.pure_,
'b': FunctionAttribute.nothrow_,
'c': FunctionAttribute.ref_,
'd': FunctionAttribute.property,
'e': FunctionAttribute.trusted,
'f': FunctionAttribute.safe,
'i': FunctionAttribute.nogc,
'j': FunctionAttribute.return_
];
uint atts = 0;
// FuncAttrs --> FuncAttr | FuncAttr FuncAttrs
// FuncAttr --> empty | Na | Nb | Nc | Nd | Ne | Nf | Ni | Nj
// except 'Ng' == inout, because it is a qualifier of function type
while (mstr.length >= 2 && mstr[0] == 'N' && mstr[1] != 'g' && mstr[1] != 'k')
{
if (FunctionAttribute att = LOOKUP_ATTRIBUTE[ mstr[1] ])
{
atts |= att;
mstr = mstr[2 .. $];
}
else assert(0);
}
return Demangle!uint(atts, mstr);
}
static if (is(ucent))
{
alias CentTypeList = TypeTuple!(cent, ucent);
alias SignedCentTypeList = TypeTuple!(cent);
alias UnsignedCentTypeList = TypeTuple!(ucent);
}
else
{
alias CentTypeList = TypeTuple!();
alias SignedCentTypeList = TypeTuple!();
alias UnsignedCentTypeList = TypeTuple!();
}
alias IntegralTypeList = TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, CentTypeList);
alias SignedIntTypeList = TypeTuple!(byte, short, int, long, SignedCentTypeList);
alias UnsignedIntTypeList = TypeTuple!(ubyte, ushort, uint, ulong, UnsignedCentTypeList);
alias FloatingPointTypeList = TypeTuple!(float, double, real);
alias ImaginaryTypeList = TypeTuple!(ifloat, idouble, ireal);
alias ComplexTypeList = TypeTuple!(cfloat, cdouble, creal);
alias NumericTypeList = TypeTuple!(IntegralTypeList, FloatingPointTypeList);
alias CharTypeList = TypeTuple!(char, wchar, dchar);
}
package
{
// Add specific qualifier to the given type T
template MutableOf(T) { alias MutableOf = T ; }
template InoutOf(T) { alias InoutOf = inout(T) ; }
template ConstOf(T) { alias ConstOf = const(T) ; }
template SharedOf(T) { alias SharedOf = shared(T) ; }
template SharedInoutOf(T) { alias SharedInoutOf = shared(inout(T)); }
template SharedConstOf(T) { alias SharedConstOf = shared(const(T)); }
template ImmutableOf(T) { alias ImmutableOf = immutable(T) ; }
unittest
{
static assert(is( MutableOf!int == int));
static assert(is( InoutOf!int == inout int));
static assert(is( ConstOf!int == const int));
static assert(is( SharedOf!int == shared int));
static assert(is(SharedInoutOf!int == shared inout int));
static assert(is(SharedConstOf!int == shared const int));
static assert(is( ImmutableOf!int == immutable int));
}
// Get qualifier template from the given type T
template QualifierOf(T)
{
static if (is(T == shared(const U), U)) alias QualifierOf = SharedConstOf;
else static if (is(T == const U , U)) alias QualifierOf = ConstOf;
else static if (is(T == shared(inout U), U)) alias QualifierOf = SharedInoutOf;
else static if (is(T == inout U , U)) alias QualifierOf = InoutOf;
else static if (is(T == immutable U , U)) alias QualifierOf = ImmutableOf;
else static if (is(T == shared U , U)) alias QualifierOf = SharedOf;
else alias QualifierOf = MutableOf;
}
unittest
{
alias Qual1 = QualifierOf!( int); static assert(is(Qual1!long == long));
alias Qual2 = QualifierOf!( inout int); static assert(is(Qual2!long == inout long));
alias Qual3 = QualifierOf!( const int); static assert(is(Qual3!long == const long));
alias Qual4 = QualifierOf!(shared int); static assert(is(Qual4!long == shared long));
alias Qual5 = QualifierOf!(shared inout int); static assert(is(Qual5!long == shared inout long));
alias Qual6 = QualifierOf!(shared const int); static assert(is(Qual6!long == shared const long));
alias Qual7 = QualifierOf!( immutable int); static assert(is(Qual7!long == immutable long));
}
}
version(unittest)
{
alias TypeQualifierList = TypeTuple!(MutableOf, ConstOf, SharedOf, SharedConstOf, ImmutableOf);
struct SubTypeOf(T)
{
T val;
alias val this;
}
}
private alias parentOf(alias sym) = Identity!(__traits(parent, sym));
private alias parentOf(alias sym : T!Args, alias T, Args...) = Identity!(__traits(parent, T));
/**
* Get the full package name for the given symbol.
*/
template packageName(alias T)
{
import std.algorithm : startsWith;
static if (__traits(compiles, parentOf!T))
enum parent = packageName!(parentOf!T);
else
enum string parent = null;
static if (T.stringof.startsWith("package "))
enum packageName = (parent.length ? parent ~ '.' : "") ~ T.stringof[8 .. $];
else static if (parent)
enum packageName = parent;
else
static assert(false, T.stringof ~ " has no parent");
}
///
unittest
{
import std.traits;
static assert(packageName!packageName == "std");
}
unittest
{
import std.array;
// Commented out because of dmd @@@BUG8922@@@
// static assert(packageName!std == "std"); // this package (currently: "std.std")
static assert(packageName!(std.traits) == "std"); // this module
static assert(packageName!packageName == "std"); // symbol in this module
static assert(packageName!(std.array) == "std"); // other module from same package
import core.sync.barrier; // local import
static assert(packageName!core == "core");
static assert(packageName!(core.sync) == "core.sync");
static assert(packageName!Barrier == "core.sync");
struct X12287(T) { T i; }
static assert(packageName!(X12287!int.i) == "std");
}
version (none) version(unittest) //Please uncomment me when changing packageName to test global imports
{
import core.sync.barrier; // global import
static assert(packageName!core == "core");
static assert(packageName!(core.sync) == "core.sync");
static assert(packageName!Barrier == "core.sync");
}
/**
* Get the module name (including package) for the given symbol.
*/
template moduleName(alias T)
{
import std.algorithm : startsWith;
static assert(!T.stringof.startsWith("package "), "cannot get the module name for a package");
static if (T.stringof.startsWith("module "))
{
static if (__traits(compiles, packageName!T))
enum packagePrefix = packageName!T ~ '.';
else
enum packagePrefix = "";
enum moduleName = packagePrefix ~ T.stringof[7..$];
}
else
alias moduleName = moduleName!(parentOf!T); // If you use enum, it will cause compiler ICE
}
///
unittest
{
import std.traits;
static assert(moduleName!moduleName == "std.traits");
}
unittest
{
import std.array;
static assert(!__traits(compiles, moduleName!std));
static assert(moduleName!(std.traits) == "std.traits"); // this module
static assert(moduleName!moduleName == "std.traits"); // symbol in this module
static assert(moduleName!(std.array) == "std.array"); // other module
static assert(moduleName!(std.array.array) == "std.array"); // symbol in other module
import core.sync.barrier; // local import
static assert(!__traits(compiles, moduleName!(core.sync)));
static assert(moduleName!(core.sync.barrier) == "core.sync.barrier");
static assert(moduleName!Barrier == "core.sync.barrier");
struct X12287(T) { T i; }
static assert(moduleName!(X12287!int.i) == "std.traits");
}
version (none) version(unittest) //Please uncomment me when changing moduleName to test global imports
{
import core.sync.barrier; // global import
static assert(!__traits(compiles, moduleName!(core.sync)));
static assert(moduleName!(core.sync.barrier) == "core.sync.barrier");
static assert(moduleName!Barrier == "core.sync.barrier");
}
/***
* Get the fully qualified name of a type or a symbol. Can act as an intelligent type/symbol to string converter.
Example:
-----------------
module myModule;
struct MyStruct {}
static assert(fullyQualifiedName!(const MyStruct[]) == "const(myModule.MyStruct[])");
-----------------
*/
template fullyQualifiedName(T...)
if (T.length == 1)
{
static if (is(T))
enum fullyQualifiedName = fqnType!(T[0], false, false, false, false);
else
enum fullyQualifiedName = fqnSym!(T[0]);
}
///
unittest
{
static assert(fullyQualifiedName!fullyQualifiedName == "std.traits.fullyQualifiedName");
}
version(unittest)
{
// Used for both fqnType and fqnSym unittests
private struct QualifiedNameTests
{
struct Inner
{
}
ref const(Inner[string]) func( ref Inner var1, lazy scope string var2 );
ref const(Inner[string]) retfunc( return ref Inner var1 );
Inner inoutFunc(inout Inner) inout;
shared(const(Inner[string])[]) data;
const Inner delegate(double, string) @safe nothrow deleg;
inout(int) delegate(inout int) inout inoutDeleg;
Inner function(out double, string) funcPtr;
extern(C) Inner function(double, string) cFuncPtr;
extern(C) void cVarArg(int, ...);
void dVarArg(...);
void dVarArg2(int, ...);
void typesafeVarArg(int[] ...);
Inner[] array;
Inner[16] sarray;
Inner[Inner] aarray;
const(Inner[const(Inner)]) qualAarray;
shared(immutable(Inner) delegate(ref double, scope string) const shared @trusted nothrow) attrDeleg;
struct Data(T) { int x; }
void tfunc(T...)(T args) {}
template Inst(alias A) { int x; }
class Test12309(T, int x, string s) {}
}
private enum QualifiedEnum
{
a = 42
}
}
private template fqnSym(alias T : X!A, alias X, A...)
{
template fqnTuple(T...)
{
static if (T.length == 0)
enum fqnTuple = "";
else static if (T.length == 1)
{
static if (isExpressionTuple!T)
enum fqnTuple = T[0].stringof;
else
enum fqnTuple = fullyQualifiedName!(T[0]);
}
else
enum fqnTuple = fqnTuple!(T[0]) ~ ", " ~ fqnTuple!(T[1 .. $]);
}
enum fqnSym =
fqnSym!(__traits(parent, X)) ~
'.' ~ __traits(identifier, X) ~ "!(" ~ fqnTuple!A ~ ")";
}
private template fqnSym(alias T)
{
static if (__traits(compiles, __traits(parent, T)))
enum parentPrefix = fqnSym!(__traits(parent, T)) ~ '.';
else
enum parentPrefix = null;
static string adjustIdent(string s)
{
import std.algorithm : skipOver, findSplit;
if (s.skipOver("package ") || s.skipOver("module "))
return s;
return s.findSplit("(")[0];
}
enum fqnSym = parentPrefix ~ adjustIdent(__traits(identifier, T));
}
unittest
{
alias fqn = fullyQualifiedName;
// Make sure those 2 are the same
static assert(fqnSym!fqn == fqn!fqn);
static assert(fqn!fqn == "std.traits.fullyQualifiedName");
alias qnTests = QualifiedNameTests;
enum prefix = "std.traits.QualifiedNameTests.";
static assert(fqn!(qnTests.Inner) == prefix ~ "Inner");
static assert(fqn!(qnTests.func) == prefix ~ "func");
static assert(fqn!(qnTests.Data!int) == prefix ~ "Data!(int)");
static assert(fqn!(qnTests.Data!int.x) == prefix ~ "Data!(int).x");
static assert(fqn!(qnTests.tfunc!(int[])) == prefix ~ "tfunc!(int[])");
static assert(fqn!(qnTests.Inst!(Object)) == prefix ~ "Inst!(object.Object)");
static assert(fqn!(qnTests.Inst!(Object).x) == prefix ~ "Inst!(object.Object).x");
static assert(fqn!(qnTests.Test12309!(int, 10, "str"))
== prefix ~ "Test12309!(int, 10, \"str\")");
import core.sync.barrier;
static assert(fqn!Barrier == "core.sync.barrier.Barrier");
}
private template fqnType(T,
bool alreadyConst, bool alreadyImmutable, bool alreadyShared, bool alreadyInout)
{
import std.format : format;
// Convenience tags
enum {
_const = 0,
_immutable = 1,
_shared = 2,
_inout = 3
}
alias qualifiers = TypeTuple!(is(T == const), is(T == immutable), is(T == shared), is(T == inout));
alias noQualifiers = TypeTuple!(false, false, false, false);
string storageClassesString(uint psc)() @property
{
alias PSC = ParameterStorageClass;
return format("%s%s%s%s%s",
psc & PSC.scope_ ? "scope " : "",
psc & PSC.return_ ? "return " : "",
psc & PSC.out_ ? "out " : "",
psc & PSC.ref_ ? "ref " : "",
psc & PSC.lazy_ ? "lazy " : ""
);
}
string parametersTypeString(T)() @property
{
alias parameters = Parameters!(T);
alias parameterStC = ParameterStorageClassTuple!(T);
enum variadic = variadicFunctionStyle!T;
static if (variadic == Variadic.no)
enum variadicStr = "";
else static if (variadic == Variadic.c)
enum variadicStr = ", ...";
else static if (variadic == Variadic.d)
enum variadicStr = parameters.length ? ", ..." : "...";
else static if (variadic == Variadic.typesafe)
enum variadicStr = " ...";
else
static assert(0, "New variadic style has been added, please update fullyQualifiedName implementation");
static if (parameters.length)
{
import std.algorithm : map;
import std.range : join, zip;
string result = join(
map!(a => format("%s%s", a[0], a[1]))(
zip([staticMap!(storageClassesString, parameterStC)],
[staticMap!(fullyQualifiedName, parameters)])
),
", "
);
return result ~= variadicStr;
}
else
return variadicStr;
}
string linkageString(T)() @property
{
enum linkage = functionLinkage!T;
if (linkage != "D")
return format("extern(%s) ", linkage);
else
return "";
}
string functionAttributeString(T)() @property
{
alias FA = FunctionAttribute;
enum attrs = functionAttributes!T;
static if (attrs == FA.none)
return "";
else
return format("%s%s%s%s%s%s%s%s",
attrs & FA.pure_ ? " pure" : "",
attrs & FA.nothrow_ ? " nothrow" : "",
attrs & FA.ref_ ? " ref" : "",
attrs & FA.property ? " @property" : "",
attrs & FA.trusted ? " @trusted" : "",
attrs & FA.safe ? " @safe" : "",
attrs & FA.nogc ? " @nogc" : "",
attrs & FA.return_ ? " return" : ""
);
}
string addQualifiers(string typeString,
bool addConst, bool addImmutable, bool addShared, bool addInout)
{
auto result = typeString;
if (addShared)
{
result = format("shared(%s)", result);
}
if (addConst || addImmutable || addInout)
{
result = format("%s(%s)",
addConst ? "const" :
addImmutable ? "immutable" : "inout",
result
);
}
return result;
}
// Convenience template to avoid copy-paste
template chain(string current)
{
enum chain = addQualifiers(current,
qualifiers[_const] && !alreadyConst,
qualifiers[_immutable] && !alreadyImmutable,
qualifiers[_shared] && !alreadyShared,
qualifiers[_inout] && !alreadyInout);
}
static if (is(T == string))
{
enum fqnType = "string";
}
else static if (is(T == wstring))
{
enum fqnType = "wstring";
}
else static if (is(T == dstring))
{
enum fqnType = "dstring";
}
else static if (isBasicType!T && !is(T == enum))
{
enum fqnType = chain!((Unqual!T).stringof);
}
else static if (isAggregateType!T || is(T == enum))
{
enum fqnType = chain!(fqnSym!T);
}
else static if (isStaticArray!T)
{
import std.conv;
enum fqnType = chain!(
format("%s[%s]", fqnType!(typeof(T.init[0]), qualifiers), T.length)
);
}
else static if (isArray!T)
{
enum fqnType = chain!(
format("%s[]", fqnType!(typeof(T.init[0]), qualifiers))
);
}
else static if (isAssociativeArray!T)
{
enum fqnType = chain!(
format("%s[%s]", fqnType!(ValueType!T, qualifiers), fqnType!(KeyType!T, noQualifiers))
);
}
else static if (isSomeFunction!T)
{
static if (is(T F == delegate))
{
enum qualifierString = format("%s%s",
is(F == shared) ? " shared" : "",
is(F == inout) ? " inout" :
is(F == immutable) ? " immutable" :
is(F == const) ? " const" : ""
);
enum formatStr = "%s%s delegate(%s)%s%s";
enum fqnType = chain!(
format(formatStr, linkageString!T, fqnType!(ReturnType!T, noQualifiers),
parametersTypeString!(T), functionAttributeString!T, qualifierString)
);
}
else
{
static if (isFunctionPointer!T)
enum formatStr = "%s%s function(%s)%s";
else
enum formatStr = "%s%s(%s)%s";
enum fqnType = chain!(
format(formatStr, linkageString!T, fqnType!(ReturnType!T, noQualifiers),
parametersTypeString!(T), functionAttributeString!T)
);
}
}
else static if (isPointer!T)
{
enum fqnType = chain!(
format("%s*", fqnType!(PointerTarget!T, qualifiers))
);
}
else static if (is(T : __vector(V[N]), V, size_t N))
{
enum fqnType = chain!(
format("__vector(%s[%s])", fqnType!(V, qualifiers), N)
);
}
else
// In case something is forgotten
static assert(0, "Unrecognized type " ~ T.stringof ~ ", can't convert to fully qualified string");
}
unittest
{
import std.format : format;
alias fqn = fullyQualifiedName;
// Verify those 2 are the same for simple case
alias Ambiguous = const(QualifiedNameTests.Inner);
static assert(fqn!Ambiguous == fqnType!(Ambiguous, false, false, false, false));
// Main tests
enum inner_name = "std.traits.QualifiedNameTests.Inner";
with (QualifiedNameTests)
{
// Special cases
static assert(fqn!(string) == "string");
static assert(fqn!(wstring) == "wstring");
static assert(fqn!(dstring) == "dstring");
// Basic qualified name
static assert(fqn!(Inner) == inner_name);
static assert(fqn!(QualifiedEnum) == "std.traits.QualifiedEnum"); // type
static assert(fqn!(QualifiedEnum.a) == "std.traits.QualifiedEnum.a"); // symbol
// Array types
static assert(fqn!(typeof(array)) == format("%s[]", inner_name));
static assert(fqn!(typeof(sarray)) == format("%s[16]", inner_name));
static assert(fqn!(typeof(aarray)) == format("%s[%s]", inner_name, inner_name));
// qualified key for AA
static assert(fqn!(typeof(qualAarray)) == format("const(%s[const(%s)])", inner_name, inner_name));
// Qualified composed data types
static assert(fqn!(typeof(data)) == format("shared(const(%s[string])[])", inner_name));
// Function types + function attributes
static assert(fqn!(typeof(func)) == format("const(%s[string])(ref %s, scope lazy string) ref", inner_name, inner_name));
static assert(fqn!(typeof(retfunc)) == format("const(%s[string])(return %s) ref", inner_name, inner_name));
static assert(fqn!(typeof(inoutFunc)) == format("inout(%s(inout(%s)))", inner_name, inner_name));
static assert(fqn!(typeof(deleg)) == format("const(%s delegate(double, string) nothrow @safe)", inner_name));
static assert(fqn!(typeof(inoutDeleg)) == "inout(int) delegate(inout(int)) inout");
static assert(fqn!(typeof(funcPtr)) == format("%s function(out double, string)", inner_name));
static assert(fqn!(typeof(cFuncPtr)) == format("extern(C) %s function(double, string)", inner_name));
// Delegate type with qualified function type
static assert(fqn!(typeof(attrDeleg)) == format("shared(immutable(%s) "~
"delegate(ref double, scope string) nothrow @trusted shared const)", inner_name));
// Variable argument function types
static assert(fqn!(typeof(cVarArg)) == "extern(C) void(int, ...)");
static assert(fqn!(typeof(dVarArg)) == "void(...)");
static assert(fqn!(typeof(dVarArg2)) == "void(int, ...)");
static assert(fqn!(typeof(typesafeVarArg)) == "void(int[] ...)");
// SIMD vector
static if (is(__vector(float[4])))
{
static assert(fqn!(__vector(float[4])) == "__vector(float[4])");
}
}
}
/***
* Get the type of the return value from a function,
* a pointer to function, a delegate, a struct
* with an opCall, a pointer to a struct with an opCall,
* or a class with an $(D opCall). Please note that $(D_KEYWORD ref)
* is not part of a type, but the attribute of the function
* (see template $(LREF functionAttributes)).
*/
template ReturnType(func...)
if (func.length == 1 && isCallable!func)
{
static if (is(FunctionTypeOf!func R == return))
alias ReturnType = R;
else
static assert(0, "argument has no return type");
}
///
unittest
{
int foo();
ReturnType!foo x; // x is declared as int
}
unittest
{
struct G
{
int opCall (int i) { return 1;}
}
alias ShouldBeInt = ReturnType!G;
static assert(is(ShouldBeInt == int));
G g;
static assert(is(ReturnType!g == int));
G* p;
alias pg = ReturnType!p;
static assert(is(pg == int));
class C
{
int opCall (int i) { return 1;}
}
static assert(is(ReturnType!C == int));
C c;
static assert(is(ReturnType!c == int));
class Test
{
int prop() @property { return 0; }
}
alias R_Test_prop = ReturnType!(Test.prop);
static assert(is(R_Test_prop == int));
alias R_dglit = ReturnType!((int a) { return a; });
static assert(is(R_dglit == int));
}
/***
Get, as a tuple, the types of the parameters to a function, a pointer
to function, a delegate, a struct with an $(D opCall), a pointer to a
struct with an $(D opCall), or a class with an $(D opCall).
*/
template Parameters(func...)
if (func.length == 1 && isCallable!func)
{
static if (is(FunctionTypeOf!func P == function))
alias Parameters = P;
else
static assert(0, "argument has no parameters");
}
///
unittest
{
int foo(int, long);
void bar(Parameters!foo); // declares void bar(int, long);
void abc(Parameters!foo[1]); // declares void abc(long);
}
/**
* Alternate name for $(LREF Parameters), kept for legacy compatibility.
*/
alias ParameterTypeTuple = Parameters;
unittest
{
int foo(int i, bool b) { return 0; }
static assert(is(ParameterTypeTuple!foo == TypeTuple!(int, bool)));
static assert(is(ParameterTypeTuple!(typeof(&foo)) == TypeTuple!(int, bool)));
struct S { real opCall(real r, int i) { return 0.0; } }
S s;
static assert(is(ParameterTypeTuple!S == TypeTuple!(real, int)));
static assert(is(ParameterTypeTuple!(S*) == TypeTuple!(real, int)));
static assert(is(ParameterTypeTuple!s == TypeTuple!(real, int)));
class Test
{
int prop() @property { return 0; }
}
alias P_Test_prop = ParameterTypeTuple!(Test.prop);
static assert(P_Test_prop.length == 0);
alias P_dglit = ParameterTypeTuple!((int a){});
static assert(P_dglit.length == 1);
static assert(is(P_dglit[0] == int));
}
/**
Returns the number of arguments of function $(D func).
arity is undefined for variadic functions.
*/
template arity(alias func)
if ( isCallable!func && variadicFunctionStyle!func == Variadic.no )
{
enum size_t arity = Parameters!func.length;
}
///
unittest {
void foo(){}
static assert(arity!foo==0);
void bar(uint){}
static assert(arity!bar==1);
void variadicFoo(uint...){}
static assert(__traits(compiles,arity!variadicFoo)==false);
}
/**
Returns a tuple consisting of the storage classes of the parameters of a
function $(D func).
*/
enum ParameterStorageClass : uint
{
/**
* These flags can be bitwise OR-ed together to represent complex storage
* class.
*/
none = 0,
scope_ = 0b000_1, /// ditto
out_ = 0b001_0, /// ditto
ref_ = 0b010_0, /// ditto
lazy_ = 0b100_0, /// ditto
return_ = 0b1000_0, /// ditto
}
/// ditto
template ParameterStorageClassTuple(func...)
if (func.length == 1 && isCallable!func)
{
alias Func = Unqual!(FunctionTypeOf!func);
/*
* TypeFuncion:
* CallConvention FuncAttrs Arguments ArgClose Type
*/
alias Params = Parameters!Func;
// chop off CallConvention and FuncAttrs
enum margs = demangleFunctionAttributes(mangledName!Func[1 .. $]).rest;
// demangle Arguments and store parameter storage classes in a tuple
template demangleNextParameter(string margs, size_t i = 0)
{
static if (i < Params.length)
{
enum demang = demangleParameterStorageClass(margs);
enum skip = mangledName!(Params[i]).length; // for bypassing Type
enum rest = demang.rest;
alias demangleNextParameter =
TypeTuple!(
demang.value + 0, // workaround: "not evaluatable at ..."
demangleNextParameter!(rest[skip .. $], i + 1)
);
}
else // went thru all the parameters
{
alias demangleNextParameter = TypeTuple!();
}
}
alias ParameterStorageClassTuple = demangleNextParameter!margs;
}
///
unittest
{
alias STC = ParameterStorageClass; // shorten the enum name
void func(ref int ctx, out real result, real param)
{
}
alias pstc = ParameterStorageClassTuple!func;
static assert(pstc.length == 3); // three parameters
static assert(pstc[0] == STC.ref_);
static assert(pstc[1] == STC.out_);
static assert(pstc[2] == STC.none);
}
unittest
{
alias STC = ParameterStorageClass;
void noparam() {}
static assert(ParameterStorageClassTuple!noparam.length == 0);
void test(scope int, ref int, out int, lazy int, int, return ref int) { }
alias test_pstc = ParameterStorageClassTuple!test;
static assert(test_pstc.length == 6);
static assert(test_pstc[0] == STC.scope_);
static assert(test_pstc[1] == STC.ref_);
static assert(test_pstc[2] == STC.out_);
static assert(test_pstc[3] == STC.lazy_);
static assert(test_pstc[4] == STC.none);
static assert(test_pstc[5] == STC.return_);
interface Test
{
void test_const(int) const;
void test_sharedconst(int) shared const;
}
Test testi;
alias test_const_pstc = ParameterStorageClassTuple!(Test.test_const);
static assert(test_const_pstc.length == 1);
static assert(test_const_pstc[0] == STC.none);
alias test_sharedconst_pstc = ParameterStorageClassTuple!(testi.test_sharedconst);
static assert(test_sharedconst_pstc.length == 1);
static assert(test_sharedconst_pstc[0] == STC.none);
alias dglit_pstc = ParameterStorageClassTuple!((ref int a) {});
static assert(dglit_pstc.length == 1);
static assert(dglit_pstc[0] == STC.ref_);
// Bugzilla 9317
static inout(int) func(inout int param) { return param; }
static assert(ParameterStorageClassTuple!(typeof(func))[0] == STC.none);
}
unittest
{
// Bugzilla 14253
static struct Foo {
ref Foo opAssign(ref Foo rhs) return { return this; }
}
alias tup = ParameterStorageClassTuple!(__traits(getOverloads, Foo, "opAssign")[0]);
}
/**
Get, as a tuple, the identifiers of the parameters to a function symbol.
*/
template ParameterIdentifierTuple(func...)
if (func.length == 1 && isCallable!func)
{
static if (is(FunctionTypeOf!func PT == __parameters))
{
template Get(size_t i)
{
static if (!isFunctionPointer!func && !isDelegate!func
// Unnamed parameters yield CT error.
&& is(typeof(__traits(identifier, PT[i..i+1]))x))
{
enum Get = __traits(identifier, PT[i..i+1]);
}
else
{
enum Get = "";
}
}
}
else
{
static assert(0, func[0].stringof ~ "is not a function");
// Define dummy entities to avoid pointless errors
template Get(size_t i) { enum Get = ""; }
alias PT = TypeTuple!();
}
template Impl(size_t i = 0)
{
static if (i == PT.length)
alias Impl = TypeTuple!();
else
alias Impl = TypeTuple!(Get!i, Impl!(i+1));
}
alias ParameterIdentifierTuple = Impl!();
}
///
unittest
{
int foo(int num, string name, int);
static assert([ParameterIdentifierTuple!foo] == ["num", "name", ""]);
}
unittest
{
alias PIT = ParameterIdentifierTuple;
void bar(int num, string name, int[] array){}
static assert([PIT!bar] == ["num", "name", "array"]);
// might be changed in the future?
void function(int num, string name) fp;
static assert([PIT!fp] == ["", ""]);
// might be changed in the future?
void delegate(int num, string name, int[long] aa) dg;
static assert([PIT!dg] == ["", "", ""]);
interface Test
{
@property string getter();
@property void setter(int a);
Test method(int a, long b, string c);
}
static assert([PIT!(Test.getter)] == []);
static assert([PIT!(Test.setter)] == ["a"]);
static assert([PIT!(Test.method)] == ["a", "b", "c"]);
/+
// depends on internal
void baw(int, string, int[]){}
static assert([PIT!baw] == ["_param_0", "_param_1", "_param_2"]);
// depends on internal
void baz(TypeTuple!(int, string, int[]) args){}
static assert([PIT!baz] == ["_param_0", "_param_1", "_param_2"]);
+/
}
/**
Get, as a tuple, the default value of the parameters to a function symbol.
If a parameter doesn't have the default value, $(D void) is returned instead.
*/
template ParameterDefaults(func...)
if (func.length == 1 && isCallable!func)
{
static if (is(FunctionTypeOf!(func[0]) PT == __parameters))
{
template Get(size_t i)
{
enum ParamName = ParameterIdentifierTuple!(func[0])[i];
static if (ParamName.length)
enum get = (PT[i..i+1]) => mixin(ParamName);
else // Unnamed parameter
enum get = (PT[i..i+1] __args) => __args[0];
static if (is(typeof(get())))
enum Get = get();
else
alias Get = void;
// If default arg doesn't exist, returns void instead.
}
}
else static if (is(FunctionTypeOf!func PT == __parameters))
{
template Get(size_t i)
{
enum Get = "";
}
}
else
{
static assert(0, func[0].stringof ~ "is not a function");
// Define dummy entities to avoid pointless errors
template Get(size_t i) { enum Get = ""; }
alias PT = TypeTuple!();
}
template Impl(size_t i = 0)
{
static if (i == PT.length)
alias Impl = TypeTuple!();
else
alias Impl = TypeTuple!(Get!i, Impl!(i+1));
}
alias ParameterDefaults = Impl!();
}
///
unittest
{
int foo(int num, string name = "hello", int[] = [1,2,3]);
static assert(is(ParameterDefaults!foo[0] == void));
static assert( ParameterDefaults!foo[1] == "hello");
static assert( ParameterDefaults!foo[2] == [1,2,3]);
}
/**
* Alternate name for $(LREF ParameterDefaults), kept for legacy compatibility.
*/
alias ParameterDefaultValueTuple = ParameterDefaults;
unittest
{
alias PDVT = ParameterDefaultValueTuple;
void bar(int n = 1, string s = "hello"){}
static assert(PDVT!bar.length == 2);
static assert(PDVT!bar[0] == 1);
static assert(PDVT!bar[1] == "hello");
static assert(is(typeof(PDVT!bar) == typeof(TypeTuple!(1, "hello"))));
void baz(int x, int n = 1, string s = "hello"){}
static assert(PDVT!baz.length == 3);
static assert(is(PDVT!baz[0] == void));
static assert( PDVT!baz[1] == 1);
static assert( PDVT!baz[2] == "hello");
static assert(is(typeof(PDVT!baz) == typeof(TypeTuple!(void, 1, "hello"))));
// bug 10800 - property functions return empty string
@property void foo(int x = 3) { }
static assert(PDVT!foo.length == 1);
static assert(PDVT!foo[0] == 3);
static assert(is(typeof(PDVT!foo) == typeof(TypeTuple!(3))));
struct Colour
{
ubyte a,r,g,b;
static immutable Colour white = Colour(255,255,255,255);
}
void bug8106(Colour c = Colour.white){}
//pragma(msg, PDVT!bug8106);
static assert(PDVT!bug8106[0] == Colour.white);
}
/**
Returns the attributes attached to a function $(D func).
*/
enum FunctionAttribute : uint
{
/**
* These flags can be bitwise OR-ed together to represent a complex attribute.
*/
none = 0,
pure_ = 1 << 0, /// ditto
nothrow_ = 1 << 1, /// ditto
ref_ = 1 << 2, /// ditto
property = 1 << 3, /// ditto
trusted = 1 << 4, /// ditto
safe = 1 << 5, /// ditto
nogc = 1 << 6, /// ditto
system = 1 << 7, /// ditto
const_ = 1 << 8, /// ditto
immutable_ = 1 << 9, /// ditto
inout_ = 1 << 10, /// ditto
shared_ = 1 << 11, /// ditto
return_ = 1 << 12, /// ditto
}
/// ditto
template functionAttributes(func...)
if (func.length == 1 && isCallable!func)
{
// @bug: workaround for opCall
alias FuncSym = Select!(is(typeof(__traits(getFunctionAttributes, func))),
func, Unqual!(FunctionTypeOf!func));
enum FunctionAttribute functionAttributes =
extractAttribFlags!(__traits(getFunctionAttributes, FuncSym))();
}
///
unittest
{
import std.traits : functionAttributes, FunctionAttribute;
alias FA = FunctionAttribute; // shorten the enum name
real func(real x) pure nothrow @safe
{
return x;
}
static assert(functionAttributes!func & FA.pure_);
static assert(functionAttributes!func & FA.safe);
static assert(!(functionAttributes!func & FA.trusted)); // not @trusted
}
unittest
{
alias FA = FunctionAttribute;
struct S
{
int noF() { return 0; }
int constF() const { return 0; }
int immutableF() immutable { return 0; }
int inoutF() inout { return 0; }
int sharedF() shared { return 0; }
int x;
ref int refF() return { return x; }
int propertyF() @property { return 0; }
int nothrowF() nothrow { return 0; }
int nogcF() @nogc { return 0; }
int systemF() @system { return 0; }
int trustedF() @trusted { return 0; }
int safeF() @safe { return 0; }
int pureF() pure { return 0; }
}
static assert(functionAttributes!(S.noF) == FA.system);
static assert(functionAttributes!(typeof(S.noF)) == FA.system);
static assert(functionAttributes!(S.constF) == (FA.const_ | FA.system));
static assert(functionAttributes!(typeof(S.constF)) == (FA.const_ | FA.system));
static assert(functionAttributes!(S.immutableF) == (FA.immutable_ | FA.system));
static assert(functionAttributes!(typeof(S.immutableF)) == (FA.immutable_ | FA.system));
static assert(functionAttributes!(S.inoutF) == (FA.inout_ | FA.system));
static assert(functionAttributes!(typeof(S.inoutF)) == (FA.inout_ | FA.system));
static assert(functionAttributes!(S.sharedF) == (FA.shared_ | FA.system));
static assert(functionAttributes!(typeof(S.sharedF)) == (FA.shared_ | FA.system));
static assert(functionAttributes!(S.refF) == (FA.ref_ | FA.system));
static assert(functionAttributes!(typeof(S.refF)) == (FA.ref_ | FA.system));
static assert(functionAttributes!(S.propertyF) == (FA.property | FA.system));
static assert(functionAttributes!(typeof(&S.propertyF)) == (FA.property | FA.system));
static assert(functionAttributes!(S.nothrowF) == (FA.nothrow_ | FA.system));
static assert(functionAttributes!(typeof(S.nothrowF)) == (FA.nothrow_ | FA.system));
static assert(functionAttributes!(S.nogcF) == (FA.nogc | FA.system));
static assert(functionAttributes!(typeof(S.nogcF)) == (FA.nogc | FA.system));
static assert(functionAttributes!(S.systemF) == FA.system);
static assert(functionAttributes!(typeof(S.systemF)) == FA.system);
static assert(functionAttributes!(S.trustedF) == FA.trusted);
static assert(functionAttributes!(typeof(S.trustedF)) == FA.trusted);
static assert(functionAttributes!(S.safeF) == FA.safe);
static assert(functionAttributes!(typeof(S.safeF)) == FA.safe);
static assert(functionAttributes!(S.pureF) == (FA.pure_ | FA.system));
static assert(functionAttributes!(typeof(S.pureF)) == (FA.pure_ | FA.system));
int pure_nothrow() nothrow pure { return 0; }
void safe_nothrow() @safe nothrow { }
static ref int static_ref_property() @property { return *(new int); }
ref int ref_property() @property { return *(new int); }
static assert(functionAttributes!(pure_nothrow) == (FA.pure_ | FA.nothrow_ | FA.system));
static assert(functionAttributes!(typeof(pure_nothrow)) == (FA.pure_ | FA.nothrow_ | FA.system));
static assert(functionAttributes!(safe_nothrow) == (FA.safe | FA.nothrow_));
static assert(functionAttributes!(typeof(safe_nothrow)) == (FA.safe | FA.nothrow_));
static assert(functionAttributes!(static_ref_property) == (FA.property | FA.ref_ | FA.system));
static assert(functionAttributes!(typeof(&static_ref_property)) == (FA.property | FA.ref_ | FA.system));
static assert(functionAttributes!(ref_property) == (FA.property | FA.ref_ | FA.system));
static assert(functionAttributes!(typeof(&ref_property)) == (FA.property | FA.ref_ | FA.system));
struct S2
{
int pure_const() const pure { return 0; }
int pure_sharedconst() const shared pure { return 0; }
}
static assert(functionAttributes!(S2.pure_const) == (FA.const_ | FA.pure_ | FA.system));
static assert(functionAttributes!(typeof(S2.pure_const)) == (FA.const_ | FA.pure_ | FA.system));
static assert(functionAttributes!(S2.pure_sharedconst) == (FA.const_ | FA.shared_ | FA.pure_ | FA.system));
static assert(functionAttributes!(typeof(S2.pure_sharedconst)) == (FA.const_ | FA.shared_ | FA.pure_ | FA.system));
static assert(functionAttributes!((int a) { }) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.safe));
static assert(functionAttributes!(typeof((int a) { })) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.safe));
auto safeDel = delegate() @safe { };
static assert(functionAttributes!(safeDel) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.safe));
static assert(functionAttributes!(typeof(safeDel)) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.safe));
auto trustedDel = delegate() @trusted { };
static assert(functionAttributes!(trustedDel) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.trusted));
static assert(functionAttributes!(typeof(trustedDel)) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.trusted));
auto systemDel = delegate() @system { };
static assert(functionAttributes!(systemDel) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.system));
static assert(functionAttributes!(typeof(systemDel)) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.system));
}
private FunctionAttribute extractAttribFlags(Attribs...)()
{
auto res = FunctionAttribute.none;
foreach (attrib; Attribs)
{
switch (attrib) with (FunctionAttribute)
{
case "pure": res |= pure_; break;
case "nothrow": res |= nothrow_; break;
case "ref": res |= ref_; break;
case "@property": res |= property; break;
case "@trusted": res |= trusted; break;
case "@safe": res |= safe; break;
case "@nogc": res |= nogc; break;
case "@system": res |= system; break;
case "const": res |= const_; break;
case "immutable": res |= immutable_; break;
case "inout": res |= inout_; break;
case "shared": res |= shared_; break;
case "return": res |= return_; break;
default: assert(0, attrib);
}
}
return res;
}
/**
$(D true) if $(D func) is $(D @safe) or $(D @trusted).
*/
template isSafe(alias func)
if(isCallable!func)
{
enum isSafe = (functionAttributes!func & FunctionAttribute.safe) != 0 ||
(functionAttributes!func & FunctionAttribute.trusted) != 0;
}
///
unittest
{
@safe int add(int a, int b) {return a+b;}
@trusted int sub(int a, int b) {return a-b;}
@system int mul(int a, int b) {return a*b;}
static assert( isSafe!add);
static assert( isSafe!sub);
static assert(!isSafe!mul);
}
unittest
{
//Member functions
interface Set
{
int systemF() @system;
int trustedF() @trusted;
int safeF() @safe;
}
static assert( isSafe!(Set.safeF));
static assert( isSafe!(Set.trustedF));
static assert(!isSafe!(Set.systemF));
//Functions
@safe static safeFunc() {}
@trusted static trustedFunc() {}
@system static systemFunc() {}
static assert( isSafe!safeFunc);
static assert( isSafe!trustedFunc);
static assert(!isSafe!systemFunc);
//Delegates
auto safeDel = delegate() @safe {};
auto trustedDel = delegate() @trusted {};
auto systemDel = delegate() @system {};
static assert( isSafe!safeDel);
static assert( isSafe!trustedDel);
static assert(!isSafe!systemDel);
//Lambdas
static assert( isSafe!({safeDel();}));
static assert( isSafe!({trustedDel();}));
static assert(!isSafe!({systemDel();}));
//Static opCall
struct SafeStatic { @safe static SafeStatic opCall() { return SafeStatic.init; } }
struct TrustedStatic { @trusted static TrustedStatic opCall() { return TrustedStatic.init; } }
struct SystemStatic { @system static SystemStatic opCall() { return SystemStatic.init; } }
static assert( isSafe!(SafeStatic()));
static assert( isSafe!(TrustedStatic()));
static assert(!isSafe!(SystemStatic()));
//Non-static opCall
struct Safe { @safe Safe opCall() { return Safe.init; } }
struct Trusted { @trusted Trusted opCall() { return Trusted.init; } }
struct System { @system System opCall() { return System.init; } }
static assert( isSafe!(Safe.init()));
static assert( isSafe!(Trusted.init()));
static assert(!isSafe!(System.init()));
}
/**
$(D true) if $(D func) is $(D @system).
*/
template isUnsafe(alias func)
{
enum isUnsafe = !isSafe!func;
}
///
unittest
{
@safe int add(int a, int b) {return a+b;}
@trusted int sub(int a, int b) {return a-b;}
@system int mul(int a, int b) {return a*b;}
static assert(!isUnsafe!add);
static assert(!isUnsafe!sub);
static assert( isUnsafe!mul);
}
unittest
{
//Member functions
interface Set
{
int systemF() @system;
int trustedF() @trusted;
int safeF() @safe;
}
static assert(!isUnsafe!(Set.safeF));
static assert(!isUnsafe!(Set.trustedF));
static assert( isUnsafe!(Set.systemF));
//Functions
@safe static safeFunc() {}
@trusted static trustedFunc() {}
@system static systemFunc() {}
static assert(!isUnsafe!safeFunc);
static assert(!isUnsafe!trustedFunc);
static assert( isUnsafe!systemFunc);
//Delegates
auto safeDel = delegate() @safe {};
auto trustedDel = delegate() @trusted {};
auto systemDel = delegate() @system {};
static assert(!isUnsafe!safeDel);
static assert(!isUnsafe!trustedDel);
static assert( isUnsafe!systemDel);
//Lambdas
static assert(!isUnsafe!({safeDel();}));
static assert(!isUnsafe!({trustedDel();}));
static assert( isUnsafe!({systemDel();}));
//Static opCall
struct SafeStatic { @safe static SafeStatic opCall() { return SafeStatic.init; } }
struct TrustedStatic { @trusted static TrustedStatic opCall() { return TrustedStatic.init; } }
struct SystemStatic { @system static SystemStatic opCall() { return SystemStatic.init; } }
static assert(!isUnsafe!(SafeStatic()));
static assert(!isUnsafe!(TrustedStatic()));
static assert( isUnsafe!(SystemStatic()));
//Non-static opCall
struct Safe { @safe Safe opCall() { return Safe.init; } }
struct Trusted { @trusted Trusted opCall() { return Trusted.init; } }
struct System { @system System opCall() { return System.init; } }
static assert(!isUnsafe!(Safe.init()));
static assert(!isUnsafe!(Trusted.init()));
static assert( isUnsafe!(System.init()));
}
/**
$(RED Deprecated. It's badly named and provides redundant functionality. It was
also badly broken prior to 2.060 (bug# 8362), so any code which uses it
probably needs to be changed anyway. Please use $(D allSatisfy(isSafe, ...))
instead. This will be removed in June 2015.)
$(D true) all functions are $(D isSafe).
Example
-------------
@safe int add(int a, int b) {return a+b;}
@trusted int sub(int a, int b) {return a-b;}
@system int mul(int a, int b) {return a*b;}
static assert( areAllSafe!(add, add));
static assert( areAllSafe!(add, sub));
static assert(!areAllSafe!(sub, mul));
-------------
*/
deprecated("Please use allSatisfy(isSafe, ...) instead.")
template areAllSafe(funcs...)
if (funcs.length > 0)
{
static if (funcs.length == 1)
{
enum areAllSafe = isSafe!(funcs[0]);
}
else static if (isSafe!(funcs[0]))
{
enum areAllSafe = areAllSafe!(funcs[1..$]);
}
else
{
enum areAllSafe = false;
}
}
// Verify Example
deprecated unittest
{
@safe int add(int a, int b) {return a+b;}
@trusted int sub(int a, int b) {return a-b;}
@system int mul(int a, int b) {return a*b;}
static assert( areAllSafe!(add, add));
static assert( areAllSafe!(add, sub));
static assert(!areAllSafe!(sub, mul));
}
deprecated unittest
{
interface Set
{
int systemF() @system;
int trustedF() @trusted;
int safeF() @safe;
}
static assert( areAllSafe!((int a){}, Set.safeF));
static assert( areAllSafe!((int a){}, Set.safeF, Set.trustedF));
static assert(!areAllSafe!(Set.trustedF, Set.systemF));
}
/**
Returns the calling convention of function as a string.
*/
template functionLinkage(func...)
if (func.length == 1 && isCallable!func)
{
alias Func = Unqual!(FunctionTypeOf!func);
enum string functionLinkage =
[
'F': "D",
'U': "C",
'W': "Windows",
'V': "Pascal",
'R': "C++"
][ mangledName!Func[0] ];
}
///
unittest
{
extern(D) void Dfunc() {}
extern(C) void Cfunc() {}
static assert(functionLinkage!Dfunc == "D");
static assert(functionLinkage!Cfunc == "C");
string a = functionLinkage!Dfunc;
assert(a == "D");
auto fp = &Cfunc;
string b = functionLinkage!fp;
assert(b == "C");
}
unittest
{
interface Test
{
void const_func() const;
void sharedconst_func() shared const;
}
static assert(functionLinkage!(Test.const_func) == "D");
static assert(functionLinkage!(Test.sharedconst_func) == "D");
static assert(functionLinkage!((int a){}) == "D");
}
/**
Determines what kind of variadic parameters function has.
*/
enum Variadic
{
no, /// Function is not variadic.
c, /// Function is a _C-style variadic function.
/// Function is a _D-style variadic function, which uses
d, /// __argptr and __arguments.
typesafe, /// Function is a typesafe variadic function.
}
/// ditto
template variadicFunctionStyle(func...)
if (func.length == 1 && isCallable!func)
{
alias Func = Unqual!(FunctionTypeOf!func);
// TypeFuncion --> CallConvention FuncAttrs Arguments ArgClose Type
enum callconv = functionLinkage!Func;
enum mfunc = mangledName!Func;
enum mtype = mangledName!(ReturnType!Func);
static assert(mfunc[$ - mtype.length .. $] == mtype, mfunc ~ "|" ~ mtype);
enum argclose = mfunc[$ - mtype.length - 1];
static assert(argclose >= 'X' && argclose <= 'Z');
enum Variadic variadicFunctionStyle =
argclose == 'X' ? Variadic.typesafe :
argclose == 'Y' ? (callconv == "C") ? Variadic.c : Variadic.d :
Variadic.no; // 'Z'
}
///
unittest
{
void func() {}
static assert(variadicFunctionStyle!func == Variadic.no);
extern(C) int printf(in char*, ...);
static assert(variadicFunctionStyle!printf == Variadic.c);
}
unittest
{
import core.vararg;
extern(D) void novar() {}
extern(C) void cstyle(int, ...) {}
extern(D) void dstyle(...) {}
extern(D) void typesafe(int[]...) {}
static assert(variadicFunctionStyle!novar == Variadic.no);
static assert(variadicFunctionStyle!cstyle == Variadic.c);
static assert(variadicFunctionStyle!dstyle == Variadic.d);
static assert(variadicFunctionStyle!typesafe == Variadic.typesafe);
static assert(variadicFunctionStyle!((int[] a...) {}) == Variadic.typesafe);
}
/**
Get the function type from a callable object $(D func).
Using builtin $(D typeof) on a property function yields the types of the
property value, not of the property function itself. Still,
$(D FunctionTypeOf) is able to obtain function types of properties.
Note:
Do not confuse function types with function pointer types; function types are
usually used for compile-time reflection purposes.
*/
template FunctionTypeOf(func...)
if (func.length == 1 && isCallable!func)
{
static if (is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function) || is(typeof(& func[0]) Fsym == delegate))
{
alias FunctionTypeOf = Fsym; // HIT: (nested) function symbol
}
else static if (is(typeof(& func[0].opCall) Fobj == delegate))
{
alias FunctionTypeOf = Fobj; // HIT: callable object
}
else static if (is(typeof(& func[0].opCall) Ftyp : Ftyp*) && is(Ftyp == function))
{
alias FunctionTypeOf = Ftyp; // HIT: callable type
}
else static if (is(func[0] T) || is(typeof(func[0]) T))
{
static if (is(T == function))
alias FunctionTypeOf = T; // HIT: function
else static if (is(T Fptr : Fptr*) && is(Fptr == function))
alias FunctionTypeOf = Fptr; // HIT: function pointer
else static if (is(T Fdlg == delegate))
alias FunctionTypeOf = Fdlg; // HIT: delegate
else
static assert(0);
}
else
static assert(0);
}
///
unittest
{
class C
{
int value() @property { return 0; }
}
static assert(is( typeof(C.value) == int ));
static assert(is( FunctionTypeOf!(C.value) == function ));
}
unittest
{
int test(int a) { return 0; }
int propGet() @property { return 0; }
int propSet(int a) @property { return 0; }
int function(int) test_fp;
int delegate(int) test_dg;
static assert(is( typeof(test) == FunctionTypeOf!(typeof(test)) ));
static assert(is( typeof(test) == FunctionTypeOf!test ));
static assert(is( typeof(test) == FunctionTypeOf!test_fp ));
static assert(is( typeof(test) == FunctionTypeOf!test_dg ));
alias int GetterType() @property;
alias int SetterType(int) @property;
static assert(is( FunctionTypeOf!propGet == GetterType ));
static assert(is( FunctionTypeOf!propSet == SetterType ));
interface Prop { int prop() @property; }
Prop prop;
static assert(is( FunctionTypeOf!(Prop.prop) == GetterType ));
static assert(is( FunctionTypeOf!(prop.prop) == GetterType ));
class Callable { int opCall(int) { return 0; } }
auto call = new Callable;
static assert(is( FunctionTypeOf!call == typeof(test) ));
struct StaticCallable { static int opCall(int) { return 0; } }
StaticCallable stcall_val;
StaticCallable* stcall_ptr;
static assert(is( FunctionTypeOf!stcall_val == typeof(test) ));
static assert(is( FunctionTypeOf!stcall_ptr == typeof(test) ));
interface Overloads
{
void test(string);
real test(real);
int test(int);
int test() @property;
}
alias ov = TypeTuple!(__traits(getVirtualFunctions, Overloads, "test"));
alias F_ov0 = FunctionTypeOf!(ov[0]);
alias F_ov1 = FunctionTypeOf!(ov[1]);
alias F_ov2 = FunctionTypeOf!(ov[2]);
alias F_ov3 = FunctionTypeOf!(ov[3]);
static assert(is(F_ov0* == void function(string)));
static assert(is(F_ov1* == real function(real)));
static assert(is(F_ov2* == int function(int)));
static assert(is(F_ov3* == int function() @property));
alias F_dglit = FunctionTypeOf!((int a){ return a; });
static assert(is(F_dglit* : int function(int)));
}
/**
* Constructs a new function or delegate type with the same basic signature
* as the given one, but different attributes (including linkage).
*
* This is especially useful for adding/removing attributes to/from types in
* generic code, where the actual type name cannot be spelt out.
*
* Params:
* T = The base type.
* linkage = The desired linkage of the result type.
* attrs = The desired $(LREF FunctionAttribute)s of the result type.
*/
template SetFunctionAttributes(T, string linkage, uint attrs)
if (isFunctionPointer!T || isDelegate!T)
{
mixin({
import std.algorithm : canFind;
static assert(!(attrs & FunctionAttribute.trusted) ||
!(attrs & FunctionAttribute.safe),
"Cannot have a function/delegate that is both trusted and safe.");
enum linkages = ["D", "C", "Windows", "Pascal", "C++", "System"];
static assert(canFind(linkages, linkage), "Invalid linkage '" ~
linkage ~ "', must be one of " ~ linkages.stringof ~ ".");
string result = "alias ";
static if (linkage != "D")
result ~= "extern(" ~ linkage ~ ") ";
static if (attrs & FunctionAttribute.ref_)
result ~= "ref ";
result ~= "ReturnType!T";
static if (isDelegate!T)
result ~= " delegate";
else
result ~= " function";
result ~= "(";
static if (Parameters!T.length > 0)
result ~= "Parameters!T";
enum varStyle = variadicFunctionStyle!T;
static if (varStyle == Variadic.c)
result ~= ", ...";
else static if (varStyle == Variadic.d)
result ~= "...";
else static if (varStyle == Variadic.typesafe)
result ~= "...";
result ~= ")";
static if (attrs & FunctionAttribute.pure_)
result ~= " pure";
static if (attrs & FunctionAttribute.nothrow_)
result ~= " nothrow";
static if (attrs & FunctionAttribute.property)
result ~= " @property";
static if (attrs & FunctionAttribute.trusted)
result ~= " @trusted";
static if (attrs & FunctionAttribute.safe)
result ~= " @safe";
static if (attrs & FunctionAttribute.nogc)
result ~= " @nogc";
static if (attrs & FunctionAttribute.system)
result ~= " @system";
static if (attrs & FunctionAttribute.const_)
result ~= " const";
static if (attrs & FunctionAttribute.immutable_)
result ~= " immutable";
static if (attrs & FunctionAttribute.inout_)
result ~= " inout";
static if (attrs & FunctionAttribute.shared_)
result ~= " shared";
static if (attrs & FunctionAttribute.return_)
result ~= " return";
result ~= " SetFunctionAttributes;";
return result;
}());
}
/// Ditto
template SetFunctionAttributes(T, string linkage, uint attrs)
if (is(T == function))
{
// To avoid a lot of syntactic headaches, we just use the above version to
// operate on the corresponding function pointer type and then remove the
// indirection again.
alias SetFunctionAttributes = FunctionTypeOf!(SetFunctionAttributes!(T*, linkage, attrs));
}
///
unittest
{
alias ExternC(T) = SetFunctionAttributes!(T, "C", functionAttributes!T);
auto assumePure(T)(T t)
if (isFunctionPointer!T || isDelegate!T)
{
enum attrs = functionAttributes!T | FunctionAttribute.pure_;
return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
}
}
version (unittest)
{
// Some function types to test.
int sc(scope int, ref int, out int, lazy int, int);
extern(System) int novar();
extern(C) int cstyle(int, ...);
extern(D) int dstyle(...);
extern(D) int typesafe(int[]...);
}
unittest
{
import std.algorithm : reduce;
alias FA = FunctionAttribute;
foreach (BaseT; TypeTuple!(typeof(&sc), typeof(&novar), typeof(&cstyle),
typeof(&dstyle), typeof(&typesafe)))
{
foreach (T; TypeTuple!(BaseT, FunctionTypeOf!BaseT))
(){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
enum linkage = functionLinkage!T;
enum attrs = functionAttributes!T;
static assert(is(SetFunctionAttributes!(T, linkage, attrs) == T),
"Identity check failed for: " ~ T.stringof);
// Check that all linkage types work (D-style variadics require D linkage).
static if (variadicFunctionStyle!T != Variadic.d)
{
foreach (newLinkage; TypeTuple!("D", "C", "Windows", "Pascal", "C++"))
{
alias New = SetFunctionAttributes!(T, newLinkage, attrs);
static assert(functionLinkage!New == newLinkage,
"Linkage test failed for: " ~ T.stringof ~ ", " ~ newLinkage ~
" (got " ~ New.stringof ~ ")");
}
}
// Add @safe.
alias T1 = SetFunctionAttributes!(T, functionLinkage!T, FA.safe);
static assert(functionAttributes!T1 == FA.safe);
// Add all known attributes, excluding conflicting ones.
enum allAttrs = reduce!"a | b"([EnumMembers!FA])
& ~FA.safe & ~FA.property & ~FA.const_ & ~FA.immutable_ & ~FA.inout_ & ~FA.shared_ & ~FA.system & ~FA.return_;
alias T2 = SetFunctionAttributes!(T1, functionLinkage!T, allAttrs);
static assert(functionAttributes!T2 == allAttrs);
// Strip all attributes again.
alias T3 = SetFunctionAttributes!(T2, functionLinkage!T, FA.none);
static assert(is(T3 == T));
}();
}
}
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
// Aggregate Types
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
/**
Determines whether $(D T) has its own context pointer.
$(D T) must be either $(D class), $(D struct), or $(D union).
*/
template isNested(T)
if(is(T == class) || is(T == struct) || is(T == union))
{
enum isNested = __traits(isNested, T);
}
///
unittest
{
static struct S { }
static assert(!isNested!S);
int i;
struct NestedStruct { void f() { ++i; } }
static assert(isNested!NestedStruct);
}
/**
Determines whether $(D T) or any of its representation types
have a context pointer.
*/
template hasNested(T)
{
static if(isStaticArray!T && T.length)
enum hasNested = hasNested!(typeof(T.init[0]));
else static if(is(T == class) || is(T == struct) || is(T == union))
enum hasNested = isNested!T ||
anySatisfy!(.hasNested, Fields!T);
else
enum hasNested = false;
}
///
unittest
{
static struct S { }
int i;
struct NS { void f() { ++i; } }
static assert(!hasNested!(S[2]));
static assert(hasNested!(NS[2]));
}
unittest
{
static assert(!__traits(compiles, isNested!int));
static assert(!hasNested!int);
static struct StaticStruct { }
static assert(!isNested!StaticStruct);
static assert(!hasNested!StaticStruct);
int i;
struct NestedStruct { void f() { ++i; } }
static assert( isNested!NestedStruct);
static assert( hasNested!NestedStruct);
static assert( isNested!(immutable NestedStruct));
static assert( hasNested!(immutable NestedStruct));
static assert(!__traits(compiles, isNested!(NestedStruct[1])));
static assert( hasNested!(NestedStruct[1]));
static assert(!hasNested!(NestedStruct[0]));
struct S1 { NestedStruct nested; }
static assert(!isNested!S1);
static assert( hasNested!S1);
static struct S2 { NestedStruct nested; }
static assert(!isNested!S2);
static assert( hasNested!S2);
static struct S3 { NestedStruct[0] nested; }
static assert(!isNested!S3);
static assert(!hasNested!S3);
static union U { NestedStruct nested; }
static assert(!isNested!U);
static assert( hasNested!U);
static class StaticClass { }
static assert(!isNested!StaticClass);
static assert(!hasNested!StaticClass);
class NestedClass { void f() { ++i; } }
static assert( isNested!NestedClass);
static assert( hasNested!NestedClass);
static assert( isNested!(immutable NestedClass));
static assert( hasNested!(immutable NestedClass));
static assert(!__traits(compiles, isNested!(NestedClass[1])));
static assert( hasNested!(NestedClass[1]));
static assert(!hasNested!(NestedClass[0]));
}
/***
* Get as a tuple the types of the fields of a struct, class, or union.
* This consists of the fields that take up memory space,
* excluding the hidden fields like the virtual function
* table pointer or a context pointer for nested types.
* If $(D T) isn't a struct, class, or union returns a tuple
* with one element $(D T).
*/
template Fields(T)
{
static if (is(T == struct) || is(T == union))
alias Fields = typeof(T.tupleof[0 .. $ - isNested!T]);
else static if (is(T == class))
alias Fields = typeof(T.tupleof);
else
alias Fields = TypeTuple!T;
}
///
unittest
{
struct S { int x; float y; }
static assert(is(Fields!S == TypeTuple!(int, float)));
}
/**
* Alternate name for $(LREF FieldTypeTuple), kept for legacy compatibility.
*/
alias FieldTypeTuple = Fields;
unittest
{
static assert(is(FieldTypeTuple!int == TypeTuple!int));
static struct StaticStruct1 { }
static assert(is(FieldTypeTuple!StaticStruct1 == TypeTuple!()));
static struct StaticStruct2 { int a, b; }
static assert(is(FieldTypeTuple!StaticStruct2 == TypeTuple!(int, int)));
int i;
struct NestedStruct1 { void f() { ++i; } }
static assert(is(FieldTypeTuple!NestedStruct1 == TypeTuple!()));
struct NestedStruct2 { int a; void f() { ++i; } }
static assert(is(FieldTypeTuple!NestedStruct2 == TypeTuple!int));
class NestedClass { int a; void f() { ++i; } }
static assert(is(FieldTypeTuple!NestedClass == TypeTuple!int));
}
//Required for FieldNameTuple
private enum NameOf(alias T) = T.stringof;
/**
* Get as an expression tuple the names of the fields of a struct, class, or
* union. This consists of the fields that take up memory space, excluding the
* hidden fields like the virtual function table pointer or a context pointer
* for nested types. If $(D T) isn't a struct, class, or union returns an
* expression tuple with an empty string.
*/
template FieldNameTuple(T)
{
static if (is(T == struct) || is(T == union))
alias FieldNameTuple = staticMap!(NameOf, T.tupleof[0 .. $ - isNested!T]);
else static if (is(T == class))
alias FieldNameTuple = staticMap!(NameOf, T.tupleof);
else
alias FieldNameTuple = TypeTuple!"";
}
///
unittest
{
struct S { int x; float y; }
static assert(FieldNameTuple!S == TypeTuple!("x", "y"));
static assert(FieldNameTuple!int == TypeTuple!"");
}
unittest
{
static assert(FieldNameTuple!int == TypeTuple!"");
static struct StaticStruct1 { }
static assert(is(FieldNameTuple!StaticStruct1 == TypeTuple!()));
static struct StaticStruct2 { int a, b; }
static assert(FieldNameTuple!StaticStruct2 == TypeTuple!("a", "b"));
int i;
struct NestedStruct1 { void f() { ++i; } }
static assert(is(FieldNameTuple!NestedStruct1 == TypeTuple!()));
struct NestedStruct2 { int a; void f() { ++i; } }
static assert(FieldNameTuple!NestedStruct2 == TypeTuple!"a");
class NestedClass { int a; void f() { ++i; } }
static assert(FieldNameTuple!NestedClass == TypeTuple!"a");
}
/***
Get the primitive types of the fields of a struct or class, in
topological order.
*/
template RepresentationTypeTuple(T)
{
template Impl(T...)
{
static if (T.length == 0)
{
alias Impl = TypeTuple!();
}
else
{
import std.typecons : Rebindable;
static if (is(T[0] R: Rebindable!R))
{
alias Impl = Impl!(Impl!R, T[1 .. $]);
}
else static if (is(T[0] == struct) || is(T[0] == union))
{
// @@@BUG@@@ this should work
//alias .RepresentationTypes!(T[0].tupleof)
// RepresentationTypes;
alias Impl = Impl!(FieldTypeTuple!(T[0]), T[1 .. $]);
}
else
{
alias Impl = TypeTuple!(T[0], Impl!(T[1 .. $]));
}
}
}
static if (is(T == struct) || is(T == union) || is(T == class))
{
alias RepresentationTypeTuple = Impl!(FieldTypeTuple!T);
}
else
{
alias RepresentationTypeTuple = Impl!T;
}
}
///
unittest
{
struct S1 { int a; float b; }
struct S2 { char[] a; union { S1 b; S1 * c; } }
alias R = RepresentationTypeTuple!S2;
assert(R.length == 4
&& is(R[0] == char[]) && is(R[1] == int)
&& is(R[2] == float) && is(R[3] == S1*));
}
unittest
{
alias S1 = RepresentationTypeTuple!int;
static assert(is(S1 == TypeTuple!int));
struct S2 { int a; }
struct S3 { int a; char b; }
struct S4 { S1 a; int b; S3 c; }
static assert(is(RepresentationTypeTuple!S2 == TypeTuple!int));
static assert(is(RepresentationTypeTuple!S3 == TypeTuple!(int, char)));
static assert(is(RepresentationTypeTuple!S4 == TypeTuple!(int, int, int, char)));
struct S11 { int a; float b; }
struct S21 { char[] a; union { S11 b; S11 * c; } }
alias R = RepresentationTypeTuple!S21;
assert(R.length == 4
&& is(R[0] == char[]) && is(R[1] == int)
&& is(R[2] == float) && is(R[3] == S11*));
class C { int a; float b; }
alias R1 = RepresentationTypeTuple!C;
static assert(R1.length == 2 && is(R1[0] == int) && is(R1[1] == float));
/* Issue 6642 */
import std.typecons : Rebindable;
struct S5 { int a; Rebindable!(immutable Object) b; }
alias R2 = RepresentationTypeTuple!S5;
static assert(R2.length == 2 && is(R2[0] == int) && is(R2[1] == immutable(Object)));
}
/*
Statically evaluates to $(D true) if and only if $(D T)'s
representation contains at least one field of pointer or array type.
Members of class types are not considered raw pointers. Pointers to
immutable objects are not considered raw aliasing.
*/
private template hasRawAliasing(T...)
{
template Impl(T...)
{
static if (T.length == 0)
{
enum Impl = false;
}
else
{
static if (is(T[0] foo : U*, U) && !isFunctionPointer!(T[0]))
enum has = !is(U == immutable);
else static if (is(T[0] foo : U[], U) && !isStaticArray!(T[0]))
enum has = !is(U == immutable);
else static if (isAssociativeArray!(T[0]))
enum has = !is(T[0] == immutable);
else
enum has = false;
enum Impl = has || Impl!(T[1 .. $]);
}
}
enum hasRawAliasing = Impl!(RepresentationTypeTuple!T);
}
///
unittest
{
// simple types
static assert(!hasRawAliasing!int);
static assert( hasRawAliasing!(char*));
// references aren't raw pointers
static assert(!hasRawAliasing!Object);
// built-in arrays do contain raw pointers
static assert( hasRawAliasing!(int[]));
// aggregate of simple types
struct S1 { int a; double b; }
static assert(!hasRawAliasing!S1);
// indirect aggregation
struct S2 { S1 a; double b; }
static assert(!hasRawAliasing!S2);
}
unittest
{
// struct with a pointer member
struct S3 { int a; double * b; }
static assert( hasRawAliasing!S3);
// struct with an indirect pointer member
struct S4 { S3 a; double b; }
static assert( hasRawAliasing!S4);
struct S5 { int a; Object z; int c; }
static assert( hasRawAliasing!S3);
static assert( hasRawAliasing!S4);
static assert(!hasRawAliasing!S5);
union S6 { int a; int b; }
union S7 { int a; int * b; }
static assert(!hasRawAliasing!S6);
static assert( hasRawAliasing!S7);
static assert(!hasRawAliasing!(void delegate()));
static assert(!hasRawAliasing!(void delegate() const));
static assert(!hasRawAliasing!(void delegate() immutable));
static assert(!hasRawAliasing!(void delegate() shared));
static assert(!hasRawAliasing!(void delegate() shared const));
static assert(!hasRawAliasing!(const(void delegate())));
static assert(!hasRawAliasing!(immutable(void delegate())));
struct S8 { void delegate() a; int b; Object c; }
class S12 { typeof(S8.tupleof) a; }
class S13 { typeof(S8.tupleof) a; int* b; }
static assert(!hasRawAliasing!S8);
static assert(!hasRawAliasing!S12);
static assert( hasRawAliasing!S13);
enum S9 { a }
static assert(!hasRawAliasing!S9);
// indirect members
struct S10 { S7 a; int b; }
struct S11 { S6 a; int b; }
static assert( hasRawAliasing!S10);
static assert(!hasRawAliasing!S11);
static assert( hasRawAliasing!(int[string]));
static assert(!hasRawAliasing!(immutable(int[string])));
}
/*
Statically evaluates to $(D true) if and only if $(D T)'s
representation contains at least one non-shared field of pointer or
array type. Members of class types are not considered raw pointers.
Pointers to immutable objects are not considered raw aliasing.
*/
private template hasRawUnsharedAliasing(T...)
{
template Impl(T...)
{
static if (T.length == 0)
{
enum Impl = false;
}
else
{
static if (is(T[0] foo : U*, U) && !isFunctionPointer!(T[0]))
enum has = !is(U == immutable) && !is(U == shared);
else static if (is(T[0] foo : U[], U) && !isStaticArray!(T[0]))
enum has = !is(U == immutable) && !is(U == shared);
else static if (isAssociativeArray!(T[0]))
enum has = !is(T[0] == immutable) && !is(T[0] == shared);
else
enum has = false;
enum Impl = has || Impl!(T[1 .. $]);
}
}
enum hasRawUnsharedAliasing = Impl!(RepresentationTypeTuple!T);
}
///
unittest
{
// simple types
static assert(!hasRawUnsharedAliasing!int);
static assert( hasRawUnsharedAliasing!(char*));
static assert(!hasRawUnsharedAliasing!(shared char*));
// references aren't raw pointers
static assert(!hasRawUnsharedAliasing!Object);
// built-in arrays do contain raw pointers
static assert( hasRawUnsharedAliasing!(int[]));
static assert(!hasRawUnsharedAliasing!(shared int[]));
// aggregate of simple types
struct S1 { int a; double b; }
static assert(!hasRawUnsharedAliasing!S1);
// indirect aggregation
struct S2 { S1 a; double b; }
static assert(!hasRawUnsharedAliasing!S2);
// struct with a pointer member
struct S3 { int a; double * b; }
static assert( hasRawUnsharedAliasing!S3);
struct S4 { int a; shared double * b; }
static assert(!hasRawUnsharedAliasing!S4);
}
unittest
{
// struct with a pointer member
struct S3 { int a; double * b; }
static assert( hasRawUnsharedAliasing!S3);
struct S4 { int a; shared double * b; }
static assert(!hasRawUnsharedAliasing!S4);
// struct with an indirect pointer member
struct S5 { S3 a; double b; }
static assert( hasRawUnsharedAliasing!S5);
struct S6 { S4 a; double b; }
static assert(!hasRawUnsharedAliasing!S6);
struct S7 { int a; Object z; int c; }
static assert( hasRawUnsharedAliasing!S5);
static assert(!hasRawUnsharedAliasing!S6);
static assert(!hasRawUnsharedAliasing!S7);
union S8 { int a; int b; }
union S9 { int a; int* b; }
union S10 { int a; shared int* b; }
static assert(!hasRawUnsharedAliasing!S8);
static assert( hasRawUnsharedAliasing!S9);
static assert(!hasRawUnsharedAliasing!S10);
static assert(!hasRawUnsharedAliasing!(void delegate()));
static assert(!hasRawUnsharedAliasing!(void delegate() const));
static assert(!hasRawUnsharedAliasing!(void delegate() immutable));
static assert(!hasRawUnsharedAliasing!(void delegate() shared));
static assert(!hasRawUnsharedAliasing!(void delegate() shared const));
static assert(!hasRawUnsharedAliasing!(const(void delegate())));
static assert(!hasRawUnsharedAliasing!(const(void delegate() const)));
static assert(!hasRawUnsharedAliasing!(const(void delegate() immutable)));
static assert(!hasRawUnsharedAliasing!(const(void delegate() shared)));
static assert(!hasRawUnsharedAliasing!(const(void delegate() shared const)));
static assert(!hasRawUnsharedAliasing!(immutable(void delegate())));
static assert(!hasRawUnsharedAliasing!(immutable(void delegate() const)));
static assert(!hasRawUnsharedAliasing!(immutable(void delegate() immutable)));
static assert(!hasRawUnsharedAliasing!(immutable(void delegate() shared)));
static assert(!hasRawUnsharedAliasing!(immutable(void delegate() shared const)));
static assert(!hasRawUnsharedAliasing!(shared(void delegate())));
static assert(!hasRawUnsharedAliasing!(shared(void delegate() const)));
static assert(!hasRawUnsharedAliasing!(shared(void delegate() immutable)));
static assert(!hasRawUnsharedAliasing!(shared(void delegate() shared)));
static assert(!hasRawUnsharedAliasing!(shared(void delegate() shared const)));
static assert(!hasRawUnsharedAliasing!(shared(const(void delegate()))));
static assert(!hasRawUnsharedAliasing!(shared(const(void delegate() const))));
static assert(!hasRawUnsharedAliasing!(shared(const(void delegate() immutable))));
static assert(!hasRawUnsharedAliasing!(shared(const(void delegate() shared))));
static assert(!hasRawUnsharedAliasing!(shared(const(void delegate() shared const))));
static assert(!hasRawUnsharedAliasing!(void function()));
enum S13 { a }
static assert(!hasRawUnsharedAliasing!S13);
// indirect members
struct S14 { S9 a; int b; }
struct S15 { S10 a; int b; }
struct S16 { S6 a; int b; }
static assert( hasRawUnsharedAliasing!S14);
static assert(!hasRawUnsharedAliasing!S15);
static assert(!hasRawUnsharedAliasing!S16);
static assert( hasRawUnsharedAliasing!(int[string]));
static assert(!hasRawUnsharedAliasing!(shared(int[string])));
static assert(!hasRawUnsharedAliasing!(immutable(int[string])));
struct S17
{
void delegate() shared a;
void delegate() immutable b;
void delegate() shared const c;
shared(void delegate()) d;
shared(void delegate() shared) e;
shared(void delegate() immutable) f;
shared(void delegate() shared const) g;
immutable(void delegate()) h;
immutable(void delegate() shared) i;
immutable(void delegate() immutable) j;
immutable(void delegate() shared const) k;
shared(const(void delegate())) l;
shared(const(void delegate() shared)) m;
shared(const(void delegate() immutable)) n;
shared(const(void delegate() shared const)) o;
}
struct S18 { typeof(S17.tupleof) a; void delegate() p; }
struct S19 { typeof(S17.tupleof) a; Object p; }
struct S20 { typeof(S17.tupleof) a; int* p; }
class S21 { typeof(S17.tupleof) a; }
class S22 { typeof(S17.tupleof) a; void delegate() p; }
class S23 { typeof(S17.tupleof) a; Object p; }
class S24 { typeof(S17.tupleof) a; int* p; }
static assert(!hasRawUnsharedAliasing!S17);
static assert(!hasRawUnsharedAliasing!(immutable(S17)));
static assert(!hasRawUnsharedAliasing!(shared(S17)));
static assert(!hasRawUnsharedAliasing!S18);
static assert(!hasRawUnsharedAliasing!(immutable(S18)));
static assert(!hasRawUnsharedAliasing!(shared(S18)));
static assert(!hasRawUnsharedAliasing!S19);
static assert(!hasRawUnsharedAliasing!(immutable(S19)));
static assert(!hasRawUnsharedAliasing!(shared(S19)));
static assert( hasRawUnsharedAliasing!S20);
static assert(!hasRawUnsharedAliasing!(immutable(S20)));
static assert(!hasRawUnsharedAliasing!(shared(S20)));
static assert(!hasRawUnsharedAliasing!S21);
static assert(!hasRawUnsharedAliasing!(immutable(S21)));
static assert(!hasRawUnsharedAliasing!(shared(S21)));
static assert(!hasRawUnsharedAliasing!S22);
static assert(!hasRawUnsharedAliasing!(immutable(S22)));
static assert(!hasRawUnsharedAliasing!(shared(S22)));
static assert(!hasRawUnsharedAliasing!S23);
static assert(!hasRawUnsharedAliasing!(immutable(S23)));
static assert(!hasRawUnsharedAliasing!(shared(S23)));
static assert( hasRawUnsharedAliasing!S24);
static assert(!hasRawUnsharedAliasing!(immutable(S24)));
static assert(!hasRawUnsharedAliasing!(shared(S24)));
struct S25 {}
class S26 {}
interface S27 {}
union S28 {}
static assert(!hasRawUnsharedAliasing!S25);
static assert(!hasRawUnsharedAliasing!S26);
static assert(!hasRawUnsharedAliasing!S27);
static assert(!hasRawUnsharedAliasing!S28);
}
/*
Statically evaluates to $(D true) if and only if $(D T)'s
representation includes at least one non-immutable object reference.
*/
private template hasObjects(T...)
{
static if (T.length == 0)
{
enum hasObjects = false;
}
else static if (is(T[0] == struct))
{
enum hasObjects = hasObjects!(
RepresentationTypeTuple!(T[0]), T[1 .. $]);
}
else
{
enum hasObjects = ((is(T[0] == class) || is(T[0] == interface))
&& !is(T[0] == immutable)) || hasObjects!(T[1 .. $]);
}
}
/*
Statically evaluates to $(D true) if and only if $(D T)'s
representation includes at least one non-immutable non-shared object
reference.
*/
private template hasUnsharedObjects(T...)
{
static if (T.length == 0)
{
enum hasUnsharedObjects = false;
}
else static if (is(T[0] == struct))
{
enum hasUnsharedObjects = hasUnsharedObjects!(
RepresentationTypeTuple!(T[0]), T[1 .. $]);
}
else
{
enum hasUnsharedObjects = ((is(T[0] == class) || is(T[0] == interface)) &&
!is(T[0] == immutable) && !is(T[0] == shared)) ||
hasUnsharedObjects!(T[1 .. $]);
}
}
/**
Returns $(D true) if and only if $(D T)'s representation includes at
least one of the following: $(OL $(LI a raw pointer $(D U*) and $(D U)
is not immutable;) $(LI an array $(D U[]) and $(D U) is not
immutable;) $(LI a reference to a class or interface type $(D C) and $(D C) is
not immutable.) $(LI an associative array that is not immutable.)
$(LI a delegate.))
*/
template hasAliasing(T...)
{
import std.typecons : Rebindable;
static if (T.length && is(T[0] : Rebindable!R, R))
{
enum hasAliasing = hasAliasing!(R, T[1 .. $]);
}
else
{
template isAliasingDelegate(T)
{
enum isAliasingDelegate = isDelegate!T
&& !is(T == immutable)
&& !is(FunctionTypeOf!T == immutable);
}
enum hasAliasing = hasRawAliasing!T || hasObjects!T ||
anySatisfy!(isAliasingDelegate, T, RepresentationTypeTuple!T);
}
}
///
unittest
{
struct S1 { int a; Object b; }
struct S2 { string a; }
struct S3 { int a; immutable Object b; }
struct S4 { float[3] vals; }
static assert( hasAliasing!S1);
static assert(!hasAliasing!S2);
static assert(!hasAliasing!S3);
static assert(!hasAliasing!S4);
}
unittest
{
static assert( hasAliasing!(uint[uint]));
static assert(!hasAliasing!(immutable(uint[uint])));
static assert( hasAliasing!(void delegate()));
static assert( hasAliasing!(void delegate() const));
static assert(!hasAliasing!(void delegate() immutable));
static assert( hasAliasing!(void delegate() shared));
static assert( hasAliasing!(void delegate() shared const));
static assert( hasAliasing!(const(void delegate())));
static assert( hasAliasing!(const(void delegate() const)));
static assert(!hasAliasing!(const(void delegate() immutable)));
static assert( hasAliasing!(const(void delegate() shared)));
static assert( hasAliasing!(const(void delegate() shared const)));
static assert(!hasAliasing!(immutable(void delegate())));
static assert(!hasAliasing!(immutable(void delegate() const)));
static assert(!hasAliasing!(immutable(void delegate() immutable)));
static assert(!hasAliasing!(immutable(void delegate() shared)));
static assert(!hasAliasing!(immutable(void delegate() shared const)));
static assert( hasAliasing!(shared(const(void delegate()))));
static assert( hasAliasing!(shared(const(void delegate() const))));
static assert(!hasAliasing!(shared(const(void delegate() immutable))));
static assert( hasAliasing!(shared(const(void delegate() shared))));
static assert( hasAliasing!(shared(const(void delegate() shared const))));
static assert(!hasAliasing!(void function()));
interface I;
static assert( hasAliasing!I);
import std.typecons : Rebindable;
static assert( hasAliasing!(Rebindable!(const Object)));
static assert(!hasAliasing!(Rebindable!(immutable Object)));
static assert( hasAliasing!(Rebindable!(shared Object)));
static assert( hasAliasing!(Rebindable!Object));
struct S5
{
void delegate() immutable b;
shared(void delegate() immutable) f;
immutable(void delegate() immutable) j;
shared(const(void delegate() immutable)) n;
}
struct S6 { typeof(S5.tupleof) a; void delegate() p; }
static assert(!hasAliasing!S5);
static assert( hasAliasing!S6);
struct S7 { void delegate() a; int b; Object c; }
class S8 { int a; int b; }
class S9 { typeof(S8.tupleof) a; }
class S10 { typeof(S8.tupleof) a; int* b; }
static assert( hasAliasing!S7);
static assert( hasAliasing!S8);
static assert( hasAliasing!S9);
static assert( hasAliasing!S10);
struct S11 {}
class S12 {}
interface S13 {}
union S14 {}
static assert(!hasAliasing!S11);
static assert( hasAliasing!S12);
static assert( hasAliasing!S13);
static assert(!hasAliasing!S14);
}
/**
Returns $(D true) if and only if $(D T)'s representation includes at
least one of the following: $(OL $(LI a raw pointer $(D U*);) $(LI an
array $(D U[]);) $(LI a reference to a class type $(D C).)
$(LI an associative array.) $(LI a delegate.))
*/
template hasIndirections(T)
{
static if (is(T == struct) || is(T == union))
enum hasIndirections = anySatisfy!(.hasIndirections, FieldTypeTuple!T);
else static if (isStaticArray!T && is(T : E[N], E, size_t N))
enum hasIndirections = is(E == void) ? true : hasIndirections!E;
else static if (isFunctionPointer!T)
enum hasIndirections = false;
else
enum hasIndirections = isPointer!T || isDelegate!T || isDynamicArray!T ||
isAssociativeArray!T || is (T == class) || is(T == interface);
}
///
unittest
{
static assert( hasIndirections!(int[string]));
static assert( hasIndirections!(void delegate()));
static assert( hasIndirections!(void delegate() immutable));
static assert( hasIndirections!(immutable(void delegate())));
static assert( hasIndirections!(immutable(void delegate() immutable)));
static assert(!hasIndirections!(void function()));
static assert( hasIndirections!(void*[1]));
static assert(!hasIndirections!(byte[1]));
}
unittest
{
// void static array hides actual type of bits, so "may have indirections".
static assert( hasIndirections!(void[1]));
interface I {}
struct S1 {}
struct S2 { int a; }
struct S3 { int a; int b; }
struct S4 { int a; int* b; }
struct S5 { int a; Object b; }
struct S6 { int a; string b; }
struct S7 { int a; immutable Object b; }
struct S8 { int a; immutable I b; }
struct S9 { int a; void delegate() b; }
struct S10 { int a; immutable(void delegate()) b; }
struct S11 { int a; void delegate() immutable b; }
struct S12 { int a; immutable(void delegate() immutable) b; }
class S13 {}
class S14 { int a; }
class S15 { int a; int b; }
class S16 { int a; Object b; }
class S17 { string a; }
class S18 { int a; immutable Object b; }
class S19 { int a; immutable(void delegate() immutable) b; }
union S20 {}
union S21 { int a; }
union S22 { int a; int b; }
union S23 { int a; Object b; }
union S24 { string a; }
union S25 { int a; immutable Object b; }
union S26 { int a; immutable(void delegate() immutable) b; }
static assert( hasIndirections!I);
static assert(!hasIndirections!S1);
static assert(!hasIndirections!S2);
static assert(!hasIndirections!S3);
static assert( hasIndirections!S4);
static assert( hasIndirections!S5);
static assert( hasIndirections!S6);
static assert( hasIndirections!S7);
static assert( hasIndirections!S8);
static assert( hasIndirections!S9);
static assert( hasIndirections!S10);
static assert( hasIndirections!S12);
static assert( hasIndirections!S13);
static assert( hasIndirections!S14);
static assert( hasIndirections!S15);
static assert( hasIndirections!S16);
static assert( hasIndirections!S17);
static assert( hasIndirections!S18);
static assert( hasIndirections!S19);
static assert(!hasIndirections!S20);
static assert(!hasIndirections!S21);
static assert(!hasIndirections!S22);
static assert( hasIndirections!S23);
static assert( hasIndirections!S24);
static assert( hasIndirections!S25);
static assert( hasIndirections!S26);
}
unittest //12000
{
static struct S(T)
{
static assert(hasIndirections!T);
}
static class A(T)
{
S!A a;
}
A!int dummy;
}
/**
Returns $(D true) if and only if $(D T)'s representation includes at
least one of the following: $(OL $(LI a raw pointer $(D U*) and $(D U)
is not immutable or shared;) $(LI an array $(D U[]) and $(D U) is not
immutable or shared;) $(LI a reference to a class type $(D C) and
$(D C) is not immutable or shared.) $(LI an associative array that is not
immutable or shared.) $(LI a delegate that is not shared.))
*/
template hasUnsharedAliasing(T...)
{
import std.typecons : Rebindable;
static if (!T.length)
{
enum hasUnsharedAliasing = false;
}
else static if (is(T[0] R: Rebindable!R))
{
enum hasUnsharedAliasing = hasUnsharedAliasing!R;
}
else
{
template unsharedDelegate(T)
{
enum bool unsharedDelegate = isDelegate!T
&& !is(T == shared)
&& !is(T == shared)
&& !is(T == immutable)
&& !is(FunctionTypeOf!T == shared)
&& !is(FunctionTypeOf!T == immutable);
}
enum hasUnsharedAliasing =
hasRawUnsharedAliasing!(T[0]) ||
anySatisfy!(unsharedDelegate, RepresentationTypeTuple!(T[0])) ||
hasUnsharedObjects!(T[0]) ||
hasUnsharedAliasing!(T[1..$]);
}
}
///
unittest
{
struct S1 { int a; Object b; }
struct S2 { string a; }
struct S3 { int a; immutable Object b; }
static assert( hasUnsharedAliasing!S1);
static assert(!hasUnsharedAliasing!S2);
static assert(!hasUnsharedAliasing!S3);
struct S4 { int a; shared Object b; }
struct S5 { char[] a; }
struct S6 { shared char[] b; }
struct S7 { float[3] vals; }
static assert(!hasUnsharedAliasing!S4);
static assert( hasUnsharedAliasing!S5);
static assert(!hasUnsharedAliasing!S6);
static assert(!hasUnsharedAliasing!S7);
}
unittest
{
/* Issue 6642 */
import std.typecons : Rebindable;
struct S8 { int a; Rebindable!(immutable Object) b; }
static assert(!hasUnsharedAliasing!S8);
static assert( hasUnsharedAliasing!(uint[uint]));
static assert( hasUnsharedAliasing!(void delegate()));
static assert( hasUnsharedAliasing!(void delegate() const));
static assert(!hasUnsharedAliasing!(void delegate() immutable));
static assert(!hasUnsharedAliasing!(void delegate() shared));
static assert(!hasUnsharedAliasing!(void delegate() shared const));
}
unittest
{
import std.typecons : Rebindable;
static assert( hasUnsharedAliasing!(const(void delegate())));
static assert( hasUnsharedAliasing!(const(void delegate() const)));
static assert(!hasUnsharedAliasing!(const(void delegate() immutable)));
static assert(!hasUnsharedAliasing!(const(void delegate() shared)));
static assert(!hasUnsharedAliasing!(const(void delegate() shared const)));
static assert(!hasUnsharedAliasing!(immutable(void delegate())));
static assert(!hasUnsharedAliasing!(immutable(void delegate() const)));
static assert(!hasUnsharedAliasing!(immutable(void delegate() immutable)));
static assert(!hasUnsharedAliasing!(immutable(void delegate() shared)));
static assert(!hasUnsharedAliasing!(immutable(void delegate() shared const)));
static assert(!hasUnsharedAliasing!(shared(void delegate())));
static assert(!hasUnsharedAliasing!(shared(void delegate() const)));
static assert(!hasUnsharedAliasing!(shared(void delegate() immutable)));
static assert(!hasUnsharedAliasing!(shared(void delegate() shared)));
static assert(!hasUnsharedAliasing!(shared(void delegate() shared const)));
static assert(!hasUnsharedAliasing!(shared(const(void delegate()))));
static assert(!hasUnsharedAliasing!(shared(const(void delegate() const))));
static assert(!hasUnsharedAliasing!(shared(const(void delegate() immutable))));
static assert(!hasUnsharedAliasing!(shared(const(void delegate() shared))));
static assert(!hasUnsharedAliasing!(shared(const(void delegate() shared const))));
static assert(!hasUnsharedAliasing!(void function()));
interface I {}
static assert(hasUnsharedAliasing!I);
static assert( hasUnsharedAliasing!(Rebindable!(const Object)));
static assert(!hasUnsharedAliasing!(Rebindable!(immutable Object)));
static assert(!hasUnsharedAliasing!(Rebindable!(shared Object)));
static assert( hasUnsharedAliasing!(Rebindable!Object));
/* Issue 6979 */
static assert(!hasUnsharedAliasing!(int, shared(int)*));
static assert( hasUnsharedAliasing!(int, int*));
static assert( hasUnsharedAliasing!(int, const(int)[]));
static assert( hasUnsharedAliasing!(int, shared(int)*, Rebindable!Object));
static assert(!hasUnsharedAliasing!(shared(int)*, Rebindable!(shared Object)));
static assert(!hasUnsharedAliasing!());
struct S9
{
void delegate() shared a;
void delegate() immutable b;
void delegate() shared const c;
shared(void delegate()) d;
shared(void delegate() shared) e;
shared(void delegate() immutable) f;
shared(void delegate() shared const) g;
immutable(void delegate()) h;
immutable(void delegate() shared) i;
immutable(void delegate() immutable) j;
immutable(void delegate() shared const) k;
shared(const(void delegate())) l;
shared(const(void delegate() shared)) m;
shared(const(void delegate() immutable)) n;
shared(const(void delegate() shared const)) o;
}
struct S10 { typeof(S9.tupleof) a; void delegate() p; }
struct S11 { typeof(S9.tupleof) a; Object p; }
struct S12 { typeof(S9.tupleof) a; int* p; }
class S13 { typeof(S9.tupleof) a; }
class S14 { typeof(S9.tupleof) a; void delegate() p; }
class S15 { typeof(S9.tupleof) a; Object p; }
class S16 { typeof(S9.tupleof) a; int* p; }
static assert(!hasUnsharedAliasing!S9);
static assert(!hasUnsharedAliasing!(immutable(S9)));
static assert(!hasUnsharedAliasing!(shared(S9)));
static assert( hasUnsharedAliasing!S10);
static assert(!hasUnsharedAliasing!(immutable(S10)));
static assert(!hasUnsharedAliasing!(shared(S10)));
static assert( hasUnsharedAliasing!S11);
static assert(!hasUnsharedAliasing!(immutable(S11)));
static assert(!hasUnsharedAliasing!(shared(S11)));
static assert( hasUnsharedAliasing!S12);
static assert(!hasUnsharedAliasing!(immutable(S12)));
static assert(!hasUnsharedAliasing!(shared(S12)));
static assert( hasUnsharedAliasing!S13);
static assert(!hasUnsharedAliasing!(immutable(S13)));
static assert(!hasUnsharedAliasing!(shared(S13)));
static assert( hasUnsharedAliasing!S14);
static assert(!hasUnsharedAliasing!(immutable(S14)));
static assert(!hasUnsharedAliasing!(shared(S14)));
static assert( hasUnsharedAliasing!S15);
static assert(!hasUnsharedAliasing!(immutable(S15)));
static assert(!hasUnsharedAliasing!(shared(S15)));
static assert( hasUnsharedAliasing!S16);
static assert(!hasUnsharedAliasing!(immutable(S16)));
static assert(!hasUnsharedAliasing!(shared(S16)));
struct S17 {}
class S18 {}
interface S19 {}
union S20 {}
static assert(!hasUnsharedAliasing!S17);
static assert( hasUnsharedAliasing!S18);
static assert( hasUnsharedAliasing!S19);
static assert(!hasUnsharedAliasing!S20);
}
/**
True if $(D S) or any type embedded directly in the representation of $(D S)
defines an elaborate copy constructor. Elaborate copy constructors are
introduced by defining $(D this(this)) for a $(D struct).
Classes and unions never have elaborate copy constructors.
*/
template hasElaborateCopyConstructor(S)
{
static if(isStaticArray!S && S.length)
{
enum bool hasElaborateCopyConstructor = hasElaborateCopyConstructor!(typeof(S.init[0]));
}
else static if(is(S == struct))
{
enum hasElaborateCopyConstructor = hasMember!(S, "__postblit")
|| anySatisfy!(.hasElaborateCopyConstructor, FieldTypeTuple!S);
}
else
{
enum bool hasElaborateCopyConstructor = false;
}
}
///
unittest
{
static assert(!hasElaborateCopyConstructor!int);
static struct S1 { }
static struct S2 { this(this) {} }
static struct S3 { S2 field; }
static struct S4 { S3[1] field; }
static struct S5 { S3[] field; }
static struct S6 { S3[0] field; }
static struct S7 { @disable this(); S3 field; }
static assert(!hasElaborateCopyConstructor!S1);
static assert( hasElaborateCopyConstructor!S2);
static assert( hasElaborateCopyConstructor!(immutable S2));
static assert( hasElaborateCopyConstructor!S3);
static assert( hasElaborateCopyConstructor!(S3[1]));
static assert(!hasElaborateCopyConstructor!(S3[0]));
static assert( hasElaborateCopyConstructor!S4);
static assert(!hasElaborateCopyConstructor!S5);
static assert(!hasElaborateCopyConstructor!S6);
static assert( hasElaborateCopyConstructor!S7);
}
/**
True if $(D S) or any type directly embedded in the representation of $(D S)
defines an elaborate assignment. Elaborate assignments are introduced by
defining $(D opAssign(typeof(this))) or $(D opAssign(ref typeof(this)))
for a $(D struct) or when there is a compiler-generated $(D opAssign).
A type $(D S) gets compiler-generated $(D opAssign) in case it has
an elaborate copy constructor or elaborate destructor.
Classes and unions never have elaborate assignments.
Note: Structs with (possibly nested) postblit operator(s) will have a
hidden yet elaborate compiler generated assignment operator (unless
explicitly disabled).
*/
template hasElaborateAssign(S)
{
static if(isStaticArray!S && S.length)
{
enum bool hasElaborateAssign = hasElaborateAssign!(typeof(S.init[0]));
}
else static if(is(S == struct))
{
enum hasElaborateAssign = is(typeof(S.init.opAssign(rvalueOf!S))) ||
is(typeof(S.init.opAssign(lvalueOf!S))) ||
anySatisfy!(.hasElaborateAssign, FieldTypeTuple!S);
}
else
{
enum bool hasElaborateAssign = false;
}
}
///
unittest
{
static assert(!hasElaborateAssign!int);
static struct S { void opAssign(S) {} }
static assert( hasElaborateAssign!S);
static assert(!hasElaborateAssign!(const(S)));
static struct S1 { void opAssign(ref S1) {} }
static struct S2 { void opAssign(int) {} }
static struct S3 { S s; }
static assert( hasElaborateAssign!S1);
static assert(!hasElaborateAssign!S2);
static assert( hasElaborateAssign!S3);
static assert( hasElaborateAssign!(S3[1]));
static assert(!hasElaborateAssign!(S3[0]));
}
unittest
{
static struct S { void opAssign(S) {} }
static struct S4
{
void opAssign(U)(U u) {}
@disable void opAssign(U)(ref U u);
}
static assert( hasElaborateAssign!S4);
static struct S41
{
void opAssign(U)(ref U u) {}
@disable void opAssign(U)(U u);
}
static assert( hasElaborateAssign!S41);
static struct S5 { @disable this(); this(int n){ s = S(); } S s; }
static assert( hasElaborateAssign!S5);
static struct S6 { this(this) {} }
static struct S7 { this(this) {} @disable void opAssign(S7); }
static struct S8 { this(this) {} @disable void opAssign(S8); void opAssign(int) {} }
static struct S9 { this(this) {} void opAssign(int) {} }
static struct S10 { ~this() { } }
static assert( hasElaborateAssign!S6);
static assert(!hasElaborateAssign!S7);
static assert(!hasElaborateAssign!S8);
static assert( hasElaborateAssign!S9);
static assert( hasElaborateAssign!S10);
static struct SS6 { S6 s; }
static struct SS7 { S7 s; }
static struct SS8 { S8 s; }
static struct SS9 { S9 s; }
static assert( hasElaborateAssign!SS6);
static assert( hasElaborateAssign!SS7);
static assert( hasElaborateAssign!SS8);
static assert( hasElaborateAssign!SS9);
}
/**
True if $(D S) or any type directly embedded in the representation
of $(D S) defines an elaborate destructor. Elaborate destructors
are introduced by defining $(D ~this()) for a $(D
struct).
Classes and unions never have elaborate destructors, even
though classes may define $(D ~this()).
*/
template hasElaborateDestructor(S)
{
static if(isStaticArray!S && S.length)
{
enum bool hasElaborateDestructor = hasElaborateDestructor!(typeof(S.init[0]));
}
else static if(is(S == struct))
{
enum hasElaborateDestructor = hasMember!(S, "__dtor")
|| anySatisfy!(.hasElaborateDestructor, FieldTypeTuple!S);
}
else
{
enum bool hasElaborateDestructor = false;
}
}
///
unittest
{
static assert(!hasElaborateDestructor!int);
static struct S1 { }
static struct S2 { ~this() {} }
static struct S3 { S2 field; }
static struct S4 { S3[1] field; }
static struct S5 { S3[] field; }
static struct S6 { S3[0] field; }
static struct S7 { @disable this(); S3 field; }
static assert(!hasElaborateDestructor!S1);
static assert( hasElaborateDestructor!S2);
static assert( hasElaborateDestructor!(immutable S2));
static assert( hasElaborateDestructor!S3);
static assert( hasElaborateDestructor!(S3[1]));
static assert(!hasElaborateDestructor!(S3[0]));
static assert( hasElaborateDestructor!S4);
static assert(!hasElaborateDestructor!S5);
static assert(!hasElaborateDestructor!S6);
static assert( hasElaborateDestructor!S7);
}
alias Identity(alias A) = A;
/**
Yields $(D true) if and only if $(D T) is an aggregate that defines
a symbol called $(D name).
*/
template hasMember(T, string name)
{
static if (is(T == struct) || is(T == class) || is(T == union) || is(T == interface))
{
enum bool hasMember =
staticIndexOf!(name, __traits(allMembers, T)) != -1 ||
__traits(compiles, { mixin("alias Sym = Identity!(T."~name~");"); });
}
else
{
enum bool hasMember = false;
}
}
///
unittest
{
static assert(!hasMember!(int, "blah"));
struct S1 { int blah; }
struct S2 { int blah(){ return 0; } }
class C1 { int blah; }
class C2 { int blah(){ return 0; } }
static assert(hasMember!(S1, "blah"));
static assert(hasMember!(S2, "blah"));
static assert(hasMember!(C1, "blah"));
static assert(hasMember!(C2, "blah"));
}
unittest
{
// 8321
struct S {
int x;
void f(){}
void t()(){}
template T(){}
}
struct R1(T) {
T t;
alias t this;
}
struct R2(T) {
T t;
@property ref inout(T) payload() inout { return t; }
alias t this;
}
static assert(hasMember!(S, "x"));
static assert(hasMember!(S, "f"));
static assert(hasMember!(S, "t"));
static assert(hasMember!(S, "T"));
static assert(hasMember!(R1!S, "x"));
static assert(hasMember!(R1!S, "f"));
static assert(hasMember!(R1!S, "t"));
static assert(hasMember!(R1!S, "T"));
static assert(hasMember!(R2!S, "x"));
static assert(hasMember!(R2!S, "f"));
static assert(hasMember!(R2!S, "t"));
static assert(hasMember!(R2!S, "T"));
}
/**
Retrieves the members of an enumerated type $(D enum E).
Params:
E = An enumerated type. $(D E) may have duplicated values.
Returns:
Static tuple composed of the members of the enumerated type $(D E).
The members are arranged in the same order as declared in $(D E).
Note:
An enum can have multiple members which have the same value. If you want
to use EnumMembers to e.g. generate switch cases at compile-time,
you should use the $(XREF typetuple, NoDuplicates) template to avoid
generating duplicate switch cases.
Note:
Returned values are strictly typed with $(D E). Thus, the following code
does not work without the explicit cast:
--------------------
enum E : int { a, b, c }
int[] abc = cast(int[]) [ EnumMembers!E ];
--------------------
Cast is not necessary if the type of the variable is inferred. See the
example below.
Examples:
Creating an array of enumerated values:
--------------------
enum Sqrts : real
{
one = 1,