@amritk/nish-x86_64-linux 0.31.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/nish CHANGED
Binary file
package/docs/AI.md CHANGED
@@ -49,7 +49,7 @@ stdout, nothing on stderr, every field 1-based with `endLine`/`endColumn`
49
49
  exclusive:
50
50
 
51
51
  ```json
52
- {"file":"p.ts","line":3,"column":17,"endLine":3,"endColumn":20,"severity":"error","code":"NL2249","message":"Unknown method `map` on i32[] (supported: push, pop, indexOf, join, set, fill)"}
52
+ {"file":"p.ts","line":3,"column":17,"endLine":3,"endColumn":20,"severity":"error","code":"NL2249","message":"Unknown method `map` on i32[] (supported: push, pop, indexOf, join, set, fill, sort)"}
53
53
  ```
54
54
 
55
55
  - **Key on `code`, never on `message`.** A code is a promise: `NL2249` means
@@ -159,7 +159,7 @@ rejects. This table is the highest-value part of the page.
159
159
  | `x == y` | `Loose equality is forbidden` | `x === y` |
160
160
  | `throw new Error(m)` | `` `throw` is forbidden `` | `return Err(m)`, or `panic(m)` to end the process |
161
161
  | `try { … } catch { … }` | `` `try`/`catch`/`finally` is forbidden `` | `Result<T, E>` and `isErr()` |
162
- | `xs.map(f)`, `.filter`, `.reduce`, `.forEach`, `.slice`, `.sort`, `.shift` | `` Unknown method `map` on i32[] (supported: push, pop, indexOf, join, set, fill) `` | a `for` loop, or a top-level `map(xs, f)` with a [function parameter](#function-parameters) |
162
+ | `xs.map(f)`, `.filter`, `.reduce`, `.forEach`, `.slice`, `.shift` | `` Unknown method `map` on i32[] (supported: push, pop, indexOf, join, set, fill, sort) `` | a `for` loop, or a top-level `map(xs, f)` with a [function parameter](#function-parameters) |
163
163
  | `s.toUpperCase()`, `s.split()`, `s.trim()`, `s.replace()` | `` Unknown method … on string `` | index bytes with `charCodeAt` / `substring` |
164
164
  | `a?.b`, `a ?? b` | `?.` only in a chain that ends in `??`; `??` only on a `T \| null`, a chain or `m.get(k)` | `a?.b ?? d`, `a ?? d`, or `if (a !== null)` first |
165
165
  | `x as T`, `<T>x`, `x satisfies T` | `Unsupported expression in Phase 1: AsExpression` (to `any` or `unknown`: `` Type assertion to `any` is forbidden ``); `x!` is a syntax error | there are no casts; `implements` is the only widening |
@@ -852,7 +852,8 @@ export const main = (): i32 => {
852
852
  (`` The arrow reads `k`, a `let` of the function it is written in: ... bind the value to a `const` before the call ``),
853
853
  read `this` (bind `const self = this`), or read a function parameter of its
854
854
  function. An arrow inside another arrow, or given to a method, a
855
- constructor, `expose` or `exposeWith`, captures nothing.
855
+ constructor, `expose` or `exposeWith`, captures nothing; `xs.sort(cmp)`'s
856
+ comparator is the exception, and captures as an arrow argument does.
856
857
  - **The argument's type must match exactly**: `(x: i32) => i64` for a
857
858
  `(x: i32) => i32` parameter is refused. A generic function cannot be passed
858
859
  by name — write `(x) => identity(x)`.
@@ -2138,7 +2139,12 @@ there is no `undefined` to return), `a.indexOf(v)`, `a.join(sep)` — **`join` i
2138
2139
  `string[]` only** — and, on an array of numbers only, `dst.set(src[, offset])`
2139
2140
  (one `memmove`; a range past the end panics) and `a.fill(v[, start[, end]])`
2140
2141
  (ends clamped and counted back from the end when negative, as in JavaScript;
2141
- never panics). Both are statements. That is every array method there is. A
2142
+ never panics). Both are statements. `a.sort(cmp)` sorts in place, stably, and
2143
+ answers `a` — the same order Node gives; the comparator is required (`a.sort()`
2144
+ is refused, since JavaScript would compare strings), a readonly array and
2145
+ `process.argv` are refused, `a - b` panics on `i32` values a full range apart
2146
+ (compare with `a > b ? 1 : a < b ? -1 : 0` there), and the comparator may read the caller's `const` locals and parameters but not
2147
+ a `let`, as any arrow argument may. That is every array method there is. A
2142
2148
  window into a buffer is `(buf, offset, length)`; there is no view type.
2143
2149
 
2144
2150
  **Strings.** `s.length` (**bytes**), `s.charCodeAt(i)` (the byte, bounds-checked),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amritk/nish-x86_64-linux",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "The nish native compiler for Linux on x86_64",
5
5
  "license": "MIT",
6
6
  "os": [
package/std/README.md CHANGED
@@ -12,6 +12,7 @@ whatever program imports it, and subject to the same rules as `examples/` or
12
12
  | [`testing.ts`](./testing.ts) | a test runner: a `Suite` a program drives with straight-line assertions, printing the `PASS` / `FAIL` / `SKIP` lines the repository's own harness prints, and answering the exit code |
13
13
  | [`text.ts`](./text.ts) | the string operations a program would otherwise write inline: `splitLines`, `splitWhitespace`, `trim` and its halves, `contains`, `replaceAll`, `firstDifference` over two arrays of lines, `codePointLength`, the number of Unicode code points (what JSON Schema's `minLength` counts, where `.length` counts UTF-8 bytes natively and UTF-16 units under Node; it answers the same on both by asking which it is reading), and `indexOfAny(text, bytes, from)`, the first index at or after `from` whose byte is one of 1 to 16 ASCII `bytes`. Its walker is the meaning and what runs under Node; natively the compiler replaces the one call to it with the runtime kernel `nish_str_index_of_any`, which reads 16 or 32 bytes at a time and is variable-time ([`docs/LANGUAGE.md`](../docs/LANGUAGE.md#byte-search-indexofany-in-nishtext)). `tests/link/std_text_index_of_any*` are its programs |
14
14
  | [`math.ts`](./math.ts) | `Math.tan`, `Math.atan2` and `Math.hypot` on `f64`, ported from fdlibm (`LICENSE-fdlibm`) so that every target, wasm included, answers alike without libm. A program never imports it: a call to one of the three loads it, and the compiler copies the functions the call reaches into the calling module as `internal` ones. JavaScript's answer for every NaN, signed zero and infinity, and within one ulp elsewhere (0.83, 0.84 and 0.93 ulp measured against mpmath). `tests/cases/math_std_edges` pins the special values |
15
+ | [`sort.ts`](./sort.ts) | `xs.sort(cmp)` on any array: `sortWith`, a stable merge sort over runs of 32 sorted by insertion — one scratch array released before it returns, a pair of runs already in order copied without merging, no bounds check left in it — so its order is element for element Node's `Array.prototype.sort`. Like `math.ts` it is one the compiler knows about: a program never imports it, a `.sort(cmp)` call loads it, the checker rewrites the call to `sortWith`, and each comparator's instantiation — the comparator called directly, no function pointer — is copied into the module that sorts. Under Node the call stays the platform's own. `tests/cases/arr_sort_cmp*` are its programs, a 10,000-element sort with ties among them |
15
16
  | [`regex.ts`](./regex.ts) | Regular expressions in JavaScript's syntax with the `u` flag's strictness, matched by a Pike VM in time linear in the input whatever the pattern; finding every match is one search per match, so `findAll` and its kin can be quadratic when a long branch is preferred to a short one that wins ([`docs/security/regex.md`](../docs/security/regex.md)). `regexCompile(pattern, flags)` answers a `Regex` or the error text; `test`, `exec` into a reused `RegexMatch`, `find`, `findAll`, `count`, `replace` and `replaceAll` with `$&`, `$1` and `$<name>`, and `split`. Flags `i`, `m`, `s` and `u`; `i` folds by Unicode's simple case folding, ASCII letters only to ASCII. `\p{…}` and `\P{…}` take Unicode 16.0's General_Category, Script, Script_Extensions and binary properties by JavaScript's names, from tables `scripts/gen-regex-unicode.mjs` generates into the module and checks against Node's `RegExp`; backreferences and lookaround are refused at compile time. Offsets are UTF-8 bytes. A search allocates nothing beyond its answer: the thread lists and capture tables are the `Regex`'s, so one `Regex` serves one thread at a time. A leading literal is found with `indexOf`, a small leading set with `indexOfAny`. `tests/link/std_regex` and `tests/link/std_regex_unicode` check it against JavaScript's own answers |
16
17
  | [`json.ts`](./json.ts) | `jsonField(object, name)`: the value of one field of one flat JSON object, which is the shape the compiler's own `--json` diagnostics have. A reader and not a parser — it answers text, answers `null` for a field that is not there, and does not validate. `JsonWriter` is the other direction: any JSON value written into a caller-owned `u8[]`, commas and colons included, byte for byte what `JSON.stringify` writes, and allocating nothing per call except an `f64`'s digits, a temporary string the call gives back before it returns (`text()` and `jsonStringifyString` build strings by design); misuse and a full buffer set a sticky negative `JSON_WRITE_*` code in `failed` rather than panicking. `setIndent(n)` and `setIndentTab()` write what `JSON.stringify(v, null, n)` or `(v, null, "\t")` writes, with no allocation for the indent, and `setStrict(true)` makes NaN and the infinities the sticky `JSON_WRITE_NON_FINITE` instead of `null`; both modes are off by default and kept by `reset`. `jsonStringifyString(s)` is the string rule answered as a string. `stringBytes(bytes, off, len)` and `keyBytes(bytes, off, len)` write a window of a byte array as `string` and `key` write a string of those bytes, allocating nothing, and refuse a window outside the array with `JSON_WRITE_BAD_WINDOW` |
17
18
  | [`json-tokenizer.ts`](./json-tokenizer.ts) | `JsonTokenizer`: a validating, streaming tokenizer for RFC 8259 JSON held in a window of a `u8[]`. `next()` answers one `JSON_TOK_*` token at a time — object and array openers and closers, keys, strings, numbers and the three literals — then `JSON_TOK_END`, or a negative `JSON_TOK_ERR_*` code that sticks in `failed`, with the byte in `errorAt`. Strings are checked as UTF-8 and a lone surrogate escape is refused; `stringInto` decodes the current string into the caller's array and `keyEquals` compares it with a name, neither allocating. `numberF64` is correctly rounded; `isInteger` and `numberI64` read an integer that fits an `i64`, and `isU64` and `numberU64` one that fits a `u64`. `isIntegral` asks whether a number's value is whole however it is written (`1.0`, `1e2`, `1e400`), JSON Schema's "integer", from the text and at any exponent. `skipValue` steps over a value. `JsonLimits` caps nesting depth, string, number and total bytes, each with its own code; `reset` reuses the tokenizer, so a reused body keeps the arena flat. Duplicate keys are reported as tokens. No input panics and no byte outside the window is read; [`docs/security/json.md`](../docs/security/json.md) is its record, and `tests/link/std_json_tokenizer` runs JSONTestSuite and a seeded fuzz |
@@ -1024,7 +1024,9 @@ const bcryptLoadSlot = (state: Secret<u32[]>, password: Secret<u8[]>, slot: i32)
1024
1024
  // the lane count changed (bench/crypto/bcrypt/gen-body.mjs writes them), not
1025
1025
  // one loop over a lane count: the lanes' l and r must live in registers and
1026
1026
  // their loads be scheduled together, which a loop over an array of lanes
1027
- // does not give.
1027
+ // does not give. Two lanes take each byte by its own shift and write every
1028
+ // lane's bytes before any lane's update, the form all widths had before the
1029
+ // rotated copy, which measured slower there.
1028
1030
 
1029
1031
  /** `bcryptBody4`'s interleave on two lanes. */
1030
1032
  const bcryptBody2 = (st: u32[]): void => {
@@ -1089,35 +1091,41 @@ const bcryptBody3 = (st: u32[]): void => {
1089
1091
  l1 ^= st[1042]
1090
1092
  l2 ^= st[2084]
1091
1093
  for (let n: i32 = 1; n < 17; n += 2) {
1094
+ const l0e: u32 = ctSelect((l0 >>> 8) | (l0 << 24), 0xffffffff, 0)
1092
1095
  const l0a: i32 = toI32(l0 >>> 24) & 0xff
1093
- const l0b: i32 = toI32(l0 >>> 16) & 0xff
1094
- const l0c: i32 = toI32(l0 >>> 8) & 0xff
1096
+ const l0b: i32 = toI32(l0e >>> 8) & 0xff
1097
+ const l0c: i32 = toI32(l0e) & 0xff
1095
1098
  const l0d: i32 = toI32(l0) & 0xff
1099
+ r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
1100
+ const l1e: u32 = ctSelect((l1 >>> 8) | (l1 << 24), 0xffffffff, 0)
1096
1101
  const l1a: i32 = toI32(l1 >>> 24) & 0xff
1097
- const l1b: i32 = toI32(l1 >>> 16) & 0xff
1098
- const l1c: i32 = toI32(l1 >>> 8) & 0xff
1102
+ const l1b: i32 = toI32(l1e >>> 8) & 0xff
1103
+ const l1c: i32 = toI32(l1e) & 0xff
1099
1104
  const l1d: i32 = toI32(l1) & 0xff
1105
+ r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
1106
+ const l2e: u32 = ctSelect((l2 >>> 8) | (l2 << 24), 0xffffffff, 0)
1100
1107
  const l2a: i32 = toI32(l2 >>> 24) & 0xff
1101
- const l2b: i32 = toI32(l2 >>> 16) & 0xff
1102
- const l2c: i32 = toI32(l2 >>> 8) & 0xff
1108
+ const l2b: i32 = toI32(l2e >>> 8) & 0xff
1109
+ const l2c: i32 = toI32(l2e) & 0xff
1103
1110
  const l2d: i32 = toI32(l2) & 0xff
1104
- r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
1105
- r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
1106
1111
  r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
1112
+ const r0e: u32 = ctSelect((r0 >>> 8) | (r0 << 24), 0xffffffff, 0)
1107
1113
  const r0a: i32 = toI32(r0 >>> 24) & 0xff
1108
- const r0b: i32 = toI32(r0 >>> 16) & 0xff
1109
- const r0c: i32 = toI32(r0 >>> 8) & 0xff
1114
+ const r0b: i32 = toI32(r0e >>> 8) & 0xff
1115
+ const r0c: i32 = toI32(r0e) & 0xff
1110
1116
  const r0d: i32 = toI32(r0) & 0xff
1117
+ l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
1118
+ const r1e: u32 = ctSelect((r1 >>> 8) | (r1 << 24), 0xffffffff, 0)
1111
1119
  const r1a: i32 = toI32(r1 >>> 24) & 0xff
1112
- const r1b: i32 = toI32(r1 >>> 16) & 0xff
1113
- const r1c: i32 = toI32(r1 >>> 8) & 0xff
1120
+ const r1b: i32 = toI32(r1e >>> 8) & 0xff
1121
+ const r1c: i32 = toI32(r1e) & 0xff
1114
1122
  const r1d: i32 = toI32(r1) & 0xff
1123
+ l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
1124
+ const r2e: u32 = ctSelect((r2 >>> 8) | (r2 << 24), 0xffffffff, 0)
1115
1125
  const r2a: i32 = toI32(r2 >>> 24) & 0xff
1116
- const r2b: i32 = toI32(r2 >>> 16) & 0xff
1117
- const r2c: i32 = toI32(r2 >>> 8) & 0xff
1126
+ const r2b: i32 = toI32(r2e >>> 8) & 0xff
1127
+ const r2c: i32 = toI32(r2e) & 0xff
1118
1128
  const r2d: i32 = toI32(r2) & 0xff
1119
- l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
1120
- l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
1121
1129
  l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
1122
1130
  }
1123
1131
  const t0: u32 = r0
@@ -1143,6 +1151,19 @@ const bcryptBody3 = (st: u32[]): void => {
1143
1151
  * place, the four encryption chains interleaved round by round so that one
1144
1152
  * lane's S-box loads overlap the others' instead of waiting on their own. The
1145
1153
  * hot loop of the batch: 2^(cost+1) calls of 521 blocks per lane.
1154
+ *
1155
+ * Each lane's half-round is written whole, its bytes and then its update,
1156
+ * before the next lane's. The two middle index bytes come from one copy of the
1157
+ * word rotated right by 8 (`e`: byte 1 is its low byte, byte 2 its second),
1158
+ * behind the value barrier: `ctSelect(v, 0xffffffff, 0)` is `v`, opaque, so
1159
+ * LLVM cannot fold the two bytes back into two shifts of the word, and copies
1160
+ * it once instead of twice; on a BMI2 target the copy is one `rorx`. Three
1161
+ * and five lanes rotate the copy the same way; six shift it right by 8, which
1162
+ * has the same two low bytes and measured faster there. On a
1163
+ * Xeon Platinum 8260 that is 6% less time a hash at the best width, 9% under
1164
+ * `--cpu x86-64-v3` (docs/security/crypto-bcrypt.md, "Cascade Lake"). The
1165
+ * barrier is an identity on a register: it adds no branch and no load, and
1166
+ * the round reads the same four S-box words.
1146
1167
  */
1147
1168
  const bcryptBody4 = (st: u32[]): void => {
1148
1169
  if (st.length < 4168) {
@@ -1162,45 +1183,53 @@ const bcryptBody4 = (st: u32[]): void => {
1162
1183
  l2 ^= st[2084]
1163
1184
  l3 ^= st[3126]
1164
1185
  for (let n: i32 = 1; n < 17; n += 2) {
1186
+ const l0e: u32 = ctSelect((l0 >>> 8) | (l0 << 24), 0xffffffff, 0)
1165
1187
  const l0a: i32 = toI32(l0 >>> 24) & 0xff
1166
- const l0b: i32 = toI32(l0 >>> 16) & 0xff
1167
- const l0c: i32 = toI32(l0 >>> 8) & 0xff
1188
+ const l0b: i32 = toI32(l0e >>> 8) & 0xff
1189
+ const l0c: i32 = toI32(l0e) & 0xff
1168
1190
  const l0d: i32 = toI32(l0) & 0xff
1191
+ r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
1192
+ const l1e: u32 = ctSelect((l1 >>> 8) | (l1 << 24), 0xffffffff, 0)
1169
1193
  const l1a: i32 = toI32(l1 >>> 24) & 0xff
1170
- const l1b: i32 = toI32(l1 >>> 16) & 0xff
1171
- const l1c: i32 = toI32(l1 >>> 8) & 0xff
1194
+ const l1b: i32 = toI32(l1e >>> 8) & 0xff
1195
+ const l1c: i32 = toI32(l1e) & 0xff
1172
1196
  const l1d: i32 = toI32(l1) & 0xff
1197
+ r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
1198
+ const l2e: u32 = ctSelect((l2 >>> 8) | (l2 << 24), 0xffffffff, 0)
1173
1199
  const l2a: i32 = toI32(l2 >>> 24) & 0xff
1174
- const l2b: i32 = toI32(l2 >>> 16) & 0xff
1175
- const l2c: i32 = toI32(l2 >>> 8) & 0xff
1200
+ const l2b: i32 = toI32(l2e >>> 8) & 0xff
1201
+ const l2c: i32 = toI32(l2e) & 0xff
1176
1202
  const l2d: i32 = toI32(l2) & 0xff
1203
+ r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
1204
+ const l3e: u32 = ctSelect((l3 >>> 8) | (l3 << 24), 0xffffffff, 0)
1177
1205
  const l3a: i32 = toI32(l3 >>> 24) & 0xff
1178
- const l3b: i32 = toI32(l3 >>> 16) & 0xff
1179
- const l3c: i32 = toI32(l3 >>> 8) & 0xff
1206
+ const l3b: i32 = toI32(l3e >>> 8) & 0xff
1207
+ const l3c: i32 = toI32(l3e) & 0xff
1180
1208
  const l3d: i32 = toI32(l3) & 0xff
1181
- r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
1182
- r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
1183
- r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
1184
1209
  r3 ^= st[3126 + n] ^ (((st[3144 + l3a] + st[3400 + l3b]) ^ st[3656 + l3c]) + st[3912 + l3d])
1210
+ const r0e: u32 = ctSelect((r0 >>> 8) | (r0 << 24), 0xffffffff, 0)
1185
1211
  const r0a: i32 = toI32(r0 >>> 24) & 0xff
1186
- const r0b: i32 = toI32(r0 >>> 16) & 0xff
1187
- const r0c: i32 = toI32(r0 >>> 8) & 0xff
1212
+ const r0b: i32 = toI32(r0e >>> 8) & 0xff
1213
+ const r0c: i32 = toI32(r0e) & 0xff
1188
1214
  const r0d: i32 = toI32(r0) & 0xff
1215
+ l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
1216
+ const r1e: u32 = ctSelect((r1 >>> 8) | (r1 << 24), 0xffffffff, 0)
1189
1217
  const r1a: i32 = toI32(r1 >>> 24) & 0xff
1190
- const r1b: i32 = toI32(r1 >>> 16) & 0xff
1191
- const r1c: i32 = toI32(r1 >>> 8) & 0xff
1218
+ const r1b: i32 = toI32(r1e >>> 8) & 0xff
1219
+ const r1c: i32 = toI32(r1e) & 0xff
1192
1220
  const r1d: i32 = toI32(r1) & 0xff
1221
+ l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
1222
+ const r2e: u32 = ctSelect((r2 >>> 8) | (r2 << 24), 0xffffffff, 0)
1193
1223
  const r2a: i32 = toI32(r2 >>> 24) & 0xff
1194
- const r2b: i32 = toI32(r2 >>> 16) & 0xff
1195
- const r2c: i32 = toI32(r2 >>> 8) & 0xff
1224
+ const r2b: i32 = toI32(r2e >>> 8) & 0xff
1225
+ const r2c: i32 = toI32(r2e) & 0xff
1196
1226
  const r2d: i32 = toI32(r2) & 0xff
1227
+ l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
1228
+ const r3e: u32 = ctSelect((r3 >>> 8) | (r3 << 24), 0xffffffff, 0)
1197
1229
  const r3a: i32 = toI32(r3 >>> 24) & 0xff
1198
- const r3b: i32 = toI32(r3 >>> 16) & 0xff
1199
- const r3c: i32 = toI32(r3 >>> 8) & 0xff
1230
+ const r3b: i32 = toI32(r3e >>> 8) & 0xff
1231
+ const r3c: i32 = toI32(r3e) & 0xff
1200
1232
  const r3d: i32 = toI32(r3) & 0xff
1201
- l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
1202
- l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
1203
- l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
1204
1233
  l3 ^= st[3126 + n + 1] ^ (((st[3144 + r3a] + st[3400 + r3b]) ^ st[3656 + r3c]) + st[3912 + r3d])
1205
1234
  }
1206
1235
  const t0: u32 = r0
@@ -1248,55 +1277,65 @@ const bcryptBody5 = (st: u32[]): void => {
1248
1277
  l3 ^= st[3126]
1249
1278
  l4 ^= st[4168]
1250
1279
  for (let n: i32 = 1; n < 17; n += 2) {
1280
+ const l0e: u32 = ctSelect((l0 >>> 8) | (l0 << 24), 0xffffffff, 0)
1251
1281
  const l0a: i32 = toI32(l0 >>> 24) & 0xff
1252
- const l0b: i32 = toI32(l0 >>> 16) & 0xff
1253
- const l0c: i32 = toI32(l0 >>> 8) & 0xff
1282
+ const l0b: i32 = toI32(l0e >>> 8) & 0xff
1283
+ const l0c: i32 = toI32(l0e) & 0xff
1254
1284
  const l0d: i32 = toI32(l0) & 0xff
1285
+ r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
1286
+ const l1e: u32 = ctSelect((l1 >>> 8) | (l1 << 24), 0xffffffff, 0)
1255
1287
  const l1a: i32 = toI32(l1 >>> 24) & 0xff
1256
- const l1b: i32 = toI32(l1 >>> 16) & 0xff
1257
- const l1c: i32 = toI32(l1 >>> 8) & 0xff
1288
+ const l1b: i32 = toI32(l1e >>> 8) & 0xff
1289
+ const l1c: i32 = toI32(l1e) & 0xff
1258
1290
  const l1d: i32 = toI32(l1) & 0xff
1291
+ r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
1292
+ const l2e: u32 = ctSelect((l2 >>> 8) | (l2 << 24), 0xffffffff, 0)
1259
1293
  const l2a: i32 = toI32(l2 >>> 24) & 0xff
1260
- const l2b: i32 = toI32(l2 >>> 16) & 0xff
1261
- const l2c: i32 = toI32(l2 >>> 8) & 0xff
1294
+ const l2b: i32 = toI32(l2e >>> 8) & 0xff
1295
+ const l2c: i32 = toI32(l2e) & 0xff
1262
1296
  const l2d: i32 = toI32(l2) & 0xff
1297
+ r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
1298
+ const l3e: u32 = ctSelect((l3 >>> 8) | (l3 << 24), 0xffffffff, 0)
1263
1299
  const l3a: i32 = toI32(l3 >>> 24) & 0xff
1264
- const l3b: i32 = toI32(l3 >>> 16) & 0xff
1265
- const l3c: i32 = toI32(l3 >>> 8) & 0xff
1300
+ const l3b: i32 = toI32(l3e >>> 8) & 0xff
1301
+ const l3c: i32 = toI32(l3e) & 0xff
1266
1302
  const l3d: i32 = toI32(l3) & 0xff
1303
+ r3 ^= st[3126 + n] ^ (((st[3144 + l3a] + st[3400 + l3b]) ^ st[3656 + l3c]) + st[3912 + l3d])
1304
+ const l4e: u32 = ctSelect((l4 >>> 8) | (l4 << 24), 0xffffffff, 0)
1267
1305
  const l4a: i32 = toI32(l4 >>> 24) & 0xff
1268
- const l4b: i32 = toI32(l4 >>> 16) & 0xff
1269
- const l4c: i32 = toI32(l4 >>> 8) & 0xff
1306
+ const l4b: i32 = toI32(l4e >>> 8) & 0xff
1307
+ const l4c: i32 = toI32(l4e) & 0xff
1270
1308
  const l4d: i32 = toI32(l4) & 0xff
1271
- r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
1272
- r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
1273
- r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
1274
- r3 ^= st[3126 + n] ^ (((st[3144 + l3a] + st[3400 + l3b]) ^ st[3656 + l3c]) + st[3912 + l3d])
1275
1309
  r4 ^= st[4168 + n] ^ (((st[4186 + l4a] + st[4442 + l4b]) ^ st[4698 + l4c]) + st[4954 + l4d])
1310
+ const r0e: u32 = ctSelect((r0 >>> 8) | (r0 << 24), 0xffffffff, 0)
1276
1311
  const r0a: i32 = toI32(r0 >>> 24) & 0xff
1277
- const r0b: i32 = toI32(r0 >>> 16) & 0xff
1278
- const r0c: i32 = toI32(r0 >>> 8) & 0xff
1312
+ const r0b: i32 = toI32(r0e >>> 8) & 0xff
1313
+ const r0c: i32 = toI32(r0e) & 0xff
1279
1314
  const r0d: i32 = toI32(r0) & 0xff
1315
+ l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
1316
+ const r1e: u32 = ctSelect((r1 >>> 8) | (r1 << 24), 0xffffffff, 0)
1280
1317
  const r1a: i32 = toI32(r1 >>> 24) & 0xff
1281
- const r1b: i32 = toI32(r1 >>> 16) & 0xff
1282
- const r1c: i32 = toI32(r1 >>> 8) & 0xff
1318
+ const r1b: i32 = toI32(r1e >>> 8) & 0xff
1319
+ const r1c: i32 = toI32(r1e) & 0xff
1283
1320
  const r1d: i32 = toI32(r1) & 0xff
1321
+ l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
1322
+ const r2e: u32 = ctSelect((r2 >>> 8) | (r2 << 24), 0xffffffff, 0)
1284
1323
  const r2a: i32 = toI32(r2 >>> 24) & 0xff
1285
- const r2b: i32 = toI32(r2 >>> 16) & 0xff
1286
- const r2c: i32 = toI32(r2 >>> 8) & 0xff
1324
+ const r2b: i32 = toI32(r2e >>> 8) & 0xff
1325
+ const r2c: i32 = toI32(r2e) & 0xff
1287
1326
  const r2d: i32 = toI32(r2) & 0xff
1327
+ l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
1328
+ const r3e: u32 = ctSelect((r3 >>> 8) | (r3 << 24), 0xffffffff, 0)
1288
1329
  const r3a: i32 = toI32(r3 >>> 24) & 0xff
1289
- const r3b: i32 = toI32(r3 >>> 16) & 0xff
1290
- const r3c: i32 = toI32(r3 >>> 8) & 0xff
1330
+ const r3b: i32 = toI32(r3e >>> 8) & 0xff
1331
+ const r3c: i32 = toI32(r3e) & 0xff
1291
1332
  const r3d: i32 = toI32(r3) & 0xff
1333
+ l3 ^= st[3126 + n + 1] ^ (((st[3144 + r3a] + st[3400 + r3b]) ^ st[3656 + r3c]) + st[3912 + r3d])
1334
+ const r4e: u32 = ctSelect((r4 >>> 8) | (r4 << 24), 0xffffffff, 0)
1292
1335
  const r4a: i32 = toI32(r4 >>> 24) & 0xff
1293
- const r4b: i32 = toI32(r4 >>> 16) & 0xff
1294
- const r4c: i32 = toI32(r4 >>> 8) & 0xff
1336
+ const r4b: i32 = toI32(r4e >>> 8) & 0xff
1337
+ const r4c: i32 = toI32(r4e) & 0xff
1295
1338
  const r4d: i32 = toI32(r4) & 0xff
1296
- l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
1297
- l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
1298
- l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
1299
- l3 ^= st[3126 + n + 1] ^ (((st[3144 + r3a] + st[3400 + r3b]) ^ st[3656 + r3c]) + st[3912 + r3d])
1300
1339
  l4 ^= st[4168 + n + 1] ^ (((st[4186 + r4a] + st[4442 + r4b]) ^ st[4698 + r4c]) + st[4954 + r4d])
1301
1340
  }
1302
1341
  const t0: u32 = r0
@@ -1352,65 +1391,77 @@ const bcryptBody6 = (st: u32[]): void => {
1352
1391
  l4 ^= st[4168]
1353
1392
  l5 ^= st[5210]
1354
1393
  for (let n: i32 = 1; n < 17; n += 2) {
1394
+ const l0e: u32 = ctSelect(l0 >>> 8, 0xffffffff, 0)
1355
1395
  const l0a: i32 = toI32(l0 >>> 24) & 0xff
1356
- const l0b: i32 = toI32(l0 >>> 16) & 0xff
1357
- const l0c: i32 = toI32(l0 >>> 8) & 0xff
1396
+ const l0b: i32 = toI32(l0e >>> 8) & 0xff
1397
+ const l0c: i32 = toI32(l0e) & 0xff
1358
1398
  const l0d: i32 = toI32(l0) & 0xff
1399
+ r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
1400
+ const l1e: u32 = ctSelect(l1 >>> 8, 0xffffffff, 0)
1359
1401
  const l1a: i32 = toI32(l1 >>> 24) & 0xff
1360
- const l1b: i32 = toI32(l1 >>> 16) & 0xff
1361
- const l1c: i32 = toI32(l1 >>> 8) & 0xff
1402
+ const l1b: i32 = toI32(l1e >>> 8) & 0xff
1403
+ const l1c: i32 = toI32(l1e) & 0xff
1362
1404
  const l1d: i32 = toI32(l1) & 0xff
1405
+ r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
1406
+ const l2e: u32 = ctSelect(l2 >>> 8, 0xffffffff, 0)
1363
1407
  const l2a: i32 = toI32(l2 >>> 24) & 0xff
1364
- const l2b: i32 = toI32(l2 >>> 16) & 0xff
1365
- const l2c: i32 = toI32(l2 >>> 8) & 0xff
1408
+ const l2b: i32 = toI32(l2e >>> 8) & 0xff
1409
+ const l2c: i32 = toI32(l2e) & 0xff
1366
1410
  const l2d: i32 = toI32(l2) & 0xff
1411
+ r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
1412
+ const l3e: u32 = ctSelect(l3 >>> 8, 0xffffffff, 0)
1367
1413
  const l3a: i32 = toI32(l3 >>> 24) & 0xff
1368
- const l3b: i32 = toI32(l3 >>> 16) & 0xff
1369
- const l3c: i32 = toI32(l3 >>> 8) & 0xff
1414
+ const l3b: i32 = toI32(l3e >>> 8) & 0xff
1415
+ const l3c: i32 = toI32(l3e) & 0xff
1370
1416
  const l3d: i32 = toI32(l3) & 0xff
1417
+ r3 ^= st[3126 + n] ^ (((st[3144 + l3a] + st[3400 + l3b]) ^ st[3656 + l3c]) + st[3912 + l3d])
1418
+ const l4e: u32 = ctSelect(l4 >>> 8, 0xffffffff, 0)
1371
1419
  const l4a: i32 = toI32(l4 >>> 24) & 0xff
1372
- const l4b: i32 = toI32(l4 >>> 16) & 0xff
1373
- const l4c: i32 = toI32(l4 >>> 8) & 0xff
1420
+ const l4b: i32 = toI32(l4e >>> 8) & 0xff
1421
+ const l4c: i32 = toI32(l4e) & 0xff
1374
1422
  const l4d: i32 = toI32(l4) & 0xff
1423
+ r4 ^= st[4168 + n] ^ (((st[4186 + l4a] + st[4442 + l4b]) ^ st[4698 + l4c]) + st[4954 + l4d])
1424
+ const l5e: u32 = ctSelect(l5 >>> 8, 0xffffffff, 0)
1375
1425
  const l5a: i32 = toI32(l5 >>> 24) & 0xff
1376
- const l5b: i32 = toI32(l5 >>> 16) & 0xff
1377
- const l5c: i32 = toI32(l5 >>> 8) & 0xff
1426
+ const l5b: i32 = toI32(l5e >>> 8) & 0xff
1427
+ const l5c: i32 = toI32(l5e) & 0xff
1378
1428
  const l5d: i32 = toI32(l5) & 0xff
1379
- r0 ^= st[n] ^ (((st[18 + l0a] + st[274 + l0b]) ^ st[530 + l0c]) + st[786 + l0d])
1380
- r1 ^= st[1042 + n] ^ (((st[1060 + l1a] + st[1316 + l1b]) ^ st[1572 + l1c]) + st[1828 + l1d])
1381
- r2 ^= st[2084 + n] ^ (((st[2102 + l2a] + st[2358 + l2b]) ^ st[2614 + l2c]) + st[2870 + l2d])
1382
- r3 ^= st[3126 + n] ^ (((st[3144 + l3a] + st[3400 + l3b]) ^ st[3656 + l3c]) + st[3912 + l3d])
1383
- r4 ^= st[4168 + n] ^ (((st[4186 + l4a] + st[4442 + l4b]) ^ st[4698 + l4c]) + st[4954 + l4d])
1384
1429
  r5 ^= st[5210 + n] ^ (((st[5228 + l5a] + st[5484 + l5b]) ^ st[5740 + l5c]) + st[5996 + l5d])
1430
+ const r0e: u32 = ctSelect(r0 >>> 8, 0xffffffff, 0)
1385
1431
  const r0a: i32 = toI32(r0 >>> 24) & 0xff
1386
- const r0b: i32 = toI32(r0 >>> 16) & 0xff
1387
- const r0c: i32 = toI32(r0 >>> 8) & 0xff
1432
+ const r0b: i32 = toI32(r0e >>> 8) & 0xff
1433
+ const r0c: i32 = toI32(r0e) & 0xff
1388
1434
  const r0d: i32 = toI32(r0) & 0xff
1435
+ l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
1436
+ const r1e: u32 = ctSelect(r1 >>> 8, 0xffffffff, 0)
1389
1437
  const r1a: i32 = toI32(r1 >>> 24) & 0xff
1390
- const r1b: i32 = toI32(r1 >>> 16) & 0xff
1391
- const r1c: i32 = toI32(r1 >>> 8) & 0xff
1438
+ const r1b: i32 = toI32(r1e >>> 8) & 0xff
1439
+ const r1c: i32 = toI32(r1e) & 0xff
1392
1440
  const r1d: i32 = toI32(r1) & 0xff
1441
+ l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
1442
+ const r2e: u32 = ctSelect(r2 >>> 8, 0xffffffff, 0)
1393
1443
  const r2a: i32 = toI32(r2 >>> 24) & 0xff
1394
- const r2b: i32 = toI32(r2 >>> 16) & 0xff
1395
- const r2c: i32 = toI32(r2 >>> 8) & 0xff
1444
+ const r2b: i32 = toI32(r2e >>> 8) & 0xff
1445
+ const r2c: i32 = toI32(r2e) & 0xff
1396
1446
  const r2d: i32 = toI32(r2) & 0xff
1447
+ l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
1448
+ const r3e: u32 = ctSelect(r3 >>> 8, 0xffffffff, 0)
1397
1449
  const r3a: i32 = toI32(r3 >>> 24) & 0xff
1398
- const r3b: i32 = toI32(r3 >>> 16) & 0xff
1399
- const r3c: i32 = toI32(r3 >>> 8) & 0xff
1450
+ const r3b: i32 = toI32(r3e >>> 8) & 0xff
1451
+ const r3c: i32 = toI32(r3e) & 0xff
1400
1452
  const r3d: i32 = toI32(r3) & 0xff
1453
+ l3 ^= st[3126 + n + 1] ^ (((st[3144 + r3a] + st[3400 + r3b]) ^ st[3656 + r3c]) + st[3912 + r3d])
1454
+ const r4e: u32 = ctSelect(r4 >>> 8, 0xffffffff, 0)
1401
1455
  const r4a: i32 = toI32(r4 >>> 24) & 0xff
1402
- const r4b: i32 = toI32(r4 >>> 16) & 0xff
1403
- const r4c: i32 = toI32(r4 >>> 8) & 0xff
1456
+ const r4b: i32 = toI32(r4e >>> 8) & 0xff
1457
+ const r4c: i32 = toI32(r4e) & 0xff
1404
1458
  const r4d: i32 = toI32(r4) & 0xff
1459
+ l4 ^= st[4168 + n + 1] ^ (((st[4186 + r4a] + st[4442 + r4b]) ^ st[4698 + r4c]) + st[4954 + r4d])
1460
+ const r5e: u32 = ctSelect(r5 >>> 8, 0xffffffff, 0)
1405
1461
  const r5a: i32 = toI32(r5 >>> 24) & 0xff
1406
- const r5b: i32 = toI32(r5 >>> 16) & 0xff
1407
- const r5c: i32 = toI32(r5 >>> 8) & 0xff
1462
+ const r5b: i32 = toI32(r5e >>> 8) & 0xff
1463
+ const r5c: i32 = toI32(r5e) & 0xff
1408
1464
  const r5d: i32 = toI32(r5) & 0xff
1409
- l0 ^= st[n + 1] ^ (((st[18 + r0a] + st[274 + r0b]) ^ st[530 + r0c]) + st[786 + r0d])
1410
- l1 ^= st[1042 + n + 1] ^ (((st[1060 + r1a] + st[1316 + r1b]) ^ st[1572 + r1c]) + st[1828 + r1d])
1411
- l2 ^= st[2084 + n + 1] ^ (((st[2102 + r2a] + st[2358 + r2b]) ^ st[2614 + r2c]) + st[2870 + r2d])
1412
- l3 ^= st[3126 + n + 1] ^ (((st[3144 + r3a] + st[3400 + r3b]) ^ st[3656 + r3c]) + st[3912 + r3d])
1413
- l4 ^= st[4168 + n + 1] ^ (((st[4186 + r4a] + st[4442 + r4b]) ^ st[4698 + r4c]) + st[4954 + r4d])
1414
1465
  l5 ^= st[5210 + n + 1] ^ (((st[5228 + r5a] + st[5484 + r5b]) ^ st[5740 + r5c]) + st[5996 + r5d])
1415
1466
  }
1416
1467
  const t0: u32 = r0
package/std/sort.ts ADDED
@@ -0,0 +1,178 @@
1
+ /**
2
+ * `std/sort` — `xs.sort(cmp)` on an array, in Nish: a stable merge sort,
3
+ * compiled once per comparator.
4
+ *
5
+ * A program does not import this module. A `.sort(cmp)` call is what loads it
6
+ * (the checker's `importSort`), and the checker routes the call to `sortWith`
7
+ * here. `cmp` is a compile-time function parameter, so each comparator is an
8
+ * instantiation of its own whose body calls the comparator directly — there is
9
+ * no function pointer. Under Node and `tsc` the call is the platform's
10
+ * `Array.prototype.sort`, so nothing here runs there.
11
+ *
12
+ * **Same order as Node.** `Array.prototype.sort` is stable (ES2019), so for a
13
+ * comparator that is a consistent total preorder there is exactly one answer,
14
+ * and any stable sort gives it. A comparator's result is read only as "greater
15
+ * than zero or not": a later element moves before an earlier one only when
16
+ * the comparator answers a positive number for (earlier, later), so a negative
17
+ * zero and NaN are zero, as Node treats them.
18
+ *
19
+ * **Shape.** The array is copied once into a scratch array of the same
20
+ * length, the only allocation, which the function's arena scope gives back
21
+ * before it returns, so a sort leaves `Arena.used()` where it was. Runs of
22
+ * `RUN` are sorted by insertion from the scratch into the array (a strictly
23
+ * descending run is copied reversed instead), then merged
24
+ * bottom-up, alternating between the two, and copied back once if the last
25
+ * pass ended in the scratch. A pair of runs already in order is copied without
26
+ * a merge. Every merge takes from the left run on a tie, which is what makes
27
+ * it stable.
28
+ *
29
+ * **No element is held across a write.** An `interface` element is stored
30
+ * inline, and `const v = xs[i]` is a pointer into the array, so an insertion
31
+ * sort in place would overwrite the element it is inserting. Every step here
32
+ * reads from one array and writes the other, and moves a whole slot, which for
33
+ * an inline record is one copy of its bytes.
34
+ *
35
+ * **Proofs.** Every index is proven in range by the guard written beside it,
36
+ * so no access keeps its bounds check. The run arithmetic wraps only where
37
+ * the operands are proven to lie in `0..n`, so it cannot wrap: a difference
38
+ * of two of them, or a sum taken only when it stays below `n`.
39
+ */
40
+
41
+ import { wrappingAdd, wrappingSub } from "nish:unsafe"
42
+
43
+ /** The length of the runs insertion sort makes before the first merge. */
44
+ const RUN: i32 = 32
45
+
46
+ /**
47
+ * `lo + step`, or `n` when that is not below `n`. Every caller has
48
+ * `0 <= lo <= n`, so `n - lo` cannot wrap, and the sum is taken only below `n`.
49
+ */
50
+ const stepTo = (lo: i32, step: i32, n: i32): i32 => (wrappingSub(n, lo) > step ? wrappingAdd(lo, step) : n)
51
+
52
+ /**
53
+ * `src[lo..hi)` sorted by insertion into `dst[lo..hi)`. The comparator call
54
+ * forgets every array length, so each access after it repeats its guard.
55
+ */
56
+ const insertionRun = <T>(src: T[], dst: T[], cmp: (a: T, b: T) => number, lo: i32, hi: i32): void => {
57
+ // A strictly descending run is copied reversed: no two of its elements are
58
+ // equal, so reversing it keeps the sort stable, and costs one comparison each.
59
+ // `lo < hi`, and `d` steps only while below `hi`, so neither `+ 1` wraps.
60
+ let d = wrappingAdd(lo, 1)
61
+ while (d > 0 && d < hi && d < toI32(src.length)) {
62
+ const p = d - 1
63
+ if (!(cmp(src[p], src[d]) > 0)) {
64
+ break
65
+ }
66
+ d = wrappingAdd(d, 1)
67
+ }
68
+ if (d >= hi) {
69
+ // `hi > lo >= 0`, so `hi - 1` does not wrap, and `r` steps down only from `r >= 0`.
70
+ let r = wrappingSub(hi, 1)
71
+ for (let k: i32 = lo; k >= 0 && k < hi && k < toI32(dst.length) && r >= 0 && r < toI32(src.length); k++) {
72
+ dst[k] = src[r]
73
+ r = wrappingSub(r, 1)
74
+ }
75
+ return
76
+ }
77
+ for (let i: i32 = lo; i >= 0 && i < hi; i++) {
78
+ let j = i
79
+ while (j > lo && j > 0 && j < toI32(dst.length) && i < toI32(src.length)) {
80
+ const k = j - 1
81
+ if (!(cmp(dst[k], src[i]) > 0) || k < 0 || k >= toI32(dst.length) || j >= toI32(dst.length)) {
82
+ break
83
+ }
84
+ dst[j] = dst[k]
85
+ j = k
86
+ }
87
+ if (i < toI32(src.length) && j >= 0 && j < toI32(dst.length)) {
88
+ dst[j] = src[i]
89
+ }
90
+ }
91
+ }
92
+
93
+ /** `src[lo..hi)` copied into `dst[lo..hi)`. */
94
+ const copyRun = <T>(src: T[], dst: T[], lo: i32, hi: i32): void => {
95
+ for (let k: i32 = lo; k >= 0 && k < hi && k < toI32(src.length) && k < toI32(dst.length); k++) {
96
+ dst[k] = src[k]
97
+ }
98
+ }
99
+
100
+ /**
101
+ * The sorted runs `src[lo..mid)` and `src[mid..hi)` merged into `dst[lo..hi)`,
102
+ * or copied when the last of the left run is not after the first of the right.
103
+ */
104
+ const mergeRuns = <T>(src: T[], dst: T[], cmp: (a: T, b: T) => number, lo: i32, mid: i32, hi: i32): void => {
105
+ if (mid > 0 && mid < hi && mid < toI32(src.length)) {
106
+ const last = mid - 1
107
+ if (last < toI32(src.length) && !(cmp(src[last], src[mid]) > 0)) {
108
+ copyRun(src, dst, lo, hi)
109
+ return
110
+ }
111
+ }
112
+ let i = lo
113
+ let j = mid
114
+ for (let k: i32 = lo; k >= 0 && k < hi; k++) {
115
+ let right = i >= mid
116
+ if (!right && j < hi && i >= 0 && i < toI32(src.length) && j >= 0 && j < toI32(src.length)) {
117
+ right = cmp(src[i], src[j]) > 0
118
+ }
119
+ if (right) {
120
+ if (j >= 0 && j < toI32(src.length) && k < toI32(dst.length)) {
121
+ dst[k] = src[j]
122
+ }
123
+ // `j` steps at most `hi - mid` times from `mid`, so it stays at most `hi`.
124
+ j = wrappingAdd(j, 1)
125
+ } else {
126
+ if (i >= 0 && i < toI32(src.length) && k < toI32(dst.length)) {
127
+ dst[k] = src[i]
128
+ }
129
+ // `i` steps at most `mid - lo` times from `lo`, so it stays at most `mid`.
130
+ i = wrappingAdd(i, 1)
131
+ }
132
+ }
133
+ }
134
+
135
+ /** One bottom-up pass: every pair of adjacent `width`-runs of `src` merged into `dst`. */
136
+ const mergePass = <T>(src: T[], dst: T[], cmp: (a: T, b: T) => number, n: i32, width: i32): void => {
137
+ let lo: i32 = 0
138
+ while (lo >= 0 && lo < n) {
139
+ const mid = stepTo(lo, width, n)
140
+ const hi = stepTo(mid, width, n)
141
+ mergeRuns(src, dst, cmp, lo, mid, hi)
142
+ lo = hi
143
+ }
144
+ }
145
+
146
+ /** `xs` sorted in place by `cmp`, stably, and answered: what `xs.sort(cmp)` compiles to. */
147
+ export const sortWith = <T>(xs: T[], cmp: (a: T, b: T) => number): T[] => {
148
+ const n: i32 = toI32(xs.length)
149
+ if (n < 2) {
150
+ return xs
151
+ }
152
+ // One allocation at full size, every slot written before any is read: the
153
+ // checker lets this `new Array<T>(n)` hold any `T`, and neither emitter
154
+ // zero-fills it (`isSortInstance`).
155
+ const tmp = new Array<T>(n)
156
+ copyRun(xs, tmp, 0, n)
157
+ let lo: i32 = 0
158
+ while (lo >= 0 && lo < n) {
159
+ const hi = stepTo(lo, RUN, n)
160
+ insertionRun(tmp, xs, cmp, lo, hi)
161
+ lo = hi
162
+ }
163
+ let inTmp = false
164
+ let width: i32 = RUN
165
+ while (width > 0 && width < n) {
166
+ if (inTmp) {
167
+ mergePass(tmp, xs, cmp, n, width)
168
+ } else {
169
+ mergePass(xs, tmp, cmp, n, width)
170
+ }
171
+ inTmp = !inTmp
172
+ width = stepTo(width, width, n)
173
+ }
174
+ if (inTmp) {
175
+ copyRun(tmp, xs, 0, n)
176
+ }
177
+ return xs
178
+ }