use std::cmp::max;
use std::intrinsics::{needs_drop, drop_in_place, abort};
use std::mem::{size_of, align_of};
use std::ptr::{copy, read, write, Unique};
extern crate alloc;
use self::alloc::heap::{allocate, reallocate, deallocate};
const MIN_CAPACITY: usize = 4;
pub struct CompRawVec<T> {
valid: usize,
capacity: usize,
ptrs: Unique<T>,
}
impl<T> CompRawVec<T> {
fn oom() -> ! {
unsafe { abort() }
}
fn allocate(capacity: usize) -> Unique<T> {
unsafe {
let size = capacity * size_of::<T>();
let array = allocate(size, align_of::<T>());
if array.is_null() {
Self::oom();
}
Unique::new(array as *mut T)
}
}
#[inline]
fn reallocate(data: &mut Unique<T>, old_capacity: usize, new_capacity: usize) {
let old_size = old_capacity * size_of::<T>();
let new_size = new_capacity * size_of::<T>();
unsafe {
let array = reallocate(data.as_ptr() as *mut u8,
old_size,
new_size,
align_of::<T>());
if array.is_null() {
Self::oom();
}
*data = Unique::new(array as *mut T);
}
}
fn deallocate(data: &mut Unique<T>, capacity: usize) {
unsafe {
let size = capacity * size_of::<T>();
deallocate(data.as_ptr() as *mut u8, size, align_of::<T>());
}
}
pub unsafe fn get_mut(&mut self, index: usize) -> &mut T {
let p: *mut T = self.ptrs.as_ptr().offset(index as isize);
&mut *p
}
pub unsafe fn get(&self, index: usize) -> &T {
let p: *const T = self.ptrs.as_ptr().offset(index as isize);
&*p
}
#[inline]
pub unsafe fn insert(&mut self, valid_bit: usize, index: usize, value: T) -> &mut T {
let size = self.size();
let capacity = self.capacity;
if size == capacity {
let new_capacity = capacity * 2;
Self::reallocate(&mut self.ptrs, capacity, new_capacity);
self.capacity = new_capacity;
}
let ptr: *mut T = self.ptrs.as_ptr().offset(index as isize);
copy(ptr, ptr.offset(1), size - index);
write(ptr, value);
self.valid |= valid_bit;
&mut *ptr
}
pub unsafe fn replace(&mut self, index: usize, value: T) -> &mut T {
let mut ptr = self.get_mut(index);
*ptr = value;
ptr
}
pub unsafe fn remove(&mut self, valid_bit: usize, index: usize) -> T {
let size = self.size();
let capacity = self.capacity;
let value;
let ptr: *mut T = self.ptrs.as_ptr().offset(index as isize);
value = read(ptr);
copy(ptr.offset(1), ptr, size - index - 1);
self.valid ^= valid_bit;
if ((size - 1) * 2 == capacity) && (capacity > MIN_CAPACITY) {
let new_capacity = max(capacity >> 1, MIN_CAPACITY);
Self::reallocate(&mut self.ptrs, capacity, new_capacity);
self.capacity = new_capacity;
}
value
}
pub fn valid(&self) -> usize {
self.valid
}
pub fn size(&self) -> usize {
self.valid.count_ones() as usize
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn new() -> CompRawVec<T> {
CompRawVec {
valid: 0,
capacity: MIN_CAPACITY,
ptrs: Self::allocate(MIN_CAPACITY),
}
}
}
impl<T> Drop for CompRawVec<T> {
fn drop(&mut self) {
unsafe {
if needs_drop::<T>() {
let size = self.size();
for index in 0..size {
let object = self.get_mut(index);
drop_in_place(object);
}
}
}
Self::deallocate(&mut self.ptrs, self.capacity);
}
}