lib/strings+test: port join from Hare str... variadic (#19)
This commit is contained in:
@@ -129,6 +129,47 @@ export fn concat(strs: str...) str = {
|
||||
return r;
|
||||
};
|
||||
|
||||
// join — fresh allocation with `delim` placed between each element of
|
||||
// `strs`. Caller releases with `os.free(r.ptr, r.len: u64)`.
|
||||
// ref/hare/strings/concat.ha:46. Hare's `nomem` return is dropped:
|
||||
// `os.alloc` aborts on OOM.
|
||||
export fn join(delim: str, strs: str...) str = {
|
||||
let total: i32 = 0;
|
||||
let i: i32 = 0;
|
||||
for (i < strs.len) {
|
||||
total += strs[i].len;
|
||||
if (i + 1 < strs.len) { total += delim.len; };
|
||||
i += 1;
|
||||
};
|
||||
let r: str;
|
||||
r.ptr = nil;
|
||||
r.len = 0;
|
||||
if (total == 0) { return r; };
|
||||
let buf: *u8 = os.alloc(total: u64): *u8;
|
||||
let off: i32 = 0;
|
||||
i = 0;
|
||||
for (i < strs.len) {
|
||||
let j: i32 = 0;
|
||||
for (j < strs[i].len) {
|
||||
buf[off + j] = strs[i][j];
|
||||
j += 1;
|
||||
};
|
||||
off += strs[i].len;
|
||||
if (i + 1 < strs.len) {
|
||||
j = 0;
|
||||
for (j < delim.len) {
|
||||
buf[off + j] = delim[j];
|
||||
j += 1;
|
||||
};
|
||||
off += delim.len;
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
r.ptr = buf;
|
||||
r.len = total;
|
||||
return r;
|
||||
};
|
||||
|
||||
// sub — borrowed `s[start..end]`. ref/hare/strings/sub.ha:30 is
|
||||
// rune-wise; this ww form is byte-wise (no rune iterator yet, planned
|
||||
// for commit 2). Clamps out-of-range silently where Hare aborts —
|
||||
|
||||
@@ -99,6 +99,62 @@ fn streq(a: str, b: str) bool = {
|
||||
};
|
||||
};
|
||||
|
||||
// ---- join -------------------------------------------------------------
|
||||
// ref/hare/strings/concat.ha:64. Rows mirror Hare's @test fn join
|
||||
// (0-arg, 1-arg, empty-sep, 3-arg.) plus 2-arg, all-empties, long sep,
|
||||
// multibyte, empty-mid (delim still inserted around the empty slot).
|
||||
// Per-row `signalled` 1620+i narrows the failing row.
|
||||
|
||||
@test fn join_cases() void = {
|
||||
let pool: [19]str;
|
||||
pool[0] = "hello";
|
||||
pool[1] = "a";
|
||||
pool[2] = "b";
|
||||
pool[3] = "a";
|
||||
pool[4] = "b";
|
||||
pool[5] = "c";
|
||||
pool[6] = "a";
|
||||
pool[7] = "b";
|
||||
pool[8] = "c";
|
||||
pool[9] = "";
|
||||
pool[10] = "";
|
||||
pool[11] = "a";
|
||||
pool[12] = "b";
|
||||
pool[13] = "c";
|
||||
pool[14] = "こん";
|
||||
pool[15] = "にちは";
|
||||
pool[16] = "a";
|
||||
pool[17] = "";
|
||||
pool[18] = "b";
|
||||
|
||||
let argo: [9]i32;
|
||||
let argn: [9]i32;
|
||||
let seps: [9]str;
|
||||
let want: [9]str;
|
||||
argo[0]=0; argn[0]=0; seps[0]="."; want[0]="";
|
||||
argo[1]=0; argn[1]=1; seps[1]="."; want[1]="hello";
|
||||
argo[2]=1; argn[2]=2; seps[2]=", "; want[2]="a, b";
|
||||
argo[3]=3; argn[3]=3; seps[3]="."; want[3]="a.b.c";
|
||||
argo[4]=6; argn[4]=3; seps[4]=""; want[4]="abc";
|
||||
argo[5]=9; argn[5]=2; seps[5]=","; want[5]=",";
|
||||
argo[6]=11; argn[6]=3; seps[6]=" :: "; want[6]="a :: b :: c";
|
||||
argo[7]=14; argn[7]=2; seps[7]="・"; want[7]="こん・にちは";
|
||||
argo[8]=16; argn[8]=3; seps[8]="-"; want[8]="a--b";
|
||||
|
||||
let i: i32 = 0;
|
||||
for (i < 9) {
|
||||
signalled = 1620 + i;
|
||||
let argv: []str;
|
||||
argv.ptr = &pool[argo[i]];
|
||||
argv.len = argn[i];
|
||||
argv.cap = argn[i];
|
||||
let got: str = strings.join(seps[i], argv...);
|
||||
if (!streq(got, want[i])) { fail(); };
|
||||
if (got.len > 0) { os.free(got.ptr: *void, got.len: u64); };
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
// ---- hasprefix --------------------------------------------------------
|
||||
// ref/hare/strings/suffix.ha:18.
|
||||
|
||||
@@ -842,6 +898,7 @@ fn streq(a: str, b: str) bool = {
|
||||
export fn main() i32 = {
|
||||
signalled = 1; dup_cases();
|
||||
signalled = 2; concat_cases();
|
||||
signalled = 30; join_cases();
|
||||
signalled = 3; hasprefix_cases();
|
||||
signalled = 4; hassuffix_cases();
|
||||
signalled = 5; contains_cases();
|
||||
|
||||
Reference in New Issue
Block a user