import type { Token } from '@rimbu/base';
import type { RMap, VariantMap } from '@rimbu/collection-types/map';
import type { Row, WithRow } from '@rimbu/collection-types/map-custom';
import type { ArrayNonEmpty, OptLazy, OptLazyOr, RelatedTo, ToJSON, TraverseState, Update } from '@rimbu/common';
import type { FastIterable, Reducer, Stream, StreamSource, Streamable } from '@rimbu/stream';
export interface VariantTableBase<R, C, V, Tp extends VariantTableBase.Types = VariantTableBase.Types> extends FastIterable<[R, C, V]> {
    /**
     * Returns the Map representation of this collection.
     * @example
     * ```ts
     * const m = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * const map: HashMap<number, HashMap.NonEmpty<number, number>> = m.rowMap
     * ```
     */
    readonly rowMap: WithRow<Tp, R, C, V>['rowMap'];
    /**
     * Returns true if the collection is empty.
     * @example
     * ```ts
     * HashTableHashColumn.empty<number, number, number>().isEmpty   // => true
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).isEmpty          // => false
     * ```
     */
    readonly isEmpty: boolean;
    /**
     * Returns the amount of entries in the collection.
     * @example
     * ```ts
     * HashTableHashColumn.empty<number, number, number>().size   // => 0
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).size          // => 2
     * ```
     */
    readonly size: number;
    /**
     * Returns the amount of rows in the collection.
     * @example
     * ```ts
     * HashTableHashColumn.empty<number, number, number>().amountRows   // => 0
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).amountRows          // => 1
     * ```
     */
    readonly amountRows: number;
    /**
     * Returns true if there is at least one entry in the collection, and instructs the compiler to treat the collection
     * as a .NonEmpty type.
     * @example
     * ```ts
     * const m: Table<number, number> = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * m.stream().first(0)     // compiler allows fallback value since the Stream may be empty
     * if (m.nonEmpty()) {
     *   m.stream().first(0)   // compiler error: fallback value not allowed since Stream is not empty
     * }
     * ```
     */
    nonEmpty(): this is WithRow<Tp, R, C, V>['nonEmpty'];
    /**
     * Returns the collection as a .NonEmpty type
     * @throws RimbuError.EmptyCollectionAssumedNonEmptyError if the collection is empty
     * @example
     * ```ts
     * HashTableHashColumn.empty<number, number, number>().assumeNonEmpty()   // => throws
     * const m: Table<number, number, number> = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * const m2: Table.NonEmpty<number, number> = m     // => compiler error
     * const m3: Table.NonEmpty<number, number> = m.assumeNonEmpty()
     * ```
     * @note returns reference to this collection
     */
    assumeNonEmpty(): WithRow<Tp, R, C, V>['nonEmpty'];
    /**
     * Returns a Stream containing all entries of this collection as tuples of row key,
     * column key, and value.
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).stream().toArray()
     * // => [[1, 2, 3], [1, 4, 5]]
     * ```
     */
    stream(): Stream<[R, C, V]>;
    /**
     * Returns a Stream containing all row keys of this collection.
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).streamRows().toArray()
     * // => [1]
     * ```
     */
    streamRows(): Stream<R>;
    /**
     * Returns a Stream containing all values of this collection.
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).streamValues().toArray()
     * // => [3, 5]
     * ```
     */
    streamValues(): Stream<V>;
    /**
     * Returns true if given `row` key is in the collection.
     * @param row - the row key to look for
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.hasRowKey(10)    // => false
     * t.hasRowKey(1)     // => true
     * ```
     */
    hasRowKey<UR = R>(row: RelatedTo<R, UR>): boolean;
    /**
     * Returns true if the collection has a value for given `row` and `column` keys.
     * @param row - the row key
     * @param column - the column key
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.hasValueAt(10, 1)    // => false
     * t.hasValueAt(1, 4)     // => true
     * ```
     */
    hasValueAt<UR = R, UC = C>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>): boolean;
    /**
     * Returns the value at given `row` and `column` keys, or the `otherwise` value if no
     * value is present.
     * @param row - the row key
     * @param column - the column key
     * @param otherwise - (default: undefined) the value to return if no value is found
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.get(10, 1)     // => undefined
     * t.get(10, 1, 0)  // => 0
     * t.get(1, 2)      // => 3
     * t.get(1, 2, 0)   // => 3
     * ```
     */
    get<UR = R, UC = C>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>): V | undefined;
    get<UR, UC, O>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>, otherwise: OptLazy<O>): V | O;
    /**
     * Returns a map containing the column keys and values in the given `row`.
     * @param row - the row key
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.getRow(10).toArray()    // => []
     * t.getRow(1).toArray()     // => [[2, 3], [4, 5]]
     * ```
     */
    getRow<UR = R>(row: RelatedTo<R, UR>): WithRow<Tp, R, C, V>['row'];
    /**
     * Returns the collection where the value at given `row` and `column` keys is removed.
     * @param row - the row key
     * @param column - the column key
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.remove(10, 11).toArray()   // => [[1, 2, 3], [1, 4, 5]]
     * t.remove(1, 4).toArray()     // => [[1, 2, 3]]
     * ```
     */
    remove<UR = R, UC = C>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>): WithRow<Tp, R, C, V>['normal'];
    /**
     * Returns the collection where all values in given `row` are removed.
     * @param row - the row key
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 2, 3])
     * t.removeRow(10).toArray()   // => [[1, 2, 3], [1, 4, 5], [2, 2, 3]]
     * t.removeRow(1).toArray()    // => [[2, 2, 3]]
     * ```
     */
    removeRow<UR = R>(row: RelatedTo<R, UR>): WithRow<Tp, R, C, V>['normal'];
    /**
     * Returns a tuple containing the collection with the value at given `row` and `column` removed,
     * and the removed value. If no such value is found, it returns undefined.
     * @param row - the row key
     * @param column - the column key
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.removeAndGet(10, 11)  // => undefined
     * t.removeAndGet(1, 2)    // => [HashTableHashColumn([1, 4, 5]), 3]
     * ```
     */
    removeAndGet<UR = R, UC = C>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>): [WithRow<Tp, R, C, V>['normal'], V] | undefined;
    /**
     * Returns a tuple containing the collection with the values at given `row` removed,
     * and a map containing the removed columns and values. If no such row is found, it
     * returns undefined.
     * @param row - the row key
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.removeRowAndGet(10)    // => undefined
     * t.removeRowAndGet(1)     // => [HashTableHashColumn(), HashMap(2 => 3, 4 => 5)]
     * ```
     */
    removeRowAndGet<UR = R>(row: RelatedTo<R, UR>): [WithRow<Tp, R, C, V>['normal'], WithRow<Tp, R, C, V>['rowNonEmpty']] | undefined;
    /**
     * Returns the collection where the values for each row key in given `rows` are removed.
     * @param rows - a `StreamSource` of row keys
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.removeRows([10, 11]).toArray()   // => [[1, 2, 3], [1, 4, 5]]
     * t.removeRows([1, 10]).toArray()    // => []
     * ```
     */
    removeRows<UR = R>(rows: StreamSource<RelatedTo<R, UR>>): WithRow<Tp, R, C, V>['normal'];
    /**
     * Returns the collection where the given `entries` are removed.
     * @param entries - a `StreamSource` of table entries
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.removeEntries([[6, 7, 8], [7, 8, 9]]).toArray()  // => [[1, 2, 3], [1, 4, 5]]
     * t.removeEntries([[6, 7, 8], [1, 2, 3]]).toArray()  // => [[1, 4, 5]]
     * ```
     */
    removeEntries<UR = R, UC = C>(entries: StreamSource<[RelatedTo<R, UR>, RelatedTo<C, UC>]>): WithRow<Tp, R, C, V>['normal'];
    /**
     * Performs given function `f` for each entry of the collection, using given `state` as initial traversal state.
     * @param f - the function to perform for each entry, receiving:<br/>
     * - `entry`: the next tuple of a row key, column key, and value<br/>
     * - `index`: the index of the element<br/>
     * - `halt`: a function that, if called, ensures that no new elements are passed
     * @param options - object containing the following<br/>
     * - state: (optional) the traverse state
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5])
     *   .forEach((entry, i, halt) => {
     *     console.log([entry]);
     *     if (i >= 1) halt();
     *   })
     * // => logs [1, 2, 3]  [1, 4, 5]
     * ```
     * @note O(N)
     */
    forEach(f: (entry: [R, C, V], index: number, halt: () => void) => void, options?: {
        state?: TraverseState;
    }): void;
    /**
     * Returns a collection containing only those entries that satisfy given `pred` predicate.
     * @param pred - a predicate function receiving:<br/>
     * - `entry`: the next entry<br/>
     * - `index`: the entry index<br/>
     * - `halt`: a function that, when called, ensures no next elements are passed
     * @param options - object containing the following<br/>
     * - negate: (default: false) when true will negate the given predicate
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5])
     *   .filter(entry => entry[2] === 5).toArray()
     * // => [[1, 4, 5], [2, 3, 5]]
     * ```
     */
    filter(pred: (entry: [R, C, V], index: number, halt: () => void) => boolean, options?: {
        negate?: boolean;
    }): WithRow<Tp, R, C, V>['normal'];
    /**
     * Returns a collection containing only those rows that satisfy given `pred` predicate.
     * @param pred - a predicate function receiving:<br/>
     * - `entry`: the next entry of the row key and a collection representing its columns and values<br/>
     * - `index`: the entry index<b/>
     * - `halt`: a function that, when called, ensures no next elements are passed
     * @param options - object containing the following<br/>
     * - negate: (default: false) when true will negate the given predicate
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5])
     *   .filterRows((rowKey, values) => rowKey === 1 && values.hasKey(4)).toArray()
     * // => [[1, 2, 3], [1, 4, 5]]
     * ```
     */
    filterRows(pred: (entry: readonly [R, WithRow<Tp, R, C, V>['rowNonEmpty']], index: number, halt: () => void) => boolean, options?: {
        negate?: boolean;
    }): WithRow<Tp, R, C, V>['normal'];
    /**
     * Returns a collection with the same row and column keys, but where the given `mapFun` function is applied to each entry value.
     * @param mapFun - a function taking a `value` and a row and column key, and returning a new value
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5])
     *   .mapValues(value => value * 2)
     * // => [[1, 2, 6], [1, 4, 10], [2, 3, 10]]
     * ```
     */
    mapValues<V2>(mapFun: (value: V, row: R, column: C) => V2): (Tp & Row<R, C, V2>)['normal'];
    /**
     * Returns an array containing all entries in this collection.
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toArray()
     * // => [[1, 2, 3], [1, 4, 5]]
     * ```
     * @note O(log(N))
     * @note it is safe to mutate the returned array, however, the array elements are not copied, thus should be treated as read-only
     */
    toArray(): [R, C, V][];
    /**
     * Returns a string representation of this collection.
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toString()
     * // => HashTableHashColumn([1, 2] -> 3, [1, 4] -> 5)
     * ```
     */
    toString(): string;
    /**
     * Returns a JSON representation of this collection.
     * @example
     * ```ts
     * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toJSON()
     * // => { dataType: 'HashTableHashColumn', value: [1, [ [2, 3], [4, 5] ] ] }
     * ```
     */
    toJSON(): ToJSON<[R, [C, V][]][]>;
}
export declare namespace VariantTableBase {
    interface NonEmpty<R, C, V, Tp extends VariantTableBase.Types = VariantTableBase.Types> extends VariantTableBase<R, C, V, Tp>, Streamable.NonEmpty<[R, C, V]> {
        /**
         * Returns the Map representation of this collection.
         * @example
         * ```ts
         * const m = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
         * const map: HashMap.NonEmpty<number, HashMap.NonEmpty<number, number>> = m.rowMap
         * ```
         */
        readonly rowMap: WithRow<Tp, R, C, V>['rowMapNonEmpty'];
        /**
         * Returns false since this collection is known to be non-empty
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).isEmpty   // => false
         * ```
         */
        readonly isEmpty: false;
        /**
         * Returns a self reference since this collection is known to be non-empty.
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
         * t === t.assumeNonEmpty()  // => true
         * ```
         */
        assumeNonEmpty(): this;
        /**
         * Returns this collection typed as a 'possibly empty' collection.
         * @example
         * ```ts
         * Table.of([1, 1, 1], [2, 2, 2]).asNormal();  // type: Table<number, number, number>
         * ```
         */
        asNormal(): WithRow<Tp, R, C, V>['normal'];
        /**
         * Returns true since this collection is known to be non-empty
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).nonEmpty()   // => true
         * ```
         */
        nonEmpty(): this is WithRow<Tp, R, C, V>['nonEmpty'];
        /**
         * Returns a non-empty Stream containing all entries of this collection as tuples of row key,
         * column key, and value.
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).stream().toArray()
         * // => [[1, 2, 3], [1, 4, 5]]
         * ```
         */
        stream(): Stream.NonEmpty<[R, C, V]>;
        /**
         * Returns a non-empty Stream containing all row keys of this collection.
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).streamRows().toArray()
         * // => [1]
         * ```
         */
        streamRows(): Stream.NonEmpty<R>;
        /**
         * Returns a non-empty Stream containing all values of this collection.
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).streamValues().toArray()
         * // => [3, 5]
         * ```
         */
        streamValues(): Stream.NonEmpty<V>;
        /**
         * Returns a non-empty collection with the same row and column keys, but where the given `mapFun` function is applied to each entry value.
         * @param mapFun - a function taking a `value` and a row and column key, and returning a new value
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5])
         *   .mapValues(value => value * 2)
         * // => [[1, 2, 6], [1, 4, 10], [2, 3, 10]]
         * ```
         */
        mapValues<V2>(mapFun: (value: V, row: R, column: C) => V2): (Tp & Row<R, C, V2>)['nonEmpty'];
        /**
         * Returns a non-empty array containing all entries in this collection.
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toArray()
         * // => [[1, 2, 3], [1, 4, 5]]
         * ```
         * @note O(log(N))
         * @note it is safe to mutate the returned array, however, the array elements are not copied, thus should be treated as read-only
         */
        toArray(): ArrayNonEmpty<[R, C, V]>;
    }
    /**
     * Utility interface that provides higher-kinded types for this collection.
     */
    interface Types extends Row {
        readonly normal: VariantTableBase<this['_R'], this['_C'], this['_V']>;
        readonly nonEmpty: VariantTableBase.NonEmpty<this['_R'], this['_C'], this['_V']>;
        readonly row: VariantMap<this['_C'], this['_V']>;
        readonly rowNonEmpty: VariantMap.NonEmpty<this['_C'], this['_V']>;
        readonly rowMap: VariantMap<this['_R'], VariantMap.NonEmpty<this['_C'], this['_V']>>;
        readonly rowMapNonEmpty: VariantMap.NonEmpty<this['_R'], VariantMap.NonEmpty<this['_C'], this['_V']>>;
    }
}
export interface TableBase<R, C, V, Tp extends TableBase.Types = TableBase.Types> extends VariantTableBase<R, C, V, Tp> {
    /**
     * Returns the `context` associated to this collection instance.
     */
    readonly context: WithRow<Tp, R, C, V>['context'];
    /**
     * Returns the collection where the given `value` is associated with the given `row` and
     * `column` keys.
     * @param row - the row key
     * @param column - the column key
     * @param value - the value to add
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.set(1, 2, 10).toArray()    // => [[1, 2, 10], [1, 4, 5]]
     * t.set(2, 6, 8).toArray()     // => [[1, 2, 3], [1, 4, 5], [2, 6, 8]]
     * ```
     */
    set(row: R, column: C, value: V): WithRow<Tp, R, C, V>['nonEmpty'];
    /**
     * Returns the collection with the given `entry` added.
     * @param entry - the entry to add
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.addEntry([2, 6, 8]).toArray()   // => [[1, 2, 3], [1, 4, 5], [2, 6, 8]]
     * ```
     */
    addEntry(entry: readonly [R, C, V]): WithRow<Tp, R, C, V>['nonEmpty'];
    /**
     * Returns the collection with the given `entries` added.
     * @param entries - a `StreamSource containing entries to add
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3])
     * t.addEntries([[1, 4, 5], [2, 6, 8]]).toArray()
     * // => [[1, 2, 3], [1, 4, 5], [2, 6, 8]]
     * ```
     */
    addEntries(entries: StreamSource.NonEmpty<readonly [R, C, V]>): WithRow<Tp, R, C, V>['nonEmpty'];
    addEntries(entries: StreamSource<readonly [R, C, V]>): WithRow<Tp, R, C, V>['normal'];
    /**
     * Returns the collection with the value at given `row` and `column` keys modified according to given `options`.
     * @param row - the row key
     * @param column - the column key
     * @param options - an object containing the following information:<br/>
     * - ifNew: (optional) if the given row-column combination has no value in the collection, this value or function will be used
     * to generate new values. If a function returning the token argument is given, no new entry is created.<br/>
     * - ifExists: (optional) if the row-column combination has a value, this function is called with the current value to
     * return a new value. As a second argument, a `remove` token is given. If the function returns this token, the current
     * entry is removed.
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.modifyAt(2, 5, { ifNew: 8 }).toArray()
     * // => [[1, 2, 3], [1, 4, 5], [2, 5, 8]]
     * t.modifyAt(2, 5, { ifNew: (none) => 1 < 2 ? none : 8 }).toArray()
     * // => [[1, 2, 3], [1, 4, 5]]
     * t.modifyAt(1, 2, { ifExists: (v) => v * 2 }).toArray()
     * // => [[1, 2, 6], [1, 4, 5]]
     * t.modifyAt(1, 2, { ifExists: (v, remove) => remove }).toArray()
     * // => [[1, 4, 5]]
     * ```
     */
    modifyAt(row: R, column: C, options: {
        ifNew?: OptLazyOr<V, Token>;
        ifExists?: ((value: V, remove: Token) => V | Token) | V;
    }): WithRow<Tp, R, C, V>['normal'];
    /**
     * Returns the collection with the value at given `row` and `column` keys updated according
     * to the given `update` function.
     * @param row - the row key
     * @param column - the column key
     * @param update - a function taking the current value and returning a new value
     * @example
     * ```ts
     * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
     * t.updateAt(1, 2, v => v * 2).toArray()
     * // => [[1, 2, 6], [1, 4, 5]]
     * t.updateAt(3, 4, v => v * 2)
     * // => [[1, 2, 3], [1, 4, 5]]
     * ```
     */
    updateAt<UR = R, UC = C>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>, update: Update<V>): WithRow<Tp, R, C, V>['normal'];
    /**
     * Returns a builder object containing the entries of this collection.
     * @example
     * ```ts
     * const builder: HashTableHashColumn.Builder<number, number, number>
     *   = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
     * ```
     */
    toBuilder(): WithRow<Tp, R, C, V>['builder'];
}
export declare namespace TableBase {
    interface NonEmpty<R, C, V, Tp extends TableBase.Types = TableBase.Types> extends VariantTableBase.NonEmpty<R, C, V, Tp>, Omit<TableBase<R, C, V, Tp>, keyof VariantTableBase.NonEmpty<any, any, any>>, Streamable.NonEmpty<[R, C, V]> {
        /**
         * Returns a non-empty Stream containing all entries of this collection as tuples of row key,
         * column key, and value.
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).stream().toArray()
         * // => [[1, 2, 3], [1, 4, 5]]
         * ```
         */
        stream(): Stream.NonEmpty<[R, C, V]>;
        /**
         * Returns the collection with the given `entries` added.
         * @param entries - a `StreamSource containing entries to add
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3])
         * t.addEntries([[1, 4, 5], [2, 6, 8]]).toArray()
         * // => [[1, 2, 3], [1, 4, 5], [2, 6, 8]]
         * ```
         */
        addEntries(entries: StreamSource<readonly [R, C, V]>): WithRow<Tp, R, C, V>['nonEmpty'];
        /**
         * Returns the collection with the value at given `row` and `column` keys updated according
         * to the given `update` function.
         * @param row - the row key
         * @param column - the column key
         * @param update - a function taking the current value and returning a new value
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
         * t.updateAt(1, 2, v => v * 2).toArray()
         * // => [[1, 2, 6], [1, 4, 5]]
         * t.updateAt(3, 4, v => v * 2)
         * // => [[1, 2, 3], [1, 4, 5]]
         * ```
         */
        updateAt<UR = R, UC = C>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>, update: Update<V>): WithRow<Tp, R, C, V>['nonEmpty'];
    }
    interface Factory<Tp extends TableBase.Types, UR = unknown, UC = unknown> {
        /**
         * Returns the (singleton) empty instance of this type and context with given key and value types.
         * @example
         * ```ts
         * HashTableHashColumn.empty<number, string, boolean>()    // => HashTableHashColumn<number, string, boolean>
         * HashTableHashColumn.empty<string, boolean, number>()    // => HashTableHashColumn<string, boolean, number>
         * ```
         */
        empty<R extends UR, C extends UC, V>(): WithRow<Tp, R, C, V>['normal'];
        /**
         * Returns an immutable multimap of this collection type and context, containing the given `entries`.
         * @param entries - a non-empty array of row-column-value entries
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5])    // => HashTableHashColumn.NonEmpty<number, number, number>
         * ```
         */
        of<R extends UR, C extends UC, V>(...entries: ArrayNonEmpty<readonly [R, C, V]>): WithRow<Tp, R, C, V>['nonEmpty'];
        /**
         * Returns an immutable table of this type and context, containing the entries in the given `sources` `StreamSource` instances.
         * @param sources - an array of `StreamSource` instances containing row-column-value entries
         * @example
         * ```ts
         * HashTableHashColumn.from([[1, 2, 3], [1, 4, 5]])    // => HashTableHashColumn.NonEmpty<number, number, number>
         * ```
         */
        from<R extends UR, C extends UC, V>(...sources: ArrayNonEmpty<StreamSource.NonEmpty<readonly [R, C, V]>>): WithRow<Tp, R, C, V>['nonEmpty'];
        from<R extends UR, C extends UC, V>(...sources: ArrayNonEmpty<StreamSource<readonly [R, C, V]>>): WithRow<Tp, R, C, V>['normal'];
        /**
         * Returns an empty builder instance for this type of collection and context.
         * @example
         * ```ts
         * HashTableHashColumn.builder<number, string, boolean>()    // => HashTableHashColumn.Builder<number, string, boolean>
         * ```
         */
        builder<R extends UR, C extends UC, V>(): WithRow<Tp, R, C, V>['builder'];
        /**
         * Returns a `Reducer` that adds received tuples to a Table and returns the Table as a result. When a `source` is given,
         * the reducer will first create a Table from the source, and then add tuples to it.
         * @param source - (optional) an initial source of tuples to add to
         * @example
         * ```ts
         * const someSource = Table.of([1, 'a', true], [2, 'b', false]);
         * const result = Stream.of([1, 'c', true], [3, 'a', false]).reduce(Table.reducer(someSource))
         * result.toArray()   // => [[1, 'c'], [2, 'b'], [3, 'a']]
         * ```
         * @note uses a builder under the hood. If the given `source` is a Table in the same context, it will directly call `.toBuilder()`.
         */
        reducer<R extends UR, C extends UC, V>(source?: StreamSource<readonly [R, C, V]>): Reducer<readonly [R, C, V], WithRow<Tp, R, C, V>['normal']>;
    }
    interface Context<UR, UC, Tp extends TableBase.Types = TableBase.Types> extends TableBase.Factory<Tp, UR, UC> {
        readonly _fixedKeys: readonly [UR, UC];
        /**
         * A string tag defining the specific collection type
         * @example
         * ```ts
         * HashTableHashColumn.defaultContext().typeTag   // => 'HashTableHashColumn'
         * ```
         */
        readonly typeTag: string;
        readonly _types: Tp;
        /**
         * The context used for the internal row map instances.
         */
        readonly rowContext: (Tp & Row<UR, UC, any>)['rowContext'];
        /**
         * The context used for the internal column map instances.
         */
        readonly columnContext: (Tp & Row<UR, UC, any>)['columnContext'];
    }
    interface Builder<R, C, V, Tp extends TableBase.Types = TableBase.Types> {
        /**
         * Returns the amount of entries in the builder.
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5])
         *   .toBuilder()
         *   .size
         * // => 3
         * ```
         */
        readonly size: number;
        /**
         * Returns true if there are no entries in the builder.
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5])
         *   .toBuilder()
         *   .isEmpty
         * // => false
         * ```
         */
        readonly isEmpty: boolean;
        /**
         * Returns the amount of rows in the builder.
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5])
         *   .toBuilder()
         *   .amountRows
         * // => 2
         * ```
         */
        readonly amountRows: number;
        /**
         * Returns the value at given `row` and `column` keys, or the `otherwise` value if no
         * value is present.
         * @param row - the row key
         * @param column - the column key
         * @param otherwise - (default: undefined) the value to return if no value is found
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * t.get(10, 1)     // => undefined
         * t.get(10, 1, 0)  // => 0
         * t.get(1, 2)      // => 3
         * t.get(1, 2, 0)   // => 3
         * ```
         */
        get<UR = R, UC = C>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>): V | undefined;
        get<UR, UC, O>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>, otherwise: OptLazy<O>): V | O;
        /**
         * Returns a map containing the column keys and values in the given `row`.
         * @param row - the row key
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * t.getRow(10).toArray()    // => []
         * t.getRow(1).toArray()     // => [[2, 3], [4, 5]]
         * ```
         */
        getRow<UR = R>(row: RelatedTo<R, UR>): WithRow<Tp, R, C, V>['row'];
        /**
         * Returns true if the builder has a value for given `row` and `column` keys.
         * @param row - the row key
         * @param column - the column key
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * t.hasValueAt(10, 1)    // => false
         * t.hasValueAt(1, 4)     // => true
         * ```
         */
        hasValueAt<UR = R, UC = C>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>): boolean;
        /**
         * Returns true if given `row` key is in the builder.
         * @param row - the row key to look for
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * t.hasRowKey(10)    // => false
         * t.hasRowKey(1)     // => true
         * ```
         */
        hasRowKey<UR = R>(row: RelatedTo<R, UR>): boolean;
        /**
         * Sets the given `value` for the given `row` and `column` keys in the builder.
         * @param row - the row key
         * @param column - the column key
         * @param value - the value to set
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * t.set(1, 2, 3)   // => false
         * t.set(1, 3, 8)   // => true
         * ```
         */
        set(row: R, column: C, value: V): boolean;
        /**
         * Adds the given `entry` to the builder.
         * @param entry - the entry to add
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * t.addEntry([1, 2, 3])   // => false
         * t.addEntry([1, 3, 8])   // => true
         * ```
         */
        addEntry(entry: readonly [R, C, V]): boolean;
        /**
         * Adds the given `entries` to the builder.
         * @param entries - a `StreamSource` containing entries to add.
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * t.addEntries([[1, 2, 3], [1, 2, 3]])  // => false
         * t.addEntries([[1, 2, 3], [2, 3, 4]])  // => true
         * ```
         */
        addEntries(entries: StreamSource<readonly [R, C, V]>): boolean;
        /**
         * Remove the value at given `row` and `column` keys in the builder.
         * @param row - the row key
         * @param column - the column key
         * @param otherwise - (default: undefined) the value to return if no value was found
         * @returns the value previously assigned at given row and column, or the otherwise value
         * if no such value was found
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * t.remove(5, 6)        // => undefined
         * t.remove(5, 6, 'a')   // => 'a'
         * t.remove(1, 2)        // => 3
         * t.remove(1, 4, 'a')   // => 5
         * ```
         */
        remove<UR = R, UC = C>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>): V | undefined;
        remove<UR, UC, O>(row: RelatedTo<R, UR>, column: RelatedTo<C, UC>, otherwise: OptLazy<O>): V | O;
        /**
         * Removes all values in the given `row` from the builder.
         * @param row - the row key
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5]).toBuilder()
         * t.removeRow(5)   // => false
         * t.removeRow(1)   // => true
         * ```
         */
        removeRow<UR = R>(row: RelatedTo<R, UR>): boolean;
        /**
         * Removes all given `rows` from the builder.
         * @param rows - a `StreamSource` containing row keys to remove
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5]).toBuilder()
         * t.removeRows([10, 11])  // => false
         * t.removeRows([1, 10])   // => true
         * ```
         */
        removeRows<UR = R>(rows: StreamSource<RelatedTo<R, UR>>): boolean;
        /**
         * Removes all given `entries` from the builder.
         * @param entries - a `StreamSource` containing entries to remove.
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5]).toBuilder()
         * t.removeEntries([[7, 8, 9], [9, 8, 7]])  // => false
         * t.removeEntries([[7, 8, 9], [1, 2, 3]])  // => true
         * ```
         */
        removeEntries<UR = R, UC = C>(entries: StreamSource<[RelatedTo<R, UR>, RelatedTo<C, UC>]>): boolean;
        /**
         * Performs given function `f` for each entry of the collection, using given `state` as initial traversal state.
         * @param f - the function to perform for each entry, receiving:<br/>
         * - `entry`: the next tuple of a row key, column key, and value<br/>
         * - `index`: the index of the element<br/>
         * - `halt`: a function that, if called, ensures that no new elements are passed
         * @param options - object containing the following<br/>
         * - state: (optional) the traverse state
         * @example
         * ```ts
         * HashTableHashColumn.of([1, 2, 3], [1, 4, 5], [2, 3, 5])
         *   .toBuilder()
         *   .forEach((entry, i, halt) => {
         *     console.log([entry]);
         *     if (i >= 1) halt();
         *   })
         * // => logs [1, 2, 3]  [1, 4, 5]
         * ```
         * @note O(N)
         */
        forEach(f: (entry: [R, C, V], index: number, halt: () => void) => void, options?: {
            state?: TraverseState;
        }): void;
        /**
         * Modifies the value at given `row` and `column` keys according to given `options`.
         * @param row - the row key
         * @param column - the column key
         * @param options - an object containing the following information:<br/>
         * - ifNew: (optional) if the given row-column combination has no value in the collection, this value or function will be used
         * to generate new values. If a function returning the token argument is given, no new entry is created.<br/>
         * - ifExists: (optional) if the row-column combination has a value, this function is called with the current value to
         * return a new value. As a second argument, a `remove` token is given. If the function returns this token, the current
         * entry is removed.
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * t.modifyAt(2, 5, { ifNew: 8 })
         * // => true
         * t.modifyAt(2, 6, { ifNew: (none) => 1 < 2 ? none : 8 })
         * // => false
         * t.modifyAt(1, 2, { ifExists: (v) => v * 2 })
         * // => true
         * t.modifyAt(1, 2, { ifExists: (v, remove) => remove })
         * // => true
         * ```
         */
        modifyAt(row: R, column: C, options: {
            ifNew?: OptLazyOr<V, Token>;
            ifExists?: (currentValue: V, remove: Token) => V | Token | V;
        }): boolean;
        /**
         * Updates the value at given `row` and `column` keys according to the given `update`
         * function.
         * @param row - the row key
         * @param column - the column key
         * @param update - a function taking the current value and returning a new value
         * @param otherwise - (default: undefined) the value to return if no value was found
         * @returns the old value at given `row` and `column` keys, or the `otherwise` value if
         * no value was found.
         * @example
         * ```ts
         * const t = HashTableHashColumn.of([1, 2, 3], [1, 4, 5])
         * t.updateAt(3, 4, v => v * 2)        // => undefined
         * t.updateAt(3, 4, v => v * 2, 'a')   // => 'a'
         * t.updateAt(1, 2, v => v * 2)        // => true
         * t.updateAt(1, 2, v => v * 2, 'a')   // => true
         * ```
         */
        updateAt(row: R, column: C, update: Update<V>): V | undefined;
        updateAt<O>(row: R, column: C, update: Update<V>, otherwise: OptLazy<O>): V | O;
        /**
         * Returns an immutable collection instance containing the entries in this builder.
         * @example
         * ```ts
         * const m = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * const m2: HashTableHashColumn<number, number, number> = m.build()
         * ```
         */
        build(): WithRow<Tp, R, C, V>['normal'];
        /**
         * Returns an immutable collection instance containing the entries in this builder.
         * @param mapFun - a function receiving the `value`, `row` and `column`, and returning a new value
         * @example
         * ```ts
         * const m = HashTableHashColumn.of([1, 2, 3], [1, 4, 5]).toBuilder()
         * const m2: HashTableHashColumn<number, number, boolean> = m.buildMapValues(v => v > 3)
         * ```
         */
        buildMapValues<V2>(mapFun: (value: V, row: R, column: C) => V2): (Tp & Row<R, C, V2>)['normal'];
    }
    /**
     * Utility interface that provides higher-kinded types for this collection.
     */
    interface Types extends VariantTableBase.Types {
        readonly normal: TableBase<this['_R'], this['_C'], this['_V']>;
        readonly nonEmpty: TableBase.NonEmpty<this['_R'], this['_C'], this['_V']>;
        readonly row: RMap<this['_C'], this['_V']>;
        readonly rowNonEmpty: RMap.NonEmpty<this['_C'], this['_V']>;
        readonly rowMap: RMap<this['_R'], RMap.NonEmpty<this['_C'], this['_V']>>;
        readonly rowMapNonEmpty: RMap.NonEmpty<this['_R'], RMap.NonEmpty<this['_C'], this['_V']>>;
        readonly context: TableBase.Context<this['_R'], this['_C']>;
        readonly builder: TableBase.Builder<this['_R'], this['_C'], this['_V']>;
        readonly rowContext: RMap.Context<this['_R']>;
        readonly columnContext: RMap.Context<this['_C']>;
    }
}
