source: trip-planner-front/node_modules/timsort/src/timsort.js@ e29cc2e

Last change on this file since e29cc2e was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 22.4 KB
Line 
1/**
2 * Default minimum size of a run.
3 */
4const DEFAULT_MIN_MERGE = 32;
5
6/**
7 * Minimum ordered subsequece required to do galloping.
8 */
9const DEFAULT_MIN_GALLOPING = 7;
10
11/**
12 * Default tmp storage length. Can increase depending on the size of the
13 * smallest run to merge.
14 */
15const DEFAULT_TMP_STORAGE_LENGTH = 256;
16
17/**
18 * Pre-computed powers of 10 for efficient lexicographic comparison of
19 * small integers.
20 */
21const POWERS_OF_TEN = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9]
22
23/**
24 * Estimate the logarithm base 10 of a small integer.
25 *
26 * @param {number} x - The integer to estimate the logarithm of.
27 * @return {number} - The estimated logarithm of the integer.
28 */
29function log10(x) {
30 if (x < 1e5) {
31 if (x < 1e2) {
32 return x < 1e1 ? 0 : 1;
33 }
34
35 if (x < 1e4) {
36 return x < 1e3 ? 2 : 3;
37 }
38
39 return 4;
40 }
41
42 if (x < 1e7) {
43 return x < 1e6 ? 5 : 6;
44 }
45
46 if (x < 1e9) {
47 return x < 1e8 ? 7 : 8;
48 }
49
50 return 9;
51}
52
53/**
54 * Default alphabetical comparison of items.
55 *
56 * @param {string|object|number} a - First element to compare.
57 * @param {string|object|number} b - Second element to compare.
58 * @return {number} - A positive number if a.toString() > b.toString(), a
59 * negative number if .toString() < b.toString(), 0 otherwise.
60 */
61function alphabeticalCompare(a, b) {
62 if (a === b) {
63 return 0;
64 }
65
66 if (~~a === a && ~~b === b) {
67 if (a === 0 || b === 0) {
68 return a < b ? -1 : 1;
69 }
70
71 if (a < 0 || b < 0) {
72 if (b >= 0) {
73 return -1;
74 }
75
76 if (a >= 0) {
77 return 1;
78 }
79
80 a = -a;
81 b = -b;
82 }
83
84 const al = log10(a);
85 const bl = log10(b);
86
87 let t = 0;
88
89 if (al < bl) {
90 a *= POWERS_OF_TEN[bl - al - 1];
91 b /= 10;
92 t = -1;
93 } else if (al > bl) {
94 b *= POWERS_OF_TEN[al - bl - 1];
95 a /= 10;
96 t = 1;
97 }
98
99 if (a === b) {
100 return t;
101 }
102
103 return a < b ? -1 : 1;
104 }
105
106 let aStr = String(a);
107 let bStr = String(b);
108
109 if (aStr === bStr) {
110 return 0;
111 }
112
113 return aStr < bStr ? -1 : 1;
114}
115
116/**
117 * Compute minimum run length for TimSort
118 *
119 * @param {number} n - The size of the array to sort.
120 */
121function minRunLength(n) {
122 let r = 0;
123
124 while (n >= DEFAULT_MIN_MERGE) {
125 r |= (n & 1);
126 n >>= 1;
127 }
128
129 return n + r;
130}
131
132/**
133 * Counts the length of a monotonically ascending or strictly monotonically
134 * descending sequence (run) starting at array[lo] in the range [lo, hi). If
135 * the run is descending it is made ascending.
136 *
137 * @param {array} array - The array to reverse.
138 * @param {number} lo - First element in the range (inclusive).
139 * @param {number} hi - Last element in the range.
140 * @param {function} compare - Item comparison function.
141 * @return {number} - The length of the run.
142 */
143function makeAscendingRun(array, lo, hi, compare) {
144 let runHi = lo + 1;
145
146 if (runHi === hi) {
147 return 1;
148 }
149
150 // Descending
151 if (compare(array[runHi++], array[lo]) < 0) {
152 while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
153 runHi++;
154 }
155
156 reverseRun(array, lo, runHi);
157 // Ascending
158 } else {
159 while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
160 runHi++;
161 }
162 }
163
164 return runHi - lo;
165}
166
167/**
168 * Reverse an array in the range [lo, hi).
169 *
170 * @param {array} array - The array to reverse.
171 * @param {number} lo - First element in the range (inclusive).
172 * @param {number} hi - Last element in the range.
173 */
174function reverseRun(array, lo, hi) {
175 hi--;
176
177 while (lo < hi) {
178 let t = array[lo];
179 array[lo++] = array[hi];
180 array[hi--] = t;
181 }
182}
183
184/**
185 * Perform the binary sort of the array in the range [lo, hi) where start is
186 * the first element possibly out of order.
187 *
188 * @param {array} array - The array to sort.
189 * @param {number} lo - First element in the range (inclusive).
190 * @param {number} hi - Last element in the range.
191 * @param {number} start - First element possibly out of order.
192 * @param {function} compare - Item comparison function.
193 */
194function binaryInsertionSort(array, lo, hi, start, compare) {
195 if (start === lo) {
196 start++;
197 }
198
199 for (; start < hi; start++) {
200 let pivot = array[start];
201
202 // Ranges of the array where pivot belongs
203 let left = lo;
204 let right = start;
205
206 /*
207 * pivot >= array[i] for i in [lo, left)
208 * pivot < array[i] for i in in [right, start)
209 */
210 while (left < right) {
211 let mid = (left + right) >>> 1;
212
213 if (compare(pivot, array[mid]) < 0) {
214 right = mid;
215 } else {
216 left = mid + 1;
217 }
218 }
219
220 /*
221 * Move elements right to make room for the pivot. If there are elements
222 * equal to pivot, left points to the first slot after them: this is also
223 * a reason for which TimSort is stable
224 */
225 let n = start - left;
226 // Switch is just an optimization for small arrays
227 switch (n) {
228 case 3:
229 array[left + 3] = array[left + 2];
230 /* falls through */
231 case 2:
232 array[left + 2] = array[left + 1];
233 /* falls through */
234 case 1:
235 array[left + 1] = array[left];
236 break;
237 default:
238 while (n > 0) {
239 array[left + n] = array[left + n - 1];
240 n--;
241 }
242 }
243
244 array[left] = pivot;
245 }
246}
247
248/**
249 * Find the position at which to insert a value in a sorted range. If the range
250 * contains elements equal to the value the leftmost element index is returned
251 * (for stability).
252 *
253 * @param {number} value - Value to insert.
254 * @param {array} array - The array in which to insert value.
255 * @param {number} start - First element in the range.
256 * @param {number} length - Length of the range.
257 * @param {number} hint - The index at which to begin the search.
258 * @param {function} compare - Item comparison function.
259 * @return {number} - The index where to insert value.
260 */
261function gallopLeft(value, array, start, length, hint, compare) {
262 let lastOffset = 0;
263 let maxOffset = 0;
264 let offset = 1;
265
266 if (compare(value, array[start + hint]) > 0) {
267 maxOffset = length - hint;
268
269 while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
270 lastOffset = offset;
271 offset = (offset << 1) + 1;
272
273 if (offset <= 0) {
274 offset = maxOffset;
275 }
276 }
277
278 if (offset > maxOffset) {
279 offset = maxOffset;
280 }
281
282 // Make offsets relative to start
283 lastOffset += hint;
284 offset += hint;
285
286 // value <= array[start + hint]
287 } else {
288 maxOffset = hint + 1;
289 while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
290 lastOffset = offset;
291 offset = (offset << 1) + 1;
292
293 if (offset <= 0) {
294 offset = maxOffset;
295 }
296 }
297 if (offset > maxOffset) {
298 offset = maxOffset;
299 }
300
301 // Make offsets relative to start
302 let tmp = lastOffset;
303 lastOffset = hint - offset;
304 offset = hint - tmp;
305 }
306
307 /*
308 * Now array[start+lastOffset] < value <= array[start+offset], so value
309 * belongs somewhere in the range (start + lastOffset, start + offset]. Do a
310 * binary search, with invariant array[start + lastOffset - 1] < value <=
311 * array[start + offset].
312 */
313 lastOffset++;
314 while (lastOffset < offset) {
315 let m = lastOffset + ((offset - lastOffset) >>> 1);
316
317 if (compare(value, array[start + m]) > 0) {
318 lastOffset = m + 1;
319
320 } else {
321 offset = m;
322 }
323 }
324 return offset;
325}
326
327/**
328 * Find the position at which to insert a value in a sorted range. If the range
329 * contains elements equal to the value the rightmost element index is returned
330 * (for stability).
331 *
332 * @param {number} value - Value to insert.
333 * @param {array} array - The array in which to insert value.
334 * @param {number} start - First element in the range.
335 * @param {number} length - Length of the range.
336 * @param {number} hint - The index at which to begin the search.
337 * @param {function} compare - Item comparison function.
338 * @return {number} - The index where to insert value.
339 */
340function gallopRight(value, array, start, length, hint, compare) {
341 let lastOffset = 0;
342 let maxOffset = 0;
343 let offset = 1;
344
345 if (compare(value, array[start + hint]) < 0) {
346 maxOffset = hint + 1;
347
348 while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
349 lastOffset = offset;
350 offset = (offset << 1) + 1;
351
352 if (offset <= 0) {
353 offset = maxOffset;
354 }
355 }
356
357 if (offset > maxOffset) {
358 offset = maxOffset;
359 }
360
361 // Make offsets relative to start
362 let tmp = lastOffset;
363 lastOffset = hint - offset;
364 offset = hint - tmp;
365
366 // value >= array[start + hint]
367 } else {
368 maxOffset = length - hint;
369
370 while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
371 lastOffset = offset;
372 offset = (offset << 1) + 1;
373
374 if (offset <= 0) {
375 offset = maxOffset;
376 }
377 }
378
379 if (offset > maxOffset) {
380 offset = maxOffset;
381 }
382
383 // Make offsets relative to start
384 lastOffset += hint;
385 offset += hint;
386 }
387
388 /*
389 * Now array[start+lastOffset] < value <= array[start+offset], so value
390 * belongs somewhere in the range (start + lastOffset, start + offset]. Do a
391 * binary search, with invariant array[start + lastOffset - 1] < value <=
392 * array[start + offset].
393 */
394 lastOffset++;
395
396 while (lastOffset < offset) {
397 let m = lastOffset + ((offset - lastOffset) >>> 1);
398
399 if (compare(value, array[start + m]) < 0) {
400 offset = m;
401
402 } else {
403 lastOffset = m + 1;
404 }
405 }
406
407 return offset;
408}
409
410class TimSort {
411 array = null;
412 compare = null;
413 minGallop = DEFAULT_MIN_GALLOPING;
414 length = 0;
415 tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
416 stackLength = 0;
417 runStart = null;
418 runLength = null;
419 stackSize = 0;
420
421 constructor(array, compare) {
422 this.array = array;
423 this.compare = compare;
424
425 this.length = array.length;
426
427 if (this.length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
428 this.tmpStorageLength = this.length >>> 1;
429 }
430
431 this.tmp = new Array(this.tmpStorageLength);
432
433 this.stackLength =
434 (this.length < 120 ? 5 :
435 this.length < 1542 ? 10 :
436 this.length < 119151 ? 19 : 40);
437
438 this.runStart = new Array(this.stackLength);
439 this.runLength = new Array(this.stackLength);
440 }
441
442 /**
443 * Push a new run on TimSort's stack.
444 *
445 * @param {number} runStart - Start index of the run in the original array.
446 * @param {number} runLength - Length of the run;
447 */
448 pushRun(runStart, runLength) {
449 this.runStart[this.stackSize] = runStart;
450 this.runLength[this.stackSize] = runLength;
451 this.stackSize += 1;
452 }
453
454 /**
455 * Merge runs on TimSort's stack so that the following holds for all i:
456 * 1) runLength[i - 3] > runLength[i - 2] + runLength[i - 1]
457 * 2) runLength[i - 2] > runLength[i - 1]
458 */
459 mergeRuns() {
460 while (this.stackSize > 1) {
461 let n = this.stackSize - 2;
462
463 if ((n >= 1 &&
464 this.runLength[n - 1] <= this.runLength[n] + this.runLength[n + 1]) ||
465 (n >= 2 &&
466 this.runLength[n - 2] <= this.runLength[n] + this.runLength[n - 1])) {
467
468 if (this.runLength[n - 1] < this.runLength[n + 1]) {
469 n--;
470 }
471
472 } else if (this.runLength[n] > this.runLength[n + 1]) {
473 break;
474 }
475 this.mergeAt(n);
476 }
477 }
478
479 /**
480 * Merge all runs on TimSort's stack until only one remains.
481 */
482 forceMergeRuns() {
483 while (this.stackSize > 1) {
484 let n = this.stackSize - 2;
485
486 if (n > 0 && this.runLength[n - 1] < this.runLength[n + 1]) {
487 n--;
488 }
489
490 this.mergeAt(n);
491 }
492 }
493
494 /**
495 * Merge the runs on the stack at positions i and i+1. Must be always be called
496 * with i=stackSize-2 or i=stackSize-3 (that is, we merge on top of the stack).
497 *
498 * @param {number} i - Index of the run to merge in TimSort's stack.
499 */
500 mergeAt(i) {
501 let compare = this.compare;
502 let array = this.array;
503
504 let start1 = this.runStart[i];
505 let length1 = this.runLength[i];
506 let start2 = this.runStart[i + 1];
507 let length2 = this.runLength[i + 1];
508
509 this.runLength[i] = length1 + length2;
510
511 if (i === this.stackSize - 3) {
512 this.runStart[i + 1] = this.runStart[i + 2];
513 this.runLength[i + 1] = this.runLength[i + 2];
514 }
515
516 this.stackSize--;
517
518 /*
519 * Find where the first element in the second run goes in run1. Previous
520 * elements in run1 are already in place
521 */
522 let k = gallopRight(array[start2], array, start1, length1, 0, compare);
523 start1 += k;
524 length1 -= k;
525
526 if (length1 === 0) {
527 return;
528 }
529
530 /*
531 * Find where the last element in the first run goes in run2. Next elements
532 * in run2 are already in place
533 */
534 length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
535
536 if (length2 === 0) {
537 return;
538 }
539
540 /*
541 * Merge remaining runs. A tmp array with length = min(length1, length2) is
542 * used
543 */
544 if (length1 <= length2) {
545 this.mergeLow(start1, length1, start2, length2);
546
547 } else {
548 this.mergeHigh(start1, length1, start2, length2);
549 }
550 }
551
552 /**
553 * Merge two adjacent runs in a stable way. The runs must be such that the
554 * first element of run1 is bigger than the first element in run2 and the
555 * last element of run1 is greater than all the elements in run2.
556 * The method should be called when run1.length <= run2.length as it uses
557 * TimSort temporary array to store run1. Use mergeHigh if run1.length >
558 * run2.length.
559 *
560 * @param {number} start1 - First element in run1.
561 * @param {number} length1 - Length of run1.
562 * @param {number} start2 - First element in run2.
563 * @param {number} length2 - Length of run2.
564 */
565 mergeLow(start1, length1, start2, length2) {
566
567 let compare = this.compare;
568 let array = this.array;
569 let tmp = this.tmp;
570 let i = 0;
571
572 for (i = 0; i < length1; i++) {
573 tmp[i] = array[start1 + i];
574 }
575
576 let cursor1 = 0;
577 let cursor2 = start2;
578 let dest = start1;
579
580 array[dest++] = array[cursor2++];
581
582 if (--length2 === 0) {
583 for (i = 0; i < length1; i++) {
584 array[dest + i] = tmp[cursor1 + i];
585 }
586 return;
587 }
588
589 if (length1 === 1) {
590 for (i = 0; i < length2; i++) {
591 array[dest + i] = array[cursor2 + i];
592 }
593 array[dest + length2] = tmp[cursor1];
594 return;
595 }
596
597 let minGallop = this.minGallop;
598
599 while (true) {
600 let count1 = 0;
601 let count2 = 0;
602 let exit = false;
603
604 do {
605 if (compare(array[cursor2], tmp[cursor1]) < 0) {
606 array[dest++] = array[cursor2++];
607 count2++;
608 count1 = 0;
609
610 if (--length2 === 0) {
611 exit = true;
612 break;
613 }
614
615 } else {
616 array[dest++] = tmp[cursor1++];
617 count1++;
618 count2 = 0;
619 if (--length1 === 1) {
620 exit = true;
621 break;
622 }
623 }
624 } while ((count1 | count2) < minGallop);
625
626 if (exit) {
627 break;
628 }
629
630 do {
631 count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
632
633 if (count1 !== 0) {
634 for (i = 0; i < count1; i++) {
635 array[dest + i] = tmp[cursor1 + i];
636 }
637
638 dest += count1;
639 cursor1 += count1;
640 length1 -= count1;
641 if (length1 <= 1) {
642 exit = true;
643 break;
644 }
645 }
646
647 array[dest++] = array[cursor2++];
648
649 if (--length2 === 0) {
650 exit = true;
651 break;
652 }
653
654 count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
655
656 if (count2 !== 0) {
657 for (i = 0; i < count2; i++) {
658 array[dest + i] = array[cursor2 + i];
659 }
660
661 dest += count2;
662 cursor2 += count2;
663 length2 -= count2;
664
665 if (length2 === 0) {
666 exit = true;
667 break;
668 }
669 }
670 array[dest++] = tmp[cursor1++];
671
672 if (--length1 === 1) {
673 exit = true;
674 break;
675 }
676
677 minGallop--;
678
679 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
680
681 if (exit) {
682 break;
683 }
684
685 if (minGallop < 0) {
686 minGallop = 0;
687 }
688
689 minGallop += 2;
690 }
691
692 this.minGallop = minGallop;
693
694 if (minGallop < 1) {
695 this.minGallop = 1;
696 }
697
698 if (length1 === 1) {
699 for (i = 0; i < length2; i++) {
700 array[dest + i] = array[cursor2 + i];
701 }
702 array[dest + length2] = tmp[cursor1];
703
704 } else if (length1 === 0) {
705 throw new Error('mergeLow preconditions were not respected');
706
707 } else {
708 for (i = 0; i < length1; i++) {
709 array[dest + i] = tmp[cursor1 + i];
710 }
711 }
712 }
713
714 /**
715 * Merge two adjacent runs in a stable way. The runs must be such that the
716 * first element of run1 is bigger than the first element in run2 and the
717 * last element of run1 is greater than all the elements in run2.
718 * The method should be called when run1.length > run2.length as it uses
719 * TimSort temporary array to store run2. Use mergeLow if run1.length <=
720 * run2.length.
721 *
722 * @param {number} start1 - First element in run1.
723 * @param {number} length1 - Length of run1.
724 * @param {number} start2 - First element in run2.
725 * @param {number} length2 - Length of run2.
726 */
727 mergeHigh(start1, length1, start2, length2) {
728 let compare = this.compare;
729 let array = this.array;
730 let tmp = this.tmp;
731 let i = 0;
732
733 for (i = 0; i < length2; i++) {
734 tmp[i] = array[start2 + i];
735 }
736
737 let cursor1 = start1 + length1 - 1;
738 let cursor2 = length2 - 1;
739 let dest = start2 + length2 - 1;
740 let customCursor = 0;
741 let customDest = 0;
742
743 array[dest--] = array[cursor1--];
744
745 if (--length1 === 0) {
746 customCursor = dest - (length2 - 1);
747
748 for (i = 0; i < length2; i++) {
749 array[customCursor + i] = tmp[i];
750 }
751
752 return;
753 }
754
755 if (length2 === 1) {
756 dest -= length1;
757 cursor1 -= length1;
758 customDest = dest + 1;
759 customCursor = cursor1 + 1;
760
761 for (i = length1 - 1; i >= 0; i--) {
762 array[customDest + i] = array[customCursor + i];
763 }
764
765 array[dest] = tmp[cursor2];
766 return;
767 }
768
769 let minGallop = this.minGallop;
770
771 while (true) {
772 let count1 = 0;
773 let count2 = 0;
774 let exit = false;
775
776 do {
777 if (compare(tmp[cursor2], array[cursor1]) < 0) {
778 array[dest--] = array[cursor1--];
779 count1++;
780 count2 = 0;
781 if (--length1 === 0) {
782 exit = true;
783 break;
784 }
785
786 } else {
787 array[dest--] = tmp[cursor2--];
788 count2++;
789 count1 = 0;
790 if (--length2 === 1) {
791 exit = true;
792 break;
793 }
794 }
795
796 } while ((count1 | count2) < minGallop);
797
798 if (exit) {
799 break;
800 }
801
802 do {
803 count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
804
805 if (count1 !== 0) {
806 dest -= count1;
807 cursor1 -= count1;
808 length1 -= count1;
809 customDest = dest + 1;
810 customCursor = cursor1 + 1;
811
812 for (i = count1 - 1; i >= 0; i--) {
813 array[customDest + i] = array[customCursor + i];
814 }
815
816 if (length1 === 0) {
817 exit = true;
818 break;
819 }
820 }
821
822 array[dest--] = tmp[cursor2--];
823
824 if (--length2 === 1) {
825 exit = true;
826 break;
827 }
828
829 count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
830
831 if (count2 !== 0) {
832 dest -= count2;
833 cursor2 -= count2;
834 length2 -= count2;
835 customDest = dest + 1;
836 customCursor = cursor2 + 1;
837
838 for (i = 0; i < count2; i++) {
839 array[customDest + i] = tmp[customCursor + i];
840 }
841
842 if (length2 <= 1) {
843 exit = true;
844 break;
845 }
846 }
847
848 array[dest--] = array[cursor1--];
849
850 if (--length1 === 0) {
851 exit = true;
852 break;
853 }
854
855 minGallop--;
856
857 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
858
859 if (exit) {
860 break;
861 }
862
863 if (minGallop < 0) {
864 minGallop = 0;
865 }
866
867 minGallop += 2;
868 }
869
870 this.minGallop = minGallop;
871
872 if (minGallop < 1) {
873 this.minGallop = 1;
874 }
875
876 if (length2 === 1) {
877 dest -= length1;
878 cursor1 -= length1;
879 customDest = dest + 1;
880 customCursor = cursor1 + 1;
881
882 for (i = length1 - 1; i >= 0; i--) {
883 array[customDest + i] = array[customCursor + i];
884 }
885
886 array[dest] = tmp[cursor2];
887
888 } else if (length2 === 0) {
889 throw new Error('mergeHigh preconditions were not respected');
890
891 } else {
892 customCursor = dest - (length2 - 1);
893 for (i = 0; i < length2; i++) {
894 array[customCursor + i] = tmp[i];
895 }
896 }
897 }
898}
899
900/**
901 * Sort an array in the range [lo, hi) using TimSort.
902 *
903 * @param {array} array - The array to sort.
904 * @param {function=} compare - Item comparison function. Default is
905 * alphabetical
906 * @param {number} lo - First element in the range (inclusive).
907 * @param {number} hi - Last element in the range.
908 * comparator.
909 */
910export function sort(array, compare, lo, hi) {
911 if (!Array.isArray(array)) {
912 throw new TypeError('Can only sort arrays');
913 }
914
915 /*
916 * Handle the case where a comparison function is not provided. We do
917 * lexicographic sorting
918 */
919 if (!compare) {
920 compare = alphabeticalCompare;
921
922 } else if (typeof compare !== 'function') {
923 hi = lo;
924 lo = compare;
925 compare = alphabeticalCompare;
926 }
927
928 if (!lo) {
929 lo = 0;
930 }
931 if (!hi) {
932 hi = array.length;
933 }
934
935 let remaining = hi - lo;
936
937 // The array is already sorted
938 if (remaining < 2) {
939 return;
940 }
941
942 let runLength = 0;
943 // On small arrays binary sort can be used directly
944 if (remaining < DEFAULT_MIN_MERGE) {
945 runLength = makeAscendingRun(array, lo, hi, compare);
946 binaryInsertionSort(array, lo, hi, lo + runLength, compare);
947 return;
948 }
949
950 let ts = new TimSort(array, compare);
951
952 let minRun = minRunLength(remaining);
953
954 do {
955 runLength = makeAscendingRun(array, lo, hi, compare);
956 if (runLength < minRun) {
957 let force = remaining;
958 if (force > minRun) {
959 force = minRun;
960 }
961
962 binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
963 runLength = force;
964 }
965 // Push new run and merge if necessary
966 ts.pushRun(lo, runLength);
967 ts.mergeRuns();
968
969 // Go find next run
970 remaining -= runLength;
971 lo += runLength;
972
973 } while (remaining !== 0);
974
975 // Force merging of remaining runs
976 ts.forceMergeRuns();
977}
Note: See TracBrowser for help on using the repository browser.