Files
plainleaf/client/space_lua/util.ts
T

135 lines
3.0 KiB
TypeScript

import { isPromise } from "./rp.ts";
export function evalPromiseValues(vals: any[]): Promise<any[]> | any[] {
const promises = [];
const promiseResults = new Array(vals.length);
for (let i = 0; i < vals.length; i++) {
if (isPromise(vals[i])) {
promises.push(
(vals[i] as Promise<any>).then((v: any) => (promiseResults[i] = v)),
);
} else {
promiseResults[i] = vals[i];
}
}
if (promises.length === 0) {
return promiseResults;
}
return Promise.all(promises).then(() => promiseResults);
}
/**
* return the mid value among x, y, and z
* @param x
* @param y
* @param z
* @param compare
* @returns {Promise.<*>}
*/
async function getPivot(
x: any,
y: any,
z: any,
compare: (a: any, b: any) => Promise<number>,
) {
if ((await compare(x, y)) < 0) {
if ((await compare(y, z)) < 0) {
return y;
}
if ((await compare(z, x)) < 0) {
return x;
}
return z;
}
if ((await compare(y, z)) > 0) {
return y;
}
if ((await compare(z, x)) > 0) {
return x;
}
return z;
}
/**
* asynchronous quick sort
* @param arr array to sort
* @param compare asynchronous comparing function
* @param left index where the range of elements to be sorted starts
* @param right index where the range of elements to be sorted ends
* @returns {Promise.<*>}
*/
export async function asyncQuickSort(
arr: any[],
compare: (a: any, b: any) => Promise<number>,
left = 0,
right = arr.length - 1,
) {
if (left < right) {
let i = left,
j = right,
tmp;
const pivot = await getPivot(
arr[i],
arr[i + Math.floor((j - i) / 2)],
arr[j],
compare,
);
while (true) {
while ((await compare(arr[i], pivot)) < 0) {
i++;
}
while ((await compare(pivot, arr[j])) < 0) {
j--;
}
if (i >= j) {
break;
}
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
await asyncQuickSort(arr, compare, left, i - 1);
await asyncQuickSort(arr, compare, j + 1, right);
}
return arr;
}
/**
* iterative async merge sort
* @param arr tagged array of { val, idx } elements
* @param compare async comparator returning <0, 0, or >0
*/
export async function asyncMergeSort(
arr: { val: any; idx: number }[],
compare: (
a: { val: any; idx: number },
b: { val: any; idx: number },
) => Promise<number>,
): Promise<void> {
const n = arr.length;
if (n <= 1) return;
const work = new Array(n);
for (let size = 1; size < n; size *= 2) {
for (let left = 0; left < n; left += 2 * size) {
const mid = Math.min(left + size, n);
const right = Math.min(left + 2 * size, n);
let i = left,
j = mid,
k = left;
while (i < mid && j < right) {
const cmp = await compare(arr[i], arr[j]);
if (cmp <= 0) work[k++] = arr[i++];
else work[k++] = arr[j++];
}
while (i < mid) work[k++] = arr[i++];
while (j < right) work[k++] = arr[j++];
for (let m = left; m < right; m++) arr[m] = work[m];
}
}
}