#![allow(clippy::tabs_in_doc_comments)]
#![no_std]
#![allow(unused)]
pub mod error;
extern crate alloc;
use alloc::{
boxed::Box,
vec::Vec,
};
use crate::error::ListError;
use core::{
fmt::{
Debug,
Display,
},
mem::MaybeUninit,
ptr,
slice,
};
pub struct ArrayList<T>
{
data: Box<[MaybeUninit<T>]>,
len: usize,
capacity: usize,
}
impl<T> ArrayList<T>
{
pub fn new() -> Self
{
Self {
data: Box::new([]),
len: 0,
capacity: 0,
}
}
pub fn with_capacity(capacity: usize) -> Self
{
if capacity == 0
{
return Self::new();
}
Self {
data: (0..capacity)
.map(|_| MaybeUninit::uninit())
.collect::<Vec<_>>()
.into_boxed_slice(),
len: 0,
capacity,
}
}
pub fn len(&self) -> usize
{
self.len
}
pub fn capacity(&self) -> usize
{
self.capacity
}
pub fn is_empty(&self) -> bool
{
self.len == 0
}
pub fn push(&mut self, val: T) -> Result<(), ListError>
{
if self.capacity == self.len
{
self.grow()?;
}
self.data[self.len].write(val);
self.len += 1;
Ok(())
}
pub fn pop(&mut self) -> Option<T>
{
if self.len == 0
{
return None;
}
self.len -= 1;
unsafe { Some(self.data[self.len].assume_init_read()) }
}
pub fn pop_front(&mut self) -> Option<T>
{
if self.len == 0
{
return None;
}
unsafe {
let val = self.data[0].assume_init_read();
ptr::copy(
self.data.as_ptr().add(1),
self.data.as_mut_ptr(),
self.len - 1,
);
self.len -= 1;
self.data[self.len] = MaybeUninit::uninit();
Some(val)
}
}
pub fn get(&self, idx: usize) -> Option<&T>
{
if idx >= self.len
{
return None;
}
unsafe { Some(self.data[idx].assume_init_ref()) }
}
pub fn get_mut(&mut self, idx: usize) -> Option<&mut T>
{
if idx >= self.len
{
return None;
}
unsafe { Some(self.data[idx].assume_init_mut()) }
}
pub fn set(&mut self, idx: usize, val: T) -> Result<(), ListError>
{
if idx >= self.len
{
match self.is_empty()
{
true =>
{
return Err(ListError::EmptyList);
},
false =>
{
return Err(ListError::OutOfBounds {
idx,
limits: (0, self.len - 1),
});
},
}
}
unsafe { self.data[idx].assume_init_drop() };
self.data[idx] = MaybeUninit::new(val);
Ok(())
}
pub fn insert(&mut self, idx: usize, val: T) -> Result<(), ListError>
{
if idx > self.len
{
match self.is_empty()
{
true =>
{
return Err(ListError::EmptyList);
},
false =>
{
return Err(ListError::OutOfBounds {
idx,
limits: (0, self.len - 1),
});
},
}
}
if self.len == self.capacity
{
self.grow()?;
}
unsafe {
ptr::copy(
self.data.as_ptr().add(idx),
self.data.as_mut_ptr().add(idx + 1),
self.len - idx,
);
}
self.data[idx] = MaybeUninit::new(val);
self.len += 1;
Ok(())
}
pub fn remove(&mut self, idx: usize) -> Result<T, ListError>
{
if idx >= self.len
{
match self.is_empty()
{
true =>
{
return Err(ListError::EmptyList);
},
false =>
{
return Err(ListError::OutOfBounds {
idx,
limits: (0, self.len - 1),
});
},
}
}
unsafe {
let val = self.data[idx].assume_init_read();
ptr::copy(
self.data.as_ptr().add(idx + 1),
self.data.as_mut_ptr().add(idx),
self.len - idx - 1,
);
self.len -= 1;
self.data[self.len] = MaybeUninit::uninit();
Ok(val)
}
}
pub fn grow(&mut self) -> Result<(), ListError>
{
let new_capacity = if self.capacity == 0
{
4
}
else
{
self.capacity
.checked_mul(2)
.ok_or(ListError::CapacityOverflow)?
};
let mut new_data: Box<[MaybeUninit<T>]> = (0..new_capacity)
.map(|_| MaybeUninit::uninit())
.collect::<Vec<_>>()
.into_boxed_slice();
unsafe {
ptr::copy_nonoverlapping(self.data.as_ptr(), new_data.as_mut_ptr(), self.len);
}
self.data = new_data;
self.capacity = new_capacity;
Ok(())
}
pub fn clear(&mut self)
{
for idx in 0..self.len
{
unsafe { self.data[idx].assume_init_drop() };
}
self.len = 0;
}
}
impl<T> ArrayList<T>
{
pub fn from_vec(vec: Vec<T>) -> Self
{
let len = vec.len();
let capacity = vec.capacity();
let data = unsafe {
let mut vec = core::mem::ManuallyDrop::new(vec);
let ptr = vec.as_mut_ptr() as *mut MaybeUninit<T>;
let cap = vec.capacity();
Vec::from_raw_parts(ptr, cap, cap).into_boxed_slice()
};
Self {
data,
len,
capacity,
}
}
pub fn from_array<const N: usize>(arr: [T; N]) -> Self
{
let mut list = Self::with_capacity(N);
for item in arr
{
list.push(item)
.expect("push failed in from_array: pre-allocated capacity exhausted");
}
list
}
pub fn from_slice(slice: &[T]) -> Self
where
T: Clone,
{
let mut list = Self::with_capacity(slice.len());
for item in slice
{
list.push(item.clone())
.expect("push failed in from_slice: pre-allocated capacity exhausted");
}
list
}
}
impl<T> ArrayList<T>
{
pub fn reverse(&mut self)
{
if self.len <= 1
{
return;
}
let mut left = 0;
let mut right = self.len - 1;
while left < right
{
unsafe {
ptr::swap(
self.data.as_mut_ptr().add(left),
self.data.as_mut_ptr().add(right),
);
}
left += 1;
right -= 1;
}
}
pub fn sort(&mut self)
where
T: Ord,
{
match self.len <= 1
{
true => (),
false =>
{
for idx in 0..self.len
{
for jdx in 0..self.len - idx - 1
{
unsafe {
if self.data[jdx].assume_init_ref()
> self.data[jdx + 1].assume_init_ref()
{
ptr::swap(
self.data.as_mut_ptr().add(jdx),
self.data.as_mut_ptr().add(jdx + 1),
);
}
}
}
}
},
}
}
pub fn linear_search(&self, target: &T) -> Option<usize>
where
T: PartialEq,
{
for idx in 0..self.len
{
unsafe {
if target == self.data[idx].assume_init_ref()
{
return Some(idx);
}
}
}
None
}
pub fn binary_search(&self, target: &T) -> Option<usize>
where
T: Ord,
{
if self.is_empty()
{
return None;
}
let mut low = 0usize;
let mut high = self.len - 1;
while low <= high
{
let mid = low + (high - low) / 2;
unsafe {
if self.data[mid].assume_init_ref() == target
{
return Some(mid);
}
else if self.data[mid].assume_init_ref() < target
{
low = mid + 1;
}
else
{
match mid.checked_sub(1)
{
Some(val) => high = val,
None => return None,
}
}
}
}
None
}
}
impl<T> From<Vec<T>> for ArrayList<T>
{
fn from(vec: Vec<T>) -> Self
{
Self::from_vec(vec)
}
}
impl<T, const N: usize> From<[T; N]> for ArrayList<T>
{
fn from(arr: [T; N]) -> Self
{
Self::from_array(arr)
}
}
impl<T> Default for ArrayList<T>
{
fn default() -> Self
{
Self::new()
}
}
impl<T: Debug> Display for ArrayList<T>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
{
write!(f, "[");
for idx in 0..self.len
{
if idx > 0
{
write!(f, ", ");
}
unsafe {
write!(f, "{:?}", self.data[idx].assume_init_ref());
}
}
write!(f, "]")
}
}
impl<T> Drop for ArrayList<T>
{
fn drop(&mut self)
{
for idx in 0..self.len
{
unsafe {
self.data[idx].assume_init_drop();
}
}
}
}
pub struct IntoIter<T>
{
arr: ArrayList<T>,
}
impl<T> Iterator for IntoIter<T>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item>
{
self.arr.pop_front()
}
}
impl<T> IntoIterator for ArrayList<T>
{
type IntoIter = IntoIter<T>;
type Item = T;
fn into_iter(self) -> Self::IntoIter
{
IntoIter { arr: self }
}
}
pub struct Iter<'a, T>
{
arr: &'a ArrayList<T>,
index: usize,
}
impl<T> ArrayList<T>
{
pub fn iter(&self) -> Iter<'_, T>
{
Iter {
arr: self,
index: 0,
}
}
}
impl<'a, T> Iterator for Iter<'a, T>
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item>
{
if self.index >= self.arr.len()
{
None
}
else
{
let item = unsafe {
let ptr = self.arr.data.as_ptr().add(self.index);
(*ptr).assume_init_ref()
};
self.index += 1;
Some(item)
}
}
}
pub struct IterMut<'a, T>
{
arr: &'a mut ArrayList<T>,
index: usize,
}
impl<T> ArrayList<T>
{
pub fn iter_mut(&mut self) -> IterMut<'_, T>
{
IterMut {
arr: self,
index: 0,
}
}
}
impl<'a, T> Iterator for IterMut<'a, T>
{
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item>
{
if self.index >= self.arr.len()
{
None
}
else
{
let item = unsafe {
let ptr = self.arr.data.as_mut_ptr().add(self.index);
(*ptr).assume_init_mut()
};
self.index += 1;
Some(item)
}
}
}
impl<'a, T> IntoIterator for &'a ArrayList<T>
{
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter
{
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut ArrayList<T>
{
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter
{
self.iter_mut()
}
}
#[macro_export]
macro_rules! arrlist {
() => {
$crate::ArrayList::new()
};
($elem:expr; $n:expr) => {
{
let mut list = $crate::ArrayList::with_capacity($n);
let mut remaining = $n;
while remaining > 1 {
list.push(::core::clone::Clone::clone(&$elem)).expect("arrlist![val; n]: capacity overflow");
remaining -= 1;
}
if $n > 0 {
list.push($elem).expect("arrlist![val; n]: capacity overflow");
}
list
}
};
($($elem:expr),+ $(,)?) => {
{
let count = $crate::_count!($($elem),+);
let mut list = $crate::ArrayList::with_capacity(count);
$(list.push($elem).expect("arrlist![...]: capacity overflow");)+
list
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _count {
() => { 0usize };
($head:expr $(, $tail:expr)*) => { 1usize + $crate::_count!($($tail),*) };
}