use crate::IsLessThan;
use crate::skiplist::{HEAD_INDEX, SkipList, SkipNode, TAIL_INDEX};
use std::fmt::Debug;
use std::marker::PhantomData;
type PhantomType<K, V> = PhantomData<fn(K, V) -> (K, V)>;
struct NodeExtensionUpdate<K, V>
where
K: Debug + Clone + IsLessThan,
V: Debug + Clone,
{
node_idx: usize,
new_levels: Vec<(usize, usize)>, pointer_updates: Vec<(usize, usize, usize)>, new_current_level: Option<usize>, _pd: PhantomType<K, V>,
}
impl<K, V> SkipList<K, V>
where
K: Debug + Clone + IsLessThan,
V: Debug + Clone,
{
pub(super) fn extend_node_level(
&mut self,
node_idx: usize,
current_node_level: usize,
rng: &mut rand::prelude::ThreadRng,
) {
let updates = self.calculate_node_extension(node_idx, current_node_level, rng);
self.apply_node_extension(updates);
}
fn calculate_node_extension(
&self,
node_idx: usize,
current_node_level: usize,
rng: &mut rand::prelude::ThreadRng,
) -> NodeExtensionUpdate<K, V> {
let mut update = NodeExtensionUpdate {
node_idx,
new_levels: Vec::new(),
pointer_updates: Vec::new(),
new_current_level: None,
_pd: PhantomData,
};
if current_node_level >= self.max_level {
return update;
}
let mut level = current_node_level;
let node_key = if node_idx != HEAD_INDEX && node_idx != TAIL_INDEX {
self.nodes[node_idx].k()
} else {
return update; };
while level < self.max_level && self.coin_flip(rng, level) {
level += 1;
let mut update_positions = vec![HEAD_INDEX; self.max_level];
let mut x = HEAD_INDEX;
for i in (0..level).rev() {
if i < current_node_level {
break;
}
loop {
let next_idx = self._forward(x, i);
if next_idx == TAIL_INDEX {
break;
}
if next_idx != HEAD_INDEX
&& next_idx != TAIL_INDEX
&& !self.nodes[next_idx].k().is_less_than(node_key)
{
break;
}
x = next_idx;
}
update_positions[i] = x;
}
let next_at_level = {
let id = update_positions[level - 1];
if id == HEAD_INDEX {
self.head.forward[level - 1]
} else if id == TAIL_INDEX {
TAIL_INDEX
} else {
self.nodes[id].forward[level - 1]
}
};
update.new_levels.push((level - 1, next_at_level));
update
.pointer_updates
.push((update_positions[level - 1], level - 1, node_idx));
if level > self.current_level {
update.new_current_level = Some(level);
}
}
update
}
fn apply_node_extension(&mut self, update: NodeExtensionUpdate<K, V>) {
if let Some(SkipNode { forward, .. }) = &mut self.nodes.get_mut(update.node_idx) {
for (level, next_idx) in update.new_levels {
while forward.len() <= level {
forward.push(TAIL_INDEX);
}
forward[level] = next_idx;
}
}
for (prev_idx, level, new_next) in update.pointer_updates {
if prev_idx == HEAD_INDEX {
if level < self.head.forward.len() {
self.head.forward[level] = new_next;
}
} else {
let forward = &mut self.nodes[prev_idx].forward;
if level < forward.len() {
forward[level] = new_next;
}
}
}
if let Some(new_level) = update.new_current_level {
if new_level > self.current_level {
self.current_level = new_level;
}
}
}
pub(super) fn adjust_max_level(&mut self, rng: &mut rand::prelude::ThreadRng) {
let node_count = self.len();
let ideal_max_level = (node_count as f64).log2().ceil() as usize;
if ideal_max_level <= self.max_level {
return;
}
let levels_to_add = ideal_max_level - self.max_level;
let old_max_level = self.max_level;
self.max_level = ideal_max_level;
self.head.forward.extend(vec![TAIL_INDEX; levels_to_add]);
let mut candidates = Vec::new();
for level_diff in 1..=levels_to_add {
let check_level = old_max_level - level_diff;
if check_level == 0 {
break;
}
let candidate_node = self.head.forward[check_level - 1];
if candidate_node != TAIL_INDEX {
candidates.push((candidate_node, old_max_level - level_diff + 1));
}
}
for (node_idx, current_level) in candidates {
self.extend_node_level(node_idx, current_level, rng);
}
}
#[inline(always)]
pub(super) fn maybe_adjust_max_level(&mut self, rng: &mut rand::prelude::ThreadRng) {
self.adjust_max_level(rng);
}
#[inline(always)]
pub fn current_level(&self) -> usize {
self.current_level
}
#[inline(always)]
pub fn max_level(&self) -> usize {
self.max_level
}
}