On type functions
Stefan Koch
uplink.coder at gmail.com
Thu May 7 13:26:36 UTC 2020
On Sunday, 3 May 2020 at 09:37:19 UTC, Stefan Koch wrote:
>
> The previous post of send before I was finished ... I hit enter
> by accident.
> anyways it should already give the gist of what I wanted to
> convey.
Here is how a simple FullyQualifiedName would look when written
as type function:
---
string fqn(alias t)
{
char[] result;
alias parent;
parent = t;
while(is(parent) || is(typeof(parent)))
{
result = __traits(identifier, parent) ~ "." ~ result;
parent = __traits(parent, parent);
}
return cast(string) result;
}
---
compare that with the phobos version below:
---
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]);
}
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)) &&
!__traits(isSame, T, __traits(parent, T)))
enum parentPrefix = fqnSym!(__traits(parent, T)) ~ ".";
else
enum parentPrefix = null;
static string adjustIdent(string s)
{
import std.algorithm.searching : findSplit, skipOver;
if (s.skipOver("package ") || s.skipOver("module "))
return s;
return s.findSplit("(")[0];
}
enum fqnSym = parentPrefix ~ adjustIdent(__traits(identifier,
T));
}
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 = AliasSeq!(is(T == const), is(T ==
immutable), is(T == shared), is(T == inout));
alias noQualifiers = AliasSeq!(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.iteration : map;
import std.array : join;
import std.meta : staticMap;
import std.range : 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)
{
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");
}
---
More information about the Digitalmars-d
mailing list