extern crate std; use std::alloc::Layout; use std::ffi::c_char as char; use ialloc::*; use ialloc::allocator::*; struct Test { pub name: &'static str, pub create: fn()->A, pub thin: Option, pub fat: Option, } #[derive(Clone, Copy, Debug)] struct AlignmentRange { pub min: Alignment, pub max: Alignment, } impl Test { pub fn new(name: &'static str, create: fn()->A) -> Self { Self { name, create, thin: None, fat: None } } pub fn thin(&mut self) -> &mut Self where A : thin::Alloc + thin::Free { let mut thin = AlignmentRange { min: Alignment::MAX, max: Alignment::MAX }; for (dst, min_size) in [(&mut thin.min, 1), (&mut thin.max, 4096)] { for _ in 0 .. 100 { let alloc = (self.create)(); let addrs = [(); 4096].into_iter().enumerate().map(|(i, _)| alloc.alloc_uninit(i%16+min_size).unwrap()).collect::>(); let addrbits = addrs[..].iter().copied().map(|addr| addr.as_ptr() as usize).reduce(|x,y| x|y).unwrap(); addrs.iter().copied().for_each(|addr| unsafe { alloc.free(addr) }); let align = Alignment::new(1 << addrbits.trailing_zeros()).unwrap(); *dst = align.min(*dst); } } self.thin = Some(thin); self } pub fn fat(&mut self) -> &mut Self where A : fat::Alloc + fat::Free { let mut fat = AlignmentRange { min: Alignment::MAX, max: ALIGN_1 }; for _ in 0 .. 100 { let layout = Layout::new::(); // 1B let alloc = (self.create)(); let addrs = [(); 4096].map(|_| alloc.alloc_uninit(layout).unwrap()); let addrbits = addrs[..].iter().copied().map(|addr| addr.as_ptr() as usize).reduce(|x,y| x|y).unwrap(); addrs.iter().copied().for_each(|addr| unsafe { alloc.free(addr, layout) }); let align = Alignment::new(1 << addrbits.trailing_zeros()).unwrap(); fat.min = align.min(fat.min); } fat.max = fat.min; let alloc = (self.create)(); while let Some(next) = fat.max.as_usize().checked_shl(1) { let Some(align) = Alignment::new(next) else { break }; let Ok(layout) = Layout::from_size_align(next, next) else { break }; let Ok(addr) = alloc.alloc_uninit(layout) else { break }; fat.max = align; unsafe { alloc.free(addr, layout) }; } self.fat = Some(fat); self } pub fn print(&self) { let name = self.name; let thin = self.thin.map_or_else(|| format!(""), |t| if t.min == t.max { format!("{:?}", t.min) } else { format!("{:?} ..= {:?}", t.min, t.max) }); let fat = self.fat .map_or_else(|| format!(""), |t| if t.min == t.max { format!("{:?}", t.min) } else { format!("{:?} ..= {:?}", t.min, t.max) }); println!("{name: <25}{thin: <20}{fat: <20}"); } } fn main() { println!("{: <25}{: <20}{: <20}", "", "thin::Alloc", "fat::Alloc", ); println!("{: <25}{: <20}{: <20}", "Allocator", "Alignment", "Alignment", ); println!("{:=<65}", ""); #[cfg(feature = "alloc")] Test::new("Global", || alloc::Global ) .fat().print(); #[cfg(c89)] Test::new("Malloc", || c::Malloc ).thin().fat().print(); #[cfg(c89)] Test::new("AlignedMalloc", || c::AlignedMalloc ) .fat().print(); #[cfg(cpp98)] Test::new("NewDelete", || cpp::NewDelete ).thin().fat().print(); #[cfg(cpp98)] Test::new("NewDeleteArray", || cpp::NewDeleteArray ).thin().fat().print(); #[cfg(cpp17)] Test::new("NewDeleteAligned", || cpp::NewDeleteAligned ) .fat().print(); #[cfg(cpp17)] Test::new("NewDeleteArrayAligned", || cpp::NewDeleteArrayAligned ) .fat().print(); #[cfg(cpp98)] Test::new("StdAllocator", || cpp::StdAllocator::::new() ) .fat().print(); #[cfg(all(windows, feature = "win32"))] { println!(); println!("win32:"); Test::new("ProcessHeap", || win32::ProcessHeap ).thin().fat().print(); Test::new("Global", || win32::Global ).thin().fat().print(); Test::new("Local", || win32::Local ).thin().fat().print(); Test::new("CryptMem", || win32::CryptMem ).thin().fat().print(); Test::new("CoTaskMem", || win32::CoTaskMem ).thin().fat().print(); Test::new("VirtualCommit", || win32::VirtualCommit ).thin().fat().print(); } }