use alloc::collections::BTreeMap;
pub struct RangeTree {
pub segments: BTreeMap<u64, u64>,
pub total_free: u64,
}
impl RangeTree {
pub fn new(disk_size: u64, reserved_start: u64) -> Self {
let mut segments = BTreeMap::new();
let usable_size = disk_size.saturating_sub(reserved_start);
if usable_size > 0 {
segments.insert(reserved_start, usable_size);
}
Self {
segments,
total_free: usable_size,
}
}
pub fn allocate(&mut self, size: u64) -> Option<u64> {
let aligned_size = (size + 4095) & !4095;
let target_key = self
.segments
.iter()
.find(|&(_, seg_size)| *seg_size >= aligned_size)
.map(|(offset, _)| *offset);
if let Some(offset) = target_key {
debug_assert!(
self.segments.contains_key(&offset),
"offset found via find() above must exist"
);
let available_size = self.segments.remove(&offset)?;
if available_size > aligned_size {
let new_start = offset + aligned_size;
let new_size = available_size - aligned_size;
self.segments.insert(new_start, new_size);
}
self.total_free -= aligned_size;
return Some(offset);
}
None }
pub fn is_allocated(&self, offset: u64) -> bool {
for (&seg_start, &seg_size) in &self.segments {
if offset >= seg_start && offset < seg_start + seg_size {
return false; }
}
true }
pub fn free(&mut self, offset: u64, size: u64) -> Result<(), &'static str> {
if !self.is_allocated(offset) {
crate::lcpfs_println!("[ SPACE] WARNING: Double-free attempted at 0x{:x}!", offset);
return Err("Double-free detected: block already free");
}
let aligned_size = (size + 4095) & !4095;
let mut start = offset;
let mut len = aligned_size;
let left_neighbor = self.segments.range(..offset).next_back();
let mut remove_left = None;
if let Some((&l_off, &l_size)) = left_neighbor {
if l_off + l_size == offset {
start = l_off;
len += l_size;
remove_left = Some(l_off);
}
}
if let Some(k) = remove_left {
self.segments.remove(&k);
}
let right_neighbor_key = offset + aligned_size;
if let Some(&r_size) = self.segments.get(&right_neighbor_key) {
len += r_size;
self.segments.remove(&right_neighbor_key);
}
self.segments.insert(start, len);
self.total_free += aligned_size;
crate::lcpfs_println!(
"[ SPACE] Freed 0x{:x} -> Merged: 0x{:x} len {}",
offset,
start,
len
);
Ok(())
}
pub fn free_unchecked(&mut self, offset: u64, size: u64) {
let _ = self.free(offset, size);
}
}