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,总是使用本地名
.不要构建外部名
,不要使用.stringof
或fullQualifiedName(全限定名)
等等(除非在极少数时).一般,写~T.stringof~
时,可简单
地用T
代替它.
2,使用插件模板
来帮助隔离名字空间
.在插件模板
中可能需要反射信息
,来避免静每一
中的重定义错误
.
3,使用内联串插件
(即与mixin()
代码在同一行开头
的串,而不是从函数
返回的串
),以便在需要它们
匹配名时,更容易阅读
错误消息.
4,尽量使用推导
,来避免查询数据
中的信息.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现