1use std::collections::{HashMap, VecDeque};
8use std::ptr::NonNull;
9use std::sync::{Arc, Mutex};
10use std::time::Instant;
11
12pub struct SlabAllocator {
14 caches: HashMap<usize, SlabCache>,
16 config: SlabConfig,
18 memory_pool: MemoryPool,
20}
21
22pub struct SlabCache {
24 object_size: usize,
26 slabs: Vec<Slab>,
28 partial_slabs: VecDeque<usize>,
30 full_slabs: Vec<usize>,
32 empty_slabs: VecDeque<usize>,
34 stats: CacheStats,
36 config: CacheConfig,
38}
39
40pub struct Slab {
42 base_ptr: NonNull<u8>,
44 slab_size: usize,
46 object_size: usize,
48 object_count: usize,
50 free_objects: VecDeque<usize>,
52 allocated_count: usize,
54 allocation_bitmap: Vec<u64>,
56 created_at: Instant,
58 last_alloc: Option<Instant>,
60 last_dealloc: Option<Instant>,
62 access_count: u64,
64}
65
66impl Slab {
67 pub fn new(base_ptr: NonNull<u8>, slab_size: usize, object_size: usize) -> Self {
68 let object_count = slab_size / object_size;
69 let bitmap_size = object_count.div_ceil(64); let mut free_objects = VecDeque::with_capacity(object_count);
72 for i in 0..object_count {
73 free_objects.push_back(i);
74 }
75
76 Self {
77 base_ptr,
78 slab_size,
79 object_size,
80 object_count,
81 free_objects,
82 allocated_count: 0,
83 allocation_bitmap: vec![0; bitmap_size],
84 created_at: Instant::now(),
85 last_alloc: None,
86 last_dealloc: None,
87 access_count: 0,
88 }
89 }
90
91 pub fn allocate(&mut self) -> Option<NonNull<u8>> {
93 if let Some(object_index) = self.free_objects.pop_front() {
94 let word_index = object_index / 64;
96 let bit_index = object_index % 64;
97 self.allocation_bitmap[word_index] |= 1u64 << bit_index;
98
99 self.allocated_count += 1;
100 self.last_alloc = Some(Instant::now());
101 self.access_count += 1;
102
103 let object_offset = object_index * self.object_size;
105 let object_ptr =
106 unsafe { NonNull::new_unchecked(self.base_ptr.as_ptr().add(object_offset)) };
107
108 Some(object_ptr)
109 } else {
110 None
111 }
112 }
113
114 pub fn deallocate(&mut self, ptr: NonNull<u8>) -> Result<(), SlabError> {
116 let ptr_addr = ptr.as_ptr() as usize;
118 let base_addr = self.base_ptr.as_ptr() as usize;
119
120 if ptr_addr < base_addr || ptr_addr >= base_addr + self.slab_size {
121 return Err(SlabError::InvalidPointer(
122 "Pointer not in this slab".to_string(),
123 ));
124 }
125
126 let offset = ptr_addr - base_addr;
127 if !offset.is_multiple_of(self.object_size) {
128 return Err(SlabError::InvalidPointer(
129 "Pointer not aligned to object boundary".to_string(),
130 ));
131 }
132
133 let object_index = offset / self.object_size;
134 if object_index >= self.object_count {
135 return Err(SlabError::InvalidPointer(
136 "Object index out of bounds".to_string(),
137 ));
138 }
139
140 let word_index = object_index / 64;
142 let bit_index = object_index % 64;
143 if (self.allocation_bitmap[word_index] & (1u64 << bit_index)) == 0 {
144 return Err(SlabError::DoubleFree("Object already free".to_string()));
145 }
146
147 self.allocation_bitmap[word_index] &= !(1u64 << bit_index);
149 self.free_objects.push_back(object_index);
150 self.allocated_count -= 1;
151 self.last_dealloc = Some(Instant::now());
152
153 Ok(())
154 }
155
156 pub fn is_full(&self) -> bool {
158 self.allocated_count == self.object_count
159 }
160
161 pub fn is_empty(&self) -> bool {
163 self.allocated_count == 0
164 }
165
166 pub fn is_partial(&self) -> bool {
168 self.allocated_count > 0 && self.allocated_count < self.object_count
169 }
170
171 pub fn get_utilization(&self) -> f64 {
173 self.allocated_count as f64 / self.object_count as f64
174 }
175
176 pub fn get_stats(&self) -> SlabStats {
178 SlabStats {
179 total_objects: self.object_count,
180 allocated_objects: self.allocated_count,
181 free_objects: self.object_count - self.allocated_count,
182 utilization: self.get_utilization(),
183 access_count: self.access_count,
184 age: self.created_at.elapsed(),
185 }
186 }
187}
188
189pub struct MemoryPool {
191 base_ptr: NonNull<u8>,
193 total_size: usize,
195 current_offset: usize,
197 free_regions: VecDeque<FreeRegion>,
199 alignment: usize,
201}
202
203#[derive(Debug, Clone)]
205pub struct FreeRegion {
206 pub offset: usize,
207 pub size: usize,
208 pub freed_at: Instant,
209}
210
211impl MemoryPool {
212 pub fn new(base_ptr: NonNull<u8>, total_size: usize, alignment: usize) -> Self {
213 Self {
214 base_ptr,
215 total_size,
216 current_offset: 0,
217 free_regions: VecDeque::new(),
218 alignment,
219 }
220 }
221
222 pub fn allocate_slab(&mut self, size: usize) -> Option<NonNull<u8>> {
224 let aligned_size = (size + self.alignment - 1) & !(self.alignment - 1);
225
226 if let Some(region_index) = self.find_suitable_free_region(aligned_size) {
228 let region = self.free_regions.remove(region_index)?;
233 let ptr = unsafe { NonNull::new_unchecked(self.base_ptr.as_ptr().add(region.offset)) };
234
235 if region.size > aligned_size {
237 let remaining_region = FreeRegion {
238 offset: region.offset + aligned_size,
239 size: region.size - aligned_size,
240 freed_at: region.freed_at,
241 };
242 self.free_regions.push_back(remaining_region);
243 }
244
245 return Some(ptr);
246 }
247
248 if self.current_offset + aligned_size <= self.total_size {
250 let ptr =
251 unsafe { NonNull::new_unchecked(self.base_ptr.as_ptr().add(self.current_offset)) };
252 self.current_offset += aligned_size;
253 Some(ptr)
254 } else {
255 None
256 }
257 }
258
259 pub fn free_slab(&mut self, ptr: NonNull<u8>, size: usize) {
261 let base_addr = self.base_ptr.as_ptr() as usize;
262 let ptr_addr = ptr.as_ptr() as usize;
263
264 if ptr_addr >= base_addr && ptr_addr < base_addr + self.total_size {
265 let offset = ptr_addr - base_addr;
266 let region = FreeRegion {
267 offset,
268 size,
269 freed_at: Instant::now(),
270 };
271
272 let insert_pos = self
274 .free_regions
275 .binary_search_by_key(&offset, |r| r.offset)
276 .unwrap_or_else(|pos| pos);
277
278 self.free_regions.insert(insert_pos, region);
279
280 self.coalesce_free_regions();
282 }
283 }
284
285 fn find_suitable_free_region(&self, size: usize) -> Option<usize> {
286 self.free_regions
287 .iter()
288 .position(|region| region.size >= size)
289 }
290
291 fn coalesce_free_regions(&mut self) {
292 let mut i = 0;
293 while i < self.free_regions.len().saturating_sub(1) {
294 let current_end = self.free_regions[i].offset + self.free_regions[i].size;
295 if current_end == self.free_regions[i + 1].offset {
296 let Some(next_region) = self.free_regions.remove(i + 1) else {
302 break;
303 };
304 self.free_regions[i].size += next_region.size;
305 } else {
306 i += 1;
307 }
308 }
309 }
310
311 pub fn get_usage(&self) -> MemoryPoolUsage {
312 let free_size = self.free_regions.iter().map(|r| r.size).sum::<usize>();
313 let allocated_size = self.current_offset - free_size;
314
315 MemoryPoolUsage {
316 total_size: self.total_size,
317 allocated_size,
318 free_size,
319 current_offset: self.current_offset,
320 free_regions: self.free_regions.len(),
321 }
322 }
323}
324
325#[derive(Debug, Clone)]
327pub struct CacheConfig {
328 pub objects_per_slab: usize,
330 pub max_empty_slabs: usize,
332 pub enable_coloring: bool,
334 pub color_offset: usize,
336 pub enable_ctor_dtor: bool,
338 pub constructor: Option<fn(*mut u8)>,
340 pub destructor: Option<fn(*mut u8)>,
342}
343
344impl Default for CacheConfig {
345 fn default() -> Self {
346 Self {
347 objects_per_slab: 64,
348 max_empty_slabs: 3,
349 enable_coloring: true,
350 color_offset: 0,
351 enable_ctor_dtor: false,
352 constructor: None,
353 destructor: None,
354 }
355 }
356}
357
358#[derive(Debug, Clone)]
360pub struct SlabConfig {
361 pub default_slab_size: usize,
363 pub alignment: usize,
365 pub enable_stats: bool,
367 pub enable_debug: bool,
369 pub reclaim_threshold: f64,
371 pub auto_reclaim: bool,
373}
374
375impl Default for SlabConfig {
376 fn default() -> Self {
377 Self {
378 default_slab_size: 4096, alignment: 256,
380 enable_stats: true,
381 enable_debug: false,
382 reclaim_threshold: 0.8,
383 auto_reclaim: true,
384 }
385 }
386}
387
388#[derive(Debug, Clone, Default)]
390pub struct CacheStats {
391 pub total_allocations: u64,
392 pub total_deallocations: u64,
393 pub cache_hits: u64,
394 pub cache_misses: u64,
395 pub slab_allocations: u64,
396 pub slab_deallocations: u64,
397 pub objects_allocated: u64,
398 pub objects_free: u64,
399 pub average_utilization: f64,
400}
401
402#[derive(Debug, Clone, Default)]
404pub struct SlabStats {
405 pub total_objects: usize,
406 pub allocated_objects: usize,
407 pub free_objects: usize,
408 pub utilization: f64,
409 pub access_count: u64,
410 pub age: std::time::Duration,
411}
412
413#[derive(Debug, Clone)]
415pub struct MemoryPoolUsage {
416 pub total_size: usize,
417 pub allocated_size: usize,
418 pub free_size: usize,
419 pub current_offset: usize,
420 pub free_regions: usize,
421}
422
423impl SlabCache {
424 pub fn new(object_size: usize, config: CacheConfig) -> Self {
425 Self {
426 object_size,
427 slabs: Vec::new(),
428 partial_slabs: VecDeque::new(),
429 full_slabs: Vec::new(),
430 empty_slabs: VecDeque::new(),
431 stats: CacheStats::default(),
432 config,
433 }
434 }
435
436 pub fn allocate(&mut self, memory_pool: &mut MemoryPool) -> Result<NonNull<u8>, SlabError> {
438 self.stats.total_allocations += 1;
439
440 if let Some(&slab_index) = self.partial_slabs.front() {
442 if let Some(ptr) = self.slabs[slab_index].allocate() {
443 self.stats.cache_hits += 1;
444 self.stats.objects_allocated += 1;
445
446 if self.slabs[slab_index].is_full() {
448 self.partial_slabs.pop_front();
449 self.full_slabs.push(slab_index);
450 }
451
452 if self.config.enable_ctor_dtor {
454 if let Some(ctor) = self.config.constructor {
455 ctor(ptr.as_ptr());
456 }
457 }
458
459 return Ok(ptr);
460 }
461 }
462
463 if let Some(slab_index) = self.empty_slabs.pop_front() {
465 if let Some(ptr) = self.slabs[slab_index].allocate() {
466 self.stats.cache_hits += 1;
467 self.stats.objects_allocated += 1;
468 self.partial_slabs.push_back(slab_index);
469
470 if self.config.enable_ctor_dtor {
471 if let Some(ctor) = self.config.constructor {
472 ctor(ptr.as_ptr());
473 }
474 }
475
476 return Ok(ptr);
477 }
478 }
479
480 self.stats.cache_misses += 1;
482 self.allocate_new_slab(memory_pool)?;
483
484 if let Some(&slab_index) = self.partial_slabs.back() {
486 if let Some(ptr) = self.slabs[slab_index].allocate() {
487 self.stats.objects_allocated += 1;
488
489 if self.config.enable_ctor_dtor {
490 if let Some(ctor) = self.config.constructor {
491 ctor(ptr.as_ptr());
492 }
493 }
494
495 return Ok(ptr);
496 }
497 }
498
499 Err(SlabError::OutOfMemory(
500 "Failed to allocate after creating new slab".to_string(),
501 ))
502 }
503
504 pub fn deallocate(&mut self, ptr: NonNull<u8>) -> Result<(), SlabError> {
506 if self.config.enable_ctor_dtor {
508 if let Some(dtor) = self.config.destructor {
509 dtor(ptr.as_ptr());
510 }
511 }
512
513 let mut slab_index = None;
515 for (i, slab) in self.slabs.iter().enumerate() {
516 let base_addr = slab.base_ptr.as_ptr() as usize;
517 let ptr_addr = ptr.as_ptr() as usize;
518
519 if ptr_addr >= base_addr && ptr_addr < base_addr + slab.slab_size {
520 slab_index = Some(i);
521 break;
522 }
523 }
524
525 let slab_index = slab_index.ok_or_else(|| {
526 SlabError::InvalidPointer("Pointer not found in any slab".to_string())
527 })?;
528
529 let was_full = self.slabs[slab_index].is_full();
530 self.slabs[slab_index].deallocate(ptr)?;
531
532 self.stats.total_deallocations += 1;
533 self.stats.objects_allocated -= 1;
534 self.stats.objects_free += 1;
535
536 if was_full {
538 if let Some(pos) = self.full_slabs.iter().position(|&i| i == slab_index) {
540 self.full_slabs.remove(pos);
541 self.partial_slabs.push_back(slab_index);
542 }
543 } else if self.slabs[slab_index].is_empty() {
544 if let Some(pos) = self.partial_slabs.iter().position(|&i| i == slab_index) {
546 self.partial_slabs.remove(pos);
547 self.empty_slabs.push_back(slab_index);
548 }
549 }
550
551 Ok(())
552 }
553
554 fn allocate_new_slab(&mut self, memory_pool: &mut MemoryPool) -> Result<(), SlabError> {
555 let slab_size = self.calculate_slab_size();
556
557 let slab_ptr = memory_pool.allocate_slab(slab_size).ok_or_else(|| {
558 SlabError::OutOfMemory("Cannot allocate slab from memory pool".to_string())
559 })?;
560
561 let slab = Slab::new(slab_ptr, slab_size, self.object_size);
562 let slab_index = self.slabs.len();
563
564 self.slabs.push(slab);
565 self.partial_slabs.push_back(slab_index);
566 self.stats.slab_allocations += 1;
567
568 Ok(())
569 }
570
571 fn calculate_slab_size(&self) -> usize {
572 let objects_per_slab = self.config.objects_per_slab;
574 let base_size = objects_per_slab * self.object_size;
575
576 if self.config.enable_coloring {
578 base_size + self.config.color_offset
579 } else {
580 base_size
581 }
582 }
583
584 pub fn get_stats(&self) -> &CacheStats {
586 &self.stats
587 }
588
589 pub fn get_cache_info(&self) -> CacheInfo {
591 let total_objects = self.slabs.iter().map(|s| s.object_count).sum();
592 let allocated_objects = self.slabs.iter().map(|s| s.allocated_count).sum();
593 let average_utilization = if total_objects > 0 {
594 allocated_objects as f64 / total_objects as f64
595 } else {
596 0.0
597 };
598
599 CacheInfo {
600 object_size: self.object_size,
601 total_slabs: self.slabs.len(),
602 partial_slabs: self.partial_slabs.len(),
603 full_slabs: self.full_slabs.len(),
604 empty_slabs: self.empty_slabs.len(),
605 total_objects,
606 allocated_objects,
607 free_objects: total_objects - allocated_objects,
608 average_utilization,
609 memory_overhead: self.calculate_memory_overhead(),
610 }
611 }
612
613 fn calculate_memory_overhead(&self) -> f64 {
614 let useful_memory: usize = self
615 .slabs
616 .iter()
617 .map(|s| s.allocated_count * s.object_size)
618 .sum();
619
620 let total_memory: usize = self.slabs.iter().map(|s| s.slab_size).sum();
621
622 if total_memory > 0 {
623 1.0 - (useful_memory as f64 / total_memory as f64)
624 } else {
625 0.0
626 }
627 }
628
629 pub fn reclaim_empty_slabs(&mut self, memory_pool: &mut MemoryPool) -> usize {
631 let mut reclaimed = 0;
632 let keep_count = self.config.max_empty_slabs;
633
634 while self.empty_slabs.len() > keep_count {
635 if let Some(slab_index) = self.empty_slabs.pop_front() {
636 let slab = &self.slabs[slab_index];
637 memory_pool.free_slab(slab.base_ptr, slab.slab_size);
638 reclaimed += 1;
639 self.stats.slab_deallocations += 1;
640 }
641 }
642
643 reclaimed
644 }
645}
646
647#[derive(Debug, Clone)]
649pub struct CacheInfo {
650 pub object_size: usize,
651 pub total_slabs: usize,
652 pub partial_slabs: usize,
653 pub full_slabs: usize,
654 pub empty_slabs: usize,
655 pub total_objects: usize,
656 pub allocated_objects: usize,
657 pub free_objects: usize,
658 pub average_utilization: f64,
659 pub memory_overhead: f64,
660}
661
662impl SlabAllocator {
663 pub fn new(base_ptr: NonNull<u8>, total_size: usize, config: SlabConfig) -> Self {
664 let memory_pool = MemoryPool::new(base_ptr, total_size, config.alignment);
665
666 Self {
667 caches: HashMap::new(),
668 memory_pool,
669 config,
670 }
671 }
672
673 pub fn allocate(&mut self, size: usize) -> Result<NonNull<u8>, SlabError> {
675 if size == 0 {
676 return Err(SlabError::InvalidSize(
677 "Cannot allocate zero bytes".to_string(),
678 ));
679 }
680
681 let aligned_size = (size + self.config.alignment - 1) & !(self.config.alignment - 1);
683
684 let cache = self
689 .caches
690 .entry(aligned_size)
691 .or_insert_with(|| SlabCache::new(aligned_size, CacheConfig::default()));
692 cache.allocate(&mut self.memory_pool)
693 }
694
695 pub fn deallocate(&mut self, ptr: NonNull<u8>, size: usize) -> Result<(), SlabError> {
697 let aligned_size = (size + self.config.alignment - 1) & !(self.config.alignment - 1);
698
699 let cache = self
700 .caches
701 .get_mut(&aligned_size)
702 .ok_or_else(|| SlabError::InvalidPointer("No cache found for this size".to_string()))?;
703
704 cache.deallocate(ptr)
705 }
706
707 pub fn get_stats(&self) -> SlabAllocatorStats {
709 let mut total_caches = 0;
710 let mut total_slabs = 0;
711 let mut total_objects = 0;
712 let mut allocated_objects = 0;
713 let mut total_allocations = 0;
714 let mut total_deallocations = 0;
715
716 for cache in self.caches.values() {
717 total_caches += 1;
718 let info = cache.get_cache_info();
719 total_slabs += info.total_slabs;
720 total_objects += info.total_objects;
721 allocated_objects += info.allocated_objects;
722
723 let stats = cache.get_stats();
724 total_allocations += stats.total_allocations;
725 total_deallocations += stats.total_deallocations;
726 }
727
728 let memory_usage = self.memory_pool.get_usage();
729
730 SlabAllocatorStats {
731 total_caches,
732 total_slabs,
733 total_objects,
734 allocated_objects,
735 free_objects: total_objects - allocated_objects,
736 total_allocations,
737 total_deallocations,
738 memory_usage,
739 cache_efficiency: if total_allocations > 0 {
740 allocated_objects as f64 / total_allocations as f64
741 } else {
742 0.0
743 },
744 }
745 }
746
747 pub fn get_all_cache_info(&self) -> Vec<(usize, CacheInfo)> {
749 self.caches
750 .iter()
751 .map(|(&size, cache)| (size, cache.get_cache_info()))
752 .collect()
753 }
754
755 pub fn reclaim_memory(&mut self) -> usize {
757 let mut total_reclaimed = 0;
758
759 for cache in self.caches.values_mut() {
760 total_reclaimed += cache.reclaim_empty_slabs(&mut self.memory_pool);
761 }
762
763 total_reclaimed
764 }
765
766 pub fn destroy_cache(&mut self, size: usize) -> Result<(), SlabError> {
768 let aligned_size = (size + self.config.alignment - 1) & !(self.config.alignment - 1);
769
770 if let Some(mut cache) = self.caches.remove(&aligned_size) {
771 cache.reclaim_empty_slabs(&mut self.memory_pool);
773 Ok(())
774 } else {
775 Err(SlabError::InvalidSize("Cache not found".to_string()))
776 }
777 }
778
779 pub fn get_memory_usage(&self) -> MemoryPoolUsage {
781 self.memory_pool.get_usage()
782 }
783}
784
785unsafe impl Send for SlabAllocator {}
791unsafe impl Sync for SlabAllocator {}
792
793#[derive(Debug, Clone)]
795pub struct SlabAllocatorStats {
796 pub total_caches: usize,
797 pub total_slabs: usize,
798 pub total_objects: usize,
799 pub allocated_objects: usize,
800 pub free_objects: usize,
801 pub total_allocations: u64,
802 pub total_deallocations: u64,
803 pub memory_usage: MemoryPoolUsage,
804 pub cache_efficiency: f64,
805}
806
807#[derive(Debug, Clone)]
809pub enum SlabError {
810 InvalidSize(String),
811 OutOfMemory(String),
812 InvalidPointer(String),
813 DoubleFree(String),
814 CorruptedSlab(String),
815}
816
817impl std::fmt::Display for SlabError {
818 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
819 match self {
820 SlabError::InvalidSize(msg) => write!(f, "Invalid size: {}", msg),
821 SlabError::OutOfMemory(msg) => write!(f, "Out of memory: {}", msg),
822 SlabError::InvalidPointer(msg) => write!(f, "Invalid pointer: {}", msg),
823 SlabError::DoubleFree(msg) => write!(f, "Double free: {}", msg),
824 SlabError::CorruptedSlab(msg) => write!(f, "Corrupted slab: {}", msg),
825 }
826 }
827}
828
829impl std::error::Error for SlabError {}
830
831pub struct ThreadSafeSlabAllocator {
833 allocator: Arc<Mutex<SlabAllocator>>,
834}
835
836impl ThreadSafeSlabAllocator {
837 pub fn new(base_ptr: NonNull<u8>, total_size: usize, config: SlabConfig) -> Self {
838 let allocator = SlabAllocator::new(base_ptr, total_size, config);
839 Self {
840 allocator: Arc::new(Mutex::new(allocator)),
841 }
842 }
843
844 pub fn allocate(&self, size: usize) -> Result<NonNull<u8>, SlabError> {
845 let mut allocator = self.allocator.lock().unwrap_or_else(|e| e.into_inner());
846 allocator.allocate(size)
847 }
848
849 pub fn deallocate(&self, ptr: NonNull<u8>, size: usize) -> Result<(), SlabError> {
850 let mut allocator = self.allocator.lock().unwrap_or_else(|e| e.into_inner());
851 allocator.deallocate(ptr, size)
852 }
853
854 pub fn get_stats(&self) -> SlabAllocatorStats {
855 let allocator = self.allocator.lock().unwrap_or_else(|e| e.into_inner());
856 allocator.get_stats()
857 }
858
859 pub fn reclaim_memory(&self) -> usize {
860 let mut allocator = self.allocator.lock().unwrap_or_else(|e| e.into_inner());
861 allocator.reclaim_memory()
862 }
863}
864
865#[cfg(test)]
866mod tests {
867 use super::*;
868
869 #[test]
870 fn test_slab_creation() {
871 let size = 4096;
872 let memory = vec![0u8; size];
873 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
874
875 let slab = Slab::new(ptr, size, 64);
876 assert_eq!(slab.object_count, size / 64);
877 assert!(slab.is_empty());
878 assert!(!slab.is_full());
879 }
880
881 #[test]
882 fn test_slab_allocation() {
883 let size = 4096;
884 let memory = vec![0u8; size];
885 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
886
887 let mut slab = Slab::new(ptr, size, 64);
888
889 let alloc1 = slab.allocate();
890 assert!(alloc1.is_some());
891 assert!(slab.is_partial());
892
893 let alloc2 = slab.allocate();
894 assert!(alloc2.is_some());
895 assert_ne!(
896 alloc1.expect("unwrap failed"),
897 alloc2.expect("unwrap failed")
898 );
899 }
900
901 #[test]
902 fn test_slab_deallocation() {
903 let size = 4096;
904 let memory = vec![0u8; size];
905 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
906
907 let mut slab = Slab::new(ptr, size, 64);
908
909 let alloc_ptr = slab.allocate().expect("unwrap failed");
910 let result = slab.deallocate(alloc_ptr);
911 assert!(result.is_ok());
912 }
913
914 #[test]
915 fn test_memory_pool() {
916 let size = 1024 * 1024;
917 let memory = vec![0u8; size];
918 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
919
920 let mut pool = MemoryPool::new(ptr, size, 256);
921
922 let slab1 = pool.allocate_slab(4096);
923 assert!(slab1.is_some());
924
925 let slab2 = pool.allocate_slab(4096);
926 assert!(slab2.is_some());
927
928 assert_ne!(slab1.expect("unwrap failed"), slab2.expect("unwrap failed"));
929 }
930
931 #[test]
932 fn test_slab_cache() {
933 let size = 1024 * 1024;
934 let memory = vec![0u8; size];
935 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
936
937 let mut pool = MemoryPool::new(ptr, size, 256);
938 let config = CacheConfig::default();
939 let mut cache = SlabCache::new(64, config);
940
941 let alloc1 = cache.allocate(&mut pool);
942 assert!(alloc1.is_ok());
943
944 let alloc2 = cache.allocate(&mut pool);
945 assert!(alloc2.is_ok());
946 }
947
948 #[test]
949 fn test_slab_allocator() {
950 let size = 1024 * 1024;
951 let memory = vec![0u8; size];
952 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
953
954 let config = SlabConfig::default();
955 let mut allocator = SlabAllocator::new(ptr, size, config);
956
957 let alloc1 = allocator.allocate(64);
958 assert!(alloc1.is_ok());
959
960 let alloc2 = allocator.allocate(128);
961 assert!(alloc2.is_ok());
962
963 let stats = allocator.get_stats();
964 assert!(stats.total_caches >= 1); }
967
968 #[test]
969 fn test_thread_safe_allocator() {
970 let size = 1024 * 1024;
971 let memory = vec![0u8; size];
972 let ptr = NonNull::new(memory.as_ptr() as *mut u8).expect("unwrap failed");
973
974 let config = SlabConfig::default();
975 let allocator = ThreadSafeSlabAllocator::new(ptr, size, config);
976
977 let alloc_result = allocator.allocate(64);
978 assert!(alloc_result.is_ok());
979
980 let stats = allocator.get_stats();
981 assert!(stats.allocated_objects > 0);
982 }
983}