use crate::float::AlpFloat;
#[inline(always)]
fn scan_deltas<F: AlpFloat>(
slice: &[F::Int],
prev: &mut F::Int,
min_delta: &mut F::Int,
max_delta: &mut F::Int,
) {
let (chunks, rem) = slice.as_chunks::<4>();
for chunk in chunks {
let d0 = F::int_sub(chunk[0], *prev);
let d1 = F::int_sub(chunk[1], chunk[0]);
let d2 = F::int_sub(chunk[2], chunk[1]);
let d3 = F::int_sub(chunk[3], chunk[2]);
*prev = chunk[3];
let l_min = d0.min(d1).min(d2.min(d3));
let l_max = d0.max(d1).max(d2.max(d3));
*min_delta = (*min_delta).min(l_min);
*max_delta = (*max_delta).max(l_max);
}
for &curr in rem {
let delta = F::int_sub(curr, *prev);
*min_delta = (*min_delta).min(delta);
*max_delta = (*max_delta).max(delta);
*prev = curr;
}
}
#[inline(always)]
pub fn delta_range<F: AlpFloat>(first: F::Int, rest: &[F::Int]) -> (F::Int, u8) {
let mut min_delta = F::MAX_INT;
let mut max_delta = F::MIN_INT;
let mut prev = first;
scan_deltas::<F>(rest, &mut prev, &mut min_delta, &mut max_delta);
let delta_bit_width = F::bits_needed(F::calc_range(min_delta, max_delta));
(min_delta, delta_bit_width)
}
#[inline(always)]
pub fn eval_delta_benefit<F: AlpFloat>(
first: F::Int,
rest: &[F::Int],
for_bit_width: u8,
) -> Option<(F::Int, u8)> {
if rest.is_empty() {
return None;
}
let pre_n = rest.len().min(16);
let mut min_delta = F::MAX_INT;
let mut max_delta = F::MIN_INT;
let mut prev = first;
scan_deltas::<F>(&rest[..pre_n], &mut prev, &mut min_delta, &mut max_delta);
let pre_bw = F::bits_needed(F::calc_range(min_delta, max_delta));
if pre_bw >= for_bit_width {
return None;
}
if pre_n < rest.len() {
scan_deltas::<F>(&rest[pre_n..], &mut prev, &mut min_delta, &mut max_delta);
}
let delta_bit_width = F::bits_needed(F::calc_range(min_delta, max_delta));
if delta_bit_width < for_bit_width {
Some((min_delta, delta_bit_width))
} else {
None
}
}
#[inline(always)]
pub fn in_place_deltas<F: AlpFloat>(data: &mut [F::Int]) {
for i in (1..data.len()).rev() {
data[i] = F::int_sub(data[i], data[i - 1]);
}
}
#[inline(always)]
pub fn reconstruct_ramp_into_floats<F: AlpFloat>(
first: F::Int,
constant_delta: F::Int,
count: usize,
fac_int: i64,
frac_flt: F,
dst: &mut [F],
) {
let mut curr = first;
for slot in dst.iter_mut().take(count) {
*slot = F::decode_from_int(curr, fac_int, frac_flt);
curr = F::int_add(curr, constant_delta);
}
}