///|
priv struct AsinhGridCursor {
run : AsinhGridRun
first : Int64
last : Int64
reverse : Bool
factor : Double
subdivision : Int32
multiplier : Int64
next : Int64
value : Double
rank : Int64
}
///|
fn asinh_grid_cursor(
context : AsinhGridContext,
run : AsinhGridRun,
first : Int64,
last : Int64,
reverse : Bool,
factor : Double,
subdivision : Int32,
multiplier : Int64,
position : Int64,
) -> AsinhGridCursor {
let native = fn(index : Int64) {
if reverse {
last - 1L - index
} else {
first + index
}
}
let value = context.value(run, native(position), factor)
let next_position = position + 1L
let next = if next_position == last - first ||
context.value(run, native(next_position), factor) != value {
next_position
} else {
next_position +
asinh_grid_boundary(last - first - next_position, index => {
context.value(run, native(next_position + index), factor) != value
})
}
// A reversed equal-value plateau can contain either zero sign. Python set
// retains the value at the earliest original outer(flatten) insertion rank.
let representative = if reverse {
native(next - 1L)
} else {
native(position)
}
{
run,
first,
last,
reverse,
factor,
subdivision,
multiplier,
next,
value: context.value(run, representative, factor),
rank: (run.rank + representative) * multiplier + subdivision.to_int64(),
}
}
///|
fn asinh_grid_cursor_less(
left : AsinhGridCursor,
right : AsinhGridCursor,
) -> Bool {
left.value < right.value ||
(left.value == right.value && left.rank < right.rank)
}
///|
fn asinh_grid_push_numeric(
heap : Array[AsinhGridCursor],
context : AsinhGridContext,
run : AsinhGridRun,
first : Int64,
last : Int64,
factor : Double,
subdivision : Int32,
multiplier : Int64,
) -> Unit {
let mut start = first
while start < last {
let finish = if context.base > 1.0 {
last
} else {
// Across decimal phases 10*round(10^n) can exceed round(10^(n+1)).
// Each constant-pows run has monotone separate multiply/round steps.
let pows = context.point(run.at(context.line, start)).pows
start +
1L +
asinh_grid_boundary(last - start - 1L, index => {
context.point(run.at(context.line, start + 1L + index)).pows != pows
})
}
let reverse = context.value(run, start, factor) >
context.value(run, finish - 1L, factor)
asinh_grid_heap_push(
heap,
asinh_grid_cursor(
context, run, start, finish, reverse, factor, subdivision, multiplier, 0L,
),
)
start = finish
}
}
///|
fn asinh_grid_heap_push(
heap : Array[AsinhGridCursor],
cursor : AsinhGridCursor,
) -> Unit {
heap.push(cursor)
let mut index = heap.length() - 1
while index > 0 {
let parent = (index - 1) / 2
if !asinh_grid_cursor_less(heap[index], heap[parent]) {
break
}
let value = heap[index]
heap[index] = heap[parent]
heap[parent] = value
index = parent
}
}
///|
fn asinh_grid_heap_pop(heap : Array[AsinhGridCursor]) -> AsinhGridCursor {
let result = heap[0]
let last = heap.pop().unwrap()
if !heap.is_empty() {
heap[0] = last
let mut index = 0
while index * 2 + 1 < heap.length() {
let left = index * 2 + 1
let right = left + 1
let child = if right < heap.length() &&
asinh_grid_cursor_less(heap[right], heap[left]) {
right
} else {
left
}
if !asinh_grid_cursor_less(heap[child], heap[index]) {
break
}
let value = heap[index]
heap[index] = heap[child]
heap[child] = value
index = child
}
}
result
}