123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- "use strict";
- const SortableSet = require("./SortableSet");
- class LazyBucketSortedSet {
-
- constructor(getKey, comparator, ...args) {
- this._getKey = getKey;
- this._innerArgs = args;
- this._leaf = args.length <= 1;
- this._keys = new SortableSet(undefined, comparator);
-
- this._map = new Map();
- this._unsortedItems = new Set();
- this.size = 0;
- }
-
- add(item) {
- this.size++;
- this._unsortedItems.add(item);
- }
-
- _addInternal(key, item) {
- let entry = this._map.get(key);
- if (entry === undefined) {
- entry = this._leaf
- ? new SortableSet(undefined, this._innerArgs[0])
- : new (LazyBucketSortedSet)(...this._innerArgs);
- this._keys.add(key);
- this._map.set(key, entry);
- }
- entry.add(item);
- }
-
- delete(item) {
- this.size--;
- if (this._unsortedItems.has(item)) {
- this._unsortedItems.delete(item);
- return;
- }
- const key = this._getKey(item);
- const entry = this._map.get(key);
- entry.delete(item);
- if (entry.size === 0) {
- this._deleteKey(key);
- }
- }
-
- _deleteKey(key) {
- this._keys.delete(key);
- this._map.delete(key);
- }
-
- popFirst() {
- if (this.size === 0) return undefined;
- this.size--;
- if (this._unsortedItems.size > 0) {
- for (const item of this._unsortedItems) {
- const key = this._getKey(item);
- this._addInternal(key, item);
- }
- this._unsortedItems.clear();
- }
- this._keys.sort();
- const key = this._keys.values().next().value;
- const entry = this._map.get(key);
- if (this._leaf) {
- const leafEntry = (entry);
- leafEntry.sort();
- const item = leafEntry.values().next().value;
- leafEntry.delete(item);
- if (leafEntry.size === 0) {
- this._deleteKey(key);
- }
- return item;
- } else {
- const nodeEntry = (entry);
- const item = nodeEntry.popFirst();
- if (nodeEntry.size === 0) {
- this._deleteKey(key);
- }
- return item;
- }
- }
-
- startUpdate(item) {
- if (this._unsortedItems.has(item)) {
- return remove => {
- if (remove) {
- this._unsortedItems.delete(item);
- this.size--;
- return;
- }
- };
- }
- const key = this._getKey(item);
- if (this._leaf) {
- const oldEntry = (this._map.get(key));
- return remove => {
- if (remove) {
- this.size--;
- oldEntry.delete(item);
- if (oldEntry.size === 0) {
- this._deleteKey(key);
- }
- return;
- }
- const newKey = this._getKey(item);
- if (key === newKey) {
-
- oldEntry.add(item);
- } else {
- oldEntry.delete(item);
- if (oldEntry.size === 0) {
- this._deleteKey(key);
- }
- this._addInternal(newKey, item);
- }
- };
- } else {
- const oldEntry = (this._map.get(
- key
- ));
- const finishUpdate = oldEntry.startUpdate(item);
- return remove => {
- if (remove) {
- this.size--;
- finishUpdate(true);
- if (oldEntry.size === 0) {
- this._deleteKey(key);
- }
- return;
- }
- const newKey = this._getKey(item);
- if (key === newKey) {
- finishUpdate();
- } else {
- finishUpdate(true);
- if (oldEntry.size === 0) {
- this._deleteKey(key);
- }
- this._addInternal(newKey, item);
- }
- };
- }
- }
-
- _appendIterators(iterators) {
- if (this._unsortedItems.size > 0)
- iterators.push(this._unsortedItems[Symbol.iterator]());
- for (const key of this._keys) {
- const entry = this._map.get(key);
- if (this._leaf) {
- const leafEntry = (entry);
- const iterator = leafEntry[Symbol.iterator]();
- iterators.push(iterator);
- } else {
- const nodeEntry = (entry);
- nodeEntry._appendIterators(iterators);
- }
- }
- }
-
- [Symbol.iterator]() {
- const iterators = [];
- this._appendIterators(iterators);
- iterators.reverse();
- let currentIterator = iterators.pop();
- return {
- next: () => {
- const res = currentIterator.next();
- if (res.done) {
- if (iterators.length === 0) return res;
- currentIterator = iterators.pop();
- return currentIterator.next();
- }
- return res;
- }
- };
- }
- }
- module.exports = LazyBucketSortedSet;
|