novy-syndicate/src/runtime/bag.ts

78 lines
1.9 KiB
TypeScript

// Bags and Deltas (which are Bags where item-counts can be negative).
import { Value, Set, Dictionary, DefaultPointer } from '@preserves/core';
export enum ChangeDescription {
PRESENT_TO_ABSENT = -1,
ABSENT_TO_ABSENT = 0,
ABSENT_TO_PRESENT = 1,
PRESENT_TO_PRESENT = 2,
}
export class Bag<T extends object = DefaultPointer> {
_items: Dictionary<T, number>;
constructor(s?: Set<T>) {
this._items = new Dictionary();
if (s) s.forEach((v) => this._items.set(v, 1));
}
get(key: Value<T>): number {
return this._items.get(key, 0) as number;
}
change(key: Value<T>, delta: number, clamp: boolean = false): ChangeDescription {
let oldCount = this.get(key);
let newCount = oldCount + delta;
if (clamp) {
newCount = Math.max(0, newCount);
}
if (newCount === 0) {
this._items.delete(key);
return (oldCount === 0)
? ChangeDescription.ABSENT_TO_ABSENT
: ChangeDescription.PRESENT_TO_ABSENT;
} else {
this._items.set(key, newCount);
return (oldCount === 0)
? ChangeDescription.ABSENT_TO_PRESENT
: ChangeDescription.PRESENT_TO_PRESENT;
}
}
clear() {
this._items = new Dictionary();
}
includes(key: Value<T>): boolean {
return this._items.has(key);
}
get size(): number {
return this._items.size;
}
keys(): IterableIterator<Value<T>> {
return this._items.keys();
}
entries(): IterableIterator<[Value<T>, number]> {
return this._items.entries();
}
forEach(f: (count: number, value: Value<T>) => void) {
this._items.forEach(f);
}
snapshot(): Dictionary<T, number> {
return this._items.clone();
}
clone(): Bag<T> {
const b = new Bag<T>();
b._items = this._items.clone();
return b;
}
}