sorted-collections 1.0.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.
@@ -0,0 +1,431 @@
1
+ /**
2
+ * A standard JS/TS comparator: negative if `a` sorts before `b`, positive if
3
+ * after, zero if equal.
4
+ */
5
+ type Comparator<T> = (a: T, b: T) => number;
6
+ interface SortedOptions<T> {
7
+ comparator?: Comparator<T>;
8
+ }
9
+ interface SortedOptionsRequired<T> {
10
+ comparator: Comparator<T>;
11
+ }
12
+ /** Types with a natural order (`<`/`>`) usable without an explicit comparator. */
13
+ type NaturallyOrderable = number | string;
14
+ /**
15
+ * Rest-tuple used in constructors so TypeScript enforces a comparator at
16
+ * compile time for any `T` that isn't naturally orderable, while keeping it
17
+ * optional for `number`/`string`.
18
+ */
19
+ type ComparatorArg<T> = T extends NaturallyOrderable ? [options?: SortedOptions<T>] : [options: SortedOptionsRequired<T>];
20
+
21
+ /**
22
+ * A list that keeps its elements in sorted order as they're inserted.
23
+ *
24
+ * A thin public wrapper around the internal {@link BucketEngine} — see there
25
+ * for the actual "list of lists" (sqrt-decomposition) implementation and its
26
+ * complexity notes.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const scores = new SortedList<number>([42, 7, 99]);
31
+ * scores.add(15);
32
+ * [...scores]; // [7, 15, 42, 99]
33
+ * ```
34
+ */
35
+ declare class SortedList<T> implements Iterable<T> {
36
+ private readonly engine;
37
+ /**
38
+ * @example
39
+ * ```ts
40
+ * new SortedList<number>(); // empty
41
+ * new SortedList<number>([3, 1, 2]); // [1, 2, 3]
42
+ * new SortedList<Person>([...], { comparator: (a, b) => a.age - b.age });
43
+ * ```
44
+ */
45
+ constructor(iterable?: Iterable<T>, ...options: ComparatorArg<T>);
46
+ /** Safe to call from subclasses/clone: both `ComparatorArg<T>` branches accept `{ comparator }`. */
47
+ protected comparatorArg(): ComparatorArg<T>;
48
+ /**
49
+ * O(√n) amortized.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const scores = new SortedList<number>();
54
+ * scores.add(42);
55
+ * scores.add(7);
56
+ * [...scores]; // [7, 42]
57
+ * ```
58
+ */
59
+ add(value: T): void;
60
+ /**
61
+ * Bulk-inserts every value from `iterable`, one {@link add} at a time.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const scores = new SortedList<number>([3, 1]);
66
+ * scores.update([2, 5, 4]);
67
+ * [...scores]; // [1, 2, 3, 4, 5]
68
+ * ```
69
+ */
70
+ update(iterable: Iterable<T>): void;
71
+ /**
72
+ * Removes the first occurrence of `value`. Returns `false` if it wasn't present.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * const scores = new SortedList<number>([1, 2, 2, 3]);
77
+ * scores.remove(2); // true — removes one occurrence
78
+ * scores.remove(99); // false — not present
79
+ * ```
80
+ */
81
+ remove(value: T): boolean;
82
+ /**
83
+ * Like {@link remove}, but never throws (or returns anything) if `value` isn't present.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * const scores = new SortedList<number>([1, 2, 3]);
88
+ * scores.discard(99); // no-op, no error
89
+ * ```
90
+ */
91
+ discard(value: T): void;
92
+ /**
93
+ * Removes and returns the element at `index` (default: the last element).
94
+ * Negative indices count from the end, same as {@link at}.
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * const scores = new SortedList<number>([10, 20, 30]);
99
+ * scores.pop(); // 30 — last element
100
+ * scores.pop(0); // 10 — first element
101
+ * ```
102
+ */
103
+ pop(index?: number): T;
104
+ /**
105
+ * O(√n): walks bucket lengths to find the element at `index` (negative indices count from the end).
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * const scores = new SortedList<number>([10, 20, 30]);
110
+ * scores.at(0); // 10
111
+ * scores.at(-1); // 30 — same as Array.prototype.at
112
+ * scores.at(99); // undefined — out of range
113
+ * ```
114
+ */
115
+ at(index: number): T | undefined;
116
+ /**
117
+ * The index of the first occurrence of `value`, or `-1` if absent.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * new SortedList<number>([1, 2, 2, 3]).indexOf(2); // 1
122
+ * new SortedList<number>([1, 2, 3]).indexOf(99); // -1
123
+ * ```
124
+ */
125
+ indexOf(value: T): number;
126
+ /**
127
+ * O(log n): binary search for the bucket, then binary search within it.
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * const scores = new SortedList<number>([1, 2, 3]);
132
+ * scores.has(2); // true
133
+ * scores.has(99); // false
134
+ * ```
135
+ */
136
+ has(value: T): boolean;
137
+ /**
138
+ * The leftmost index where `value` could be inserted while keeping the list sorted.
139
+ *
140
+ * @example
141
+ * ```ts
142
+ * new SortedList<number>([1, 2, 2, 2, 3]).bisectLeft(2); // 1
143
+ * ```
144
+ */
145
+ bisectLeft(value: T): number;
146
+ /**
147
+ * The rightmost index where `value` could be inserted while keeping the list sorted.
148
+ *
149
+ * @example
150
+ * ```ts
151
+ * new SortedList<number>([1, 2, 2, 2, 3]).bisectRight(2); // 4
152
+ * ```
153
+ */
154
+ bisectRight(value: T): number;
155
+ /**
156
+ * O(log n) to locate both bounds by value + O(k) to iterate the k results.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * const scores = new SortedList<number>([1, 2, 3, 4, 5]);
161
+ * [...scores.irange(2, 4)]; // [2, 3, 4] — inclusive by default
162
+ * [...scores.irange(2, 4, { inclusive: [false, true] })]; // [3, 4]
163
+ * ```
164
+ */
165
+ irange(min?: T, max?: T, options?: {
166
+ inclusive?: [boolean, boolean];
167
+ }): IterableIterator<T>;
168
+ /**
169
+ * O(√n) to locate both positional bounds + O(k) to iterate the k results.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * const scores = new SortedList<number>([10, 20, 30, 40, 50]);
174
+ * [...scores.islice(1, 4)]; // [20, 30, 40] — like Array.prototype.slice
175
+ * ```
176
+ */
177
+ islice(start?: number, end?: number): IterableIterator<T>;
178
+ /**
179
+ * @example
180
+ * ```ts
181
+ * new SortedList<number>([1, 2, 3]).length; // 3
182
+ * ```
183
+ */
184
+ get length(): number;
185
+ /**
186
+ * @example
187
+ * ```ts
188
+ * const scores = new SortedList<number>([1, 2, 3]);
189
+ * scores.clear();
190
+ * scores.length; // 0
191
+ * ```
192
+ */
193
+ clear(): void;
194
+ /**
195
+ * An independent copy — mutating the clone never affects the original.
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * const original = new SortedList<number>([1, 2, 3]);
200
+ * const copy = original.clone();
201
+ * copy.add(4);
202
+ * original.length; // 3
203
+ * copy.length; // 4
204
+ * ```
205
+ */
206
+ clone(): SortedList<T>;
207
+ /**
208
+ * @example
209
+ * ```ts
210
+ * const scores = new SortedList<number>([3, 1, 2]);
211
+ * for (const value of scores) console.log(value); // 1, 2, 3
212
+ * ```
213
+ */
214
+ [Symbol.iterator](): IterableIterator<T>;
215
+ }
216
+
217
+ /**
218
+ * Like {@link SortedList}, but rejects duplicates (compared via the
219
+ * comparator, not reference identity). Adds set-theory operations.
220
+ *
221
+ * Reuses `SortedList`'s bucket structure entirely: the only behavioral
222
+ * difference is that `add` is a no-op for values already present.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * const tags = new SortedSet<string>(['b', 'a', 'c', 'a']);
227
+ * [...tags]; // ['a', 'b', 'c'] — the duplicate 'a' was dropped
228
+ * ```
229
+ */
230
+ declare class SortedSet<T> extends SortedList<T> {
231
+ /**
232
+ * O(log n) `has` check + O(√n) amortized insert if the value is new.
233
+ *
234
+ * @example
235
+ * ```ts
236
+ * const tags = new SortedSet<string>(['a']);
237
+ * tags.add('a'); // no-op, already present
238
+ * tags.length; // 1
239
+ * ```
240
+ */
241
+ add(value: T): void;
242
+ /**
243
+ * @example
244
+ * ```ts
245
+ * const original = new SortedSet<number>([1, 2, 3]);
246
+ * const copy = original.clone();
247
+ * copy.add(4);
248
+ * original.length; // 3
249
+ * ```
250
+ */
251
+ clone(): SortedSet<T>;
252
+ /**
253
+ * O(m log n + m) for a set of size m being merged in.
254
+ *
255
+ * @example
256
+ * ```ts
257
+ * const a = new SortedSet<number>([1, 2, 3]);
258
+ * const b = new SortedSet<number>([3, 4]);
259
+ * [...a.union(b)]; // [1, 2, 3, 4]
260
+ * ```
261
+ */
262
+ union(other: SortedSet<T>): SortedSet<T>;
263
+ /**
264
+ * @example
265
+ * ```ts
266
+ * const a = new SortedSet<number>([1, 2, 3]);
267
+ * const b = new SortedSet<number>([2, 3, 4]);
268
+ * [...a.intersection(b)]; // [2, 3]
269
+ * ```
270
+ */
271
+ intersection(other: SortedSet<T>): SortedSet<T>;
272
+ /**
273
+ * @example
274
+ * ```ts
275
+ * const a = new SortedSet<number>([1, 2, 3]);
276
+ * const b = new SortedSet<number>([2, 3]);
277
+ * [...a.difference(b)]; // [1] — in a, not in b
278
+ * ```
279
+ */
280
+ difference(other: SortedSet<T>): SortedSet<T>;
281
+ /**
282
+ * @example
283
+ * ```ts
284
+ * new SortedSet<number>([2, 3]).isSubsetOf(new SortedSet<number>([1, 2, 3, 4])); // true
285
+ * new SortedSet<number>([1, 5]).isSubsetOf(new SortedSet<number>([1, 2, 3])); // false
286
+ * ```
287
+ */
288
+ isSubsetOf(other: SortedSet<T>): boolean;
289
+ }
290
+
291
+ /**
292
+ * A dictionary ordered by key.
293
+ *
294
+ * Uses the internal {@link BucketEngine} directly (on `[K, V]` tuples, with a
295
+ * comparator that only looks at the key) rather than composing over
296
+ * `SortedList`'s public API. Two reasons: `set` needs the engine's O(log n)
297
+ * in-place replace-or-insert (`SortedList#bisectLeft` + `#at` would pay for a
298
+ * positional index it doesn't need), and `get`/`has`/`delete` use the `*By`
299
+ * lookup methods with a closure over the bare key — that compares the key
300
+ * only once per candidate (not twice, since the search side needs no
301
+ * `entry[0]` unwrapping) and avoids allocating a throwaway `[key, undefined]`
302
+ * search tuple per call.
303
+ *
304
+ * @example
305
+ * ```ts
306
+ * const byPrice = new SortedMap<number, string>([[101.5, 'order-1'], [99.75, 'order-2']]);
307
+ * [...byPrice.keys()]; // [99.75, 101.5]
308
+ * ```
309
+ */
310
+ declare class SortedMap<K, V> implements Iterable<[K, V]> {
311
+ private readonly engine;
312
+ private readonly keyComparator;
313
+ /**
314
+ * @example
315
+ * ```ts
316
+ * new SortedMap<number, string>(); // empty
317
+ * new SortedMap<number, string>([[2, 'b'], [1, 'a']]); // ordered by key: 1, 2
318
+ * ```
319
+ */
320
+ constructor(entries?: Iterable<[K, V]>, ...options: ComparatorArg<K>);
321
+ /**
322
+ * O(log n) to locate + O(1) to replace in place, or O(√n) amortized to insert.
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * const byPrice = new SortedMap<number, string>();
327
+ * byPrice.set(101.5, 'order-1');
328
+ * byPrice.set(101.5, 'order-1-updated'); // overwrites, doesn't grow size
329
+ * ```
330
+ */
331
+ set(key: K, value: V): void;
332
+ /**
333
+ * O(log n): binary search for the bucket, then binary search within it.
334
+ *
335
+ * @example
336
+ * ```ts
337
+ * const byPrice = new SortedMap<number, string>([[101.5, 'order-1']]);
338
+ * byPrice.get(101.5); // 'order-1'
339
+ * byPrice.get(1); // undefined
340
+ * ```
341
+ */
342
+ get(key: K): V | undefined;
343
+ /**
344
+ * @example
345
+ * ```ts
346
+ * const byPrice = new SortedMap<number, string>([[101.5, 'order-1']]);
347
+ * byPrice.delete(101.5); // true
348
+ * byPrice.delete(101.5); // false — already gone
349
+ * ```
350
+ */
351
+ delete(key: K): boolean;
352
+ /**
353
+ * @example
354
+ * ```ts
355
+ * new SortedMap<number, string>([[1, 'a']]).has(1); // true
356
+ * ```
357
+ */
358
+ has(key: K): boolean;
359
+ /**
360
+ * A snapshot `SortedSet` of the current keys — not a live view.
361
+ *
362
+ * @example
363
+ * ```ts
364
+ * const byPrice = new SortedMap<number, string>([[2, 'b'], [1, 'a']]);
365
+ * [...byPrice.keys()]; // [1, 2]
366
+ * ```
367
+ */
368
+ keys(): SortedSet<K>;
369
+ private keysGenerator;
370
+ /**
371
+ * @example
372
+ * ```ts
373
+ * [...new SortedMap<number, string>([[2, 'b'], [1, 'a']]).values()]; // ['a', 'b']
374
+ * ```
375
+ */
376
+ values(): IterableIterator<V>;
377
+ /**
378
+ * @example
379
+ * ```ts
380
+ * [...new SortedMap<number, string>([[2, 'b'], [1, 'a']]).entries()]; // [[1, 'a'], [2, 'b']]
381
+ * ```
382
+ */
383
+ entries(): IterableIterator<[K, V]>;
384
+ /**
385
+ * Iterates `[key, value]` pairs with keys in `[minKey, maxKey]`.
386
+ *
387
+ * @example
388
+ * ```ts
389
+ * const byPrice = new SortedMap<number, string>([[95, 'a'], [100, 'b'], [105, 'c']]);
390
+ * [...byPrice.irange(95, 100)]; // [[95, 'a'], [100, 'b']]
391
+ * ```
392
+ */
393
+ irange(minKey?: K, maxKey?: K): IterableIterator<[K, V]>;
394
+ /**
395
+ * O(√n). Entry at ordinal position `index` in key order.
396
+ *
397
+ * @example
398
+ * ```ts
399
+ * const byPrice = new SortedMap<number, string>([[2, 'b'], [1, 'a']]);
400
+ * byPrice.at(0); // [1, 'a']
401
+ * ```
402
+ */
403
+ at(index: number): [K, V] | undefined;
404
+ /**
405
+ * @example
406
+ * ```ts
407
+ * new SortedMap<number, string>([[1, 'a'], [2, 'b']]).size; // 2
408
+ * ```
409
+ */
410
+ get size(): number;
411
+ /**
412
+ * @example
413
+ * ```ts
414
+ * const byPrice = new SortedMap<number, string>([[1, 'a']]);
415
+ * byPrice.clear();
416
+ * byPrice.size; // 0
417
+ * ```
418
+ */
419
+ clear(): void;
420
+ /**
421
+ * @example
422
+ * ```ts
423
+ * for (const [key, value] of new SortedMap([[2, 'b'], [1, 'a']])) {
424
+ * console.log(key, value); // 1 'a', then 2 'b'
425
+ * }
426
+ * ```
427
+ */
428
+ [Symbol.iterator](): IterableIterator<[K, V]>;
429
+ }
430
+
431
+ export { type Comparator, type NaturallyOrderable, SortedList, SortedMap, type SortedOptions, type SortedOptionsRequired, SortedSet };