lib/strings+test: port lpad/rpad from Hare
This commit is contained in:
@@ -724,3 +724,66 @@ export fn rsplitn(in: str, delim: str, n: i32) []str = {
|
||||
export fn split(in: str, delim: str) []str = {
|
||||
return splitn(in, delim, types.I32_MAX);
|
||||
};
|
||||
|
||||
// lpad — left-pad `s` with `p` rune until the result reaches `maxlen`
|
||||
// bytes. Length comparison is BYTES, mirroring Hare's `len(s) >= maxlen`
|
||||
// at ref/hare/strings/pad.ha:9. A multibyte `p` whose encoded width
|
||||
// doesn't divide `maxlen - s.len` evenly leaves a trailing pad byte
|
||||
// pair sliced mid-codepoint at byte `maxlen-1`, exactly as Hare's
|
||||
// `res[..maxlen]` does (ref/hare/strings/pad.ha:20). When
|
||||
// `(maxlen - s.len) * pad.len >= maxlen` (multibyte pad overflows the
|
||||
// budget), `s` is entirely sliced off — same as Hare. Caller releases
|
||||
// with `os.free(r.ptr, r.len: u64)`. Hare's `nomem` return is dropped:
|
||||
// `os.alloc` aborts on OOM. Buf size == r.len keeps the free-contract
|
||||
// shape of [[dup]] / [[concat]] / [[join]]; Hare's `alloc([], maxlen)!`
|
||||
// over-allocs via append then slices, but Hare's slice-free recovers
|
||||
// the true capacity from the heap allocator (rt/ensure.ha:24), which
|
||||
// ww's munmap-based `os.free` cannot do.
|
||||
export fn lpad(s: str, p: rune, maxlen: i32) str = {
|
||||
if (s.len >= maxlen) { return dup(s); };
|
||||
let scratch: [4]u8;
|
||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
||||
let padwrite: i32 = (maxlen - s.len) * pad.len;
|
||||
if (padwrite > maxlen) { padwrite = maxlen; };
|
||||
let off: i32 = 0;
|
||||
for (off < padwrite) {
|
||||
buf[off] = pad.ptr[off % pad.len];
|
||||
off += 1;
|
||||
};
|
||||
let k: i32 = 0;
|
||||
let srem: i32 = maxlen - off;
|
||||
if (srem > s.len) { srem = s.len; };
|
||||
for (k < srem) {
|
||||
buf[off + k] = s[k];
|
||||
k += 1;
|
||||
};
|
||||
let r: str;
|
||||
r.ptr = buf;
|
||||
r.len = maxlen;
|
||||
return r;
|
||||
};
|
||||
|
||||
// rpad — right-pad `s` with `p` rune until the result reaches `maxlen`
|
||||
// bytes. Symmetric with [[lpad]]. ref/hare/strings/pad.ha:39.
|
||||
export fn rpad(s: str, p: rune, maxlen: i32) str = {
|
||||
if (s.len >= maxlen) { return dup(s); };
|
||||
let scratch: [4]u8;
|
||||
let pad: []u8 = runebytes(scratch[0:4], p);
|
||||
let buf: *u8 = os.alloc(maxlen: u64): *u8;
|
||||
let k: i32 = 0;
|
||||
for (k < s.len) {
|
||||
buf[k] = s[k];
|
||||
k += 1;
|
||||
};
|
||||
let padwrite: i32 = maxlen - s.len;
|
||||
let i: i32 = 0;
|
||||
for (i < padwrite) {
|
||||
buf[s.len + i] = pad.ptr[i % pad.len];
|
||||
i += 1;
|
||||
};
|
||||
let r: str;
|
||||
r.ptr = buf;
|
||||
r.len = maxlen;
|
||||
return r;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user