diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c456acb9e..b67ab6a882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,13 @@ history. ## Unreleased +- **BREAKING CHANGES:** `fjs/types/btree/find` migrates from authored + TypeScript (`.f.ts`) to JSDoc-typed JavaScript (`.f.mjs`) under the + stage-1 TypeScript-to-mjs migration — importers must use the `.f.mjs` + specifier; implementation-only typedefs (`FirstLeaf1`, `FirstBranch3`, + `FirstLeaf2`, `FirstBranch5`, `PathItem3`, `PathItem5`) are renamed to + their private `_`-prefixed forms + [#1470](https://github.com/functionalscript/functionalscript/pull/1470) - **BREAKING CHANGES:** `fjs/types/btree/types` migrates from authored TypeScript (`.f.ts`) to JSDoc-typed JavaScript (`.f.mjs`) under the stage-1 TypeScript-to-mjs migration — importers must use the `.f.mjs` diff --git a/fjs/types/btree/find/module.f.mjs b/fjs/types/btree/find/module.f.mjs new file mode 100644 index 0000000000..a9c61f5c29 --- /dev/null +++ b/fjs/types/btree/find/module.f.mjs @@ -0,0 +1,133 @@ +/** + * Lookup operations for persistent B-tree structures. + * + * @module + */ +/** @import { Leaf1, Leaf2, Branch3, Branch5, TNode } from '../types/module.f.mjs' */ +/** @import { List } from '../../list/module.f.mjs' */ + +import { index3, index5 } from '../../function/compare/module.f.mjs' +/** @import { Compare } from '../../function/compare/module.f.mjs' */ + +/** @import { KeyOf, Index } from '../../array/module.f.mjs' */ + +/** + * @template T + * @typedef {readonly[Index<3>, Leaf1]} _FirstLeaf1 + */ + +/** + * @template T + * @typedef {readonly[1, Branch3]} _FirstBranch3 + */ + +/** + * @template T + * @typedef {readonly[Index<5>, Leaf2]} _FirstLeaf2 + */ + +/** + * @template T + * @typedef {readonly[1|3, Branch5]} _FirstBranch5 + */ + +/** + * @template T + * @typedef {_FirstLeaf1 | _FirstBranch3 | _FirstLeaf2 | _FirstBranch5} First + */ + +/** + * @template T + * @typedef {readonly[0|2, Branch3]} _PathItem3 + */ + +/** + * @template T + * @typedef {readonly[0|2|4, Branch5]} _PathItem5 + */ + +/** + * @template T + * @typedef {_PathItem3 | _PathItem5} PathItem + */ + +/** @type {(item: PathItem) => TNode} */ +const child = item => { + /** @typedef {typeof item extends PathItem ? T : never} T */ + return /** @type {TNode} */ (item[1][item[0]]) +} + +/** + * @template T + * @typedef {List>} Path + */ + +/** + * @template T + * @typedef {{ + * readonly first: First, + * readonly tail: Path + * }} Result + */ + +/** @type {(c: Compare) => (node: TNode) => Result} */ +export const find = c => { + /** @typedef {typeof c extends Compare ? T : never} T */ + const i3 = index3(c) + const i5 = index5(c) + /** @type {(tail: Path) => (node: TNode) => Result} */ + const f = tail => node => { + /** @type {(index: KeyOf) => Result} */ + const append = index => { + const first = /** @type {PathItem} */ ([index, node]) + return f({ first, tail })(child(first)) + } + /** @type {(index: KeyOf) => Result} */ + const done = index => ({ first: /** @type {First} */ ([index, node]), tail }) + switch (node.length) { + case 1: { return done(i3(node[0])) } + case 2: { return done(i5(node)) } + case 3: { + const i = i3(node[1]) + switch (i) { + case 0: case 2: { return append(i) } + case 1: { return done(i) } + } + } + case 5: { + const i = i5([node[1], node[3]]) + switch (i) { + case 0: case 2: case 4: { return append(i) } + case 1: case 3: { return done(i) } + } + } + } + } + return f(null) +} + +/** @type {(first: First) => boolean} */ +export const isFound = ([i]) => { + switch (i) { + case 1: case 3: { return true } + default: { return false } + } +} + +/** @type {(first: First) => T | null} */ +export const value = ([i, r]) => { + switch (i) { + case 1: { + switch (r.length) { + case 1: case 2: { return r[0] } + default: { return r[1] } + } + } + case 3: { + return r.length === 2 ? r[1] : r[3] + } + default: { + return null + } + } +} diff --git a/fjs/types/btree/find/module.f.ts b/fjs/types/btree/find/module.f.ts deleted file mode 100644 index e806546ba6..0000000000 --- a/fjs/types/btree/find/module.f.ts +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Lookup operations for persistent B-tree structures. - * - * @module - */ -import type { Leaf1, Leaf2, Branch3, Branch5, TNode } from '../types/module.f.mjs' -import type { List } from '../../list/module.f.mjs' -import { index3, index5, type Compare } from '../../function/compare/module.f.mjs' -import type { KeyOf, Index } from "../../array/module.f.mjs" - -export type FirstLeaf1 = readonly[Index<3>, Leaf1] - -export type FirstBranch3 = readonly[1, Branch3] - -export type FirstLeaf2 = readonly[Index<5>, Leaf2] - -export type FirstBranch5 = readonly[1|3, Branch5] - -export type First = FirstLeaf1 | FirstBranch3 | FirstLeaf2 | FirstBranch5 - -export type PathItem3 = readonly[0|2, Branch3] - -export type PathItem5 = readonly[0|2|4, Branch5] - -export type PathItem = PathItem3 | PathItem5 - -const child -= (item: PathItem): TNode => (item[1][item[0]] as TNode) - -export type Path = List> - -export type Result = { - readonly first: First, - readonly tail: Path -} - -export const find -= (c: Compare): (node: TNode) => Result => { - const i3 = index3(c) - const i5 = index5(c) - const f = (tail: Path) => (node: TNode): Result => { - const append: (index: KeyOf) => Result - = index => { - const first = [index, node] as PathItem - return f({ first, tail })(child(first)) - } - const done: (index: KeyOf) => Result - = index => ({ first: [index, node] as First, tail }) - switch (node.length) { - case 1: { return done(i3(node[0])) } - case 2: { return done(i5(node)) } - case 3: { - const i = i3(node[1]) - switch (i) { - case 0: case 2: { return append(i) } - case 1: { return done(i) } - } - } - case 5: { - const i = i5([node[1], node[3]]) - switch (i) { - case 0: case 2: case 4: { return append(i) } - case 1: case 3: { return done(i) } - } - } - } - } - return f(null) -} - -export const isFound = ([i]: First): boolean => { - switch (i) { - case 1: case 3: { return true } - default: { return false } - } -} - -export const value = ([i, r]: First): T | null => { - switch (i) { - case 1: { - switch (r.length) { - case 1: case 2: { return r[0] } - default: { return r[1] } - } - } - case 3: { - return r.length === 2 ? r[1] : r[3] - } - default: { - return null - } - } -} diff --git a/fjs/types/btree/find/proof.f.ts b/fjs/types/btree/find/proof.f.ts index a67de88076..2242bc1550 100644 --- a/fjs/types/btree/find/proof.f.ts +++ b/fjs/types/btree/find/proof.f.ts @@ -1,4 +1,4 @@ -import { type Result, find as btreeFind } from './module.f.ts' +import { type Result, find as btreeFind } from './module.f.mjs' import { map, toArray } from '../../list/module.f.mjs' import { stringify, type Unknown } from '../../../media/json/module.f.ts' import { sort } from '../../object/module.f.ts' diff --git a/fjs/types/btree/proof.f.ts b/fjs/types/btree/proof.f.ts index 369ea69d4d..7fe6b442d1 100644 --- a/fjs/types/btree/proof.f.ts +++ b/fjs/types/btree/proof.f.ts @@ -5,7 +5,7 @@ import { sort } from '../object/module.f.ts' import { cmp } from '../string/module.f.ts' import { next, toArray, type List, type Result } from '../list/module.f.mjs' import { set as setSet } from './set/module.f.ts' -import { value, find as findFind } from './find/module.f.ts' +import { value, find as findFind } from './find/module.f.mjs' import { assertEq } from '../../asserts/module.f.mjs' const jsonStr = jsonStringify(sort) diff --git a/fjs/types/btree/remove/module.f.ts b/fjs/types/btree/remove/module.f.ts index 0bd0128415..7bac1fcfa6 100644 --- a/fjs/types/btree/remove/module.f.ts +++ b/fjs/types/btree/remove/module.f.ts @@ -5,7 +5,7 @@ */ import { collapseRoot, type Leaf1, type TNode, type Branch1, type Branch3, type Branch5, type Tree } from '../types/module.f.mjs' import type { Compare } from '../../function/compare/module.f.mjs' -import { type Path, type PathItem, find } from '../find/module.f.ts' +import { type Path, type PathItem, find } from '../find/module.f.mjs' import { fold, concat, next } from '../../list/module.f.mjs' import type { Tuple } from '../../array/module.f.mjs' import { map } from '../../nullable/module.f.mjs' diff --git a/fjs/types/btree/set/module.f.ts b/fjs/types/btree/set/module.f.ts index adecad7e00..6db47a4010 100644 --- a/fjs/types/btree/set/module.f.ts +++ b/fjs/types/btree/set/module.f.ts @@ -4,7 +4,7 @@ * @module */ import { collapseRoot, type Branch1, type Branch3, type Branch5, type Branch7, type TNode, type Tree } from '../types/module.f.mjs' -import { find, type First, type PathItem, type Result } from '../find/module.f.ts' +import { find, type First, type PathItem, type Result } from '../find/module.f.mjs' import type { Compare } from '../../function/compare/module.f.mjs' import { fold } from '../../list/module.f.mjs' diff --git a/fjs/types/ordered_map/module.f.ts b/fjs/types/ordered_map/module.f.ts index 715e009694..7c6402e30d 100644 --- a/fjs/types/ordered_map/module.f.ts +++ b/fjs/types/ordered_map/module.f.ts @@ -4,7 +4,7 @@ * @module */ import type { Tree } from '../btree/types/module.f.mjs' -import { value, find } from '../btree/find/module.f.ts' +import { value, find } from '../btree/find/module.f.mjs' import { set } from '../btree/set/module.f.ts' import { remove as btreeRemove } from '../btree/remove/module.f.ts' import { values } from '../btree/module.f.ts' diff --git a/fjs/types/string_set/module.f.ts b/fjs/types/string_set/module.f.ts index b5914b2c18..ec2636675b 100644 --- a/fjs/types/string_set/module.f.ts +++ b/fjs/types/string_set/module.f.ts @@ -22,7 +22,7 @@ import type { Tree } from '../btree/types/module.f.mjs' import { empty as btEmpty, values as btValues } from '../btree/module.f.ts' -import { find, isFound } from '../btree/find/module.f.ts' +import { find, isFound } from '../btree/find/module.f.mjs' import { remove as btreeRemove } from '../btree/remove/module.f.ts' import { set as btreeSet } from '../btree/set/module.f.ts' import { cmp } from "../string/module.f.ts"