Files
scriptc/tests/corpus/5750-string-from-char-codes.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

28 lines
1.3 KiB
TypeScript

// String.fromCharCode with several arguments: ASCII and non-ASCII units,
// surrogate pairs that combine, lone and reversed surrogates, ToUint16 of
// large, negative, fractional and NaN codes, zero to seventeen arguments,
// and the spread form.
const show = (s: string): string =>
`${JSON.stringify(s)}:${s.length}:${Array.from(s, (c) => c.codePointAt(0)!.toString(16)).join(".")}`;
console.log(show(String.fromCharCode()));
console.log(show(String.fromCharCode(104, 105)));
console.log(show(String.fromCharCode(0xe9, 0x65e5, 0x41)));
console.log(show(String.fromCharCode(0xd83d, 0xde00)));
console.log(show(String.fromCharCode(0xde00, 0xd83d)));
console.log(show(String.fromCharCode(0xd800, 0x41, 0xdc00)));
console.log(show(String.fromCharCode(0x10041, -1, 65.9, NaN, 2 ** 32 + 66)));
console.log(
show(String.fromCharCode(97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112)),
);
console.log(
show(String.fromCharCode(97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113)),
);
const codes = [0x48, 0xd83d, 0xde00, 0x21];
console.log(show(String.fromCharCode(...codes)));
let out = "";
for (let i = 0; i < 26; i++) out += String.fromCharCode(97 + i, 65 + i);
console.log(out, out.length);
let calls = 0;
const next = (): number => 65 + calls++;
console.log(String.fromCharCode(next(), next(), next()), calls);