radixsort = {
const countArrayBackingArray = new Uint32Array(256 * 5);
const countingArrays = [0, 1, 2, 3, 4].map(i =>
countArrayBackingArray.subarray(i * 256, (i + 1) * 256)
);
function _radixsort(
array,
indices,
left = 0,
right = array.length,
pass = 0
) {
const mask = 0xFFFFFFFF >>> (8 * pass);
let val = (array[indices[left]] & mask) >>> 0;
let maxVal = val | 0;
let i = left;
let sorted = true,
prev = val;
if (maxVal < 0x100) {
const countingArray = countingArrays[3];
countingArray.fill(0);
for (; i < right; i++) {
val = (array[indices[i]] & mask) >>> 0;
maxVal = (maxVal | val) >>> 0;
if (maxVal > 0xFF) break;
countingArray[val]++;
sorted = sorted && prev <= (prev = val);
}
}
if (maxVal < 0x10000 && i < right) {
const countingArray = countingArrays[2];
countingArray.fill(0);
countingArray[0] = i - left;
for (; i < right; i++) {
val = (array[indices[i]] & mask) >>> 0;
maxVal = (maxVal | (val & mask)) >>> 0;
if (maxVal > 0xFFFF) break;
countingArray[(val >>> 8) & 0xFF]++;
sorted = sorted && prev <= (prev = val);
}
}
if (maxVal < 0x1000000 && i < right) {
const countingArray = countingArrays[1];
countingArray.fill(0);
countingArray[0] = i - left;
for (; i < right; i++) {
val = (array[indices[i]] & mask) >>> 0;
maxVal = (maxVal | (val & mask)) >>> 0;
if (maxVal > 0xFFFFFF) break;
countingArray[(val >>> 16) & 0xFF]++;
sorted = sorted && prev <= (prev = val);
}
}
if (i < right) {
const countingArray = countingArrays[0];
countingArray.fill(0);
countingArray[0] = i - left;
while (i < right) {
val = array[indices[i++]];
countingArray[val >>> 24]++;
sorted = sorted && prev <= (prev = val);
}
}
if (sorted) return indices;
if (maxVal < 0x100) {
pass = 3;
} else if (maxVal < 0x10000) {
pass = 2;
} else if (maxVal < 0x1000000) {
pass = 1;
}
const countingArray = countingArrays[pass];
const shift = 24 - pass * 8;
let liftedValues = [];
const indexArray = countingArrays[4];
if (countingArray[0] === right - left) {
return _radixsort(array, indices, left, right, ++pass);
} else if (countingArray[0] > 0) {
liftedValues.push(indices[left]);
}
indexArray[0] = left;
for (let i = 1, prevCount = (countingArray[0] += left); i < 256; i++) {
let count = countingArray[i];
if (count === right - left)
return _radixsort(array, indices, left, right, ++pass);
else if (count > 0) liftedValues.push(indices[prevCount]);
indexArray[i] = prevCount;
prevCount += count;
countingArray[i] = prevCount;
}
for (let i = 0; i < liftedValues.length - 1; i++) {
let index = liftedValues[i];
let val = array[index];
let bucket = (val >>> shift) & 0xFF;
let bIdx = indexArray[bucket]++;
let end = countingArray[bucket];
indices[bIdx++] = index;
while (bIdx < end) {
index = indices[bIdx];
val = array[index];
bucket = (val >>> shift) & 0xFF;
bIdx = indexArray[bucket]++;
end = countingArray[bucket];
indices[bIdx++] = index;
}
}
let index = liftedValues[liftedValues.length - 1];
val = array[index];
indices[indexArray[(val >>> shift) & 0xFF]] = index;
pass++;
for (let i = 0, sum = left; i < 256; i++) {
const nextSum = countingArray[i];
if (sum < nextSum) {
if (nextSum - sum <= 40) {
for (let j = sum + 1, k; j < nextSum; j++) {
index = indices[j];
val = array[index];
for (k = j - 1; k >= sum && array[indices[k]] > val; k--) {
indices[k + 1] = indices[k];
}
if (++k < j) indices[k] = index;
}
} else {
_radixsort(array, indices, sum, nextSum, pass);
}
}
sum = nextSum;
}
return indices;
}
return function radixsort(array, indices) {
if (array.length <= 200) {
indices.sort((a, b) => array[a] - array[b]);
return indices;
}
return _radixsort(array, indices, 0, array.length, 0);
};
}