import { type ITimestampStruct, type ITimespanStruct } from '../../../json-crdt-patch/clock'; import { UndEndIterator, type UndEndNext } from '../../../util/iterator'; /** * @category CRDT Node */ export interface Chunk { /** Unique sortable ID of this chunk and its span. */ id: ITimestampStruct; /** Length of the logical clock interval of this chunk. */ span: number; /** Whether this chunk is deleted. */ del: boolean; /** Actual content of the chunk, may be undefined if chunk is deleted. */ data: T | undefined; /** Length of content in this subtree (this node and its children). */ len: number; /** Parent. */ p: Chunk | undefined; /** Left. */ l: Chunk | undefined; /** Right. */ r: Chunk | undefined; /** Parent 2. */ p2: Chunk | undefined; /** Left 2. */ l2: Chunk | undefined; /** Right 2. */ r2: Chunk | undefined; /** Split link, next chunk which was split from this chunk. */ s: Chunk | undefined; /** Add more content to this chunk. */ merge(content: T): void; /** * Split this chunk after given clock ticks. Minimal `ticks` is 1. */ split(ticks: number): Chunk; /** Mark chunk as deleted. */ delete(): void; /** Return a deep copy of itself. */ clone(): Chunk; /** Return the data of the chunk, if not deleted. */ view(): T & { slice: (start: number, end: number) => T; }; } /** * @category CRDT Node */ export declare abstract class AbstractRga = Chunk> { readonly id: ITimestampStruct; root: Chunk | undefined; ids: Chunk | undefined; count: number; abstract view(): unknown; protected abstract createChunk(id: ITimestampStruct, content: T | undefined): Chunk; protected abstract onChange(): void; constructor(id: ITimestampStruct); ins(after: ITimestampStruct, id: ITimestampStruct, content: T): void; insAt(position: number, id: ITimestampStruct, content: T): ITimestampStruct | undefined; protected insAfterRoot(after: ITimestampStruct, id: ITimestampStruct, content: T): void; protected insAfterChunk(after: ITimestampStruct, chunk: Chunk, chunkOffset: number, id: ITimestampStruct, content: T): void; delete(spans: ITimespanStruct[]): void; protected deleteSpan(span: ITimespanStruct): void; find(position: number): undefined | ITimestampStruct; findChunk(position: number): undefined | [chunk: Chunk, offset: number]; findInterval(position: number, length: number): ITimespanStruct[]; /** Rename to .rangeX() method? */ findInterval2(from: ITimestampStruct, to: ITimestampStruct): ITimespanStruct[]; /** * @note All ".rangeX()" method are not performance optimized. For hot paths * it is better to hand craft the loop. * * @param startChunk Chunk from which to start the range. If undefined, the * chunk containing `from` will be used. This is an optimization * to avoid a lookup. * @param from ID of the first element in the range. * @param to ID of the last element in the range. * @param callback Function to call for each chunk slice in the range. If it * returns truthy value, the iteration will stop. * @returns Reference to the last chunk in the range. */ range0(startChunk: Chunk | undefined, from: ITimestampStruct, to: ITimestampStruct, callback: (chunk: Chunk, off: number, len: number) => boolean | void): Chunk | void; first(): C | undefined; last(): Chunk | undefined; lastId(): ITimestampStruct | undefined; /** @todo Maybe use implementation from tree utils, if does not impact performance. */ /** @todo Or better remove this method completely, as it does not require "this". */ next(curr: Chunk): Chunk | undefined; /** @todo Maybe use implementation from tree utils, if does not impact performance. */ /** @todo Or better remove this method completely, as it does not require "this". */ prev(curr: Chunk): Chunk | undefined; /** Content length. */ length(): number; /** Number of chunks. */ size(): number; /** Returns the position of the first element in the chunk. */ pos(chunk: Chunk): number; chunks0(): UndEndNext; chunks(): UndEndIterator; setRoot(chunk: Chunk): void; insertBefore(chunk: Chunk, before: Chunk): void; insertAfter(chunk: Chunk, after: Chunk): void; protected insertAfterRef(chunk: Chunk, ref: ITimestampStruct, left: Chunk): void; protected mergeContent(chunk: Chunk, content: T): void; protected insertInside(chunk: Chunk, at: Chunk, offset: number): void; protected split(chunk: Chunk, ticks: number): Chunk; protected mergeTombstones(ch1: Chunk, ch2: Chunk): boolean; protected mergeTombstones2(start: Chunk, end: Chunk): void; rmTombstones(): void; deleteChunk(chunk: Chunk): void; insertId(chunk: Chunk): void; insertIdFast(chunk: Chunk): void; protected deleteId(chunk: Chunk): void; findById(after: ITimestampStruct): Chunk | undefined; posById(id: ITimestampStruct): number | undefined; /** * @param id ID of character to start the search from. * @returns Previous ID in the RGA sequence. */ prevId(id: ITimestampStruct): ITimestampStruct | undefined; spanView(span: ITimespanStruct): T[]; splay(chunk: Chunk): void; iterator(): () => Chunk | undefined; ingest(size: number, next: () => Chunk): void; private _ingest; protected toStringName(): string; toString(tab?: string): string; protected printChunk(tab: string, chunk: Chunk): string; protected formatChunk(chunk: Chunk): string; }