@datakable/core 2.0.2 → 2.1.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/dist/{codes-AX8XkMNY.d.cts → codes-4sYQv_7J.d.cts} +36 -10
- package/dist/{codes-AX8XkMNY.d.ts → codes-4sYQv_7J.d.ts} +36 -10
- package/dist/column-filters.d.cts +2 -2
- package/dist/column-filters.d.ts +2 -2
- package/dist/diagnostics/build.cjs +1 -1
- package/dist/diagnostics/build.cjs.map +1 -1
- package/dist/diagnostics/build.js +2 -2
- package/dist/diagnostics/build.js.map +1 -1
- package/dist/diagnostics/console.cjs +15 -4
- package/dist/diagnostics/console.cjs.map +1 -1
- package/dist/diagnostics/console.js +15 -4
- package/dist/diagnostics/console.js.map +1 -1
- package/dist/diagnostics/prose.cjs +10 -1
- package/dist/diagnostics/prose.cjs.map +1 -1
- package/dist/diagnostics/prose.js +9 -1
- package/dist/diagnostics/prose.js.map +1 -1
- package/dist/{explain-pKAnnxEW.d.cts → explain-DmwN_RG9.d.cts} +11 -4
- package/dist/{explain-BVE3ln3G.d.ts → explain-Dr3SmMNY.d.ts} +11 -4
- package/dist/feature/install.cjs +2 -1
- package/dist/feature/install.cjs.map +1 -1
- package/dist/feature/install.js +2 -1
- package/dist/feature/install.js.map +1 -1
- package/dist/feature/slice-guard.cjs +76 -0
- package/dist/feature/slice-guard.cjs.map +1 -0
- package/dist/feature/slice-guard.js +50 -0
- package/dist/feature/slice-guard.js.map +1 -0
- package/dist/features/column-filters/codes.cjs +2 -19
- package/dist/features/column-filters/codes.cjs.map +1 -1
- package/dist/features/column-filters/codes.js +2 -19
- package/dist/features/column-filters/codes.js.map +1 -1
- package/dist/features/column-filters/column-filters.cjs +37 -22
- package/dist/features/column-filters/column-filters.cjs.map +1 -1
- package/dist/features/column-filters/column-filters.js +37 -22
- package/dist/features/column-filters/column-filters.js.map +1 -1
- package/dist/features/column-filters/match.cjs +6 -2
- package/dist/features/column-filters/match.cjs.map +1 -1
- package/dist/features/column-filters/match.js +6 -2
- package/dist/features/column-filters/match.js.map +1 -1
- package/dist/features/pagination/pagination.cjs +2 -2
- package/dist/features/pagination/pagination.cjs.map +1 -1
- package/dist/features/pagination/pagination.js +2 -2
- package/dist/features/pagination/pagination.js.map +1 -1
- package/dist/features/search/codes.cjs +18 -2
- package/dist/features/search/codes.cjs.map +1 -1
- package/dist/features/search/codes.js +16 -1
- package/dist/features/search/codes.js.map +1 -1
- package/dist/features/search/search-engine.cjs +24 -5
- package/dist/features/search/search-engine.cjs.map +1 -1
- package/dist/features/search/search-engine.js +25 -6
- package/dist/features/search/search-engine.js.map +1 -1
- package/dist/features/search/search-index.cjs +23 -44
- package/dist/features/search/search-index.cjs.map +1 -1
- package/dist/features/search/search-index.js +24 -45
- package/dist/features/search/search-index.js.map +1 -1
- package/dist/features/sorting/ranks.cjs +117 -50
- package/dist/features/sorting/ranks.cjs.map +1 -1
- package/dist/features/sorting/ranks.js +117 -50
- package/dist/features/sorting/ranks.js.map +1 -1
- package/dist/features/sorting/sorting.cjs +87 -32
- package/dist/features/sorting/sorting.cjs.map +1 -1
- package/dist/features/sorting/sorting.js +87 -32
- package/dist/features/sorting/sorting.js.map +1 -1
- package/dist/index.d.cts +26 -17
- package/dist/index.d.ts +26 -17
- package/dist/intercept/runtime.cjs +3 -2
- package/dist/intercept/runtime.cjs.map +1 -1
- package/dist/intercept/runtime.js +3 -2
- package/dist/intercept/runtime.js.map +1 -1
- package/dist/messages/index.cjs +2 -0
- package/dist/messages/index.cjs.map +1 -1
- package/dist/messages/index.js +2 -0
- package/dist/messages/index.js.map +1 -1
- package/dist/pagination.d.cts +2 -2
- package/dist/pagination.d.ts +2 -2
- package/dist/pipeline/column-cache.cjs +6 -2
- package/dist/pipeline/column-cache.cjs.map +1 -1
- package/dist/pipeline/column-cache.js +6 -2
- package/dist/pipeline/column-cache.js.map +1 -1
- package/dist/pipeline/release.cjs +34 -0
- package/dist/pipeline/release.cjs.map +1 -0
- package/dist/pipeline/release.js +8 -0
- package/dist/pipeline/release.js.map +1 -0
- package/dist/pipeline/runner.cjs +15 -1
- package/dist/pipeline/runner.cjs.map +1 -1
- package/dist/pipeline/runner.js +15 -1
- package/dist/pipeline/runner.js.map +1 -1
- package/dist/schema.d.cts +2 -2
- package/dist/schema.d.ts +2 -2
- package/dist/{search-async-entry-ByMJbHjc.d.cts → search-async-entry-BiemO3JT.d.cts} +2 -2
- package/dist/{search-async-entry-CFQODE08.d.ts → search-async-entry-GRj0E06n.d.ts} +2 -2
- package/dist/search-async.d.cts +3 -3
- package/dist/search-async.d.ts +3 -3
- package/dist/search.d.cts +4 -4
- package/dist/search.d.ts +4 -4
- package/dist/server.d.cts +3 -3
- package/dist/server.d.ts +3 -3
- package/dist/sorting.d.cts +2 -2
- package/dist/sorting.d.ts +2 -2
- package/dist/source/async-control.cjs +2 -1
- package/dist/source/async-control.cjs.map +1 -1
- package/dist/source/async-control.js +2 -1
- package/dist/source/async-control.js.map +1 -1
- package/dist/source/fetcher.cjs.map +1 -1
- package/dist/source/fetcher.js.map +1 -1
- package/dist/source/server.cjs +58 -5
- package/dist/source/server.cjs.map +1 -1
- package/dist/source/server.js +58 -5
- package/dist/source/server.js.map +1 -1
- package/dist/table/create-table.cjs +33 -20
- package/dist/table/create-table.cjs.map +1 -1
- package/dist/table/create-table.js +33 -20
- package/dist/table/create-table.js.map +1 -1
- package/dist/table/index.cjs +3 -0
- package/dist/table/index.cjs.map +1 -1
- package/dist/table/index.js +5 -1
- package/dist/table/index.js.map +1 -1
- package/dist/table/state-codes.cjs +72 -0
- package/dist/table/state-codes.cjs.map +1 -0
- package/dist/table/state-codes.js +45 -0
- package/dist/table/state-codes.js.map +1 -0
- package/dist/table/types.cjs.map +1 -1
- package/dist/table/types.js.map +1 -1
- package/dist/validity.d.cts +2 -2
- package/dist/validity.d.ts +2 -2
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +3 -3
- package/dist/ingest/test-schemas.cjs +0 -73
- package/dist/ingest/test-schemas.cjs.map +0 -1
- package/dist/ingest/test-schemas.js +0 -46
- package/dist/ingest/test-schemas.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/features/sorting/ranks.ts"],"sourcesContent":["import { RANK, typeRank } from './compare'\n\n/** Comparisons / rows between two `yield`s of the jobs below (§9.1). */\nconst CHUNK = 4096\n/** Run length sorted natively before the merge passes. */\nconst RUN = 512\n\n/**\n * Sorts `0..n-1` by `cmp` as a time-sliced job (§9.1): native sorts of short runs, then bottom-up\n * merge passes that `yield` every {@link CHUNK} comparisons. Stable.\n */\nfunction* sortPositions(\n n: number,\n cmp: (a: number, b: number) => number,\n): Generator<undefined, Uint32Array, undefined> {\n let a = new Uint32Array(n)\n for (let i = 0; i < n; i++) a[i] = i\n for (let lo = 0; lo < n; lo += RUN) {\n a.subarray(lo, Math.min(lo + RUN, n)).sort(cmp)\n yield\n }\n let b = new Uint32Array(n)\n let ops = 0\n for (let width = RUN; width < n; width *= 2) {\n for (let lo = 0; lo < n; lo += 2 * width) {\n const mid = Math.min(lo + width, n)\n const hi = Math.min(lo + 2 * width, n)\n let i = lo\n let j = mid\n let k = lo\n while (i < mid && j < hi) {\n const x = a[i] as number\n const y = a[j] as number\n if (cmp(y, x) < 0) {\n b[k++] = y\n j++\n } else {\n b[k++] = x\n i++\n }\n if (++ops === CHUNK) {\n ops = 0\n yield\n }\n }\n while (i < mid) b[k++] = a[i++] as number\n while (j < hi) b[k++] = a[j++] as number\n }\n const t = a\n a = b\n b = t\n }\n return a\n}\n\n/**\n * Collation ranks of a string column (§6.4, §9.1): per row, the dense rank of its string among\n * the column's distinct strings in `collator` order (strings the collator finds equal share a\n * rank), `NaN` for a missing value. Sorting by these numbers gives exactly the order of\n * `collator.compare`, with integer keys (counting / radix sort) instead of a collator call per\n * comparison. A time-sliced job; `null` when a present value is not a string.\n */\nexport function* collationRanks(\n values: readonly unknown[],\n collator: Intl.Collator,\n): Generator<undefined, Float64Array | null, undefined> {\n const n = values.length\n const ids = new Map<string, number>()\n const distinct: string[] = []\n /** Per row: its string's position in `distinct`, -1 when missing. */\n const slot = new Int32Array(n)\n for (let r = 0; r < n; r++) {\n const v = values[r]\n if (typeof v === 'string') {\n let id = ids.get(v)\n if (id === undefined) {\n id = distinct.length\n ids.set(v, id)\n distinct.push(v)\n }\n slot[r] = id\n } else if (typeRank(v) === RANK.missing) slot[r] = -1\n else return null\n if (r % CHUNK === CHUNK - 1) yield\n }\n const order = yield* sortPositions(distinct.length, (a, b) =>\n collator.compare(distinct[a] as string, distinct[b] as string),\n )\n const rankOf = new Float64Array(distinct.length)\n let rank = 0\n for (let k = 0; k < order.length; k++) {\n const id = order[k] as number\n const s = distinct[id] as string\n if (k > 0 && collator.compare(distinct[order[k - 1] as number] as string, s) !== 0) rank++\n rankOf[id] = rank\n if (k % CHUNK === CHUNK - 1) yield\n }\n const out = new Float64Array(n)\n for (let r = 0; r < n; r++) {\n const id = slot[r] as number\n out[r] = id < 0 ? Number.NaN : (rankOf[id] as number)\n }\n return out\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/features/sorting/ranks.ts"],"sourcesContent":["import { RANK, typeRank } from './compare'\n\n/** Comparisons / rows between two `yield`s of the jobs below (§9.1). */\nconst CHUNK = 4096\n/**\n * Run length sorted natively before the merge passes (#97, was 512): each doubling saves a merge\n * pass, and one native run of collator calls stays within a slice even under a 4x CPU throttle.\n */\nconst RUN = 1024\n\n/**\n * Sorts `0..n-1` by `cmp` as a time-sliced job (§9.1): native sorts of `run`s, then bottom-up\n * merge passes that `yield` every {@link CHUNK} comparisons. Stable. Also returns `eq`:\n * `eq[k] = 1` when `order[k]` compares equal to `order[k - 1]`, from the comparisons the merges\n * make anyway (#97). Inside a native run it costs a second pass only when that sort saw a 0.\n */\nfunction* sortPositions(\n n: number,\n cmp: (a: number, b: number) => number,\n run: number,\n): Generator<undefined, { order: Uint32Array; eq: Uint8Array }, undefined> {\n let a = new Uint32Array(n)\n let ea = new Uint8Array(n)\n for (let i = 0; i < n; i++) a[i] = i\n for (let lo = 0; lo < n; lo += run) {\n const hi = Math.min(lo + run, n)\n let zero = false\n a.subarray(lo, hi).sort((x, y) => {\n const c = cmp(x, y)\n if (c === 0) zero = true\n return c\n })\n // Neighbours can only be equal if the sort saw a 0 (it must, to order them).\n if (zero)\n for (let k = lo + 1; k < hi; k++) ea[k] = cmp(a[k - 1] as number, a[k] as number) ? 0 : 1\n yield\n }\n let b = new Uint32Array(n)\n let eb = new Uint8Array(n)\n let ops = 0\n for (let width = run; width < n; width *= 2) {\n for (let lo = 0; lo < n; lo += 2 * width) {\n const mid = Math.min(lo + width, n)\n const hi = Math.min(lo + 2 * width, n)\n let i = lo\n let j = mid\n // The run of the last output (-1: none yet) and whether it equals the other run's head.\n let prev = -1\n let same = 0\n for (let k = lo; k < hi; k++) {\n let c = 1\n let src: number\n if (i < mid && j < hi) {\n c = cmp(a[j] as number, a[i] as number)\n src = c < 0 ? 1 : 0\n if (++ops === CHUNK) {\n ops = 0\n yield\n }\n } else src = i < mid ? 0 : 1\n const p = src ? j++ : i++\n b[k] = a[p] as number\n eb[k] = prev === src ? (ea[p] as number) : prev < 0 ? 0 : same\n same = src === 0 && c === 0 ? 1 : 0\n prev = src\n }\n }\n const t = a\n a = b\n b = t\n const e = ea\n ea = eb\n eb = e\n }\n return { order: a, eq: ea }\n}\n\n/**\n * What the next {@link collationRanks} of the same column starts from (#95): the values it ranked,\n * their ranks (the `ranks` it returned, shared) and the distinct strings in rank order (one per\n * rank, shared with the data). No string → id map: a row whose string is unchanged at its position\n * (or at a shifted one) keeps its rank, any other string is found by binary search over `reps`.\n * Never mutated (a job builds a new one), so a cancelled job leaves it usable.\n */\nexport interface RankState {\n readonly values: readonly unknown[]\n readonly ranks: ArrayLike<number>\n readonly reps: readonly string[]\n}\n\nexport interface Ranked {\n readonly ranks: Float64Array\n readonly state: RankState\n}\n\n/**\n * Collation ranks of a string column (§6.4, §9.1): per row, the dense rank of its string among\n * the column's distinct strings in `collator` order (strings the collator finds equal share a\n * rank), `NaN` for a missing value. Sorting by these numbers gives exactly the order of\n * `collator.compare`, with integer keys (counting / radix sort) instead of a collator call per\n * comparison. A time-sliced job; `null` when a present value is not a string.\n *\n * Incremental across data versions (#95): a string ranked in `prev` (the state of an earlier array\n * of the same column) keeps that rank as its sort key. It is read from the same row of `prev` when\n * the string is the same there (or at the row offset of the last match, for inserted / removed\n * rows), else found by binary search over the ranked strings; a new string is placed in the gap\n * below the first greater one. Only new strings are sorted (two in the same gap call the\n * collator): a one-row edit costs O(log d) collator calls (and a sort of numbers), not a cold\n * sort. The new state holds only the strings present now.\n */\nexport function* collationRanks(\n values: readonly unknown[],\n collator: Intl.Collator,\n prev: RankState = { values: [], ranks: [], reps: [] },\n): Generator<undefined, Ranked | null, undefined> {\n const n = values.length\n const { values: was, ranks: wasRank, reps } = prev\n const m = reps.length\n /** Per row: its rank in `prev`, `m + id` for the new string `fresh[id]`, NaN when missing. */\n const out = new Float64Array(n)\n /** Ranks of `prev` still present (the rest are dropped from the new state). */\n const used = new Uint8Array(m)\n // New strings only (a cold job: every distinct string), dropped with the job.\n const freshIds = new Map<string, number>()\n const fresh: string[] = []\n /** Per new string: `g - 0.5`, between ranks g-1 and g of `prev`. */\n const gap: number[] = []\n /** Per rank of `prev`: one row holding it, built on the first lookup that finds one. */\n let rowOf: Int32Array | undefined\n /** Offset to `prev`'s row of the last match: rows inserted / removed above shift it. */\n let shift = 0\n let ops = 0\n for (let r = 0; r < n; r++) {\n const v = values[r]\n if (typeof v === 'string') {\n let k: number | undefined\n const q = r + shift\n // Out of range: `undefined`, never a string.\n if (was[q] === v) k = wasRank[q] as number\n else {\n const id = freshIds.get(v)\n if (id !== undefined) k = m + id\n else {\n let lo = 0\n let hi = m\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n const c = collator.compare(v, reps[mid] as string)\n ops++\n if (c === 0) {\n k = mid\n break\n }\n if (c < 0) hi = mid\n else lo = mid + 1\n }\n if (k === undefined) {\n k = m + fresh.length\n freshIds.set(v, fresh.length)\n fresh.push(v)\n gap.push(lo - 0.5)\n } else {\n if (!rowOf) {\n rowOf = new Int32Array(m)\n for (let p = 0; p < was.length; p++) {\n const x = wasRank[p] as number\n if (!Number.isNaN(x)) rowOf[x] = p\n }\n }\n shift = (rowOf[k] as number) - r\n }\n }\n }\n if (k < m) used[k] = 1\n out[r] = k\n } else if (typeRank(v) === RANK.missing) out[r] = Number.NaN\n else return null\n if (++ops >= CHUNK) {\n ops = 0\n yield\n }\n }\n // The same strings as `prev` (a new array of equal content, rows moved): the same ranks.\n if (!fresh.length && !used.includes(0)) return { ranks: out, state: { values, ranks: out, reps } }\n\n const f = fresh.length\n const { order, eq } = yield* sortPositions(\n f,\n // By gap; two new strings in the same gap (cold: all of them) go to the collator.\n (a, b) =>\n (gap[a] as number) - (gap[b] as number) ||\n collator.compare(fresh[a] as string, fresh[b] as string),\n // Comparing numbers is far cheaper: longer native runs, fewer merge passes.\n m ? 8 * RUN : RUN,\n )\n // Merge the kept ranks of `prev` and the new strings (each before the rank above its gap). No\n // collator call: one pass, like the rank lookup below.\n const remap = new Float64Array(m + f)\n const kept: string[] = []\n let rank = -1\n let j = 0\n for (let g = 0; g <= m; g++) {\n while (j < f && (gap[order[j] as number] as number) < g) {\n const id = order[j] as number\n if (!eq[j]) kept[++rank] = fresh[id] as string\n remap[m + id] = rank\n j++\n }\n if (g < m && used[g]) {\n kept[++rank] = reps[g] as string\n remap[g] = rank\n }\n }\n for (let r = 0; r < n; r++) {\n const k = out[r] as number\n if (!Number.isNaN(k)) out[r] = remap[k] as number\n }\n return { ranks: out, state: { values, ranks: out, reps: kept } }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,85 +1,152 @@
|
|
|
1
1
|
// src/features/sorting/ranks.ts
|
|
2
2
|
import { RANK, typeRank } from "./compare.js";
|
|
3
3
|
var CHUNK = 4096;
|
|
4
|
-
var RUN =
|
|
5
|
-
function* sortPositions(n, cmp) {
|
|
4
|
+
var RUN = 1024;
|
|
5
|
+
function* sortPositions(n, cmp, run) {
|
|
6
6
|
let a = new Uint32Array(n);
|
|
7
|
+
let ea = new Uint8Array(n);
|
|
7
8
|
for (let i = 0; i < n; i++) a[i] = i;
|
|
8
|
-
for (let lo = 0; lo < n; lo +=
|
|
9
|
-
|
|
9
|
+
for (let lo = 0; lo < n; lo += run) {
|
|
10
|
+
const hi = Math.min(lo + run, n);
|
|
11
|
+
let zero = false;
|
|
12
|
+
a.subarray(lo, hi).sort((x, y) => {
|
|
13
|
+
const c = cmp(x, y);
|
|
14
|
+
if (c === 0) zero = true;
|
|
15
|
+
return c;
|
|
16
|
+
});
|
|
17
|
+
if (zero)
|
|
18
|
+
for (let k = lo + 1; k < hi; k++) ea[k] = cmp(a[k - 1], a[k]) ? 0 : 1;
|
|
10
19
|
yield;
|
|
11
20
|
}
|
|
12
21
|
let b = new Uint32Array(n);
|
|
22
|
+
let eb = new Uint8Array(n);
|
|
13
23
|
let ops = 0;
|
|
14
|
-
for (let width =
|
|
24
|
+
for (let width = run; width < n; width *= 2) {
|
|
15
25
|
for (let lo = 0; lo < n; lo += 2 * width) {
|
|
16
26
|
const mid = Math.min(lo + width, n);
|
|
17
27
|
const hi = Math.min(lo + 2 * width, n);
|
|
18
28
|
let i = lo;
|
|
19
29
|
let j = mid;
|
|
20
|
-
let
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
j
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
let prev = -1;
|
|
31
|
+
let same = 0;
|
|
32
|
+
for (let k = lo; k < hi; k++) {
|
|
33
|
+
let c = 1;
|
|
34
|
+
let src;
|
|
35
|
+
if (i < mid && j < hi) {
|
|
36
|
+
c = cmp(a[j], a[i]);
|
|
37
|
+
src = c < 0 ? 1 : 0;
|
|
38
|
+
if (++ops === CHUNK) {
|
|
39
|
+
ops = 0;
|
|
40
|
+
yield;
|
|
41
|
+
}
|
|
42
|
+
} else src = i < mid ? 0 : 1;
|
|
43
|
+
const p = src ? j++ : i++;
|
|
44
|
+
b[k] = a[p];
|
|
45
|
+
eb[k] = prev === src ? ea[p] : prev < 0 ? 0 : same;
|
|
46
|
+
same = src === 0 && c === 0 ? 1 : 0;
|
|
47
|
+
prev = src;
|
|
35
48
|
}
|
|
36
|
-
while (i < mid) b[k++] = a[i++];
|
|
37
|
-
while (j < hi) b[k++] = a[j++];
|
|
38
49
|
}
|
|
39
50
|
const t = a;
|
|
40
51
|
a = b;
|
|
41
52
|
b = t;
|
|
53
|
+
const e = ea;
|
|
54
|
+
ea = eb;
|
|
55
|
+
eb = e;
|
|
42
56
|
}
|
|
43
|
-
return a;
|
|
57
|
+
return { order: a, eq: ea };
|
|
44
58
|
}
|
|
45
|
-
function* collationRanks(values, collator) {
|
|
59
|
+
function* collationRanks(values, collator, prev = { values: [], ranks: [], reps: [] }) {
|
|
46
60
|
const n = values.length;
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
61
|
+
const { values: was, ranks: wasRank, reps } = prev;
|
|
62
|
+
const m = reps.length;
|
|
63
|
+
const out = new Float64Array(n);
|
|
64
|
+
const used = new Uint8Array(m);
|
|
65
|
+
const freshIds = /* @__PURE__ */ new Map();
|
|
66
|
+
const fresh = [];
|
|
67
|
+
const gap = [];
|
|
68
|
+
let rowOf;
|
|
69
|
+
let shift = 0;
|
|
70
|
+
let ops = 0;
|
|
50
71
|
for (let r = 0; r < n; r++) {
|
|
51
72
|
const v = values[r];
|
|
52
73
|
if (typeof v === "string") {
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
let k;
|
|
75
|
+
const q = r + shift;
|
|
76
|
+
if (was[q] === v) k = wasRank[q];
|
|
77
|
+
else {
|
|
78
|
+
const id = freshIds.get(v);
|
|
79
|
+
if (id !== void 0) k = m + id;
|
|
80
|
+
else {
|
|
81
|
+
let lo = 0;
|
|
82
|
+
let hi = m;
|
|
83
|
+
while (lo < hi) {
|
|
84
|
+
const mid = lo + hi >>> 1;
|
|
85
|
+
const c = collator.compare(v, reps[mid]);
|
|
86
|
+
ops++;
|
|
87
|
+
if (c === 0) {
|
|
88
|
+
k = mid;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
if (c < 0) hi = mid;
|
|
92
|
+
else lo = mid + 1;
|
|
93
|
+
}
|
|
94
|
+
if (k === void 0) {
|
|
95
|
+
k = m + fresh.length;
|
|
96
|
+
freshIds.set(v, fresh.length);
|
|
97
|
+
fresh.push(v);
|
|
98
|
+
gap.push(lo - 0.5);
|
|
99
|
+
} else {
|
|
100
|
+
if (!rowOf) {
|
|
101
|
+
rowOf = new Int32Array(m);
|
|
102
|
+
for (let p = 0; p < was.length; p++) {
|
|
103
|
+
const x = wasRank[p];
|
|
104
|
+
if (!Number.isNaN(x)) rowOf[x] = p;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
shift = rowOf[k] - r;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
58
110
|
}
|
|
59
|
-
|
|
60
|
-
|
|
111
|
+
if (k < m) used[k] = 1;
|
|
112
|
+
out[r] = k;
|
|
113
|
+
} else if (typeRank(v) === RANK.missing) out[r] = Number.NaN;
|
|
61
114
|
else return null;
|
|
62
|
-
if (
|
|
115
|
+
if (++ops >= CHUNK) {
|
|
116
|
+
ops = 0;
|
|
117
|
+
yield;
|
|
118
|
+
}
|
|
63
119
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
120
|
+
if (!fresh.length && !used.includes(0)) return { ranks: out, state: { values, ranks: out, reps } };
|
|
121
|
+
const f = fresh.length;
|
|
122
|
+
const { order, eq } = yield* sortPositions(
|
|
123
|
+
f,
|
|
124
|
+
// By gap; two new strings in the same gap (cold: all of them) go to the collator.
|
|
125
|
+
(a, b) => gap[a] - gap[b] || collator.compare(fresh[a], fresh[b]),
|
|
126
|
+
// Comparing numbers is far cheaper: longer native runs, fewer merge passes.
|
|
127
|
+
m ? 8 * RUN : RUN
|
|
67
128
|
);
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
129
|
+
const remap = new Float64Array(m + f);
|
|
130
|
+
const kept = [];
|
|
131
|
+
let rank = -1;
|
|
132
|
+
let j = 0;
|
|
133
|
+
for (let g = 0; g <= m; g++) {
|
|
134
|
+
while (j < f && gap[order[j]] < g) {
|
|
135
|
+
const id = order[j];
|
|
136
|
+
if (!eq[j]) kept[++rank] = fresh[id];
|
|
137
|
+
remap[m + id] = rank;
|
|
138
|
+
j++;
|
|
139
|
+
}
|
|
140
|
+
if (g < m && used[g]) {
|
|
141
|
+
kept[++rank] = reps[g];
|
|
142
|
+
remap[g] = rank;
|
|
143
|
+
}
|
|
76
144
|
}
|
|
77
|
-
const out = new Float64Array(n);
|
|
78
145
|
for (let r = 0; r < n; r++) {
|
|
79
|
-
const
|
|
80
|
-
out[r] =
|
|
146
|
+
const k = out[r];
|
|
147
|
+
if (!Number.isNaN(k)) out[r] = remap[k];
|
|
81
148
|
}
|
|
82
|
-
return out;
|
|
149
|
+
return { ranks: out, state: { values, ranks: out, reps: kept } };
|
|
83
150
|
}
|
|
84
151
|
export {
|
|
85
152
|
collationRanks
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/features/sorting/ranks.ts"],"sourcesContent":["import { RANK, typeRank } from './compare'\n\n/** Comparisons / rows between two `yield`s of the jobs below (§9.1). */\nconst CHUNK = 4096\n/** Run length sorted natively before the merge passes. */\nconst RUN = 512\n\n/**\n * Sorts `0..n-1` by `cmp` as a time-sliced job (§9.1): native sorts of short runs, then bottom-up\n * merge passes that `yield` every {@link CHUNK} comparisons. Stable.\n */\nfunction* sortPositions(\n n: number,\n cmp: (a: number, b: number) => number,\n): Generator<undefined, Uint32Array, undefined> {\n let a = new Uint32Array(n)\n for (let i = 0; i < n; i++) a[i] = i\n for (let lo = 0; lo < n; lo += RUN) {\n a.subarray(lo, Math.min(lo + RUN, n)).sort(cmp)\n yield\n }\n let b = new Uint32Array(n)\n let ops = 0\n for (let width = RUN; width < n; width *= 2) {\n for (let lo = 0; lo < n; lo += 2 * width) {\n const mid = Math.min(lo + width, n)\n const hi = Math.min(lo + 2 * width, n)\n let i = lo\n let j = mid\n let k = lo\n while (i < mid && j < hi) {\n const x = a[i] as number\n const y = a[j] as number\n if (cmp(y, x) < 0) {\n b[k++] = y\n j++\n } else {\n b[k++] = x\n i++\n }\n if (++ops === CHUNK) {\n ops = 0\n yield\n }\n }\n while (i < mid) b[k++] = a[i++] as number\n while (j < hi) b[k++] = a[j++] as number\n }\n const t = a\n a = b\n b = t\n }\n return a\n}\n\n/**\n * Collation ranks of a string column (§6.4, §9.1): per row, the dense rank of its string among\n * the column's distinct strings in `collator` order (strings the collator finds equal share a\n * rank), `NaN` for a missing value. Sorting by these numbers gives exactly the order of\n * `collator.compare`, with integer keys (counting / radix sort) instead of a collator call per\n * comparison. A time-sliced job; `null` when a present value is not a string.\n */\nexport function* collationRanks(\n values: readonly unknown[],\n collator: Intl.Collator,\n): Generator<undefined, Float64Array | null, undefined> {\n const n = values.length\n const ids = new Map<string, number>()\n const distinct: string[] = []\n /** Per row: its string's position in `distinct`, -1 when missing. */\n const slot = new Int32Array(n)\n for (let r = 0; r < n; r++) {\n const v = values[r]\n if (typeof v === 'string') {\n let id = ids.get(v)\n if (id === undefined) {\n id = distinct.length\n ids.set(v, id)\n distinct.push(v)\n }\n slot[r] = id\n } else if (typeRank(v) === RANK.missing) slot[r] = -1\n else return null\n if (r % CHUNK === CHUNK - 1) yield\n }\n const order = yield* sortPositions(distinct.length, (a, b) =>\n collator.compare(distinct[a] as string, distinct[b] as string),\n )\n const rankOf = new Float64Array(distinct.length)\n let rank = 0\n for (let k = 0; k < order.length; k++) {\n const id = order[k] as number\n const s = distinct[id] as string\n if (k > 0 && collator.compare(distinct[order[k - 1] as number] as string, s) !== 0) rank++\n rankOf[id] = rank\n if (k % CHUNK === CHUNK - 1) yield\n }\n const out = new Float64Array(n)\n for (let r = 0; r < n; r++) {\n const id = slot[r] as number\n out[r] = id < 0 ? Number.NaN : (rankOf[id] as number)\n }\n return out\n}\n"],"mappings":";AAAA,SAAS,MAAM,gBAAgB;AAG/B,IAAM,QAAQ;AAEd,IAAM,MAAM;AAMZ,UAAU,cACR,GACA,KAC8C;AAC9C,MAAI,IAAI,IAAI,YAAY,CAAC;AACzB,WAAS,IAAI,GAAG,IAAI,GAAG,IAAK,GAAE,CAAC,IAAI;AACnC,WAAS,KAAK,GAAG,KAAK,GAAG,MAAM,KAAK;AAClC,MAAE,SAAS,IAAI,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG;AAC9C;AAAA,EACF;AACA,MAAI,IAAI,IAAI,YAAY,CAAC;AACzB,MAAI,MAAM;AACV,WAAS,QAAQ,KAAK,QAAQ,GAAG,SAAS,GAAG;AAC3C,aAAS,KAAK,GAAG,KAAK,GAAG,MAAM,IAAI,OAAO;AACxC,YAAM,MAAM,KAAK,IAAI,KAAK,OAAO,CAAC;AAClC,YAAM,KAAK,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC;AACrC,UAAI,IAAI;AACR,UAAI,IAAI;AACR,UAAI,IAAI;AACR,aAAO,IAAI,OAAO,IAAI,IAAI;AACxB,cAAM,IAAI,EAAE,CAAC;AACb,cAAM,IAAI,EAAE,CAAC;AACb,YAAI,IAAI,GAAG,CAAC,IAAI,GAAG;AACjB,YAAE,GAAG,IAAI;AACT;AAAA,QACF,OAAO;AACL,YAAE,GAAG,IAAI;AACT;AAAA,QACF;AACA,YAAI,EAAE,QAAQ,OAAO;AACnB,gBAAM;AACN;AAAA,QACF;AAAA,MACF;AACA,aAAO,IAAI,IAAK,GAAE,GAAG,IAAI,EAAE,GAAG;AAC9B,aAAO,IAAI,GAAI,GAAE,GAAG,IAAI,EAAE,GAAG;AAAA,IAC/B;AACA,UAAM,IAAI;AACV,QAAI;AACJ,QAAI;AAAA,EACN;AACA,SAAO;AACT;AASO,UAAU,eACf,QACA,UACsD;AACtD,QAAM,IAAI,OAAO;AACjB,QAAM,MAAM,oBAAI,IAAoB;AACpC,QAAM,WAAqB,CAAC;AAE5B,QAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,OAAO,MAAM,UAAU;AACzB,UAAI,KAAK,IAAI,IAAI,CAAC;AAClB,UAAI,OAAO,QAAW;AACpB,aAAK,SAAS;AACd,YAAI,IAAI,GAAG,EAAE;AACb,iBAAS,KAAK,CAAC;AAAA,MACjB;AACA,WAAK,CAAC,IAAI;AAAA,IACZ,WAAW,SAAS,CAAC,MAAM,KAAK,QAAS,MAAK,CAAC,IAAI;AAAA,QAC9C,QAAO;AACZ,QAAI,IAAI,UAAU,QAAQ,EAAG;AAAA,EAC/B;AACA,QAAM,QAAQ,OAAO;AAAA,IAAc,SAAS;AAAA,IAAQ,CAAC,GAAG,MACtD,SAAS,QAAQ,SAAS,CAAC,GAAa,SAAS,CAAC,CAAW;AAAA,EAC/D;AACA,QAAM,SAAS,IAAI,aAAa,SAAS,MAAM;AAC/C,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,KAAK,MAAM,CAAC;AAClB,UAAM,IAAI,SAAS,EAAE;AACrB,QAAI,IAAI,KAAK,SAAS,QAAQ,SAAS,MAAM,IAAI,CAAC,CAAW,GAAa,CAAC,MAAM,EAAG;AACpF,WAAO,EAAE,IAAI;AACb,QAAI,IAAI,UAAU,QAAQ,EAAG;AAAA,EAC/B;AACA,QAAM,MAAM,IAAI,aAAa,CAAC;AAC9B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,KAAK,KAAK,CAAC;AACjB,QAAI,CAAC,IAAI,KAAK,IAAI,OAAO,MAAO,OAAO,EAAE;AAAA,EAC3C;AACA,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/features/sorting/ranks.ts"],"sourcesContent":["import { RANK, typeRank } from './compare'\n\n/** Comparisons / rows between two `yield`s of the jobs below (§9.1). */\nconst CHUNK = 4096\n/**\n * Run length sorted natively before the merge passes (#97, was 512): each doubling saves a merge\n * pass, and one native run of collator calls stays within a slice even under a 4x CPU throttle.\n */\nconst RUN = 1024\n\n/**\n * Sorts `0..n-1` by `cmp` as a time-sliced job (§9.1): native sorts of `run`s, then bottom-up\n * merge passes that `yield` every {@link CHUNK} comparisons. Stable. Also returns `eq`:\n * `eq[k] = 1` when `order[k]` compares equal to `order[k - 1]`, from the comparisons the merges\n * make anyway (#97). Inside a native run it costs a second pass only when that sort saw a 0.\n */\nfunction* sortPositions(\n n: number,\n cmp: (a: number, b: number) => number,\n run: number,\n): Generator<undefined, { order: Uint32Array; eq: Uint8Array }, undefined> {\n let a = new Uint32Array(n)\n let ea = new Uint8Array(n)\n for (let i = 0; i < n; i++) a[i] = i\n for (let lo = 0; lo < n; lo += run) {\n const hi = Math.min(lo + run, n)\n let zero = false\n a.subarray(lo, hi).sort((x, y) => {\n const c = cmp(x, y)\n if (c === 0) zero = true\n return c\n })\n // Neighbours can only be equal if the sort saw a 0 (it must, to order them).\n if (zero)\n for (let k = lo + 1; k < hi; k++) ea[k] = cmp(a[k - 1] as number, a[k] as number) ? 0 : 1\n yield\n }\n let b = new Uint32Array(n)\n let eb = new Uint8Array(n)\n let ops = 0\n for (let width = run; width < n; width *= 2) {\n for (let lo = 0; lo < n; lo += 2 * width) {\n const mid = Math.min(lo + width, n)\n const hi = Math.min(lo + 2 * width, n)\n let i = lo\n let j = mid\n // The run of the last output (-1: none yet) and whether it equals the other run's head.\n let prev = -1\n let same = 0\n for (let k = lo; k < hi; k++) {\n let c = 1\n let src: number\n if (i < mid && j < hi) {\n c = cmp(a[j] as number, a[i] as number)\n src = c < 0 ? 1 : 0\n if (++ops === CHUNK) {\n ops = 0\n yield\n }\n } else src = i < mid ? 0 : 1\n const p = src ? j++ : i++\n b[k] = a[p] as number\n eb[k] = prev === src ? (ea[p] as number) : prev < 0 ? 0 : same\n same = src === 0 && c === 0 ? 1 : 0\n prev = src\n }\n }\n const t = a\n a = b\n b = t\n const e = ea\n ea = eb\n eb = e\n }\n return { order: a, eq: ea }\n}\n\n/**\n * What the next {@link collationRanks} of the same column starts from (#95): the values it ranked,\n * their ranks (the `ranks` it returned, shared) and the distinct strings in rank order (one per\n * rank, shared with the data). No string → id map: a row whose string is unchanged at its position\n * (or at a shifted one) keeps its rank, any other string is found by binary search over `reps`.\n * Never mutated (a job builds a new one), so a cancelled job leaves it usable.\n */\nexport interface RankState {\n readonly values: readonly unknown[]\n readonly ranks: ArrayLike<number>\n readonly reps: readonly string[]\n}\n\nexport interface Ranked {\n readonly ranks: Float64Array\n readonly state: RankState\n}\n\n/**\n * Collation ranks of a string column (§6.4, §9.1): per row, the dense rank of its string among\n * the column's distinct strings in `collator` order (strings the collator finds equal share a\n * rank), `NaN` for a missing value. Sorting by these numbers gives exactly the order of\n * `collator.compare`, with integer keys (counting / radix sort) instead of a collator call per\n * comparison. A time-sliced job; `null` when a present value is not a string.\n *\n * Incremental across data versions (#95): a string ranked in `prev` (the state of an earlier array\n * of the same column) keeps that rank as its sort key. It is read from the same row of `prev` when\n * the string is the same there (or at the row offset of the last match, for inserted / removed\n * rows), else found by binary search over the ranked strings; a new string is placed in the gap\n * below the first greater one. Only new strings are sorted (two in the same gap call the\n * collator): a one-row edit costs O(log d) collator calls (and a sort of numbers), not a cold\n * sort. The new state holds only the strings present now.\n */\nexport function* collationRanks(\n values: readonly unknown[],\n collator: Intl.Collator,\n prev: RankState = { values: [], ranks: [], reps: [] },\n): Generator<undefined, Ranked | null, undefined> {\n const n = values.length\n const { values: was, ranks: wasRank, reps } = prev\n const m = reps.length\n /** Per row: its rank in `prev`, `m + id` for the new string `fresh[id]`, NaN when missing. */\n const out = new Float64Array(n)\n /** Ranks of `prev` still present (the rest are dropped from the new state). */\n const used = new Uint8Array(m)\n // New strings only (a cold job: every distinct string), dropped with the job.\n const freshIds = new Map<string, number>()\n const fresh: string[] = []\n /** Per new string: `g - 0.5`, between ranks g-1 and g of `prev`. */\n const gap: number[] = []\n /** Per rank of `prev`: one row holding it, built on the first lookup that finds one. */\n let rowOf: Int32Array | undefined\n /** Offset to `prev`'s row of the last match: rows inserted / removed above shift it. */\n let shift = 0\n let ops = 0\n for (let r = 0; r < n; r++) {\n const v = values[r]\n if (typeof v === 'string') {\n let k: number | undefined\n const q = r + shift\n // Out of range: `undefined`, never a string.\n if (was[q] === v) k = wasRank[q] as number\n else {\n const id = freshIds.get(v)\n if (id !== undefined) k = m + id\n else {\n let lo = 0\n let hi = m\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n const c = collator.compare(v, reps[mid] as string)\n ops++\n if (c === 0) {\n k = mid\n break\n }\n if (c < 0) hi = mid\n else lo = mid + 1\n }\n if (k === undefined) {\n k = m + fresh.length\n freshIds.set(v, fresh.length)\n fresh.push(v)\n gap.push(lo - 0.5)\n } else {\n if (!rowOf) {\n rowOf = new Int32Array(m)\n for (let p = 0; p < was.length; p++) {\n const x = wasRank[p] as number\n if (!Number.isNaN(x)) rowOf[x] = p\n }\n }\n shift = (rowOf[k] as number) - r\n }\n }\n }\n if (k < m) used[k] = 1\n out[r] = k\n } else if (typeRank(v) === RANK.missing) out[r] = Number.NaN\n else return null\n if (++ops >= CHUNK) {\n ops = 0\n yield\n }\n }\n // The same strings as `prev` (a new array of equal content, rows moved): the same ranks.\n if (!fresh.length && !used.includes(0)) return { ranks: out, state: { values, ranks: out, reps } }\n\n const f = fresh.length\n const { order, eq } = yield* sortPositions(\n f,\n // By gap; two new strings in the same gap (cold: all of them) go to the collator.\n (a, b) =>\n (gap[a] as number) - (gap[b] as number) ||\n collator.compare(fresh[a] as string, fresh[b] as string),\n // Comparing numbers is far cheaper: longer native runs, fewer merge passes.\n m ? 8 * RUN : RUN,\n )\n // Merge the kept ranks of `prev` and the new strings (each before the rank above its gap). No\n // collator call: one pass, like the rank lookup below.\n const remap = new Float64Array(m + f)\n const kept: string[] = []\n let rank = -1\n let j = 0\n for (let g = 0; g <= m; g++) {\n while (j < f && (gap[order[j] as number] as number) < g) {\n const id = order[j] as number\n if (!eq[j]) kept[++rank] = fresh[id] as string\n remap[m + id] = rank\n j++\n }\n if (g < m && used[g]) {\n kept[++rank] = reps[g] as string\n remap[g] = rank\n }\n }\n for (let r = 0; r < n; r++) {\n const k = out[r] as number\n if (!Number.isNaN(k)) out[r] = remap[k] as number\n }\n return { ranks: out, state: { values, ranks: out, reps: kept } }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -29,13 +29,17 @@ var import_slots = require("../../catalog/slots.cjs");
|
|
|
29
29
|
var import_get_value = require("../../column/get-value.cjs");
|
|
30
30
|
var import_catalog = require("../../diagnostics/catalog.cjs");
|
|
31
31
|
var import_process_guard = require("../../diagnostics/process-guard.cjs");
|
|
32
|
+
var import_prose = require("../../diagnostics/prose.cjs");
|
|
33
|
+
var import_redact = require("../../diagnostics/redact.cjs");
|
|
32
34
|
var import_define = require("../../feature/define.cjs");
|
|
35
|
+
var import_slice_guard = require("../../feature/slice-guard.cjs");
|
|
33
36
|
var import_cell_batch = require("../../intercept/cell-batch.cjs");
|
|
34
37
|
var import_classify = require("../../intercept/classify.cjs");
|
|
35
38
|
var import_codes2 = require("../../intercept/codes.cjs");
|
|
36
39
|
var import_columns = require("../../pipeline/columns.cjs");
|
|
37
40
|
var import_env_codes = require("../../pipeline/env-codes.cjs");
|
|
38
41
|
var import_indices = require("../../pipeline/indices.cjs");
|
|
42
|
+
var import_release = require("../../pipeline/release.cjs");
|
|
39
43
|
var import_slice = require("../../pipeline/slice.cjs");
|
|
40
44
|
var import_mode = require("../../source/mode.cjs");
|
|
41
45
|
var import_capability = require("../../versioning/capability.cjs");
|
|
@@ -50,7 +54,30 @@ var import_strategy = require("./strategy.cjs");
|
|
|
50
54
|
import_codes.optionDiagnostics,
|
|
51
55
|
import_env_codes.envDiagnostics
|
|
52
56
|
);
|
|
53
|
-
var
|
|
57
|
+
var isEntry = (e) => e?.id != null;
|
|
58
|
+
var byOf = (s) => s?.by;
|
|
59
|
+
var entriesOf = (s) => {
|
|
60
|
+
const by = byOf(s);
|
|
61
|
+
return Array.isArray(by) ? by.filter(isEntry) : [];
|
|
62
|
+
};
|
|
63
|
+
function fixSlice(s) {
|
|
64
|
+
const raw = byOf(s);
|
|
65
|
+
const by = entriesOf(s);
|
|
66
|
+
if (Array.isArray(raw) && raw.length === by.length) return void 0;
|
|
67
|
+
const bad = Array.isArray(raw) ? raw.findIndex((e) => !isEntry(e)) : -1;
|
|
68
|
+
return [
|
|
69
|
+
{ by },
|
|
70
|
+
bad < 0 ? (0, import_redact.describeValue)(raw ?? s) : `by[${bad}]: ${(0, import_redact.describeValue)(raw[bad])}`,
|
|
71
|
+
`{ by: [${by.length} valid] }`
|
|
72
|
+
];
|
|
73
|
+
}
|
|
74
|
+
var setSort = (ctx, by) => {
|
|
75
|
+
try {
|
|
76
|
+
if (JSON.stringify(byOf(ctx.getState())) === JSON.stringify(by)) return;
|
|
77
|
+
} catch {
|
|
78
|
+
}
|
|
79
|
+
ctx.setState({ by: Array.isArray(by) ? by.slice() : by });
|
|
80
|
+
};
|
|
54
81
|
var validLocale = (v) => {
|
|
55
82
|
try {
|
|
56
83
|
Intl.getCanonicalLocales(v);
|
|
@@ -113,6 +140,7 @@ var SortFnFailed = class {
|
|
|
113
140
|
}
|
|
114
141
|
};
|
|
115
142
|
var sorting = (opts = {}) => {
|
|
143
|
+
const guard = process.env.NODE_ENV !== "production" ? (0, import_slice_guard.sliceGuard)("sorting", fixSlice) : void 0;
|
|
116
144
|
let collator;
|
|
117
145
|
const getCollator = (emit) => {
|
|
118
146
|
if (collator) return collator;
|
|
@@ -135,19 +163,31 @@ var sorting = (opts = {}) => {
|
|
|
135
163
|
}
|
|
136
164
|
return collator;
|
|
137
165
|
};
|
|
138
|
-
|
|
139
|
-
|
|
166
|
+
let rankKeys = /* @__PURE__ */ new WeakMap();
|
|
167
|
+
let history = /* @__PURE__ */ new Map();
|
|
168
|
+
function keepHistory(by) {
|
|
169
|
+
for (const id of history.keys()) {
|
|
170
|
+
if (!by.some((e) => String(e.id) === id)) history.delete(id);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function ranksFor(ctx, id, values) {
|
|
140
174
|
let key = rankKeys.get(values);
|
|
141
175
|
if (!key) {
|
|
142
176
|
key = {};
|
|
143
177
|
rankKeys.set(values, key);
|
|
144
178
|
}
|
|
145
179
|
const c = getCollator(ctx.emit);
|
|
146
|
-
|
|
180
|
+
const into = history;
|
|
181
|
+
return (0, import_slice.sliced)(ctx, key, function* () {
|
|
182
|
+
const r = yield* (0, import_ranks.collationRanks)(values, c, into.get(id));
|
|
183
|
+
if (!r) return null;
|
|
184
|
+
into.set(id, r.state);
|
|
185
|
+
return r.ranks;
|
|
186
|
+
});
|
|
147
187
|
}
|
|
148
188
|
let shown;
|
|
149
|
-
|
|
150
|
-
|
|
189
|
+
let sortByCache = /* @__PURE__ */ new WeakMap();
|
|
190
|
+
let pathCache = /* @__PURE__ */ new WeakMap();
|
|
151
191
|
let exsorted;
|
|
152
192
|
const sortByFailures = new import_cell_batch.CellFailures();
|
|
153
193
|
function sortByValues(ctx, col, sortBy) {
|
|
@@ -193,7 +233,7 @@ var sorting = (opts = {}) => {
|
|
|
193
233
|
byId.set(id, out);
|
|
194
234
|
return out;
|
|
195
235
|
}
|
|
196
|
-
|
|
236
|
+
const feature = (0, import_define.defineFeature)({
|
|
197
237
|
name: "sorting",
|
|
198
238
|
stage: "sort",
|
|
199
239
|
mode: opts.mode ?? "client",
|
|
@@ -202,32 +242,37 @@ var sorting = (opts = {}) => {
|
|
|
202
242
|
process.env.NODE_ENV !== "production" ? sortingOptions : {},
|
|
203
243
|
opts
|
|
204
244
|
),
|
|
245
|
+
...guard ? { interceptors: [guard.interceptor] } : void 0,
|
|
205
246
|
initialState: () => ({ by: [] }),
|
|
206
247
|
// After destroy(): still a declared value (`aria-sort` reads it during teardown renders).
|
|
207
248
|
destroyedResult: { getSortDirection: () => false },
|
|
208
|
-
createApi: (ctx) =>
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
249
|
+
createApi: (ctx) => {
|
|
250
|
+
guard?.install(ctx);
|
|
251
|
+
return {
|
|
252
|
+
toggleSort: (id, options) => {
|
|
253
|
+
const by = entriesOf(ctx.getState());
|
|
254
|
+
const i = by.findIndex((e) => e.id === id);
|
|
255
|
+
const cur = by[i];
|
|
256
|
+
const next = !cur ? { id, desc: false } : cur.desc ? void 0 : { id, desc: true };
|
|
257
|
+
if (!options?.multi) return ctx.setState({ by: next ? [next] : [] });
|
|
258
|
+
if (!cur) return ctx.setState({ by: [...by, next] });
|
|
259
|
+
const out = by.slice();
|
|
260
|
+
if (next) out[i] = next;
|
|
261
|
+
else out.splice(i, 1);
|
|
262
|
+
ctx.setState({ by: out });
|
|
263
|
+
},
|
|
264
|
+
setSorting: (by) => setSort(ctx, by),
|
|
265
|
+
clearSorting: () => setSort(ctx, []),
|
|
266
|
+
getSortDirection: (id) => {
|
|
267
|
+
const e = entriesOf(ctx.getState()).find((x) => x.id === id);
|
|
268
|
+
return e ? e.desc ? "desc" : "asc" : false;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
},
|
|
228
272
|
rowModel: (indices, state, ctx) => {
|
|
229
|
-
const by = state
|
|
230
|
-
|
|
273
|
+
const by = entriesOf(state);
|
|
274
|
+
keepHistory(by);
|
|
275
|
+
if (by.length === 0 || indices.length < 2) {
|
|
231
276
|
shown = void 0;
|
|
232
277
|
return indices;
|
|
233
278
|
}
|
|
@@ -239,7 +284,7 @@ var sorting = (opts = {}) => {
|
|
|
239
284
|
const sortBy = col && fnField(col.def, "sortBy");
|
|
240
285
|
const values = sortBy ? sortByValues(ctx, col, sortBy) : ctx.getColumnValues(id) ?? pathValues(ctx, id);
|
|
241
286
|
const sortFn = col && !sortBy ? fnField(col.def, "sortFn") : void 0;
|
|
242
|
-
return { col, desc: e.desc === true, values, sortFn, ranked: false };
|
|
287
|
+
return { id, col, desc: e.desc === true, values, sortFn, ranked: false };
|
|
243
288
|
});
|
|
244
289
|
if (process.env.NODE_ENV !== "production") {
|
|
245
290
|
for (const e of entries) {
|
|
@@ -260,7 +305,7 @@ var sorting = (opts = {}) => {
|
|
|
260
305
|
fromColumn ? { path: `columns[${primary.col?.index}].sortAlgorithm`, reason: reason2, once: false } : { path: "algorithm", feature: "sorting", reason: reason2, once: false }
|
|
261
306
|
);
|
|
262
307
|
if (typeof requested !== "function" && !ALGORITHMS.includes(requested)) {
|
|
263
|
-
noEffect(`not-algorithm|${JSON.stringify(requested)}`);
|
|
308
|
+
noEffect(`not-algorithm|${(0, import_prose.proseArg)(JSON.stringify(requested))}`);
|
|
264
309
|
requested = "auto";
|
|
265
310
|
}
|
|
266
311
|
if (requested !== "native" && exsorted === void 0) {
|
|
@@ -280,7 +325,7 @@ var sorting = (opts = {}) => {
|
|
|
280
325
|
let computing = false;
|
|
281
326
|
for (const e of entries) {
|
|
282
327
|
if (e.sortFn || e.values instanceof Float64Array) continue;
|
|
283
|
-
const ranks = ranksFor(ctx, e.values);
|
|
328
|
+
const ranks = ranksFor(ctx, e.id, e.values);
|
|
284
329
|
if (ranks === void 0) computing = true;
|
|
285
330
|
else if (ranks) {
|
|
286
331
|
e.values = ranks;
|
|
@@ -434,6 +479,16 @@ var sorting = (opts = {}) => {
|
|
|
434
479
|
}
|
|
435
480
|
}
|
|
436
481
|
});
|
|
482
|
+
const internal = feature;
|
|
483
|
+
internal[import_release.RELEASE] = () => {
|
|
484
|
+
rankKeys = /* @__PURE__ */ new WeakMap();
|
|
485
|
+
history = /* @__PURE__ */ new Map();
|
|
486
|
+
shown = void 0;
|
|
487
|
+
sortByCache = /* @__PURE__ */ new WeakMap();
|
|
488
|
+
pathCache = /* @__PURE__ */ new WeakMap();
|
|
489
|
+
};
|
|
490
|
+
if (process.env.NODE_ENV !== "production") internal[import_release.PROBE] = () => ({ rankKeys, history, shown, sortByCache, pathCache });
|
|
491
|
+
return feature;
|
|
437
492
|
};
|
|
438
493
|
// Annotate the CommonJS export names for ESM import in node:
|
|
439
494
|
0 && (module.exports = {
|