d避免的串的插件技巧

原文
我用了两个示例,来研究删除.stringof及减少一些串连接.
左边:

module dcompute.driver.ocl.util;

import std.range;
import std.meta;
import std.traits;

//单独处理数组,部分这样来避免窄串
@property auto memSize(R)(R r)
if (is(R : T[], T))
{
    static if (is(R : T[], T))
        return r.length * T.sizeof;
    else
        static assert(false);
}

@property auto memSize(R)(R r)
if(isInputRange!R && hasLength!R && !is(R : T[], T))
{
    return r.length * (ElementType!R).sizeof;
}

T[Args.length + 1] propertyList(T,Args...)(Args args)
{
    T[Args.length + 1] props;
    foreach(i, arg; args)
        props[i] = *cast(T*)(&arg);
    props[$-1] = cast(T)0;
    return props;
}

struct ArrayAccesssor(alias ptr, alias len) {}

struct StringzAccessor(alias ptr) {}

struct ZeroTerminatedArrayAccessor(alias ptr) {}

struct ArrayAccesssor2D(alias ptr, alias lens, alias len) {}

// ArrayAccesssor2D返回
struct RangeOfArray(T)
{
    T**     ptr;
    size_t* lengths;
    size_t  length;
    size_t  index;

    bool empty()
    {
        return index == length;
    }

    @property T[] front()
    {
        return ptr[index][0 .. lengths[index]];
    }

    T[] opIndex(size_t i)
    {
        return ptr[i][0 .. lengths[i]];
    }
    void popFront()
    {
        ++index;
    }

    @property size_t opDollar() { return length; }
}

string generateGetInfo(Info,alias func,string args = "raw")()
{
    import std.string;
    return helper!(Info.tupleof).format(func.stringof,args);
}

// 替代全名来加速编译
private template isModule(alias a) {
    static if (is(a) || is(typeof(a)) || a.stringof.length < 7) {
        enum isModule = false;
    } else {
        enum isModule = a.stringof[0..7] == "module ";
    }
}

private template partiallyQualifiedName(alias a) {
    static if (isModule!a) {
        enum partiallyQualifiedName = "";
    } else {
        static if (!isModule!(__traits(parent, a))) {
            enum prefix = partiallyQualifiedName!(__traits(parent, a)) ~ ".";
        } else {
            enum prefix = "";
        }
        enum partiallyQualifiedName = prefix ~ __traits(identifier, a);
    }
}

private template helper(Fields...)
{
    static if (Fields.length == 0)
        enum helper = "";

    else static if (is(typeof(Fields[0]) : ArrayAccesssor!(ptr,len),alias ptr,alias len))
    {
        enum helper = "@property " ~ typeof(*ptr).stringof ~ "[] " ~ Fields[0].stringof ~ "()\n" ~
            "{\n" ~
            "    return " ~ ptr.stringof ~ "[0 .. " ~ len.stringof ~"];"~
            "}\n" ~ helper!(Fields[1 .. $]);
    }
    else static if (is(typeof(Fields[0]) : StringzAccessor!ptr,alias ptr))
    {
        enum helper = "@property char[] " ~ Fields[0].stringof ~ "()\n" ~
            "{\n" ~
            "    import std.typecons; char[] ret;" ~
            "    size_t len;" ~
            "    %1$s(%2$s," ~ __traits(getAttributes, ptr).stringof ~ "[0], 0, null, &len);" ~
            "    ret.length = len;" ~
            "    %1$s(%2$s," ~ __traits(getAttributes, ptr).stringof ~ "[0], memSize(ret), ret.ptr, null);" ~
            "    return ret;" ~
            "}\n" ~ helper!(Fields[1 .. $]);
    }
    else static if (is(typeof(Fields[0]) : ArrayAccesssor2D!(ptr,lens,len) , alias ptr, alias lens, alias len))
    {
        enum helper = "@property RangeOfArray!(" ~ typeof(**ptr).stringof ~ ") " ~ Fields[0].stringof ~ "()\n" ~
            "{\n" ~
            "   import std.typecons; size_t length; size_t* lengths; " ~ typeof(ptr).stringof ~ " ptr;" ~
            "   %1$s(%2$s," ~ __traits(getAttributes, len).stringof ~ "[0],length.sizeof, &length,null);" ~
            "   lengths = (new size_t[length]).ptr; ptr = (new " ~ typeof(*ptr).stringof ~ "[length]).ptr;" ~
            "   %1$s(%2$s," ~ __traits(getAttributes, lens).stringof ~ "[0],lengths.sizeof, lengths,null);" ~
            "   if (lengths[length - 1] == 0) length--;" ~
            "   foreach(i; 0 .. length) \n{" ~
            "       ptr[i] = (new " ~ typeof(**ptr).stringof ~ "[lengths[i]]).ptr;" ~
            "   }\n" ~
            "   %1$s(%2$s," ~ __traits(getAttributes, ptr).stringof ~ "[0], ptr.sizeof, ptr, null);" ~
            "   return typeof(return)(ptr,lengths,length,0);" ~
            "}\n" ~ helper!(Fields[1 .. $]);
    }
    else
    {
        static if (is(typeof(Fields[0]) == enum))
        {
            enum helper = "@property " ~ partiallyQualifiedName!(typeof(Fields[0])) ~ " " ~ Fields[0].stringof ~ "()\n" ~
                "{\n" ~
                "    import std.typecons; typeof(return) ret;" ~
                "%1$s(%2$s,"~ __traits(getAttributes, Fields[0]).stringof ~ "[0], ret.sizeof, &ret, null);" ~
                "return ret; " ~
                "}\n" ~ helper!(Fields[1 .. $]);

        }
        else
        {
            enum helper = "@property " ~ typeof(Fields[0]).stringof ~ " " ~ Fields[0].stringof ~ "()\n" ~
                "{\n" ~
                "    import std.typecons; typeof(return) ret;" ~
                "%1$s(%2$s,"~ __traits(getAttributes, Fields[0]).stringof ~ "[0], ret.sizeof, &ret, null);" ~
                "return ret; " ~
                "}\n" ~ helper!(Fields[1 .. $]);
        }
    }
}

右边:

module dcompute.driver.ocl.util;

import std.range;
import std.meta;
import std.traits;
//同上
@property auto memSize(R)(R r)
if (is(R : T[], T))
{
    static if (is(R : T[], T))
        return r.length * T.sizeof;
    else
        static assert(false);
}

@property auto memSize(R)(R r)
if(isInputRange!R && hasLength!R && !is(R : T[], T))
{
    return r.length * (ElementType!R).sizeof;
}

T[Args.length + 1] propertyList(T,Args...)(Args args)
{
    T[Args.length + 1] props;
    foreach(i, arg; args)
        props[i] = *cast(T*)(&arg);
    props[$-1] = cast(T)0;
    return props;
}

struct ArrayAccesssor(alias ptr, alias len) {}

struct StringzAccessor(alias ptr) {}

struct ZeroTerminatedArrayAccessor(alias ptr) {}

struct ArrayAccesssor2D(alias ptr, alias lens, alias len) {}

// 同上
struct RangeOfArray(T)
{
    T**     ptr;
    size_t* lengths;
    size_t  length;
    size_t  index;

    bool empty()
    {
        return index == length;
    }

    @property T[] front()
    {
        return ptr[index][0 .. lengths[index]];
    }

    T[] opIndex(size_t i)
    {
        return ptr[i][0 .. lengths[i]];
    }
    void popFront()
    {
        ++index;
    }

    @property size_t opDollar() { return length; }
}

mixin template generateGetInfo(Info,alias func, args...)
{
    static foreach(Field; Info.tupleof) {
        mixin helper!(Field, Info, func, args);
    }
}

mixin template helper(alias Field, Info, alias func, args...)
{
    static if (is(typeof(Field) : ArrayAccesssor!(ptr,len),alias ptr,alias len))
    {
        mixin(q{@property typeof(*ptr)[] } ~ __traits(identifier, Field) ~ q{()
            {
                return ptr[0 .. len];
            }
        });
    }
    else static if (is(typeof(Field) : StringzAccessor!ptr,alias ptr))
    {
        mixin(q{@property char[] } ~ __traits(identifier, Field) ~ q{()
            {
                char[] ret;
                size_t len;
                func(args, __traits(getAttributes, ptr)[0], 0, null, &len);
                ret.length = len;
                func(args, __traits(getAttributes, ptr)[0], memSize(ret), ret.ptr, null);
                return ret;
            }
        });
    }
    else static if (is(typeof(Field) : ArrayAccesssor2D!(ptr,lens,len) , alias ptr, alias lens, alias len))
    {
        mixin(q{@property RangeOfArray!(typeof(**ptr)) } ~ __traits(identifier, Field) ~ q{()
            {
               size_t length; size_t* lengths; typeof(ptr) ptr;
               func(args, __traits(getAttributes, len)[0],length.sizeof, &length,null);
               lengths = (new size_t[length]).ptr; ptr = (new typeof(*ptr)[length]).ptr;
               func(args, __traits(getAttributes, lens)[0],lengths.sizeof, lengths,null);
               if (lengths[length - 1] == 0) length--;
               foreach(i; 0 .. length)
               {
                   ptr[i] = (new typeof(**ptr)[lengths[i]]).ptr;
               }
               func(args, __traits(getAttributes, ptr)[0], ptr.sizeof, ptr, null);
               return typeof(return)(ptr,lengths,length,0);
            }
        });
    }
    else
    {
        static if (is(typeof(Field) == enum))
        {
            mixin(q{@property typeof(Field) } ~ __traits(identifier, Field) ~ q{()
                {
                typeof(return) ret;
                func(args, __traits(getAttributes, Field)[0], ret.sizeof, &ret, null);
                return ret;
                }
            });
        }
        else
        {
            mixin(q{@property typeof(Field) } ~ __traits(identifier, Field) ~ q{()
                {
                typeof(return) ret;
                func(args, __traits(getAttributes, Field)[0], ret.sizeof, &ret, null);
                return ret;
                }
            });
        }
    }
}

左前,右后.调用点更改为使用mixin thing!(args)替代mixin(thing(args));.编译时间在最初的测试中减少超过70%.
还有个关于转发接口的:

interface ITest {
    void foo() @(4) @nogc;
    string bar(int a, int b) const;
    string bar(string s) nothrow;
}

class Impl :ITest {
    void foo() {import core.stdc.stdio; printf("foo\n");}
    string bar(int a, int b) const { return "lol"; }
    string bar(string s) { return "rofl"; }
}

class A : ITest {
    this() { member = new Impl;}

    ITest member;

    mixin ForwardInterfaceTo!(ITest, member);
}

mixin template ForwardInterfaceTo(IFace, alias member) {
    static foreach(memberName; __traits(allMembers, IFace))
    static foreach(idx, overload; __traits(getOverloads, IFace, memberName)) {
 //`stringof`可工作,很罕见,尽管
 //最好使用`to!string(idx)`或类似
        mixin("mixin helper!(overload, member) " ~ memberName ~ idx.stringof ~ ";");
 //来合并助手的重载集
 //如果不关心重载,这里就不需要`mixin 串`了,但是
 //这些需要`mixin`来连接,因为基本上都是`名字`
        mixin("alias " ~ memberName ~ " = " ~ memberName ~ idx.stringof ~ "." ~ memberName ~ ";");

     //可惜没有保罗的`mixin foo this;`.这并不是正确的,但它会掩盖美丽.
    }
}

string constness(alias member)() {
    string ret;
    foreach(attr; __traits(getFunctionAttributes, member))
        if(attr == "const" || attr == "immutable")
            ret = attr;
    return ret;
}

mixin template helper(alias member, alias forwardTo) {
    static if(is(typeof(member) ReturnType == return))
    static if(is(typeof(member) Params == __parameters))
    mixin(q{
        ReturnType
        // 必须连接名字
        } ~ __traits(identifier, member) ~ q{
        // 和常性
        (Params params) } ~ constness!member ~ q{
        @(__traits(getAttributes, member))
        {
            // 而不需要其它
            return __traits(child, __traits(child, this, forwardTo), member)(params);
        }
    });
}

void main() {
    import std.stdio;
    auto a = new A;
    a.foo();
    writeln(a.bar("foo"));
    writeln(a.bar(4, 3));
    pragma(msg, __traits(getAttributes, A.foo));
}

接口中支持重载有点丑陋,没有"之前"的代码可比较,两个研究总体思路是:
1,总是使用本地名.不要构建外部名,不要使用.stringoffullQualifiedName(全限定名)等等(除非在极少数时).一般,写~T.stringof~时,可简单地用T代替它.
2,使用插件模板来帮助隔离名字空间.在插件模板中可能需要反射信息,来避免静每一中的重定义错误.
3,使用内联串插件(即与mixin()代码在同一行开头的串,而不是从函数返回的),以便在需要它们匹配名时,更容易阅读错误消息.
4,尽量使用推导,来避免查询数据中的信息.

posted @   zjh6  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示