use std::alloc::Layout;
pub struct AnyList {
data: *mut u8,
capacity: usize,
past_cap: usize,
len: usize,
layout: Layout
}
impl AnyList {
pub unsafe fn new<T>() -> AnyList {
let layout = Layout::array::<T>(1).unwrap();
let data: *mut u8 = std::alloc::alloc(layout);
AnyList { data, capacity: 1, len: 0, past_cap: 1, layout }
}
pub unsafe fn data<T>(&self) -> &[T] {
std::slice::from_raw_parts(self.data.cast::<T>(), self.len)
}
pub unsafe fn mut_data<T>(&self) -> &mut [T] {
std::slice::from_raw_parts_mut(self.data.cast::<T>(), self.len)
}
pub unsafe fn index<T>(&self, idx: usize) -> &T {
assert!(idx < self.len);
&self.data::<T>()[idx]
}
pub unsafe fn index_mut<T>(&mut self, idx: usize) -> &mut T {
assert!(idx < self.len);
&mut self.mut_data::<T>()[idx]
}
pub unsafe fn resize<T>(&mut self, size: usize) {
if self.capacity <= size {
return;
}
let new_layout = Layout::array::<T>(size).unwrap();
let new_data: *mut u8 = std::alloc::alloc_zeroed(new_layout);
for i in 0..self.len * std::mem::size_of::<T>() {
*new_data.add(i) = *self.data.add(i);
}
std::alloc::dealloc(self.data, Layout::array::<T>(self.capacity).unwrap());
self.data = new_data;
self.capacity = size;
self.layout = new_layout;
}
pub unsafe fn push<T>(&mut self, item: T) {
if self.len + 1 > self.capacity {
let past = self.capacity;
self.resize::<T>(self.capacity + self.past_cap);
self.past_cap = past;
}
self.len += 1;
*self.index_mut(self.len - 1) = item;
}
pub unsafe fn pop(&mut self) {
assert!(self.len > 1);
self.len -= 1;
}
pub unsafe fn remove<T>(&mut self, index: usize) {
assert!(index < self.len);
let data = self.mut_data::<T>();
for i in index + 1..self.len {
data.swap(i, i - 1);
}
self.len -= 1;
}
pub unsafe fn insert<T>(&mut self, index: usize, item: T) {
assert!(index < self.len);
if self.len + 1 > self.capacity {
let past = self.capacity;
self.resize::<T>(self.capacity + self.past_cap);
self.past_cap = past;
}
self.len += 1;
let data = self.mut_data::<T>();
for i in (index..self.len - 1).rev() {
data.swap(i, i + 1);
}
data[index] = item;
}
pub fn len(&self) -> usize {
self.len
}
pub fn capacity(&self) -> usize {
self.capacity
}
}
impl Drop for AnyList {
fn drop(&mut self) {
unsafe { std::alloc::dealloc(self.data, self.layout); }
}
}
mod tests {
#[test]
fn push_test() {
use crate::AnyList;
unsafe {
let mut list = AnyList::new::<u32>();
list.push::<u32>(1);
list.push::<u32>(2);
assert!(list.data::<u32>() == &[1,2]);
}
}
#[test]
fn pop_test() {
use crate::AnyList;
unsafe {
let mut list = AnyList::new::<u32>();
list.push::<u32>(1);
list.push::<u32>(2);
list.push::<u32>(3);
list.pop();
assert!(list.data::<u32>() == &[1,2]);
}
}
#[test]
fn remove_test() {
use crate::AnyList;
unsafe {
let mut list = AnyList::new::<u32>();
list.push::<u32>(1);
list.push::<u32>(2);
list.push::<u32>(3);
list.remove::<u32>(1);
assert!(list.data::<u32>() == &[1,3]);
}
}
#[test]
fn insert_test() {
use crate::AnyList;
unsafe {
let mut list = AnyList::new::<u32>();
list.push::<u32>(1);
list.push::<u32>(3);
list.insert::<u32>(1, 2);
assert!(list.data::<u32>() == &[1,2,3]);
}
}
}