Bug 1784090 - Part 5: Avoid copying the array for ArrayToSorted. r=mgaudet

Change `MergeSort` to directly modify its input instead of creating a copy.
`ArraySort` now needs to copy the input and re-arrange any holes, whereas
`ArrayToSorted` can directly return the result from `MergeSort`.

Depends on D154264

Differential Revision: https://phabricator.services.mozilla.com/D154265
This commit is contained in:
André Bargull 2022-08-12 12:49:54 +00:00
Родитель 324aa95386
Коммит b4cd6b075b
2 изменённых файлов: 41 добавлений и 27 удалений

Просмотреть файл

@ -130,7 +130,29 @@ function ArraySort(comparefn) {
var wrappedCompareFn = ArraySortCompare(comparefn);
// Step 5.
return MergeSort(O, len, wrappedCompareFn);
// To save effort we will do all of our work on a dense list, then create
// holes at the end.
var denseList = [];
var denseLen = 0;
for (var i = 0; i < len; i++) {
if (i in O) {
DefineDataProperty(denseList, denseLen++, O[i]);
}
}
if (denseLen < 1) {
return O;
}
var sorted = MergeSort(denseList, denseLen, wrappedCompareFn);
assert(IsPackedArray(sorted), "sorted is a packed array");
assert(sorted.length === denseLen, "sorted array has the correct length");
MoveHoles(O, len, sorted, denseLen);
return O;
}
/* ES5 15.4.4.18. */
@ -1401,7 +1423,12 @@ function ArrayToSorted(comparefn) {
var wrappedCompareFn = ArraySortCompare(comparefn);
// Steps 6-9.
return MergeSort(items, len, wrappedCompareFn);
var sorted = MergeSort(items, len, wrappedCompareFn);
assert(IsPackedArray(sorted), "sorted is a packed array");
assert(sorted.length === len, "sorted array has the correct length");
return sorted;
}
#endif

Просмотреть файл

@ -76,47 +76,35 @@ function MoveHoles(sparse, sparseLen, dense, denseLen) {
// Iterative, bottom up, mergesort.
function MergeSort(array, len, comparefn) {
// To save effort we will do all of our work on a dense list,
// then create holes at the end.
var denseList = [];
var denseLen = 0;
for (var i = 0; i < len; i++) {
if (i in array) {
DefineDataProperty(denseList, denseLen++, array[i]);
}
}
if (denseLen < 1) {
return array;
}
assert(IsPackedArray(array), "array is packed");
assert(array.length === len, "length mismatch");
assert(len > 0, "array should be non-empty");
// Insertion sort for small arrays, where "small" is defined by performance
// testing.
if (denseLen < 24) {
InsertionSort(denseList, 0, denseLen - 1, comparefn);
MoveHoles(array, len, denseList, denseLen);
if (len < 24) {
InsertionSort(array, 0, len - 1, comparefn);
return array;
}
// We do all of our allocating up front
var lBuffer = denseList;
var lBuffer = array;
var rBuffer = [];
// Use insertion sort for initial ranges.
var windowSize = 4;
for (var start = 0; start < denseLen - 1; start += windowSize) {
var end = std_Math_min(start + windowSize - 1, denseLen - 1);
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 < denseLen; windowSize = 2 * windowSize) {
for (var start = 0; start < denseLen; start += 2 * windowSize) {
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, denseLen - 1);
var end = std_Math_min(start + 2 * windowSize - 1, len - 1);
Merge(lBuffer, rBuffer, start, mid, end, comparefn);
}
@ -126,8 +114,7 @@ function MergeSort(array, len, comparefn) {
lBuffer = rBuffer;
rBuffer = swap;
}
MoveHoles(array, len, lBuffer, denseLen);
return array;
return lBuffer;
}
// A helper function for MergeSortTypedArray.