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;
|
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
|
// 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
|
// rune-wise; this ww form is byte-wise (no rune iterator yet, planned
|
||||||
// for commit 2). Clamps out-of-range silently where Hare aborts —
|
// 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 --------------------------------------------------------
|
// ---- hasprefix --------------------------------------------------------
|
||||||
// ref/hare/strings/suffix.ha:18.
|
// ref/hare/strings/suffix.ha:18.
|
||||||
|
|
||||||
@@ -842,6 +898,7 @@ fn streq(a: str, b: str) bool = {
|
|||||||
export fn main() i32 = {
|
export fn main() i32 = {
|
||||||
signalled = 1; dup_cases();
|
signalled = 1; dup_cases();
|
||||||
signalled = 2; concat_cases();
|
signalled = 2; concat_cases();
|
||||||
|
signalled = 30; join_cases();
|
||||||
signalled = 3; hasprefix_cases();
|
signalled = 3; hasprefix_cases();
|
||||||
signalled = 4; hassuffix_cases();
|
signalled = 4; hassuffix_cases();
|
||||||
signalled = 5; contains_cases();
|
signalled = 5; contains_cases();
|
||||||
|
|||||||
@@ -1795,6 +1795,47 @@ export fn concat(strs: str...) str = {
|
|||||||
return r;
|
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
|
// 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
|
// rune-wise; this ww form is byte-wise (no rune iterator yet, planned
|
||||||
// for commit 2). Clamps out-of-range silently where Hare aborts —
|
// for commit 2). Clamps out-of-range silently where Hare aborts —
|
||||||
|
|||||||
@@ -1795,6 +1795,47 @@ export fn concat(strs: str...) str = {
|
|||||||
return r;
|
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
|
// 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
|
// rune-wise; this ww form is byte-wise (no rune iterator yet, planned
|
||||||
// for commit 2). Clamps out-of-range silently where Hare aborts —
|
// for commit 2). Clamps out-of-range silently where Hare aborts —
|
||||||
|
|||||||
@@ -1686,6 +1686,47 @@ export fn concat(strs: str...) str = {
|
|||||||
return r;
|
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
|
// 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
|
// rune-wise; this ww form is byte-wise (no rune iterator yet, planned
|
||||||
// for commit 2). Clamps out-of-range silently where Hare aborts —
|
// for commit 2). Clamps out-of-range silently where Hare aborts —
|
||||||
|
|||||||
Reference in New Issue
Block a user