lib/strings+test: port split family from Hare
This commit is contained in:
@@ -1064,6 +1064,146 @@ fn expect_str_done(t: *strings.tokenizer) void = {
|
||||
if (!streq(strings.remaining_tokens(&t2), "a b c")) { fail(); };
|
||||
};
|
||||
|
||||
// ---- splitn / rsplitn / split ----------------------------------------
|
||||
// ref/hare/strings/tokenize.ha:245 @test fn split. Hare's vectors
|
||||
// mirrored here directly; element reads go through `&toks.ptr[i]: *str`
|
||||
// rather than `toks[i]` so the 16B str element copy stays out of the
|
||||
// multi-word-store gap noted at cmd/w6c/cgen.c:6515.
|
||||
|
||||
fn expect_str(toks: []str, i: i32, want: str) void = {
|
||||
if (i >= toks.len) { fail(); };
|
||||
let p: *str = &toks.ptr[i];
|
||||
if (p.len != want.len) { fail(); };
|
||||
let j: i32 = 0;
|
||||
for (j < want.len) {
|
||||
if (p.ptr[j] != want[j]) { fail(); };
|
||||
j += 1;
|
||||
};
|
||||
};
|
||||
|
||||
@test fn splitn_cases() void = {
|
||||
// ref/hare/strings/tokenize.ha:247 — n=4 buckets the trailing
|
||||
// "is Drew" as the remainder slot.
|
||||
signalled = 1740;
|
||||
let t1: []str = strings.splitn("Hello, my name is Drew", " ", 4);
|
||||
if (t1.len != 4) { fail(); };
|
||||
expect_str(t1, 0, "Hello,");
|
||||
expect_str(t1, 1, "my");
|
||||
expect_str(t1, 2, "name");
|
||||
expect_str(t1, 3, "is Drew");
|
||||
os.free(t1.ptr: *void, (t1.cap: u64) * 16u64);
|
||||
|
||||
// ref/hare/strings/tokenize.ha:263 — n > tokens leaves a single
|
||||
// slot holding the unchanged input (delim not found).
|
||||
signalled = 1741;
|
||||
let t2: []str = strings.splitn("one", "=", 2);
|
||||
if (t2.len != 1) { fail(); };
|
||||
expect_str(t2, 0, "one");
|
||||
os.free(t2.ptr: *void, (t2.cap: u64) * 16u64);
|
||||
|
||||
// n == 1 — single slot holding the whole input as remainder.
|
||||
signalled = 1742;
|
||||
let t3: []str = strings.splitn("a b c", " ", 1);
|
||||
if (t3.len != 1) { fail(); };
|
||||
expect_str(t3, 0, "a b c");
|
||||
os.free(t3.ptr: *void, (t3.cap: u64) * 16u64);
|
||||
|
||||
// Empty input — empty result.
|
||||
signalled = 1743;
|
||||
let t4: []str = strings.splitn("", " ", 5);
|
||||
if (t4.len != 0) { fail(); };
|
||||
if (t4.cap > 0) {
|
||||
os.free(t4.ptr: *void, (t4.cap: u64) * 16u64);
|
||||
};
|
||||
|
||||
// Multi-byte delim set (byte-set semantics per
|
||||
// ref/hare/strings/tokenize.ha:35) — split on ',' OR ':' OR ';'.
|
||||
signalled = 1744;
|
||||
let t5: []str = strings.splitn("hello;world,foo:bar", ",:;", 10);
|
||||
if (t5.len != 4) { fail(); };
|
||||
expect_str(t5, 0, "hello");
|
||||
expect_str(t5, 1, "world");
|
||||
expect_str(t5, 2, "foo");
|
||||
expect_str(t5, 3, "bar");
|
||||
os.free(t5.ptr: *void, (t5.cap: u64) * 16u64);
|
||||
};
|
||||
|
||||
@test fn rsplitn_cases() void = {
|
||||
// ref/hare/strings/tokenize.ha:271 — reverse n=4 with the
|
||||
// "Hello, my" prefix as the remainder slot at index 0.
|
||||
signalled = 1750;
|
||||
let t1: []str = strings.rsplitn("Hello, my name is Drew", " ", 4);
|
||||
if (t1.len != 4) { fail(); };
|
||||
expect_str(t1, 0, "Hello, my");
|
||||
expect_str(t1, 1, "name");
|
||||
expect_str(t1, 2, "is");
|
||||
expect_str(t1, 3, "Drew");
|
||||
os.free(t1.ptr: *void, (t1.cap: u64) * 16u64);
|
||||
|
||||
// n > token count — done short-circuit returns toks UN-reversed
|
||||
// (last-token-first order). Mirrors bytes.rsplitn (Hare's
|
||||
// ref/hare/strings/tokenize.ha:219-224 reverse step is gated
|
||||
// behind the n-1 loop completion).
|
||||
signalled = 1751;
|
||||
let t2: []str = strings.rsplitn("a b c", " ", 10);
|
||||
if (t2.len != 3) { fail(); };
|
||||
expect_str(t2, 0, "c");
|
||||
expect_str(t2, 1, "b");
|
||||
expect_str(t2, 2, "a");
|
||||
os.free(t2.ptr: *void, (t2.cap: u64) * 16u64);
|
||||
|
||||
// n == 1 — single slot holding the whole input as remainder.
|
||||
signalled = 1752;
|
||||
let t3: []str = strings.rsplitn("a b c", " ", 1);
|
||||
if (t3.len != 1) { fail(); };
|
||||
expect_str(t3, 0, "a b c");
|
||||
os.free(t3.ptr: *void, (t3.cap: u64) * 16u64);
|
||||
|
||||
// delim absent — first next_token yields the entire input as the
|
||||
// sole token; second iter sees done and short-circuits with the
|
||||
// 1-elem toks un-reversed (single element, reverse is a no-op).
|
||||
signalled = 1753;
|
||||
let t4: []str = strings.rsplitn("abc", "=", 5);
|
||||
if (t4.len != 1) { fail(); };
|
||||
expect_str(t4, 0, "abc");
|
||||
os.free(t4.ptr: *void, (t4.cap: u64) * 16u64);
|
||||
};
|
||||
|
||||
@test fn split_cases() void = {
|
||||
// ref/hare/strings/tokenize.ha:255 — full split, every delim hit
|
||||
// is a boundary.
|
||||
signalled = 1760;
|
||||
let t1: []str = strings.split("Hello, my name is Drew", " ");
|
||||
if (t1.len != 5) { fail(); };
|
||||
expect_str(t1, 0, "Hello,");
|
||||
expect_str(t1, 1, "my");
|
||||
expect_str(t1, 2, "name");
|
||||
expect_str(t1, 3, "is");
|
||||
expect_str(t1, 4, "Drew");
|
||||
os.free(t1.ptr: *void, (t1.cap: u64) * 16u64);
|
||||
|
||||
// Leading + trailing delim — empty tokens at ends.
|
||||
signalled = 1761;
|
||||
let t2: []str = strings.split(" a b ", " ");
|
||||
if (t2.len != 4) { fail(); };
|
||||
expect_str(t2, 0, "");
|
||||
expect_str(t2, 1, "a");
|
||||
expect_str(t2, 2, "b");
|
||||
expect_str(t2, 3, "");
|
||||
os.free(t2.ptr: *void, (t2.cap: u64) * 16u64);
|
||||
|
||||
// Multi-byte delim set, byte-set semantics matching Hare's
|
||||
// strings::split example at ref/hare/strings/tokenize.ha:235.
|
||||
signalled = 1762;
|
||||
let t3: []str = strings.split("hello;world,foo:bar", ",:;");
|
||||
if (t3.len != 4) { fail(); };
|
||||
expect_str(t3, 0, "hello");
|
||||
expect_str(t3, 1, "world");
|
||||
expect_str(t3, 2, "foo");
|
||||
expect_str(t3, 3, "bar");
|
||||
os.free(t3.ptr: *void, (t3.cap: u64) * 16u64);
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; dup_cases();
|
||||
signalled = 2; concat_cases();
|
||||
@@ -1099,5 +1239,8 @@ export fn main() i32 = {
|
||||
signalled = 32; rtokenize_cases();
|
||||
signalled = 33; peek_token_cases();
|
||||
signalled = 34; remaining_tokens_cases();
|
||||
signalled = 35; splitn_cases();
|
||||
signalled = 36; rsplitn_cases();
|
||||
signalled = 37; split_cases();
|
||||
return 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user