use std::{alloc::Layout, fmt::Debug, hash::Hash, marker::PhantomData, ops::{Index, IndexMut}, ptr::NonNull, slice::SliceIndex};
pub struct ThinArray<T> {
data: Option<NonNull<u32>>,
phantom: PhantomData<T>
}
unsafe impl<T: Send> Send for ThinArray<T> {}
unsafe impl<T: Sync> Sync for ThinArray<T> {}
static_assertions::assert_eq_size!(ThinArray<usize>, usize);
impl<T: Debug> Debug for ThinArray<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", &self.as_slice())
}
}
impl<T: Hash> Hash for ThinArray<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
for item in self.iter() {
item.hash(state);
}
}
}
impl<T> ThinArray<T> {
fn layout(len: usize) -> Layout {
Layout::new::<u32>().extend(Layout::array::<T>(len).unwrap()).unwrap().0
}
pub fn new() -> Self {
ThinArray {data: None, phantom: PhantomData::default()}
}
pub fn from_results<E, U: IntoIterator<Item = Result<T, E>>>(obj: U) -> Result<Self, E> where U::IntoIter: ExactSizeIterator {
let iter = obj.into_iter();
if iter.len() == 0 {
Ok(ThinArray {data: None, phantom: PhantomData::default()})
} else {
unsafe {
let len = iter.len();
let ptr = NonNull::new(std::alloc::alloc(Self::layout(len))).unwrap().cast();
std::ptr::write(ptr.as_ptr(), len as u32);
let items_ptr = Self::get_items_ptr(ptr);
for (i, item) in iter.enumerate() {
match item {
Ok(item) => {
std::ptr::write(items_ptr.add(i), item);
}
Err(err) => {
for j in 0..i {
std::ptr::drop_in_place(items_ptr.add(j));
}
std::alloc::dealloc(ptr.cast().as_ptr(), Self::layout(len));
return Err(err);
}
}
}
Ok(ThinArray {data: Some(ptr), phantom: PhantomData::default()})
}
}
}
pub fn is_empty(&self) -> bool {
self.data.is_none()
}
unsafe fn get_items_ptr(ptr: NonNull<u32>) -> *mut T {
ptr.as_ptr().byte_add(std::mem::align_of::<T>().max(std::mem::size_of::<u32>())).cast::<T>()
}
pub fn get<I>(&self, idx: I) -> Option<&<I as SliceIndex<[T]>>::Output> where I: SliceIndex<[T]> {
self.as_slice().get(idx)
}
pub fn get_mut<I>(&mut self, idx: I) -> Option<&mut <I as SliceIndex<[T]>>::Output> where I: SliceIndex<[T]> {
self.as_slice_mut().get_mut(idx)
}
pub unsafe fn get_unchecked<I>(&self, idx: I) -> &<I as SliceIndex<[T]>>::Output where I: SliceIndex<[T]> {
self.as_slice().get_unchecked(idx)
}
pub unsafe fn get_unchecked_mut<I>(&mut self, idx: I) -> &mut <I as SliceIndex<[T]>>::Output where I: SliceIndex<[T]> {
self.as_slice_mut().get_unchecked_mut(idx)
}
pub fn as_slice(&self) -> &[T] {
self.data.map_or(&[], |ptr| unsafe {NonNull::new(
std::ptr::slice_from_raw_parts_mut(Self::get_items_ptr(ptr), self.len())
).unwrap().as_ref()})
}
pub fn as_slice_mut(&mut self) -> &mut [T] {
self.data.map_or(&mut [], |ptr| unsafe {NonNull::new(
std::ptr::slice_from_raw_parts_mut(Self::get_items_ptr(ptr), self.len())
).unwrap().as_mut()})
}
pub fn last(&self) -> Option<&T> {
self.as_slice().last()
}
pub fn len(&self) -> usize {
self.data.map_or(0, |p| *unsafe {p.as_ref()} as usize)
}
pub fn into_iter(self) -> ThinArrayIntoIter<T> {
ThinArrayIntoIter {arr: self, pos: 0}
}
pub fn iter<'a>(&'a self) -> std::slice::Iter<'a, T> {
self.as_slice().iter()
}
pub fn iter_mut<'a>(&'a mut self) -> std::slice::IterMut<'a, T> {
self.as_slice_mut().iter_mut()
}
pub fn from_two<U: IntoIterator<Item = T>, V: IntoIterator<Item = T>>(obj1: U, obj2: V) -> Self where U::IntoIter: ExactSizeIterator, V::IntoIter: ExactSizeIterator {
let iter1 = obj1.into_iter();
let iter1_len = iter1.len();
let iter2 = obj2.into_iter();
if iter1.len() + iter2.len() == 0 {
ThinArray {data: None, phantom: PhantomData::default()}
} else {
unsafe {
let len = iter1_len + iter2.len();
let ptr = NonNull::new(std::alloc::alloc(Self::layout(len))).unwrap().cast();
std::ptr::write(ptr.as_ptr(), len as u32);
let items_ptr = Self::get_items_ptr(ptr);
for (i, item) in iter1.enumerate() {
std::ptr::write(items_ptr.add(i), item);
}
for (i, item) in iter2.enumerate() {
std::ptr::write(items_ptr.add(iter1_len + i), item);
}
ThinArray {data: Some(ptr), phantom: PhantomData::default()}
}
}
}
}
impl<T> Drop for ThinArray<T> {
fn drop(&mut self) {
if let Some(ptr) = self.data.take() {
unsafe {
let items_ptr = Self::get_items_ptr(ptr);
let len = self.len();
for i in 0..len {
std::ptr::drop_in_place(items_ptr.add(i));
}
std::alloc::dealloc(ptr.cast().as_ptr(), Self::layout(len));
}
}
}
}
impl<T: PartialEq> PartialEq for ThinArray<T> {
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() || self.iter().zip(other.iter()).all(|(x, y)| x == y)
}
}
impl<T: Eq> Eq for ThinArray<T> {}
impl<T: Clone> Clone for ThinArray<T> {
fn clone(&self) -> Self {
self.iter().cloned().into()
}
}
impl<T> Default for ThinArray<T> {
fn default() -> Self {
Self::new()
}
}
impl<T, R: SliceIndex<[T]>> Index<R> for ThinArray<T> {
type Output = R::Output;
fn index(&self, index: R) -> &Self::Output {
&self.as_slice()[index]
}
}
impl<T, R: SliceIndex<[T]>> IndexMut<R> for ThinArray<T> {
fn index_mut(&mut self, index: R) -> &mut Self::Output {
&mut self.as_slice_mut()[index]
}
}
impl<T, U: IntoIterator<Item = T>> From<U> for ThinArray<T> where U::IntoIter: ExactSizeIterator {
fn from(obj: U) -> Self where U::IntoIter: ExactSizeIterator {
let iter = obj.into_iter();
if iter.len() == 0 {
ThinArray {data: None, phantom: PhantomData::default()}
} else {
unsafe {
let len = iter.len();
let ptr = NonNull::new(std::alloc::alloc(Self::layout(len))).unwrap().cast();
std::ptr::write(ptr.as_ptr(), len as u32);
let items_ptr = Self::get_items_ptr(ptr);
for (i, item) in iter.enumerate() {
std::ptr::write(items_ptr.add(i), item);
}
ThinArray {data: Some(ptr), phantom: PhantomData::default()}
}
}
}
}
impl<'a, T> IntoIterator for &'a ThinArray<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut ThinArray<T> {
type Item = &'a mut T;
type IntoIter = std::slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
pub struct ThinArrayIntoIter<T> {
arr: ThinArray<T>,
pos: usize
}
impl<T> Iterator for ThinArrayIntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.arr.len() {
None
} else {
self.pos += 1;
Some(unsafe {std::ptr::read(&self.arr[self.pos - 1])})
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.arr.len() - self.pos;
(len, Some(len))
}
}
impl<T> ExactSizeIterator for ThinArrayIntoIter<T> {
fn len(&self) -> usize {
self.arr.len() - self.pos
}
}
impl<T> Drop for ThinArrayIntoIter<T> {
fn drop(&mut self) {
while self.next().is_some() {}
unsafe {std::ptr::write(&mut self.arr, ThinArray::new())}
self.arr.as_slice();
}
}
#[test]
fn test() {
let arr: ThinArray<_> = [1, 3].into();
assert_eq!(arr.len(), 2);
assert_eq!(arr[0], 1);
assert_eq!(arr[1], 3);
}