@okikio/observables 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.
- package/LICENSE +21 -0
- package/README.md +578 -0
- package/esm/_dnt.polyfills.d.ts +20 -0
- package/esm/_dnt.polyfills.d.ts.map +1 -0
- package/esm/_dnt.polyfills.js +12 -0
- package/esm/_spec.d.ts +260 -0
- package/esm/_spec.d.ts.map +1 -0
- package/esm/_spec.js +1 -0
- package/esm/_types.d.ts +141 -0
- package/esm/_types.d.ts.map +1 -0
- package/esm/_types.js +20 -0
- package/esm/error.d.ts +331 -0
- package/esm/error.d.ts.map +1 -0
- package/esm/error.js +408 -0
- package/esm/events.d.ts +320 -0
- package/esm/events.d.ts.map +1 -0
- package/esm/events.js +451 -0
- package/esm/helpers/_types.d.ts +188 -0
- package/esm/helpers/_types.d.ts.map +1 -0
- package/esm/helpers/_types.js +1 -0
- package/esm/helpers/mod.d.ts +90 -0
- package/esm/helpers/mod.d.ts.map +1 -0
- package/esm/helpers/mod.js +90 -0
- package/esm/helpers/operations/batch.d.ts +109 -0
- package/esm/helpers/operations/batch.d.ts.map +1 -0
- package/esm/helpers/operations/batch.js +140 -0
- package/esm/helpers/operations/combination.d.ts +162 -0
- package/esm/helpers/operations/combination.d.ts.map +1 -0
- package/esm/helpers/operations/combination.js +350 -0
- package/esm/helpers/operations/conditional.d.ts +211 -0
- package/esm/helpers/operations/conditional.d.ts.map +1 -0
- package/esm/helpers/operations/conditional.js +280 -0
- package/esm/helpers/operations/core.d.ts +198 -0
- package/esm/helpers/operations/core.d.ts.map +1 -0
- package/esm/helpers/operations/core.js +264 -0
- package/esm/helpers/operations/errors.d.ts +277 -0
- package/esm/helpers/operations/errors.d.ts.map +1 -0
- package/esm/helpers/operations/errors.js +378 -0
- package/esm/helpers/operations/mod.d.ts +26 -0
- package/esm/helpers/operations/mod.d.ts.map +1 -0
- package/esm/helpers/operations/mod.js +25 -0
- package/esm/helpers/operations/timing.d.ts +206 -0
- package/esm/helpers/operations/timing.d.ts.map +1 -0
- package/esm/helpers/operations/timing.js +457 -0
- package/esm/helpers/operators.d.ts +520 -0
- package/esm/helpers/operators.d.ts.map +1 -0
- package/esm/helpers/operators.js +563 -0
- package/esm/helpers/pipe.d.ts +118 -0
- package/esm/helpers/pipe.d.ts.map +1 -0
- package/esm/helpers/pipe.js +129 -0
- package/esm/helpers/utils.d.ts +142 -0
- package/esm/helpers/utils.d.ts.map +1 -0
- package/esm/helpers/utils.js +193 -0
- package/esm/mod.d.ts +863 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +861 -0
- package/esm/observable.d.ts +1610 -0
- package/esm/observable.d.ts.map +1 -0
- package/esm/observable.js +1970 -0
- package/esm/package.json +3 -0
- package/esm/queue.d.ts +201 -0
- package/esm/queue.d.ts.map +1 -0
- package/esm/queue.js +273 -0
- package/esm/symbol.d.ts +60 -0
- package/esm/symbol.d.ts.map +1 -0
- package/esm/symbol.js +132 -0
- package/package.json +96 -0
- package/script/_dnt.polyfills.d.ts +20 -0
- package/script/_dnt.polyfills.d.ts.map +1 -0
- package/script/_dnt.polyfills.js +13 -0
- package/script/_spec.d.ts +260 -0
- package/script/_spec.d.ts.map +1 -0
- package/script/_spec.js +2 -0
- package/script/_types.d.ts +141 -0
- package/script/_types.d.ts.map +1 -0
- package/script/_types.js +22 -0
- package/script/error.d.ts +331 -0
- package/script/error.d.ts.map +1 -0
- package/script/error.js +414 -0
- package/script/events.d.ts +320 -0
- package/script/events.d.ts.map +1 -0
- package/script/events.js +458 -0
- package/script/helpers/_types.d.ts +188 -0
- package/script/helpers/_types.d.ts.map +1 -0
- package/script/helpers/_types.js +2 -0
- package/script/helpers/mod.d.ts +90 -0
- package/script/helpers/mod.d.ts.map +1 -0
- package/script/helpers/mod.js +106 -0
- package/script/helpers/operations/batch.d.ts +109 -0
- package/script/helpers/operations/batch.d.ts.map +1 -0
- package/script/helpers/operations/batch.js +144 -0
- package/script/helpers/operations/combination.d.ts +162 -0
- package/script/helpers/operations/combination.d.ts.map +1 -0
- package/script/helpers/operations/combination.js +355 -0
- package/script/helpers/operations/conditional.d.ts +211 -0
- package/script/helpers/operations/conditional.d.ts.map +1 -0
- package/script/helpers/operations/conditional.js +286 -0
- package/script/helpers/operations/core.d.ts +198 -0
- package/script/helpers/operations/core.d.ts.map +1 -0
- package/script/helpers/operations/core.js +272 -0
- package/script/helpers/operations/errors.d.ts +277 -0
- package/script/helpers/operations/errors.d.ts.map +1 -0
- package/script/helpers/operations/errors.js +387 -0
- package/script/helpers/operations/mod.d.ts +26 -0
- package/script/helpers/operations/mod.d.ts.map +1 -0
- package/script/helpers/operations/mod.js +41 -0
- package/script/helpers/operations/timing.d.ts +206 -0
- package/script/helpers/operations/timing.d.ts.map +1 -0
- package/script/helpers/operations/timing.js +464 -0
- package/script/helpers/operators.d.ts +520 -0
- package/script/helpers/operators.d.ts.map +1 -0
- package/script/helpers/operators.js +570 -0
- package/script/helpers/pipe.d.ts +118 -0
- package/script/helpers/pipe.d.ts.map +1 -0
- package/script/helpers/pipe.js +132 -0
- package/script/helpers/utils.d.ts +142 -0
- package/script/helpers/utils.d.ts.map +1 -0
- package/script/helpers/utils.js +200 -0
- package/script/mod.d.ts +863 -0
- package/script/mod.d.ts.map +1 -0
- package/script/mod.js +877 -0
- package/script/observable.d.ts +1610 -0
- package/script/observable.d.ts.map +1 -0
- package/script/observable.js +1984 -0
- package/script/package.json +3 -0
- package/script/queue.d.ts +201 -0
- package/script/queue.d.ts.map +1 -0
- package/script/queue.js +286 -0
- package/script/symbol.d.ts +60 -0
- package/script/symbol.d.ts.map +1 -0
- package/script/symbol.js +135 -0
package/esm/package.json
ADDED
package/esm/queue.d.ts
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A lightweight circular-buffer queue for the library's hot paths.
|
|
3
|
+
*
|
|
4
|
+
* This entrypoint exposes the small FIFO data structure that backs replay,
|
|
5
|
+
* buffering, and event fan-out inside the Observable runtime. It keeps
|
|
6
|
+
* enqueue/dequeue work O(1) by moving `head` and `tail` pointers around a fixed
|
|
7
|
+
* array instead of repeatedly calling `Array.shift()`, which has to move every
|
|
8
|
+
* remaining element one slot to the left.
|
|
9
|
+
*
|
|
10
|
+
* Use this module when you need predictable queue performance and explicit
|
|
11
|
+
* capacity control. It is especially useful for buffers that grow and shrink
|
|
12
|
+
* frequently, where repeated array reindexing would turn steady traffic into an
|
|
13
|
+
* unnecessary O(n) cost.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```
|
|
17
|
+
* import { createQueue, enqueue, dequeue, peek } from './queue.ts';
|
|
18
|
+
*
|
|
19
|
+
* const taskQueue = createQueue<string>(100); // capacity of 100
|
|
20
|
+
* enqueue(taskQueue, 'process-order-123'); // add task
|
|
21
|
+
* enqueue(taskQueue, 'send-email-456'); // add another
|
|
22
|
+
*
|
|
23
|
+
* console.log(peek(taskQueue)); // 'process-order-123' (doesn't remove)
|
|
24
|
+
* console.log(dequeue(taskQueue)); // 'process-order-123' (removes and returns)
|
|
25
|
+
*
|
|
26
|
+
* clear(taskQueue); // empty the queue instantly
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @module
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Represents a circular buffer-based queue for efficient FIFO operations.
|
|
33
|
+
*
|
|
34
|
+
* @template T - The type of elements stored in the queue
|
|
35
|
+
*/
|
|
36
|
+
import "./_dnt.polyfills.js";
|
|
37
|
+
export interface Queue<T> {
|
|
38
|
+
/** The backing array that holds queue elements */
|
|
39
|
+
items: T[];
|
|
40
|
+
/** Index pointing to the front element (next to dequeue) */
|
|
41
|
+
head: number;
|
|
42
|
+
/** Index pointing to where the next element will be added */
|
|
43
|
+
tail: number;
|
|
44
|
+
/** Current number of elements in the queue */
|
|
45
|
+
size: number;
|
|
46
|
+
/** Maximum capacity of the queue */
|
|
47
|
+
capacity: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Creates a new empty queue with the specified capacity.
|
|
51
|
+
*
|
|
52
|
+
* The queue uses a circular buffer internally, which means operations
|
|
53
|
+
* like enqueue and dequeue run in constant O(1) time regardless of
|
|
54
|
+
* queue size.
|
|
55
|
+
*
|
|
56
|
+
* @param capacity - Maximum number of elements the queue can hold (default: 1000)
|
|
57
|
+
* @returns A new empty queue ready for use
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```
|
|
61
|
+
* const messageQueue = createQueue<string>(50); // for messages
|
|
62
|
+
* const numberQueue = createQueue<number>(); // uses default capacity
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function createQueue<T>(capacity?: number): Queue<T>;
|
|
66
|
+
/**
|
|
67
|
+
* Adds an element to the back of the queue (FIFO: last in, first served).
|
|
68
|
+
* Runs in O(1) constant time.
|
|
69
|
+
*
|
|
70
|
+
* @param queue - The target queue
|
|
71
|
+
* @param item - Element to add to the queue
|
|
72
|
+
* @throws Error if the queue is at capacity
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```
|
|
76
|
+
* enqueue(userQueue, { id: 123, name: 'Alice' });
|
|
77
|
+
* enqueue(userQueue, { id: 124, name: 'Bob' });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function enqueue<T>(queue: Queue<T>, item: T): void;
|
|
81
|
+
/**
|
|
82
|
+
* Removes and returns the front element from the queue (FIFO: first in, first out).
|
|
83
|
+
* Runs in O(1) constant time.
|
|
84
|
+
*
|
|
85
|
+
* @param queue - The target queue
|
|
86
|
+
* @returns The front element, or undefined if queue is empty
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```
|
|
90
|
+
* const nextTask = dequeue(taskQueue);
|
|
91
|
+
* if (nextTask) {
|
|
92
|
+
* console.log('Processing:', nextTask);
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function dequeue<T>(queue: Queue<T>): T | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* Returns the front element without removing it from the queue.
|
|
99
|
+
* Useful for checking what's next without consuming it.
|
|
100
|
+
* Runs in O(1) constant time.
|
|
101
|
+
*
|
|
102
|
+
* @param queue - The target queue
|
|
103
|
+
* @returns The front element, or undefined if queue is empty
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```
|
|
107
|
+
* const nextInLine = peek(queue);
|
|
108
|
+
* if (nextInLine?.priority === 'urgent') {
|
|
109
|
+
* // handle urgent task immediately
|
|
110
|
+
* dequeue(queue);
|
|
111
|
+
* }
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare function peek<T>(queue: Queue<T>): T | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* Checks if the queue contains no elements.
|
|
117
|
+
*
|
|
118
|
+
* @param queue - The target queue
|
|
119
|
+
* @returns true if the queue is empty, false otherwise
|
|
120
|
+
*/
|
|
121
|
+
export declare function isEmpty<T>(queue: Queue<T>): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Checks if the queue has reached its maximum capacity.
|
|
124
|
+
*
|
|
125
|
+
* @param queue - The target queue
|
|
126
|
+
* @returns true if the queue is full, false otherwise
|
|
127
|
+
*/
|
|
128
|
+
export declare function isFull<T>(queue: Queue<T>): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Returns the current number of elements in the queue.
|
|
131
|
+
*
|
|
132
|
+
* @param queue - The target queue
|
|
133
|
+
* @returns Current queue size (0 to capacity)
|
|
134
|
+
*/
|
|
135
|
+
export declare function getSize<T>(queue: Queue<T>): number;
|
|
136
|
+
/**
|
|
137
|
+
* Returns how many more elements can be added before hitting capacity.
|
|
138
|
+
*
|
|
139
|
+
* @param queue - The target queue
|
|
140
|
+
* @returns Number of available slots
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```
|
|
144
|
+
* if (remainingSpace(queue) < 10) {
|
|
145
|
+
* console.warn('Queue nearly full, consider processing items');
|
|
146
|
+
* }
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export declare function remainingSpace<T>(queue: Queue<T>): number;
|
|
150
|
+
/**
|
|
151
|
+
* Empties the queue instantly using the `.length = 0` optimization[87][90].
|
|
152
|
+
* This immediately releases all object references for garbage collection,
|
|
153
|
+
* making it much faster than dequeuing items one by one.
|
|
154
|
+
*
|
|
155
|
+
* Runs in O(1) constant time regardless of queue size.
|
|
156
|
+
*
|
|
157
|
+
* @param queue - The target queue
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```
|
|
161
|
+
* // Instead of: while (!isEmpty(queue)) dequeue(queue); // O(n)
|
|
162
|
+
* clear(queue); // O(1) - much faster!
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export declare function clear<T>(queue: Queue<T>): void;
|
|
166
|
+
/**
|
|
167
|
+
* Creates a new array containing all queue elements in order (front to back).
|
|
168
|
+
* Useful for debugging, logging, or when you need array methods.
|
|
169
|
+
*
|
|
170
|
+
* Note: This is O(n) operation - use sparingly in performance-critical code.
|
|
171
|
+
*
|
|
172
|
+
* @param queue - The source queue
|
|
173
|
+
* @returns New array with queue elements in FIFO order
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```
|
|
177
|
+
* const queueSnapshot = toArray(queue);
|
|
178
|
+
* console.log('Current queue:', queueSnapshot.join(' -> '));
|
|
179
|
+
*
|
|
180
|
+
* // Process without modifying original queue
|
|
181
|
+
* const urgentItems = queueSnapshot.filter(item => item.priority === 'urgent');
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export declare function toArray<T>(queue: Queue<T>): T[];
|
|
185
|
+
/**
|
|
186
|
+
* Applies a function to each element in the queue without modifying it.
|
|
187
|
+
* Elements are visited in FIFO order (front to back).
|
|
188
|
+
*
|
|
189
|
+
* @param queue - The target queue
|
|
190
|
+
* @param callback - Function to call for each element
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```
|
|
194
|
+
* // Log all pending tasks
|
|
195
|
+
* forEach(taskQueue, (task, index) => {
|
|
196
|
+
* console.log(`Task ${index + 1}: ${task.description}`);
|
|
197
|
+
* });
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
export declare function forEach<T>(queue: Queue<T>, callback: (item: T, index: number) => void): void;
|
|
201
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH;;;;GAIG;AACH,OAAO,qBAAqB,CAAC;AAE7B,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,kDAAkD;IAClD,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAE,MAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAQhE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAUzD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAWzD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAEtD;AAMD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAElD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAEzD;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAS9C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAc/C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACzC,IAAI,CAON"}
|
package/esm/queue.js
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A lightweight circular-buffer queue for the library's hot paths.
|
|
3
|
+
*
|
|
4
|
+
* This entrypoint exposes the small FIFO data structure that backs replay,
|
|
5
|
+
* buffering, and event fan-out inside the Observable runtime. It keeps
|
|
6
|
+
* enqueue/dequeue work O(1) by moving `head` and `tail` pointers around a fixed
|
|
7
|
+
* array instead of repeatedly calling `Array.shift()`, which has to move every
|
|
8
|
+
* remaining element one slot to the left.
|
|
9
|
+
*
|
|
10
|
+
* Use this module when you need predictable queue performance and explicit
|
|
11
|
+
* capacity control. It is especially useful for buffers that grow and shrink
|
|
12
|
+
* frequently, where repeated array reindexing would turn steady traffic into an
|
|
13
|
+
* unnecessary O(n) cost.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```
|
|
17
|
+
* import { createQueue, enqueue, dequeue, peek } from './queue.ts';
|
|
18
|
+
*
|
|
19
|
+
* const taskQueue = createQueue<string>(100); // capacity of 100
|
|
20
|
+
* enqueue(taskQueue, 'process-order-123'); // add task
|
|
21
|
+
* enqueue(taskQueue, 'send-email-456'); // add another
|
|
22
|
+
*
|
|
23
|
+
* console.log(peek(taskQueue)); // 'process-order-123' (doesn't remove)
|
|
24
|
+
* console.log(dequeue(taskQueue)); // 'process-order-123' (removes and returns)
|
|
25
|
+
*
|
|
26
|
+
* clear(taskQueue); // empty the queue instantly
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @module
|
|
30
|
+
*/
|
|
31
|
+
///////////////////////
|
|
32
|
+
// Core Data Types //
|
|
33
|
+
///////////////////////
|
|
34
|
+
/**
|
|
35
|
+
* Represents a circular buffer-based queue for efficient FIFO operations.
|
|
36
|
+
*
|
|
37
|
+
* @template T - The type of elements stored in the queue
|
|
38
|
+
*/
|
|
39
|
+
import "./_dnt.polyfills.js";
|
|
40
|
+
/**
|
|
41
|
+
* Advances a circular-buffer index by one slot and wraps back to `0` at the end.
|
|
42
|
+
*
|
|
43
|
+
* This keeps the same O(1) behavior as `% capacity`, but avoids paying modulo
|
|
44
|
+
* cost for arbitrary capacities in the queue hot path. It is private because
|
|
45
|
+
* it only exists to speed up internal queue pointer movement.
|
|
46
|
+
*/
|
|
47
|
+
function advanceIndex(index, capacity) {
|
|
48
|
+
const next = index + 1;
|
|
49
|
+
return next === capacity ? 0 : next;
|
|
50
|
+
}
|
|
51
|
+
////////////////////////////
|
|
52
|
+
// Factory & Core Setup //
|
|
53
|
+
////////////////////////////
|
|
54
|
+
/**
|
|
55
|
+
* Creates a new empty queue with the specified capacity.
|
|
56
|
+
*
|
|
57
|
+
* The queue uses a circular buffer internally, which means operations
|
|
58
|
+
* like enqueue and dequeue run in constant O(1) time regardless of
|
|
59
|
+
* queue size.
|
|
60
|
+
*
|
|
61
|
+
* @param capacity - Maximum number of elements the queue can hold (default: 1000)
|
|
62
|
+
* @returns A new empty queue ready for use
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```
|
|
66
|
+
* const messageQueue = createQueue<string>(50); // for messages
|
|
67
|
+
* const numberQueue = createQueue<number>(); // uses default capacity
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function createQueue(capacity = 1000) {
|
|
71
|
+
return {
|
|
72
|
+
items: new Array(capacity),
|
|
73
|
+
head: 0,
|
|
74
|
+
tail: 0,
|
|
75
|
+
size: 0,
|
|
76
|
+
capacity,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/////////////////////////
|
|
80
|
+
// Core Queue Operations //
|
|
81
|
+
/////////////////////////
|
|
82
|
+
/**
|
|
83
|
+
* Adds an element to the back of the queue (FIFO: last in, first served).
|
|
84
|
+
* Runs in O(1) constant time.
|
|
85
|
+
*
|
|
86
|
+
* @param queue - The target queue
|
|
87
|
+
* @param item - Element to add to the queue
|
|
88
|
+
* @throws Error if the queue is at capacity
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```
|
|
92
|
+
* enqueue(userQueue, { id: 123, name: 'Alice' });
|
|
93
|
+
* enqueue(userQueue, { id: 124, name: 'Bob' });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export function enqueue(queue, item) {
|
|
97
|
+
if (isFull(queue)) {
|
|
98
|
+
throw new Error(`Queue overflow: cannot add item, capacity ${queue.capacity} reached`);
|
|
99
|
+
}
|
|
100
|
+
queue.items[queue.tail] = item;
|
|
101
|
+
queue.tail = advanceIndex(queue.tail, queue.capacity);
|
|
102
|
+
queue.size++;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Removes and returns the front element from the queue (FIFO: first in, first out).
|
|
106
|
+
* Runs in O(1) constant time.
|
|
107
|
+
*
|
|
108
|
+
* @param queue - The target queue
|
|
109
|
+
* @returns The front element, or undefined if queue is empty
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```
|
|
113
|
+
* const nextTask = dequeue(taskQueue);
|
|
114
|
+
* if (nextTask) {
|
|
115
|
+
* console.log('Processing:', nextTask);
|
|
116
|
+
* }
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export function dequeue(queue) {
|
|
120
|
+
if (isEmpty(queue)) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const item = queue.items[queue.head];
|
|
124
|
+
queue.items[queue.head] = undefined; // help garbage collector
|
|
125
|
+
queue.head = advanceIndex(queue.head, queue.capacity);
|
|
126
|
+
queue.size--;
|
|
127
|
+
return item;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Returns the front element without removing it from the queue.
|
|
131
|
+
* Useful for checking what's next without consuming it.
|
|
132
|
+
* Runs in O(1) constant time.
|
|
133
|
+
*
|
|
134
|
+
* @param queue - The target queue
|
|
135
|
+
* @returns The front element, or undefined if queue is empty
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```
|
|
139
|
+
* const nextInLine = peek(queue);
|
|
140
|
+
* if (nextInLine?.priority === 'urgent') {
|
|
141
|
+
* // handle urgent task immediately
|
|
142
|
+
* dequeue(queue);
|
|
143
|
+
* }
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export function peek(queue) {
|
|
147
|
+
return isEmpty(queue) ? undefined : queue.items[queue.head];
|
|
148
|
+
}
|
|
149
|
+
////////////////////////////////
|
|
150
|
+
// Utility & Status Functions //
|
|
151
|
+
////////////////////////////////
|
|
152
|
+
/**
|
|
153
|
+
* Checks if the queue contains no elements.
|
|
154
|
+
*
|
|
155
|
+
* @param queue - The target queue
|
|
156
|
+
* @returns true if the queue is empty, false otherwise
|
|
157
|
+
*/
|
|
158
|
+
export function isEmpty(queue) {
|
|
159
|
+
return queue.size === 0;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Checks if the queue has reached its maximum capacity.
|
|
163
|
+
*
|
|
164
|
+
* @param queue - The target queue
|
|
165
|
+
* @returns true if the queue is full, false otherwise
|
|
166
|
+
*/
|
|
167
|
+
export function isFull(queue) {
|
|
168
|
+
return queue.size >= queue.capacity;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Returns the current number of elements in the queue.
|
|
172
|
+
*
|
|
173
|
+
* @param queue - The target queue
|
|
174
|
+
* @returns Current queue size (0 to capacity)
|
|
175
|
+
*/
|
|
176
|
+
export function getSize(queue) {
|
|
177
|
+
return queue.size;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Returns how many more elements can be added before hitting capacity.
|
|
181
|
+
*
|
|
182
|
+
* @param queue - The target queue
|
|
183
|
+
* @returns Number of available slots
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```
|
|
187
|
+
* if (remainingSpace(queue) < 10) {
|
|
188
|
+
* console.warn('Queue nearly full, consider processing items');
|
|
189
|
+
* }
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
export function remainingSpace(queue) {
|
|
193
|
+
return queue.capacity - queue.size;
|
|
194
|
+
}
|
|
195
|
+
/////////////////////////////
|
|
196
|
+
// Advanced Utility Functions //
|
|
197
|
+
/////////////////////////////
|
|
198
|
+
/**
|
|
199
|
+
* Empties the queue instantly using the `.length = 0` optimization[87][90].
|
|
200
|
+
* This immediately releases all object references for garbage collection,
|
|
201
|
+
* making it much faster than dequeuing items one by one.
|
|
202
|
+
*
|
|
203
|
+
* Runs in O(1) constant time regardless of queue size.
|
|
204
|
+
*
|
|
205
|
+
* @param queue - The target queue
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```
|
|
209
|
+
* // Instead of: while (!isEmpty(queue)) dequeue(queue); // O(n)
|
|
210
|
+
* clear(queue); // O(1) - much faster!
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
export function clear(queue) {
|
|
214
|
+
// Fast array truncation - instantly releases references for GC[87][90]
|
|
215
|
+
queue.items.length = 0;
|
|
216
|
+
queue.items.length = queue.capacity; // restore original capacity
|
|
217
|
+
// Reset pointers
|
|
218
|
+
queue.head = 0;
|
|
219
|
+
queue.tail = 0;
|
|
220
|
+
queue.size = 0;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Creates a new array containing all queue elements in order (front to back).
|
|
224
|
+
* Useful for debugging, logging, or when you need array methods.
|
|
225
|
+
*
|
|
226
|
+
* Note: This is O(n) operation - use sparingly in performance-critical code.
|
|
227
|
+
*
|
|
228
|
+
* @param queue - The source queue
|
|
229
|
+
* @returns New array with queue elements in FIFO order
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```
|
|
233
|
+
* const queueSnapshot = toArray(queue);
|
|
234
|
+
* console.log('Current queue:', queueSnapshot.join(' -> '));
|
|
235
|
+
*
|
|
236
|
+
* // Process without modifying original queue
|
|
237
|
+
* const urgentItems = queueSnapshot.filter(item => item.priority === 'urgent');
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
export function toArray(queue) {
|
|
241
|
+
if (isEmpty(queue)) {
|
|
242
|
+
return [];
|
|
243
|
+
}
|
|
244
|
+
const result = new Array(queue.size);
|
|
245
|
+
let index = queue.head;
|
|
246
|
+
for (let i = 0; i < queue.size; i++) {
|
|
247
|
+
result[i] = queue.items[index];
|
|
248
|
+
index = advanceIndex(index, queue.capacity);
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Applies a function to each element in the queue without modifying it.
|
|
254
|
+
* Elements are visited in FIFO order (front to back).
|
|
255
|
+
*
|
|
256
|
+
* @param queue - The target queue
|
|
257
|
+
* @param callback - Function to call for each element
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```
|
|
261
|
+
* // Log all pending tasks
|
|
262
|
+
* forEach(taskQueue, (task, index) => {
|
|
263
|
+
* console.log(`Task ${index + 1}: ${task.description}`);
|
|
264
|
+
* });
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
export function forEach(queue, callback) {
|
|
268
|
+
let index = queue.head;
|
|
269
|
+
for (let i = 0; i < queue.size; i++) {
|
|
270
|
+
callback(queue.items[index], i);
|
|
271
|
+
index = advanceIndex(index, queue.capacity);
|
|
272
|
+
}
|
|
273
|
+
}
|
package/esm/symbol.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* > Inspired by https://jsr.io/@nick/dispose/1.1.0/symbol.ts
|
|
3
|
+
*
|
|
4
|
+
* Extensions to the global Symbol constructor for interoperability with
|
|
5
|
+
* Observable.
|
|
6
|
+
*
|
|
7
|
+
* This interface extends the standard Symbol constructor with well-known
|
|
8
|
+
* symbols needed for Observable interoperability and resource cleanup:
|
|
9
|
+
*
|
|
10
|
+
* 1. `Symbol.observable`: For Observable interoperability (TC39 proposal)
|
|
11
|
+
*
|
|
12
|
+
* These symbols enable our implementation to work with:
|
|
13
|
+
* - Other Observable libraries via Symbol.observable
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* // Using Symbol.observable for interop
|
|
18
|
+
* const myObservable = {
|
|
19
|
+
* [Symbol.observable]() {
|
|
20
|
+
* return new Observable(observer => {
|
|
21
|
+
* observer.next('Hello');
|
|
22
|
+
* observer.complete();
|
|
23
|
+
* });
|
|
24
|
+
* }
|
|
25
|
+
* };
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @module
|
|
29
|
+
*/
|
|
30
|
+
export interface SymbolConstructor extends Omit<typeof globalThis.Symbol, "observable"> {
|
|
31
|
+
/**
|
|
32
|
+
* Well-known symbol for Observable interoperability.
|
|
33
|
+
*
|
|
34
|
+
* This symbol allows any object to define how it converts to an Observable.
|
|
35
|
+
* Objects with a `[Symbol.observable]()` method can be passed directly to
|
|
36
|
+
* `Observable.from()` and will be properly converted.
|
|
37
|
+
*
|
|
38
|
+
* This is analogous to how `Symbol.iterator` enables iteration interop.
|
|
39
|
+
*
|
|
40
|
+
* @see {@link https://github.com/tc39/proposal-observable | TC39 Observable proposal}
|
|
41
|
+
*/
|
|
42
|
+
readonly observable: unique symbol;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Provides a cross-platform Symbol implementation with Observable
|
|
46
|
+
* and resource management symbols.
|
|
47
|
+
*
|
|
48
|
+
* This implementation:
|
|
49
|
+
* 1. Uses the native Symbol if available
|
|
50
|
+
* 2. Falls back to a polyfill if Symbol is not supported
|
|
51
|
+
* 3. Adds our special symbols if they don't exist natively
|
|
52
|
+
*
|
|
53
|
+
* The polyfill is lightweight and provides basic Symbol functionality
|
|
54
|
+
* for environments that don't support it natively.
|
|
55
|
+
*
|
|
56
|
+
* Note: The polyfill does not implement the full Symbol specification
|
|
57
|
+
* and is intended only for basic interoperability in legacy environments.
|
|
58
|
+
*/
|
|
59
|
+
export declare const Symbol: SymbolConstructor;
|
|
60
|
+
//# sourceMappingURL=symbol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symbol.d.ts","sourceRoot":"","sources":["../src/symbol.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,WAAW,iBACf,SAAQ,IAAI,CAAC,OAAO,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC;IACpD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,MAAM,CAAC;CACpC;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,EAAE,iBAIiB,CAAC"}
|
package/esm/symbol.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides a cross-platform Symbol implementation with Observable
|
|
3
|
+
* and resource management symbols.
|
|
4
|
+
*
|
|
5
|
+
* This implementation:
|
|
6
|
+
* 1. Uses the native Symbol if available
|
|
7
|
+
* 2. Falls back to a polyfill if Symbol is not supported
|
|
8
|
+
* 3. Adds our special symbols if they don't exist natively
|
|
9
|
+
*
|
|
10
|
+
* The polyfill is lightweight and provides basic Symbol functionality
|
|
11
|
+
* for environments that don't support it natively.
|
|
12
|
+
*
|
|
13
|
+
* Note: The polyfill does not implement the full Symbol specification
|
|
14
|
+
* and is intended only for basic interoperability in legacy environments.
|
|
15
|
+
*/
|
|
16
|
+
export const Symbol = (globalThis.Symbol ??
|
|
17
|
+
((description) => ({
|
|
18
|
+
description,
|
|
19
|
+
toString: () => `Symbol(${description})`,
|
|
20
|
+
})));
|
|
21
|
+
/**
|
|
22
|
+
* Adds Symbol.dispose if it doesn't exist natively.
|
|
23
|
+
*
|
|
24
|
+
* Symbol.dispose enables automatic resource cleanup using the `using` declaration.
|
|
25
|
+
* When a variable declared with `using` goes out of scope, its `[Symbol.dispose]()`
|
|
26
|
+
* method is called automatically, ensuring cleanup happens even if errors occur.
|
|
27
|
+
*
|
|
28
|
+
* @example Basic resource cleanup with using
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { Observable } from './observable.ts';
|
|
31
|
+
*
|
|
32
|
+
* {
|
|
33
|
+
* using subscription = Observable.of(1, 2, 3).subscribe({
|
|
34
|
+
* next: (val) => console.log('Value:', val)
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* // Use the subscription here
|
|
38
|
+
* // ...
|
|
39
|
+
* } // subscription.unsubscribe() called automatically at block end
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @example Automatic cleanup on error
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { Observable } from './observable.ts';
|
|
45
|
+
*
|
|
46
|
+
* function processData() {
|
|
47
|
+
* using sub = Observable.from(dataStream).subscribe({
|
|
48
|
+
* next: (data) => processItem(data)
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* if (invalidCondition) {
|
|
52
|
+
* throw new Error('Processing failed');
|
|
53
|
+
* }
|
|
54
|
+
* // sub.unsubscribe() called even if error thrown
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
if (typeof globalThis.Symbol === "function" &&
|
|
59
|
+
typeof Symbol.dispose !== "symbol") {
|
|
60
|
+
Reflect.defineProperty(Symbol, "dispose", {
|
|
61
|
+
// deno-lint-ignore no-explicit-any
|
|
62
|
+
value: Symbol("Symbol.dispose"),
|
|
63
|
+
enumerable: false,
|
|
64
|
+
configurable: false,
|
|
65
|
+
writable: false,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Adds Symbol.asyncDispose if it doesn't exist natively.
|
|
70
|
+
*
|
|
71
|
+
* Symbol.asyncDispose enables automatic async resource cleanup using `await using`.
|
|
72
|
+
* When a variable declared with `await using` goes out of scope, its
|
|
73
|
+
* `[Symbol.asyncDispose]()` method is called and awaited automatically,
|
|
74
|
+
* ensuring async cleanup (like closing connections) happens safely.
|
|
75
|
+
*
|
|
76
|
+
* @example Async resource cleanup with await using
|
|
77
|
+
* ```ts
|
|
78
|
+
* import { Observable } from './observable.ts';
|
|
79
|
+
*
|
|
80
|
+
* async function streamData() {
|
|
81
|
+
* await using sub = Observable.of(1, 2, 3).subscribe({
|
|
82
|
+
* next: async (data) => await saveData(data)
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* // Use the subscription here
|
|
86
|
+
* // ...
|
|
87
|
+
* } // sub.unsubscribe() (or async dispose) awaited automatically at block end
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @example Guaranteed async cleanup on error
|
|
91
|
+
* ```ts
|
|
92
|
+
* import { Observable } from './observable.ts';
|
|
93
|
+
*
|
|
94
|
+
* async function fetchAndProcess() {
|
|
95
|
+
* await using sub = Observable.from(apiStream).subscribe({
|
|
96
|
+
* next: async (item) => await processAsync(item)
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* if (errorCondition) {
|
|
100
|
+
* throw new Error('Failed');
|
|
101
|
+
* }
|
|
102
|
+
* // Async cleanup guaranteed even if error thrown
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
if (typeof globalThis.Symbol === "function" &&
|
|
107
|
+
typeof Symbol.asyncDispose !== "symbol") {
|
|
108
|
+
Reflect.defineProperty(Symbol, "asyncDispose", {
|
|
109
|
+
// deno-lint-ignore no-explicit-any
|
|
110
|
+
value: Symbol("Symbol.asyncDispose"),
|
|
111
|
+
enumerable: false,
|
|
112
|
+
configurable: false,
|
|
113
|
+
writable: false,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Adds Symbol.observable if it doesn't exist natively.
|
|
118
|
+
*
|
|
119
|
+
* This ensures Symbol.observable is available for Observable
|
|
120
|
+
* interoperability, even in environments that don't support
|
|
121
|
+
* it natively.
|
|
122
|
+
*/
|
|
123
|
+
if (typeof globalThis.Symbol === "function" &&
|
|
124
|
+
typeof Symbol.observable !== "symbol") {
|
|
125
|
+
Reflect.defineProperty(Symbol, "observable", {
|
|
126
|
+
// deno-lint-ignore no-explicit-any
|
|
127
|
+
value: Symbol("Symbol.observable"),
|
|
128
|
+
enumerable: false,
|
|
129
|
+
configurable: false,
|
|
130
|
+
writable: false,
|
|
131
|
+
});
|
|
132
|
+
}
|