Skip to main content

sim_lib_audio_graph_core/
arena.rs

1use sim_kernel::{Error, Result};
2
3/// Bump allocator for per-block `f32` scratch buffers.
4///
5/// Processors borrow zeroed slices from the arena during a process call; the
6/// graph calls [`BlockArena::reset`] before each node so its capacity is reused
7/// without per-block heap allocation.
8#[derive(Clone, Debug, Default, PartialEq)]
9pub struct BlockArena {
10    f32_cells: Vec<f32>,
11    used_f32: usize,
12}
13
14impl BlockArena {
15    /// Creates an arena with no capacity.
16    pub fn empty() -> Self {
17        Self::default()
18    }
19
20    /// Creates an arena pre-sized for `capacity` `f32` cells.
21    pub fn with_f32_capacity(capacity: usize) -> Self {
22        Self {
23            f32_cells: vec![0.0; capacity],
24            used_f32: 0,
25        }
26    }
27
28    /// Releases all outstanding allocations, keeping the backing capacity.
29    pub fn reset(&mut self) {
30        self.used_f32 = 0;
31    }
32
33    /// Returns the total `f32` capacity of the arena.
34    pub fn f32_capacity(&self) -> usize {
35        self.f32_cells.len()
36    }
37
38    /// Allocates and zero-fills a `len`-cell `f32` slice.
39    ///
40    /// Fails if the request overflows or exceeds the remaining capacity.
41    pub fn alloc_f32(&mut self, len: usize) -> Result<&mut [f32]> {
42        let start = self.used_f32;
43        let end = start
44            .checked_add(len)
45            .ok_or_else(|| Error::Eval("audio block arena allocation overflow".to_owned()))?;
46        if end > self.f32_cells.len() {
47            return Err(Error::Eval(format!(
48                "audio block arena exhausted: requested {len} f32 cells with {} remaining",
49                self.f32_cells.len().saturating_sub(start)
50            )));
51        }
52        self.used_f32 = end;
53        let cells = &mut self.f32_cells[start..end];
54        cells.fill(0.0);
55        Ok(cells)
56    }
57}