UNPKG

88.6 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.lumino_algorithm = {}));
5})(this, (function (exports) { 'use strict';
6
7 // Copyright (c) Jupyter Development Team.
8 // Distributed under the terms of the Modified BSD License.
9 /*-----------------------------------------------------------------------------
10 | Copyright (c) 2014-2017, PhosphorJS Contributors
11 |
12 | Distributed under the terms of the BSD 3-Clause License.
13 |
14 | The full license is in the file LICENSE, distributed with this software.
15 |----------------------------------------------------------------------------*/
16 /**
17 * The namespace for array-specific algorithms.
18 */
19 exports.ArrayExt = void 0;
20 (function (ArrayExt) {
21 /**
22 * Find the index of the first occurrence of a value in an array.
23 *
24 * @param array - The array-like object to search.
25 *
26 * @param value - The value to locate in the array. Values are
27 * compared using strict `===` equality.
28 *
29 * @param start - The index of the first element in the range to be
30 * searched, inclusive. The default value is `0`. Negative values
31 * are taken as an offset from the end of the array.
32 *
33 * @param stop - The index of the last element in the range to be
34 * searched, inclusive. The default value is `-1`. Negative values
35 * are taken as an offset from the end of the array.
36 *
37 * @returns The index of the first occurrence of the value, or `-1`
38 * if the value is not found.
39 *
40 * #### Notes
41 * If `stop < start` the search will wrap at the end of the array.
42 *
43 * #### Complexity
44 * Linear.
45 *
46 * #### Undefined Behavior
47 * A `start` or `stop` which is non-integral.
48 *
49 * #### Example
50 * ```typescript
51 * import { ArrayExt } from '@lumino/algorithm';
52 *
53 * let data = ['one', 'two', 'three', 'four', 'one'];
54 * ArrayExt.firstIndexOf(data, 'red'); // -1
55 * ArrayExt.firstIndexOf(data, 'one'); // 0
56 * ArrayExt.firstIndexOf(data, 'one', 1); // 4
57 * ArrayExt.firstIndexOf(data, 'two', 2); // -1
58 * ArrayExt.firstIndexOf(data, 'two', 2, 1); // 1
59 * ```
60 */
61 function firstIndexOf(array, value, start = 0, stop = -1) {
62 let n = array.length;
63 if (n === 0) {
64 return -1;
65 }
66 if (start < 0) {
67 start = Math.max(0, start + n);
68 }
69 else {
70 start = Math.min(start, n - 1);
71 }
72 if (stop < 0) {
73 stop = Math.max(0, stop + n);
74 }
75 else {
76 stop = Math.min(stop, n - 1);
77 }
78 let span;
79 if (stop < start) {
80 span = stop + 1 + (n - start);
81 }
82 else {
83 span = stop - start + 1;
84 }
85 for (let i = 0; i < span; ++i) {
86 let j = (start + i) % n;
87 if (array[j] === value) {
88 return j;
89 }
90 }
91 return -1;
92 }
93 ArrayExt.firstIndexOf = firstIndexOf;
94 /**
95 * Find the index of the last occurrence of a value in an array.
96 *
97 * @param array - The array-like object to search.
98 *
99 * @param value - The value to locate in the array. Values are
100 * compared using strict `===` equality.
101 *
102 * @param start - The index of the first element in the range to be
103 * searched, inclusive. The default value is `-1`. Negative values
104 * are taken as an offset from the end of the array.
105 *
106 * @param stop - The index of the last element in the range to be
107 * searched, inclusive. The default value is `0`. Negative values
108 * are taken as an offset from the end of the array.
109 *
110 * @returns The index of the last occurrence of the value, or `-1`
111 * if the value is not found.
112 *
113 * #### Notes
114 * If `start < stop` the search will wrap at the front of the array.
115 *
116 * #### Complexity
117 * Linear.
118 *
119 * #### Undefined Behavior
120 * A `start` or `stop` which is non-integral.
121 *
122 * #### Example
123 * ```typescript
124 * import { ArrayExt } from '@lumino/algorithm';
125 *
126 * let data = ['one', 'two', 'three', 'four', 'one'];
127 * ArrayExt.lastIndexOf(data, 'red'); // -1
128 * ArrayExt.lastIndexOf(data, 'one'); // 4
129 * ArrayExt.lastIndexOf(data, 'one', 1); // 0
130 * ArrayExt.lastIndexOf(data, 'two', 0); // -1
131 * ArrayExt.lastIndexOf(data, 'two', 0, 1); // 1
132 * ```
133 */
134 function lastIndexOf(array, value, start = -1, stop = 0) {
135 let n = array.length;
136 if (n === 0) {
137 return -1;
138 }
139 if (start < 0) {
140 start = Math.max(0, start + n);
141 }
142 else {
143 start = Math.min(start, n - 1);
144 }
145 if (stop < 0) {
146 stop = Math.max(0, stop + n);
147 }
148 else {
149 stop = Math.min(stop, n - 1);
150 }
151 let span;
152 if (start < stop) {
153 span = start + 1 + (n - stop);
154 }
155 else {
156 span = start - stop + 1;
157 }
158 for (let i = 0; i < span; ++i) {
159 let j = (start - i + n) % n;
160 if (array[j] === value) {
161 return j;
162 }
163 }
164 return -1;
165 }
166 ArrayExt.lastIndexOf = lastIndexOf;
167 /**
168 * Find the index of the first value which matches a predicate.
169 *
170 * @param array - The array-like object to search.
171 *
172 * @param fn - The predicate function to apply to the values.
173 *
174 * @param start - The index of the first element in the range to be
175 * searched, inclusive. The default value is `0`. Negative values
176 * are taken as an offset from the end of the array.
177 *
178 * @param stop - The index of the last element in the range to be
179 * searched, inclusive. The default value is `-1`. Negative values
180 * are taken as an offset from the end of the array.
181 *
182 * @returns The index of the first matching value, or `-1` if no
183 * matching value is found.
184 *
185 * #### Notes
186 * If `stop < start` the search will wrap at the end of the array.
187 *
188 * #### Complexity
189 * Linear.
190 *
191 * #### Undefined Behavior
192 * A `start` or `stop` which is non-integral.
193 *
194 * Modifying the length of the array while searching.
195 *
196 * #### Example
197 * ```typescript
198 * import { ArrayExt } from '@lumino/algorithm';
199 *
200 * function isEven(value: number): boolean {
201 * return value % 2 === 0;
202 * }
203 *
204 * let data = [1, 2, 3, 4, 3, 2, 1];
205 * ArrayExt.findFirstIndex(data, isEven); // 1
206 * ArrayExt.findFirstIndex(data, isEven, 4); // 5
207 * ArrayExt.findFirstIndex(data, isEven, 6); // -1
208 * ArrayExt.findFirstIndex(data, isEven, 6, 5); // 1
209 * ```
210 */
211 function findFirstIndex(array, fn, start = 0, stop = -1) {
212 let n = array.length;
213 if (n === 0) {
214 return -1;
215 }
216 if (start < 0) {
217 start = Math.max(0, start + n);
218 }
219 else {
220 start = Math.min(start, n - 1);
221 }
222 if (stop < 0) {
223 stop = Math.max(0, stop + n);
224 }
225 else {
226 stop = Math.min(stop, n - 1);
227 }
228 let span;
229 if (stop < start) {
230 span = stop + 1 + (n - start);
231 }
232 else {
233 span = stop - start + 1;
234 }
235 for (let i = 0; i < span; ++i) {
236 let j = (start + i) % n;
237 if (fn(array[j], j)) {
238 return j;
239 }
240 }
241 return -1;
242 }
243 ArrayExt.findFirstIndex = findFirstIndex;
244 /**
245 * Find the index of the last value which matches a predicate.
246 *
247 * @param object - The array-like object to search.
248 *
249 * @param fn - The predicate function to apply to the values.
250 *
251 * @param start - The index of the first element in the range to be
252 * searched, inclusive. The default value is `-1`. Negative values
253 * are taken as an offset from the end of the array.
254 *
255 * @param stop - The index of the last element in the range to be
256 * searched, inclusive. The default value is `0`. Negative values
257 * are taken as an offset from the end of the array.
258 *
259 * @returns The index of the last matching value, or `-1` if no
260 * matching value is found.
261 *
262 * #### Notes
263 * If `start < stop` the search will wrap at the front of the array.
264 *
265 * #### Complexity
266 * Linear.
267 *
268 * #### Undefined Behavior
269 * A `start` or `stop` which is non-integral.
270 *
271 * Modifying the length of the array while searching.
272 *
273 * #### Example
274 * ```typescript
275 * import { ArrayExt } from '@lumino/algorithm';
276 *
277 * function isEven(value: number): boolean {
278 * return value % 2 === 0;
279 * }
280 *
281 * let data = [1, 2, 3, 4, 3, 2, 1];
282 * ArrayExt.findLastIndex(data, isEven); // 5
283 * ArrayExt.findLastIndex(data, isEven, 4); // 3
284 * ArrayExt.findLastIndex(data, isEven, 0); // -1
285 * ArrayExt.findLastIndex(data, isEven, 0, 1); // 5
286 * ```
287 */
288 function findLastIndex(array, fn, start = -1, stop = 0) {
289 let n = array.length;
290 if (n === 0) {
291 return -1;
292 }
293 if (start < 0) {
294 start = Math.max(0, start + n);
295 }
296 else {
297 start = Math.min(start, n - 1);
298 }
299 if (stop < 0) {
300 stop = Math.max(0, stop + n);
301 }
302 else {
303 stop = Math.min(stop, n - 1);
304 }
305 let d;
306 if (start < stop) {
307 d = start + 1 + (n - stop);
308 }
309 else {
310 d = start - stop + 1;
311 }
312 for (let i = 0; i < d; ++i) {
313 let j = (start - i + n) % n;
314 if (fn(array[j], j)) {
315 return j;
316 }
317 }
318 return -1;
319 }
320 ArrayExt.findLastIndex = findLastIndex;
321 /**
322 * Find the first value which matches a predicate.
323 *
324 * @param array - The array-like object to search.
325 *
326 * @param fn - The predicate function to apply to the values.
327 *
328 * @param start - The index of the first element in the range to be
329 * searched, inclusive. The default value is `0`. Negative values
330 * are taken as an offset from the end of the array.
331 *
332 * @param stop - The index of the last element in the range to be
333 * searched, inclusive. The default value is `-1`. Negative values
334 * are taken as an offset from the end of the array.
335 *
336 * @returns The first matching value, or `undefined` if no matching
337 * value is found.
338 *
339 * #### Notes
340 * If `stop < start` the search will wrap at the end of the array.
341 *
342 * #### Complexity
343 * Linear.
344 *
345 * #### Undefined Behavior
346 * A `start` or `stop` which is non-integral.
347 *
348 * Modifying the length of the array while searching.
349 *
350 * #### Example
351 * ```typescript
352 * import { ArrayExt } from '@lumino/algorithm';
353 *
354 * function isEven(value: number): boolean {
355 * return value % 2 === 0;
356 * }
357 *
358 * let data = [1, 2, 3, 4, 3, 2, 1];
359 * ArrayExt.findFirstValue(data, isEven); // 2
360 * ArrayExt.findFirstValue(data, isEven, 2); // 4
361 * ArrayExt.findFirstValue(data, isEven, 6); // undefined
362 * ArrayExt.findFirstValue(data, isEven, 6, 5); // 2
363 * ```
364 */
365 function findFirstValue(array, fn, start = 0, stop = -1) {
366 let index = findFirstIndex(array, fn, start, stop);
367 return index !== -1 ? array[index] : undefined;
368 }
369 ArrayExt.findFirstValue = findFirstValue;
370 /**
371 * Find the last value which matches a predicate.
372 *
373 * @param object - The array-like object to search.
374 *
375 * @param fn - The predicate function to apply to the values.
376 *
377 * @param start - The index of the first element in the range to be
378 * searched, inclusive. The default value is `-1`. Negative values
379 * are taken as an offset from the end of the array.
380 *
381 * @param stop - The index of the last element in the range to be
382 * searched, inclusive. The default value is `0`. Negative values
383 * are taken as an offset from the end of the array.
384 *
385 * @returns The last matching value, or `undefined` if no matching
386 * value is found.
387 *
388 * #### Notes
389 * If `start < stop` the search will wrap at the front of the array.
390 *
391 * #### Complexity
392 * Linear.
393 *
394 * #### Undefined Behavior
395 * A `start` or `stop` which is non-integral.
396 *
397 * Modifying the length of the array while searching.
398 *
399 * #### Example
400 * ```typescript
401 * import { ArrayExt } from '@lumino/algorithm';
402 *
403 * function isEven(value: number): boolean {
404 * return value % 2 === 0;
405 * }
406 *
407 * let data = [1, 2, 3, 4, 3, 2, 1];
408 * ArrayExt.findLastValue(data, isEven); // 2
409 * ArrayExt.findLastValue(data, isEven, 4); // 4
410 * ArrayExt.findLastValue(data, isEven, 0); // undefined
411 * ArrayExt.findLastValue(data, isEven, 0, 1); // 2
412 * ```
413 */
414 function findLastValue(array, fn, start = -1, stop = 0) {
415 let index = findLastIndex(array, fn, start, stop);
416 return index !== -1 ? array[index] : undefined;
417 }
418 ArrayExt.findLastValue = findLastValue;
419 /**
420 * Find the index of the first element which compares `>=` to a value.
421 *
422 * @param array - The sorted array-like object to search.
423 *
424 * @param value - The value to locate in the array.
425 *
426 * @param fn - The 3-way comparison function to apply to the values.
427 * It should return `< 0` if an element is less than a value, `0` if
428 * an element is equal to a value, or `> 0` if an element is greater
429 * than a value.
430 *
431 * @param start - The index of the first element in the range to be
432 * searched, inclusive. The default value is `0`. Negative values
433 * are taken as an offset from the end of the array.
434 *
435 * @param stop - The index of the last element in the range to be
436 * searched, inclusive. The default value is `-1`. Negative values
437 * are taken as an offset from the end of the array.
438 *
439 * @returns The index of the first element which compares `>=` to the
440 * value, or `length` if there is no such element. If the computed
441 * index for `stop` is less than `start`, then the computed index
442 * for `start` is returned.
443 *
444 * #### Notes
445 * The array must already be sorted in ascending order according to
446 * the comparison function.
447 *
448 * #### Complexity
449 * Logarithmic.
450 *
451 * #### Undefined Behavior
452 * Searching a range which is not sorted in ascending order.
453 *
454 * A `start` or `stop` which is non-integral.
455 *
456 * Modifying the length of the array while searching.
457 *
458 * #### Example
459 * ```typescript
460 * import { ArrayExt } from '@lumino/algorithm';
461 *
462 * function numberCmp(a: number, b: number): number {
463 * return a - b;
464 * }
465 *
466 * let data = [0, 3, 4, 7, 7, 9];
467 * ArrayExt.lowerBound(data, 0, numberCmp); // 0
468 * ArrayExt.lowerBound(data, 6, numberCmp); // 3
469 * ArrayExt.lowerBound(data, 7, numberCmp); // 3
470 * ArrayExt.lowerBound(data, -1, numberCmp); // 0
471 * ArrayExt.lowerBound(data, 10, numberCmp); // 6
472 * ```
473 */
474 function lowerBound(array, value, fn, start = 0, stop = -1) {
475 let n = array.length;
476 if (n === 0) {
477 return 0;
478 }
479 if (start < 0) {
480 start = Math.max(0, start + n);
481 }
482 else {
483 start = Math.min(start, n - 1);
484 }
485 if (stop < 0) {
486 stop = Math.max(0, stop + n);
487 }
488 else {
489 stop = Math.min(stop, n - 1);
490 }
491 let begin = start;
492 let span = stop - start + 1;
493 while (span > 0) {
494 let half = span >> 1;
495 let middle = begin + half;
496 if (fn(array[middle], value) < 0) {
497 begin = middle + 1;
498 span -= half + 1;
499 }
500 else {
501 span = half;
502 }
503 }
504 return begin;
505 }
506 ArrayExt.lowerBound = lowerBound;
507 /**
508 * Find the index of the first element which compares `>` than a value.
509 *
510 * @param array - The sorted array-like object to search.
511 *
512 * @param value - The value to locate in the array.
513 *
514 * @param fn - The 3-way comparison function to apply to the values.
515 * It should return `< 0` if an element is less than a value, `0` if
516 * an element is equal to a value, or `> 0` if an element is greater
517 * than a value.
518 *
519 * @param start - The index of the first element in the range to be
520 * searched, inclusive. The default value is `0`. Negative values
521 * are taken as an offset from the end of the array.
522 *
523 * @param stop - The index of the last element in the range to be
524 * searched, inclusive. The default value is `-1`. Negative values
525 * are taken as an offset from the end of the array.
526 *
527 * @returns The index of the first element which compares `>` than the
528 * value, or `length` if there is no such element. If the computed
529 * index for `stop` is less than `start`, then the computed index
530 * for `start` is returned.
531 *
532 * #### Notes
533 * The array must already be sorted in ascending order according to
534 * the comparison function.
535 *
536 * #### Complexity
537 * Logarithmic.
538 *
539 * #### Undefined Behavior
540 * Searching a range which is not sorted in ascending order.
541 *
542 * A `start` or `stop` which is non-integral.
543 *
544 * Modifying the length of the array while searching.
545 *
546 * #### Example
547 * ```typescript
548 * import { ArrayExt } from '@lumino/algorithm';
549 *
550 * function numberCmp(a: number, b: number): number {
551 * return a - b;
552 * }
553 *
554 * let data = [0, 3, 4, 7, 7, 9];
555 * ArrayExt.upperBound(data, 0, numberCmp); // 1
556 * ArrayExt.upperBound(data, 6, numberCmp); // 3
557 * ArrayExt.upperBound(data, 7, numberCmp); // 5
558 * ArrayExt.upperBound(data, -1, numberCmp); // 0
559 * ArrayExt.upperBound(data, 10, numberCmp); // 6
560 * ```
561 */
562 function upperBound(array, value, fn, start = 0, stop = -1) {
563 let n = array.length;
564 if (n === 0) {
565 return 0;
566 }
567 if (start < 0) {
568 start = Math.max(0, start + n);
569 }
570 else {
571 start = Math.min(start, n - 1);
572 }
573 if (stop < 0) {
574 stop = Math.max(0, stop + n);
575 }
576 else {
577 stop = Math.min(stop, n - 1);
578 }
579 let begin = start;
580 let span = stop - start + 1;
581 while (span > 0) {
582 let half = span >> 1;
583 let middle = begin + half;
584 if (fn(array[middle], value) > 0) {
585 span = half;
586 }
587 else {
588 begin = middle + 1;
589 span -= half + 1;
590 }
591 }
592 return begin;
593 }
594 ArrayExt.upperBound = upperBound;
595 /**
596 * Test whether two arrays are shallowly equal.
597 *
598 * @param a - The first array-like object to compare.
599 *
600 * @param b - The second array-like object to compare.
601 *
602 * @param fn - The comparison function to apply to the elements. It
603 * should return `true` if the elements are "equal". The default
604 * compares elements using strict `===` equality.
605 *
606 * @returns Whether the two arrays are shallowly equal.
607 *
608 * #### Complexity
609 * Linear.
610 *
611 * #### Undefined Behavior
612 * Modifying the length of the arrays while comparing.
613 *
614 * #### Example
615 * ```typescript
616 * import { ArrayExt } from '@lumino/algorithm';
617 *
618 * let d1 = [0, 3, 4, 7, 7, 9];
619 * let d2 = [0, 3, 4, 7, 7, 9];
620 * let d3 = [42];
621 * ArrayExt.shallowEqual(d1, d2); // true
622 * ArrayExt.shallowEqual(d2, d3); // false
623 * ```
624 */
625 function shallowEqual(a, b, fn) {
626 // Check for object identity first.
627 if (a === b) {
628 return true;
629 }
630 // Bail early if the lengths are different.
631 if (a.length !== b.length) {
632 return false;
633 }
634 // Compare each element for equality.
635 for (let i = 0, n = a.length; i < n; ++i) {
636 if (fn ? !fn(a[i], b[i]) : a[i] !== b[i]) {
637 return false;
638 }
639 }
640 // The array are shallowly equal.
641 return true;
642 }
643 ArrayExt.shallowEqual = shallowEqual;
644 /**
645 * Create a slice of an array subject to an optional step.
646 *
647 * @param array - The array-like object of interest.
648 *
649 * @param options - The options for configuring the slice.
650 *
651 * @returns A new array with the specified values.
652 *
653 * @throws An exception if the slice `step` is `0`.
654 *
655 * #### Complexity
656 * Linear.
657 *
658 * #### Undefined Behavior
659 * A `start`, `stop`, or `step` which is non-integral.
660 *
661 * #### Example
662 * ```typescript
663 * import { ArrayExt } from '@lumino/algorithm';
664 *
665 * let data = [0, 3, 4, 7, 7, 9];
666 * ArrayExt.slice(data); // [0, 3, 4, 7, 7, 9]
667 * ArrayExt.slice(data, { start: 2 }); // [4, 7, 7, 9]
668 * ArrayExt.slice(data, { start: 0, stop: 4 }); // [0, 3, 4, 7]
669 * ArrayExt.slice(data, { step: 2 }); // [0, 4, 7]
670 * ArrayExt.slice(data, { step: -1 }); // [9, 7, 7, 4, 3, 0]
671 * ```
672 */
673 function slice(array, options = {}) {
674 // Extract the options.
675 let { start, stop, step } = options;
676 // Set up the `step` value.
677 if (step === undefined) {
678 step = 1;
679 }
680 // Validate the step size.
681 if (step === 0) {
682 throw new Error('Slice `step` cannot be zero.');
683 }
684 // Look up the length of the array.
685 let n = array.length;
686 // Set up the `start` value.
687 if (start === undefined) {
688 start = step < 0 ? n - 1 : 0;
689 }
690 else if (start < 0) {
691 start = Math.max(start + n, step < 0 ? -1 : 0);
692 }
693 else if (start >= n) {
694 start = step < 0 ? n - 1 : n;
695 }
696 // Set up the `stop` value.
697 if (stop === undefined) {
698 stop = step < 0 ? -1 : n;
699 }
700 else if (stop < 0) {
701 stop = Math.max(stop + n, step < 0 ? -1 : 0);
702 }
703 else if (stop >= n) {
704 stop = step < 0 ? n - 1 : n;
705 }
706 // Compute the slice length.
707 let length;
708 if ((step < 0 && stop >= start) || (step > 0 && start >= stop)) {
709 length = 0;
710 }
711 else if (step < 0) {
712 length = Math.floor((stop - start + 1) / step + 1);
713 }
714 else {
715 length = Math.floor((stop - start - 1) / step + 1);
716 }
717 // Compute the sliced result.
718 let result = [];
719 for (let i = 0; i < length; ++i) {
720 result[i] = array[start + i * step];
721 }
722 // Return the result.
723 return result;
724 }
725 ArrayExt.slice = slice;
726 /**
727 * Move an element in an array from one index to another.
728 *
729 * @param array - The mutable array-like object of interest.
730 *
731 * @param fromIndex - The index of the element to move. Negative
732 * values are taken as an offset from the end of the array.
733 *
734 * @param toIndex - The target index of the element. Negative
735 * values are taken as an offset from the end of the array.
736 *
737 * #### Complexity
738 * Linear.
739 *
740 * #### Undefined Behavior
741 * A `fromIndex` or `toIndex` which is non-integral.
742 *
743 * #### Example
744 * ```typescript
745 * import { ArrayExt } from from '@lumino/algorithm';
746 *
747 * let data = [0, 1, 2, 3, 4];
748 * ArrayExt.move(data, 1, 2); // [0, 2, 1, 3, 4]
749 * ArrayExt.move(data, 4, 2); // [0, 2, 4, 1, 3]
750 * ```
751 */
752 function move(array, fromIndex, toIndex) {
753 let n = array.length;
754 if (n <= 1) {
755 return;
756 }
757 if (fromIndex < 0) {
758 fromIndex = Math.max(0, fromIndex + n);
759 }
760 else {
761 fromIndex = Math.min(fromIndex, n - 1);
762 }
763 if (toIndex < 0) {
764 toIndex = Math.max(0, toIndex + n);
765 }
766 else {
767 toIndex = Math.min(toIndex, n - 1);
768 }
769 if (fromIndex === toIndex) {
770 return;
771 }
772 let value = array[fromIndex];
773 let d = fromIndex < toIndex ? 1 : -1;
774 for (let i = fromIndex; i !== toIndex; i += d) {
775 array[i] = array[i + d];
776 }
777 array[toIndex] = value;
778 }
779 ArrayExt.move = move;
780 /**
781 * Reverse an array in-place.
782 *
783 * @param array - The mutable array-like object of interest.
784 *
785 * @param start - The index of the first element in the range to be
786 * reversed, inclusive. The default value is `0`. Negative values
787 * are taken as an offset from the end of the array.
788 *
789 * @param stop - The index of the last element in the range to be
790 * reversed, inclusive. The default value is `-1`. Negative values
791 * are taken as an offset from the end of the array.
792 *
793 * #### Complexity
794 * Linear.
795 *
796 * #### Undefined Behavior
797 * A `start` or `stop` index which is non-integral.
798 *
799 * #### Example
800 * ```typescript
801 * import { ArrayExt } from '@lumino/algorithm';
802 *
803 * let data = [0, 1, 2, 3, 4];
804 * ArrayExt.reverse(data, 1, 3); // [0, 3, 2, 1, 4]
805 * ArrayExt.reverse(data, 3); // [0, 3, 2, 4, 1]
806 * ArrayExt.reverse(data); // [1, 4, 2, 3, 0]
807 * ```
808 */
809 function reverse(array, start = 0, stop = -1) {
810 let n = array.length;
811 if (n <= 1) {
812 return;
813 }
814 if (start < 0) {
815 start = Math.max(0, start + n);
816 }
817 else {
818 start = Math.min(start, n - 1);
819 }
820 if (stop < 0) {
821 stop = Math.max(0, stop + n);
822 }
823 else {
824 stop = Math.min(stop, n - 1);
825 }
826 while (start < stop) {
827 let a = array[start];
828 let b = array[stop];
829 array[start++] = b;
830 array[stop--] = a;
831 }
832 }
833 ArrayExt.reverse = reverse;
834 /**
835 * Rotate the elements of an array in-place.
836 *
837 * @param array - The mutable array-like object of interest.
838 *
839 * @param delta - The amount of rotation to apply to the elements. A
840 * positive value will rotate the elements to the left. A negative
841 * value will rotate the elements to the right.
842 *
843 * @param start - The index of the first element in the range to be
844 * rotated, inclusive. The default value is `0`. Negative values
845 * are taken as an offset from the end of the array.
846 *
847 * @param stop - The index of the last element in the range to be
848 * rotated, inclusive. The default value is `-1`. Negative values
849 * are taken as an offset from the end of the array.
850 *
851 * #### Complexity
852 * Linear.
853 *
854 * #### Undefined Behavior
855 * A `delta`, `start`, or `stop` which is non-integral.
856 *
857 * #### Example
858 * ```typescript
859 * import { ArrayExt } from '@lumino/algorithm';
860 *
861 * let data = [0, 1, 2, 3, 4];
862 * ArrayExt.rotate(data, 2); // [2, 3, 4, 0, 1]
863 * ArrayExt.rotate(data, -2); // [0, 1, 2, 3, 4]
864 * ArrayExt.rotate(data, 10); // [0, 1, 2, 3, 4]
865 * ArrayExt.rotate(data, 9); // [4, 0, 1, 2, 3]
866 * ArrayExt.rotate(data, 2, 1, 3); // [4, 2, 0, 1, 3]
867 * ```
868 */
869 function rotate(array, delta, start = 0, stop = -1) {
870 let n = array.length;
871 if (n <= 1) {
872 return;
873 }
874 if (start < 0) {
875 start = Math.max(0, start + n);
876 }
877 else {
878 start = Math.min(start, n - 1);
879 }
880 if (stop < 0) {
881 stop = Math.max(0, stop + n);
882 }
883 else {
884 stop = Math.min(stop, n - 1);
885 }
886 if (start >= stop) {
887 return;
888 }
889 let length = stop - start + 1;
890 if (delta > 0) {
891 delta = delta % length;
892 }
893 else if (delta < 0) {
894 delta = ((delta % length) + length) % length;
895 }
896 if (delta === 0) {
897 return;
898 }
899 let pivot = start + delta;
900 reverse(array, start, pivot - 1);
901 reverse(array, pivot, stop);
902 reverse(array, start, stop);
903 }
904 ArrayExt.rotate = rotate;
905 /**
906 * Fill an array with a static value.
907 *
908 * @param array - The mutable array-like object to fill.
909 *
910 * @param value - The static value to use to fill the array.
911 *
912 * @param start - The index of the first element in the range to be
913 * filled, inclusive. The default value is `0`. Negative values
914 * are taken as an offset from the end of the array.
915 *
916 * @param stop - The index of the last element in the range to be
917 * filled, inclusive. The default value is `-1`. Negative values
918 * are taken as an offset from the end of the array.
919 *
920 * #### Notes
921 * If `stop < start` the fill will wrap at the end of the array.
922 *
923 * #### Complexity
924 * Linear.
925 *
926 * #### Undefined Behavior
927 * A `start` or `stop` which is non-integral.
928 *
929 * #### Example
930 * ```typescript
931 * import { ArrayExt } from '@lumino/algorithm';
932 *
933 * let data = ['one', 'two', 'three', 'four'];
934 * ArrayExt.fill(data, 'r'); // ['r', 'r', 'r', 'r']
935 * ArrayExt.fill(data, 'g', 1); // ['r', 'g', 'g', 'g']
936 * ArrayExt.fill(data, 'b', 2, 3); // ['r', 'g', 'b', 'b']
937 * ArrayExt.fill(data, 'z', 3, 1); // ['z', 'z', 'b', 'z']
938 * ```
939 */
940 function fill(array, value, start = 0, stop = -1) {
941 let n = array.length;
942 if (n === 0) {
943 return;
944 }
945 if (start < 0) {
946 start = Math.max(0, start + n);
947 }
948 else {
949 start = Math.min(start, n - 1);
950 }
951 if (stop < 0) {
952 stop = Math.max(0, stop + n);
953 }
954 else {
955 stop = Math.min(stop, n - 1);
956 }
957 let span;
958 if (stop < start) {
959 span = stop + 1 + (n - start);
960 }
961 else {
962 span = stop - start + 1;
963 }
964 for (let i = 0; i < span; ++i) {
965 array[(start + i) % n] = value;
966 }
967 }
968 ArrayExt.fill = fill;
969 /**
970 * Insert a value into an array at a specific index.
971 *
972 * @param array - The array of interest.
973 *
974 * @param index - The index at which to insert the value. Negative
975 * values are taken as an offset from the end of the array.
976 *
977 * @param value - The value to set at the specified index.
978 *
979 * #### Complexity
980 * Linear.
981 *
982 * #### Undefined Behavior
983 * An `index` which is non-integral.
984 *
985 * #### Example
986 * ```typescript
987 * import { ArrayExt } from '@lumino/algorithm';
988 *
989 * let data = [0, 1, 2];
990 * ArrayExt.insert(data, 0, -1); // [-1, 0, 1, 2]
991 * ArrayExt.insert(data, 2, 12); // [-1, 0, 12, 1, 2]
992 * ArrayExt.insert(data, -1, 7); // [-1, 0, 12, 1, 7, 2]
993 * ArrayExt.insert(data, 6, 19); // [-1, 0, 12, 1, 7, 2, 19]
994 * ```
995 */
996 function insert(array, index, value) {
997 let n = array.length;
998 if (index < 0) {
999 index = Math.max(0, index + n);
1000 }
1001 else {
1002 index = Math.min(index, n);
1003 }
1004 for (let i = n; i > index; --i) {
1005 array[i] = array[i - 1];
1006 }
1007 array[index] = value;
1008 }
1009 ArrayExt.insert = insert;
1010 /**
1011 * Remove and return a value at a specific index in an array.
1012 *
1013 * @param array - The array of interest.
1014 *
1015 * @param index - The index of the value to remove. Negative values
1016 * are taken as an offset from the end of the array.
1017 *
1018 * @returns The value at the specified index, or `undefined` if the
1019 * index is out of range.
1020 *
1021 * #### Complexity
1022 * Linear.
1023 *
1024 * #### Undefined Behavior
1025 * An `index` which is non-integral.
1026 *
1027 * #### Example
1028 * ```typescript
1029 * import { ArrayExt } from '@lumino/algorithm';
1030 *
1031 * let data = [0, 12, 23, 39, 14, 12, 75];
1032 * ArrayExt.removeAt(data, 2); // 23
1033 * ArrayExt.removeAt(data, -2); // 12
1034 * ArrayExt.removeAt(data, 10); // undefined;
1035 * ```
1036 */
1037 function removeAt(array, index) {
1038 let n = array.length;
1039 if (index < 0) {
1040 index += n;
1041 }
1042 if (index < 0 || index >= n) {
1043 return undefined;
1044 }
1045 let value = array[index];
1046 for (let i = index + 1; i < n; ++i) {
1047 array[i - 1] = array[i];
1048 }
1049 array.length = n - 1;
1050 return value;
1051 }
1052 ArrayExt.removeAt = removeAt;
1053 /**
1054 * Remove the first occurrence of a value from an array.
1055 *
1056 * @param array - The array of interest.
1057 *
1058 * @param value - The value to remove from the array. Values are
1059 * compared using strict `===` equality.
1060 *
1061 * @param start - The index of the first element in the range to be
1062 * searched, inclusive. The default value is `0`. Negative values
1063 * are taken as an offset from the end of the array.
1064 *
1065 * @param stop - The index of the last element in the range to be
1066 * searched, inclusive. The default value is `-1`. Negative values
1067 * are taken as an offset from the end of the array.
1068 *
1069 * @returns The index of the removed value, or `-1` if the value
1070 * is not contained in the array.
1071 *
1072 * #### Notes
1073 * If `stop < start` the search will wrap at the end of the array.
1074 *
1075 * #### Complexity
1076 * Linear.
1077 *
1078 * #### Example
1079 * ```typescript
1080 * import { ArrayExt } from '@lumino/algorithm';
1081 *
1082 * let data = [0, 12, 23, 39, 14, 12, 75];
1083 * ArrayExt.removeFirstOf(data, 12); // 1
1084 * ArrayExt.removeFirstOf(data, 17); // -1
1085 * ArrayExt.removeFirstOf(data, 39, 3); // -1
1086 * ArrayExt.removeFirstOf(data, 39, 3, 2); // 2
1087 * ```
1088 */
1089 function removeFirstOf(array, value, start = 0, stop = -1) {
1090 let index = firstIndexOf(array, value, start, stop);
1091 if (index !== -1) {
1092 removeAt(array, index);
1093 }
1094 return index;
1095 }
1096 ArrayExt.removeFirstOf = removeFirstOf;
1097 /**
1098 * Remove the last occurrence of a value from an array.
1099 *
1100 * @param array - The array of interest.
1101 *
1102 * @param value - The value to remove from the array. Values are
1103 * compared using strict `===` equality.
1104 *
1105 * @param start - The index of the first element in the range to be
1106 * searched, inclusive. The default value is `-1`. Negative values
1107 * are taken as an offset from the end of the array.
1108 *
1109 * @param stop - The index of the last element in the range to be
1110 * searched, inclusive. The default value is `0`. Negative values
1111 * are taken as an offset from the end of the array.
1112 *
1113 * @returns The index of the removed value, or `-1` if the value
1114 * is not contained in the array.
1115 *
1116 * #### Notes
1117 * If `start < stop` the search will wrap at the end of the array.
1118 *
1119 * #### Complexity
1120 * Linear.
1121 *
1122 * #### Example
1123 * ```typescript
1124 * import { ArrayExt } from '@lumino/algorithm';
1125 *
1126 * let data = [0, 12, 23, 39, 14, 12, 75];
1127 * ArrayExt.removeLastOf(data, 12); // 5
1128 * ArrayExt.removeLastOf(data, 17); // -1
1129 * ArrayExt.removeLastOf(data, 39, 2); // -1
1130 * ArrayExt.removeLastOf(data, 39, 2, 3); // 3
1131 * ```
1132 */
1133 function removeLastOf(array, value, start = -1, stop = 0) {
1134 let index = lastIndexOf(array, value, start, stop);
1135 if (index !== -1) {
1136 removeAt(array, index);
1137 }
1138 return index;
1139 }
1140 ArrayExt.removeLastOf = removeLastOf;
1141 /**
1142 * Remove all occurrences of a value from an array.
1143 *
1144 * @param array - The array of interest.
1145 *
1146 * @param value - The value to remove from the array. Values are
1147 * compared using strict `===` equality.
1148 *
1149 * @param start - The index of the first element in the range to be
1150 * searched, inclusive. The default value is `0`. Negative values
1151 * are taken as an offset from the end of the array.
1152 *
1153 * @param stop - The index of the last element in the range to be
1154 * searched, inclusive. The default value is `-1`. Negative values
1155 * are taken as an offset from the end of the array.
1156 *
1157 * @returns The number of elements removed from the array.
1158 *
1159 * #### Notes
1160 * If `stop < start` the search will conceptually wrap at the end of
1161 * the array, however the array will be traversed front-to-back.
1162 *
1163 * #### Complexity
1164 * Linear.
1165 *
1166 * #### Example
1167 * ```typescript
1168 * import { ArrayExt } from '@lumino/algorithm';
1169 *
1170 * let data = [14, 12, 23, 39, 14, 12, 19, 14];
1171 * ArrayExt.removeAllOf(data, 12); // 2
1172 * ArrayExt.removeAllOf(data, 17); // 0
1173 * ArrayExt.removeAllOf(data, 14, 1, 4); // 1
1174 * ```
1175 */
1176 function removeAllOf(array, value, start = 0, stop = -1) {
1177 let n = array.length;
1178 if (n === 0) {
1179 return 0;
1180 }
1181 if (start < 0) {
1182 start = Math.max(0, start + n);
1183 }
1184 else {
1185 start = Math.min(start, n - 1);
1186 }
1187 if (stop < 0) {
1188 stop = Math.max(0, stop + n);
1189 }
1190 else {
1191 stop = Math.min(stop, n - 1);
1192 }
1193 let count = 0;
1194 for (let i = 0; i < n; ++i) {
1195 if (start <= stop && i >= start && i <= stop && array[i] === value) {
1196 count++;
1197 }
1198 else if (stop < start &&
1199 (i <= stop || i >= start) &&
1200 array[i] === value) {
1201 count++;
1202 }
1203 else if (count > 0) {
1204 array[i - count] = array[i];
1205 }
1206 }
1207 if (count > 0) {
1208 array.length = n - count;
1209 }
1210 return count;
1211 }
1212 ArrayExt.removeAllOf = removeAllOf;
1213 /**
1214 * Remove the first occurrence of a value which matches a predicate.
1215 *
1216 * @param array - The array of interest.
1217 *
1218 * @param fn - The predicate function to apply to the values.
1219 *
1220 * @param start - The index of the first element in the range to be
1221 * searched, inclusive. The default value is `0`. Negative values
1222 * are taken as an offset from the end of the array.
1223 *
1224 * @param stop - The index of the last element in the range to be
1225 * searched, inclusive. The default value is `-1`. Negative values
1226 * are taken as an offset from the end of the array.
1227 *
1228 * @returns The removed `{ index, value }`, which will be `-1` and
1229 * `undefined` if the value is not contained in the array.
1230 *
1231 * #### Notes
1232 * If `stop < start` the search will wrap at the end of the array.
1233 *
1234 * #### Complexity
1235 * Linear.
1236 *
1237 * #### Example
1238 * ```typescript
1239 * import { ArrayExt } from '@lumino/algorithm';
1240 *
1241 * function isEven(value: number): boolean {
1242 * return value % 2 === 0;
1243 * }
1244 *
1245 * let data = [0, 12, 23, 39, 14, 12, 75];
1246 * ArrayExt.removeFirstWhere(data, isEven); // { index: 0, value: 0 }
1247 * ArrayExt.removeFirstWhere(data, isEven, 2); // { index: 3, value: 14 }
1248 * ArrayExt.removeFirstWhere(data, isEven, 4); // { index: -1, value: undefined }
1249 * ```
1250 */
1251 function removeFirstWhere(array, fn, start = 0, stop = -1) {
1252 let value;
1253 let index = findFirstIndex(array, fn, start, stop);
1254 if (index !== -1) {
1255 value = removeAt(array, index);
1256 }
1257 return { index, value };
1258 }
1259 ArrayExt.removeFirstWhere = removeFirstWhere;
1260 /**
1261 * Remove the last occurrence of a value which matches a predicate.
1262 *
1263 * @param array - The array of interest.
1264 *
1265 * @param fn - The predicate function to apply to the values.
1266 *
1267 * @param start - The index of the first element in the range to be
1268 * searched, inclusive. The default value is `-1`. Negative values
1269 * are taken as an offset from the end of the array.
1270 *
1271 * @param stop - The index of the last element in the range to be
1272 * searched, inclusive. The default value is `0`. Negative values
1273 * are taken as an offset from the end of the array.
1274 *
1275 * @returns The removed `{ index, value }`, which will be `-1` and
1276 * `undefined` if the value is not contained in the array.
1277 *
1278 * #### Notes
1279 * If `start < stop` the search will wrap at the end of the array.
1280 *
1281 * #### Complexity
1282 * Linear.
1283 *
1284 * #### Example
1285 * ```typescript
1286 * import { ArrayExt } from '@lumino/algorithm';
1287 *
1288 * function isEven(value: number): boolean {
1289 * return value % 2 === 0;
1290 * }
1291 *
1292 * let data = [0, 12, 23, 39, 14, 12, 75];
1293 * ArrayExt.removeLastWhere(data, isEven); // { index: 5, value: 12 }
1294 * ArrayExt.removeLastWhere(data, isEven, 2); // { index: 1, value: 12 }
1295 * ArrayExt.removeLastWhere(data, isEven, 2, 1); // { index: -1, value: undefined }
1296 * ```
1297 */
1298 function removeLastWhere(array, fn, start = -1, stop = 0) {
1299 let value;
1300 let index = findLastIndex(array, fn, start, stop);
1301 if (index !== -1) {
1302 value = removeAt(array, index);
1303 }
1304 return { index, value };
1305 }
1306 ArrayExt.removeLastWhere = removeLastWhere;
1307 /**
1308 * Remove all occurrences of values which match a predicate.
1309 *
1310 * @param array - The array of interest.
1311 *
1312 * @param fn - The predicate function to apply to the values.
1313 *
1314 * @param start - The index of the first element in the range to be
1315 * searched, inclusive. The default value is `0`. Negative values
1316 * are taken as an offset from the end of the array.
1317 *
1318 * @param stop - The index of the last element in the range to be
1319 * searched, inclusive. The default value is `-1`. Negative values
1320 * are taken as an offset from the end of the array.
1321 *
1322 * @returns The number of elements removed from the array.
1323 *
1324 * #### Notes
1325 * If `stop < start` the search will conceptually wrap at the end of
1326 * the array, however the array will be traversed front-to-back.
1327 *
1328 * #### Complexity
1329 * Linear.
1330 *
1331 * #### Example
1332 * ```typescript
1333 * import { ArrayExt } from '@lumino/algorithm';
1334 *
1335 * function isEven(value: number): boolean {
1336 * return value % 2 === 0;
1337 * }
1338 *
1339 * function isNegative(value: number): boolean {
1340 * return value < 0;
1341 * }
1342 *
1343 * let data = [0, 12, -13, -9, 23, 39, 14, -15, 12, 75];
1344 * ArrayExt.removeAllWhere(data, isEven); // 4
1345 * ArrayExt.removeAllWhere(data, isNegative, 0, 3); // 2
1346 * ```
1347 */
1348 function removeAllWhere(array, fn, start = 0, stop = -1) {
1349 let n = array.length;
1350 if (n === 0) {
1351 return 0;
1352 }
1353 if (start < 0) {
1354 start = Math.max(0, start + n);
1355 }
1356 else {
1357 start = Math.min(start, n - 1);
1358 }
1359 if (stop < 0) {
1360 stop = Math.max(0, stop + n);
1361 }
1362 else {
1363 stop = Math.min(stop, n - 1);
1364 }
1365 let count = 0;
1366 for (let i = 0; i < n; ++i) {
1367 if (start <= stop && i >= start && i <= stop && fn(array[i], i)) {
1368 count++;
1369 }
1370 else if (stop < start && (i <= stop || i >= start) && fn(array[i], i)) {
1371 count++;
1372 }
1373 else if (count > 0) {
1374 array[i - count] = array[i];
1375 }
1376 }
1377 if (count > 0) {
1378 array.length = n - count;
1379 }
1380 return count;
1381 }
1382 ArrayExt.removeAllWhere = removeAllWhere;
1383 })(exports.ArrayExt || (exports.ArrayExt = {}));
1384
1385 // Copyright (c) Jupyter Development Team.
1386 // Distributed under the terms of the Modified BSD License.
1387 /*-----------------------------------------------------------------------------
1388 | Copyright (c) 2014-2017, PhosphorJS Contributors
1389 |
1390 | Distributed under the terms of the BSD 3-Clause License.
1391 |
1392 | The full license is in the file LICENSE, distributed with this software.
1393 |----------------------------------------------------------------------------*/
1394 /**
1395 * Chain together several iterables.
1396 *
1397 * @deprecated
1398 *
1399 * @param objects - The iterable objects of interest.
1400 *
1401 * @returns An iterator which yields the values of the iterables
1402 * in the order in which they are supplied.
1403 *
1404 * #### Example
1405 * ```typescript
1406 * import { chain } from '@lumino/algorithm';
1407 *
1408 * let data1 = [1, 2, 3];
1409 * let data2 = [4, 5, 6];
1410 *
1411 * let stream = chain(data1, data2);
1412 *
1413 * Array.from(stream); // [1, 2, 3, 4, 5, 6]
1414 * ```
1415 */
1416 function* chain(...objects) {
1417 for (const object of objects) {
1418 yield* object;
1419 }
1420 }
1421
1422 // Copyright (c) Jupyter Development Team.
1423 // Distributed under the terms of the Modified BSD License.
1424 /*-----------------------------------------------------------------------------
1425 | Copyright (c) 2014-2017, PhosphorJS Contributors
1426 |
1427 | Distributed under the terms of the BSD 3-Clause License.
1428 |
1429 | The full license is in the file LICENSE, distributed with this software.
1430 |----------------------------------------------------------------------------*/
1431 /**
1432 * Create an empty iterator.
1433 *
1434 * @returns A new iterator which yields nothing.
1435 *
1436 * #### Example
1437 * ```typescript
1438 * import { empty } from '@lumino/algorithm';
1439 *
1440 * let stream = empty<number>();
1441 *
1442 * Array.from(stream); // []
1443 * ```
1444 */
1445 // eslint-disable-next-line require-yield
1446 function* empty() {
1447 return;
1448 }
1449
1450 // Copyright (c) Jupyter Development Team.
1451 // Distributed under the terms of the Modified BSD License.
1452 /*-----------------------------------------------------------------------------
1453 | Copyright (c) 2014-2017, PhosphorJS Contributors
1454 |
1455 | Distributed under the terms of the BSD 3-Clause License.
1456 |
1457 | The full license is in the file LICENSE, distributed with this software.
1458 |----------------------------------------------------------------------------*/
1459 /**
1460 * Enumerate an iterable object.
1461 *
1462 * @param object - The iterable object of interest.
1463 *
1464 * @param start - The starting enum value. The default is `0`.
1465 *
1466 * @returns An iterator which yields the enumerated values.
1467 *
1468 * #### Example
1469 * ```typescript
1470 * import { enumerate } from '@lumino/algorithm';
1471 *
1472 * let data = ['foo', 'bar', 'baz'];
1473 *
1474 * let stream = enumerate(data, 1);
1475 *
1476 * Array.from(stream); // [[1, 'foo'], [2, 'bar'], [3, 'baz']]
1477 * ```
1478 */
1479 function* enumerate(object, start = 0) {
1480 for (const value of object) {
1481 yield [start++, value];
1482 }
1483 }
1484
1485 // Copyright (c) Jupyter Development Team.
1486 // Distributed under the terms of the Modified BSD License.
1487 /*-----------------------------------------------------------------------------
1488 | Copyright (c) 2014-2017, PhosphorJS Contributors
1489 |
1490 | Distributed under the terms of the BSD 3-Clause License.
1491 |
1492 | The full license is in the file LICENSE, distributed with this software.
1493 |----------------------------------------------------------------------------*/
1494 /**
1495 * Filter an iterable for values which pass a test.
1496 *
1497 * @param object - The iterable object of interest.
1498 *
1499 * @param fn - The predicate function to invoke for each value.
1500 *
1501 * @returns An iterator which yields the values which pass the test.
1502 *
1503 * #### Example
1504 * ```typescript
1505 * import { filter } from '@lumino/algorithm';
1506 *
1507 * let data = [1, 2, 3, 4, 5, 6];
1508 *
1509 * let stream = filter(data, value => value % 2 === 0);
1510 *
1511 * Array.from(stream); // [2, 4, 6]
1512 * ```
1513 */
1514 function* filter(object, fn) {
1515 let index = 0;
1516 for (const value of object) {
1517 if (fn(value, index++)) {
1518 yield value;
1519 }
1520 }
1521 }
1522
1523 // Copyright (c) Jupyter Development Team.
1524 // Distributed under the terms of the Modified BSD License.
1525 /*-----------------------------------------------------------------------------
1526 | Copyright (c) 2014-2017, PhosphorJS Contributors
1527 |
1528 | Distributed under the terms of the BSD 3-Clause License.
1529 |
1530 | The full license is in the file LICENSE, distributed with this software.
1531 |----------------------------------------------------------------------------*/
1532 /**
1533 * Find the first value in an iterable which matches a predicate.
1534 *
1535 * @param object - The iterable object to search.
1536 *
1537 * @param fn - The predicate function to apply to the values.
1538 *
1539 * @returns The first matching value, or `undefined` if no matching
1540 * value is found.
1541 *
1542 * #### Complexity
1543 * Linear.
1544 *
1545 * #### Example
1546 * ```typescript
1547 * import { find } from '@lumino/algorithm';
1548 *
1549 * interface IAnimal { species: string, name: string };
1550 *
1551 * function isCat(value: IAnimal): boolean {
1552 * return value.species === 'cat';
1553 * }
1554 *
1555 * let data: IAnimal[] = [
1556 * { species: 'dog', name: 'spot' },
1557 * { species: 'cat', name: 'fluffy' },
1558 * { species: 'alligator', name: 'pocho' }
1559 * ];
1560 *
1561 * find(data, isCat).name; // 'fluffy'
1562 * ```
1563 */
1564 function find(object, fn) {
1565 let index = 0;
1566 for (const value of object) {
1567 if (fn(value, index++)) {
1568 return value;
1569 }
1570 }
1571 return undefined;
1572 }
1573 /**
1574 * Find the index of the first value which matches a predicate.
1575 *
1576 * @param object - The iterable object to search.
1577 *
1578 * @param fn - The predicate function to apply to the values.
1579 *
1580 * @returns The index of the first matching value, or `-1` if no
1581 * matching value is found.
1582 *
1583 * #### Complexity
1584 * Linear.
1585 *
1586 * #### Example
1587 * ```typescript
1588 * import { findIndex } from '@lumino/algorithm';
1589 *
1590 * interface IAnimal { species: string, name: string };
1591 *
1592 * function isCat(value: IAnimal): boolean {
1593 * return value.species === 'cat';
1594 * }
1595 *
1596 * let data: IAnimal[] = [
1597 * { species: 'dog', name: 'spot' },
1598 * { species: 'cat', name: 'fluffy' },
1599 * { species: 'alligator', name: 'pocho' }
1600 * ];
1601 *
1602 * findIndex(data, isCat); // 1
1603 * ```
1604 */
1605 function findIndex(object, fn) {
1606 let index = 0;
1607 for (const value of object) {
1608 if (fn(value, index++)) {
1609 return index - 1;
1610 }
1611 }
1612 return -1;
1613 }
1614 /**
1615 * Find the minimum value in an iterable.
1616 *
1617 * @param object - The iterable object to search.
1618 *
1619 * @param fn - The 3-way comparison function to apply to the values.
1620 * It should return `< 0` if the first value is less than the second.
1621 * `0` if the values are equivalent, or `> 0` if the first value is
1622 * greater than the second.
1623 *
1624 * @returns The minimum value in the iterable. If multiple values are
1625 * equivalent to the minimum, the left-most value is returned. If
1626 * the iterable is empty, this returns `undefined`.
1627 *
1628 * #### Complexity
1629 * Linear.
1630 *
1631 * #### Example
1632 * ```typescript
1633 * import { min } from '@lumino/algorithm';
1634 *
1635 * function numberCmp(a: number, b: number): number {
1636 * return a - b;
1637 * }
1638 *
1639 * min([7, 4, 0, 3, 9, 4], numberCmp); // 0
1640 * ```
1641 */
1642 function min(object, fn) {
1643 let result = undefined;
1644 for (const value of object) {
1645 if (result === undefined) {
1646 result = value;
1647 continue;
1648 }
1649 if (fn(value, result) < 0) {
1650 result = value;
1651 }
1652 }
1653 return result;
1654 }
1655 /**
1656 * Find the maximum value in an iterable.
1657 *
1658 * @param object - The iterable object to search.
1659 *
1660 * @param fn - The 3-way comparison function to apply to the values.
1661 * It should return `< 0` if the first value is less than the second.
1662 * `0` if the values are equivalent, or `> 0` if the first value is
1663 * greater than the second.
1664 *
1665 * @returns The maximum value in the iterable. If multiple values are
1666 * equivalent to the maximum, the left-most value is returned. If
1667 * the iterable is empty, this returns `undefined`.
1668 *
1669 * #### Complexity
1670 * Linear.
1671 *
1672 * #### Example
1673 * ```typescript
1674 * import { max } from '@lumino/algorithm';
1675 *
1676 * function numberCmp(a: number, b: number): number {
1677 * return a - b;
1678 * }
1679 *
1680 * max([7, 4, 0, 3, 9, 4], numberCmp); // 9
1681 * ```
1682 */
1683 function max(object, fn) {
1684 let result = undefined;
1685 for (const value of object) {
1686 if (result === undefined) {
1687 result = value;
1688 continue;
1689 }
1690 if (fn(value, result) > 0) {
1691 result = value;
1692 }
1693 }
1694 return result;
1695 }
1696 /**
1697 * Find the minimum and maximum values in an iterable.
1698 *
1699 * @param object - The iterable object to search.
1700 *
1701 * @param fn - The 3-way comparison function to apply to the values.
1702 * It should return `< 0` if the first value is less than the second.
1703 * `0` if the values are equivalent, or `> 0` if the first value is
1704 * greater than the second.
1705 *
1706 * @returns A 2-tuple of the `[min, max]` values in the iterable. If
1707 * multiple values are equivalent, the left-most values are returned.
1708 * If the iterable is empty, this returns `undefined`.
1709 *
1710 * #### Complexity
1711 * Linear.
1712 *
1713 * #### Example
1714 * ```typescript
1715 * import { minmax } from '@lumino/algorithm';
1716 *
1717 * function numberCmp(a: number, b: number): number {
1718 * return a - b;
1719 * }
1720 *
1721 * minmax([7, 4, 0, 3, 9, 4], numberCmp); // [0, 9]
1722 * ```
1723 */
1724 function minmax(object, fn) {
1725 let empty = true;
1726 let vmin;
1727 let vmax;
1728 for (const value of object) {
1729 if (empty) {
1730 vmin = value;
1731 vmax = value;
1732 empty = false;
1733 }
1734 else if (fn(value, vmin) < 0) {
1735 vmin = value;
1736 }
1737 else if (fn(value, vmax) > 0) {
1738 vmax = value;
1739 }
1740 }
1741 return empty ? undefined : [vmin, vmax];
1742 }
1743
1744 // Copyright (c) Jupyter Development Team.
1745 // Distributed under the terms of the Modified BSD License.
1746 /*-----------------------------------------------------------------------------
1747 | Copyright (c) 2014-2017, PhosphorJS Contributors
1748 |
1749 | Distributed under the terms of the BSD 3-Clause License.
1750 |
1751 | The full license is in the file LICENSE, distributed with this software.
1752 |----------------------------------------------------------------------------*/
1753 /**
1754 * Create an array from an iterable of values.
1755 *
1756 * @deprecated
1757 *
1758 * @param object - The iterable object of interest.
1759 *
1760 * @returns A new array of values from the given object.
1761 *
1762 * #### Example
1763 * ```typescript
1764 * import { toArray } from '@lumino/algorithm';
1765 *
1766 * let stream = [1, 2, 3, 4, 5, 6][Symbol.iterator]();
1767 *
1768 * toArray(stream); // [1, 2, 3, 4, 5, 6];
1769 * ```
1770 */
1771 function toArray(object) {
1772 return Array.from(object);
1773 }
1774 /**
1775 * Create an object from an iterable of key/value pairs.
1776 *
1777 * @param object - The iterable object of interest.
1778 *
1779 * @returns A new object mapping keys to values.
1780 *
1781 * #### Example
1782 * ```typescript
1783 * import { toObject } from '@lumino/algorithm';
1784 *
1785 * let data: [string, number][] = [['one', 1], ['two', 2], ['three', 3]];
1786 *
1787 * toObject(data); // { one: 1, two: 2, three: 3 }
1788 * ```
1789 */
1790 function toObject(object) {
1791 const result = {};
1792 for (const [key, value] of object) {
1793 result[key] = value;
1794 }
1795 return result;
1796 }
1797 /**
1798 * Invoke a function for each value in an iterable.
1799 *
1800 * @deprecated
1801 *
1802 * @param object - The iterable object of interest.
1803 *
1804 * @param fn - The callback function to invoke for each value.
1805 *
1806 * #### Notes
1807 * Iteration can be terminated early by returning `false` from the
1808 * callback function.
1809 *
1810 * #### Complexity
1811 * Linear.
1812 *
1813 * #### Example
1814 * ```typescript
1815 * import { each } from '@lumino/algorithm';
1816 *
1817 * let data = [5, 7, 0, -2, 9];
1818 *
1819 * each(data, value => { console.log(value); });
1820 * ```
1821 */
1822 function each(object, fn) {
1823 let index = 0;
1824 for (const value of object) {
1825 if (false === fn(value, index++)) {
1826 return;
1827 }
1828 }
1829 }
1830 /**
1831 * Test whether all values in an iterable satisfy a predicate.
1832 *
1833 * @param object - The iterable object of interest.
1834 *
1835 * @param fn - The predicate function to invoke for each value.
1836 *
1837 * @returns `true` if all values pass the test, `false` otherwise.
1838 *
1839 * #### Notes
1840 * Iteration terminates on the first `false` predicate result.
1841 *
1842 * #### Complexity
1843 * Linear.
1844 *
1845 * #### Example
1846 * ```typescript
1847 * import { every } from '@lumino/algorithm';
1848 *
1849 * let data = [5, 7, 1];
1850 *
1851 * every(data, value => value % 2 === 0); // false
1852 * every(data, value => value % 2 === 1); // true
1853 * ```
1854 */
1855 function every(object, fn) {
1856 let index = 0;
1857 for (const value of object) {
1858 if (false === fn(value, index++)) {
1859 return false;
1860 }
1861 }
1862 return true;
1863 }
1864 /**
1865 * Test whether any value in an iterable satisfies a predicate.
1866 *
1867 * @param object - The iterable object of interest.
1868 *
1869 * @param fn - The predicate function to invoke for each value.
1870 *
1871 * @returns `true` if any value passes the test, `false` otherwise.
1872 *
1873 * #### Notes
1874 * Iteration terminates on the first `true` predicate result.
1875 *
1876 * #### Complexity
1877 * Linear.
1878 *
1879 * #### Example
1880 * ```typescript
1881 * import { some } from '@lumino/algorithm';
1882 *
1883 * let data = [5, 7, 1];
1884 *
1885 * some(data, value => value === 7); // true
1886 * some(data, value => value === 3); // false
1887 * ```
1888 */
1889 function some(object, fn) {
1890 let index = 0;
1891 for (const value of object) {
1892 if (fn(value, index++)) {
1893 return true;
1894 }
1895 }
1896 return false;
1897 }
1898
1899 // Copyright (c) Jupyter Development Team.
1900 // Distributed under the terms of the Modified BSD License.
1901 /*-----------------------------------------------------------------------------
1902 | Copyright (c) 2014-2017, PhosphorJS Contributors
1903 |
1904 | Distributed under the terms of the BSD 3-Clause License.
1905 |
1906 | The full license is in the file LICENSE, distributed with this software.
1907 |----------------------------------------------------------------------------*/
1908 /**
1909 * Transform the values of an iterable with a mapping function.
1910 *
1911 * @param object - The iterable object of interest.
1912 *
1913 * @param fn - The mapping function to invoke for each value.
1914 *
1915 * @returns An iterator which yields the transformed values.
1916 *
1917 * #### Example
1918 * ```typescript
1919 * import { map } from '@lumino/algorithm';
1920 *
1921 * let data = [1, 2, 3];
1922 *
1923 * let stream = map(data, value => value * 2);
1924 *
1925 * Array.from(stream); // [2, 4, 6]
1926 * ```
1927 */
1928 function* map(object, fn) {
1929 let index = 0;
1930 for (const value of object) {
1931 yield fn(value, index++);
1932 }
1933 }
1934
1935 // Copyright (c) Jupyter Development Team.
1936 // Distributed under the terms of the Modified BSD License.
1937 /*-----------------------------------------------------------------------------
1938 | Copyright (c) 2014-2017, PhosphorJS Contributors
1939 |
1940 | Distributed under the terms of the BSD 3-Clause License.
1941 |
1942 | The full license is in the file LICENSE, distributed with this software.
1943 |----------------------------------------------------------------------------*/
1944 /**
1945 * Create an iterator of evenly spaced values.
1946 *
1947 * @param start - The starting value for the range, inclusive.
1948 *
1949 * @param stop - The stopping value for the range, exclusive.
1950 *
1951 * @param step - The distance between each value.
1952 *
1953 * @returns An iterator which produces evenly spaced values.
1954 *
1955 * #### Notes
1956 * In the single argument form of `range(stop)`, `start` defaults to
1957 * `0` and `step` defaults to `1`.
1958 *
1959 * In the two argument form of `range(start, stop)`, `step` defaults
1960 * to `1`.
1961 *
1962 * #### Example
1963 * ```typescript
1964 * import { range } from '@lumino/algorithm';
1965 *
1966 * let stream = range(2, 4);
1967 *
1968 * Array.from(stream); // [2, 3]
1969 * ```
1970 */
1971 function* range(start, stop, step) {
1972 if (stop === undefined) {
1973 stop = start;
1974 start = 0;
1975 step = 1;
1976 }
1977 else if (step === undefined) {
1978 step = 1;
1979 }
1980 const length = Private.rangeLength(start, stop, step);
1981 for (let index = 0; index < length; index++) {
1982 yield start + step * index;
1983 }
1984 }
1985 /**
1986 * The namespace for the module implementation details.
1987 */
1988 var Private;
1989 (function (Private) {
1990 /**
1991 * Compute the effective length of a range.
1992 *
1993 * @param start - The starting value for the range, inclusive.
1994 *
1995 * @param stop - The stopping value for the range, exclusive.
1996 *
1997 * @param step - The distance between each value.
1998 *
1999 * @returns The number of steps need to traverse the range.
2000 */
2001 function rangeLength(start, stop, step) {
2002 if (step === 0) {
2003 return Infinity;
2004 }
2005 if (start > stop && step > 0) {
2006 return 0;
2007 }
2008 if (start < stop && step < 0) {
2009 return 0;
2010 }
2011 return Math.ceil((stop - start) / step);
2012 }
2013 Private.rangeLength = rangeLength;
2014 })(Private || (Private = {}));
2015
2016 // Copyright (c) Jupyter Development Team.
2017 // Distributed under the terms of the Modified BSD License.
2018 /*-----------------------------------------------------------------------------
2019 | Copyright (c) 2014-2017, PhosphorJS Contributors
2020 |
2021 | Distributed under the terms of the BSD 3-Clause License.
2022 |
2023 | The full license is in the file LICENSE, distributed with this software.
2024 |----------------------------------------------------------------------------*/
2025 function reduce(object, fn, initial) {
2026 // Setup the iterator and fetch the first value.
2027 const it = object[Symbol.iterator]();
2028 let index = 0;
2029 let first = it.next();
2030 // An empty iterator and no initial value is an error.
2031 if (first.done && initial === undefined) {
2032 throw new TypeError('Reduce of empty iterable with no initial value.');
2033 }
2034 // If the iterator is empty, return the initial value.
2035 if (first.done) {
2036 return initial;
2037 }
2038 // If the iterator has a single item and no initial value, the
2039 // reducer is not invoked and the first item is the return value.
2040 let second = it.next();
2041 if (second.done && initial === undefined) {
2042 return first.value;
2043 }
2044 // If iterator has a single item and an initial value is provided,
2045 // the reducer is invoked and that result is the return value.
2046 if (second.done) {
2047 return fn(initial, first.value, index++);
2048 }
2049 // Setup the initial accumlated value.
2050 let accumulator;
2051 if (initial === undefined) {
2052 accumulator = fn(first.value, second.value, index++);
2053 }
2054 else {
2055 accumulator = fn(fn(initial, first.value, index++), second.value, index++);
2056 }
2057 // Iterate the rest of the values, updating the accumulator.
2058 let next;
2059 while (!(next = it.next()).done) {
2060 accumulator = fn(accumulator, next.value, index++);
2061 }
2062 // Return the final accumulated value.
2063 return accumulator;
2064 }
2065
2066 // Copyright (c) Jupyter Development Team.
2067 // Distributed under the terms of the Modified BSD License.
2068 /*-----------------------------------------------------------------------------
2069 | Copyright (c) 2014-2017, PhosphorJS Contributors
2070 |
2071 | Distributed under the terms of the BSD 3-Clause License.
2072 |
2073 | The full license is in the file LICENSE, distributed with this software.
2074 |----------------------------------------------------------------------------*/
2075 /**
2076 * Create an iterator which repeats a value a number of times.
2077 *
2078 * @deprecated
2079 *
2080 * @param value - The value to repeat.
2081 *
2082 * @param count - The number of times to repeat the value.
2083 *
2084 * @returns A new iterator which repeats the specified value.
2085 *
2086 * #### Example
2087 * ```typescript
2088 * import { repeat } from '@lumino/algorithm';
2089 *
2090 * let stream = repeat(7, 3);
2091 *
2092 * Array.from(stream); // [7, 7, 7]
2093 * ```
2094 */
2095 function* repeat(value, count) {
2096 while (0 < count--) {
2097 yield value;
2098 }
2099 }
2100 /**
2101 * Create an iterator which yields a value a single time.
2102 *
2103 * @deprecated
2104 *
2105 * @param value - The value to wrap in an iterator.
2106 *
2107 * @returns A new iterator which yields the value a single time.
2108 *
2109 * #### Example
2110 * ```typescript
2111 * import { once } from '@lumino/algorithm';
2112 *
2113 * let stream = once(7);
2114 *
2115 * Array.from(stream); // [7]
2116 * ```
2117 */
2118 function* once(value) {
2119 yield value;
2120 }
2121
2122 // Copyright (c) Jupyter Development Team.
2123 // Distributed under the terms of the Modified BSD License.
2124 /*-----------------------------------------------------------------------------
2125 | Copyright (c) 2014-2017, PhosphorJS Contributors
2126 |
2127 | Distributed under the terms of the BSD 3-Clause License.
2128 |
2129 | The full license is in the file LICENSE, distributed with this software.
2130 |----------------------------------------------------------------------------*/
2131 /**
2132 * Create an iterator for a retroable object.
2133 *
2134 * @param object - The retroable or array-like object of interest.
2135 *
2136 * @returns An iterator which traverses the object's values in reverse.
2137 *
2138 * #### Example
2139 * ```typescript
2140 * import { retro } from '@lumino/algorithm';
2141 *
2142 * let data = [1, 2, 3, 4, 5, 6];
2143 *
2144 * let stream = retro(data);
2145 *
2146 * Array.from(stream); // [6, 5, 4, 3, 2, 1]
2147 * ```
2148 */
2149 function* retro(object) {
2150 if (typeof object.retro === 'function') {
2151 yield* object.retro();
2152 }
2153 else {
2154 for (let index = object.length - 1; index > -1; index--) {
2155 yield object[index];
2156 }
2157 }
2158 }
2159
2160 // Copyright (c) Jupyter Development Team.
2161 // Distributed under the terms of the Modified BSD License.
2162 /*-----------------------------------------------------------------------------
2163 | Copyright (c) 2014-2017, PhosphorJS Contributors
2164 |
2165 | Distributed under the terms of the BSD 3-Clause License.
2166 |
2167 | The full license is in the file LICENSE, distributed with this software.
2168 |----------------------------------------------------------------------------*/
2169 /**
2170 * Topologically sort an iterable of edges.
2171 *
2172 * @param edges - The iterable object of edges to sort.
2173 * An edge is represented as a 2-tuple of `[fromNode, toNode]`.
2174 *
2175 * @returns The topologically sorted array of nodes.
2176 *
2177 * #### Notes
2178 * If a cycle is present in the graph, the cycle will be ignored and
2179 * the return value will be only approximately sorted.
2180 *
2181 * #### Example
2182 * ```typescript
2183 * import { topologicSort } from '@lumino/algorithm';
2184 *
2185 * let data = [
2186 * ['d', 'e'],
2187 * ['c', 'd'],
2188 * ['a', 'b'],
2189 * ['b', 'c']
2190 * ];
2191 *
2192 * topologicSort(data); // ['a', 'b', 'c', 'd', 'e']
2193 * ```
2194 */
2195 function topologicSort(edges) {
2196 // Setup the shared sorting state.
2197 let sorted = [];
2198 let visited = new Set();
2199 let graph = new Map();
2200 // Add the edges to the graph.
2201 for (const edge of edges) {
2202 addEdge(edge);
2203 }
2204 // Visit each node in the graph.
2205 for (const [k] of graph) {
2206 visit(k);
2207 }
2208 // Return the sorted results.
2209 return sorted;
2210 // Add an edge to the graph.
2211 function addEdge(edge) {
2212 let [fromNode, toNode] = edge;
2213 let children = graph.get(toNode);
2214 if (children) {
2215 children.push(fromNode);
2216 }
2217 else {
2218 graph.set(toNode, [fromNode]);
2219 }
2220 }
2221 // Recursively visit the node.
2222 function visit(node) {
2223 if (visited.has(node)) {
2224 return;
2225 }
2226 visited.add(node);
2227 let children = graph.get(node);
2228 if (children) {
2229 for (const child of children) {
2230 visit(child);
2231 }
2232 }
2233 sorted.push(node);
2234 }
2235 }
2236
2237 // Copyright (c) Jupyter Development Team.
2238 // Distributed under the terms of the Modified BSD License.
2239 /*-----------------------------------------------------------------------------
2240 | Copyright (c) 2014-2017, PhosphorJS Contributors
2241 |
2242 | Distributed under the terms of the BSD 3-Clause License.
2243 |
2244 | The full license is in the file LICENSE, distributed with this software.
2245 |----------------------------------------------------------------------------*/
2246 /**
2247 * Iterate over an iterable using a stepped increment.
2248 *
2249 * @param object - The iterable object of interest.
2250 *
2251 * @param step - The distance to step on each iteration. A value
2252 * of less than `1` will behave the same as a value of `1`.
2253 *
2254 * @returns An iterator which traverses the iterable step-wise.
2255 *
2256 * #### Example
2257 * ```typescript
2258 * import { stride } from '@lumino/algorithm';
2259 *
2260 * let data = [1, 2, 3, 4, 5, 6];
2261 *
2262 * let stream = stride(data, 2);
2263 *
2264 * Array.from(stream); // [1, 3, 5];
2265 * ```
2266 */
2267 function* stride(object, step) {
2268 let count = 0;
2269 for (const value of object) {
2270 if (0 === count++ % step) {
2271 yield value;
2272 }
2273 }
2274 }
2275
2276 // Copyright (c) Jupyter Development Team.
2277 // Distributed under the terms of the Modified BSD License.
2278 /*-----------------------------------------------------------------------------
2279 | Copyright (c) 2014-2017, PhosphorJS Contributors
2280 |
2281 | Distributed under the terms of the BSD 3-Clause License.
2282 |
2283 | The full license is in the file LICENSE, distributed with this software.
2284 |----------------------------------------------------------------------------*/
2285 /**
2286 * The namespace for string-specific algorithms.
2287 */
2288 exports.StringExt = void 0;
2289 (function (StringExt) {
2290 /**
2291 * Find the indices of characters in a source text.
2292 *
2293 * @param source - The source text which should be searched.
2294 *
2295 * @param query - The characters to locate in the source text.
2296 *
2297 * @param start - The index to start the search.
2298 *
2299 * @returns The matched indices, or `null` if there is no match.
2300 *
2301 * #### Complexity
2302 * Linear on `sourceText`.
2303 *
2304 * #### Notes
2305 * In order for there to be a match, all of the characters in `query`
2306 * **must** appear in `source` in the order given by `query`.
2307 *
2308 * Characters are matched using strict `===` equality.
2309 */
2310 function findIndices(source, query, start = 0) {
2311 let indices = new Array(query.length);
2312 for (let i = 0, j = start, n = query.length; i < n; ++i, ++j) {
2313 j = source.indexOf(query[i], j);
2314 if (j === -1) {
2315 return null;
2316 }
2317 indices[i] = j;
2318 }
2319 return indices;
2320 }
2321 StringExt.findIndices = findIndices;
2322 /**
2323 * A string matcher which uses a sum-of-squares algorithm.
2324 *
2325 * @param source - The source text which should be searched.
2326 *
2327 * @param query - The characters to locate in the source text.
2328 *
2329 * @param start - The index to start the search.
2330 *
2331 * @returns The match result, or `null` if there is no match.
2332 * A lower `score` represents a stronger match.
2333 *
2334 * #### Complexity
2335 * Linear on `sourceText`.
2336 *
2337 * #### Notes
2338 * This scoring algorithm uses a sum-of-squares approach to determine
2339 * the score. In order for there to be a match, all of the characters
2340 * in `query` **must** appear in `source` in order. The index of each
2341 * matching character is squared and added to the score. This means
2342 * that early and consecutive character matches are preferred, while
2343 * late matches are heavily penalized.
2344 */
2345 function matchSumOfSquares(source, query, start = 0) {
2346 let indices = findIndices(source, query, start);
2347 if (!indices) {
2348 return null;
2349 }
2350 let score = 0;
2351 for (let i = 0, n = indices.length; i < n; ++i) {
2352 let j = indices[i] - start;
2353 score += j * j;
2354 }
2355 return { score, indices };
2356 }
2357 StringExt.matchSumOfSquares = matchSumOfSquares;
2358 /**
2359 * A string matcher which uses a sum-of-deltas algorithm.
2360 *
2361 * @param source - The source text which should be searched.
2362 *
2363 * @param query - The characters to locate in the source text.
2364 *
2365 * @param start - The index to start the search.
2366 *
2367 * @returns The match result, or `null` if there is no match.
2368 * A lower `score` represents a stronger match.
2369 *
2370 * #### Complexity
2371 * Linear on `sourceText`.
2372 *
2373 * #### Notes
2374 * This scoring algorithm uses a sum-of-deltas approach to determine
2375 * the score. In order for there to be a match, all of the characters
2376 * in `query` **must** appear in `source` in order. The delta between
2377 * the indices are summed to create the score. This means that groups
2378 * of matched characters are preferred, while fragmented matches are
2379 * penalized.
2380 */
2381 function matchSumOfDeltas(source, query, start = 0) {
2382 let indices = findIndices(source, query, start);
2383 if (!indices) {
2384 return null;
2385 }
2386 let score = 0;
2387 let last = start - 1;
2388 for (let i = 0, n = indices.length; i < n; ++i) {
2389 let j = indices[i];
2390 score += j - last - 1;
2391 last = j;
2392 }
2393 return { score, indices };
2394 }
2395 StringExt.matchSumOfDeltas = matchSumOfDeltas;
2396 /**
2397 * Highlight the matched characters of a source text.
2398 *
2399 * @param source - The text which should be highlighted.
2400 *
2401 * @param indices - The indices of the matched characters. They must
2402 * appear in increasing order and must be in bounds of the source.
2403 *
2404 * @param fn - The function to apply to the matched chunks.
2405 *
2406 * @returns An array of unmatched and highlighted chunks.
2407 */
2408 function highlight(source, indices, fn) {
2409 // Set up the result array.
2410 let result = [];
2411 // Set up the counter variables.
2412 let k = 0;
2413 let last = 0;
2414 let n = indices.length;
2415 // Iterator over each index.
2416 while (k < n) {
2417 // Set up the chunk indices.
2418 let i = indices[k];
2419 let j = indices[k];
2420 // Advance the right chunk index until it's non-contiguous.
2421 while (++k < n && indices[k] === j + 1) {
2422 j++;
2423 }
2424 // Extract the unmatched text.
2425 if (last < i) {
2426 result.push(source.slice(last, i));
2427 }
2428 // Extract and highlight the matched text.
2429 if (i < j + 1) {
2430 result.push(fn(source.slice(i, j + 1)));
2431 }
2432 // Update the last visited index.
2433 last = j + 1;
2434 }
2435 // Extract any remaining unmatched text.
2436 if (last < source.length) {
2437 result.push(source.slice(last));
2438 }
2439 // Return the highlighted result.
2440 return result;
2441 }
2442 StringExt.highlight = highlight;
2443 /**
2444 * A 3-way string comparison function.
2445 *
2446 * @param a - The first string of interest.
2447 *
2448 * @param b - The second string of interest.
2449 *
2450 * @returns `-1` if `a < b`, else `1` if `a > b`, else `0`.
2451 */
2452 function cmp(a, b) {
2453 return a < b ? -1 : a > b ? 1 : 0;
2454 }
2455 StringExt.cmp = cmp;
2456 })(exports.StringExt || (exports.StringExt = {}));
2457
2458 // Copyright (c) Jupyter Development Team.
2459 // Distributed under the terms of the Modified BSD License.
2460 /*-----------------------------------------------------------------------------
2461 | Copyright (c) 2014-2017, PhosphorJS Contributors
2462 |
2463 | Distributed under the terms of the BSD 3-Clause License.
2464 |
2465 | The full license is in the file LICENSE, distributed with this software.
2466 |----------------------------------------------------------------------------*/
2467 /**
2468 * Take a fixed number of items from an iterable.
2469 *
2470 * @param object - The iterable object of interest.
2471 *
2472 * @param count - The number of items to take from the iterable.
2473 *
2474 * @returns An iterator which yields the specified number of items
2475 * from the source iterable.
2476 *
2477 * #### Notes
2478 * The returned iterator will exhaust early if the source iterable
2479 * contains an insufficient number of items.
2480 *
2481 * #### Example
2482 * ```typescript
2483 * import { take } from '@lumino/algorithm';
2484 *
2485 * let stream = take([5, 4, 3, 2, 1, 0, -1], 3);
2486 *
2487 * Array.from(stream); // [5, 4, 3]
2488 * ```
2489 */
2490 function* take(object, count) {
2491 if (count < 1) {
2492 return;
2493 }
2494 const it = object[Symbol.iterator]();
2495 let item;
2496 while (0 < count-- && !(item = it.next()).done) {
2497 yield item.value;
2498 }
2499 }
2500
2501 // Copyright (c) Jupyter Development Team.
2502 /**
2503 * Iterate several iterables in lockstep.
2504 *
2505 * @param objects - The iterable objects of interest.
2506 *
2507 * @returns An iterator which yields successive tuples of values where
2508 * each value is taken in turn from the provided iterables. It will
2509 * be as long as the shortest provided iterable.
2510 *
2511 * #### Example
2512 * ```typescript
2513 * import { zip } from '@lumino/algorithm';
2514 *
2515 * let data1 = [1, 2, 3];
2516 * let data2 = [4, 5, 6];
2517 *
2518 * let stream = zip(data1, data2);
2519 *
2520 * Array.from(stream); // [[1, 4], [2, 5], [3, 6]]
2521 * ```
2522 */
2523 function* zip(...objects) {
2524 const iters = objects.map(obj => obj[Symbol.iterator]());
2525 let tuple = iters.map(it => it.next());
2526 for (; every(tuple, item => !item.done); tuple = iters.map(it => it.next())) {
2527 yield tuple.map(item => item.value);
2528 }
2529 }
2530
2531 exports.chain = chain;
2532 exports.each = each;
2533 exports.empty = empty;
2534 exports.enumerate = enumerate;
2535 exports.every = every;
2536 exports.filter = filter;
2537 exports.find = find;
2538 exports.findIndex = findIndex;
2539 exports.map = map;
2540 exports.max = max;
2541 exports.min = min;
2542 exports.minmax = minmax;
2543 exports.once = once;
2544 exports.range = range;
2545 exports.reduce = reduce;
2546 exports.repeat = repeat;
2547 exports.retro = retro;
2548 exports.some = some;
2549 exports.stride = stride;
2550 exports.take = take;
2551 exports.toArray = toArray;
2552 exports.toObject = toObject;
2553 exports.topologicSort = topologicSort;
2554 exports.zip = zip;
2555
2556}));
2557//# sourceMappingURL=index.js.map