diff --git a/src/lib.rs b/src/lib.rs index a25f5fc..c42c850 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,10 @@ use core::panic; #[cfg(feature = "only_store_meta")] use std::{ptr::Pointee, mem::align_of_val_raw}; use std::{ - ptr::{NonNull, self, drop_in_place, metadata}, + ptr::{NonNull, self, drop_in_place, metadata, Pointee}, marker::PhantomData, alloc::{alloc, Layout}, - mem::{size_of, size_of_val, align_of_val, self, size_of_val_raw}, + mem::{size_of, size_of_val, align_of_val, self, size_of_val_raw, align_of_val_raw}, slice, fmt::Debug, ops::{CoerceUnsized, Index, IndexMut} @@ -44,67 +44,81 @@ fn align_up_mut(ptr: *mut T, align: usize) -> *mut T { align_up(ptr as _, align) as _ } +trait Strategy: Sized { + type Metadata: Copy; + + unsafe fn get_ptr(vec: &Vec, index: usize) -> *const T; + + unsafe fn next(vec: &Vec, prev: *const T, index: usize) -> *const T; + + fn create_meta_from_ptr(vec: &Vec, ptr: *const T) -> Self::Metadata; +} + +struct StorePtr; + +impl Strategy for StorePtr { + type Metadata = *const T; + + unsafe fn get_ptr(vec: &Vec, index: usize) -> *const T { + vec.get_ptr_to_meta(index + 1).cast::<*const T>().read() + } + + unsafe fn next(vec: &Vec, _prev: *const T, index: usize) -> *const T { + Self::get_ptr(vec, index) + } + + fn create_meta_from_ptr(_vec: &Vec, ptr: *const T) -> Self::Metadata { + ptr + } +} + +struct OnlyStoreMeta; + +impl Strategy for OnlyStoreMeta { + type Metadata = ::Metadata; + + unsafe fn get_ptr(vec: &Vec, index: usize) -> *const T { + let meta = vec.get_ptr_to_meta(1).cast::<::Metadata>().read(); + let fake = ptr::from_raw_parts::(0 as _, meta); + let ptr = align_up(vec.ptr.as_ptr(), align_of_val_raw(fake)); + let mut ptr = ptr::from_raw_parts(ptr.cast(), meta); + + for index in 1..=index { + ptr = Self::next(vec, ptr, index); + } + + ptr + } + + unsafe fn next(vec: &Vec, prev: *const T, index: usize) -> *const T { + let ptr = prev.cast::().wrapping_add(size_of_val_raw(prev)); + + let meta = vec.get_ptr_to_meta(index + 1).cast::<::Metadata>().read(); + let fake = ptr::from_raw_parts::(0 as _, meta); + let ptr = align_up(ptr, align_of_val_raw(fake)); + ptr::from_raw_parts(ptr.cast(), meta) + } + + fn create_meta_from_ptr(_vec: &Vec, ptr: *const T) -> Self::Metadata { + metadata(ptr) + } +} + /// A heap allocated, dynamically sized collection of `?Sized` elements. /// /// See [`::alloc::vec::Vec`] (the standard library `Vec` type) for more information. -pub struct Vec { +struct Vec> { ptr: NonNull, len: usize, capacity: usize, end_ptr: NonNull, - _phantom: PhantomData + _phantom: PhantomData<(*mut S, T)> } -impl std::fmt::Debug for Vec { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_list().entries(self.iter()).finish() - } -} - -// Vec == Vec -impl, U: ?Sized> PartialEq> for Vec { - fn eq(&self, other: &Vec) -> bool { - if self.len != other.len { return false } - for (el, el2) in self.iter().zip(other.iter()) { - if el != el2 { return false } - } - true - } -} - -impl Eq for Vec {} - -// Vec == &[U] -impl, U> PartialEq<&[U]> for Vec { - fn eq(&self, other: &&[U]) -> bool { - if self.len != other.len() { return false } - for (el, el2) in self.iter().zip(other.iter()) { - if el != el2 { return false } - } - true - } -} - -// &[U] == Vec -impl, U> PartialEq> for &[U] { - fn eq(&self, other: &Vec) -> bool { - other == self - } -} - -// Vec == [U; N] -impl, U, const N: usize> PartialEq<[U; N]> for Vec { - fn eq(&self, other: &[U; N]) -> bool { - *self == &other[..] - } -} - -// [U; N] == Vec -impl, U, const N: usize> PartialEq> for [U; N] { - fn eq(&self, other: &Vec) -> bool { - other == self - } -} +// keeps this file cleaner +mod impls; +mod iter; +pub use iter::*; /// The data stored as metadata at the end of the allocation. #[cfg(feature = "only_store_meta")] @@ -122,7 +136,7 @@ unsafe fn align_of_val_meta(meta: Meta) -> usize { align_of_val_raw(ptr::from_raw_parts::(0 as *const (), meta)) } -impl Vec { +impl> Vec { /// Creates a new, empty `Vec`. pub fn new() -> Self { let ptr = NonNull::dangling(); @@ -136,6 +150,8 @@ impl Vec { } /// Appends an element to the end of the `Vec`. + /// + /// Only avaliable if `T: Sized`. pub fn push(&mut self, v: T) where T: Sized { unsafe { self.push_raw(&v) } mem::forget(v); @@ -166,7 +182,7 @@ impl Vec { // make sure we have enough space for a new element, but also space for future elements // this bit is tricky, we must make sure we have enough space for padding too, so its probably UB somehow // FIXME: ^^^ - let new_alloc_size = self.capacity * 2 + size * 2 + size_of::>(); + let new_alloc_size = self.capacity * 2 + size * 2 + size_of::(); self.realloc(new_alloc_size); } @@ -178,14 +194,14 @@ impl Vec { /// The pointer will be aligned, but writing to it may overwrite data belonging to the Vec. /// To check for this, call `will_fit`. /// In addition, the metedata for the element must be set using `set_meta_from_ptr`. - pub fn get_next_elem_ptr(&self, v: &T) -> *mut u8 { + fn get_next_elem_ptr(&self, v: &T) -> *mut u8 { align_up_mut(self.end_ptr.as_ptr(), align_of_val(v)) } /// Checks if a given element will fill in the `Vec` without reallocations. pub fn will_fit(&self, v: &T) -> bool { let remaining_space = self.get_ptr_to_meta(self.len) as usize - self.end_ptr.as_ptr() as usize; - let needed_space = size_of_val(v) + size_of::>(); + let needed_space = size_of_val(v) + size_of::(); remaining_space >= needed_space } @@ -250,46 +266,24 @@ impl Vec { /// for internal use /// /// NOTE: 1-indexed, to allow getting a pointer to the end of the alloc easily - fn get_ptr_to_meta(&self, index: usize) -> *mut Meta { + fn get_ptr_to_meta(&self, index: usize) -> *mut S::Metadata { self.ptr.as_ptr() .wrapping_add(self.capacity) - .cast::>() + .cast::() .wrapping_sub(index) } /// for internal use - unsafe fn get_meta(&self, index: usize) -> Meta { + unsafe fn get_meta(&self, index: usize) -> S::Metadata { *self.get_ptr_to_meta(index + 1) } unsafe fn set_meta_from_ptr(&self, index: usize, ptr: *const T) { - #[cfg(feature = "only_store_meta")] - self.get_ptr_to_meta(index + 1).write(metadata(ptr)); - - #[cfg(not(feature = "only_store_meta"))] - self.get_ptr_to_meta(index + 1).write(ptr); + self.get_ptr_to_meta(index + 1).write(S::create_meta_from_ptr(self, ptr)); } unsafe fn get_ptr(&self, index: usize) -> *const T { - #[cfg(feature = "only_store_meta")] - { - let mut ptr = self.ptr.as_ptr(); - - for i in 0..index { - let meta = self.get_meta(i); - let align = align_of_val_meta::(meta); - let size = size_of_val_meta::(meta); - - ptr = align_up_mut(ptr, align).wrapping_add(size); - } - - let meta = self.get_meta(index); - let align = align_of_val_meta::(meta); - ptr::from_raw_parts(align_up_mut(ptr, align).cast(), meta) - } - - #[cfg(not(feature = "only_store_meta"))] - self.get_meta(index) + S::get_ptr(self, index) } pub fn get(&self, index: usize) -> Option<&T> { @@ -347,7 +341,7 @@ impl Vec { } /// Converts a `Vec` into a `Vec`, given that `T` can be `CoerceUnsized` into `U`. - pub fn unsize(self) -> Vec where for<'a> &'a T: CoerceUnsized<&'a U> { + pub fn unsize(self) -> Vec where for<'a> &'a T: CoerceUnsized<&'a U>, S: Strategy { let new_vec = Vec:: { ptr: self.ptr, len: self.len, @@ -356,7 +350,7 @@ impl Vec { _phantom: PhantomData, }; - if size_of::>() > size_of::>() { + if size_of::<>::Metadata>() > size_of::<>::Metadata>() { // new meta larger than old meta, must go from back to front for i in (0..self.len).rev() { @@ -417,231 +411,6 @@ impl Drop for Vec { } } - -// Iteration -struct BaseIter { - ptr: *const Meta, - ptr_back: *const Meta, - #[cfg(feature = "only_store_meta")] - running_ptr: *mut u8, - // #[cfg(feature = "only_store_meta")] - // running_ptr_back: *mut u8 -} - -impl BaseIter { - fn new(vec: &Vec) -> Self { - Self { - ptr: vec.get_ptr_to_meta(vec.len), - ptr_back: vec.get_ptr_to_meta(0), - #[cfg(feature = "only_store_meta")] - running_ptr: vec.ptr.as_ptr(), - // #[cfg(feature = "only_store_meta")] - // running_ptr_back: vec.end_ptr.as_ptr() - } - } -} - -impl Iterator for BaseIter { - type Item = *mut T; - - fn next(&mut self) -> Option { - if self.ptr == self.ptr_back { - return None - } - - self.ptr_back = self.ptr_back.wrapping_sub(1); - #[cfg(not(feature = "only_store_meta"))] - { - Some(unsafe { self.ptr_back.read() as *mut T }) - } - #[cfg(feature = "only_store_meta")] - unsafe { - let meta = self.ptr_back.read(); - self.running_ptr = align_up_mut(self.running_ptr, align_of_val_meta::(meta)); - let ret = ptr::from_raw_parts_mut(self.running_ptr.cast(), meta); - self.running_ptr = self.running_ptr.wrapping_add(size_of_val_meta::(meta)); - Some(ret) - } - } -} - -#[cfg(not(feature = "only_store_meta"))] -impl DoubleEndedIterator for BaseIter { - fn next_back(&mut self) -> Option { - if self.ptr == self.ptr_back { - return None - } - - let el = unsafe { self.ptr.read() }; - self.ptr = self.ptr.wrapping_add(1); - Some(el as *mut T) - } -} - - -// By-ref iteration -impl<'a, T: ?Sized> IntoIterator for &'a Vec { - type Item = &'a T; - - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -pub struct Iter<'a, T: ?Sized> { - base: BaseIter, - _phantom: PhantomData<&'a T> -} - -impl<'a, T: ?Sized> Iter<'a, T> { - pub fn new(vec: &'a Vec) -> Self { - Self { base: BaseIter::new(vec), _phantom: PhantomData } - } -} - -impl<'a, T: ?Sized> Iterator for Iter<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option { - unsafe { self.base.next().map(|v| &*v) } - } -} - -#[cfg(not(feature = "only_store_meta"))] -impl<'a, T: ?Sized> DoubleEndedIterator for Iter<'a, T> { - fn next_back(&mut self) -> Option { - unsafe { self.base.next_back().map(|v| &*v) } - } -} - - -// By-mut iteration -impl<'a, T: ?Sized> IntoIterator for &'a mut Vec { - type Item = &'a mut T; - - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } -} - -pub struct IterMut<'a, T: ?Sized> { - base: BaseIter, - _phantom: PhantomData<&'a mut T> -} - -impl<'a, T: ?Sized> IterMut<'a, T> { - pub fn new(vec: &'a mut Vec) -> Self { - Self { base: BaseIter::new(vec), _phantom: PhantomData } - } -} - -impl<'a, T: ?Sized> Iterator for IterMut<'a, T> { - type Item = &'a mut T; - - fn next(&mut self) -> Option { - unsafe { self.base.next().map(|v| &mut *v) } - } -} - -#[cfg(not(feature = "only_store_meta"))] -impl<'a, T: ?Sized> DoubleEndedIterator for IterMut<'a, T> { - fn next_back(&mut self) -> Option { - unsafe { self.base.next_back().map(|v| &mut *v) } - } -} - - -// By-value iteration -impl IntoIterator for Vec { - type Item = Box; - - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter::new(self) - } -} - -pub struct IntoIter { - ptr: NonNull, - capacity: usize, - base: BaseIter -} - -impl IntoIter { - pub fn new(vec: Vec) -> Self { - let this = Self { - ptr: vec.ptr, - capacity: vec.capacity, - base: BaseIter::new(&vec) - }; - mem::forget(vec); - this - } -} - -impl Iterator for IntoIter { - type Item = Box; - - fn next(&mut self) -> Option { - let ptr = self.base.next()?; - unsafe { - let alloc = alloc(Layout::for_value_raw(ptr)); - memcpy(ptr.cast(), alloc, size_of_val_raw(ptr)); - Some(Box::from_raw(ptr::from_raw_parts_mut(alloc.cast(), metadata(ptr)))) - } - } -} - -#[cfg(not(feature = "only_store_meta"))] -impl DoubleEndedIterator for IntoIter { - fn next_back(&mut self) -> Option { - let ptr = self.base.next_back()?; - unsafe { - let alloc = alloc(Layout::for_value_raw(ptr)); - memcpy(ptr.cast(), alloc, size_of_val_raw(ptr)); - Some(Box::from_raw(ptr::from_raw_parts_mut(alloc.cast(), metadata(ptr)))) - } - } -} - -impl Drop for IntoIter { - fn drop(&mut self) { - unsafe { dealloc(self.ptr.as_ptr(), Layout::from_size_align_unchecked(self.capacity, 8)) } - } -} - - -// // this implementation will collect *while unsizing*, and would conflict with the other -// impl FromIterator for Vec where for<'a> &'a U: CoerceUnsized<&'a T> { -// fn from_iter>(iter: I) -> Self { -// let mut vec = Vec::new(); - -// for item in iter.into_iter() { -// vec.push_unsize(item); -// } - -// vec -// } -// } - -impl FromIterator for Vec { - fn from_iter>(iter: I) -> Self { - let mut vec = Vec::new(); - - for item in iter.into_iter() { - vec.push(item); - } - - vec - } -} - - impl Index for Vec { type Output = T; @@ -665,7 +434,6 @@ impl IndexMut for Vec { } } - /// Creates a [`Vec`]. /// /// # Examples @@ -697,7 +465,7 @@ macro_rules! vec { vec }}; ($elem:expr; $n:expr) => { - unimplemented!("vec![T; N] is currently not supported"); + compile_error!("dyn_vec::vec![T; N] is currently not supported"); }; ($($elem:expr),+ $(,)?) => {{ let mut vec = $crate::Vec::new();