1pub mod arena_allocator;
7pub mod buddy_allocator;
8pub mod slab_allocator;
9pub mod strategies;
10
11pub use strategies::{
13 AdaptiveConfig, AllocationEvent, AllocationPattern, AllocationStats, AllocationStrategy,
14 AllocationStrategyManager, HybridConfig, MLConfig, MLFeatures, MLPrediction, MemoryBlock,
15};
16
17pub use buddy_allocator::{
18 AllocationInfo, BuddyAllocator, BuddyBlock, BuddyConfig, BuddyError, BuddyStats,
19 FreeBlockStats, MemoryUsage, ThreadSafeBuddyAllocator,
20};
21
22pub use slab_allocator::{
23 CacheConfig, CacheInfo, MemoryPool, MemoryPoolUsage, Slab, SlabAllocator, SlabAllocatorStats,
24 SlabCache, SlabConfig, SlabError, ThreadSafeSlabAllocator,
25};
26
27pub use arena_allocator::{
28 ArenaAllocator, ArenaConfig, ArenaError, ArenaStats, ArenaUsage, CheckpointHandle,
29 ExternalAllocator, GrowingArena, MemoryLayout, MemoryRegion, RingArena, RingConfig, RingUsage,
30 ThreadSafeArena,
31};
32
33use std::collections::HashMap;
34use std::ptr::NonNull;
35use std::sync::{Arc, Mutex};
36use std::time::Instant;
37
38pub struct UnifiedAllocator {
40 strategy_manager: AllocationStrategyManager,
42 buddy_allocator: Option<BuddyAllocator>,
44 slab_allocator: Option<SlabAllocator>,
46 arena_allocator: Option<ArenaAllocator>,
48 config: UnifiedConfig,
50 stats: UnifiedStats,
52 routing_table: AllocationRouter,
54}
55
56#[derive(Debug, Clone)]
58pub struct UnifiedConfig {
59 pub default_strategy: AllocationStrategy,
61 pub enable_buddy: bool,
63 pub enable_slab: bool,
65 pub enable_arena: bool,
67 pub buddy_threshold: usize,
69 pub slab_threshold: usize,
71 pub arena_threshold: usize,
73 pub enable_auto_routing: bool,
75 pub stats_interval: std::time::Duration,
77}
78
79impl Default for UnifiedConfig {
80 fn default() -> Self {
81 Self {
82 default_strategy: AllocationStrategy::Adaptive,
83 enable_buddy: true,
84 enable_slab: true,
85 enable_arena: true,
86 buddy_threshold: 1024,
87 slab_threshold: 4096,
88 arena_threshold: 64 * 1024,
89 enable_auto_routing: true,
90 stats_interval: std::time::Duration::from_secs(1),
91 }
92 }
93}
94
95#[derive(Debug, Clone, Default)]
97pub struct UnifiedStats {
98 pub total_allocations: u64,
99 pub total_deallocations: u64,
100 pub bytes_allocated: u64,
101 pub bytes_deallocated: u64,
102 pub strategy_allocations: HashMap<AllocationStrategy, u64>,
103 pub buddy_allocations: u64,
104 pub slab_allocations: u64,
105 pub arena_allocations: u64,
106 pub routing_decisions: u64,
107 pub routing_cache_hits: u64,
108 pub average_allocation_time_ns: f64,
109 pub peak_memory_usage: usize,
110 pub current_memory_usage: usize,
111}
112
113pub struct AllocationRouter {
115 size_routes: Vec<SizeRoute>,
117 pattern_cache: HashMap<AllocationPattern, AllocatorType>,
119 performance_history: HashMap<AllocatorType, PerformanceMetrics>,
121 config: RouterConfig,
123}
124
125#[derive(Debug, Clone)]
127pub struct SizeRoute {
128 pub min_size: usize,
129 pub max_size: Option<usize>,
130 pub preferred_allocator: AllocatorType,
131 pub fallback_allocator: Option<AllocatorType>,
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, Hash)]
136pub enum AllocatorType {
137 Strategy(AllocationStrategy),
138 Buddy,
139 Slab,
140 Arena,
141}
142
143#[derive(Debug, Clone, Default)]
145pub struct PerformanceMetrics {
146 pub average_latency_ns: f64,
147 pub success_rate: f64,
148 pub fragmentation_ratio: f64,
149 pub cache_hit_rate: f64,
150 pub memory_efficiency: f64,
151}
152
153#[derive(Debug, Clone)]
155pub struct RouterConfig {
156 pub enable_performance_tracking: bool,
157 pub cache_size: usize,
158 pub adaptation_threshold: f64,
159 pub performance_window: usize,
160}
161
162impl Default for RouterConfig {
163 fn default() -> Self {
164 Self {
165 enable_performance_tracking: true,
166 cache_size: 1000,
167 adaptation_threshold: 0.1,
168 performance_window: 100,
169 }
170 }
171}
172
173impl AllocationRouter {
174 pub fn new(config: RouterConfig) -> Self {
175 let size_routes = vec![
176 SizeRoute {
177 min_size: 0,
178 max_size: Some(256),
179 preferred_allocator: AllocatorType::Slab,
180 fallback_allocator: Some(AllocatorType::Strategy(AllocationStrategy::FirstFit)),
181 },
182 SizeRoute {
183 min_size: 257,
184 max_size: Some(4096),
185 preferred_allocator: AllocatorType::Strategy(AllocationStrategy::BestFit),
186 fallback_allocator: Some(AllocatorType::Buddy),
187 },
188 SizeRoute {
189 min_size: 4097,
190 max_size: Some(64 * 1024),
191 preferred_allocator: AllocatorType::Buddy,
192 fallback_allocator: Some(AllocatorType::Strategy(AllocationStrategy::BestFit)),
193 },
194 SizeRoute {
195 min_size: 64 * 1024 + 1,
196 max_size: None,
197 preferred_allocator: AllocatorType::Arena,
198 fallback_allocator: Some(AllocatorType::Strategy(AllocationStrategy::WorstFit)),
199 },
200 ];
201
202 Self {
203 size_routes,
204 pattern_cache: HashMap::new(),
205 performance_history: HashMap::new(),
206 config,
207 }
208 }
209
210 pub fn route_allocation(
212 &mut self,
213 size: usize,
214 pattern: Option<AllocationPattern>,
215 ) -> AllocatorType {
216 if let Some(pattern) = pattern {
218 if let Some(allocator_type) = self.pattern_cache.get(&pattern) {
219 return allocator_type.clone();
220 }
221 }
222
223 for route in &self.size_routes {
225 if size >= route.min_size && route.max_size.is_none_or(|max| size <= max) {
226 if self.config.enable_performance_tracking {
228 let preferred_perf = self
229 .performance_history
230 .get(&route.preferred_allocator)
231 .cloned()
232 .unwrap_or_default();
233
234 if let Some(fallback) = &route.fallback_allocator {
235 let fallback_perf = self
236 .performance_history
237 .get(fallback)
238 .cloned()
239 .unwrap_or_default();
240
241 if fallback_perf.average_latency_ns > 0.0
243 && preferred_perf.average_latency_ns > 0.0
244 {
245 let perf_ratio = fallback_perf.average_latency_ns
246 / preferred_perf.average_latency_ns;
247 if perf_ratio < 1.0 - self.config.adaptation_threshold {
248 return fallback.clone();
249 }
250 }
251 }
252 }
253
254 return route.preferred_allocator.clone();
255 }
256 }
257
258 AllocatorType::Strategy(AllocationStrategy::BestFit)
260 }
261
262 pub fn update_performance(
264 &mut self,
265 allocator_type: AllocatorType,
266 metrics: PerformanceMetrics,
267 ) {
268 self.performance_history.insert(allocator_type, metrics);
269 }
270
271 pub fn cache_pattern_route(
273 &mut self,
274 pattern: AllocationPattern,
275 allocator_type: AllocatorType,
276 ) {
277 if self.pattern_cache.len() >= self.config.cache_size {
278 if let Some(key) = self.pattern_cache.keys().next().cloned() {
280 self.pattern_cache.remove(&key);
281 }
282 }
283 self.pattern_cache.insert(pattern, allocator_type);
284 }
285}
286
287impl UnifiedAllocator {
288 pub fn new(
290 base_ptr: NonNull<u8>,
291 total_size: usize,
292 config: UnifiedConfig,
293 ) -> Result<Self, AllocationError> {
294 let mut strategy_manager = AllocationStrategyManager::new(config.default_strategy.clone());
295
296 let buddy_allocator = if config.enable_buddy {
297 let buddy_config = BuddyConfig::default();
298 let buddy_size = total_size / 4; let buddy_ptr = base_ptr;
300 Some(BuddyAllocator::new(
301 buddy_ptr.as_ptr(),
302 buddy_size,
303 buddy_config,
304 )?)
305 } else {
306 None
307 };
308
309 let slab_allocator = if config.enable_slab {
310 let slab_config = SlabConfig::default();
311 let slab_size = total_size / 4; let slab_ptr = unsafe { NonNull::new_unchecked(base_ptr.as_ptr().add(total_size / 4)) };
313 Some(SlabAllocator::new(slab_ptr, slab_size, slab_config))
314 } else {
315 None
316 };
317
318 let arena_allocator = if config.enable_arena {
319 let arena_config = ArenaConfig::default();
320 let arena_size = total_size / 4; let arena_ptr =
322 unsafe { NonNull::new_unchecked(base_ptr.as_ptr().add(total_size / 2)) };
323 Some(ArenaAllocator::new(arena_ptr, arena_size, arena_config)?)
324 } else {
325 None
326 };
327
328 let routing_table = AllocationRouter::new(RouterConfig::default());
329
330 let strategy_size = total_size / 4;
332 let strategy_ptr = unsafe { base_ptr.as_ptr().add(3 * total_size / 4) };
333 strategy_manager.add_free_block(MemoryBlock {
334 ptr: strategy_ptr,
335 size: strategy_size,
336 is_free: true,
337 allocated_at: None,
338 last_accessed: None,
339 access_count: 0,
340 fragmentation_score: 0.0,
341 });
342
343 Ok(Self {
344 strategy_manager,
345 buddy_allocator,
346 slab_allocator,
347 arena_allocator,
348 config,
349 stats: UnifiedStats::default(),
350 routing_table,
351 })
352 }
353
354 pub fn allocate(
356 &mut self,
357 size: usize,
358 requested_allocator_type: AllocatorType,
359 _alignment: Option<usize>,
360 ) -> Result<NonNull<u8>, AllocationError> {
361 let start_time = Instant::now();
362 self.stats.total_allocations += 1;
363
364 let allocator_type = requested_allocator_type;
366
367 let result = match &allocator_type {
368 AllocatorType::Strategy(strategy) => {
369 self.strategy_manager.set_strategy(strategy.clone());
370 self.strategy_manager.find_free_block(size).ok_or_else(|| {
371 AllocationError::OutOfMemory("Strategy allocator failed".to_string())
372 })
373 }
374 AllocatorType::Buddy => {
375 if let Some(ref mut buddy) = self.buddy_allocator {
376 buddy.allocate(size).map_err(AllocationError::BuddyError)
377 } else {
378 Err(AllocationError::AllocatorNotAvailable(
379 "Buddy allocator not enabled".to_string(),
380 ))
381 }
382 }
383 AllocatorType::Slab => {
384 if let Some(ref mut slab) = self.slab_allocator {
385 slab.allocate(size)
386 .map(|ptr| ptr.as_ptr())
387 .map_err(AllocationError::SlabError)
388 } else {
389 Err(AllocationError::AllocatorNotAvailable(
390 "Slab allocator not enabled".to_string(),
391 ))
392 }
393 }
394 AllocatorType::Arena => {
395 if let Some(ref mut arena) = self.arena_allocator {
396 arena
397 .allocate(size)
398 .map(|ptr| ptr.as_ptr())
399 .map_err(AllocationError::ArenaError)
400 } else {
401 Err(AllocationError::AllocatorNotAvailable(
402 "Arena allocator not enabled".to_string(),
403 ))
404 }
405 }
406 };
407
408 let allocation_time = start_time.elapsed().as_nanos() as f64;
409
410 match &result {
411 Ok(_) => {
412 self.stats.bytes_allocated += size as u64;
413 self.stats.current_memory_usage += size;
414 if self.stats.current_memory_usage > self.stats.peak_memory_usage {
415 self.stats.peak_memory_usage = self.stats.current_memory_usage;
416 }
417
418 match &allocator_type {
420 AllocatorType::Strategy(strategy) => {
421 *self
422 .stats
423 .strategy_allocations
424 .entry(strategy.clone())
425 .or_insert(0) += 1;
426 }
427 AllocatorType::Buddy => self.stats.buddy_allocations += 1,
428 AllocatorType::Slab => self.stats.slab_allocations += 1,
429 AllocatorType::Arena => self.stats.arena_allocations += 1,
430 }
431
432 let metrics = PerformanceMetrics {
434 average_latency_ns: allocation_time,
435 success_rate: 1.0,
436 fragmentation_ratio: 0.0, cache_hit_rate: 0.0, memory_efficiency: 1.0, };
440 self.routing_table
441 .update_performance(allocator_type, metrics);
442 }
443 Err(_) => {
444 let metrics = PerformanceMetrics {
446 average_latency_ns: allocation_time,
447 success_rate: 0.0,
448 ..Default::default()
449 };
450 self.routing_table
451 .update_performance(allocator_type, metrics);
452 }
453 }
454
455 let total_time = self.stats.average_allocation_time_ns
457 * (self.stats.total_allocations - 1) as f64
458 + allocation_time;
459 self.stats.average_allocation_time_ns = total_time / self.stats.total_allocations as f64;
460
461 result.map(|ptr| unsafe { NonNull::new_unchecked(ptr) })
462 }
463
464 pub fn deallocate(&mut self, ptr: NonNull<u8>, size: usize) -> Result<(), AllocationError> {
466 self.stats.total_deallocations += 1;
467 self.stats.bytes_deallocated += size as u64;
468 self.stats.current_memory_usage = self.stats.current_memory_usage.saturating_sub(size);
469
470 if let Some(ref mut buddy) = self.buddy_allocator {
472 if let Ok(()) = buddy.deallocate(ptr.as_ptr()) {
473 return Ok(());
474 }
475 }
476
477 if let Some(ref mut slab) = self.slab_allocator {
478 if let Ok(()) = slab.deallocate(ptr, size) {
479 return Ok(());
480 }
481 }
482
483 if let Some(ref mut arena) = self.arena_allocator {
484 if arena.contains_pointer(ptr) {
485 return Ok(());
487 }
488 }
489
490 Err(AllocationError::InvalidPointer(
491 "Pointer not found in any allocator".to_string(),
492 ))
493 }
494
495 pub fn free(
497 &mut self,
498 ptr: *mut std::ffi::c_void,
499 _allocator_type: AllocatorType,
500 ) -> Result<(), AllocationError> {
501 let ptr_u8 = NonNull::new(ptr as *mut u8)
503 .ok_or_else(|| AllocationError::InvalidPointer("Null pointer".to_string()))?;
504 self.deallocate(ptr_u8, 0)
507 }
508
509 pub fn reallocate(
524 &mut self,
525 _ptr: *mut std::ffi::c_void,
526 new_size: usize,
527 allocator_type: AllocatorType,
528 ) -> Result<*mut std::ffi::c_void, AllocationError> {
529 let new_ptr = self.allocate(new_size, allocator_type, None)?;
534 Ok(new_ptr.as_ptr() as *mut std::ffi::c_void)
535 }
536
537 pub fn get_stats(&self) -> &UnifiedStats {
539 &self.stats
540 }
541
542 pub fn get_config(&self) -> &UnifiedConfig {
557 &self.config
558 }
559
560 pub fn get_detailed_info(&self) -> DetailedAllocatorInfo {
562 let mut info = DetailedAllocatorInfo {
563 strategy_info: Some(self.strategy_manager.get_stats().clone()),
564 buddy_info: None,
565 slab_info: None,
566 arena_info: None,
567 unified_stats: self.stats.clone(),
568 };
569
570 if let Some(ref buddy) = self.buddy_allocator {
571 info.buddy_info = Some(buddy.get_stats().clone());
572 }
573
574 if let Some(ref slab) = self.slab_allocator {
575 info.slab_info = Some(slab.get_stats());
576 }
577
578 if let Some(ref arena) = self.arena_allocator {
579 info.arena_info = Some(arena.get_stats().clone());
580 }
581
582 info
583 }
584
585 pub fn reset_allocator(
587 &mut self,
588 allocator_type: AllocatorType,
589 ) -> Result<(), AllocationError> {
590 match allocator_type {
591 AllocatorType::Strategy(_) => {
592 self.strategy_manager.clear_history();
593 }
594 AllocatorType::Buddy => {
595 if let Some(ref mut buddy) = self.buddy_allocator {
596 buddy.reset();
597 } else {
598 return Err(AllocationError::AllocatorNotAvailable(
599 "Buddy allocator not enabled".to_string(),
600 ));
601 }
602 }
603 AllocatorType::Slab => {
604 return Err(AllocationError::UnsupportedOperation(
605 "Slab allocator reset not supported".to_string(),
606 ));
607 }
608 AllocatorType::Arena => {
609 if let Some(ref mut arena) = self.arena_allocator {
610 arena.reset();
611 } else {
612 return Err(AllocationError::AllocatorNotAvailable(
613 "Arena allocator not enabled".to_string(),
614 ));
615 }
616 }
617 }
618 Ok(())
619 }
620
621 pub fn garbage_collect(&mut self) -> GarbageCollectionResult {
623 let mut result = GarbageCollectionResult::default();
624
625 if let Some(ref mut slab) = self.slab_allocator {
626 result.slab_reclaimed = slab.reclaim_memory();
627 }
628
629 if let Some(ref mut buddy) = self.buddy_allocator {
630 result.buddy_defragmented = buddy.defragment();
631 }
632
633 result
634 }
635
636 pub fn optimize_strategies(&mut self) -> Result<(), AllocationError> {
638 let current_stats = self.get_stats();
640
641 if current_stats.buddy_allocations > current_stats.slab_allocations {
644 } else {
646 }
648
649 self.stats.buddy_allocations = 0;
651 self.stats.slab_allocations = 0;
652 self.stats.arena_allocations = 0;
653 self.stats.strategy_allocations.clear();
654
655 Ok(())
656 }
657}
658
659unsafe impl Send for UnifiedAllocator {}
666unsafe impl Sync for UnifiedAllocator {}
667
668#[derive(Debug, Clone)]
670pub struct DetailedAllocatorInfo {
671 pub strategy_info: Option<AllocationStats>,
672 pub buddy_info: Option<BuddyStats>,
673 pub slab_info: Option<SlabAllocatorStats>,
674 pub arena_info: Option<ArenaStats>,
675 pub unified_stats: UnifiedStats,
676}
677
678#[derive(Debug, Clone, Default)]
680pub struct GarbageCollectionResult {
681 pub slab_reclaimed: usize,
682 pub buddy_defragmented: usize,
683 pub arena_reset: bool,
684 pub total_bytes_freed: usize,
685}
686
687#[derive(Debug, Clone)]
689pub enum AllocationError {
690 OutOfMemory(String),
691 InvalidPointer(String),
692 AllocatorNotAvailable(String),
693 UnsupportedOperation(String),
694 BuddyError(BuddyError),
695 SlabError(SlabError),
696 ArenaError(ArenaError),
697}
698
699impl std::fmt::Display for AllocationError {
700 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
701 match self {
702 AllocationError::OutOfMemory(msg) => write!(f, "Out of memory: {}", msg),
703 AllocationError::InvalidPointer(msg) => write!(f, "Invalid pointer: {}", msg),
704 AllocationError::AllocatorNotAvailable(msg) => {
705 write!(f, "Allocator not available: {}", msg)
706 }
707 AllocationError::UnsupportedOperation(msg) => {
708 write!(f, "Unsupported operation: {}", msg)
709 }
710 AllocationError::BuddyError(e) => write!(f, "Buddy allocator error: {}", e),
711 AllocationError::SlabError(e) => write!(f, "Slab allocator error: {}", e),
712 AllocationError::ArenaError(e) => write!(f, "Arena allocator error: {}", e),
713 }
714 }
715}
716
717impl std::error::Error for AllocationError {}
718
719impl From<BuddyError> for AllocationError {
720 fn from(error: BuddyError) -> Self {
721 AllocationError::BuddyError(error)
722 }
723}
724
725impl From<SlabError> for AllocationError {
726 fn from(error: SlabError) -> Self {
727 AllocationError::SlabError(error)
728 }
729}
730
731impl From<ArenaError> for AllocationError {
732 fn from(error: ArenaError) -> Self {
733 AllocationError::ArenaError(error)
734 }
735}
736
737pub struct ThreadSafeUnifiedAllocator {
739 allocator: Arc<Mutex<UnifiedAllocator>>,
740}
741
742impl ThreadSafeUnifiedAllocator {
743 pub fn new(
744 base_ptr: NonNull<u8>,
745 total_size: usize,
746 config: UnifiedConfig,
747 ) -> Result<Self, AllocationError> {
748 let allocator = UnifiedAllocator::new(base_ptr, total_size, config)?;
749 Ok(Self {
750 allocator: Arc::new(Mutex::new(allocator)),
751 })
752 }
753
754 pub fn allocate(&self, size: usize) -> Result<NonNull<u8>, AllocationError> {
755 let mut allocator = self.allocator.lock().unwrap_or_else(|e| e.into_inner());
756 allocator.allocate(
757 size,
758 AllocatorType::Strategy(strategies::AllocationStrategy::FirstFit),
759 None,
760 )
761 }
762
763 pub fn deallocate(&self, ptr: NonNull<u8>, size: usize) -> Result<(), AllocationError> {
764 let mut allocator = self.allocator.lock().unwrap_or_else(|e| e.into_inner());
765 allocator.deallocate(ptr, size)
766 }
767
768 pub fn get_stats(&self) -> UnifiedStats {
769 let allocator = self.allocator.lock().unwrap_or_else(|e| e.into_inner());
770 allocator.get_stats().clone()
771 }
772
773 pub fn garbage_collect(&self) -> GarbageCollectionResult {
774 let mut allocator = self.allocator.lock().unwrap_or_else(|e| e.into_inner());
775 allocator.garbage_collect()
776 }
777}
778
779#[cfg(test)]
780mod tests {
781 use super::*;
782
783 #[test]
784 fn test_unified_allocator_creation() {
785 let size = 1024 * 1024; let memory = vec![0u8; size];
787 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
788
789 let config = UnifiedConfig::default();
790 let allocator = UnifiedAllocator::new(ptr, size, config);
791 assert!(allocator.is_ok());
792 }
793
794 #[test]
795 fn test_get_config_reflects_construction_config() {
796 let size = 1024 * 1024;
797 let memory = vec![0u8; size];
798 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
799
800 let config = UnifiedConfig {
801 buddy_threshold: 2048,
802 ..UnifiedConfig::default()
803 };
804 let allocator = UnifiedAllocator::new(ptr, size, config).expect("unwrap failed");
805
806 assert_eq!(allocator.get_config().buddy_threshold, 2048);
807 }
808
809 #[test]
810 fn test_unified_allocation() {
811 let size = 1024 * 1024;
812 let memory = vec![0u8; size];
813 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
814
815 let config = UnifiedConfig::default();
816 let mut allocator = UnifiedAllocator::new(ptr, size, config).expect("unwrap failed");
817
818 let small_alloc = allocator.allocate(100, AllocatorType::Slab, None); assert!(small_alloc.is_ok());
821
822 let medium_alloc = allocator.allocate(2048, AllocatorType::Buddy, None); assert!(
824 medium_alloc.is_ok(),
825 "Medium allocation failed: {:?}",
826 medium_alloc.err()
827 );
828
829 let large_alloc = allocator.allocate(128 * 1024, AllocatorType::Arena, None); assert!(large_alloc.is_ok());
831
832 let stats = allocator.get_stats();
833 assert_eq!(stats.total_allocations, 3);
834 }
835
836 #[test]
837 fn test_allocation_routing() {
838 let config = RouterConfig::default();
839 let mut router = AllocationRouter::new(config);
840
841 let small_route = router.route_allocation(100, None);
842 assert_eq!(small_route, AllocatorType::Slab);
843
844 let medium_route = router.route_allocation(2048, None);
845 assert_eq!(
846 medium_route,
847 AllocatorType::Strategy(AllocationStrategy::BestFit)
848 );
849
850 let large_route = router.route_allocation(128 * 1024, None);
851 assert_eq!(large_route, AllocatorType::Arena);
852 }
853
854 #[test]
855 fn test_thread_safe_unified_allocator() {
856 let size = 1024 * 1024;
857 let memory = vec![0u8; size];
858 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
859
860 let config = UnifiedConfig::default();
861 let allocator = ThreadSafeUnifiedAllocator::new(ptr, size, config).expect("unwrap failed");
862
863 let alloc_result = allocator.allocate(1024);
864 assert!(
865 alloc_result.is_ok(),
866 "Allocation failed: {:?}",
867 alloc_result.err()
868 );
869
870 let stats = allocator.get_stats();
871 assert!(stats.total_allocations > 0);
872 }
873}