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或类似操作来避免.
浙公网安备 33010602011771号