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