oxilean_runtime/region_alloc/
types.rs1use std::marker::PhantomData;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
7pub struct RegionId(pub u32);
8
9impl RegionId {
10 pub fn new(id: u32) -> Self {
12 RegionId(id)
13 }
14
15 pub fn raw(self) -> u32 {
17 self.0
18 }
19}
20
21impl std::fmt::Display for RegionId {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 write!(f, "region#{}", self.0)
24 }
25}
26
27#[derive(Debug)]
32pub struct Region {
33 pub id: RegionId,
35 pub data: Vec<u8>,
37 pub offset: usize,
39 pub capacity: usize,
41}
42
43impl Region {
44 pub fn new(id: RegionId, capacity: usize) -> Self {
46 let capacity = capacity.max(1);
47 Region {
48 id,
49 data: vec![0u8; capacity],
50 offset: 0,
51 capacity,
52 }
53 }
54
55 pub fn remaining(&self) -> usize {
57 self.capacity.saturating_sub(self.offset)
58 }
59
60 pub fn used(&self) -> usize {
62 self.offset
63 }
64
65 pub fn is_empty(&self) -> bool {
67 self.offset == 0
68 }
69
70 pub fn reset(&mut self) {
72 self.offset = 0;
73 for b in &mut self.data {
75 *b = 0;
76 }
77 }
78}
79
80#[derive(Clone, Copy, Debug, PartialEq, Eq)]
85pub struct RegionHandle<'a> {
86 pub id: RegionId,
88 pub phantom: PhantomData<&'a ()>,
90}
91
92impl<'a> RegionHandle<'a> {
93 pub fn new(id: RegionId) -> Self {
95 RegionHandle {
96 id,
97 phantom: PhantomData,
98 }
99 }
100
101 pub fn region_id(self) -> RegionId {
103 self.id
104 }
105}
106
107impl<'a> std::fmt::Display for RegionHandle<'a> {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 write!(f, "handle({})", self.id)
110 }
111}
112
113#[derive(Clone, Debug, Default, PartialEq, Eq)]
115pub struct AllocStats {
116 pub regions_created: usize,
118 pub regions_freed: usize,
120 pub total_allocated: usize,
122 pub total_freed: usize,
124 pub peak_usage: usize,
126}
127
128impl AllocStats {
129 pub fn active_regions(&self) -> usize {
131 self.regions_created.saturating_sub(self.regions_freed)
132 }
133
134 pub fn utilization(&self, total_capacity: usize) -> f64 {
136 if total_capacity == 0 {
137 return 0.0;
138 }
139 self.total_allocated as f64 / total_capacity as f64
140 }
141}
142
143impl std::fmt::Display for AllocStats {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 write!(
146 f,
147 "AllocStats {{ created: {}, freed: {}, allocated: {}, peak: {} }}",
148 self.regions_created, self.regions_freed, self.total_allocated, self.peak_usage
149 )
150 }
151}
152
153#[derive(Clone, Debug)]
155pub struct RegionConfig {
156 pub initial_capacity: usize,
158 pub growth_factor: f64,
161 pub max_regions: usize,
163}
164
165impl RegionConfig {
166 pub fn new(initial_capacity: usize, growth_factor: f64, max_regions: usize) -> Self {
168 let growth_factor = growth_factor.clamp(1.001, 16.0);
169 RegionConfig {
170 initial_capacity: initial_capacity.max(64),
171 growth_factor,
172 max_regions: max_regions.max(1),
173 }
174 }
175
176 pub fn grow(&self, current: usize) -> usize {
178 ((current as f64 * self.growth_factor) as usize).max(current + 64)
179 }
180}
181
182impl Default for RegionConfig {
183 fn default() -> Self {
184 RegionConfig::new(4096, 2.0, 256)
185 }
186}
187
188pub struct RegionAllocator {
193 pub regions: Vec<Region>,
195 pub free_list: Vec<RegionId>,
197 pub default_capacity: usize,
199 pub(super) config: RegionConfig,
201 pub(super) stats: AllocStats,
203 pub(super) next_id: u32,
205 pub(super) current_usage: usize,
207}