use std::alloc::{alloc, dealloc, Layout};
use std::mem::size_of;
use std::ptr::NonNull;
use crate::*;
const MAX_ALIGN: usize = 1073741824usize;
pub(crate) struct Block<T: Sized> {
memory: NonNull<Entry<T>>,
len_used: usize,
capacity: usize,
layout: Layout,
}
impl<T: Sized> Block<T> {
fn new(capacity: usize) -> Self {
let layout = Layout::array::<Entry<T>>(capacity).unwrap();
let layout = layout
.align_to(std::cmp::min(layout.size().next_power_of_two(), MAX_ALIGN))
.unwrap();
let memory =
unsafe { NonNull::new(alloc(layout) as *mut Entry<T>).expect("Allocation failure") };
Self {
memory,
len_used: 0,
capacity,
layout,
}
}
pub(crate) fn new_first(min_entries: usize) -> Self {
let min_entries = std::cmp::max(64, min_entries);
let blocksize =
(min_entries * size_of::<Entry<T>>()).next_power_of_two() / size_of::<Entry<T>>();
Self::new(blocksize)
}
pub(crate) fn new_next(&self) -> Self {
let blocksize =
(self.capacity * 2 * size_of::<Entry<T>>()).next_power_of_two() / size_of::<Entry<T>>();
Self::new(blocksize)
}
fn entries(&self) -> &[Entry<T>] {
unsafe { std::slice::from_raw_parts(self.memory.as_ptr(), self.len_used) }
}
fn entries_mut(&mut self) -> &mut [Entry<T>] {
unsafe { std::slice::from_raw_parts_mut(self.memory.as_mut(), self.len_used) }
}
#[inline]
pub(crate) fn is_full(&self) -> bool {
self.len_used == self.capacity
}
pub(crate) fn extend(&mut self) -> NonNull<Entry<T>> {
debug_assert!(self.len_used < self.capacity);
let pos = self.len_used;
self.len_used += 1;
unsafe { NonNull::new_unchecked(self.entries_mut().get_unchecked_mut(pos)) }
}
pub(crate) fn contains_entry(&self, entry: *mut Entry<T>) -> bool {
self.entries()
.as_ptr_range()
.contains(&(entry as *const Entry<T>))
}
}
impl<T> Drop for Block<T> {
fn drop(&mut self) {
unsafe { dealloc(self.memory.as_ptr() as *mut u8, self.layout) };
}
}
use std::fmt;
impl<T> fmt::Debug for Block<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_struct("Block")
.field("len_used", &self.len_used)
.field("capacity", &self.capacity)
.field("layout", &self.layout)
.finish()
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn smoke() {
let block: Block<String> = Block::new_first(0);
let _block2 = Block::new_next(&block);
}
}