use std::alloc::Layout;
use super::{
Arena, DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER,
bumpalo_alloc::Alloc as BumpaloAlloc,
create::{OVERHEAD, TYPICAL_PAGE_SIZE},
};
#[cfg(doctest)]
fn arena_not_sync() {}
#[test]
fn allocated_and_used_bytes() {
fn chunk_count<const MIN_ALIGN: usize>(b: &mut Arena<MIN_ALIGN>) -> usize {
b.iter_allocated_chunks().count()
}
const fn next_chunk_size(prev: usize) -> usize {
let raw = 2 * prev + OVERHEAD;
let aligned = (raw + TYPICAL_PAGE_SIZE - 1) & !(TYPICAL_PAGE_SIZE - 1);
aligned - OVERHEAD
}
const SECOND_CHUNK: usize = next_chunk_size(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
const THIRD_CHUNK: usize = next_chunk_size(SECOND_CHUNK);
let mut b = Arena::new();
assert_eq!(b.allocated_bytes(), 0);
assert_eq!(b.used_bytes(), 0);
assert_eq!(chunk_count(&mut b), 0);
b.alloc(0u8);
assert_eq!(b.allocated_bytes(), DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
assert_eq!(b.used_bytes(), 1);
assert_eq!(chunk_count(&mut b), 1);
b.reset();
assert_eq!(b.allocated_bytes(), DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
assert_eq!(b.used_bytes(), 0);
assert_eq!(chunk_count(&mut b), 1);
let small = Layout::from_size_align(64, 1).unwrap();
b.alloc_layout(small);
b.alloc_layout(small);
assert_eq!(b.allocated_bytes(), DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
assert_eq!(b.used_bytes(), small.size() * 2);
assert_eq!(chunk_count(&mut b), 1);
let big = Layout::from_size_align(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER, 1).unwrap();
b.alloc_layout(big);
let two_chunks = b.allocated_bytes();
assert_eq!(two_chunks, DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER + SECOND_CHUNK);
assert_eq!(b.used_bytes(), small.size() * 2 + big.size());
assert_eq!(chunk_count(&mut b), 2);
let huge = Layout::from_size_align(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER * 2, 1).unwrap();
b.alloc_layout(huge);
let three_chunks = b.allocated_bytes();
assert_eq!(three_chunks, DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER + SECOND_CHUNK + THIRD_CHUNK);
assert_eq!(b.used_bytes(), small.size() * 2 + big.size() + huge.size());
assert_eq!(chunk_count(&mut b), 3);
b.reset();
let after_reset = b.allocated_bytes();
assert_eq!(after_reset, THIRD_CHUNK);
assert_eq!(b.used_bytes(), 0);
assert_eq!(chunk_count(&mut b), 1);
}
#[test]
fn test_realloc() {
unsafe {
const CAPACITY: usize = DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER;
let mut b = Arena::<1>::with_min_align_and_capacity(CAPACITY);
let layout = Layout::from_size_align(100, 1).unwrap();
let p = b.alloc_layout(layout);
let q = (&b).realloc(p, layout, 51).unwrap();
assert_eq!(p, q);
b.reset();
let layout = Layout::from_size_align(100, 1).unwrap();
let p = b.alloc_layout(layout);
let q = (&b).realloc(p, layout, 50).unwrap();
assert!(p != q);
b.reset();
let layout = Layout::from_size_align(10, 1).unwrap();
let p = b.alloc_layout(layout);
let q = (&b).realloc(p, layout, 11).unwrap();
assert_eq!(q.as_ptr().addr(), p.as_ptr().addr() - 1);
b.reset();
let layout = Layout::from_size_align(1, 1).unwrap();
let p = b.alloc_layout(layout);
let q = (&b).realloc(p, layout, CAPACITY + 1).unwrap();
assert_ne!(q.as_ptr().addr(), p.as_ptr().addr() - CAPACITY);
b.reset();
let layout = Layout::from_size_align(1, 1).unwrap();
let p = b.alloc_layout(layout);
let _ = b.alloc_layout(layout);
let q = (&b).realloc(p, layout, 2).unwrap();
assert!(q.as_ptr().addr() != p.as_ptr().addr() - 1);
b.reset();
}
}
#[test]
fn invalid_read() {
let mut b = &Arena::new();
unsafe {
let l1 = Layout::from_size_align(12000, 4).unwrap();
let p1 = BumpaloAlloc::alloc(&mut b, l1).unwrap();
let l2 = Layout::from_size_align(1000, 4).unwrap();
BumpaloAlloc::alloc(&mut b, l2).unwrap();
let p1 = b.realloc(p1, l1, 24000).unwrap();
let l3 = Layout::from_size_align(24000, 4).unwrap();
b.realloc(p1, l3, 48000).unwrap();
}
}