@llblab/uniqueue 1.3.0 → 1.4.0

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/README.md CHANGED
@@ -19,6 +19,10 @@ Combines a binary heap with a key-to-index `Map`, enabling O(log n) inserts/upda
19
19
  npm install @llblab/uniqueue
20
20
  ```
21
21
 
22
+ ```bash
23
+ deno add jsr:@llblab/uniqueue
24
+ ```
25
+
22
26
  ## Usage
23
27
 
24
28
  ### Basic Example (Top-N Leaderboard)
@@ -34,8 +38,8 @@ import { Uniqueue } from "@llblab/uniqueue";
34
38
  // the root (smallest/worst) is evicted, keeping the best scores.
35
39
  const leaderboard = new Uniqueue({
36
40
  compare: (a, b) => a.score - b.score,
37
- extractKey: (item) => item.playerId, // Unique by playerId
38
- maxSize: 3, // Keep only top 3 scores
41
+ extractKey: (item) => item.playerId,
42
+ maxSize: 3,
39
43
  });
40
44
 
41
45
  // Add items
@@ -53,7 +57,7 @@ leaderboard.push({ playerId: "alice", score: 150 });
53
57
  leaderboard.push({ playerId: "dave", score: 200 });
54
58
  // Bob (lowest score at root) is evicted
55
59
 
56
- console.log(leaderboard.data);
60
+ leaderboard.snapshot();
57
61
  // Contains charlie (120), alice (150), dave (200)
58
62
 
59
63
  // Iterate over all items
@@ -114,6 +118,10 @@ Removes all items from the queue.
114
118
 
115
119
  Getter property that returns the number of items.
116
120
 
121
+ #### `snapshot(): T[]`
122
+
123
+ Returns a shallow copy of the underlying heap array. Safe for sorting or other mutations without affecting the queue.
124
+
117
125
  #### `[Symbol.iterator](): IterableIterator<T>`
118
126
 
119
127
  Iterates over items in heap order (not sorted).
package/dist/index.d.ts CHANGED
@@ -6,8 +6,6 @@ export interface UniqueueOptions<T, K = string> {
6
6
  }
7
7
  export declare class Uniqueue<T, K = string> {
8
8
  #private;
9
- data: T[];
10
- indexes: Map<K, number>;
11
9
  constructor({ data, maxSize, compare, extractKey, }?: UniqueueOptions<T, K>);
12
10
  push(item: T): T | undefined;
13
11
  pop(): T | undefined;
@@ -17,6 +15,7 @@ export declare class Uniqueue<T, K = string> {
17
15
  get(key: K): T | undefined;
18
16
  clear(): void;
19
17
  get size(): number;
18
+ snapshot(): T[];
20
19
  [Symbol.iterator](): IterableIterator<T>;
21
20
  }
22
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM;IAC5C,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;CAC7B;AAED,qBAAa,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM;;IACjC,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;gBAMZ,EACV,IAAS,EACT,OAAkB,EAClB,OAAgD,EAChD,UAA2C,GAC5C,GAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAM;IAyE7B,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAsB5B,GAAG,IAAI,CAAC,GAAG,SAAS;IAgBpB,IAAI,IAAI,CAAC,GAAG,SAAS;IAIrB,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IA0BvB,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIpB,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAK1B,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI,MAAM,CAEjB;IAEA,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC;CAG1C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM;IAC5C,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;CAC7B;AAED,qBAAa,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM;;gBAOrB,EACV,IAAS,EACT,OAAkB,EAClB,OAAgD,EAChD,UAA2C,GAC5C,GAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAM;IA0E7B,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAsB5B,GAAG,IAAI,CAAC,GAAG,SAAS;IAgBpB,IAAI,IAAI,CAAC,GAAG,SAAS;IAIrB,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IA0BvB,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIpB,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAK1B,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,QAAQ,IAAI,CAAC,EAAE;IAId,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC;CAG1C"}
package/dist/index.js CHANGED
@@ -1,30 +1,31 @@
1
1
  export class Uniqueue {
2
- data;
3
- indexes;
2
+ #data;
3
+ #indexes;
4
4
  #maxSize;
5
5
  #compare;
6
6
  #extractKey;
7
7
  constructor({ data = [], maxSize = Infinity, compare = (a, b) => (a < b ? -1 : a > b ? 1 : 0), extractKey = (item) => item, } = {}) {
8
+ this.#data = [];
9
+ this.#indexes = new Map();
8
10
  this.#maxSize = maxSize;
9
11
  this.#compare = compare;
10
12
  this.#extractKey = extractKey;
11
- this.data = [];
12
- this.indexes = new Map();
13
13
  for (const item of data) {
14
14
  const key = extractKey(item);
15
- if (!this.indexes.has(key)) {
16
- this.indexes.set(key, this.data.length);
17
- this.data.push(item);
15
+ if (!this.#indexes.has(key)) {
16
+ this.#indexes.set(key, this.#data.length);
17
+ this.#data.push(item);
18
18
  }
19
19
  }
20
- if (this.data.length > 0) {
21
- for (let i = (this.data.length >>> 1) - 1; i >= 0; i--) {
20
+ if (this.#data.length > 0) {
21
+ for (let i = (this.#data.length >>> 1) - 1; i >= 0; i--) {
22
22
  this.#siftDown(i);
23
23
  }
24
24
  }
25
25
  }
26
26
  #siftUp(pos) {
27
- const { data, indexes } = this;
27
+ const data = this.#data;
28
+ const indexes = this.#indexes;
28
29
  const compare = this.#compare;
29
30
  const extractKey = this.#extractKey;
30
31
  const item = data[pos];
@@ -41,7 +42,8 @@ export class Uniqueue {
41
42
  data[pos] = item;
42
43
  }
43
44
  #siftDown(pos) {
44
- const { data, indexes } = this;
45
+ const data = this.#data;
46
+ const indexes = this.#indexes;
45
47
  const compare = this.#compare;
46
48
  const extractKey = this.#extractKey;
47
49
  const item = data[pos];
@@ -68,16 +70,16 @@ export class Uniqueue {
68
70
  }
69
71
  push(item) {
70
72
  const key = this.#extractKey(item);
71
- const index = this.indexes.get(key);
73
+ const index = this.#indexes.get(key);
72
74
  if (index === undefined) {
73
- this.data.push(item);
74
- this.#siftUp(this.data.length - 1);
75
- if (this.data.length <= this.#maxSize)
75
+ this.#data.push(item);
76
+ this.#siftUp(this.#data.length - 1);
77
+ if (this.#data.length <= this.#maxSize)
76
78
  return;
77
79
  return this.pop();
78
80
  }
79
- const oldItem = this.data[index];
80
- this.data[index] = item;
81
+ const oldItem = this.#data[index];
82
+ this.#data[index] = item;
81
83
  const cmp = this.#compare(oldItem, item);
82
84
  if (cmp < 0) {
83
85
  this.#siftDown(index);
@@ -87,37 +89,37 @@ export class Uniqueue {
87
89
  }
88
90
  }
89
91
  pop() {
90
- if (this.data.length === 0)
92
+ if (this.#data.length === 0)
91
93
  return;
92
- const top = this.data[0];
93
- this.indexes.delete(this.#extractKey(top));
94
- const bottom = this.data.pop();
95
- if (this.data.length > 0 && bottom !== undefined) {
96
- this.indexes.set(this.#extractKey(bottom), 0);
97
- this.data[0] = bottom;
94
+ const top = this.#data[0];
95
+ this.#indexes.delete(this.#extractKey(top));
96
+ const bottom = this.#data.pop();
97
+ if (this.#data.length > 0 && bottom !== undefined) {
98
+ this.#indexes.set(this.#extractKey(bottom), 0);
99
+ this.#data[0] = bottom;
98
100
  this.#siftDown(0);
99
101
  }
100
102
  return top;
101
103
  }
102
104
  peek() {
103
- return this.data[0];
105
+ return this.#data[0];
104
106
  }
105
107
  remove(key) {
106
- const index = this.indexes.get(key);
108
+ const index = this.#indexes.get(key);
107
109
  if (index === undefined)
108
110
  return false;
109
- const lastIndex = this.data.length - 1;
111
+ const lastIndex = this.#data.length - 1;
110
112
  if (index === lastIndex) {
111
- this.indexes.delete(key);
112
- this.data.pop();
113
+ this.#indexes.delete(key);
114
+ this.#data.pop();
113
115
  return true;
114
116
  }
115
- const item = this.data.pop();
116
- this.indexes.delete(key);
117
- this.indexes.set(this.#extractKey(item), index);
118
- this.data[index] = item;
117
+ const item = this.#data.pop();
118
+ this.#indexes.delete(key);
119
+ this.#indexes.set(this.#extractKey(item), index);
120
+ this.#data[index] = item;
119
121
  const parentIndex = (index - 1) >>> 1;
120
- if (index > 0 && this.#compare(item, this.data[parentIndex]) < 0) {
122
+ if (index > 0 && this.#compare(item, this.#data[parentIndex]) < 0) {
121
123
  this.#siftUp(index);
122
124
  }
123
125
  else {
@@ -126,20 +128,23 @@ export class Uniqueue {
126
128
  return true;
127
129
  }
128
130
  has(key) {
129
- return this.indexes.has(key);
131
+ return this.#indexes.has(key);
130
132
  }
131
133
  get(key) {
132
- const index = this.indexes.get(key);
133
- return index !== undefined ? this.data[index] : undefined;
134
+ const index = this.#indexes.get(key);
135
+ return index !== undefined ? this.#data[index] : undefined;
134
136
  }
135
137
  clear() {
136
- this.data = [];
137
- this.indexes.clear();
138
+ this.#data = [];
139
+ this.#indexes.clear();
138
140
  }
139
141
  get size() {
140
- return this.data.length;
142
+ return this.#data.length;
143
+ }
144
+ snapshot() {
145
+ return [...this.#data];
141
146
  }
142
147
  *[Symbol.iterator]() {
143
- yield* this.data;
148
+ yield* this.#data;
144
149
  }
145
150
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/uniqueue",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "High-performance priority queue with unique key constraint (O(1) lookup, O(log n) update)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",