#[derive(Clone, Debug)]
pub struct SumTree {
nodes: Vec<f32>,
size: usize,
capacity: usize,
write: usize,
len: usize,
}
impl SumTree {
pub fn new(capacity: usize) -> Self {
let capacity = capacity.max(1);
let size = capacity.next_power_of_two();
SumTree {
nodes: vec![0.0; 2 * size],
size,
capacity,
write: 0,
len: 0,
}
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn is_full(&self) -> bool {
self.len == self.capacity
}
#[inline]
pub fn total(&self) -> f32 {
self.nodes[1]
}
#[inline]
pub fn priority(&self, index: usize) -> f32 {
assert!(index < self.capacity, "index {index} out of bounds");
self.nodes[self.size + index]
}
#[inline]
pub fn update(&mut self, index: usize, priority: f32) {
assert!(index < self.capacity, "index {index} out of bounds");
assert!(priority >= 0.0, "priority must be non-negative");
let nodes = &mut self.nodes;
let mask = nodes.len() - 1;
let mut i = index + self.size;
let delta = priority - nodes[i & mask];
nodes[i & mask] = priority;
while i > 1 {
i >>= 1;
nodes[i & mask] += delta;
}
}
pub fn rebuild(&mut self) {
for i in (1..self.size).rev() {
self.nodes[i] = self.nodes[2 * i] + self.nodes[2 * i + 1];
}
}
#[inline]
pub fn push(&mut self, priority: f32) -> usize {
let index = self.write;
self.update(index, priority);
self.write = (self.write + 1) % self.capacity;
if self.len < self.capacity {
self.len += 1;
}
index
}
#[inline]
pub fn get(&self, s: f32) -> Option<(usize, f32)> {
let total = self.nodes[1];
if self.len == 0 || total <= 0.0 {
return None;
}
let mut s = if s.is_nan() { 0.0 } else { s.clamp(0.0, total) };
let size = self.size;
let nodes = self.nodes.as_slice();
let mask = nodes.len() - 1;
let mut i = 1;
while i < size {
let left = 2 * i;
let left_sum = nodes[left & mask];
let go_right = (s > left_sum) as usize;
s -= left_sum * go_right as f32;
i = left + go_right;
}
let leaf = (i - size).min(self.len - 1);
Some((leaf, nodes[(size + leaf) & mask]))
}
}