source: imaps-frontend/node_modules/webpack/lib/util/LazyBucketSortedSet.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 5.9 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { first } = require("./SetHelpers");
9const SortableSet = require("./SortableSet");
10
11/**
12 * @template T
13 * @typedef {LazyBucketSortedSet<T, any> | SortableSet<T>} Entry
14 */
15
16/**
17 * @template T
18 * @typedef {(function(T): any) | (function(any, any): number)} Arg
19 */
20
21/**
22 * Multi layer bucket sorted set:
23 * Supports adding non-existing items (DO NOT ADD ITEM TWICE),
24 * Supports removing exiting items (DO NOT REMOVE ITEM NOT IN SET),
25 * Supports popping the first items according to defined order,
26 * Supports iterating all items without order,
27 * Supports updating an item in an efficient way,
28 * Supports size property, which is the number of items,
29 * Items are lazy partially sorted when needed
30 * @template T
31 * @template K
32 */
33class LazyBucketSortedSet {
34 /**
35 * @param {function(T): K} getKey function to get key from item
36 * @param {function(K, K): number} comparator comparator to sort keys
37 * @param {...Arg<T>} args more pairs of getKey and comparator plus optional final comparator for the last layer
38 */
39 constructor(getKey, comparator, ...args) {
40 this._getKey = getKey;
41 /** @type {Arg<T>[]} */
42 this._innerArgs = args;
43 this._leaf = args.length <= 1;
44 this._keys = new SortableSet(undefined, comparator);
45 /** @type {Map<K, Entry<T>>} */
46 this._map = new Map();
47 this._unsortedItems = new Set();
48 this.size = 0;
49 }
50
51 /**
52 * @param {T} item an item
53 * @returns {void}
54 */
55 add(item) {
56 this.size++;
57 this._unsortedItems.add(item);
58 }
59
60 /**
61 * @param {K} key key of item
62 * @param {T} item the item
63 * @returns {void}
64 */
65 _addInternal(key, item) {
66 let entry = this._map.get(key);
67 if (entry === undefined) {
68 entry =
69 /** @type {Entry<T>} */
70 (
71 this._leaf
72 ? new SortableSet(undefined, this._innerArgs[0])
73 : new /** @type {TODO} */ (LazyBucketSortedSet)(...this._innerArgs)
74 );
75 this._keys.add(key);
76 this._map.set(key, entry);
77 }
78 /** @type {Entry<T>} */
79 (entry).add(item);
80 }
81
82 /**
83 * @param {T} item an item
84 * @returns {void}
85 */
86 delete(item) {
87 this.size--;
88 if (this._unsortedItems.has(item)) {
89 this._unsortedItems.delete(item);
90 return;
91 }
92 const key = this._getKey(item);
93 const entry = /** @type {Entry<T>} */ (this._map.get(key));
94 entry.delete(item);
95 if (entry.size === 0) {
96 this._deleteKey(key);
97 }
98 }
99
100 /**
101 * @param {K} key key to be removed
102 * @returns {void}
103 */
104 _deleteKey(key) {
105 this._keys.delete(key);
106 this._map.delete(key);
107 }
108
109 /**
110 * @returns {T | undefined} an item
111 */
112 popFirst() {
113 if (this.size === 0) return;
114 this.size--;
115 if (this._unsortedItems.size > 0) {
116 for (const item of this._unsortedItems) {
117 const key = this._getKey(item);
118 this._addInternal(key, item);
119 }
120 this._unsortedItems.clear();
121 }
122 this._keys.sort();
123 const key = /** @type {K} */ (first(this._keys));
124 const entry = this._map.get(key);
125 if (this._leaf) {
126 const leafEntry = /** @type {SortableSet<T>} */ (entry);
127 leafEntry.sort();
128 const item = /** @type {T} */ (first(leafEntry));
129 leafEntry.delete(item);
130 if (leafEntry.size === 0) {
131 this._deleteKey(key);
132 }
133 return item;
134 }
135 const nodeEntry = /** @type {LazyBucketSortedSet<T, any>} */ (entry);
136 const item = nodeEntry.popFirst();
137 if (nodeEntry.size === 0) {
138 this._deleteKey(key);
139 }
140 return item;
141 }
142
143 /**
144 * @param {T} item to be updated item
145 * @returns {function(true=): void} finish update
146 */
147 startUpdate(item) {
148 if (this._unsortedItems.has(item)) {
149 return remove => {
150 if (remove) {
151 this._unsortedItems.delete(item);
152 this.size--;
153 }
154 };
155 }
156 const key = this._getKey(item);
157 if (this._leaf) {
158 const oldEntry = /** @type {SortableSet<T>} */ (this._map.get(key));
159 return remove => {
160 if (remove) {
161 this.size--;
162 oldEntry.delete(item);
163 if (oldEntry.size === 0) {
164 this._deleteKey(key);
165 }
166 return;
167 }
168 const newKey = this._getKey(item);
169 if (key === newKey) {
170 // This flags the sortable set as unordered
171 oldEntry.add(item);
172 } else {
173 oldEntry.delete(item);
174 if (oldEntry.size === 0) {
175 this._deleteKey(key);
176 }
177 this._addInternal(newKey, item);
178 }
179 };
180 }
181 const oldEntry = /** @type {LazyBucketSortedSet<T, any>} */ (
182 this._map.get(key)
183 );
184 const finishUpdate = oldEntry.startUpdate(item);
185 return remove => {
186 if (remove) {
187 this.size--;
188 finishUpdate(true);
189 if (oldEntry.size === 0) {
190 this._deleteKey(key);
191 }
192 return;
193 }
194 const newKey = this._getKey(item);
195 if (key === newKey) {
196 finishUpdate();
197 } else {
198 finishUpdate(true);
199 if (oldEntry.size === 0) {
200 this._deleteKey(key);
201 }
202 this._addInternal(newKey, item);
203 }
204 };
205 }
206
207 /**
208 * @param {Iterator<T>[]} iterators list of iterators to append to
209 * @returns {void}
210 */
211 _appendIterators(iterators) {
212 if (this._unsortedItems.size > 0)
213 iterators.push(this._unsortedItems[Symbol.iterator]());
214 for (const key of this._keys) {
215 const entry = this._map.get(key);
216 if (this._leaf) {
217 const leafEntry = /** @type {SortableSet<T>} */ (entry);
218 const iterator = leafEntry[Symbol.iterator]();
219 iterators.push(iterator);
220 } else {
221 const nodeEntry = /** @type {LazyBucketSortedSet<T, any>} */ (entry);
222 nodeEntry._appendIterators(iterators);
223 }
224 }
225 }
226
227 /**
228 * @returns {Iterator<T>} the iterator
229 */
230 [Symbol.iterator]() {
231 /** @type {Iterator<T>[]} */
232 const iterators = [];
233 this._appendIterators(iterators);
234 iterators.reverse();
235 let currentIterator =
236 /** @type {Iterator<T>} */
237 (iterators.pop());
238 return {
239 next: () => {
240 const res = currentIterator.next();
241 if (res.done) {
242 if (iterators.length === 0) return res;
243 currentIterator = /** @type {Iterator<T>} */ (iterators.pop());
244 return currentIterator.next();
245 }
246 return res;
247 }
248 };
249 }
250}
251
252module.exports = LazyBucketSortedSet;
Note: See TracBrowser for help on using the repository browser.