atomic-fns 1.1.7 → 1.2.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 (46) hide show
  1. package/README.md +51 -12
  2. package/dist/collections/BTree.d.ts +11 -10
  3. package/dist/collections/BTree.js +58 -80
  4. package/dist/collections/Heap.js +1 -1
  5. package/dist/collections/LRUCache.d.ts +6 -3
  6. package/dist/collections/LRUCache.js +24 -11
  7. package/dist/collections/SortedMap.js +2 -2
  8. package/dist/collections/SortedTree.d.ts +2 -2
  9. package/dist/collections/SortedTree.js +3 -2
  10. package/dist/collections/SplayTree.d.ts +7 -5
  11. package/dist/collections/SplayTree.js +39 -26
  12. package/dist/collections/Trie.d.ts +1 -1
  13. package/dist/collections/Trie.js +26 -26
  14. package/dist/collections/deque.d.ts +1 -1
  15. package/dist/collections/deque.js +17 -10
  16. package/dist/collections/frozenset.js +4 -1
  17. package/dist/collections/index.d.ts +13 -32
  18. package/dist/collections/index.js +210 -82
  19. package/dist/decimal/index.d.ts +5 -2
  20. package/dist/decimal/index.js +63 -27
  21. package/dist/functools/index.d.ts +6 -30
  22. package/dist/functools/index.js +24 -56
  23. package/dist/globals/index.d.ts +3 -20
  24. package/dist/globals/index.js +23 -39
  25. package/dist/i18n/currency.d.ts +3 -0
  26. package/dist/i18n/currency.js +22 -7
  27. package/dist/i18n/date/index.d.ts +17 -10
  28. package/dist/i18n/date/index.js +79 -58
  29. package/dist/i18n/date/utils.d.ts +4 -5
  30. package/dist/i18n/date/utils.js +15 -113
  31. package/dist/i18n/duration.d.ts +11 -10
  32. package/dist/i18n/duration.js +38 -32
  33. package/dist/i18n/format.d.ts +5 -2
  34. package/dist/i18n/format.js +81 -209
  35. package/dist/i18n/index.d.ts +2 -1
  36. package/dist/itertools/index.d.ts +9 -13
  37. package/dist/itertools/index.js +38 -41
  38. package/dist/math/index.d.ts +10 -27
  39. package/dist/math/index.js +16 -33
  40. package/dist/operators/index.d.ts +1 -5
  41. package/dist/operators/index.js +60 -40
  42. package/dist/random/index.js +9 -6
  43. package/dist/string/index.d.ts +1 -1
  44. package/dist/string/index.js +2 -4
  45. package/dist/types.d.ts +3 -3
  46. package/package.json +16 -21
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * @module collections
5
5
  */
6
- import { call, get, isArray, isArrayLike, isBool, isEmpty, isFunction, isIterable, isNull, isNumber, isObject, isString, keys } from '../globals/index.js';
6
+ import { call, get, isArrayLike, isDate, isEmpty, isFunction, isIterable, isNull, isObject, isRegExp } from '../globals/index.js';
7
7
  import { enumerate } from '../itertools/index.js';
8
- import { compare, eq, id } from '../operators/index.js';
8
+ import { compare, eq, identity } from '../operators/index.js';
9
9
  export * from './abc.js';
10
10
  export * from './BTree.js';
11
11
  export * from './deque.js';
@@ -17,15 +17,30 @@ export * from './SortedSet.js';
17
17
  export * from './SortedTree.js';
18
18
  export * from './SplayTree.js';
19
19
  export * from './Trie.js';
20
+ /** Assigns `key`, defining it where a plain write would set the prototype instead. */
21
+ function setOwn(obj, key, value) {
22
+ if (typeof key === 'string' && key !== '__proto__') {
23
+ obj[key] = value;
24
+ }
25
+ else {
26
+ Object.defineProperty(obj, key, { value, enumerable: true, writable: true, configurable: true });
27
+ }
28
+ }
29
+ /** `isEmpty` counts declared parameters and keys, which says nothing about these values. */
30
+ function isBlank(x) {
31
+ if (isPlainObject(x))
32
+ return Object.keys(x).length === 0;
33
+ return isEmpty(x) && typeof x !== 'function' && !isDate(x) && !isRegExp(x);
34
+ }
20
35
  export function compact(arr) {
21
36
  if (!arr)
22
37
  return;
23
38
  if (Array.isArray(arr))
24
- return arr.filter((x) => !isEmpty(x));
39
+ return arr.filter((x) => !isBlank(x));
25
40
  const result = {};
26
41
  for (const key of Object.keys(arr)) {
27
- if (!isEmpty(arr[key])) {
28
- result[key] = arr[key];
42
+ if (!isBlank(arr[key])) {
43
+ setOwn(result, key, arr[key]);
29
44
  }
30
45
  }
31
46
  return result;
@@ -34,7 +49,7 @@ export function count(obj, func) {
34
49
  const counters = {};
35
50
  forEach(obj, (value, key) => {
36
51
  const result = func(value, key);
37
- counters[result] = get(result, counters, 0) + 1;
52
+ setOwn(counters, result, Object.hasOwn(counters, result) ? counters[result] + 1 : 1);
38
53
  });
39
54
  return counters;
40
55
  }
@@ -54,6 +69,12 @@ export function find(arr, fn) {
54
69
  if (Array.isArray(arr)) {
55
70
  return arr.find(it);
56
71
  }
72
+ else if (isIterable(arr)) {
73
+ for (const [index, value] of enumerate(arr)) {
74
+ if (it(value, index, arr))
75
+ return value;
76
+ }
77
+ }
57
78
  else if (isObject(arr)) {
58
79
  for (const key of Object.keys(arr)) {
59
80
  if (it(arr[key], key, arr)) {
@@ -94,17 +115,34 @@ filter(objects, matches({ a: 4, c: 6 }))
94
115
  * @returns
95
116
  */
96
117
  export function matches(shape) {
97
- return function (obj) {
118
+ return (obj) => {
98
119
  if (!shape || !obj)
99
120
  return false;
121
+ const seen = new Map();
100
122
  for (const key in shape) {
101
- if (obj[key] !== shape[key])
123
+ if (!isPartialMatch(shape[key], obj[key], seen))
102
124
  return false;
103
125
  }
104
126
  return true;
105
127
  };
106
128
  }
129
+ function isPartialMatch(shape, value, seen) {
130
+ if (shape === value)
131
+ return true;
132
+ const isList = Array.isArray(shape);
133
+ if (!isList && !isPlainObject(shape))
134
+ return false;
135
+ if (value === null || typeof value !== 'object' || isList !== Array.isArray(value))
136
+ return false;
137
+ const visited = seen.get(shape) ?? new Set();
138
+ if (visited.has(value))
139
+ return true;
140
+ seen.set(shape, visited.add(value));
141
+ return Object.keys(shape).every((key) => isPartialMatch(shape[key], value[key], seen));
142
+ }
107
143
  export function forEach(collection, fn) {
144
+ if (collection == null)
145
+ return;
108
146
  if (Array.isArray(collection)) {
109
147
  for (let i = 0; i < collection.length; i++) {
110
148
  const res = fn(collection[i], i, collection);
@@ -120,7 +158,7 @@ export function forEach(collection, fn) {
120
158
  }
121
159
  }
122
160
  else {
123
- for (const key of keys(collection)) {
161
+ for (const key of Object.keys(collection)) {
124
162
  const res = fn(collection[key], key, collection);
125
163
  if (res === false)
126
164
  return;
@@ -129,7 +167,7 @@ export function forEach(collection, fn) {
129
167
  }
130
168
  export function findLast(arr, fn) {
131
169
  let result;
132
- const it = isFunction(fn) ? fn : matches(fn);
170
+ const it = isFunction(fn) ? fn : isObject(fn) ? matches(fn) : (obj) => get(fn, obj);
133
171
  forEachRight(arr, (val, key) => {
134
172
  if (it(val, key, arr)) {
135
173
  result = val;
@@ -147,6 +185,14 @@ export function forEachRight(collection, fn) {
147
185
  return;
148
186
  }
149
187
  }
188
+ else if (isIterable(collection)) {
189
+ const items = Array.from(collection);
190
+ for (let i = items.length - 1; i >= 0; i--) {
191
+ const res = fn(items[i], i, collection);
192
+ if (res === false)
193
+ return;
194
+ }
195
+ }
150
196
  else if (isObject(collection)) {
151
197
  const keys = Object.keys(collection);
152
198
  for (let i = keys.length - 1; i >= 0; i--) {
@@ -163,7 +209,7 @@ export function flatten(arr, depth = 1) {
163
209
  return arr;
164
210
  if (Array.isArray(arr))
165
211
  return flattenArray(arr, depth, []);
166
- if (isObject(arr))
212
+ if (isFlattenable(arr))
167
213
  return flattenObj(arr);
168
214
  return arr;
169
215
  }
@@ -178,15 +224,19 @@ function flattenArray(arr, depth = 1, result = []) {
178
224
  }
179
225
  return result;
180
226
  }
227
+ /** A `Date` or `RegExp` has no keys to walk, so `flatten` keeps it as a leaf. */
228
+ function isFlattenable(x) {
229
+ return Array.isArray(x) || (isObject(x) && !isDate(x) && !isRegExp(x));
230
+ }
181
231
  function flattenObj(obj, prefix = '', result = {}, keepNull = false) {
182
- if (isString(obj) || isNumber(obj) || isBool(obj) || (keepNull && isNull(obj))) {
183
- result[prefix] = obj;
232
+ if (isNull(obj) ? keepNull : !isFlattenable(obj)) {
233
+ setOwn(result, prefix, obj);
184
234
  return result;
185
235
  }
186
- if (isArray(obj) || isObject(obj)) {
236
+ if (Array.isArray(obj) || isObject(obj)) {
187
237
  for (const i of Object.keys(obj)) {
188
238
  let pref = prefix;
189
- if (isArray(obj)) {
239
+ if (Array.isArray(obj)) {
190
240
  pref = `${pref}[${i}]`;
191
241
  }
192
242
  else {
@@ -208,6 +258,9 @@ export function map(arr, fn) {
208
258
  if (Array.isArray(arr)) {
209
259
  return arr.map((x, i) => it(x, i, arr));
210
260
  }
261
+ if (isIterable(arr)) {
262
+ return Array.from(arr, (x, i) => it(x, i, arr));
263
+ }
211
264
  if (isObject(arr)) {
212
265
  return Object.keys(arr).map((key) => it(arr[key], key, arr));
213
266
  }
@@ -219,13 +272,16 @@ export function pick(obj, paths) {
219
272
  if (isFunction(paths)) {
220
273
  for (const key of Object.keys(obj)) {
221
274
  if (paths(obj[key], key)) {
222
- result[key] = obj[key];
275
+ setOwn(result, key, obj[key]);
223
276
  }
224
277
  }
225
278
  return result;
226
279
  }
227
- for (const key of paths) {
228
- result[key] = get(key, obj);
280
+ for (const path of paths) {
281
+ const key = typeof path === 'symbol' ? path : String(path);
282
+ const value = get(path, obj);
283
+ if (key !== '__proto__' && (value !== undefined || key in Object(obj)))
284
+ result[key] = value;
229
285
  }
230
286
  return result;
231
287
  }
@@ -236,16 +292,16 @@ export function omit(obj, paths) {
236
292
  if (isFunction(paths)) {
237
293
  for (const key of Object.keys(obj)) {
238
294
  if (!paths(obj[key], key)) {
239
- result[key] = obj[key];
295
+ setOwn(result, key, obj[key]);
240
296
  }
241
297
  }
242
298
  return result;
243
299
  }
244
- Object.assign(result, obj);
300
+ const kept = { ...obj };
245
301
  for (const key of paths) {
246
- delete result[key];
302
+ delete kept[key];
247
303
  }
248
- return result;
304
+ return kept;
249
305
  }
250
306
  export function findIndex(obj, fn, start = 0) {
251
307
  if (!obj)
@@ -303,8 +359,7 @@ export function findLastIndex(arr, fn, start) {
303
359
  if (arr == null)
304
360
  return -1;
305
361
  const length = arr.length;
306
- if (start == null)
307
- start = length - 1;
362
+ start = Math.min(start ?? length - 1, length - 1);
308
363
  if (!length || start < 0)
309
364
  return -1;
310
365
  const it = isFunction(fn) ? fn : isObject(fn) ? matches(fn) : (obj) => get(fn, obj);
@@ -335,12 +390,11 @@ lastIndexOf([1, 2, 1, 2], 2, 2)
335
390
  export function lastIndexOf(obj, value, start) {
336
391
  if (obj == null)
337
392
  return -1;
338
- const op = call(obj, 'lastIndexOf', value, start);
393
+ const op = call(obj, 'lastIndexOf', ...(start === undefined ? [value] : [value, start]));
339
394
  if (op != null)
340
395
  return op;
341
396
  const length = obj.length;
342
- if (start == null)
343
- start = length - 1;
397
+ start = Math.min(start ?? length - 1, length - 1);
344
398
  if (!length || start < 0)
345
399
  return -1;
346
400
  for (; start >= 0; start--) {
@@ -350,29 +404,62 @@ export function lastIndexOf(obj, value, start) {
350
404
  return -1;
351
405
  }
352
406
  export function clone(value, deep = false) {
353
- if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
407
+ return cloneValue(value, deep, new Map());
408
+ }
409
+ function cloneValue(value, deep, copies) {
410
+ if (copies.has(value))
411
+ return copies.get(value);
412
+ if (value instanceof ArrayBuffer)
413
+ return value.slice(0);
414
+ if (ArrayBuffer.isView(value)) {
354
415
  return cloneTypedArray(value, deep);
355
416
  }
356
- if (isArray(value) || isArrayLike(value)) {
357
- return cloneArray(value, deep);
417
+ if (isObject(value) && isFunction(value.clone)) {
418
+ return value.clone();
419
+ }
420
+ if (Array.isArray(value) || hasElements(value)) {
421
+ return cloneArray(value, deep, copies);
422
+ }
423
+ if (value?.constructor === Map) {
424
+ const map = new Map();
425
+ copies.set(value, map);
426
+ for (const [key, item] of value)
427
+ map.set(key, deep ? cloneValue(item, deep, copies) : item);
428
+ return map;
429
+ }
430
+ if (value?.constructor === Set) {
431
+ const set = new Set();
432
+ copies.set(value, set);
433
+ for (const item of value)
434
+ set.add(deep ? cloneValue(item, deep, copies) : item);
435
+ return set;
358
436
  }
359
437
  if (isObject(value)) {
360
- if (isFunction(value.clone)) {
361
- return value.clone();
438
+ if (isDate(value))
439
+ return new Date(value.getTime());
440
+ if (isRegExp(value)) {
441
+ const regex = new RegExp(value.source, value.flags);
442
+ regex.lastIndex = value.lastIndex;
443
+ return regex;
362
444
  }
363
445
  const copy = {};
446
+ copies.set(value, copy);
364
447
  for (const key in value) {
365
448
  if (deep) {
366
- copy[key] = clone(value[key], deep);
449
+ setOwn(copy, key, cloneValue(value[key], deep, copies));
367
450
  }
368
451
  else {
369
- copy[key] = value[key];
452
+ setOwn(copy, key, value[key]);
370
453
  }
371
454
  }
372
455
  return copy;
373
456
  }
374
457
  return value;
375
458
  }
459
+ /** `isArrayLike` accepts any numeric `length`, so this also looks for the elements. */
460
+ function hasElements(x) {
461
+ return isArrayLike(x) && (isIterable(x) || x.length - 1 in x);
462
+ }
376
463
  /**
377
464
  * Clones an array. If `deep` is `false` (default) the clone will be shallow. Otherwise {@link https://developer.mozilla.org/en-US/docs/Web/API/structuredClone structuredClone} is used.
378
465
  * @param arr The array to clone
@@ -380,10 +467,20 @@ export function clone(value, deep = false) {
380
467
  * @returns The new array
381
468
  * @see {@link clone}
382
469
  */
383
- export function cloneArray(arr, deep = false) {
470
+ function cloneArray(arr, deep, copies) {
384
471
  if (!deep)
385
472
  return Array.from(arr);
386
- return structuredClone(arr);
473
+ try {
474
+ return structuredClone(arr);
475
+ }
476
+ catch {
477
+ const copy = Array.from(arr);
478
+ copies.set(arr, copy);
479
+ copy.forEach((item, index) => {
480
+ copy[index] = cloneValue(item, deep, copies);
481
+ });
482
+ return copy;
483
+ }
387
484
  }
388
485
  /**
389
486
  * Clones a typed array. If `deep` is `false` (default) the clone will be shallow. Otherwise {@link https://developer.mozilla.org/en-US/docs/Web/API/structuredClone structuredClone} is used.
@@ -392,40 +489,56 @@ export function cloneArray(arr, deep = false) {
392
489
  * @returns The new array
393
490
  * @see {@link clone}
394
491
  */
395
- export function cloneTypedArray(typedArray, isDeep = false) {
492
+ function cloneTypedArray(typedArray, isDeep = false) {
493
+ if (typedArray instanceof DataView) {
494
+ const viewed = isDeep ? typedArray.buffer.slice(0) : typedArray.buffer;
495
+ return new DataView(viewed, typedArray.byteOffset, typedArray.byteLength);
496
+ }
396
497
  const buffer = isDeep ? structuredClone(typedArray) : typedArray.buffer;
397
498
  return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
398
499
  }
399
- export function uniq(arr, fn = id) {
500
+ export function uniq(arr, fn = identity) {
400
501
  const keys = new Set();
502
+ const results = [];
401
503
  const it = isFunction(fn) ? fn : (x) => get(fn, x);
402
- for (const x of arr) {
403
- keys.add(it(x));
504
+ for (const x of arr ?? []) {
505
+ const key = it(x);
506
+ if (keys.has(key))
507
+ continue;
508
+ keys.add(key);
509
+ results.push(Object.is(x, -0) ? 0 : x);
404
510
  }
405
- return Array.from(keys.values());
511
+ return results;
512
+ }
513
+ export function sortedUniq(arr, fn = identity) {
514
+ const it = isFunction(fn) ? fn : (x) => get(fn, x);
515
+ return uniq(arr, it).sort((x, y) => compare(it(x), it(y)));
406
516
  }
407
- export function sortedUniq(arr, fn = id) {
408
- const values = uniq(arr, fn);
409
- values.sort(compare);
410
- return values;
517
+ /** True for an object made by `{}`, `JSON.parse` or `Object.create(null)`, in any realm. */
518
+ function isPlainObject(x) {
519
+ if (Object.prototype.toString.call(x) !== '[object Object]')
520
+ return false;
521
+ const proto = Object.getPrototypeOf(x);
522
+ return proto === null || Object.getPrototypeOf(proto) === null;
411
523
  }
412
- function baseMergeDeep(obj, source, key, stack) {
524
+ function baseMergeDeep(obj, source, key, stack, copies, merged) {
413
525
  const objValue = obj[key];
414
526
  const srcValue = source[key];
415
527
  const stacked = stack.get(srcValue);
416
- if (stacked && (objValue !== stacked || !(key in obj))) {
528
+ if (stacked) {
417
529
  obj[key] = stacked;
418
530
  return;
419
531
  }
420
532
  let newValue;
421
533
  let isCommon = newValue === undefined;
534
+ let isCopy = false;
422
535
  const isArray = Array.isArray(srcValue);
423
536
  const isTyped = ArrayBuffer.isView(srcValue);
424
537
  if (isArray || isTyped) {
425
538
  if (Array.isArray(objValue)) {
426
539
  newValue = objValue;
427
540
  }
428
- else if (isArrayLike(objValue)) {
541
+ else if (hasElements(objValue)) {
429
542
  newValue = Array.from(objValue);
430
543
  }
431
544
  else if (isTyped) {
@@ -434,42 +547,52 @@ function baseMergeDeep(obj, source, key, stack) {
434
547
  }
435
548
  else {
436
549
  newValue = [];
550
+ isCopy = true;
437
551
  }
438
552
  }
439
- else if (isObject(srcValue)) {
440
- newValue = objValue;
441
- if (!isObject(objValue)) {
442
- newValue = srcValue;
443
- }
553
+ else if (isPlainObject(srcValue)) {
554
+ isCopy = !isObject(objValue);
555
+ newValue = isCopy ? {} : objValue;
444
556
  }
445
557
  else {
446
558
  isCommon = false;
559
+ newValue = srcValue;
447
560
  }
448
- if (isCommon) {
561
+ if (isCopy && copies.has(srcValue)) {
562
+ obj[key] = copies.get(srcValue);
563
+ return;
564
+ }
565
+ const targets = merged.get(srcValue) ?? new WeakSet();
566
+ if (isCommon && !targets.has(newValue)) {
567
+ merged.set(srcValue, targets.add(newValue));
449
568
  stack.set(srcValue, newValue);
450
- baseMerge(newValue, srcValue, stack);
569
+ baseMerge(newValue, srcValue, stack, copies, merged);
451
570
  stack.delete(srcValue);
452
571
  }
572
+ if (isCopy)
573
+ copies.set(srcValue, newValue);
453
574
  obj[key] = newValue;
454
575
  }
455
- function baseMerge(obj, source, stack) {
576
+ function baseMerge(obj, source, stack, copies, merged) {
456
577
  if (obj === source)
457
578
  return obj;
458
579
  for (const key of Object.keys(source)) {
580
+ if (key === '__proto__')
581
+ continue;
459
582
  const srcValue = source[key];
460
583
  const objValue = obj[key];
461
584
  if (typeof srcValue === 'object' && srcValue !== null) {
462
- baseMergeDeep(obj, source, key, stack || new WeakMap());
585
+ baseMergeDeep(obj, source, key, stack, copies, merged);
463
586
  }
464
587
  else {
465
- if (objValue !== srcValue) {
588
+ if (srcValue !== undefined && objValue !== srcValue) {
466
589
  obj[key] = srcValue;
467
590
  }
468
591
  }
469
592
  }
470
593
  }
471
594
  /**
472
- * Recursively merges own and inherited enumerable string keyed properties of source objects into the destination object. Source properties that resolve to `undefined` are skipped if a destination value exists. Array and plain object properties are merged recursively. Other objects and value types are overridden by assignment. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.
595
+ * Recursively merges own enumerable string keyed properties of source objects into the destination object. Source properties that resolve to `undefined` are skipped if a destination value exists. Array and plain object properties are merged recursively. Other objects and value types are overridden by assignment. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.
473
596
  *
474
597
  * Note: this method mutates `object`
475
598
  *
@@ -494,7 +617,8 @@ merge(object, other)
494
617
  */
495
618
  export function merge(object, ...sources) {
496
619
  for (const source of sources) {
497
- baseMerge(object, source);
620
+ if (source != null)
621
+ baseMerge(object, source, new WeakMap(), new WeakMap(), new WeakMap());
498
622
  }
499
623
  return object;
500
624
  }
@@ -534,11 +658,10 @@ export function defaults(object, ...sources) {
534
658
  */
535
659
  export function* difference(...args) {
536
660
  const sets = args.map((arr) => new Set(arr));
537
- const setA = sets[0];
661
+ const setA = sets[0] ?? new Set();
538
662
  for (let i = 1; i < sets.length; i++) {
539
663
  for (const x of sets[i].values()) {
540
- if (!setA.delete(x))
541
- setA.add(x);
664
+ setA.delete(x);
542
665
  }
543
666
  }
544
667
  for (const x of setA.values()) {
@@ -586,7 +709,7 @@ export function* intersection(...args) {
586
709
  export function* union(...args) {
587
710
  const results = new Set();
588
711
  for (const arr of args) {
589
- for (const item of arr) {
712
+ for (const item of arr ?? []) {
590
713
  results.add(item);
591
714
  }
592
715
  }
@@ -594,18 +717,18 @@ export function* union(...args) {
594
717
  yield item;
595
718
  }
596
719
  }
597
- export function groupBy(arr, func = id) {
720
+ export function groupBy(arr, func = identity) {
598
721
  const useKey = isFunction(func) ? func : (obj) => get(func, obj);
599
722
  const results = {};
600
723
  forEach(arr, (value) => {
601
724
  const groupKey = useKey(value);
602
- const values = results[groupKey] || [];
603
- values.push(value);
604
- results[groupKey] = values;
725
+ if (!Object.hasOwn(results, groupKey))
726
+ setOwn(results, groupKey, []);
727
+ results[groupKey].push(value);
605
728
  });
606
729
  return results;
607
730
  }
608
- export function groupByMap(arr, func = id) {
731
+ export function groupByMap(arr, func = identity) {
609
732
  const results = new Map();
610
733
  const useKey = isFunction(func) ? func : (obj) => get(func, obj);
611
734
  forEach(arr, (value) => {
@@ -617,13 +740,17 @@ export function groupByMap(arr, func = id) {
617
740
  return results;
618
741
  }
619
742
  export function remove(arr, func) {
620
- const it = isFunction(func) ? func : isArray(func) ? (x) => func.includes(x) : (x) => func === x;
743
+ const it = isFunction(func)
744
+ ? func
745
+ : Array.isArray(func)
746
+ ? (x) => func.includes(x)
747
+ : (x) => func === x;
621
748
  return arr.filter((x, i) => !it(x, i, arr));
622
749
  }
623
750
  /**
624
751
  * Returns the index of `x` in a **sorted** array if found, in `O(log n)` using binary search.
625
- * If the element is not found, returns a negative integer.
626
- * @param arr The array to sort
752
+ * If the element is not found, returns `-n - 1`, where `n` is the index to insert `x` at.
753
+ * @param arr The sorted array
627
754
  * @param x The element to find
628
755
  * @param lo The starting index
629
756
  * @param hi The end index to search within
@@ -631,7 +758,7 @@ export function remove(arr, func) {
631
758
  * @returns {number} The index if the element is found or a negative integer.
632
759
  */
633
760
  export function binarySearch(arr, x, lo = 0, hi, comp = compare) {
634
- hi = hi ?? arr.length - 1;
761
+ hi ??= arr.length - 1;
635
762
  while (lo < hi) {
636
763
  const mid = (lo + hi) >> 1;
637
764
  const check = comp(x, arr[mid]);
@@ -642,14 +769,15 @@ export function binarySearch(arr, x, lo = 0, hi, comp = compare) {
642
769
  else
643
770
  hi = mid - 1;
644
771
  }
645
- if (comp(x, arr[lo]) === 0)
772
+ const check = lo <= hi ? comp(x, arr[lo]) : -1;
773
+ if (check === 0)
646
774
  return lo;
647
- // Returns (-lo - 1) where n is the insertion point for new element in the range
648
- return -lo - 1;
775
+ // Returns (-n - 1) where n is the insertion point for new element in the range
776
+ return check > 0 ? -lo - 2 : -lo - 1;
649
777
  }
650
778
  /**
651
779
  * Returns an insertion index which comes after any existing entries of `x` in a **sorted** array, using binary search.
652
- * @param arr The array to sort
780
+ * @param arr The sorted array
653
781
  * @param x The element to find
654
782
  * @param lo The starting index
655
783
  * @param hi The end index to search within
@@ -657,20 +785,20 @@ export function binarySearch(arr, x, lo = 0, hi, comp = compare) {
657
785
  * @returns {number}
658
786
  */
659
787
  export function bisect(arr, x, lo = 0, hi, comp = compare) {
660
- hi = hi ?? arr.length;
788
+ hi ??= arr.length;
661
789
  while (lo < hi) {
662
790
  const mid = (lo + hi) >> 1;
663
791
  const check = comp(x, arr[mid]);
664
792
  if (check >= 0)
665
793
  lo = mid + 1;
666
794
  else
667
- hi = mid - 1;
795
+ hi = mid;
668
796
  }
669
797
  return lo;
670
798
  }
671
799
  /**
672
800
  * Returns an insertion index which comes before any existing entries of `x` in a **sorted** array, using binary search.
673
- * @param arr The array to sort
801
+ * @param arr The sorted array
674
802
  * @param x The element to find
675
803
  * @param lo The starting index
676
804
  * @param hi The end index to search within
@@ -678,12 +806,12 @@ export function bisect(arr, x, lo = 0, hi, comp = compare) {
678
806
  * @returns {number}
679
807
  */
680
808
  export function bisectLeft(arr, x, lo = 0, hi, comp = compare) {
681
- hi = hi ?? arr.length;
809
+ hi ??= arr.length;
682
810
  while (lo < hi) {
683
811
  const mid = (lo + hi) >> 1;
684
812
  const check = comp(x, arr[mid]);
685
813
  if (check <= 0)
686
- hi = mid - 1;
814
+ hi = mid;
687
815
  else
688
816
  lo = mid + 1;
689
817
  }
@@ -20,6 +20,8 @@ export declare class Decimal {
20
20
  * Returns a new `Decimal` instance from the value or `0`.
21
21
  * @param {*} value
22
22
  * @returns {Decimal}
23
+ * @throws {ValueError} if the value is not numeric.
24
+ * @throws {RangeError} if the value is infinite or its exponent is past 10,000.
23
25
  */
24
26
  constructor(value?: any);
25
27
  /**
@@ -75,14 +77,15 @@ export declare class Decimal {
75
77
  ```js
76
78
  let a = decimal('1')
77
79
  let b = decimal('3')
78
- a.div(b) // 0.333333333333333333333333333333
80
+ a.div(b) // 0.33333333333333333333
79
81
  ```
80
82
  * @returns {Decimal}
81
83
  */
82
84
  div(x: Decimal | string | number): Decimal;
83
85
  /**
84
86
  * Returns the square root of this `Decimal`.
85
- * @returns {TDecimal}
87
+ * @returns {Decimal}
88
+ * @throws {ValueError} if this value is negative.
86
89
  */
87
90
  sqrt(): Decimal;
88
91
  /** Returns a new copy of this Decimal value. */