/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import type { IIdCompressor } from "@fluidframework/id-compressor";
import { CursorLocationType, type FieldKey, type FieldUpPath, type PathRootPrefix, type TreeNodeSchemaIdentifier, type TreeValue, type UpPath, type Value, type ChunkedCursor, type TreeChunk, cursorChunk } from "../../core/index.js";
import { ReferenceCountedBase } from "../../util/index.js";
import { SynchronousCursor } from "../treeCursorUtils.js";
/**
 * Create a tree chunk with ref count 1.
 *
 * @param shape - describes the semantics and layout of `values`.
 * @param values - provides exclusive ownership of this array to this object (which might mutate it in the future).
 */
export declare function uniformChunk(shape: ChunkShape, values: TreeValue[]): TreeChunk;
/**
 * Chunk which handles a sequence of trees with identical "shape" (see `TreeShape`).
 *
 * Separates shape from content,
 * allowing deduplication of shape information and storing of content as a flat sequence of values.
 */
export declare class UniformChunk extends ReferenceCountedBase implements TreeChunk {
    shape: ChunkShape;
    values: TreeValue[];
    idCompressor: undefined | IIdCompressor;
    /**
     * Create a tree chunk with ref count 1.
     *
     * @param shape - describes the semantics and layout of `values`.
     * @param values - provides exclusive ownership of this array to this object (which might mutate it in the future).
     */
    constructor(shape: ChunkShape, values: TreeValue[], idCompressor?: IIdCompressor);
    get topLevelLength(): number;
    clone(): UniformChunk;
    cursor(): Cursor;
    protected onUnreferenced(): void;
}
/**
 * The "shape" of a field.
 *
 * Requires that all trees in the field have the same shape, which is described by `TreeShape`.
 * Note that this requirement means that not all fields can be described using this type.
 */
export type FieldShape = readonly [FieldKey, TreeShape, number];
/**
 * The "shape" of a tree.
 * Does not contain the actual values from  the tree, but describes everything else,
 * including where the values would be found in a flat values array.
 *
 * Note that since this requires fields to have uniform shapes (see `FieldShape`),
 * not all trees can have their shape described using this type.
 */
export declare class TreeShape {
    readonly type: TreeNodeSchemaIdentifier;
    readonly hasValue: boolean;
    readonly fieldsArray: readonly FieldShape[];
    readonly fields: ReadonlyMap<FieldKey, OffsetShape>;
    readonly fieldsOffsetArray: readonly OffsetShape[];
    readonly valuesPerTopLevelNode: number;
    /**
     * Information about every node in this shape.
     * The root is first, and all indexes it uses to refer to other nodes are indexes into this array.
     * Beyond that the ordering is an implementation detail of this shape.
     * @remarks
     * Use of this in contexts where there might be multiple top-level nodes requires some additional care.
     * For example {@link Cursor} derives each node's actual position info from this shared
     * array plus the node's top-level index within the chunk.
     */
    readonly positions: readonly NodePositionInfo[];
    /**
     * Whether chunks using this shape (including any descendant leaf within it) may contain values compressed by the {@link UniformChunk.idCompressor}.
     *
     * @remarks
     * For string leaf nodes, this can be explicitly set to `true` to indicate that the value may be a compressed id
     * stored as a number that needs to be decompressed back to a string.
     * For non-leaf nodes, this is automatically derived from whether any child shapes have it set.
     */
    readonly mayContainCompressedIds: boolean;
    /**
     * Cache for ChunkShape instances created by {@link withTopLevelLength}.
     * `topLevelLength` is always a positive integer (enforced by the {@link ChunkShape} constructor),
     * so the cache only ever holds entries for values in `1..chunkShapeCacheLimit - 1` to prevent unbounded growth.
     */
    private readonly chunkShapeCache;
    /**
     * @param type - {@link TreeNodeSchemaIdentifier} used to compare shapes.
     * @param hasValue - whether or not the TreeShape has a value.
     * @param fieldsArray - an array of {@link FieldShape} values, which contains a TreeShape for each FieldKey.
     *
     * @param maybeCompressedIdLeaf - whether the value may have been compressed by the {@link UniformChunk.idCompressor}.
     * Can only be explicitly set to `true` on string leaf nodes; otherwise this constructor asserts.
     * For non-leaf nodes, {@link TreeShape.mayContainCompressedIds} is automatically derived from child shapes.
     */
    constructor(type: TreeNodeSchemaIdentifier, hasValue: boolean, fieldsArray: readonly FieldShape[], maybeCompressedIdLeaf?: boolean);
    equals(other: TreeShape): boolean;
    withTopLevelLength(topLevelLength: number): ChunkShape;
}
/**
 * The shape (see `TreeShape`) of a sequence of trees, all with the same shape (like `FieldShape`, but without a field key).
 *
 * @remarks
 * Paired with a value array, this lets a {@link UniformChunk} be traversed like a tree by an
 * {@link ITreeCursorSynchronous}. The {@link Cursor} derives each node's position info from the
 * shared {@link TreeShape.positions} plus the node's top-level index.
 *
 * TODO: consider storing shape information in WASM
 */
export declare class ChunkShape {
    readonly treeShape: TreeShape;
    readonly topLevelLength: number;
    constructor(treeShape: TreeShape, topLevelLength: number);
    equals(other: ChunkShape): boolean;
}
/**
 * Shape of a field (like `FieldShape`) but with information about how it would be offset within a chunk because of its parents.
 */
declare class OffsetShape {
    readonly shape: TreeShape;
    readonly topLevelLength: number;
    readonly offset: number;
    readonly key: FieldKey;
    readonly indexOfParentField: number | undefined;
    /**
     * @param shape - the shape of each child in this field
     * @param topLevelLength - number of top level nodes in this sequence chunk (either field within a chunk, or top level chunk)
     * @param offset - number of nodes before this in the parent's subtree. The nodes are considered in depth first pre order
     * traversal, so a parent is the first node in its subtree (before its children) with offset 0
     * @param key - field key
     * @param indexOfParentField - index to this shape in the parent's array of fields
     */
    constructor(shape: TreeShape, topLevelLength: number, offset: number, key: FieldKey, indexOfParentField: number | undefined);
}
/**
 * Information about a node at a specific position within one top-level tree of a {@link TreeShape}.
 */
declare class NodePositionInfo implements UpPath {
    readonly parent: NodePositionInfo | undefined;
    readonly parentField: FieldKey;
    readonly parentIndex: number;
    readonly indexOfParentField: number | undefined;
    readonly indexOfParentPosition: number | undefined;
    readonly shape: TreeShape;
    readonly topLevelLength: number;
    readonly valueOffset: number;
    /**
     * @param parent - The parent node's {@link NodePositionInfo} or `undefined` for a root.
     * @param parentField - The {@link FieldKey} of the field this node occupies within its parent.
     * @param parentIndex - indexWithinParentField
     * @param indexOfParentField - Which field of the parent `parentIndex` is indexing into to locate this.
     * @param indexOfParentPosition - Index of this node's parent in {@link TreeShape.positions}
     * @param shape - Shape of the top level sequence this node is part of
     * @param topLevelLength - Number of siblings in this node's field. For a root this is unused
     * @param valueOffset - Offset of this node's value within one top-level tree's slice of the chunk's flat `values` array;
     * only valid when `shape.hasValue` (otherwise it's where the value would have gone, and should not be used to read a value).
     */
    constructor(parent: NodePositionInfo | undefined, // TODO; general UpPath to allow prefixing here?
    parentField: FieldKey, parentIndex: number, indexOfParentField: number | undefined, indexOfParentPosition: number | undefined, shape: TreeShape, // Shape of sequence that contains this node (top level is parent of this node)
    topLevelLength: number, valueOffset: number);
}
/**
 * The cursor implementation for `UniformChunk`.
 *
 * @remarks
 * Tracks a flat `positionIndex` and derives each node's position info from the shape's shared
 * {@link TreeShape.positions} plus the node's top-level index.
 */
declare class Cursor extends SynchronousCursor implements ChunkedCursor {
    private readonly chunk;
    private positionIndex;
    /** Position info for the current node, or `undefined` when in root field. */
    private nodePositionInfo;
    /** Which top-level node of the chunk the current position is within. Valid when nodePositionInfo !== undefined. */
    private topLevelIndex;
    /** The chunk's shape. */
    private readonly shape;
    /** The chunk's per-tree shape (shape of each top-level tree). */
    private readonly treeShape;
    /** Number of positions in one top-level tree (treeShape.positions.length). */
    private readonly nodeLength;
    /** Number of values per top-level node (treeShape.valuesPerTopLevelNode). */
    private readonly stride;
    mode: CursorLocationType;
    private fieldKey?;
    private indexOfField;
    constructor(chunk: UniformChunk);
    get [cursorChunk](): UniformChunk | undefined;
    atChunkRoot(): boolean;
    fork(): Cursor;
    /**
     * Change the current node within the chunk.
     *
     * @param positionIndex - flat position index of the newly selected node. This is NOT an index
     * within a field, and is not bounds checked.
     *
     * @remarks
     * Decomposes the index into {@link Cursor.topLevelIndex} and {@link Cursor.nodePositionInfo}.
     * See `nodeInfo` for getting data about the current node.
     *
     */
    private moveToPosition;
    /**
     * Decode a flat `positionIndex` into its components.
     *
     * @param positionIndex - flat position index of the node to decode. Must be greater than 0;
     * @returns the node's index within {@link TreeShape.positions} (`withinTree`), which top-level
     * tree holds it (`topLevelIndex`), and the corresponding shared {@link NodePositionInfo} (`info`).
     */
    private decodePosition;
    /**
     * Build a standalone {@link UpPath} for the node at `positionIndex`. O(depth) allocation.
     *
     * @remarks
     * walks the shared per-tree {@link TreeShape.positions} and applies the top-level index
     * at each level. Mirrors how the `BasicChunk` cursor allocates paths.
     */
    private materializePath;
    /**
     * Gets information about the current node.
     *
     * When in Nodes mode, this means the node this cursor is current at.
     * When if fields mode, this means the node which is the parent of the current field.
     * This cursor is in Nodes mode at the root, so there is no case where a fields mode does not have a parent.
     *
     * @param requiredMode - asserts that the mode matches this. Since the semantics of this function are somewhat mode dependent,
     * providing this ensures that the caller knows what the results will mean.
     */
    private nodeInfo;
    nextField(): boolean;
    exitField(): void;
    getFieldKey(): FieldKey;
    getFieldLength(): number;
    firstNode(): boolean;
    enterNode(childIndex: number): void;
    /**
     * Enter the current field, at `childIndex`.
     * @param childIndex - index into current field to navigate to. Must be non-negative integer.
     */
    private enterNodeInner;
    private enterRootNodeInner;
    getFieldPath(prefix?: PathRootPrefix): FieldUpPath;
    getPath(prefix?: PathRootPrefix): UpPath | undefined;
    get fieldIndex(): number;
    readonly chunkStart: number;
    /**
     * Number of nodes in `info`'s field including `info` itself.
     *
     * @remarks
     * For top-level nodes this is the chunk's `topLevelLength`, read from the chunk
     * rather than the node, so the shared per-tree {@link TreeShape.positions} stays independent of
     * chunk length; the root entry's own `topLevelLength` field is unused. Nested nodes use the
     * field length stored on the node.
     */
    private siblingCount;
    get chunkLength(): number;
    seekNodes(offset: number): boolean;
    nextNode(): boolean;
    exitNode(): void;
    firstField(): boolean;
    enterField(key: FieldKey): void;
    get type(): TreeNodeSchemaIdentifier;
    get value(): Value;
}
export {};
//# sourceMappingURL=uniformChunk.d.ts.map