import type { RMap, VariantMap } from '@rimbu/collection-types/map';
import type { Elem, WithElem } from '@rimbu/collection-types/map-custom';
import type { ArrayNonEmpty, RelatedTo, ToJSON, TraverseState } from '@rimbu/common';
import type { FastIterable, Reducer, Stream, StreamSource, Streamable } from '@rimbu/stream';
export interface VariantMultiSetBase<T, Tp extends VariantMultiSetBase.Types = VariantMultiSetBase.Types> extends FastIterable<T> {
    /**
     * Returns true if the collection is empty.
     * @example
     * ```ts
     * HashMultiSet.empty<number>().isEmpty     // => true
     * HashMultiSet.of(1, 2, 2).isEmpty         // => false
     * ```
     */
    readonly isEmpty: boolean;
    /**
     * Returns the number of values in the collection.
     * @example
     * ```ts
     * HashMultiSet.of(1, 2).size         // => 2
     * HashMultiSet.of(1, 2, 2).size      // => 3
     * ```
     */
    readonly size: number;
    /**
     * Returns the number of distinct values in the collection.
     * @example
     * ```ts
     * HashMultiSet.of(1, 2).sizeDistinct       // => 2
     * HashMultiSet.of(1, 2, 2).sizeDistinct    // => 2
     * ```
     */
    readonly sizeDistinct: number;
    /**
     * Returns the Map representation of this collection.
     * @example
     * ```ts
     * const m = HashMultiSet.of(1, 2, 2)
     * const map: HashMap.NonEmpty<number, number> = m.countMap
     * ```
     */
    readonly countMap: WithElem<Tp, T>['countMap'];
    /**
     * 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: HashMultiSet<number> = HashMultiSet.of(1, 2, 2)
     * 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 WithElem<Tp, T>['nonEmpty'];
    /**
     * Returns the collection as a .NonEmpty type
     * @throws RimbuError.EmptyCollectionAssumedNonEmptyError if the collection is empty
     * @example
     * ```ts
     * HashMultiSet.empty<number>().assumeNonEmpty()   // => throws
     * const m: HashMultiSet<number> = HashMultiSet.of(1, 2)
     * const m2: HashMultiSet.NonEmpty<number> = m     // => compiler error
     * const m3: HashMultiSet.NonEmpty<number> = m.assumeNonEmpty()
     * ```
     * @note returns reference to this collection
     */
    assumeNonEmpty(): WithElem<Tp, T>['nonEmpty'];
    /**
     * Returns a Stream containing all values of this collection.
     * @example
     * ```ts
     * HashMultiSet.of(1, 2, 2).stream().toArray()  // => [1, 2, 2]
     * ```
     */
    stream(): Stream<T>;
    /**
     * Returns a Stream containing all distinct values of this collection.
     * @example
     * ```ts
     * HashMultiSet.of(1, 2, 2).stream().toArray()  // => [1, 2]
     * ```
     */
    streamDistinct(): Stream<T>;
    /**
     * Returns the collection where the given `amount` (default: 'ALL') of the given `value`
     * are removed.
     * @param value - the value to remove
     * @param options - (optional) an object containing the following properties:<br/>
     * - amount: (default: 'ALL') the amount of values to remove, or 'ALL' to remove all values.
     * @example
     * ```ts
     * const m = HashMultiSet.of(1, 2, 2)
     * m.remove(5).toArray()     // => [1, 2, 2]
     * m.remove(2).toArray()     // => [1]
     * m.remove(2, 1).toArray()  // => [1, 2]
     * ```
     */
    remove<U = T>(value: RelatedTo<T, U>, options?: {
        amount?: number | 'ALL';
    }): WithElem<Tp, T>['normal'];
    /**
     * Returns the collection where every single value from given `values` `StreamSource` is
     * removed.
     * @param values - a `StreamSource` containing values to remove.
     * @example
     * ```ts
     * const m = HashMultiSet.of(1, 2, 2)
     * m.removeAllSingle([5, 6]).toArray()    // => [1, 2, 2]
     * m.removeAllSingle([2, 3]).toArray()    // => [1, 2]
     * m.removeAllSingle([2, 3, 2]).toArray() // => [1]
     * ```
     */
    removeAllSingle<U = T>(values: StreamSource<RelatedTo<T, U>>): WithElem<Tp, T>['normal'];
    /**
     * Returns the collection where for every value from given `values` `StreamSource`,
     * all values in the collection are removed.
     * @param values - a `StreamSource` containing values to remove.
     * @example
     * ```ts
     * const m = HashMultiSet.of(1, 2, 2)
     * m.removeAllEvery([5, 6]).toArray()    // => [1, 2, 2]
     * m.removeAllEvery([2, 3]).toArray()    // => [1]
     * ```
     */
    removeAllEvery<U = T>(values: StreamSource<RelatedTo<T, U>>): WithElem<Tp, T>['normal'];
    /**
     * Returns true if the given `value` exists in the collection.
     * @param value - the value to look for
     * @example
     * ```ts
     * const m = HashMultiSet.of(1, 2, 2)
     * m.has(5)   // => false
     * m.has(2)   // => true
     * ```
     */
    has<U = T>(value: RelatedTo<T, U>): boolean;
    /**
     * Returns the amount of occurrances of the given `value` in the collection.
     * @param value - the value to look for
     * @example
     * ```ts
     * const m = HashMultiSet.of(1, 2, 2)
     * m.count(5)   // => 0
     * m.count(2)   // => 2
     * ```
     */
    count<U = T>(value: RelatedTo<T, U>): number;
    /**
     * Performs given function `f` for each value of the collection, using given `state` as initial traversal state.
     * @param f - the function to perform for each value, receiving:<br/>
     * - `value`: the next value<br/>
     * - `index`: the index of the value<br/>
     * - `halt`: a function that, if called, ensures that no new values are passed
     * @param options - (optional) an object containing the following properties:<br/>
     * - state: (optional) the traversal state
     * @example
     * ```ts
     * HashMultiSet.of(1, 2, 2, 3).forEach((entry, i, halt) => {
     *   console.log(entry)
     *   if (i >= 1) halt()
     * })
     * // => logs [1, 1]  [2, 2]
     * ```
     */
    forEach(f: (value: T, index: number, halt: () => void) => void, options?: {
        state?: TraverseState;
    }): void;
    /**
     * Returns the collection containing only those values for which the given `pred` function returns true.
     * @param pred - a predicate function receiving:<br/>
     * - `entry`: the next entry consisting of the value and its count<br/>
     * - `index`: the entry index<br/>
     * - `halt`: a function that, when called, ensures no next entries are passed
     * @param options - (optional) an object containing the following properties:<br/>
     * - negate: (default: false) when true will negate the predicate
     * @note if the predicate is a type guard, the return type is automatically inferred
     * @example
     * ```ts
     * HashMultiSet.of(1, 2, 2, 3)
     *   .filterEntries(entry => entry[1] > 1)
     *   .toArray()
     * // => [[2, 2]]
     * ```
     */
    filterEntries<TF extends T>(pred: (entry: readonly [T, number], index: number) => entry is [TF, number], options?: {
        negate?: false | undefined;
    }): WithElem<Tp, TF>['normal'];
    filterEntries<TF extends T>(pred: (entry: readonly [T, number], index: number) => entry is [TF, number], options: {
        negate: true;
    }): WithElem<Tp, Exclude<T, TF>>['normal'];
    filterEntries(pred: (entry: readonly [T, number], index: number) => boolean, options?: {
        negate?: boolean;
    }): WithElem<Tp, T>['normal'];
    /**
     * Returns an array containing all values in this collection.
     * @example
     * ```ts
     * HashMultiSet.of(1, 2, 2).toArray()  // => [1, 2, 2]
     * ```
     * @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(): T[];
    /**
     * Returns a string representation of this collection.
     * @example
     * ```ts
     * HashMultiSet.of(1, 2, 2).toString()  // => HashMultiSet(1, 2, 2)
     * ```
     */
    toString(): string;
    /**
     * Returns a JSON representation of this collection.
     * @example
     * ```ts
     * HashMultiSet.of(1, 2, 2).toJSON()   // => { dataType: 'HashMultiSet', value: [[1, 1], [2, 2]] }
     * ```
     */
    toJSON(): ToJSON<(readonly [T, number])[]>;
}
export declare namespace VariantMultiSetBase {
    interface NonEmpty<T, Tp extends VariantMultiSetBase.Types = VariantMultiSetBase.Types> extends VariantMultiSetBase<T, Tp>, Streamable.NonEmpty<T> {
        /**
         * Returns false since this collection is known to be non-empty
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2).isEmpty         // => false
         * ```
         */
        readonly isEmpty: false;
        /**
         * Returns the Map representation of this collection.
         * @example
         * ```ts
         * const m = HashMultiMapHashValue.of([1, 1], [2, 2])
         * const map: HashMap.NonEmpty<number, HashSet.NonEmpty<number>> = m.countMap
         * ```
         */
        readonly countMap: WithElem<Tp, T>['countMapNonEmpty'];
        /**
         * Returns true since this collection is known to be non-empty
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2).nonEmpty()   // => true
         * ```
         */
        nonEmpty(): this is WithElem<Tp, T>['nonEmpty'];
        /**
         * Returns this collection typed as a 'possibly empty' collection.
         * @example
         * ```ts
         * HashMultiSet.of(1, 2).asNormal();  // type: HashMultiSet<number>
         * ```
         */
        asNormal(): WithElem<Tp, T>['normal'];
        /**
         * Returns a non-empty Stream containing all values of this collection.
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2).stream().toArray()  // => [1, 2, 2]
         * ```
         */
        stream(): Stream.NonEmpty<T>;
        /**
         * Returns a non-empty Stream containing all distinct values of this collection.
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2).stream().toArray()  // => [1, 2]
         * ```
         */
        streamDistinct(): Stream.NonEmpty<T>;
        /**
         * Returns a non-empty array containing all values in this collection.
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2).toArray()  // => [1, 2, 2]
         * ```
         * @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<T>;
    }
    /**
     * Utility interface that provides higher-kinded types for this collection.
     */
    interface Types extends Elem {
        readonly normal: VariantMultiSetBase<this['_T']>;
        readonly nonEmpty: VariantMultiSetBase.NonEmpty<this['_T']>;
        readonly countMap: VariantMap<this['_T'], number>;
        readonly countMapNonEmpty: VariantMap.NonEmpty<this['_T'], number>;
    }
}
export interface MultiSetBase<T, Tp extends MultiSetBase.Types = MultiSetBase.Types> extends VariantMultiSetBase<T, Tp> {
    /**
     * Returns the `context` associated to this collection instance.
     */
    readonly context: WithElem<Tp, T>['context'];
    /**
     * Returns the collection with the given `value` added `amount` times.
     * @param value - the value to add
     * @param amount - (default: 1) the amount of values to add
     * @example
     * ```ts
     * HashMultiSet.of(1, 2).add(2).toArray()      // => [1, 2, 2]
     * HashMultiSet.of(1, 2).add(3, 2).toArray()   // => [1, 2, 3, 3]
     * ```
     * @note amount < 0 will be normalized to 0
     */
    add(value: T): WithElem<Tp, T>['nonEmpty'];
    add(value: T, amount: number): WithElem<Tp, T>['normal'];
    /**
     * Returns the collection with the values in `values` added.
     * @param values - a `StreamSource` containing values to add
     * @example
     * ```ts
     * HashMultiSet.of(1, 2).addAll([2, 3]).toArray()   // => [1, 2, 2, 3]
     * ```
     */
    addAll(values: StreamSource.NonEmpty<T>): WithElem<Tp, T>['nonEmpty'];
    addAll(values: StreamSource<T>): WithElem<Tp, T>['normal'];
    /**
     * Returns the collection where for every entry in `entries` consisting of a tuple
     * of a value and an amount, that value is added `amount` times.
     * @param entries - a `StreamSource` containing tuples that contain a value and an amount
     * @example
     * ```ts
     * HashMultiSet.of(1, 2).addEntries([[2, 2], [3, 2]]).toArray()
     * // => [1, 2, 2, 2, 3, 3]
     * ```
     */
    addEntries(entries: StreamSource<readonly [T, number]>): WithElem<Tp, T>['normal'];
    /**
     * Returns the collection where the amount of values of `value` if set to `amount`.
     * @param value - the value of which to set the amount
     * @param amount - the new amount of values
     *
     * @note if amount <= 0, the value will be removed
     * @example
     * ```ts
     * const m = HashMultiSet.of(1, 2, 2)
     * m.setCount(1, 2).toArray()    // => [1, 1, 2, 2]
     * m.setCount(2, 0).toArray()    // => [1]
     * ```
     */
    setCount(value: T, amount: number): WithElem<Tp, T>['normal'];
    /**
     * Returns the collection where the count of the given `value` is modified according to
     * the given `update` function.
     * @param value - the value of which to modify the count
     * @param update - a function taking the current count and returning a new count.
     *
     * @note if the given `value` does not exists, the `update` function is called with 0.
     * @note if the result of `update` is <= 0, the value will be removed (or not added)
     * @example
     * ```ts
     * const m = HashMultiSet.of(1, 2, 2)
     * m.modifyCount(1, v => v + 1).toArray()   // => [1, 1, 2, 2]
     * m.modifyCount(3, v => v + 1).toArray()   // => [1, 2, 2, 3]
     * ```
     */
    modifyCount(value: T, update: (currentCount: number) => number): WithElem<Tp, T>['normal'];
    /**
     * Returns a builder object containing the entries of this collection.
     * @example
     * ```ts
     * const builder: HashMultiSet.Builder<number>
     *   = HashMultiSet.of(1, 2, 2).toBuilder()
     * ```
     */
    toBuilder(): WithElem<Tp, T>['builder'];
}
export declare namespace MultiSetBase {
    interface NonEmpty<T, Tp extends MultiSetBase.Types = MultiSetBase.Types> extends VariantMultiSetBase.NonEmpty<T, Tp>, Omit<MultiSetBase<T, Tp>, keyof VariantMultiSetBase.NonEmpty<any, any>>, Streamable.NonEmpty<T> {
        /**
         * Returns a non-empty Stream containing all values of this collection.
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2).stream().toArray()  // => [1, 2, 2]
         * ```
         */
        stream(): Stream.NonEmpty<T>;
        /**
         * Returns the collection with the given `value` added `amount` times.
         * @param value - the value to add
         * @param amount - (default: 1) the amount of values to add
         * @example
         * ```ts
         * HashMultiSet.of(1, 2).add(2).toArray()      // => [1, 2, 2]
         * HashMultiSet.of(1, 2).add(3, 2).toArray()   // => [1, 2, 3, 3]
         * ```
         * @note amount < 0 will be normalized to 0
         */
        add(value: T, amount?: number): WithElem<Tp, T>['nonEmpty'];
        /**
         * Returns the collection with the values in `values` added.
         * @param values - a `StreamSource` containing values to add
         * @example
         * ```ts
         * HashMultiSet.of(1, 2).addAll([2, 3]).toArray()   // => [1, 2, 2, 3]
         * ```
         */
        addAll(values: StreamSource<T>): WithElem<Tp, T>['nonEmpty'];
        /**
         * Returns the collection where for every entry in `entries` consisting of a tuple
         * of a value and an amount, that value is added `amount` times.
         * @param entries - a `StreamSource` containing tuples that contain a value and an amount
         * @example
         * ```ts
         * HashMultiSet.of(1, 2).addEntries([[2, 2], [3, 2]]).toArray()
         * // => [1, 2, 2, 2, 3, 3]
         * ```
         */
        addEntries(entries: StreamSource<readonly [T, number]>): WithElem<Tp, T>['nonEmpty'];
    }
    interface Factory<Tp extends MultiSetBase.Types, UT = unknown> {
        /**
         * Returns the (singleton) empty instance of this type and context with given key and value types.
         * @example
         * ```ts
         * HashMultiSet.empty<number>()    // => HashMultiSet<number>
         * HashMultiSet.empty<string>()    // => HashMultiSet<string>
         * ```
         */
        empty<T extends UT>(): WithElem<Tp, T>['normal'];
        /**
         * Returns an immutable multimap of this collection type and context, containing the given `values`.
         * @param values - a non-empty array of vslues
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2)    // => HashMultiSet.NonEmpty<number>
         * ```
         */
        of<T extends UT>(...values: ArrayNonEmpty<T>): WithElem<Tp, T>['nonEmpty'];
        /**
         * Returns an immutable multimap of this type and context, containing the values in the given `sources`
         * `StreamSource`.
         * @param sources - a non-empty array of `StreamSource` instances containing values to add
         * @example
         * ```ts
         * HashMultiSet.from([1, 2], [2, 3, 4]).toArray()    // => [1, 2, 2, 3, 4]
         * ```
         */
        from<T extends UT>(...sources: ArrayNonEmpty<StreamSource.NonEmpty<T>>): WithElem<Tp, T>['nonEmpty'];
        from<T extends UT>(...sources: ArrayNonEmpty<StreamSource<T>>): WithElem<Tp, T>['normal'];
        /**
         * Returns an empty builder instance for this type of collection and context.
         * @example
         * ```ts
         * HashMultiSet.builder<number>()    // => HashMultiSet.Builder<number>
         * ```
         */
        builder<T extends UT>(): WithElem<Tp, T>['builder'];
        /**
         * Returns a `Reducer` that appends received items to a MultiSet and returns the MultiSet as a result. When a `source` is given,
         * the reducer will first create a MultiSet from the source, and then add elements to it.
         * @param source - (optional) an initial source of elements to add to
         * @example
         * ```ts
         * const someList = [1, 2, 3];
         * const result = Stream.range({ start: 20, amount: 5 }).reduce(SortedMultiSet.reducer(someList))
         * result.toArray()   // => [1, 2, 3, 20, 21, 22, 23, 24]
         * ```
         * @note uses a MultiSet builder under the hood. If the given `source` is a MultiSet in the same context, it will directly call `.toBuilder()`.
         */
        reducer<T extends UT>(source?: StreamSource<T>): Reducer<T, WithElem<Tp, T>['normal']>;
    }
    interface Context<UT, Tp extends MultiSetBase.Types = MultiSetBase.Types> extends MultiSetBase.Factory<Tp, UT> {
        /**
         * A string tag defining the specific collection type
         * @example
         * ```ts
         * HashMultiSet.defaultContext().typeTag   // => 'HashMultiSet'
         * ```
         */
        readonly typeTag: string;
        readonly _types: Tp;
        /**
         * The context used for the internal countMap instances.
         */
        readonly countMapContext: WithElem<Tp, UT>['countMapContext'];
        /**
         * Returns true if given `obj` could be a valid key in this Context.
         * @param obj - the object to check
         * @example
         * ```ts
         * HashMultiSet.defaultContext().isValidKey(1)   // => true
         * ```
         */
        isValidElem(key: any): key is UT;
    }
    interface Builder<T, Tp extends MultiSetBase.Types = MultiSetBase.Types> {
        /**
         * Returns the amount of values in the builder.
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2).toBuilder().size
         * // => 3
         * ```
         */
        readonly size: number;
        /**
         * Returns the amount of distinct values in the builder.
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2).toBuilder().sizeDistinct
         * // => 2
         * ```
         */
        readonly sizeDistinct: number;
        /**
         * Returns true if there are no values in the builder.
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2).toBuilder().isEmpty
         * // => false
         * ```
         */
        readonly isEmpty: boolean;
        /**
         * Returns true if the given `value` is present in the builder.
         * @param value - the value to look for
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.has(2)   // => true
         * s.has(10)  // => false
         * ```
         */
        has<U = T>(value: RelatedTo<T, U>): boolean;
        /**
         * Adds given `value` to the builder.
         * @param value - the value to add
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.add(2)     // => true
         * s.add(3, 5)  // => true
         * s.add(3, 0)  // => false
         * ```
         */
        add(value: T, amount?: number): boolean;
        /**
         * Adds the values in given `values` `StreamSource` to the builder.
         * @param values - the values to add
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.addAll(1, 3)   // => false
         * s.addAll(2, 10)  // => true
         * ```
         */
        addAll(values: StreamSource<T>): boolean;
        /**
         * Adds for each tuple of a value and amount in the given `entries`, the amount of values
         * to the builder.
         * @param entries - a `StreamSource` containing tuples of a value and amount
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.addEntries([[1, 2], [2, 3]])   // => true
         * s.addEntries([[1, 0], [3, 0]])   // => false
         * ```
         */
        addEntries(entries: StreamSource<readonly [T, number]>): boolean;
        /**
         * Removes given `amount` or all of given `value` from the builder.
         * @param value - the value to remove
         * @param amount - (default: 'ALL') the amount of values to remove
         * @returns the amount of elements that are removed
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.remove(10)    // => 0
         * s.remove(1, 2)  // => 1
         * s.remove(2, 2)  // => 2
         * ```
         */
        remove<U = T>(value: RelatedTo<T, U>, amount?: number | 'ALL'): number;
        /**
         * Removes every single value in given `values` from the builder.
         * @param values - a `StreamSource` of values to remove.
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.removeAllSingle([10, 11])   // => false
         * s.removeAllSingle([1, 11])    // => true
         * ```
         */
        removeAllSingle<U = T>(values: StreamSource<RelatedTo<T, U>>): boolean;
        /**
         * Removes every instance of the given `values` from the builder.
         * @param values - a `StreamSource` of values to remove.
         * @returns true if the data in the builder has changed
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.removeAllEvery([10, 11])   // => false
         * s.removeAllEvery([1, 11])    // => true
         * ```
         */
        removeAllEvery<U = T>(values: StreamSource<RelatedTo<T, U>>): boolean;
        /**
         * Sets the amount of given `value` in the collection to `amount`.
         * @param value - the value for which to set the amount
         * @param amount - the amount of values
         * @returns true if the data in the builder has changed
         * @note if amount <= 0, the value will be removed
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.setCount(1, 1)    // => false
         * s.setCount(1, 3)    // => true
         * ```
         */
        setCount(value: T, amount: number): boolean;
        /**
         * Changes the amount of given `value` in the builder according to the result of given `update`
         * function.
         * @param value - the value of which to update the amount
         * @param update - a function taking the current count and returning a new count.
         * @returns true if the data in the builder has changed
         *
         * @note if the given `value` does not exists, the `update` function is called with 0.
         * @note if the result of `update` is <= 0, the value will be removed (or not added)
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.modifyCount(3, v => v)      // => false
         * s.modifyCount(3, v => v + 1)  // => true
         * s.modifyCount(2, v => v + 1)  // => true
         * ```
         */
        modifyCount(value: T, update: (currentCount: number) => number): boolean;
        /**
         * Returns the amount of given `value` in the builder.
         * @param value - the value to look for
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * s.count(10)    // => 0
         * s.count(2)     // => 2
         * ```
         */
        count<U = T>(value: RelatedTo<T, U>): number;
        /**
         * Performs given function `f` for each value of the collection, using given `state` as initial traversal state.
         * @param f - the function to perform for each value, receiving:<br/>
         * - `value`: the next value<br/>
         * - `index`: the index of the value<br/>
         * - `halt`: a function that, if called, ensures that no new values are passed
         * @param options - (optional) an object containing the following properties:<br/>
         * - state: (optional) the traversal state
         * @throws RibuError.ModifiedBuilderWhileLoopingOverItError if the builder is modified while
         * looping over it
         * @example
         * ```ts
         * HashMultiSet.of(1, 2, 2, 3).toBuilder().forEach((entry, i, halt) => {
         *   console.log(entry)
         *   if (i >= 1) halt()
         * })
         * // => logs [1, 1]  [2, 2]
         * ```
         */
        forEach(f: (value: T, index: number, halt: () => void) => void, options?: {
            state?: TraverseState;
        }): void;
        /**
         * Returns an immutable instance containing the values in this builder.
         * @example
         * ```ts
         * const s = HashMultiSet.of(1, 2, 2).toBuilder()
         * const s2: HashMultiSet<number> = m.build()
         * ```
         */
        build(): WithElem<Tp, T>['normal'];
    }
    /**
     * Utility interface that provides higher-kinded types for this collection.
     */
    interface Types extends VariantMultiSetBase.Types {
        readonly normal: MultiSetBase<this['_T']>;
        readonly nonEmpty: MultiSetBase.NonEmpty<this['_T']>;
        readonly context: MultiSetBase.Context<this['_T']>;
        readonly builder: MultiSetBase.Builder<this['_T']>;
        readonly countMap: RMap<this['_T'], number>;
        readonly countMapNonEmpty: RMap.NonEmpty<this['_T'], number>;
        readonly countMapContext: RMap.Context<this['_T']>;
    }
}
