Files
scriptc/tests/corpus/5608-string-char-switch.ts
T
Chris Tate ba8849a269 Speed up native string character tests, optional-string switches, fromCharCode and long-string length
`s.charAt(i) === "c"`, and `s[i] === "c"` where the index is proven in
bounds, built a one-character string to compare with the literal. When
the literal is one UTF-16 code unit, the comparison now reads
`s.charCodeAt(i)` and compares the number. charCodeAt converts the index
the same way charAt does, and an index out of range answers NaN, which
equals no unit, as "" equals no one-unit literal. A switch on
`s.charAt(i)` whose case tests are all one-unit literals switches on the
code unit the same way.

A switch on a `string | undefined` value with string literal cases, such
as an array element or an optional field, lowered to a chain of union
equalities. It now tests for undefined, which matches no case, and
dispatches the string through the string switch: by byte length, then by
the literal's leading bytes.

`String.fromCharCode(a, b, ...)` with up to sixteen arguments passes the
codes to the runtime in a stack array instead of a heap f64[], and up to
64 code units encode into a stack buffer instead of a heap scratch block.

`.length` of a string that is not ASCII counts its UTF-16 units. The
string index keeps four entries, so a program that read the lengths of
more long texts than that in turn (the text of every source file) walked
each whole string on every read. Lengths of non-ASCII strings longer than
64 bytes now go into a 1024-slot table keyed by address, allocated by
the first length it records. A slot is dropped when the string is freed
or reallocated and when an append changes it in place, which is where
the index drops its facts.
2026-10-20 01:11:36 -05:00

96 lines
2.1 KiB
TypeScript

// switch on one character of a string with one-unit case literals: the
// index and charAt forms, indexes out of range, negative, fractional and
// NaN, astral text and lone surrogates, duplicate cases, fallthrough, a
// switch without default, few and many cases, and an index expression
// with a side effect.
function classify(ch: string): string {
return ch;
}
function kind(s: string, i: number): string {
switch (s[i]) {
case "(":
case ")":
return "paren";
case "{":
return "brace";
case "é":
return "e-acute";
case "\uD83D":
return "high";
case "\uDE00":
return "low";
case "\uD800":
return "lone";
case "(":
return "duplicate";
case " ":
return "space";
default:
return "other";
}
}
function few(s: string, i: number): number {
let n = 0;
switch (s.charAt(i)) {
case "a":
n += 1;
case "b":
n += 2;
break;
case "c":
n += 4;
}
return n;
}
const samples = ["(x) {é}", "😀", "\uD800", "", "abc", " "];
const indexes = [0, 1, 2, 3, -1, 0.5, NaN, 100];
for (const s of samples) {
console.log(
JSON.stringify(s),
indexes.map((i) => kind(s, i)).join(","),
indexes.map((i) => few(s, i)).join(","),
);
}
let calls = 0;
const text = "abc";
const next = (): number => calls++;
for (let r = 0; r < 4; r++) {
switch (text.charAt(next())) {
case "a":
console.log("a", calls);
break;
case "c":
console.log("c", calls);
break;
default:
console.log("default", calls);
}
}
function tokens(text: string): string {
const out: string[] = [];
for (let i = 0; i < text.length; i++) {
switch (text[i]) {
case "(":
case ")":
out.push("p");
break;
case "+":
case "-":
case "*":
case "/":
out.push("o");
break;
case "\uD83D":
out.push("h");
break;
case " ":
break;
default:
out.push(text[i]);
}
}
return out.join("");
}
console.log(tokens("(a + b) * c / d - é"), tokens("x😀y"), tokens(""));
console.log(classify("ok"));