/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // We use varying sorts across the self-hosted codebase. All sorts are // consolidated here to avoid confusion and re-implementation of existing // algorithms. // For sorting small typed arrays. function InsertionSort(array, from, to, comparefn) { var item, swap, i, j; for (i = from + 1; i <= to; i++) { item = array[i]; for (j = i - 1; j >= from; j--) { swap = array[j]; if (callContentFunction(comparefn, undefined, swap, item) <= 0) { break; } array[j + 1] = swap; } array[j + 1] = item; } } // A helper function for MergeSortTypedArray. // // Merge comparefn-sorted slices list[start..<=mid] and list[mid+1..<=end], // storing the merged sequence in out[start..<=end]. function MergeTypedArray(list, out, start, mid, end, comparefn) { // Skip lopsided runs to avoid doing useless work. // Skip calling the comparator if the sub-list is already sorted. if ( mid >= end || callContentFunction(comparefn, undefined, list[mid], list[mid + 1]) <= 0 ) { for (var i = start; i <= end; i++) { out[i] = list[i]; } return; } var i = start; var j = mid + 1; var k = start; while (i <= mid && j <= end) { var lvalue = list[i]; var rvalue = list[j]; if (callContentFunction(comparefn, undefined, lvalue, rvalue) <= 0) { out[k++] = lvalue; i++; } else { out[k++] = rvalue; j++; } } // Empty out any remaining elements. while (i <= mid) { out[k++] = list[i++]; } while (j <= end) { out[k++] = list[j++]; } } // Iterative, bottom up, mergesort. Optimized version for TypedArrays. function MergeSortTypedArray(array, len, comparefn) { assert( IsPossiblyWrappedTypedArray(array), "MergeSortTypedArray works only with typed arrays." ); // Use the same TypedArray kind for the buffer. var C = ConstructorForTypedArray(array); var lBuffer = new C(len); // Copy all elements into a temporary buffer, so that any modifications // when calling |comparefn| are ignored. for (var i = 0; i < len; i++) { lBuffer[i] = array[i]; } // Insertion sort for small arrays, where "small" is defined by performance // testing. if (len < 8) { InsertionSort(lBuffer, 0, len - 1, comparefn); return lBuffer; } // We do all of our allocating up front. var rBuffer = new C(len); // Use insertion sort for the initial ranges. var windowSize = 4; for (var start = 0; start < len - 1; start += windowSize) { var end = std_Math_min(start + windowSize - 1, len - 1); InsertionSort(lBuffer, start, end, comparefn); } for (; windowSize < len; windowSize = 2 * windowSize) { for (var start = 0; start < len; start += 2 * windowSize) { // The midpoint between the two subarrays. var mid = start + windowSize - 1; // To keep from going over the edge. var end = std_Math_min(start + 2 * windowSize - 1, len - 1); MergeTypedArray(lBuffer, rBuffer, start, mid, end, comparefn); } // Swap both lists. var swap = lBuffer; lBuffer = rBuffer; rBuffer = swap; } return lBuffer; }