@mark1russell7/collections 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@mark1russell7/collections",
4
- "version": "0.9.1",
4
+ "version": "0.9.2",
5
5
  "description": "Collections with no dependencies: lists, maps, queues, a summary tree, channels, lazy operations and dependency graphs.",
6
6
  "keywords": [
7
7
  "collections",
@@ -88,6 +88,9 @@ const MUTATING_METHODS = new Set([
88
88
  // Queue changes that give undefined on an empty queue (C27: a readonly view removed an element)
89
89
  "pollOrUndefined",
90
90
 
91
+ // The removal by a test of LRUCache (C31: a readonly view of an LRU cache emptied it)
92
+ "deleteWhere",
93
+
91
94
  // The internal changes of the structures of this package. TypeScript marks them private, but a call at run
92
95
  // time reaches them. `readonly.test.ts` puts each method of each structure in the reads or in this list.
93
96
  "ensureCapacity",
@@ -108,6 +111,9 @@ const MUTATING_METHODS = new Set([
108
111
  "fixAfterDeletion",
109
112
  "rotateLeft",
110
113
  "rotateRight",
114
+ "moveToHead",
115
+ "removeNode",
116
+ "evictLRU",
111
117
  ]);
112
118
 
113
119
  /** Methods that return a view of the collection: the view is readonly too. */
@@ -63,6 +63,7 @@ export interface HashSetOptions<T> {
63
63
  export class HashSet<T> implements Set<T> {
64
64
  private readonly _map: HashMap<T, symbol>;
65
65
  private readonly _eq: Eq<T>;
66
+ private readonly _hash: Hash<T>;
66
67
 
67
68
  constructor(options: HashSetOptions<T> = {}) {
68
69
  const {
@@ -73,6 +74,7 @@ export class HashSet<T> implements Set<T> {
73
74
  } = options;
74
75
 
75
76
  this._eq = eq;
77
+ this._hash = hash;
76
78
  this._map = new HashMap<T, symbol>({
77
79
  initialCapacity,
78
80
  loadFactor,
@@ -140,18 +142,11 @@ export class HashSet<T> implements Set<T> {
140
142
  }
141
143
 
142
144
  retainAll(other: Iterable<T>): boolean {
143
- const toRetain = new globalThis.Set(other);
145
+ const toRetain = this.setOf(other);
144
146
  const toRemove: T[] = [];
145
147
 
146
148
  for (const element of this) {
147
- let shouldRetain = false;
148
- for (const retainElement of toRetain) {
149
- if (this._eq(element, retainElement)) {
150
- shouldRetain = true;
151
- break;
152
- }
153
- }
154
- if (!shouldRetain) {
149
+ if (!toRetain.contains(element)) {
155
150
  toRemove.push(element);
156
151
  }
157
152
  }
@@ -197,13 +192,12 @@ export class HashSet<T> implements Set<T> {
197
192
  * The new set contains only elements present in both sets.
198
193
  */
199
194
  intersection(other: Iterable<T>): HashSet<T> {
200
- const result = new HashSet<T>({ eq: this._eq });
195
+ // The loop reads `other` one time, so a generator gives all of its elements
196
+ const others = this.setOf(other);
197
+ const result = this.empty();
201
198
  for (const element of this) {
202
- for (const otherElement of other) {
203
- if (this._eq(element, otherElement)) {
204
- result.add(element);
205
- break;
206
- }
199
+ if (others.contains(element)) {
200
+ result.add(element);
207
201
  }
208
202
  }
209
203
  return result;
@@ -224,8 +218,10 @@ export class HashSet<T> implements Set<T> {
224
218
  * The new set contains elements in either set but not in both.
225
219
  */
226
220
  symmetricDifference(other: Iterable<T>): HashSet<T> {
227
- const result = this.union(other);
228
- const inter = this.intersection(other);
221
+ // The union and the intersection each read `other`, so read it one time first
222
+ const others = this.setOf(other);
223
+ const result = this.union(others);
224
+ const inter = this.intersection(others);
229
225
  result.removeAll(inter);
230
226
  return result;
231
227
  }
@@ -235,8 +231,7 @@ export class HashSet<T> implements Set<T> {
235
231
  * All elements in this set are also in the other set.
236
232
  */
237
233
  isSubsetOf(other: Iterable<T>): boolean {
238
- const otherSet = new HashSet<T>({ eq: this._eq });
239
- otherSet.addAll(other);
234
+ const otherSet = this.setOf(other);
240
235
 
241
236
  for (const element of this) {
242
237
  if (!otherSet.contains(element)) {
@@ -300,9 +295,22 @@ export class HashSet<T> implements Set<T> {
300
295
  * This method makes a shallow copy of this set.
301
296
  */
302
297
  clone(): HashSet<T> {
303
- const clone = new HashSet<T>({ eq: this._eq });
304
- clone.addAll(this);
305
- return clone;
298
+ return this.setOf(this);
299
+ }
300
+
301
+ /**
302
+ * This method makes an empty set with the equality and the hash function of this set.
303
+ * Before, the inner sets kept only the equality, so they did not find an element with a custom hash.
304
+ */
305
+ private empty(): HashSet<T> {
306
+ return new HashSet<T>({ eq: this._eq, hash: this._hash });
307
+ }
308
+
309
+ /** This method makes a set of the elements, with the equality and the hash function of this set. */
310
+ private setOf(elements: Iterable<T>): HashSet<T> {
311
+ const set = this.empty();
312
+ set.addAll(elements);
313
+ return set;
306
314
  }
307
315
 
308
316
  /**
@@ -160,10 +160,7 @@ export class TreeSet<T> implements NavigableSet<T> {
160
160
  }
161
161
 
162
162
  retainAll(elements: Iterable<T>): boolean {
163
- const toRetain = new Set<T>();
164
- for (const element of elements) {
165
- toRetain.add(element);
166
- }
163
+ const toRetain = this.setOf(elements);
167
164
 
168
165
  let modified = false;
169
166
  for (const element of Array.from(this)) {
@@ -201,10 +198,7 @@ export class TreeSet<T> implements NavigableSet<T> {
201
198
  eq: this._eq,
202
199
  });
203
200
 
204
- const otherSet = new Set<T>();
205
- for (const element of other) {
206
- otherSet.add(element);
207
- }
201
+ const otherSet = this.setOf(other);
208
202
 
209
203
  for (const element of this) {
210
204
  if (otherSet.has(element)) {
@@ -221,10 +215,7 @@ export class TreeSet<T> implements NavigableSet<T> {
221
215
  eq: this._eq,
222
216
  });
223
217
 
224
- const otherSet = new Set<T>();
225
- for (const element of other) {
226
- otherSet.add(element);
227
- }
218
+ const otherSet = this.setOf(other);
228
219
 
229
220
  for (const element of this) {
230
221
  if (!otherSet.has(element)) {
@@ -246,8 +237,8 @@ export class TreeSet<T> implements NavigableSet<T> {
246
237
  result.add(element);
247
238
  }
248
239
 
249
- // Toggle elements from other set
250
- for (const element of other) {
240
+ // Toggle each element of the other set one time, so a repeated element does not toggle back
241
+ for (const element of this.setOf(other)) {
251
242
  if (result.has(element)) {
252
243
  result.remove(element);
253
244
  } else {
@@ -259,10 +250,7 @@ export class TreeSet<T> implements NavigableSet<T> {
259
250
  }
260
251
 
261
252
  isSubsetOf(other: Iterable<T>): boolean {
262
- const otherSet = new Set<T>();
263
- for (const element of other) {
264
- otherSet.add(element);
265
- }
253
+ const otherSet = this.setOf(other);
266
254
 
267
255
  for (const element of this) {
268
256
  if (!otherSet.has(element)) {
@@ -272,6 +260,18 @@ export class TreeSet<T> implements NavigableSet<T> {
272
260
  return true;
273
261
  }
274
262
 
263
+ /**
264
+ * This method makes a set of the elements, with the comparator and the equality of this set.
265
+ * Before, the set operations used a native `Set`, which compares with `===` and ignores the comparator.
266
+ */
267
+ private setOf(elements: Iterable<T>): TreeSet<T> {
268
+ const set = new TreeSet<T>({ compare: this._compare, eq: this._eq });
269
+ for (const element of elements) {
270
+ set.add(element);
271
+ }
272
+ return set;
273
+ }
274
+
275
275
  isSupersetOf(other: Iterable<T>): boolean {
276
276
  for (const element of other) {
277
277
  if (!this.has(element)) {