lib/ascii: add strlower_buf/strupper_buf (#11)
Restore Hare's two-tier delegation: strlower/strupper alloc a buffer then delegate to strlower_buf/strupper_buf, which fold ASCII case into a caller-provided buffer. Too-small buffer returns nomem via the `let nm: nomem` value form. ref/hare/ascii/string.ha:21,43. Regen w6c/wwdump/smoke combined.ww — all three embed lib/ascii.
This commit is contained in:
@@ -138,15 +138,10 @@ export fn strcasecmp(a: str, b: str) i32 = {
|
||||
};
|
||||
|
||||
// strlower — ASCII-lowercased copy of s, newly allocated.
|
||||
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
|
||||
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
|
||||
// equals Hare's rune fold and is length-preserving.
|
||||
// _buf variants deferred — ww has no nomem-value form / static-append
|
||||
// builtin; restore Hare's two-tier delegation when they land (#230).
|
||||
// ref/hare/ascii/string.ha:11.
|
||||
export fn strlower(s: str) (str | nomem) = {
|
||||
// empty bypass: ww alloc([],0) routes through nomem; Hare allocs 0
|
||||
// and zero-loops (ref/hare/ascii/string.ha)
|
||||
// and zero-loops (ref/hare/ascii/string.ha:12).
|
||||
if (s.len == 0) {
|
||||
let r: str;
|
||||
r.ptr = nil;
|
||||
@@ -154,6 +149,22 @@ export fn strlower(s: str) (str | nomem) = {
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
return strlower_buf(s, buf);
|
||||
};
|
||||
|
||||
// strlower_buf — ASCII-lowercase s into buf (overwrites). nomem if buf
|
||||
// too small. ref/hare/ascii/string.ha:21.
|
||||
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
|
||||
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
|
||||
// equals Hare's rune fold and is length-preserving.
|
||||
// ww uses an explicit `buf.cap < s.len` check + `let nm: nomem` value
|
||||
// because it has no static-append builtin; Hare reaches the same
|
||||
// nomem-on-too-small via `static append(buf, ...)?` (string.ha:25).
|
||||
export fn strlower_buf(s: str, buf: []u8) (str | nomem) = {
|
||||
if (buf.cap < s.len) {
|
||||
let nm: nomem;
|
||||
return nm;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = tolower(s[i]: rune): u8;
|
||||
@@ -173,6 +184,15 @@ export fn strupper(s: str) (str | nomem) = {
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
return strupper_buf(s, buf);
|
||||
};
|
||||
|
||||
// strupper_buf — see strlower_buf. ref/hare/ascii/string.ha:43.
|
||||
export fn strupper_buf(s: str, buf: []u8) (str | nomem) = {
|
||||
if (buf.cap < s.len) {
|
||||
let nm: nomem;
|
||||
return nm;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = toupper(s[i]: rune): u8;
|
||||
|
||||
@@ -35,7 +35,45 @@ fn checkfold(in: str, lo: str, up: str) void = {
|
||||
signalled = 105; checkfold("aB1z", "ab1z", "AB1Z");
|
||||
};
|
||||
|
||||
// checkbuf — strlower_buf/strupper_buf into an exactly-sized buf.
|
||||
fn checkbuf(in: str, lo: str, up: str) void = {
|
||||
let lstore: [16]u8; let lbuf: []u8 = lstore[0:16]; lbuf.len = 0;
|
||||
match (ascii.strlower_buf(in, lbuf)) {
|
||||
case let got: str => { if (got != lo) { fail(); }; };
|
||||
case nomem => { fail(); };
|
||||
};
|
||||
let ustore: [16]u8; let ubuf: []u8 = ustore[0:16]; ubuf.len = 0;
|
||||
match (ascii.strupper_buf(in, ubuf)) {
|
||||
case let got: str => { if (got != up) { fail(); }; };
|
||||
case nomem => { fail(); };
|
||||
};
|
||||
};
|
||||
|
||||
@test fn strfold_buf_cases() void = {
|
||||
signalled = 110; checkbuf("ABC", "abc", "ABC");
|
||||
signalled = 111; checkbuf("aB1z", "ab1z", "AB1Z");
|
||||
signalled = 112; checkbuf("", "", "");
|
||||
// non-ASCII pins UTF-8 multibyte passthrough through the _buf path
|
||||
// directly (all bytes >=0x80, untouched by the byte-wise fold).
|
||||
signalled = 113; checkbuf("こ", "こ", "こ");
|
||||
// cap exactly == s.len must succeed — pins the `<` boundary in the
|
||||
// buf.cap check (a `<=` off-by-one would wrongly return nomem here).
|
||||
signalled = 114;
|
||||
let exact: [3]u8; let ebuf: []u8 = exact[0:3]; ebuf.len = 0;
|
||||
match (ascii.strlower_buf("ABC", ebuf)) {
|
||||
case let got: str => { if (got != "abc") { fail(); }; };
|
||||
case nomem => { fail(); };
|
||||
};
|
||||
signalled = 115;
|
||||
let small: [2]u8; let sbuf: []u8 = small[0:2]; sbuf.len = 0;
|
||||
match (ascii.strlower_buf("ABC", sbuf)) {
|
||||
case let got: str => { fail(); };
|
||||
case nomem => void;
|
||||
};
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; strfold_cases();
|
||||
signalled = 2; strfold_buf_cases();
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -4477,15 +4477,10 @@ export fn strcasecmp(a: str, b: str) i32 = {
|
||||
};
|
||||
|
||||
// strlower — ASCII-lowercased copy of s, newly allocated.
|
||||
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
|
||||
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
|
||||
// equals Hare's rune fold and is length-preserving.
|
||||
// _buf variants deferred — ww has no nomem-value form / static-append
|
||||
// builtin; restore Hare's two-tier delegation when they land (#230).
|
||||
// ref/hare/ascii/string.ha:11.
|
||||
export fn strlower(s: str) (str | nomem) = {
|
||||
// empty bypass: ww alloc([],0) routes through nomem; Hare allocs 0
|
||||
// and zero-loops (ref/hare/ascii/string.ha)
|
||||
// and zero-loops (ref/hare/ascii/string.ha:12).
|
||||
if (s.len == 0) {
|
||||
let r: str;
|
||||
r.ptr = nil;
|
||||
@@ -4493,6 +4488,22 @@ export fn strlower(s: str) (str | nomem) = {
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
return strlower_buf(s, buf);
|
||||
};
|
||||
|
||||
// strlower_buf — ASCII-lowercase s into buf (overwrites). nomem if buf
|
||||
// too small. ref/hare/ascii/string.ha:21.
|
||||
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
|
||||
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
|
||||
// equals Hare's rune fold and is length-preserving.
|
||||
// ww uses an explicit `buf.cap < s.len` check + `let nm: nomem` value
|
||||
// because it has no static-append builtin; Hare reaches the same
|
||||
// nomem-on-too-small via `static append(buf, ...)?` (string.ha:25).
|
||||
export fn strlower_buf(s: str, buf: []u8) (str | nomem) = {
|
||||
if (buf.cap < s.len) {
|
||||
let nm: nomem;
|
||||
return nm;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = tolower(s[i]: rune): u8;
|
||||
@@ -4512,6 +4523,15 @@ export fn strupper(s: str) (str | nomem) = {
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
return strupper_buf(s, buf);
|
||||
};
|
||||
|
||||
// strupper_buf — see strlower_buf. ref/hare/ascii/string.ha:43.
|
||||
export fn strupper_buf(s: str, buf: []u8) (str | nomem) = {
|
||||
if (buf.cap < s.len) {
|
||||
let nm: nomem;
|
||||
return nm;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = toupper(s[i]: rune): u8;
|
||||
|
||||
@@ -4477,15 +4477,10 @@ export fn strcasecmp(a: str, b: str) i32 = {
|
||||
};
|
||||
|
||||
// strlower — ASCII-lowercased copy of s, newly allocated.
|
||||
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
|
||||
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
|
||||
// equals Hare's rune fold and is length-preserving.
|
||||
// _buf variants deferred — ww has no nomem-value form / static-append
|
||||
// builtin; restore Hare's two-tier delegation when they land (#230).
|
||||
// ref/hare/ascii/string.ha:11.
|
||||
export fn strlower(s: str) (str | nomem) = {
|
||||
// empty bypass: ww alloc([],0) routes through nomem; Hare allocs 0
|
||||
// and zero-loops (ref/hare/ascii/string.ha)
|
||||
// and zero-loops (ref/hare/ascii/string.ha:12).
|
||||
if (s.len == 0) {
|
||||
let r: str;
|
||||
r.ptr = nil;
|
||||
@@ -4493,6 +4488,22 @@ export fn strlower(s: str) (str | nomem) = {
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
return strlower_buf(s, buf);
|
||||
};
|
||||
|
||||
// strlower_buf — ASCII-lowercase s into buf (overwrites). nomem if buf
|
||||
// too small. ref/hare/ascii/string.ha:21.
|
||||
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
|
||||
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
|
||||
// equals Hare's rune fold and is length-preserving.
|
||||
// ww uses an explicit `buf.cap < s.len` check + `let nm: nomem` value
|
||||
// because it has no static-append builtin; Hare reaches the same
|
||||
// nomem-on-too-small via `static append(buf, ...)?` (string.ha:25).
|
||||
export fn strlower_buf(s: str, buf: []u8) (str | nomem) = {
|
||||
if (buf.cap < s.len) {
|
||||
let nm: nomem;
|
||||
return nm;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = tolower(s[i]: rune): u8;
|
||||
@@ -4512,6 +4523,15 @@ export fn strupper(s: str) (str | nomem) = {
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
return strupper_buf(s, buf);
|
||||
};
|
||||
|
||||
// strupper_buf — see strlower_buf. ref/hare/ascii/string.ha:43.
|
||||
export fn strupper_buf(s: str, buf: []u8) (str | nomem) = {
|
||||
if (buf.cap < s.len) {
|
||||
let nm: nomem;
|
||||
return nm;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = toupper(s[i]: rune): u8;
|
||||
|
||||
@@ -4477,15 +4477,10 @@ export fn strcasecmp(a: str, b: str) i32 = {
|
||||
};
|
||||
|
||||
// strlower — ASCII-lowercased copy of s, newly allocated.
|
||||
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
|
||||
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
|
||||
// equals Hare's rune fold and is length-preserving.
|
||||
// _buf variants deferred — ww has no nomem-value form / static-append
|
||||
// builtin; restore Hare's two-tier delegation when they land (#230).
|
||||
// ref/hare/ascii/string.ha:11.
|
||||
export fn strlower(s: str) (str | nomem) = {
|
||||
// empty bypass: ww alloc([],0) routes through nomem; Hare allocs 0
|
||||
// and zero-loops (ref/hare/ascii/string.ha)
|
||||
// and zero-loops (ref/hare/ascii/string.ha:12).
|
||||
if (s.len == 0) {
|
||||
let r: str;
|
||||
r.ptr = nil;
|
||||
@@ -4493,6 +4488,22 @@ export fn strlower(s: str) (str | nomem) = {
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
return strlower_buf(s, buf);
|
||||
};
|
||||
|
||||
// strlower_buf — ASCII-lowercase s into buf (overwrites). nomem if buf
|
||||
// too small. ref/hare/ascii/string.ha:21.
|
||||
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
|
||||
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
|
||||
// equals Hare's rune fold and is length-preserving.
|
||||
// ww uses an explicit `buf.cap < s.len` check + `let nm: nomem` value
|
||||
// because it has no static-append builtin; Hare reaches the same
|
||||
// nomem-on-too-small via `static append(buf, ...)?` (string.ha:25).
|
||||
export fn strlower_buf(s: str, buf: []u8) (str | nomem) = {
|
||||
if (buf.cap < s.len) {
|
||||
let nm: nomem;
|
||||
return nm;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = tolower(s[i]: rune): u8;
|
||||
@@ -4512,6 +4523,15 @@ export fn strupper(s: str) (str | nomem) = {
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
return strupper_buf(s, buf);
|
||||
};
|
||||
|
||||
// strupper_buf — see strlower_buf. ref/hare/ascii/string.ha:43.
|
||||
export fn strupper_buf(s: str, buf: []u8) (str | nomem) = {
|
||||
if (buf.cap < s.len) {
|
||||
let nm: nomem;
|
||||
return nm;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = toupper(s[i]: rune): u8;
|
||||
|
||||
Reference in New Issue
Block a user