d无分配0终止串
原文
通过传递InputRange
而不是const(char)
给toCStringThen
来提供无分配0终止串
.
//version=AllowMalloc;//.1
auto toCStringThen(alias dg, Range)(Range src) /*nothrow*/ if (isInputRange!Range && !isInfinite!Range) {
const len = src.walkLength;
char[512] small = void;
version(AllowMalloc) {
import dmd.common.string : SmallBuffer;
auto sb = SmallBuffer!char(len + 1, small[]);
scope ptr = sb[];
} else {
enforce(len < small.length, format!"C串溢出"(len, small.length));
scope ptr = small[];
}
size_t i = 0;
foreach (char c; src)
ptr[i++] = c;
ptr[len] = '\0';
return dg(ptr);
}
void main() {
string path = "include/";
string name = "file";
string ext = ".ext";
auto filename = chain(path, name, ext);
filename.writeln;
filename.byChar.toCStringThen!(
(str) => printf("printf: {%s}\n", str.ptr)
);
}
可能需要清理符类型
,且如果允许分配
,还需要迭代两次
,而walkLength/chain()
的区间函数不是不抛
的.
见.1
,你不能两次
迭代真输入区间
.为此,你需要前向
区间.
你不需要迭代区间两次
:
//version=AllowMalloc;
auto toCStringThen(alias dg, Range)(Range src) /*nothrow*/ if (isInputRange!Range && !isInfinite!Range) {
char[10] small = void;
size_t i = 0;
while(!src.empty && i < small.length) {
small[i++] = src.front;
src.popFront;
}
if(i == small.length) {
version(AllowMalloc) {
import std.container.array;
Array!char large = small[];
large ~= src;
large ~= '\0';
return dg(large.data);
} else {
throw new Exception(
"C串缓冲溢出(%s >= %s)"
.format(i+src.walkLength, small.length-1)
);
}
} else {
small[i] = '\0';
return dg(small[0..i]);
}
}
可惜,如果区间
内容不适合小缓冲区
,此版本会多次
分配,但是可通过检测src
是否是前向区间
或是否定义.length
及执行large.reserve
或类似操作来避免.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现