Files
scriptc/tests/corpus/1536-string-array-sweep.ts
T
Chris Tate 53af3dc930 Compare strings in UTF-16 code-unit order
Relational string operators (`<`, `<=`, `>`, `>=`) compared the UTF-8
bytes, which is code-point order. Node compares UTF-16 code units, so the
results differed for characters above U+FFFF against U+E000..U+FFFF and
for lone surrogates against surrogate pairs. The default `sort()`
comparator, `util.inspect` with `sorted: true` and dynamic comparisons
already used UTF-16 order; the default comparator of a dynamic array's
`sort()` did not.

Typed comparisons and the dynamic array sort now use `scr_str_cmp_u16`,
and the IR's `strCmp` node no longer has a `utf16` flag. The two orders
agree unless both of the first differing bytes are at least 0xED, so:

- the inline wrapper decides differing first words, or last words of
  equal lengths up to 16 bytes, in byte order when neither word has a
  byte of at least 0xED (a SWAR test). Other differing words, and the
  first bytes of shorter strings, decide by their first differing byte:
  in byte order when one of the two is below 0xED, and by plane when both
  are lead bytes from 0xEE to 0xF4 (a supplementary character orders
  below U+E000..U+FFFF);
- otherwise a proven-ASCII string on either side compares with `memcmp`
  (`scr_str_cmp`), and other pairs call `scr_str_cmp_u16_bytes`. It finds
  the first differing byte with words up to byte 32, then with 32-byte
  SSE2 or NEON blocks where the target has them. The call is marked as
  only reading its arguments, so repeated comparisons of one pair merge.
- `scr_str_cmp_u16` itself takes the same `memcmp` path for proven-ASCII
  strings.

The native compiler sorts record fields with `<` and checks the order
with `sort()`, so it reported SC9001 for 5888-inspect-sorted.ts, whose
object has the keys "\u{1F600}" and "\uffff". 5888 runs in the
native-frontend self-host check. Adds corpus 6023.
2026-10-19 18:10:54 -05:00

38 lines
1.6 KiB
TypeScript

// The surface-tail sweep trio: string.substring (clamp-and-swap, the
// port-suffix idiom), array findIndex (first match or -1, index-aware
// callbacks), and the comparator-less sort() on string[] (JS's default
// UTF-16 code-unit ordering).
const localAddr = "127.0.0.1.51823";
const lastColon = localAddr.lastIndexOf(".");
console.log(localAddr.substring(lastColon + 1));
console.log(parseInt(localAddr.substring(lastColon + 1), 10));
const s = "hello world";
console.log(s.substring(0, 5));
console.log(s.substring(5, 0));
console.log(s.substring(-3, 4));
console.log(s.substring(4));
console.log(s.substring(99));
console.log(s.substring(3, 99));
console.log(s.substring(2.9, 7.1));
console.log(s.substring(0 / 0, 5));
console.log("héllo wörld".substring(1, 4));
// findIndex — the proxy-start scan idiom (arg + lookahead by index).
const command = ["node", "cli.js", "proxy", "start", "--port", "443"];
const proxyIndex = command.findIndex(
(arg, index) => arg === "proxy" && command[index + 1] === "start"
);
console.log(proxyIndex);
console.log(command.findIndex((arg) => arg === "nope"));
console.log([3, 1, 4, 1, 5].findIndex((n) => n < 2));
console.log(([] as string[]).findIndex((x) => x === ""));
// Comparator-less sort on string[]: stable, in-place, returns the array.
const included = new Set(["zeta", "alpha", "Beta", "beta", "10", "2", ""]);
console.log(JSON.stringify([...included].sort()));
const names = ["b", "a", "c", "a"];
const same = names.sort();
console.log(JSON.stringify(names), same === names);
console.log(JSON.stringify(["é", "e", "z", "Z"].sort()));