UNPKG

47.7 kBJavaScriptView Raw
1"use strict";
2/*-----------------------------------------------------------------------------
3| Copyright (c) 2014-2017, PhosphorJS Contributors
4|
5| Distributed under the terms of the BSD 3-Clause License.
6|
7| The full license is in the file LICENSE, distributed with this software.
8|----------------------------------------------------------------------------*/
9Object.defineProperty(exports, "__esModule", { value: true });
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 '@phosphor/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, stop) {
56 if (start === void 0) { start = 0; }
57 if (stop === void 0) { stop = -1; }
58 var n = array.length;
59 if (n === 0) {
60 return -1;
61 }
62 if (start < 0) {
63 start = Math.max(0, start + n);
64 }
65 else {
66 start = Math.min(start, n - 1);
67 }
68 if (stop < 0) {
69 stop = Math.max(0, stop + n);
70 }
71 else {
72 stop = Math.min(stop, n - 1);
73 }
74 var span;
75 if (stop < start) {
76 span = (stop + 1) + (n - start);
77 }
78 else {
79 span = stop - start + 1;
80 }
81 for (var i = 0; i < span; ++i) {
82 var j = (start + i) % n;
83 if (array[j] === value) {
84 return j;
85 }
86 }
87 return -1;
88 }
89 ArrayExt.firstIndexOf = firstIndexOf;
90 /**
91 * Find the index of the last occurrence of a value in an array.
92 *
93 * @param array - The array-like object to search.
94 *
95 * @param value - The value to locate in the array. Values are
96 * compared using strict `===` equality.
97 *
98 * @param start - The index of the first element in the range to be
99 * searched, inclusive. The default value is `-1`. Negative values
100 * are taken as an offset from the end of the array.
101 *
102 * @param stop - The index of the last element in the range to be
103 * searched, inclusive. The default value is `0`. Negative values
104 * are taken as an offset from the end of the array.
105 *
106 * @returns The index of the last occurrence of the value, or `-1`
107 * if the value is not found.
108 *
109 * #### Notes
110 * If `start < stop` the search will wrap at the front of the array.
111 *
112 * #### Complexity
113 * Linear.
114 *
115 * #### Undefined Behavior
116 * A `start` or `stop` which is non-integral.
117 *
118 * #### Example
119 * ```typescript
120 * import { ArrayExt } from '@phosphor/algorithm';
121 *
122 * let data = ['one', 'two', 'three', 'four', 'one'];
123 * ArrayExt.lastIndexOf(data, 'red'); // -1
124 * ArrayExt.lastIndexOf(data, 'one'); // 4
125 * ArrayExt.lastIndexOf(data, 'one', 1); // 0
126 * ArrayExt.lastIndexOf(data, 'two', 0); // -1
127 * ArrayExt.lastIndexOf(data, 'two', 0, 1); // 1
128 * ```
129 */
130 function lastIndexOf(array, value, start, stop) {
131 if (start === void 0) { start = -1; }
132 if (stop === void 0) { stop = 0; }
133 var n = array.length;
134 if (n === 0) {
135 return -1;
136 }
137 if (start < 0) {
138 start = Math.max(0, start + n);
139 }
140 else {
141 start = Math.min(start, n - 1);
142 }
143 if (stop < 0) {
144 stop = Math.max(0, stop + n);
145 }
146 else {
147 stop = Math.min(stop, n - 1);
148 }
149 var span;
150 if (start < stop) {
151 span = (start + 1) + (n - stop);
152 }
153 else {
154 span = start - stop + 1;
155 }
156 for (var i = 0; i < span; ++i) {
157 var j = (start - i + n) % n;
158 if (array[j] === value) {
159 return j;
160 }
161 }
162 return -1;
163 }
164 ArrayExt.lastIndexOf = lastIndexOf;
165 /**
166 * Find the index of the first value which matches a predicate.
167 *
168 * @param array - The array-like object to search.
169 *
170 * @param fn - The predicate function to apply to the values.
171 *
172 * @param start - The index of the first element in the range to be
173 * searched, inclusive. The default value is `0`. Negative values
174 * are taken as an offset from the end of the array.
175 *
176 * @param stop - The index of the last element in the range to be
177 * searched, inclusive. The default value is `-1`. Negative values
178 * are taken as an offset from the end of the array.
179 *
180 * @returns The index of the first matching value, or `-1` if no
181 * matching value is found.
182 *
183 * #### Notes
184 * If `stop < start` the search will wrap at the end of the array.
185 *
186 * #### Complexity
187 * Linear.
188 *
189 * #### Undefined Behavior
190 * A `start` or `stop` which is non-integral.
191 *
192 * Modifying the length of the array while searching.
193 *
194 * #### Example
195 * ```typescript
196 * import { ArrayExt } from '@phosphor/algorithm';
197 *
198 * function isEven(value: number): boolean {
199 * return value % 2 === 0;
200 * }
201 *
202 * let data = [1, 2, 3, 4, 3, 2, 1];
203 * ArrayExt.findFirstIndex(data, isEven); // 1
204 * ArrayExt.findFirstIndex(data, isEven, 4); // 5
205 * ArrayExt.findFirstIndex(data, isEven, 6); // -1
206 * ArrayExt.findFirstIndex(data, isEven, 6, 5); // 1
207 * ```
208 */
209 function findFirstIndex(array, fn, start, stop) {
210 if (start === void 0) { start = 0; }
211 if (stop === void 0) { stop = -1; }
212 var 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 var span;
229 if (stop < start) {
230 span = (stop + 1) + (n - start);
231 }
232 else {
233 span = stop - start + 1;
234 }
235 for (var i = 0; i < span; ++i) {
236 var 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 '@phosphor/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, stop) {
289 if (start === void 0) { start = -1; }
290 if (stop === void 0) { stop = 0; }
291 var n = array.length;
292 if (n === 0) {
293 return -1;
294 }
295 if (start < 0) {
296 start = Math.max(0, start + n);
297 }
298 else {
299 start = Math.min(start, n - 1);
300 }
301 if (stop < 0) {
302 stop = Math.max(0, stop + n);
303 }
304 else {
305 stop = Math.min(stop, n - 1);
306 }
307 var d;
308 if (start < stop) {
309 d = (start + 1) + (n - stop);
310 }
311 else {
312 d = start - stop + 1;
313 }
314 for (var i = 0; i < d; ++i) {
315 var j = (start - i + n) % n;
316 if (fn(array[j], j)) {
317 return j;
318 }
319 }
320 return -1;
321 }
322 ArrayExt.findLastIndex = findLastIndex;
323 /**
324 * Find the first value which matches a predicate.
325 *
326 * @param array - The array-like object to search.
327 *
328 * @param fn - The predicate function to apply to the values.
329 *
330 * @param start - The index of the first element in the range to be
331 * searched, inclusive. The default value is `0`. Negative values
332 * are taken as an offset from the end of the array.
333 *
334 * @param stop - The index of the last element in the range to be
335 * searched, inclusive. The default value is `-1`. Negative values
336 * are taken as an offset from the end of the array.
337 *
338 * @returns The first matching value, or `undefined` if no matching
339 * value is found.
340 *
341 * #### Notes
342 * If `stop < start` the search will wrap at the end of the array.
343 *
344 * #### Complexity
345 * Linear.
346 *
347 * #### Undefined Behavior
348 * A `start` or `stop` which is non-integral.
349 *
350 * Modifying the length of the array while searching.
351 *
352 * #### Example
353 * ```typescript
354 * import { ArrayExt } from '@phosphor/algorithm';
355 *
356 * function isEven(value: number): boolean {
357 * return value % 2 === 0;
358 * }
359 *
360 * let data = [1, 2, 3, 4, 3, 2, 1];
361 * ArrayExt.findFirstValue(data, isEven); // 2
362 * ArrayExt.findFirstValue(data, isEven, 2); // 4
363 * ArrayExt.findFirstValue(data, isEven, 6); // undefined
364 * ArrayExt.findFirstValue(data, isEven, 6, 5); // 2
365 * ```
366 */
367 function findFirstValue(array, fn, start, stop) {
368 if (start === void 0) { start = 0; }
369 if (stop === void 0) { stop = -1; }
370 var index = findFirstIndex(array, fn, start, stop);
371 return index !== -1 ? array[index] : undefined;
372 }
373 ArrayExt.findFirstValue = findFirstValue;
374 /**
375 * Find the last value which matches a predicate.
376 *
377 * @param object - The array-like object to search.
378 *
379 * @param fn - The predicate function to apply to the values.
380 *
381 * @param start - The index of the first element in the range to be
382 * searched, inclusive. The default value is `-1`. Negative values
383 * are taken as an offset from the end of the array.
384 *
385 * @param stop - The index of the last element in the range to be
386 * searched, inclusive. The default value is `0`. Negative values
387 * are taken as an offset from the end of the array.
388 *
389 * @returns The last matching value, or `undefined` if no matching
390 * value is found.
391 *
392 * #### Notes
393 * If `start < stop` the search will wrap at the front of the array.
394 *
395 * #### Complexity
396 * Linear.
397 *
398 * #### Undefined Behavior
399 * A `start` or `stop` which is non-integral.
400 *
401 * Modifying the length of the array while searching.
402 *
403 * #### Example
404 * ```typescript
405 * import { ArrayExt } from '@phosphor/algorithm';
406 *
407 * function isEven(value: number): boolean {
408 * return value % 2 === 0;
409 * }
410 *
411 * let data = [1, 2, 3, 4, 3, 2, 1];
412 * ArrayExt.findLastValue(data, isEven); // 2
413 * ArrayExt.findLastValue(data, isEven, 4); // 4
414 * ArrayExt.findLastValue(data, isEven, 0); // undefined
415 * ArrayExt.findLastValue(data, isEven, 0, 1); // 2
416 * ```
417 */
418 function findLastValue(array, fn, start, stop) {
419 if (start === void 0) { start = -1; }
420 if (stop === void 0) { stop = 0; }
421 var index = findLastIndex(array, fn, start, stop);
422 return index !== -1 ? array[index] : undefined;
423 }
424 ArrayExt.findLastValue = findLastValue;
425 /**
426 * Find the index of the first element which compares `>=` to a value.
427 *
428 * @param array - The sorted array-like object to search.
429 *
430 * @param value - The value to locate in the array.
431 *
432 * @param fn - The 3-way comparison function to apply to the values.
433 * It should return `< 0` if an element is less than a value, `0` if
434 * an element is equal to a value, or `> 0` if an element is greater
435 * than a value.
436 *
437 * @param start - The index of the first element in the range to be
438 * searched, inclusive. The default value is `0`. Negative values
439 * are taken as an offset from the end of the array.
440 *
441 * @param stop - The index of the last element in the range to be
442 * searched, inclusive. The default value is `-1`. Negative values
443 * are taken as an offset from the end of the array.
444 *
445 * @returns The index of the first element which compares `>=` to the
446 * value, or `length` if there is no such element. If the computed
447 * index for `stop` is less than `start`, then the computed index
448 * for `start` is returned.
449 *
450 * #### Notes
451 * The array must already be sorted in ascending order according to
452 * the comparison function.
453 *
454 * #### Complexity
455 * Logarithmic.
456 *
457 * #### Undefined Behavior
458 * Searching a range which is not sorted in ascending order.
459 *
460 * A `start` or `stop` which is non-integral.
461 *
462 * Modifying the length of the array while searching.
463 *
464 * #### Example
465 * ```typescript
466 * import { ArrayExt } from '@phosphor/algorithm';
467 *
468 * function numberCmp(a: number, b: number): number {
469 * return a - b;
470 * }
471 *
472 * let data = [0, 3, 4, 7, 7, 9];
473 * ArrayExt.lowerBound(data, 0, numberCmp); // 0
474 * ArrayExt.lowerBound(data, 6, numberCmp); // 3
475 * ArrayExt.lowerBound(data, 7, numberCmp); // 3
476 * ArrayExt.lowerBound(data, -1, numberCmp); // 0
477 * ArrayExt.lowerBound(data, 10, numberCmp); // 6
478 * ```
479 */
480 function lowerBound(array, value, fn, start, stop) {
481 if (start === void 0) { start = 0; }
482 if (stop === void 0) { stop = -1; }
483 var n = array.length;
484 if (n === 0) {
485 return 0;
486 }
487 if (start < 0) {
488 start = Math.max(0, start + n);
489 }
490 else {
491 start = Math.min(start, n - 1);
492 }
493 if (stop < 0) {
494 stop = Math.max(0, stop + n);
495 }
496 else {
497 stop = Math.min(stop, n - 1);
498 }
499 var begin = start;
500 var span = stop - start + 1;
501 while (span > 0) {
502 var half = span >> 1;
503 var middle = begin + half;
504 if (fn(array[middle], value) < 0) {
505 begin = middle + 1;
506 span -= half + 1;
507 }
508 else {
509 span = half;
510 }
511 }
512 return begin;
513 }
514 ArrayExt.lowerBound = lowerBound;
515 /**
516 * Find the index of the first element which compares `>` than a value.
517 *
518 * @param array - The sorted array-like object to search.
519 *
520 * @param value - The value to locate in the array.
521 *
522 * @param fn - The 3-way comparison function to apply to the values.
523 * It should return `< 0` if an element is less than a value, `0` if
524 * an element is equal to a value, or `> 0` if an element is greater
525 * than a value.
526 *
527 * @param start - The index of the first element in the range to be
528 * searched, inclusive. The default value is `0`. Negative values
529 * are taken as an offset from the end of the array.
530 *
531 * @param stop - The index of the last element in the range to be
532 * searched, inclusive. The default value is `-1`. Negative values
533 * are taken as an offset from the end of the array.
534 *
535 * @returns The index of the first element which compares `>` than the
536 * value, or `length` if there is no such element. If the computed
537 * index for `stop` is less than `start`, then the computed index
538 * for `start` is returned.
539 *
540 * #### Notes
541 * The array must already be sorted in ascending order according to
542 * the comparison function.
543 *
544 * #### Complexity
545 * Logarithmic.
546 *
547 * #### Undefined Behavior
548 * Searching a range which is not sorted in ascending order.
549 *
550 * A `start` or `stop` which is non-integral.
551 *
552 * Modifying the length of the array while searching.
553 *
554 * #### Example
555 * ```typescript
556 * import { ArrayExt } from '@phosphor/algorithm';
557 *
558 * function numberCmp(a: number, b: number): number {
559 * return a - b;
560 * }
561 *
562 * let data = [0, 3, 4, 7, 7, 9];
563 * ArrayExt.upperBound(data, 0, numberCmp); // 1
564 * ArrayExt.upperBound(data, 6, numberCmp); // 3
565 * ArrayExt.upperBound(data, 7, numberCmp); // 5
566 * ArrayExt.upperBound(data, -1, numberCmp); // 0
567 * ArrayExt.upperBound(data, 10, numberCmp); // 6
568 * ```
569 */
570 function upperBound(array, value, fn, start, stop) {
571 if (start === void 0) { start = 0; }
572 if (stop === void 0) { stop = -1; }
573 var n = array.length;
574 if (n === 0) {
575 return 0;
576 }
577 if (start < 0) {
578 start = Math.max(0, start + n);
579 }
580 else {
581 start = Math.min(start, n - 1);
582 }
583 if (stop < 0) {
584 stop = Math.max(0, stop + n);
585 }
586 else {
587 stop = Math.min(stop, n - 1);
588 }
589 var begin = start;
590 var span = stop - start + 1;
591 while (span > 0) {
592 var half = span >> 1;
593 var middle = begin + half;
594 if (fn(array[middle], value) > 0) {
595 span = half;
596 }
597 else {
598 begin = middle + 1;
599 span -= half + 1;
600 }
601 }
602 return begin;
603 }
604 ArrayExt.upperBound = upperBound;
605 /**
606 * Test whether two arrays are shallowly equal.
607 *
608 * @param a - The first array-like object to compare.
609 *
610 * @param b - The second array-like object to compare.
611 *
612 * @param fn - The comparison function to apply to the elements. It
613 * should return `true` if the elements are "equal". The default
614 * compares elements using strict `===` equality.
615 *
616 * @returns Whether the two arrays are shallowly equal.
617 *
618 * #### Complexity
619 * Linear.
620 *
621 * #### Undefined Behavior
622 * Modifying the length of the arrays while comparing.
623 *
624 * #### Example
625 * ```typescript
626 * import { ArrayExt } from '@phosphor/algorithm';
627 *
628 * let d1 = [0, 3, 4, 7, 7, 9];
629 * let d2 = [0, 3, 4, 7, 7, 9];
630 * let d3 = [42];
631 * ArrayExt.shallowEqual(d1, d2); // true
632 * ArrayExt.shallowEqual(d2, d3); // false
633 * ```
634 */
635 function shallowEqual(a, b, fn) {
636 // Check for object identity first.
637 if (a === b) {
638 return true;
639 }
640 // Bail early if the lengths are different.
641 if (a.length !== b.length) {
642 return false;
643 }
644 // Compare each element for equality.
645 for (var i = 0, n = a.length; i < n; ++i) {
646 if (fn ? !fn(a[i], b[i]) : a[i] !== b[i]) {
647 return false;
648 }
649 }
650 // The array are shallowly equal.
651 return true;
652 }
653 ArrayExt.shallowEqual = shallowEqual;
654 /**
655 * Create a slice of an array subject to an optional step.
656 *
657 * @param array - The array-like object of interest.
658 *
659 * @param options - The options for configuring the slice.
660 *
661 * @returns A new array with the specified values.
662 *
663 * @throws An exception if the slice `step` is `0`.
664 *
665 * #### Complexity
666 * Linear.
667 *
668 * #### Undefined Behavior
669 * A `start`, `stop`, or `step` which is non-integral.
670 *
671 * #### Example
672 * ```typescript
673 * import { ArrayExt } from '@phosphor/algorithm';
674 *
675 * let data = [0, 3, 4, 7, 7, 9];
676 * ArrayExt.slice(data); // [0, 3, 4, 7, 7, 9]
677 * ArrayExt.slice(data, { start: 2 }); // [4, 7, 7, 9]
678 * ArrayExt.slice(data, { start: 0, stop: 4 }); // [0, 3, 4, 7]
679 * ArrayExt.slice(data, { step: 2 }); // [0, 4, 7]
680 * ArrayExt.slice(data, { step: -1 }); // [9, 7, 7, 4, 3, 0]
681 * ```
682 */
683 function slice(array, options) {
684 if (options === void 0) { options = {}; }
685 // Extract the options.
686 var start = options.start, stop = options.stop, step = options.step;
687 // Set up the `step` value.
688 if (step === undefined) {
689 step = 1;
690 }
691 // Validate the step size.
692 if (step === 0) {
693 throw new Error('Slice `step` cannot be zero.');
694 }
695 // Look up the length of the array.
696 var n = array.length;
697 // Set up the `start` value.
698 if (start === undefined) {
699 start = step < 0 ? n - 1 : 0;
700 }
701 else if (start < 0) {
702 start = Math.max(start + n, step < 0 ? -1 : 0);
703 }
704 else if (start >= n) {
705 start = step < 0 ? n - 1 : n;
706 }
707 // Set up the `stop` value.
708 if (stop === undefined) {
709 stop = step < 0 ? -1 : n;
710 }
711 else if (stop < 0) {
712 stop = Math.max(stop + n, step < 0 ? -1 : 0);
713 }
714 else if (stop >= n) {
715 stop = step < 0 ? n - 1 : n;
716 }
717 // Compute the slice length.
718 var length;
719 if ((step < 0 && stop >= start) || (step > 0 && start >= stop)) {
720 length = 0;
721 }
722 else if (step < 0) {
723 length = Math.floor((stop - start + 1) / step + 1);
724 }
725 else {
726 length = Math.floor((stop - start - 1) / step + 1);
727 }
728 // Compute the sliced result.
729 var result = [];
730 for (var i = 0; i < length; ++i) {
731 result[i] = array[start + i * step];
732 }
733 // Return the result.
734 return result;
735 }
736 ArrayExt.slice = slice;
737 /**
738 * Move an element in an array from one index to another.
739 *
740 * @param array - The mutable array-like object of interest.
741 *
742 * @param fromIndex - The index of the element to move. Negative
743 * values are taken as an offset from the end of the array.
744 *
745 * @param toIndex - The target index of the element. Negative
746 * values are taken as an offset from the end of the array.
747 *
748 * #### Complexity
749 * Linear.
750 *
751 * #### Undefined Behavior
752 * A `fromIndex` or `toIndex` which is non-integral.
753 *
754 * #### Example
755 * ```typescript
756 * import { ArrayExt } from from '@phosphor/algorithm';
757 *
758 * let data = [0, 1, 2, 3, 4];
759 * ArrayExt.move(data, 1, 2); // [0, 2, 1, 3, 4]
760 * ArrayExt.move(data, 4, 2); // [0, 2, 4, 1, 3]
761 * ```
762 */
763 function move(array, fromIndex, toIndex) {
764 var n = array.length;
765 if (n <= 1) {
766 return;
767 }
768 if (fromIndex < 0) {
769 fromIndex = Math.max(0, fromIndex + n);
770 }
771 else {
772 fromIndex = Math.min(fromIndex, n - 1);
773 }
774 if (toIndex < 0) {
775 toIndex = Math.max(0, toIndex + n);
776 }
777 else {
778 toIndex = Math.min(toIndex, n - 1);
779 }
780 if (fromIndex === toIndex) {
781 return;
782 }
783 var value = array[fromIndex];
784 var d = fromIndex < toIndex ? 1 : -1;
785 for (var i = fromIndex; i !== toIndex; i += d) {
786 array[i] = array[i + d];
787 }
788 array[toIndex] = value;
789 }
790 ArrayExt.move = move;
791 /**
792 * Reverse an array in-place.
793 *
794 * @param array - The mutable array-like object of interest.
795 *
796 * @param start - The index of the first element in the range to be
797 * reversed, inclusive. The default value is `0`. Negative values
798 * are taken as an offset from the end of the array.
799 *
800 * @param stop - The index of the last element in the range to be
801 * reversed, inclusive. The default value is `-1`. Negative values
802 * are taken as an offset from the end of the array.
803 *
804 * #### Complexity
805 * Linear.
806 *
807 * #### Undefined Behavior
808 * A `start` or `stop` index which is non-integral.
809 *
810 * #### Example
811 * ```typescript
812 * import { ArrayExt } from '@phosphor/algorithm';
813 *
814 * let data = [0, 1, 2, 3, 4];
815 * ArrayExt.reverse(data, 1, 3); // [0, 3, 2, 1, 4]
816 * ArrayExt.reverse(data, 3); // [0, 3, 2, 4, 1]
817 * ArrayExt.reverse(data); // [1, 4, 2, 3, 0]
818 * ```
819 */
820 function reverse(array, start, stop) {
821 if (start === void 0) { start = 0; }
822 if (stop === void 0) { stop = -1; }
823 var n = array.length;
824 if (n <= 1) {
825 return;
826 }
827 if (start < 0) {
828 start = Math.max(0, start + n);
829 }
830 else {
831 start = Math.min(start, n - 1);
832 }
833 if (stop < 0) {
834 stop = Math.max(0, stop + n);
835 }
836 else {
837 stop = Math.min(stop, n - 1);
838 }
839 while (start < stop) {
840 var a = array[start];
841 var b = array[stop];
842 array[start++] = b;
843 array[stop--] = a;
844 }
845 }
846 ArrayExt.reverse = reverse;
847 /**
848 * Rotate the elements of an array in-place.
849 *
850 * @param array - The mutable array-like object of interest.
851 *
852 * @param delta - The amount of rotation to apply to the elements. A
853 * positive value will rotate the elements to the left. A negative
854 * value will rotate the elements to the right.
855 *
856 * @param start - The index of the first element in the range to be
857 * rotated, inclusive. The default value is `0`. Negative values
858 * are taken as an offset from the end of the array.
859 *
860 * @param stop - The index of the last element in the range to be
861 * rotated, inclusive. The default value is `-1`. Negative values
862 * are taken as an offset from the end of the array.
863 *
864 * #### Complexity
865 * Linear.
866 *
867 * #### Undefined Behavior
868 * A `delta`, `start`, or `stop` which is non-integral.
869 *
870 * #### Example
871 * ```typescript
872 * import { ArrayExt } from '@phosphor/algorithm';
873 *
874 * let data = [0, 1, 2, 3, 4];
875 * ArrayExt.rotate(data, 2); // [2, 3, 4, 0, 1]
876 * ArrayExt.rotate(data, -2); // [0, 1, 2, 3, 4]
877 * ArrayExt.rotate(data, 10); // [0, 1, 2, 3, 4]
878 * ArrayExt.rotate(data, 9); // [4, 0, 1, 2, 3]
879 * ArrayExt.rotate(data, 2, 1, 3); // [4, 2, 0, 1, 3]
880 * ```
881 */
882 function rotate(array, delta, start, stop) {
883 if (start === void 0) { start = 0; }
884 if (stop === void 0) { stop = -1; }
885 var n = array.length;
886 if (n <= 1) {
887 return;
888 }
889 if (start < 0) {
890 start = Math.max(0, start + n);
891 }
892 else {
893 start = Math.min(start, n - 1);
894 }
895 if (stop < 0) {
896 stop = Math.max(0, stop + n);
897 }
898 else {
899 stop = Math.min(stop, n - 1);
900 }
901 if (start >= stop) {
902 return;
903 }
904 var length = stop - start + 1;
905 if (delta > 0) {
906 delta = delta % length;
907 }
908 else if (delta < 0) {
909 delta = ((delta % length) + length) % length;
910 }
911 if (delta === 0) {
912 return;
913 }
914 var pivot = start + delta;
915 reverse(array, start, pivot - 1);
916 reverse(array, pivot, stop);
917 reverse(array, start, stop);
918 }
919 ArrayExt.rotate = rotate;
920 /**
921 * Fill an array with a static value.
922 *
923 * @param array - The mutable array-like object to fill.
924 *
925 * @param value - The static value to use to fill the array.
926 *
927 * @param start - The index of the first element in the range to be
928 * filled, inclusive. The default value is `0`. Negative values
929 * are taken as an offset from the end of the array.
930 *
931 * @param stop - The index of the last element in the range to be
932 * filled, inclusive. The default value is `-1`. Negative values
933 * are taken as an offset from the end of the array.
934 *
935 * #### Notes
936 * If `stop < start` the fill will wrap at the end of the array.
937 *
938 * #### Complexity
939 * Linear.
940 *
941 * #### Undefined Behavior
942 * A `start` or `stop` which is non-integral.
943 *
944 * #### Example
945 * ```typescript
946 * import { ArrayExt } from '@phosphor/algorithm';
947 *
948 * let data = ['one', 'two', 'three', 'four'];
949 * ArrayExt.fill(data, 'r'); // ['r', 'r', 'r', 'r']
950 * ArrayExt.fill(data, 'g', 1); // ['r', 'g', 'g', 'g']
951 * ArrayExt.fill(data, 'b', 2, 3); // ['r', 'g', 'b', 'b']
952 * ArrayExt.fill(data, 'z', 3, 1); // ['z', 'z', 'b', 'z']
953 * ```
954 */
955 function fill(array, value, start, stop) {
956 if (start === void 0) { start = 0; }
957 if (stop === void 0) { stop = -1; }
958 var n = array.length;
959 if (n === 0) {
960 return;
961 }
962 if (start < 0) {
963 start = Math.max(0, start + n);
964 }
965 else {
966 start = Math.min(start, n - 1);
967 }
968 if (stop < 0) {
969 stop = Math.max(0, stop + n);
970 }
971 else {
972 stop = Math.min(stop, n - 1);
973 }
974 var span;
975 if (stop < start) {
976 span = (stop + 1) + (n - start);
977 }
978 else {
979 span = stop - start + 1;
980 }
981 for (var i = 0; i < span; ++i) {
982 array[(start + i) % n] = value;
983 }
984 }
985 ArrayExt.fill = fill;
986 /**
987 * Insert a value into an array at a specific index.
988 *
989 * @param array - The array of interest.
990 *
991 * @param index - The index at which to insert the value. Negative
992 * values are taken as an offset from the end of the array.
993 *
994 * @param value - The value to set at the specified index.
995 *
996 * #### Complexity
997 * Linear.
998 *
999 * #### Undefined Behavior
1000 * An `index` which is non-integral.
1001 *
1002 * #### Example
1003 * ```typescript
1004 * import { ArrayExt } from '@phosphor/algorithm';
1005 *
1006 * let data = [0, 1, 2];
1007 * ArrayExt.insert(data, 0, -1); // [-1, 0, 1, 2]
1008 * ArrayExt.insert(data, 2, 12); // [-1, 0, 12, 1, 2]
1009 * ArrayExt.insert(data, -1, 7); // [-1, 0, 12, 1, 7, 2]
1010 * ArrayExt.insert(data, 6, 19); // [-1, 0, 12, 1, 7, 2, 19]
1011 * ```
1012 */
1013 function insert(array, index, value) {
1014 var n = array.length;
1015 if (index < 0) {
1016 index = Math.max(0, index + n);
1017 }
1018 else {
1019 index = Math.min(index, n);
1020 }
1021 for (var i = n; i > index; --i) {
1022 array[i] = array[i - 1];
1023 }
1024 array[index] = value;
1025 }
1026 ArrayExt.insert = insert;
1027 /**
1028 * Remove and return a value at a specific index in an array.
1029 *
1030 * @param array - The array of interest.
1031 *
1032 * @param index - The index of the value to remove. Negative values
1033 * are taken as an offset from the end of the array.
1034 *
1035 * @returns The value at the specified index, or `undefined` if the
1036 * index is out of range.
1037 *
1038 * #### Complexity
1039 * Linear.
1040 *
1041 * #### Undefined Behavior
1042 * An `index` which is non-integral.
1043 *
1044 * #### Example
1045 * ```typescript
1046 * import { ArrayExt } from '@phosphor/algorithm';
1047 *
1048 * let data = [0, 12, 23, 39, 14, 12, 75];
1049 * ArrayExt.removeAt(data, 2); // 23
1050 * ArrayExt.removeAt(data, -2); // 12
1051 * ArrayExt.removeAt(data, 10); // undefined;
1052 * ```
1053 */
1054 function removeAt(array, index) {
1055 var n = array.length;
1056 if (index < 0) {
1057 index += n;
1058 }
1059 if (index < 0 || index >= n) {
1060 return undefined;
1061 }
1062 var value = array[index];
1063 for (var i = index + 1; i < n; ++i) {
1064 array[i - 1] = array[i];
1065 }
1066 array.length = n - 1;
1067 return value;
1068 }
1069 ArrayExt.removeAt = removeAt;
1070 /**
1071 * Remove the first occurrence of a value from an array.
1072 *
1073 * @param array - The array of interest.
1074 *
1075 * @param value - The value to remove from the array. Values are
1076 * compared using strict `===` equality.
1077 *
1078 * @param start - The index of the first element in the range to be
1079 * searched, inclusive. The default value is `0`. Negative values
1080 * are taken as an offset from the end of the array.
1081 *
1082 * @param stop - The index of the last element in the range to be
1083 * searched, inclusive. The default value is `-1`. Negative values
1084 * are taken as an offset from the end of the array.
1085 *
1086 * @returns The index of the removed value, or `-1` if the value
1087 * is not contained in the array.
1088 *
1089 * #### Notes
1090 * If `stop < start` the search will wrap at the end of the array.
1091 *
1092 * #### Complexity
1093 * Linear.
1094 *
1095 * #### Example
1096 * ```typescript
1097 * import { ArrayExt } from '@phosphor/algorithm';
1098 *
1099 * let data = [0, 12, 23, 39, 14, 12, 75];
1100 * ArrayExt.removeFirstOf(data, 12); // 1
1101 * ArrayExt.removeFirstOf(data, 17); // -1
1102 * ArrayExt.removeFirstOf(data, 39, 3); // -1
1103 * ArrayExt.removeFirstOf(data, 39, 3, 2); // 2
1104 * ```
1105 */
1106 function removeFirstOf(array, value, start, stop) {
1107 if (start === void 0) { start = 0; }
1108 if (stop === void 0) { stop = -1; }
1109 var index = firstIndexOf(array, value, start, stop);
1110 if (index !== -1) {
1111 removeAt(array, index);
1112 }
1113 return index;
1114 }
1115 ArrayExt.removeFirstOf = removeFirstOf;
1116 /**
1117 * Remove the last occurrence of a value from an array.
1118 *
1119 * @param array - The array of interest.
1120 *
1121 * @param value - The value to remove from the array. Values are
1122 * compared using strict `===` equality.
1123 *
1124 * @param start - The index of the first element in the range to be
1125 * searched, inclusive. The default value is `-1`. Negative values
1126 * are taken as an offset from the end of the array.
1127 *
1128 * @param stop - The index of the last element in the range to be
1129 * searched, inclusive. The default value is `0`. Negative values
1130 * are taken as an offset from the end of the array.
1131 *
1132 * @returns The index of the removed value, or `-1` if the value
1133 * is not contained in the array.
1134 *
1135 * #### Notes
1136 * If `start < stop` the search will wrap at the end of the array.
1137 *
1138 * #### Complexity
1139 * Linear.
1140 *
1141 * #### Example
1142 * ```typescript
1143 * import { ArrayExt } from '@phosphor/algorithm';
1144 *
1145 * let data = [0, 12, 23, 39, 14, 12, 75];
1146 * ArrayExt.removeLastOf(data, 12); // 5
1147 * ArrayExt.removeLastOf(data, 17); // -1
1148 * ArrayExt.removeLastOf(data, 39, 2); // -1
1149 * ArrayExt.removeLastOf(data, 39, 2, 3); // 3
1150 * ```
1151 */
1152 function removeLastOf(array, value, start, stop) {
1153 if (start === void 0) { start = -1; }
1154 if (stop === void 0) { stop = 0; }
1155 var index = lastIndexOf(array, value, start, stop);
1156 if (index !== -1) {
1157 removeAt(array, index);
1158 }
1159 return index;
1160 }
1161 ArrayExt.removeLastOf = removeLastOf;
1162 /**
1163 * Remove all occurrences of a value from an array.
1164 *
1165 * @param array - The array of interest.
1166 *
1167 * @param value - The value to remove from the array. Values are
1168 * compared using strict `===` equality.
1169 *
1170 * @param start - The index of the first element in the range to be
1171 * searched, inclusive. The default value is `0`. Negative values
1172 * are taken as an offset from the end of the array.
1173 *
1174 * @param stop - The index of the last element in the range to be
1175 * searched, inclusive. The default value is `-1`. Negative values
1176 * are taken as an offset from the end of the array.
1177 *
1178 * @returns The number of elements removed from the array.
1179 *
1180 * #### Notes
1181 * If `stop < start` the search will conceptually wrap at the end of
1182 * the array, however the array will be traversed front-to-back.
1183 *
1184 * #### Complexity
1185 * Linear.
1186 *
1187 * #### Example
1188 * ```typescript
1189 * import { ArrayExt } from '@phosphor/algorithm';
1190 *
1191 * let data = [14, 12, 23, 39, 14, 12, 19, 14];
1192 * ArrayExt.removeAllOf(data, 12); // 2
1193 * ArrayExt.removeAllOf(data, 17); // 0
1194 * ArrayExt.removeAllOf(data, 14, 1, 4); // 1
1195 * ```
1196 */
1197 function removeAllOf(array, value, start, stop) {
1198 if (start === void 0) { start = 0; }
1199 if (stop === void 0) { stop = -1; }
1200 var n = array.length;
1201 if (n === 0) {
1202 return 0;
1203 }
1204 if (start < 0) {
1205 start = Math.max(0, start + n);
1206 }
1207 else {
1208 start = Math.min(start, n - 1);
1209 }
1210 if (stop < 0) {
1211 stop = Math.max(0, stop + n);
1212 }
1213 else {
1214 stop = Math.min(stop, n - 1);
1215 }
1216 var count = 0;
1217 for (var i = 0; i < n; ++i) {
1218 if (start <= stop && (i >= start && i <= stop) && array[i] === value) {
1219 count++;
1220 }
1221 else if (stop < start && (i <= stop || i >= start) && array[i] === value) {
1222 count++;
1223 }
1224 else if (count > 0) {
1225 array[i - count] = array[i];
1226 }
1227 }
1228 if (count > 0) {
1229 array.length = n - count;
1230 }
1231 return count;
1232 }
1233 ArrayExt.removeAllOf = removeAllOf;
1234 /**
1235 * Remove the first occurrence of a value which matches a predicate.
1236 *
1237 * @param array - The array of interest.
1238 *
1239 * @param fn - The predicate function to apply to the values.
1240 *
1241 * @param start - The index of the first element in the range to be
1242 * searched, inclusive. The default value is `0`. Negative values
1243 * are taken as an offset from the end of the array.
1244 *
1245 * @param stop - The index of the last element in the range to be
1246 * searched, inclusive. The default value is `-1`. Negative values
1247 * are taken as an offset from the end of the array.
1248 *
1249 * @returns The removed `{ index, value }`, which will be `-1` and
1250 * `undefined` if the value is not contained in the array.
1251 *
1252 * #### Notes
1253 * If `stop < start` the search will wrap at the end of the array.
1254 *
1255 * #### Complexity
1256 * Linear.
1257 *
1258 * #### Example
1259 * ```typescript
1260 * import { ArrayExt } from '@phosphor/algorithm';
1261 *
1262 * function isEven(value: number): boolean {
1263 * return value % 2 === 0;
1264 * }
1265 *
1266 * let data = [0, 12, 23, 39, 14, 12, 75];
1267 * ArrayExt.removeFirstWhere(data, isEven); // { index: 0, value: 0 }
1268 * ArrayExt.removeFirstWhere(data, isEven, 2); // { index: 3, value: 14 }
1269 * ArrayExt.removeFirstWhere(data, isEven, 4); // { index: -1, value: undefined }
1270 * ```
1271 */
1272 function removeFirstWhere(array, fn, start, stop) {
1273 if (start === void 0) { start = 0; }
1274 if (stop === void 0) { stop = -1; }
1275 var value;
1276 var index = findFirstIndex(array, fn, start, stop);
1277 if (index !== -1) {
1278 value = removeAt(array, index);
1279 }
1280 return { index: index, value: value };
1281 }
1282 ArrayExt.removeFirstWhere = removeFirstWhere;
1283 /**
1284 * Remove the last occurrence of a value which matches a predicate.
1285 *
1286 * @param array - The array of interest.
1287 *
1288 * @param fn - The predicate function to apply to the values.
1289 *
1290 * @param start - The index of the first element in the range to be
1291 * searched, inclusive. The default value is `-1`. Negative values
1292 * are taken as an offset from the end of the array.
1293 *
1294 * @param stop - The index of the last element in the range to be
1295 * searched, inclusive. The default value is `0`. Negative values
1296 * are taken as an offset from the end of the array.
1297 *
1298 * @returns The removed `{ index, value }`, which will be `-1` and
1299 * `undefined` if the value is not contained in the array.
1300 *
1301 * #### Notes
1302 * If `start < stop` the search will wrap at the end of the array.
1303 *
1304 * #### Complexity
1305 * Linear.
1306 *
1307 * #### Example
1308 * ```typescript
1309 * import { ArrayExt } from '@phosphor/algorithm';
1310 *
1311 * function isEven(value: number): boolean {
1312 * return value % 2 === 0;
1313 * }
1314 *
1315 * let data = [0, 12, 23, 39, 14, 12, 75];
1316 * ArrayExt.removeLastWhere(data, isEven); // { index: 5, value: 12 }
1317 * ArrayExt.removeLastWhere(data, isEven, 2); // { index: 1, value: 12 }
1318 * ArrayExt.removeLastWhere(data, isEven, 2, 1); // { index: -1, value: undefined }
1319 * ```
1320 */
1321 function removeLastWhere(array, fn, start, stop) {
1322 if (start === void 0) { start = -1; }
1323 if (stop === void 0) { stop = 0; }
1324 var value;
1325 var index = findLastIndex(array, fn, start, stop);
1326 if (index !== -1) {
1327 value = removeAt(array, index);
1328 }
1329 return { index: index, value: value };
1330 }
1331 ArrayExt.removeLastWhere = removeLastWhere;
1332 /**
1333 * Remove all occurrences of values which match a predicate.
1334 *
1335 * @param array - The array of interest.
1336 *
1337 * @param fn - The predicate function to apply to the values.
1338 *
1339 * @param start - The index of the first element in the range to be
1340 * searched, inclusive. The default value is `0`. Negative values
1341 * are taken as an offset from the end of the array.
1342 *
1343 * @param stop - The index of the last element in the range to be
1344 * searched, inclusive. The default value is `-1`. Negative values
1345 * are taken as an offset from the end of the array.
1346 *
1347 * @returns The number of elements removed from the array.
1348 *
1349 * #### Notes
1350 * If `stop < start` the search will conceptually wrap at the end of
1351 * the array, however the array will be traversed front-to-back.
1352 *
1353 * #### Complexity
1354 * Linear.
1355 *
1356 * #### Example
1357 * ```typescript
1358 * import { ArrayExt } from '@phosphor/algorithm';
1359 *
1360 * function isEven(value: number): boolean {
1361 * return value % 2 === 0;
1362 * }
1363 *
1364 * function isNegative(value: number): boolean {
1365 * return value < 0;
1366 * }
1367 *
1368 * let data = [0, 12, -13, -9, 23, 39, 14, -15, 12, 75];
1369 * ArrayExt.removeAllWhere(data, isEven); // 4
1370 * ArrayExt.removeAllWhere(data, isNegative, 0, 3); // 2
1371 * ```
1372 */
1373 function removeAllWhere(array, fn, start, stop) {
1374 if (start === void 0) { start = 0; }
1375 if (stop === void 0) { stop = -1; }
1376 var n = array.length;
1377 if (n === 0) {
1378 return 0;
1379 }
1380 if (start < 0) {
1381 start = Math.max(0, start + n);
1382 }
1383 else {
1384 start = Math.min(start, n - 1);
1385 }
1386 if (stop < 0) {
1387 stop = Math.max(0, stop + n);
1388 }
1389 else {
1390 stop = Math.min(stop, n - 1);
1391 }
1392 var count = 0;
1393 for (var i = 0; i < n; ++i) {
1394 if (start <= stop && (i >= start && i <= stop) && fn(array[i], i)) {
1395 count++;
1396 }
1397 else if (stop < start && (i <= stop || i >= start) && fn(array[i], i)) {
1398 count++;
1399 }
1400 else if (count > 0) {
1401 array[i - count] = array[i];
1402 }
1403 }
1404 if (count > 0) {
1405 array.length = n - count;
1406 }
1407 return count;
1408 }
1409 ArrayExt.removeAllWhere = removeAllWhere;
1410})(ArrayExt = exports.ArrayExt || (exports.ArrayExt = {}));