atomic-fns 1.2.0 → 2.0.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.
Files changed (216) hide show
  1. package/README.md +397 -91
  2. package/dist/array/index.d.ts +9 -0
  3. package/dist/array/index.js +9 -0
  4. package/dist/array/list.d.ts +99 -0
  5. package/dist/array/list.js +133 -0
  6. package/dist/array/sets.d.ts +130 -0
  7. package/dist/array/sets.js +213 -0
  8. package/dist/async/index.d.ts +6 -0
  9. package/dist/async/index.js +6 -0
  10. package/dist/async/retry.d.ts +38 -0
  11. package/dist/async/retry.js +56 -0
  12. package/dist/async/sleep.d.ts +42 -0
  13. package/dist/async/sleep.js +76 -0
  14. package/dist/collections/bisect.d.ts +103 -0
  15. package/dist/collections/bisect.js +157 -0
  16. package/dist/collections/deque.d.ts +67 -97
  17. package/dist/collections/deque.js +197 -256
  18. package/dist/collections/entries.d.ts +89 -0
  19. package/dist/collections/entries.js +131 -0
  20. package/dist/collections/frozen-set.d.ts +42 -0
  21. package/dist/collections/frozen-set.js +64 -0
  22. package/dist/collections/group.d.ts +141 -0
  23. package/dist/collections/group.js +241 -0
  24. package/dist/collections/heap.d.ts +64 -0
  25. package/dist/collections/heap.js +205 -0
  26. package/dist/collections/index.d.ts +15 -623
  27. package/dist/collections/index.js +14 -844
  28. package/dist/collections/internal/arrayKeys.d.ts +19 -0
  29. package/dist/collections/internal/arrayKeys.js +83 -0
  30. package/dist/collections/internal/invariants.d.ts +4 -0
  31. package/dist/collections/internal/invariants.js +12 -0
  32. package/dist/collections/internal/iterable.d.ts +25 -0
  33. package/dist/collections/internal/iterable.js +62 -0
  34. package/dist/collections/iterate.d.ts +162 -0
  35. package/dist/collections/iterate.js +188 -0
  36. package/dist/collections/lru-cache.d.ts +58 -0
  37. package/dist/collections/lru-cache.js +164 -0
  38. package/dist/collections/order.d.ts +19 -0
  39. package/dist/collections/order.js +38 -0
  40. package/dist/collections/shape.d.ts +32 -0
  41. package/dist/collections/shape.js +86 -0
  42. package/dist/collections/sorted-map.d.ts +171 -0
  43. package/dist/collections/sorted-map.js +845 -0
  44. package/dist/collections/sorted-set.d.ts +103 -0
  45. package/dist/collections/sorted-set.js +147 -0
  46. package/dist/collections/splay-tree.d.ts +82 -0
  47. package/dist/collections/splay-tree.js +354 -0
  48. package/dist/collections/trie.d.ts +58 -0
  49. package/dist/collections/trie.js +196 -0
  50. package/dist/decimal/currency.d.ts +211 -0
  51. package/dist/decimal/currency.js +321 -0
  52. package/dist/decimal/decimal.d.ts +299 -0
  53. package/dist/decimal/decimal.js +660 -0
  54. package/dist/decimal/index.d.ts +11 -148
  55. package/dist/decimal/index.js +10 -410
  56. package/dist/decimal/internal/bits.d.ts +2 -0
  57. package/dist/decimal/internal/bits.js +7 -0
  58. package/dist/decimal/internal/echo.d.ts +4 -0
  59. package/dist/decimal/internal/echo.js +6 -0
  60. package/dist/decimal/internal/isqrt.d.ts +9 -0
  61. package/dist/decimal/internal/isqrt.js +34 -0
  62. package/dist/decimal/internal/locale.d.ts +7 -0
  63. package/dist/decimal/internal/locale.js +24 -0
  64. package/dist/decimal/internal/minor-units.d.ts +2 -0
  65. package/dist/decimal/internal/minor-units.js +33 -0
  66. package/dist/decimal/internal/pow10.d.ts +24 -0
  67. package/dist/decimal/internal/pow10.js +96 -0
  68. package/dist/encoding/base64.d.ts +39 -0
  69. package/dist/encoding/base64.js +53 -0
  70. package/dist/encoding/hex.d.ts +23 -0
  71. package/dist/encoding/hex.js +34 -0
  72. package/dist/encoding/index.d.ts +6 -0
  73. package/dist/encoding/index.js +6 -0
  74. package/dist/function/debounce.d.ts +68 -0
  75. package/dist/function/debounce.js +203 -0
  76. package/dist/function/index.d.ts +6 -0
  77. package/dist/function/index.js +6 -0
  78. package/dist/function/shared.d.ts +2 -0
  79. package/dist/function/shared.js +5 -0
  80. package/dist/function/wrap.d.ts +130 -0
  81. package/dist/function/wrap.js +113 -0
  82. package/dist/hash/digest.d.ts +18 -0
  83. package/dist/hash/digest.js +26 -0
  84. package/dist/hash/hash.d.ts +22 -0
  85. package/dist/hash/hash.js +252 -0
  86. package/dist/hash/hashString.d.ts +13 -0
  87. package/dist/hash/hashString.js +53 -0
  88. package/dist/hash/index.d.ts +8 -0
  89. package/dist/hash/index.js +8 -0
  90. package/dist/hash/stableStringify.d.ts +19 -0
  91. package/dist/hash/stableStringify.js +102 -0
  92. package/dist/id/index.d.ts +7 -0
  93. package/dist/id/index.js +7 -0
  94. package/dist/id/nanoid.d.ts +16 -0
  95. package/dist/id/nanoid.js +65 -0
  96. package/dist/id/uniqueId.d.ts +14 -0
  97. package/dist/id/uniqueId.js +20 -0
  98. package/dist/id/uuid.d.ts +25 -0
  99. package/dist/id/uuid.js +64 -0
  100. package/dist/index.d.ts +15 -8
  101. package/dist/index.js +15 -8
  102. package/dist/internal/bytes.d.ts +11 -0
  103. package/dist/internal/bytes.js +33 -0
  104. package/dist/internal/codec.d.ts +11 -0
  105. package/dist/internal/codec.js +84 -0
  106. package/dist/internal/compare.d.ts +10 -0
  107. package/dist/internal/compare.js +26 -0
  108. package/dist/internal/crypto.d.ts +5 -0
  109. package/dist/internal/crypto.js +11 -0
  110. package/dist/internal/keys.d.ts +12 -0
  111. package/dist/internal/keys.js +23 -0
  112. package/dist/internal/kind.d.ts +44 -0
  113. package/dist/internal/kind.js +139 -0
  114. package/dist/internal/sparse.d.ts +51 -0
  115. package/dist/internal/sparse.js +104 -0
  116. package/dist/internal/text.d.ts +7 -0
  117. package/dist/internal/text.js +15 -0
  118. package/dist/internal/timer.d.ts +10 -0
  119. package/dist/internal/timer.js +17 -0
  120. package/dist/internal/truncate.d.ts +10 -0
  121. package/dist/internal/truncate.js +22 -0
  122. package/dist/internal/walk.d.ts +47 -0
  123. package/dist/internal/walk.js +100 -0
  124. package/dist/is/index.d.ts +8 -0
  125. package/dist/is/index.js +8 -0
  126. package/dist/is/isArrayLike.d.ts +18 -0
  127. package/dist/is/isArrayLike.js +25 -0
  128. package/dist/is/isError.d.ts +13 -0
  129. package/dist/is/isError.js +18 -0
  130. package/dist/is/isNil.d.ts +12 -0
  131. package/dist/is/isNil.js +14 -0
  132. package/dist/is/isPlainObject.d.ts +15 -0
  133. package/dist/is/isPlainObject.js +34 -0
  134. package/dist/number/index.d.ts +7 -0
  135. package/dist/number/index.js +7 -0
  136. package/dist/number/round.d.ts +86 -0
  137. package/dist/number/round.js +130 -0
  138. package/dist/number/stats.d.ts +52 -0
  139. package/dist/number/stats.js +115 -0
  140. package/dist/object/cloneDeep.d.ts +28 -0
  141. package/dist/object/cloneDeep.js +200 -0
  142. package/dist/object/index.d.ts +14 -0
  143. package/dist/object/index.js +13 -0
  144. package/dist/object/isEqual.d.ts +64 -0
  145. package/dist/object/isEqual.js +289 -0
  146. package/dist/object/matches.d.ts +40 -0
  147. package/dist/object/matches.js +284 -0
  148. package/dist/object/merge.d.ts +66 -0
  149. package/dist/object/merge.js +272 -0
  150. package/dist/object/parsePath.d.ts +22 -0
  151. package/dist/object/parsePath.js +111 -0
  152. package/dist/object/path.d.ts +85 -0
  153. package/dist/object/path.js +208 -0
  154. package/dist/object/pick.d.ts +91 -0
  155. package/dist/object/pick.js +180 -0
  156. package/dist/object/reshape.d.ts +73 -0
  157. package/dist/object/reshape.js +144 -0
  158. package/dist/random/index.d.ts +96 -32
  159. package/dist/random/index.js +215 -53
  160. package/dist/string/case.d.ts +71 -0
  161. package/dist/string/case.js +152 -0
  162. package/dist/string/fold.d.ts +35 -0
  163. package/dist/string/fold.js +100 -0
  164. package/dist/string/index.d.ts +6 -187
  165. package/dist/string/index.js +6 -224
  166. package/dist/string/truncate.d.ts +25 -0
  167. package/dist/string/truncate.js +44 -0
  168. package/dist/string/words.d.ts +27 -0
  169. package/dist/string/words.js +241 -0
  170. package/package.json +99 -51
  171. package/dist/collections/BTree.d.ts +0 -230
  172. package/dist/collections/BTree.js +0 -1143
  173. package/dist/collections/Heap.d.ts +0 -69
  174. package/dist/collections/Heap.js +0 -181
  175. package/dist/collections/LRUCache.d.ts +0 -83
  176. package/dist/collections/LRUCache.js +0 -139
  177. package/dist/collections/SortedMap.d.ts +0 -92
  178. package/dist/collections/SortedMap.js +0 -131
  179. package/dist/collections/SortedSet.d.ts +0 -69
  180. package/dist/collections/SortedSet.js +0 -99
  181. package/dist/collections/SortedTree.d.ts +0 -103
  182. package/dist/collections/SortedTree.js +0 -142
  183. package/dist/collections/SplayTree.d.ts +0 -107
  184. package/dist/collections/SplayTree.js +0 -351
  185. package/dist/collections/Trie.d.ts +0 -42
  186. package/dist/collections/Trie.js +0 -104
  187. package/dist/collections/abc.d.ts +0 -152
  188. package/dist/collections/abc.js +0 -39
  189. package/dist/collections/frozenset.d.ts +0 -19
  190. package/dist/collections/frozenset.js +0 -33
  191. package/dist/functools/index.d.ts +0 -106
  192. package/dist/functools/index.js +0 -203
  193. package/dist/globals/index.d.ts +0 -268
  194. package/dist/globals/index.js +0 -447
  195. package/dist/i18n/currency.d.ts +0 -27
  196. package/dist/i18n/currency.js +0 -100
  197. package/dist/i18n/date/index.d.ts +0 -210
  198. package/dist/i18n/date/index.js +0 -552
  199. package/dist/i18n/date/utils.d.ts +0 -64
  200. package/dist/i18n/date/utils.js +0 -192
  201. package/dist/i18n/duration.d.ts +0 -113
  202. package/dist/i18n/duration.js +0 -398
  203. package/dist/i18n/format.d.ts +0 -34
  204. package/dist/i18n/format.js +0 -378
  205. package/dist/i18n/index.d.ts +0 -9
  206. package/dist/i18n/index.js +0 -8
  207. package/dist/itertools/index.d.ts +0 -251
  208. package/dist/itertools/index.js +0 -434
  209. package/dist/math/index.d.ts +0 -79
  210. package/dist/math/index.js +0 -81
  211. package/dist/mod.d.ts +0 -1
  212. package/dist/mod.js +0 -1
  213. package/dist/operators/index.d.ts +0 -148
  214. package/dist/operators/index.js +0 -325
  215. package/dist/types.d.ts +0 -19
  216. package/dist/types.js +0 -1
@@ -1,298 +1,239 @@
1
- import { KeyError, ValueError } from '../globals/index.js';
2
- import { eq } from '../operators/index.js';
3
- import { Sequence } from './abc.js';
4
- function IterableIterator(next) {
5
- return {
6
- next,
7
- [Symbol.iterator]() {
8
- return this;
9
- }
10
- };
11
- }
1
+ import { assertNotHugeSparse } from './internal/arrayKeys.js';
2
+ import { sameValueZero } from '../internal/compare.js';
3
+ import { iteratesAsArray, requireIterable } from './internal/iterable.js';
4
+ const MIN_CAPACITY = 8;
12
5
  /**
13
- * Fixed capacity double-ended queue implemented as ring deque.
14
- * @template T
6
+ * A double-ended queue on a ring buffer, with Array's method names: `push` and `pop` at the end,
7
+ * `unshift` and `shift` at the front, `at` and `set` by index, all O(1) amortized. It grows by
8
+ * doubling when unbounded; with `maxlen` it evicts from the opposite end, as Python's `deque` does.
9
+ * `includes` uses SameValueZero.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const recent = new Deque<number>([], { maxlen: 3 })
14
+ * recent.push(1, 2, 3, 4)
15
+ * ;[...recent] // [2, 3, 4]
16
+ * recent.shift() // 2
17
+ * ```
15
18
  */
16
- export class Deque extends Sequence {
17
- items;
18
- start = 0;
19
- count = 0;
20
- capacity;
21
- ArrayConstructor;
22
- /**
23
- * Creates a new `Deque` instance of a fixed size.
24
- * @param {Array} [arrType = []] The initial elements or array type to use (accepts any kind of typed array).
25
- * @param {number} [capacity=1024] The fixed size of the deque. Defaults to `1024`.
26
- */
27
- constructor(arrType = [], capacity = 1024) {
28
- super();
29
- if (typeof capacity !== 'number' || capacity <= 0)
30
- throw new ValueError(`Deque capacity should be a positive integer.`);
31
- this.ArrayConstructor = arrType.constructor;
32
- this.capacity = capacity;
33
- // A typed array cannot grow, so it takes the whole capacity up front
34
- const length = ArrayBuffer.isView(arrType) ? capacity : arrType.length || capacity;
35
- this.items = new this.ArrayConstructor(length);
36
- this.clear();
37
- if (arrType.length) {
38
- for (const item of arrType) {
39
- this.append(item);
40
- }
19
+ export class Deque {
20
+ #buf;
21
+ #cap;
22
+ #head = 0;
23
+ #size = 0;
24
+ #maxlen;
25
+ #arrType;
26
+ #empty;
27
+ /**
28
+ * Create a deque holding `items`, in order.
29
+ * @param items Initial elements, read one at a time. When longer than `maxlen`, only the last
30
+ * `maxlen` remain.
31
+ * @param options.maxlen Maximum size; overflow evicts from the opposite end. `0` makes push/unshift
32
+ * no-ops. `null`, `undefined` and `Infinity` mean unbounded.
33
+ * @param options.arrType Typed-array (or similar) constructor used for storage.
34
+ * @throws {TypeError} when `items` is not iterable, or `maxlen` is not a number, `null` or
35
+ * `undefined`.
36
+ * @throws {RangeError} when `maxlen` is negative, not an integer, or above
37
+ * `Number.MAX_SAFE_INTEGER`, or when `items` is a huge sparse array.
38
+ */
39
+ constructor(items, options) {
40
+ const maxlen = options?.maxlen ?? undefined;
41
+ if (maxlen !== undefined && typeof maxlen !== 'number') {
42
+ throw new TypeError('maxlen must be a number');
43
+ }
44
+ if (maxlen !== undefined &&
45
+ maxlen !== Infinity &&
46
+ (!Number.isInteger(maxlen) || maxlen < 0 || maxlen > Number.MAX_SAFE_INTEGER)) {
47
+ throw new RangeError('maxlen must be a non-negative integer <= Number.MAX_SAFE_INTEGER or Infinity');
48
+ }
49
+ this.#maxlen = maxlen === Infinity ? undefined : maxlen;
50
+ this.#arrType = options?.arrType;
51
+ this.#empty = this.#alloc(1)[0];
52
+ const source = requireIterable(items ?? []);
53
+ if (iteratesAsArray(source))
54
+ assertNotHugeSparse(source);
55
+ this.#cap = MIN_CAPACITY;
56
+ this.#buf = this.#alloc(this.#cap);
57
+ for (const x of source) {
58
+ this.#pushOne(x);
41
59
  }
42
60
  }
43
- /** Returns the total number of elements in the deque. */
61
+ /** The number of elements. */
44
62
  get size() {
45
- return this.count;
63
+ return this.#size;
46
64
  }
47
65
  /**
48
- * Method used to clear the structure.
66
+ * Maximum size when constructed with a finite `maxlen`, otherwise `undefined`.
49
67
  */
50
- clear() {
51
- // Properties
52
- this.start = 0;
53
- this.count = 0;
68
+ get maxlen() {
69
+ return this.#maxlen;
54
70
  }
55
- /**
56
- * Alias of {@link Deque.append}
57
- * @param {T} item Item to append.
58
- * @returns {number} Returns the new size of the deque.
59
- */
60
- add(item) {
61
- return this.append(item);
62
- }
63
- /**
64
- * Appends a new element to the end of the deque.
65
- * @param {T} item Item to append.
66
- * @returns {number} Returns the new size of the deque.
67
- */
68
- append(item) {
69
- if (this.count === this.capacity)
70
- this.popleft();
71
- const index = (this.start + this.count) % this.capacity;
72
- this.items[index] = item;
73
- return ++this.count;
71
+ /** `'Deque'`, for `Object.prototype.toString`. */
72
+ get [Symbol.toStringTag]() {
73
+ return 'Deque';
74
74
  }
75
- /**
76
- * Appends a new element to the beginning of the deque.
77
- * @param {T} item Item to prepend.
78
- * @returns {number} Returns the new size of the deque.
79
- */
80
- appendleft(item) {
81
- if (this.count === this.capacity)
82
- this.pop();
83
- let index = this.start - 1;
84
- if (this.start === 0)
85
- index = this.capacity - 1;
86
- this.items[index] = item;
87
- this.start = index;
88
- return ++this.count;
89
- }
90
- /**
91
- * Removes and returns the element at the end of the deque.
92
- * @returns {?T} Returns the popped item.
93
- */
94
- pop() {
95
- if (this.count === 0)
96
- return;
97
- const index = (this.start + this.count - 1) % this.capacity;
98
- this.count--;
99
- return this.items[index];
100
- }
101
- /**
102
- * Alias of {@link Deque.pop}
103
- * @returns {?T} Returns the popped item.
104
- */
105
- remove() {
106
- return this.pop();
107
- }
108
- /**
109
- * Removes and returns the element at the beginning of the deque.
110
- * @returns {?T} Returns the removed deque element.
111
- */
112
- popleft() {
113
- if (this.count === 0)
114
- return;
115
- const index = this.start;
116
- this.count--;
117
- this.start++;
118
- if (this.start === this.capacity)
119
- this.start = 0;
120
- return this.items[index];
75
+ /** Remove every element and give back the buffer a burst grew. */
76
+ clear() {
77
+ this.#cap = MIN_CAPACITY;
78
+ this.#buf = this.#alloc(this.#cap);
79
+ this.#head = 0;
80
+ this.#size = 0;
121
81
  }
122
82
  /**
123
- * Returns the element at the beginning of the deque.
124
- * @returns {?T} The element if exists
83
+ * Append one or more elements at the end.
84
+ * @returns The new size.
125
85
  */
126
- first() {
127
- if (this.count === 0)
128
- return;
129
- return this.items[this.start];
86
+ push(...xs) {
87
+ for (const x of xs)
88
+ this.#pushOne(x);
89
+ return this.#size;
130
90
  }
131
91
  /**
132
- * Returns the element at a specified index position in the deque.
133
- * @param {number} index The given index
134
- * @returns {?T} The element if exists
92
+ * Insert one or more elements at the front, preserving argument order.
93
+ * @returns The new size.
135
94
  */
136
- get(index) {
137
- if (index < 0)
138
- index += this.count;
139
- if (index < 0 || index >= this.count)
140
- return;
141
- return this.items[(this.start + index) % this.capacity];
95
+ unshift(...xs) {
96
+ for (let i = xs.length - 1; i >= 0; i--)
97
+ this.#unshiftOne(xs[i]);
98
+ return this.#size;
142
99
  }
143
100
  /**
144
- * Update the element at a given `index`.
145
- * @param {number} index The given index
101
+ * Remove and return the last element, or `undefined` when empty.
146
102
  */
147
- set(index, value) {
148
- if (index < 0)
149
- index += this.count;
150
- if (index < 0 || index >= this.count) {
151
- throw new KeyError(`Invalid index: ${index} not in Deque.`);
152
- }
153
- this.items[(this.start + index) % this.capacity] = value;
103
+ pop() {
104
+ if (this.#size === 0)
105
+ return undefined;
106
+ const j = this.#phys(this.#size - 1);
107
+ const x = this.#buf[j];
108
+ this.#buf[j] = this.#empty;
109
+ this.#size--;
110
+ return x;
154
111
  }
155
112
  /**
156
- * Check if a given element is in the deque.
157
- * @param {T} x The value to find
158
- * @returns {boolean} `true` if the value is found
113
+ * Remove and return the first element, or `undefined` when empty.
159
114
  */
160
- contains(x) {
161
- for (const value of this.values()) {
162
- if (eq(x, value))
163
- return true;
164
- }
165
- return false;
115
+ shift() {
116
+ if (this.#size === 0)
117
+ return undefined;
118
+ const x = this.#buf[this.#head];
119
+ this.#buf[this.#head] = this.#empty;
120
+ this.#head = (this.#head + 1) % this.#cap;
121
+ this.#size--;
122
+ return x;
166
123
  }
167
124
  /**
168
- * Returns the first element that matches the `iteratee` function.
169
- * @param {Iteratee<T>} iteratee A function that will be invoked per element
170
- * @returns {?T} The element if exists
125
+ * Element at index `i` (negative from the end). Out of range or empty -> `undefined`.
126
+ * The index coerces as in `Array.prototype.at`; values that coerce to `NaN` mean `0`.
171
127
  */
172
- find(iteratee) {
173
- for (const [key, value] of this.entries()) {
174
- if (iteratee(value, key, this))
175
- return value;
176
- }
128
+ at(i) {
129
+ const idx = this.#fromEnd(i);
130
+ if (idx < 0 || idx >= this.#size)
131
+ return undefined;
132
+ return this.#buf[this.#phys(idx)];
177
133
  }
178
134
  /**
179
- * Calls `iteratee` function for every element in the deque.
180
- * @param {Iteratee<T>} iteratee A function that will be invoked per element
135
+ * Replace the element at index `i` (negative from the end). The index coerces as in {@link at}.
136
+ * @returns `this`
137
+ * @throws {RangeError} when the index is out of range.
181
138
  */
182
- forEach(iteratee) {
183
- const c = this.capacity;
184
- const l = this.count;
185
- let i = this.start;
186
- let j = 0;
187
- while (j < l) {
188
- iteratee(this.items[i], j, this);
189
- i++;
190
- j++;
191
- if (i === c)
192
- i = 0;
139
+ set(i, v) {
140
+ const idx = this.#fromEnd(i);
141
+ if (idx < 0 || idx >= this.#size) {
142
+ throw new RangeError(`index ${String(i).slice(0, 40)} out of range`);
193
143
  }
144
+ this.#buf[this.#phys(idx)] = v;
145
+ return this;
194
146
  }
195
- /**
196
- * Returns a new array with all the elements in reverse order.
197
- * @returns {Array<T>} The elements reversed
198
- */
199
- reversed() {
200
- return this.toArray().reverse();
147
+ /** Whether `value` is present (SameValueZero). */
148
+ includes(value) {
149
+ return this.values().some((v) => sameValueZero(v, value));
201
150
  }
202
- /**
203
- * Returns a new array with all the elements in the order they were added to the deque.
204
- * @returns {Array<T>} The elements array
205
- */
206
- toArray() {
207
- // Optimization
208
- const offset = this.start + this.count;
209
- if (offset < this.capacity)
210
- return this.items.slice(this.start, offset);
211
- const array = new this.ArrayConstructor(this.count);
212
- const c = this.capacity;
213
- const l = this.count;
214
- let i = this.start;
215
- let j = 0;
216
- while (j < l) {
217
- array[j] = this.items[i];
218
- i++;
219
- j++;
220
- if (i === c)
221
- i = 0;
151
+ /** Call `callback(element, index, deque)` for each element, front to back. */
152
+ forEach(callback, thisArg) {
153
+ for (let i = 0; i < this.#size; i++) {
154
+ Reflect.apply(callback, thisArg, [this.#buf[this.#phys(i)], i, this]);
222
155
  }
223
- return array;
224
156
  }
225
- /**
226
- * Returns an iterator over the deque's values.
227
- * @returns {Iterator}
228
- */
229
- values() {
230
- const items = this.items;
231
- const c = this.capacity;
232
- const l = this.count;
233
- let i = this.start;
234
- let j = 0;
235
- return IterableIterator(() => {
236
- if (j >= l)
237
- return {
238
- done: true,
239
- value: undefined
240
- };
241
- const value = items[i];
242
- i++;
243
- j++;
244
- if (i === c)
245
- i = 0;
246
- return { value };
247
- });
157
+ /** The indices, front to back, as `Array.prototype.keys` gives them. */
158
+ *keys() {
159
+ for (let i = 0; i < this.#size; i++)
160
+ yield i;
248
161
  }
249
- /**
250
- * Alias of {@link Deque.values}. Returns iterator of values.
251
- */
252
- keys() {
253
- return this.values();
162
+ /** The elements, front to back. */
163
+ *values() {
164
+ for (let i = 0; i < this.#size; i++)
165
+ yield this.#buf[this.#phys(i)];
254
166
  }
255
- /**
256
- * Creates an iterator of `[index, value]` pairs for all elements in the deque.
257
- * @returns {Iterator}
258
- */
259
- entries() {
260
- const items = this.items;
261
- const c = this.capacity;
262
- const l = this.count;
263
- let i = this.start;
264
- let j = 0;
265
- return IterableIterator(() => {
266
- if (j >= l)
267
- return {
268
- done: true,
269
- value: undefined
270
- };
271
- const value = items[i];
272
- i++;
273
- if (i === c)
274
- i = 0;
275
- return {
276
- value: [j++, value]
277
- };
278
- });
167
+ /** `[index, element]` pairs, front to back. */
168
+ *entries() {
169
+ for (let i = 0; i < this.#size; i++)
170
+ yield [i, this.#buf[this.#phys(i)]];
279
171
  }
172
+ /** The elements, front to back. */
280
173
  [Symbol.iterator]() {
281
174
  return this.values();
282
175
  }
283
- [Symbol.for('nodejs.util.inspect.custom')]() {
284
- return this.inspect();
176
+ /** Index `i` as `Array.prototype.at` reads it: truncated, `NaN` as `0`, negative from the end. */
177
+ #fromEnd(i) {
178
+ const idx = Math.trunc(i) || 0;
179
+ return idx < 0 ? idx + this.#size : idx;
180
+ }
181
+ #phys(i) {
182
+ return (this.#head + i) % this.#cap;
183
+ }
184
+ #alloc(n) {
185
+ if (this.#arrType)
186
+ return new this.#arrType(n);
187
+ return new Array(n);
188
+ }
189
+ /** Double the buffer, clamped to `maxlen`. Called only when full and below `maxlen`. */
190
+ #grow() {
191
+ let newCap = this.#cap * 2;
192
+ if (this.#maxlen !== undefined)
193
+ newCap = Math.min(newCap, this.#maxlen);
194
+ const nb = this.#alloc(newCap);
195
+ for (let i = 0; i < this.#size; i++)
196
+ nb[i] = this.#buf[this.#phys(i)];
197
+ this.#buf = nb;
198
+ this.#cap = newCap;
199
+ this.#head = 0;
200
+ }
201
+ // Both inserts write the new slot before they move `#head` or `#size`, so a value that typed
202
+ // storage rejects leaves the deque as it was, the element it would evict included. At `maxlen`
203
+ // with a full buffer the new slot is the one being evicted, so the write itself evicts it.
204
+ #pushOne(x) {
205
+ if (this.#maxlen === 0)
206
+ return;
207
+ const atMaxlen = this.#size === this.#maxlen;
208
+ if (!atMaxlen && this.#size === this.#cap)
209
+ this.#grow();
210
+ const j = this.#phys(this.#size);
211
+ this.#buf[j] = x;
212
+ if (atMaxlen) {
213
+ if (j !== this.#head)
214
+ this.#buf[this.#head] = this.#empty;
215
+ this.#head = (this.#head + 1) % this.#cap;
216
+ }
217
+ else {
218
+ this.#size++;
219
+ }
285
220
  }
286
- // This is just for debugging in nodejs
287
- inspect() {
288
- const array = this.toArray();
289
- array.type = this.ArrayConstructor.name;
290
- array.capacity = this.capacity;
291
- // Trick so that node displays the name of the constructor
292
- Object.defineProperty(array, 'constructor', {
293
- value: Deque,
294
- enumerable: false
295
- });
296
- return array;
221
+ #unshiftOne(x) {
222
+ if (this.#maxlen === 0)
223
+ return;
224
+ const atMaxlen = this.#size === this.#maxlen;
225
+ if (!atMaxlen && this.#size === this.#cap)
226
+ this.#grow();
227
+ const j = (this.#head - 1 + this.#cap) % this.#cap;
228
+ this.#buf[j] = x;
229
+ if (atMaxlen) {
230
+ const back = this.#phys(this.#size - 1);
231
+ if (j !== back)
232
+ this.#buf[back] = this.#empty;
233
+ }
234
+ else {
235
+ this.#size++;
236
+ }
237
+ this.#head = j;
297
238
  }
298
239
  }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * What a collection holds: `keys`, `values`, `entries`, `size`, `isEmpty`, `includes`.
3
+ */
4
+ import { type Collection, type CollectionKey, type CollectionValue } from './shape.js';
5
+ /**
6
+ * The keys of `collection`: indices of an array (holes skipped), typed array, string (one per code
7
+ * point) or other iterable, the keys of a `Map`, the members of a `Set`, and the own enumerable
8
+ * string keys of any other object. `null`, `undefined`, numbers, booleans, bigints and symbols
9
+ * have none. Other iterables are consumed to obtain positions.
10
+ * @param collection The collection to read.
11
+ * @returns A new array of keys, in iteration order.
12
+ * @example
13
+ * ```ts
14
+ * keys({ a: 1, b: 2 }) // ['a', 'b']
15
+ * keys(new Map([['x', 1]])) // ['x']
16
+ * keys('héllo') // [0, 1, 2, 3, 4]
17
+ * ```
18
+ */
19
+ export declare function keys<C extends Collection>(collection: C): CollectionKey<C>[];
20
+ /**
21
+ * The values of `collection`, in the order {@link keys} gives their keys.
22
+ * @param collection The collection to read.
23
+ * @returns A new array of values.
24
+ * @example
25
+ * ```ts
26
+ * values({ a: 1, b: 2 }) // [1, 2]
27
+ * values(new Map([['x', 1]])) // [1]
28
+ * values('👍🏽!') // ['👍', '🏽', '!']
29
+ * ```
30
+ */
31
+ export declare function values<C extends Collection>(collection: C): CollectionValue<C>[];
32
+ /**
33
+ * The `[key, value]` pairs of `collection`, as `Map.prototype.entries` gives them.
34
+ * @param collection The collection to read.
35
+ * @returns A new array of pairs.
36
+ * @example
37
+ * ```ts
38
+ * entries({ a: 1 }) // [['a', 1]]
39
+ * entries(['x', 'y']) // [[0, 'x'], [1, 'y']]
40
+ * entries(new Set(['s'])) // [['s', 's']]
41
+ * ```
42
+ */
43
+ export declare function entries<C extends Collection>(collection: C): [CollectionKey<C>, CollectionValue<C>][];
44
+ /**
45
+ * How many entries `collection` has: the `size` of a `Map` or `Set`, the present elements of an
46
+ * array (holes do not count), the length of a typed array, the code points of a string, the own
47
+ * enumerable string keys of an object. An iterable that is none of these is read to its end to
48
+ * count it, so a one-shot iterator such as a generator is exhausted.
49
+ * @param collection The collection to measure.
50
+ * @returns The number of entries.
51
+ * @example
52
+ * ```ts
53
+ * size({ a: 1, b: 2 }) // 2
54
+ * size([1, , 3]) // 2
55
+ * size('👍🏽') // 2
56
+ * ```
57
+ */
58
+ export declare function size(collection: Collection): number;
59
+ /**
60
+ * True when `collection` has no entries, by the rules of {@link size}. An iterable is read only
61
+ * until its first element, and is then closed, so a one-shot iterator such as a generator has
62
+ * nothing left to give.
63
+ * @param collection The collection to test.
64
+ * @returns Whether it has no entries.
65
+ * @example
66
+ * ```ts
67
+ * isEmpty({}) // true
68
+ * isEmpty([, ,]) // true
69
+ * isEmpty(new Map([[1, 2]])) // false
70
+ * isEmpty(null) // true
71
+ * ```
72
+ */
73
+ export declare function isEmpty(collection: Collection): boolean;
74
+ /**
75
+ * True when `collection` holds `value`, compared with SameValueZero against its values (`NaN`
76
+ * finds `NaN`, `0` finds `-0`). For a string, `value` is a substring, as
77
+ * `String.prototype.includes` reads it. An iterable is read until the first match, where it is
78
+ * closed, or to its end, so a one-shot iterator such as a generator is used up either way.
79
+ * @param collection The collection to search.
80
+ * @param value The value to look for.
81
+ * @returns Whether it is there.
82
+ * @example
83
+ * ```ts
84
+ * includes({ a: 1 }, 1) // true
85
+ * includes(new Map([['k', NaN]]), NaN) // true
86
+ * includes('hello', 'ell') // true
87
+ * ```
88
+ */
89
+ export declare function includes<C extends Collection>(collection: C, value: C extends string ? string : CollectionValue<C>): boolean;