lib: collapse the manual rt_ensure append workarounds onto the fixed builtin (#34 follow-up)
shlex.appendstr, getopt.appendoption, bytes.appendslice and
strings.appendstr existed only because the append builtin stored the
first 8 bytes of the element; each carried its own @symbol("rt_ensure")
bind and a grow-then-store-through-*T body, with comments promising to
"collapse in one go when the append builtin is fixed". The previous
commit fixed the builtin; this removes all four helpers and their
rt_ensure binds and spells every call site as plain append().
Bonus correctness: getopt's appendoption passed a hardcoded membsz of
24, stale since the str 24B redesign made option {rune, str} 32B — the
manual growth under-allocated past 6 options while &opts.ptr[i] strode
32 (latent OOB). The builtin derives membsz from the type table
(probe: MOVQ $32, SI), closing that drift by construction.
This commit is contained in:
@@ -386,28 +386,6 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
|
||||
return s.in;
|
||||
};
|
||||
|
||||
// rt_ensure is the runtime slice-growth helper invoked by the
|
||||
// `append(s, v)` builtin. We bind it directly because the builtin's
|
||||
// expansion stores only 8 bytes of the new element (cgen emits a
|
||||
// single MOVQ), losing the .len/.cap fields of a []u8 element (24B).
|
||||
// Mirrors the same workaround in lib/shlex.shlex (appendstr, 16B) and
|
||||
// lib/getopt.getopt (appendoption, 24B); collapses in one go when the
|
||||
// append builtin learns to store the full element width.
|
||||
@symbol("rt_ensure") fn rtensure(s: *void, membsz: u64) void;
|
||||
|
||||
// appendslice — grow `*slice` by one and store `item` (24B). Mirror
|
||||
// of [[shlex.appendstr]] / [[getopt.appendoption]]. Bypasses the
|
||||
// `append` builtin's first-8B-only-store gap for a slice-element.
|
||||
fn appendslice(slice: *[][]u8, item: []u8) void = {
|
||||
let newlen: i32 = slice.len + 1;
|
||||
slice.len = newlen;
|
||||
rtensure(slice: *void, 24u64);
|
||||
let dst: *[]u8 = &slice.ptr[newlen - 1];
|
||||
dst.ptr = item.ptr;
|
||||
dst.len = item.len;
|
||||
dst.cap = item.cap;
|
||||
};
|
||||
|
||||
// splitn — split `in` on any byte in `delim`, returning up to `n`
|
||||
// tokens via forward iteration. The trailing slot (when more than
|
||||
// `n - 1` tokens exist) holds the unconsumed remainder.
|
||||
@@ -432,7 +410,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
let i: i32 = 0;
|
||||
for (i < n - 1) {
|
||||
match (next_token(&tok)) {
|
||||
case let s: []u8 => { appendslice(&toks, s); };
|
||||
case let s: []u8 => { append(toks, s); };
|
||||
case done => { return toks; };
|
||||
};
|
||||
i += 1;
|
||||
@@ -441,7 +419,7 @@ export fn splitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
case done => void;
|
||||
case let pk: []u8 => {
|
||||
let r: []u8 = remaining_tokens(&tok);
|
||||
appendslice(&toks, r);
|
||||
append(toks, r);
|
||||
};
|
||||
};
|
||||
return toks;
|
||||
@@ -470,7 +448,7 @@ export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
let i: i32 = 0;
|
||||
for (i < n - 1) {
|
||||
match (next_token(&tok)) {
|
||||
case let s: []u8 => { appendslice(&toks, s); };
|
||||
case let s: []u8 => { append(toks, s); };
|
||||
case done => { return toks; };
|
||||
};
|
||||
i += 1;
|
||||
@@ -479,7 +457,7 @@ export fn rsplitn(in: []u8, delim: []u8, n: i32) [][]u8 = {
|
||||
case done => void;
|
||||
case let pk: []u8 => {
|
||||
let r: []u8 = remaining_tokens(&tok);
|
||||
appendslice(&toks, r);
|
||||
append(toks, r);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user