|
import ascending from "./ascending.js"; |
|
import descending from "./descending.js"; |
|
|
|
export default function bisector(f) { |
|
let compare1, compare2, delta; |
|
|
|
|
|
|
|
|
|
|
|
|
|
if (f.length !== 2) { |
|
compare1 = ascending; |
|
compare2 = (d, x) => ascending(f(d), x); |
|
delta = (d, x) => f(d) - x; |
|
} else { |
|
compare1 = f === ascending || f === descending ? f : zero; |
|
compare2 = f; |
|
delta = f; |
|
} |
|
|
|
function left(a, x, lo = 0, hi = a.length) { |
|
if (lo < hi) { |
|
if (compare1(x, x) !== 0) return hi; |
|
do { |
|
const mid = (lo + hi) >>> 1; |
|
if (compare2(a[mid], x) < 0) lo = mid + 1; |
|
else hi = mid; |
|
} while (lo < hi); |
|
} |
|
return lo; |
|
} |
|
|
|
function right(a, x, lo = 0, hi = a.length) { |
|
if (lo < hi) { |
|
if (compare1(x, x) !== 0) return hi; |
|
do { |
|
const mid = (lo + hi) >>> 1; |
|
if (compare2(a[mid], x) <= 0) lo = mid + 1; |
|
else hi = mid; |
|
} while (lo < hi); |
|
} |
|
return lo; |
|
} |
|
|
|
function center(a, x, lo = 0, hi = a.length) { |
|
const i = left(a, x, lo, hi - 1); |
|
return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i; |
|
} |
|
|
|
return {left, center, right}; |
|
} |
|
|
|
function zero() { |
|
return 0; |
|
} |
|
|