use core::ffi::c_void;
use core::ptr;
use super::alloc::{free, malloc, realloc};
#[inline]
pub unsafe fn ptr_ref<'a, T>(ptr: *const T) -> &'a T {
debug_assert!(!ptr.is_null());
ptr.as_ref().unwrap_unchecked()
}
#[inline]
pub unsafe fn ptr_mut<'a, T>(ptr: *mut T) -> &'a mut T {
debug_assert!(!ptr.is_null());
ptr.as_mut().unwrap_unchecked()
}
pub struct Array<T> {
pub contents: *mut T,
pub size: u32,
pub capacity: u32,
}
impl<T> Array<T> {
pub const fn new() -> Self {
Self {
contents: ptr::null_mut(),
size: 0,
capacity: 0,
}
}
#[inline]
pub const fn len(&self) -> usize {
self.size as usize
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.size == 0
}
#[inline]
pub const fn as_slice(&self) -> &[T] {
if self.is_empty() {
&[]
} else {
unsafe { core::slice::from_raw_parts(self.contents, self.len()) }
}
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
if self.is_empty() {
&mut []
} else {
unsafe { core::slice::from_raw_parts_mut(self.contents, self.len()) }
}
}
pub unsafe fn delete(&mut self) {
if !self.contents.is_null() {
free(self.contents.cast::<c_void>());
}
*self = Self::new();
}
#[inline]
pub fn clear(&mut self) {
self.size = 0;
}
#[inline]
pub unsafe fn reserve(&mut self, new_capacity: u32) {
if new_capacity <= self.capacity {
return;
}
let byte_count = new_capacity as usize * core::mem::size_of::<T>();
self.contents = if self.contents.is_null() {
malloc(byte_count).cast::<T>()
} else {
realloc(self.contents.cast::<c_void>(), byte_count).cast::<T>()
};
self.capacity = new_capacity;
}
#[inline]
unsafe fn grow(&mut self, count: u32) {
let new_size = self.size + count;
if new_size > self.capacity {
self.reserve((self.capacity * 2).max(8).max(new_size));
}
}
#[inline]
pub unsafe fn push(&mut self, element: T) {
self.grow(1);
ptr::write(self.contents.add(self.size as usize), element);
self.size += 1;
}
#[inline]
pub unsafe fn grow_by(&mut self, count: u32) {
if count == 0 {
return;
}
self.grow(count);
ptr::write_bytes(self.contents.add(self.size as usize), 0, count as usize);
self.size += count;
}
#[inline]
pub unsafe fn pop(&mut self) -> T {
self.size -= 1;
ptr::read(self.contents.add(self.size as usize))
}
#[inline]
pub unsafe fn get_unchecked(&self, index: u32) -> &T {
self.as_slice().get_unchecked(index as usize)
}
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: u32) -> &mut T {
self.as_mut_slice().get_unchecked_mut(index as usize)
}
#[inline]
pub unsafe fn last_unchecked(&self) -> &T {
self.as_slice().last().unwrap_unchecked()
}
#[inline]
pub unsafe fn last_unchecked_mut(&mut self) -> &mut T {
self.as_mut_slice().last_mut().unwrap_unchecked()
}
pub unsafe fn erase(&mut self, index: u32) {
debug_assert!(index < self.size);
let count = self.size as usize - index as usize - 1;
if count > 0 {
ptr::copy(
self.contents.add(index as usize + 1),
self.contents.add(index as usize),
count,
);
}
self.size -= 1;
}
pub unsafe fn insert(&mut self, index: u32, element: T) {
self.grow(1);
let count = self.size as usize - index as usize;
if count > 0 {
ptr::copy(
self.contents.add(index as usize),
self.contents.add(index as usize + 1),
count,
);
}
ptr::write(self.contents.add(index as usize), element);
self.size += 1;
}
pub unsafe fn splice(
&mut self,
index: u32,
old_count: u32,
new_count: u32,
new_contents: *const T,
) {
let new_size = self.size + new_count - old_count;
let old_end = index + old_count;
let new_end = index + new_count;
debug_assert!(old_end <= self.size);
self.reserve(new_size);
let trailing_count = (self.size - old_end) as usize;
if trailing_count > 0 {
ptr::copy(
self.contents.add(old_end as usize),
self.contents.add(new_end as usize),
trailing_count,
);
}
if new_count > 0 && !new_contents.is_null() {
ptr::copy(
new_contents,
self.contents.add(index as usize),
new_count as usize,
);
}
self.size = new_size;
}
pub unsafe fn assign(&mut self, source: &Self) {
self.reserve(source.size);
self.size = source.size;
if !source.is_empty() {
ptr::copy(source.contents, self.contents, source.len());
}
}
}
pub fn array_init<T>(arr: &mut Array<T>) {
arr.size = 0;
arr.capacity = 0;
arr.contents = ptr::null_mut();
}
pub unsafe fn array_delete<T>(arr: &mut Array<T>) {
arr.delete();
}
#[inline]
pub fn array_clear<T>(arr: &mut Array<T>) {
arr.clear();
}
#[inline]
pub unsafe fn array_reserve<T>(arr: &mut Array<T>, new_capacity: u32) {
arr.reserve(new_capacity);
}
#[inline]
pub unsafe fn array_push<T>(arr: &mut Array<T>, element: T) {
arr.push(element);
}
#[inline]
pub unsafe fn array_grow_by<T>(arr: &mut Array<T>, count: u32) {
arr.grow_by(count);
}
#[inline]
pub unsafe fn array_pop<T>(arr: &mut Array<T>) -> T {
arr.pop()
}
#[inline]
pub unsafe fn array_get_ref<T>(arr: &Array<T>, index: u32) -> &T {
arr.get_unchecked(index)
}
#[inline]
pub unsafe fn array_get_mut<T>(arr: &mut Array<T>, index: u32) -> &mut T {
arr.get_unchecked_mut(index)
}
#[inline]
pub unsafe fn array_back_ref<T>(arr: &Array<T>) -> &T {
arr.last_unchecked()
}
#[inline]
pub unsafe fn array_back_mut<T>(arr: &mut Array<T>) -> &mut T {
arr.last_unchecked_mut()
}
pub unsafe fn array_erase<T>(arr: &mut Array<T>, index: u32) {
arr.erase(index);
}
pub unsafe fn array_insert<T>(arr: &mut Array<T>, index: u32, element: T) {
arr.insert(index, element);
}
pub const fn array_new<T>() -> Array<T> {
Array::new()
}
pub unsafe fn array_splice<T>(
arr: &mut Array<T>,
index: u32,
old_count: u32,
new_count: u32,
new_contents: *const T,
) {
arr.splice(index, old_count, new_count, new_contents);
}
pub unsafe fn array_assign<T>(destination: &mut Array<T>, source: &Array<T>) {
destination.assign(source);
}