#[cfg(test)]
mod tests {
use crate::HeapVec;
#[test]
fn size_ok() {
use std::mem::size_of;
assert_eq!(size_of::<*mut u8>(), size_of::<HeapVec<u8>>());
}
#[test]
fn insert_test() {
let mut hv: crate::HeapVec<u8> = crate::HeapVec::new();
assert_eq!(hv.len(), 0);
hv.push(0);
assert_eq!(hv.len(), 1);
hv.push(1);
assert_eq!(hv.len(), 2);
let hvc = hv.clone();
assert_eq!(hv[0], 0);
assert_eq!(hv[1], 1);
assert_eq!(hv.pop(), Some(1));
assert_eq!(hv.len(), 1);
assert_eq!(hv.pop(), Some(0));
assert_eq!(hv.len(), 0);
assert_eq!(hv.pop(), None);
assert_eq!(hvc[..], [0, 1]);
}
#[test]
#[should_panic(expected = "droppanic.drop()")]
fn test_drop_panic() {
struct DropPanic {
test: u8
};
impl Drop for DropPanic {
fn drop(&mut self) {
panic!("droppanic.drop()");
}
}
let mut v = HeapVec::new();
v.push(DropPanic{test: 0});
}
}
use std::marker::PhantomData;
use std::mem;
struct Unique<T> {
ptr: *const T, _marker: PhantomData<T>, }
unsafe impl<T: Send> Send for Unique<T> {}
unsafe impl<T: Sync> Sync for Unique<T> {}
impl<T> Unique<T> {
pub fn new(ptr: *mut T) -> Self {
Unique { ptr: ptr, _marker: PhantomData }
}
pub fn as_ptr(&self) -> *mut T {
self.ptr as *mut T
}
pub fn is_null(&self) -> bool {
self.ptr as usize == 0
}
}
use std::alloc;
pub struct HeapVec<T> {
ptr: Unique<T>,
}
impl<T> HeapVec<T> {
pub fn new() -> Self {
assert!(std::mem::size_of::<T>() != 0, "We're not ready to handle types with size 0!");
Self { ptr: Unique::new(0 as *mut T)}
}
pub fn raw_ptr(&self) -> *const T {
(self.ptr.as_ptr() as usize + Self::get_offset()) as *mut T
}
const fn get_offset() -> usize {
((mem::size_of::<usize>()*2 + mem::align_of::<T>() - 1) / mem::align_of::<T>()) * mem::align_of::<T>()
}
fn get_offset_of(&self, index: usize) -> *mut T {
(self.ptr.as_ptr() as usize + Self::get_offset() + mem::size_of::<T>() * index) as *mut T
}
fn capacity(&self) -> usize {
if self.ptr.is_null() {
0
} else {
unsafe {
*(self.ptr.as_ptr() as *const usize)
}
}
}
pub fn len(&self) -> usize {
if self.ptr.is_null() {
0
} else {
unsafe {
*((self.ptr.as_ptr() as usize + mem::size_of::<usize>()) as *const usize)
}
}
}
fn get_cap_mut(&mut self) -> &mut usize {
unsafe {
&mut*(self.ptr.as_ptr() as *mut usize)
}
}
fn get_len_mut(&mut self) -> &mut usize {
unsafe {
&mut *((self.ptr.as_ptr() as usize + mem::size_of::<usize>()) as *mut usize)
}
}
fn grow(&mut self) {
unsafe {
let cap_size = Self::get_offset();
let elem_size = mem::size_of::<T>();
let align = std::cmp::max(mem::align_of::<T>(), mem::align_of::<usize>());
if self.ptr.is_null() {
let new_num_bytes = cap_size + elem_size;
let ptr = alloc::alloc(alloc::Layout::from_size_align(new_num_bytes, align).expect("Couldn't create layout!"));
if ptr.is_null() {
panic!("Allocation failed!");
}
self.ptr = Unique::new(ptr as *mut T);
*self.get_cap_mut() = 1;
} else {
let old_cap = self.capacity();
let new_cap = old_cap * 2;
let old_num_bytes = cap_size + old_cap*elem_size;
let new_num_bytes = cap_size + 2*old_cap*elem_size;
let ptr = alloc::realloc(self.ptr.as_ptr() as *mut u8,
alloc::Layout::from_size_align(old_num_bytes, align).expect("Couldn't create layout!"),
new_num_bytes
);
self.ptr = Unique::new(ptr as *mut T);
*self.get_cap_mut() = new_cap;
};
}
}
pub fn push(&mut self, elem: T) {
if self.len() == self.capacity() {
self.grow();
}
unsafe {
std::ptr::write(self.get_offset_of(self.len()), elem);
}
*self.get_len_mut() += 1;
}
pub fn pop(&mut self) -> Option<T> {
if self.len() == 0 {
None
} else {
*self.get_len_mut() -= 1;
unsafe {
Some(std::ptr::read(self.get_offset_of(self.len())))
}
}
}
pub fn insert(&mut self, index: usize, elem: T) {
assert!(index <= self.len(), "index out of bounds");
if self.capacity() == self.len() { self.grow(); }
unsafe {
if index < self.len() {
std::ptr::copy(self.get_offset_of(index),
self.get_offset_of(index + 1),
self.len() - index);
}
std::ptr::write(self.get_offset_of(index), elem);
}
*self.get_len_mut() += 1;
}
pub fn remove(&mut self, index: usize) -> T {
assert!(index < self.len(), "index out of bounds");
unsafe {
*self.get_len_mut() -= 1;
let result = std::ptr::read(self.get_offset_of(index));
std::ptr::copy(self.get_offset_of(index + 1),
self.get_offset_of(index),
self.len() - index);
result
}
}
}
impl<T> Drop for HeapVec<T> {
fn drop(&mut self) {
if !self.ptr.is_null() {
while let Some(_) = self.pop() { }
let align = std::cmp::max(mem::align_of::<T>(), mem::align_of::<usize>());
let elem_size = mem::size_of::<T>();
let cap_size = Self::get_offset();
let num_bytes = cap_size + elem_size * self.capacity();
unsafe {
alloc::dealloc(self.ptr.as_ptr() as *mut _, alloc::Layout::from_size_align(num_bytes, align).expect("Couldn't create layout!"));
}
}
}
}
use std::ops::Deref;
impl<T> Deref for HeapVec<T> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe {
std::slice::from_raw_parts(self.get_offset_of(0), self.len())
}
}
}
use std::ops::DerefMut;
impl<T> DerefMut for HeapVec<T> {
fn deref_mut(&mut self) -> &mut [T] {
unsafe {
std::slice::from_raw_parts_mut(self.get_offset_of(0), self.len())
}
}
}
impl<T: Clone> Clone for HeapVec<T> {
fn clone(&self) -> Self {
unsafe {
let cap_size = Self::get_offset();
let elem_size = mem::size_of::<T>();
let align = std::cmp::max(mem::align_of::<T>(), mem::align_of::<usize>());
let num_bytes = cap_size + elem_size * self.capacity();
let ptr = alloc::alloc(alloc::Layout::from_size_align(num_bytes, align).expect("Couldn't create layout!"));
if ptr.is_null() {
panic!("Allocation failed!");
}
let mut new_hv = Self{ptr: Unique::new(ptr as *mut T)};
*new_hv.get_cap_mut() = self.capacity();
for v in self.iter() {
new_hv.push(v.clone());
}
new_hv
}
}
}