UNPKG

thorish

Version:

This is a library of useful JS concepts and data structures for Node and the browser. It it, unashamedly, a dumping ground for code needed by [@samthor](https://twitter.com/samthor)'s projects.

178 lines (177 loc) 4.95 kB
/** * @fileoverview Derived from @josephg's implementation here: https://github.com/josephg/jumprope * * MIT license etc etc * * Version that doesn't break reactivity. */ export type RopeLookup<K, T> = { data: T; length: number; /** * The ID of this lookup. * This will be the same as what was passed in to perform the lookup. */ id: K; /** * The previous ID in sequence. */ prevId: K; /** * The next ID in sequence. * This will be the zero ID if there is no following data. */ nextId: K; }; export type RopeRead<T> = { out: T[]; len: number[]; }; /** * Implements a skip list with `O(logn)-ish` performance. * * We store data here, but mostly only as a convenience: it's a simple k/v map. * The length is far more important. * * Individual parts can have zero length. */ export declare class Rope<K, T = void> { private _length; private head; private tail; private readonly _zeroId; private readonly byId; private readonly dataById; private readonly nodeCache; /** * The zero ID that this {@link Rope} was created with. */ zeroId(): K; /** * Clones this {@link Rope} using {@link structuredClone}. */ clone(): Rope<K, T>; /** * Constructs a new {@link Rope}. * * The second argument may be passed purely as a TypeScript hint for {@link T} and it is stored on the root node, but it is not required and cannot ever be read. */ constructor(zeroId: K, sampleData?: T); /** * The total length of all items in this {@link Rope}. */ length(): number; /** * The ID of the right-most entry here. */ last(): K; /** * The count of items in this {@link Rope}, even zero-length ones. */ count(): number; /** * Find the length between these two valid IDs. * * This isn't a substitute for {@link compare} as zero length entries are allowed, so this won't return which one is first. * * Currently just calls {@link find} twice, so `O(logn)-ish`. */ lengthBetween(low: K, high: K): number; /** * Prints out the rope for debugging. */ _debug(): void; [Symbol.iterator](): Iterator<T, void, void>; /** * Finds the position after the given ID. * * Perf: `O(logn)-ish`. */ find(ropeId: K): number; /** * Does this ID exist here. * * Perf: `O(1)-ish` (just {@link Map}). */ has(ropeId: K): boolean; /** * Lookup information on this ID. * * This throws when trying to look up the zero ID. * * Perf: `O(1)-ish` (just {@link Map}). */ lookup(ropeId: K): RopeLookup<K, T>; /** * Find the ID for the given position, and the offset from the end of that ID. * Always returns a valid value, is clamped to edge. * * By default, this will be the left-most ID that contains the position (even 'at end'). * For example, looking up `offset=0` in an already-used rope will always yield `id=0`, as it has zero length. * * Specify the `biasEnd` parameter to flip this behavior. * * Perf: `O(logn)-ish`. */ byPosition(position: number, biasAfter?: boolean): { id: K; offset: number; }; /** * Reduced version of `rseek` for various purposes... */ private rseekNodes; /** * Adjust the given entry's data/length. */ adjust(id: K, data: T, length: number): void; /** * Inserts a node after a previous node. * * Perf: `O(logn)-ish`. */ insertAfter(afterId: K, newId: K, length: number, data: T): void; /** * Deletes the given ID from this rope. * * Perf: `O(logn)-ish`. */ deleteById(id: K): void; /** * Deletes after the given ID until the target ID. * * Perf: `O(logn)-ish`. */ deleteTo(afterId: K, untilId: K): void; private insertIntoPool; /** * Is the ID in `a` before the ID in `b`? * * Perf: `O(logn)-ish`. */ before(a: K, b: K): boolean; /** * Compares the position of these two IDs. * * Returns -1 if A is before B, zero if they are the same, and +1 if A is after B. * * Perf: `O(logn)-ish`. */ compare(a: K, b: K): number; /** * Iterate from after the given ID, to the target ID inclusive (i.e., `(afterId,untilId]`). * * If no `untilId` is passed or the IDs are in the wrong order, iterates from after `afterId` until the end of this {@link Rope}. */ iter(afterId?: K, untilId?: K): Iterable<{ id: K; data: T; length: number; }, void, void>; /** * Reads all data from after the given ID, to the target ID inclusive. * * This is a convenience over {@link iter} and has the same semantics. */ read(afterId?: K, untilId?: K): RopeRead<T>; }