1#[allow(dead_code)]
9use std::collections::VecDeque;
10use std::marker::PhantomData;
11use std::ptr::NonNull;
12use std::sync::{Arc, Mutex};
13use std::time::{Duration, Instant};
14
15pub struct ArenaAllocator {
17 base_ptr: NonNull<u8>,
19 total_size: usize,
21 current_offset: usize,
23 high_water_mark: usize,
25 alignment: usize,
27 config: ArenaConfig,
29 allocations: Vec<AllocationRecord>,
31 stats: ArenaStats,
33 checkpoints: Vec<ArenaCheckpoint>,
35}
36
37#[derive(Debug, Clone)]
39pub struct AllocationRecord {
40 pub ptr: NonNull<u8>,
42 pub size: usize,
44 pub offset: usize,
46 pub allocated_at: Instant,
48 pub id: u64,
50 pub tag: Option<String>,
52}
53
54#[derive(Debug, Clone)]
56pub struct ArenaCheckpoint {
57 pub offset: usize,
59 pub allocation_count: usize,
61 pub created_at: Instant,
63 pub name: Option<String>,
65}
66
67#[derive(Debug, Clone)]
69pub struct ArenaConfig {
70 pub alignment: usize,
72 pub enable_tracking: bool,
74 pub enable_debug: bool,
76 pub enable_checkpoints: bool,
78 pub enable_stats: bool,
80 pub growth_strategy: GrowthStrategy,
82 pub initial_tracking_capacity: usize,
84}
85
86impl Default for ArenaConfig {
87 fn default() -> Self {
88 Self {
89 alignment: 8,
90 enable_tracking: false,
91 enable_debug: false,
92 enable_checkpoints: true,
93 enable_stats: true,
94 growth_strategy: GrowthStrategy::Fixed,
95 initial_tracking_capacity: 1024,
96 }
97 }
98}
99
100#[derive(Debug, Clone, PartialEq)]
102pub enum GrowthStrategy {
103 Fixed,
105 Double,
107 Linear(usize),
109 Custom(fn(usize) -> usize),
111}
112
113#[derive(Debug, Clone, Default)]
115pub struct ArenaStats {
116 pub total_allocations: u64,
118 pub total_bytes_allocated: u64,
120 pub current_bytes_allocated: usize,
122 pub peak_bytes_allocated: usize,
124 pub reset_count: u64,
126 pub checkpoint_count: u64,
128 pub rollback_count: u64,
130 pub average_allocation_size: f64,
132 pub allocation_rate: f64,
134 pub utilization_ratio: f64,
136 pub first_allocation_time: Option<Instant>,
138 pub last_allocation_time: Option<Instant>,
140}
141
142impl ArenaStats {
143 pub fn record_allocation(&mut self, size: usize) {
144 let now = Instant::now();
145
146 self.total_allocations += 1;
147 self.total_bytes_allocated += size as u64;
148 self.current_bytes_allocated += size;
149
150 if self.current_bytes_allocated > self.peak_bytes_allocated {
151 self.peak_bytes_allocated = self.current_bytes_allocated;
152 }
153
154 self.average_allocation_size =
156 self.total_bytes_allocated as f64 / self.total_allocations as f64;
157
158 if let Some(first_time) = self.first_allocation_time {
160 let elapsed = now.duration_since(first_time).as_secs_f64();
161 if elapsed > 0.0 {
162 self.allocation_rate = self.total_allocations as f64 / elapsed;
163 }
164 } else {
165 self.first_allocation_time = Some(now);
166 }
167
168 self.last_allocation_time = Some(now);
169 }
170
171 pub fn record_reset(&mut self) {
172 self.reset_count += 1;
173 self.current_bytes_allocated = 0;
174 }
175
176 pub fn record_checkpoint(&mut self) {
177 self.checkpoint_count += 1;
178 }
179
180 pub fn record_rollback(&mut self, bytes_freed: usize) {
181 self.rollback_count += 1;
182 self.current_bytes_allocated = self.current_bytes_allocated.saturating_sub(bytes_freed);
183 }
184
185 pub fn update_utilization(&mut self, total_size: usize) {
186 if total_size > 0 {
187 self.utilization_ratio = self.current_bytes_allocated as f64 / total_size as f64;
188 }
189 }
190}
191
192impl ArenaAllocator {
193 pub fn new(
195 base_ptr: NonNull<u8>,
196 size: usize,
197 config: ArenaConfig,
198 ) -> Result<Self, ArenaError> {
199 if size == 0 {
200 return Err(ArenaError::InvalidSize(
201 "Arena size cannot be zero".to_string(),
202 ));
203 }
204
205 if !config.alignment.is_power_of_two() {
206 return Err(ArenaError::InvalidAlignment(format!(
207 "Alignment {} is not a power of two",
208 config.alignment
209 )));
210 }
211
212 let allocations = if config.enable_tracking {
213 Vec::with_capacity(config.initial_tracking_capacity)
214 } else {
215 Vec::new()
216 };
217
218 Ok(Self {
219 base_ptr,
220 total_size: size,
221 current_offset: 0,
222 high_water_mark: 0,
223 alignment: config.alignment,
224 allocations,
225 stats: ArenaStats::default(),
226 checkpoints: Vec::new(),
227 config,
228 })
229 }
230
231 pub fn allocate(&mut self, size: usize) -> Result<NonNull<u8>, ArenaError> {
233 if size == 0 {
234 return Err(ArenaError::InvalidSize(
235 "Cannot allocate zero bytes".to_string(),
236 ));
237 }
238
239 let aligned_size = (size + self.alignment - 1) & !(self.alignment - 1);
241
242 if self.current_offset + aligned_size > self.total_size {
244 return Err(ArenaError::OutOfMemory(format!(
245 "Not enough space: need {}, have {}",
246 aligned_size,
247 self.total_size - self.current_offset
248 )));
249 }
250
251 let ptr =
253 unsafe { NonNull::new_unchecked(self.base_ptr.as_ptr().add(self.current_offset)) };
254
255 self.current_offset += aligned_size;
257 if self.current_offset > self.high_water_mark {
258 self.high_water_mark = self.current_offset;
259 }
260
261 if self.config.enable_tracking {
263 let record = AllocationRecord {
264 ptr,
265 size: aligned_size,
266 offset: self.current_offset - aligned_size,
267 allocated_at: Instant::now(),
268 id: self.stats.total_allocations,
269 tag: None,
270 };
271 self.allocations.push(record);
272 }
273
274 if self.config.enable_stats {
276 self.stats.record_allocation(aligned_size);
277 self.stats.update_utilization(self.total_size);
278 }
279
280 Ok(ptr)
281 }
282
283 pub fn allocate_tagged(&mut self, size: usize, tag: String) -> Result<NonNull<u8>, ArenaError> {
285 let ptr = self.allocate(size)?;
286
287 if self.config.enable_tracking && !self.allocations.is_empty() {
288 let last_idx = self.allocations.len() - 1;
289 self.allocations[last_idx].tag = Some(tag);
290 }
291
292 Ok(ptr)
293 }
294
295 pub fn allocate_aligned(
297 &mut self,
298 size: usize,
299 alignment: usize,
300 ) -> Result<NonNull<u8>, ArenaError> {
301 if !alignment.is_power_of_two() {
302 return Err(ArenaError::InvalidAlignment(format!(
303 "Alignment {} is not a power of two",
304 alignment
305 )));
306 }
307
308 let aligned_offset = (self.current_offset + alignment - 1) & !(alignment - 1);
310 let padding = aligned_offset - self.current_offset;
311
312 if aligned_offset + size > self.total_size {
314 return Err(ArenaError::OutOfMemory(format!(
315 "Not enough space for aligned allocation: need {}, have {}",
316 aligned_offset + size - self.current_offset,
317 self.total_size - self.current_offset
318 )));
319 }
320
321 self.current_offset = aligned_offset;
323
324 self.allocate(size)
326 }
327
328 pub fn reset(&mut self) {
330 self.current_offset = 0;
331
332 if self.config.enable_tracking {
333 self.allocations.clear();
334 }
335
336 if self.config.enable_stats {
337 self.stats.record_reset();
338 self.stats.update_utilization(self.total_size);
339 }
340
341 self.checkpoints.clear();
342 }
343
344 pub fn checkpoint(&mut self) -> Result<CheckpointHandle, ArenaError> {
346 if !self.config.enable_checkpoints {
347 return Err(ArenaError::CheckpointsDisabled);
348 }
349
350 let checkpoint = ArenaCheckpoint {
351 offset: self.current_offset,
352 allocation_count: self.allocations.len(),
353 created_at: Instant::now(),
354 name: None,
355 };
356
357 self.checkpoints.push(checkpoint);
358
359 if self.config.enable_stats {
360 self.stats.record_checkpoint();
361 }
362
363 Ok(CheckpointHandle {
364 index: self.checkpoints.len() - 1,
365 offset: self.current_offset,
366 })
367 }
368
369 pub fn checkpoint_named(&mut self, name: String) -> Result<CheckpointHandle, ArenaError> {
371 if !self.config.enable_checkpoints {
372 return Err(ArenaError::CheckpointsDisabled);
373 }
374
375 let checkpoint = ArenaCheckpoint {
376 offset: self.current_offset,
377 allocation_count: self.allocations.len(),
378 created_at: Instant::now(),
379 name: Some(name),
380 };
381
382 self.checkpoints.push(checkpoint);
383
384 if self.config.enable_stats {
385 self.stats.record_checkpoint();
386 }
387
388 Ok(CheckpointHandle {
389 index: self.checkpoints.len() - 1,
390 offset: self.current_offset,
391 })
392 }
393
394 pub fn rollback(&mut self, handle: CheckpointHandle) -> Result<(), ArenaError> {
396 if !self.config.enable_checkpoints {
397 return Err(ArenaError::CheckpointsDisabled);
398 }
399
400 if handle.index >= self.checkpoints.len() {
401 return Err(ArenaError::InvalidCheckpoint(
402 "Checkpoint index out of range".to_string(),
403 ));
404 }
405
406 let checkpoint = &self.checkpoints[handle.index];
407 let bytes_freed = self.current_offset - checkpoint.offset;
408
409 self.current_offset = checkpoint.offset;
411
412 if self.config.enable_tracking {
413 self.allocations.truncate(checkpoint.allocation_count);
414 }
415
416 self.checkpoints.truncate(handle.index);
418
419 if self.config.enable_stats {
420 self.stats.record_rollback(bytes_freed);
421 self.stats.update_utilization(self.total_size);
422 }
423
424 Ok(())
425 }
426
427 pub fn get_usage(&self) -> ArenaUsage {
429 ArenaUsage {
430 total_size: self.total_size,
431 used_size: self.current_offset,
432 free_size: self.total_size - self.current_offset,
433 high_water_mark: self.high_water_mark,
434 allocation_count: self.allocations.len(),
435 checkpoint_count: self.checkpoints.len(),
436 utilization_ratio: self.current_offset as f64 / self.total_size as f64,
437 }
438 }
439
440 pub fn get_stats(&self) -> &ArenaStats {
442 &self.stats
443 }
444
445 pub fn get_allocations(&self) -> &[AllocationRecord] {
447 &self.allocations
448 }
449
450 pub fn get_checkpoints(&self) -> &[ArenaCheckpoint] {
452 &self.checkpoints
453 }
454
455 pub fn contains_pointer(&self, ptr: NonNull<u8>) -> bool {
457 let ptr_addr = ptr.as_ptr() as usize;
458 let base_addr = self.base_ptr.as_ptr() as usize;
459
460 ptr_addr >= base_addr && ptr_addr < base_addr + self.current_offset
461 }
462
463 pub fn get_allocation_info(&self, ptr: NonNull<u8>) -> Option<&AllocationRecord> {
465 if !self.config.enable_tracking {
466 return None;
467 }
468
469 self.allocations.iter().find(|record| record.ptr == ptr)
470 }
471
472 pub fn validate(&self) -> Result<(), ArenaError> {
474 if self.current_offset > self.total_size {
475 return Err(ArenaError::CorruptedArena(format!(
476 "Current offset {} exceeds total size {}",
477 self.current_offset, self.total_size
478 )));
479 }
480
481 if self.high_water_mark > self.total_size {
482 return Err(ArenaError::CorruptedArena(format!(
483 "High water mark {} exceeds total size {}",
484 self.high_water_mark, self.total_size
485 )));
486 }
487
488 if self.high_water_mark < self.current_offset {
489 return Err(ArenaError::CorruptedArena(format!(
490 "High water mark {} is less than current offset {}",
491 self.high_water_mark, self.current_offset
492 )));
493 }
494
495 if self.config.enable_tracking {
497 let mut total_tracked_size = 0;
498
499 for (i, record) in self.allocations.iter().enumerate() {
500 if !self.contains_pointer(record.ptr) {
502 return Err(ArenaError::CorruptedArena(format!(
503 "Allocation {} has pointer outside arena bounds",
504 i
505 )));
506 }
507
508 total_tracked_size += record.size;
509 }
510
511 if total_tracked_size > self.current_offset {
513 return Err(ArenaError::CorruptedArena(format!(
514 "Tracked size {} exceeds current offset {}",
515 total_tracked_size, self.current_offset
516 )));
517 }
518 }
519
520 Ok(())
521 }
522
523 pub fn get_memory_layout(&self) -> MemoryLayout {
525 let mut layout = MemoryLayout {
526 base_address: self.base_ptr.as_ptr() as usize,
527 total_size: self.total_size,
528 used_size: self.current_offset,
529 regions: Vec::new(),
530 };
531
532 if self.config.enable_tracking {
533 for record in &self.allocations {
534 layout.regions.push(MemoryRegion {
535 offset: record.offset,
536 size: record.size,
537 allocated_at: record.allocated_at,
538 tag: record.tag.clone(),
539 });
540 }
541 }
542
543 layout
544 }
545}
546
547unsafe impl Send for ArenaAllocator {}
553unsafe impl Sync for ArenaAllocator {}
554
555#[derive(Debug, Clone)]
557pub struct CheckpointHandle {
558 index: usize,
559 offset: usize,
560}
561
562#[derive(Debug, Clone)]
564pub struct ArenaUsage {
565 pub total_size: usize,
566 pub used_size: usize,
567 pub free_size: usize,
568 pub high_water_mark: usize,
569 pub allocation_count: usize,
570 pub checkpoint_count: usize,
571 pub utilization_ratio: f64,
572}
573
574#[derive(Debug, Clone)]
576pub struct MemoryLayout {
577 pub base_address: usize,
578 pub total_size: usize,
579 pub used_size: usize,
580 pub regions: Vec<MemoryRegion>,
581}
582
583#[derive(Debug, Clone)]
585pub struct MemoryRegion {
586 pub offset: usize,
587 pub size: usize,
588 pub allocated_at: Instant,
589 pub tag: Option<String>,
590}
591
592pub struct RingArena {
594 arena: ArenaAllocator,
595 read_offset: usize,
597 live_allocations: usize,
599 ring_config: RingConfig,
601}
602
603#[derive(Debug, Clone)]
605pub struct RingConfig {
606 pub overwrite_protection: bool,
608 pub overwrite_callback: Option<fn(*mut u8, usize)>,
610 pub enable_stats: bool,
612}
613
614impl Default for RingConfig {
615 fn default() -> Self {
616 Self {
617 overwrite_protection: true,
618 overwrite_callback: None,
619 enable_stats: true,
620 }
621 }
622}
623
624impl RingArena {
625 pub fn new(
626 base_ptr: NonNull<u8>,
627 size: usize,
628 ring_config: RingConfig,
629 ) -> Result<Self, ArenaError> {
630 let arena_config = ArenaConfig {
631 enable_tracking: ring_config.enable_stats,
632 enable_checkpoints: false,
633 ..ArenaConfig::default()
634 };
635
636 let arena = ArenaAllocator::new(base_ptr, size, arena_config)?;
637
638 Ok(Self {
639 arena,
640 read_offset: 0,
641 live_allocations: 0,
642 ring_config,
643 })
644 }
645
646 pub fn allocate(&mut self, size: usize) -> Result<NonNull<u8>, ArenaError> {
648 if self.ring_config.overwrite_protection {
650 let aligned_size = (size + self.arena.alignment - 1) & !(self.arena.alignment - 1);
651
652 if self.arena.current_offset + aligned_size > self.arena.total_size {
653 if self.read_offset > 0 && aligned_size > self.read_offset {
655 return Err(ArenaError::RingBufferFull(
656 "Ring buffer full, would overwrite live data".to_string(),
657 ));
658 }
659
660 self.arena.current_offset = 0;
662 } else if self.read_offset > self.arena.current_offset {
663 if self.arena.current_offset + aligned_size > self.read_offset {
665 return Err(ArenaError::RingBufferFull(
666 "Ring buffer full, would overwrite live data".to_string(),
667 ));
668 }
669 }
670 }
671
672 let ptr = self.arena.allocate(size)?;
673 self.live_allocations += 1;
674
675 Ok(ptr)
676 }
677
678 pub fn consume(&mut self, size: usize) -> Result<(), ArenaError> {
680 let aligned_size = (size + self.arena.alignment - 1) & !(self.arena.alignment - 1);
681
682 if self.read_offset + aligned_size > self.arena.total_size {
683 self.read_offset = aligned_size - (self.arena.total_size - self.read_offset);
685 } else {
686 self.read_offset += aligned_size;
687 }
688
689 self.live_allocations = self.live_allocations.saturating_sub(1);
690
691 Ok(())
692 }
693
694 pub fn reset(&mut self) {
696 self.arena.reset();
697 self.read_offset = 0;
698 self.live_allocations = 0;
699 }
700
701 pub fn get_ring_usage(&self) -> RingUsage {
703 let total_size = self.arena.total_size;
704 let write_offset = self.arena.current_offset;
705
706 let used_size = if write_offset >= self.read_offset {
707 write_offset - self.read_offset
708 } else {
709 total_size - self.read_offset + write_offset
710 };
711
712 RingUsage {
713 total_size,
714 used_size,
715 free_size: total_size - used_size,
716 read_offset: self.read_offset,
717 write_offset,
718 live_allocations: self.live_allocations,
719 }
720 }
721}
722
723#[derive(Debug, Clone)]
725pub struct RingUsage {
726 pub total_size: usize,
727 pub used_size: usize,
728 pub free_size: usize,
729 pub read_offset: usize,
730 pub write_offset: usize,
731 pub live_allocations: usize,
732}
733
734pub struct GrowingArena {
736 current_arena: ArenaAllocator,
738 previous_arenas: Vec<ArenaAllocator>,
740 growth_strategy: GrowthStrategy,
742 external_allocator: Option<Box<dyn ExternalAllocator>>,
744}
745
746pub trait ExternalAllocator {
748 fn allocate(&mut self, size: usize) -> Result<NonNull<u8>, ArenaError>;
749 fn deallocate(&mut self, ptr: NonNull<u8>, size: usize);
750}
751
752impl GrowingArena {
753 pub fn new(
754 base_ptr: NonNull<u8>,
755 initial_size: usize,
756 growth_strategy: GrowthStrategy,
757 ) -> Result<Self, ArenaError> {
758 let config = ArenaConfig::default();
759 let arena = ArenaAllocator::new(base_ptr, initial_size, config)?;
760
761 Ok(Self {
762 current_arena: arena,
763 previous_arenas: Vec::new(),
764 growth_strategy,
765 external_allocator: None,
766 })
767 }
768
769 pub fn with_external_allocator(mut self, allocator: Box<dyn ExternalAllocator>) -> Self {
770 self.external_allocator = Some(allocator);
771 self
772 }
773
774 pub fn allocate(&mut self, size: usize) -> Result<NonNull<u8>, ArenaError> {
776 match self.current_arena.allocate(size) {
778 Ok(ptr) => Ok(ptr),
779 Err(ArenaError::OutOfMemory(_)) => {
780 self.grow(size)?;
782 self.current_arena.allocate(size)
783 }
784 Err(e) => Err(e),
785 }
786 }
787
788 fn grow(&mut self, min_additional_size: usize) -> Result<(), ArenaError> {
789 if self.external_allocator.is_none() {
790 return Err(ArenaError::CannotGrow(
791 "No external allocator configured".to_string(),
792 ));
793 }
794
795 let current_size = self.current_arena.total_size;
796 let new_size = match &self.growth_strategy {
797 GrowthStrategy::Fixed => {
798 return Err(ArenaError::CannotGrow("Fixed size arena".to_string()))
799 }
800 GrowthStrategy::Double => current_size * 2,
801 GrowthStrategy::Linear(increment) => current_size + increment,
802 GrowthStrategy::Custom(func) => func(current_size),
803 };
804
805 let actual_new_size = new_size.max(min_additional_size);
806
807 let new_ptr = self
808 .external_allocator
809 .as_mut()
810 .expect("unwrap failed")
811 .allocate(actual_new_size)?;
812
813 let old_arena = std::mem::replace(
815 &mut self.current_arena,
816 ArenaAllocator::new(new_ptr, actual_new_size, ArenaConfig::default())?,
817 );
818
819 self.previous_arenas.push(old_arena);
820
821 Ok(())
822 }
823
824 pub fn contains_pointer(&self, ptr: NonNull<u8>) -> bool {
826 if self.current_arena.contains_pointer(ptr) {
827 return true;
828 }
829
830 self.previous_arenas
831 .iter()
832 .any(|arena| arena.contains_pointer(ptr))
833 }
834
835 pub fn get_total_usage(&self) -> GrowingArenaUsage {
837 let mut total_size = self.current_arena.total_size;
838 let mut used_size = self.current_arena.current_offset;
839 let mut allocation_count = self.current_arena.allocations.len();
840
841 for arena in &self.previous_arenas {
842 total_size += arena.total_size;
843 used_size += arena.current_offset;
844 allocation_count += arena.allocations.len();
845 }
846
847 GrowingArenaUsage {
848 total_size,
849 used_size,
850 free_size: total_size - used_size,
851 arena_count: 1 + self.previous_arenas.len(),
852 allocation_count,
853 current_arena_size: self.current_arena.total_size,
854 utilization_ratio: used_size as f64 / total_size as f64,
855 }
856 }
857}
858
859#[derive(Debug, Clone)]
861pub struct GrowingArenaUsage {
862 pub total_size: usize,
863 pub used_size: usize,
864 pub free_size: usize,
865 pub arena_count: usize,
866 pub allocation_count: usize,
867 pub current_arena_size: usize,
868 pub utilization_ratio: f64,
869}
870
871#[derive(Debug, Clone)]
873pub enum ArenaError {
874 InvalidSize(String),
875 InvalidAlignment(String),
876 OutOfMemory(String),
877 CheckpointsDisabled,
878 InvalidCheckpoint(String),
879 CorruptedArena(String),
880 RingBufferFull(String),
881 CannotGrow(String),
882}
883
884impl std::fmt::Display for ArenaError {
885 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
886 match self {
887 ArenaError::InvalidSize(msg) => write!(f, "Invalid size: {}", msg),
888 ArenaError::InvalidAlignment(msg) => write!(f, "Invalid alignment: {}", msg),
889 ArenaError::OutOfMemory(msg) => write!(f, "Out of memory: {}", msg),
890 ArenaError::CheckpointsDisabled => write!(f, "Checkpoints are disabled"),
891 ArenaError::InvalidCheckpoint(msg) => write!(f, "Invalid checkpoint: {}", msg),
892 ArenaError::CorruptedArena(msg) => write!(f, "Corrupted arena: {}", msg),
893 ArenaError::RingBufferFull(msg) => write!(f, "Ring buffer full: {}", msg),
894 ArenaError::CannotGrow(msg) => write!(f, "Cannot grow: {}", msg),
895 }
896 }
897}
898
899impl std::error::Error for ArenaError {}
900
901pub struct ThreadSafeArena {
903 arena: Arc<Mutex<ArenaAllocator>>,
904}
905
906impl ThreadSafeArena {
907 pub fn new(
908 base_ptr: NonNull<u8>,
909 size: usize,
910 config: ArenaConfig,
911 ) -> Result<Self, ArenaError> {
912 let arena = ArenaAllocator::new(base_ptr, size, config)?;
913 Ok(Self {
914 arena: Arc::new(Mutex::new(arena)),
915 })
916 }
917
918 pub fn allocate(&self, size: usize) -> Result<NonNull<u8>, ArenaError> {
919 let mut arena = self.arena.lock().expect("lock poisoned");
920 arena.allocate(size)
921 }
922
923 pub fn reset(&self) {
924 let mut arena = self.arena.lock().expect("lock poisoned");
925 arena.reset();
926 }
927
928 pub fn checkpoint(&self) -> Result<CheckpointHandle, ArenaError> {
929 let mut arena = self.arena.lock().expect("lock poisoned");
930 arena.checkpoint()
931 }
932
933 pub fn rollback(&self, handle: CheckpointHandle) -> Result<(), ArenaError> {
934 let mut arena = self.arena.lock().expect("lock poisoned");
935 arena.rollback(handle)
936 }
937
938 pub fn get_usage(&self) -> ArenaUsage {
939 let arena = self.arena.lock().expect("lock poisoned");
940 arena.get_usage()
941 }
942
943 pub fn get_stats(&self) -> ArenaStats {
944 let arena = self.arena.lock().expect("lock poisoned");
945 arena.get_stats().clone()
946 }
947}
948
949#[cfg(test)]
950mod tests {
951 use super::*;
952
953 #[test]
954 fn test_arena_creation() {
955 let size = 4096;
956 let memory = vec![0u8; size];
957 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
958
959 let config = ArenaConfig::default();
960 let arena = ArenaAllocator::new(ptr, size, config);
961 assert!(arena.is_ok());
962 }
963
964 #[test]
965 fn test_basic_allocation() {
966 let size = 4096;
967 let memory = vec![0u8; size];
968 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
969
970 let config = ArenaConfig::default();
971 let mut arena = ArenaAllocator::new(ptr, size, config).expect("unwrap failed");
972
973 let alloc1 = arena.allocate(100);
974 assert!(alloc1.is_ok());
975
976 let alloc2 = arena.allocate(200);
977 assert!(alloc2.is_ok());
978
979 let usage = arena.get_usage();
980 assert!(usage.used_size > 0);
981 assert!(usage.allocation_count == 2 || !arena.config.enable_tracking);
982 }
983
984 #[test]
985 fn test_alignment() {
986 let size = 4096;
987 let memory = vec![0u8; size];
988 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
989
990 let config = ArenaConfig {
991 alignment: 16,
992 ..ArenaConfig::default()
993 };
994 let mut arena = ArenaAllocator::new(ptr, size, config).expect("unwrap failed");
995
996 let alloc_ptr = arena.allocate(10).expect("unwrap failed");
997 assert_eq!(alloc_ptr.as_ptr() as usize % 16, 0);
998 }
999
1000 #[test]
1001 fn test_checkpoints() {
1002 let size = 4096;
1003 let memory = vec![0u8; size];
1004 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
1005
1006 let config = ArenaConfig {
1007 enable_checkpoints: true,
1008 enable_tracking: true,
1009 ..ArenaConfig::default()
1010 };
1011 let mut arena = ArenaAllocator::new(ptr, size, config).expect("unwrap failed");
1012
1013 arena.allocate(100).expect("unwrap failed");
1014 let checkpoint = arena.checkpoint().expect("unwrap failed");
1015 arena.allocate(200).expect("unwrap failed");
1016
1017 let usage_before = arena.get_usage();
1018 arena.rollback(checkpoint).expect("unwrap failed");
1019 let usage_after = arena.get_usage();
1020
1021 assert!(usage_after.used_size < usage_before.used_size);
1022 }
1023
1024 #[test]
1025 fn test_reset() {
1026 let size = 4096;
1027 let memory = vec![0u8; size];
1028 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
1029
1030 let config = ArenaConfig::default();
1031 let mut arena = ArenaAllocator::new(ptr, size, config).expect("unwrap failed");
1032
1033 arena.allocate(100).expect("unwrap failed");
1034 arena.allocate(200).expect("unwrap failed");
1035
1036 let usage_before = arena.get_usage();
1037 assert!(usage_before.used_size > 0);
1038
1039 arena.reset();
1040 let usage_after = arena.get_usage();
1041 assert_eq!(usage_after.used_size, 0);
1042 }
1043
1044 #[test]
1045 fn test_ring_arena() {
1046 let size = 1024;
1047 let memory = vec![0u8; size];
1048 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
1049
1050 let config = RingConfig::default();
1051 let mut ring = RingArena::new(ptr, size, config).expect("unwrap failed");
1052
1053 let alloc1 = ring.allocate(100);
1054 assert!(alloc1.is_ok());
1055
1056 ring.consume(100).expect("unwrap failed");
1057
1058 let alloc2 = ring.allocate(100);
1059 assert!(alloc2.is_ok());
1060 }
1061
1062 #[test]
1063 fn test_thread_safe_arena() {
1064 let size = 4096;
1065 let memory = vec![0u8; size];
1066 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
1067
1068 let config = ArenaConfig::default();
1069 let arena = ThreadSafeArena::new(ptr, size, config).expect("unwrap failed");
1070
1071 let alloc_result = arena.allocate(100);
1072 assert!(alloc_result.is_ok());
1073
1074 let usage = arena.get_usage();
1075 assert!(usage.used_size > 0);
1076 }
1077
1078 #[test]
1079 fn test_arena_validation() {
1080 let size = 4096;
1081 let memory = vec![0u8; size];
1082 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
1083
1084 let config = ArenaConfig {
1085 enable_tracking: true,
1086 ..ArenaConfig::default()
1087 };
1088 let mut arena = ArenaAllocator::new(ptr, size, config).expect("unwrap failed");
1089
1090 arena.allocate(100).expect("unwrap failed");
1091 arena.allocate(200).expect("unwrap failed");
1092
1093 let validation_result = arena.validate();
1094 assert!(validation_result.is_ok());
1095 }
1096}