/**
 * @fileoverview Derived from @josephg's implementation here: https://github.com/josephg/jumprope
 *
 * MIT license etc etc
 */
/**
 * Returns a value [1,31] inclusive, with 50% chance of 1, 25% chance of 2, 12.5% chance of 3, ...
 */
export declare const randomHeight: () => number;
export type RopeLookup<K, T> = {
    data: T;
    length: number;
    id: K;
    prevId: K;
    nextId: K;
};
export type RopeRead<T> = {
    out: T[];
    len: number[];
};
/**
 * Actually an 'immutable rope'.
 *
 * Parts cannot be modified, because they are objects with length that have some kind of rendering that this class won't understand.
 */
export declare class Rope<K, T> {
    private _length;
    private head;
    private tail;
    private readonly zeroId;
    private byId;
    private readonly _nodesBuffer;
    private readonly _subBuffer;
    private readonly _nodesPool;
    /**
     * Clones this {@link Rope} using {@link structuredClone}.
     */
    clone(): Rope<K, T>;
    constructor(zeroId: K, root: T);
    length(): number;
    last(): K;
    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.
     */
    lengthBetween(low: K, high: K): number;
    /**
     * Prints out the rope for debugging.
     */
    _debug(): void;
    [Symbol.iterator](): Generator<T, void, unknown>;
    /**
     * Finds the position after the given ID.
     *
     * Perf: `O(logn)-ish`.
     */
    find(ropeId: K): number;
    has(ropeId: K): boolean;
    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.
     */
    byPosition(position: number, biasAfter?: boolean): {
        id: K;
        offset: number;
    };
    /**
     * Reduced version of `rseek` for various purposes...
     *
     * Result placed in `_nodesBuffer`.
     */
    private rseekNodes;
    /**
     * Adjust the given entry's data/length.
     */
    adjust(id: K, data: T, length: number): void;
    /**
     * Inserts a node after a previous node.
     */
    insertAfter(afterId: K, newId: K, length: number, data: T): void;
    /**
     * Deletes the given ID from this rope.
     */
    deleteById(id: K): T[];
    /**
     * Deletes after the given ID until the target ID.
     */
    deleteTo(afterId: K, untilId: K): T[];
    private insertIntoPool;
    /**
     * Is the ID in `a` before the ID in `b`?
     */
    before(a: K, b: K): boolean;
    compare(a: K, b: K): number;
    iter(afterId: K): Iterable<{
        id: K;
        data: T;
    }>;
    read(from: K, to?: K): RopeRead<T> | undefined;
}
