use crate::IsLessThan;
use crate::prelude::SkipList;
use crate::skiplist::{HEAD_INDEX, SkipNode, TAIL_INDEX};
use std::fmt::Debug;
impl<K, V> SkipList<K, V>
where
K: Debug + Clone + IsLessThan,
V: Debug + Clone,
{
pub(super) fn get_rank_in_between(&self, current_idx: usize, next_idx: usize) -> (i64, bool) {
if current_idx == HEAD_INDEX && next_idx == TAIL_INDEX {
return (0, false);
}
let current_rank = match current_idx {
HEAD_INDEX => self.head.rank,
TAIL_INDEX => unreachable!(),
_ => self.nodes[current_idx].rank,
};
let next_rank = match next_idx {
HEAD_INDEX => unreachable!(),
TAIL_INDEX => self.tail.rank,
_ => self.nodes[next_idx].rank,
};
get_rank_between(current_rank, next_rank)
}
pub(super) fn rebalance_ranks(&mut self) {
if self.len() < 2 {
self.is_congested = false;
return;
}
let rank_step = i64::MAX / (self.len() as i64);
let mut current_rank: i64 = (-i64::MAX / 2).saturating_add(1);
if let Some(mut idx) = self.first_() {
while idx != TAIL_INDEX {
if let Some(SkipNode { rank, forward, .. }) = self.nodes.get_mut(idx) {
*rank = current_rank;
current_rank += rank_step;
idx = forward[0];
} else {
break;
}
}
}
self.is_congested = false;
#[cfg(feature = "console_debug")]
{
println!("new ranks");
self.debug_print_ranks();
println!("end new ranks");
}
}
pub(super) fn find_position_by_rank_with_path_(&self, rank: i64) -> Vec<usize> {
let mut update = vec![HEAD_INDEX; self.max_level];
let mut current = HEAD_INDEX;
for level in (0..=self.current_level).rev() {
loop {
let next = self._forward(current, level);
if next == TAIL_INDEX || self.nodes[next].rank >= rank {
update[level] = current;
break;
}
current = next;
}
}
update
}
#[cfg(feature = "console_debug")]
pub(super) fn debug_print_ranks(&self) {
let mut cursor = self.first();
while cursor.is_some() {
let node = &self.nodes[cursor.unwrap().0];
print!(
"[index:{}, rank:{}, key:{:?}, val:{:?}]",
cursor.unwrap().0,
node.rank,
node.k(),
node.v()
);
cursor = self.next_pos(cursor);
if cursor.is_some() {
println!(",");
}
}
println!();
}
}
#[inline(always)]
pub(super) fn get_rank_between(prev: i64, next: i64) -> (i64, bool) {
dbg_assert!(prev < next, "prev:{} next:{}", prev, next);
let half_sum = (prev >> 1).wrapping_add(next >> 1);
let remainder_adjustment = ((prev & 1).wrapping_add(next & 1)) >> 1;
let mid = half_sum.wrapping_add(remainder_adjustment);
dbg_assert!(mid > prev, "prev:{} <! mid:{} next:{}", prev, mid, next);
dbg_assert!(mid < next, "prev:{} mid:{} <! next:{}", prev, mid, next);
const THRESHOLD: i64 = 6;
let dist_to_prev = mid - prev;
let dist_to_next = next - mid;
(mid, dist_to_prev < THRESHOLD || dist_to_next < THRESHOLD)
}