import { Event } from "@hmans/event";
import { Predicate } from "./types";
export declare type BucketOptions<E> = {
    entities?: E[];
};
/**
 * A bucket is a collection of entities. Entities can be added, removed, and
 * touched; the bucket exposes events for each of these operations.
 */
export declare class Bucket<E> {
    [Symbol.iterator](): {
        next: () => {
            value: E;
            done: boolean;
        };
    };
    constructor({ entities }?: BucketOptions<E>);
    /** The entities in the bucket. */
    entities: E[];
    /**
     * An internal map of entities to their positions in the `entities` array.
     * This is used to quickly find the position of an entity in the array.
     */
    private entityPositions;
    /**
     * The event that is emitted when an entity is added to this bucket.
     */
    onEntityAdded: Event<E>;
    /**
     * The event that is emitted when an entity is removed from this bucket.
     */
    onEntityRemoved: Event<E>;
    /**
     * The event that is emitted when an entity is touched in this bucket.
     */
    onEntityTouched: Event<E>;
    /**
     * The event that is emitted when the bucket is cleared.
     */
    onCleared: Event<void>;
    /**
     * The event that is emitted when the bucket is being disposed.
     */
    onDisposed: Event<void>;
    /**
     * A cache of derived buckets. This is used to ensure that we don't create
     * multiple derived buckets for the same predicate.
     */
    derivedBuckets: Map<any, any>;
    /**
     * Returns the size of this bucket (the number of entities it contains).
     */
    get size(): number;
    /**
     * Returns true if this bucket is currently tracking the given entity.
     *
     * @param entity The entity to check for.
     * @returns True if the entity is being tracked.
     */
    has(entity: E): boolean;
    /**
     * Adds the entity to this bucket. If the entity is already in the bucket, it
     * does nothing.
     *
     * @param entity The entity to add.
     * @returns The entity that was added.
     */
    add<D extends E>(entity: D): E & D;
    /**
     * Touches the entity, signaling this bucket that the entity was updated, and should
     * be re-evaluated by any buckets derived from this one.
     *
     * @param entity The entity to touch.
     * @returns The entity that was touched.
     */
    touch(entity: E): E;
    /**
     * Removes the entity from this bucket. If the entity is not in the bucket,
     * it does nothing.
     *
     * @param entity The entity to remove.
     * @returns The entity that was removed.
     */
    remove(entity: E): E;
    /**
     * Removes all entities from this bucket. This will emit the `onEntityRemoved` event
     * for each entity, giving derived buckets a chance to remove the entity as well.
     */
    clear(): void;
    /**
     * Dispose of this bucket. This will remove all entities from the bucket, dispose of all
     * known derived buckets, and clear all event listeners.
     */
    dispose(): void;
    /**
     * Create a new bucket derived from this bucket. The derived bucket will contain
     * only entities that match the given predicate, and will be updated reactively
     * as entities are added, removed, or touched.
     *
     * @param predicate The predicate to use to filter entities.
     * @returns The new derived bucket.
     */
    derive<D extends E = E>(predicate?: Predicate<E, D> | ((entity: E) => boolean)): Bucket<D>;
}
