use rlx_ir::NodeId;
use rlx_opt::memory::MemoryPlan;
#[derive(Clone)]
pub struct Arena {
buf: Vec<u8>,
plan: MemoryPlan,
}
impl Arena {
pub fn from_plan(plan: MemoryPlan) -> Self {
let buf = vec![0u8; plan.arena_size];
Self { buf, plan }
}
pub fn size(&self) -> usize {
self.plan.arena_size
}
pub fn slice_mut(&mut self, id: NodeId) -> &mut [f32] {
let slot = self
.plan
.assignments
.get(&id)
.unwrap_or_else(|| panic!("no buffer for {id}"));
let bytes = &mut self.buf[slot.offset..slot.offset + slot.size];
unsafe { std::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut f32, slot.size / 4) }
}
pub fn slice(&self, id: NodeId) -> &[f32] {
let slot = self
.plan
.assignments
.get(&id)
.unwrap_or_else(|| panic!("no buffer for {id}"));
let bytes = &self.buf[slot.offset..slot.offset + slot.size];
unsafe { std::slice::from_raw_parts(bytes.as_ptr() as *const f32, slot.size / 4) }
}
pub fn slice_mut_f64(&mut self, id: NodeId) -> &mut [f64] {
let slot = self
.plan
.assignments
.get(&id)
.unwrap_or_else(|| panic!("no buffer for {id}"));
debug_assert!(
slot.size.is_multiple_of(8),
"slice_mut_f64: slot {} has size {} not divisible by 8",
id,
slot.size
);
let bytes = &mut self.buf[slot.offset..slot.offset + slot.size];
unsafe { std::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut f64, slot.size / 8) }
}
pub fn slice_f64(&self, id: NodeId) -> &[f64] {
let slot = self
.plan
.assignments
.get(&id)
.unwrap_or_else(|| panic!("no buffer for {id}"));
debug_assert!(
slot.size.is_multiple_of(8),
"slice_f64: slot {} has size {} not divisible by 8",
id,
slot.size
);
let bytes = &self.buf[slot.offset..slot.offset + slot.size];
unsafe { std::slice::from_raw_parts(bytes.as_ptr() as *const f64, slot.size / 8) }
}
pub fn has_buffer(&self, id: NodeId) -> bool {
self.plan.assignments.contains_key(&id)
}
pub fn raw_ptr(&self, id: NodeId) -> (*mut f32, usize) {
let slot = self
.plan
.assignments
.get(&id)
.unwrap_or_else(|| panic!("no buffer for {id}"));
let ptr = unsafe { self.buf.as_ptr().add(slot.offset) as *mut f32 };
(ptr, slot.size / 4)
}
pub fn schedule(&self) -> &[NodeId] {
&self.plan.schedule
}
pub fn byte_offset(&self, id: NodeId) -> usize {
self.plan
.assignments
.get(&id)
.map(|s| s.offset)
.unwrap_or(usize::MAX)
}
pub fn raw_buf_mut(&mut self) -> &mut [u8] {
&mut self.buf
}
pub fn raw_buf(&self) -> &[u8] {
&self.buf
}
pub fn raw_buf_mut_ptr(&self) -> *const u8 {
self.buf.as_ptr()
}
}
#[cfg(test)]
mod tests {
use super::*;
use rlx_opt::memory::BufferSlot;
use std::collections::HashMap;
#[test]
fn arena_slice_access() {
let plan = MemoryPlan {
arena_size: 1024,
assignments: {
let mut m = HashMap::new();
m.insert(
NodeId(0),
BufferSlot {
offset: 0,
size: 256,
},
);
m.insert(
NodeId(1),
BufferSlot {
offset: 256,
size: 512,
},
);
m
},
schedule: vec![NodeId(0), NodeId(1)],
};
let mut arena = Arena::from_plan(plan);
let s0 = arena.slice_mut(NodeId(0));
assert_eq!(s0.len(), 64); s0[0] = 42.0;
let s1 = arena.slice_mut(NodeId(1));
assert_eq!(s1.len(), 128);
let s0_read = arena.slice(NodeId(0));
assert_eq!(s0_read[0], 42.0);
}
}