UNPKG

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