From c15e2488423d743365fef2213f9340bab17c353b Mon Sep 17 00:00:00 2001 From: tower120 Date: Tue, 21 Jun 2022 23:56:43 +0300 Subject: [PATCH 01/35] MemBuilder * mem module staff * AnyVecPtr refactor * AnyVec reserve/shrink tests added * AnyVecTyped reserve/shrink * clone_empty_in added * pop added * Refactor: TempValue Operation::Type removed * iter bench added --- CHANGELOG.md | 12 +++ Cargo.toml | 4 + Readme.md | 34 +++++++ benches/iter.rs | 58 ++++++++++++ src/any_vec.rs | 200 ++++++++++++++++++++++++++++----------- src/any_vec_ptr.rs | 62 ++++++------ src/any_vec_raw.rs | 187 +++++++++++++++++------------------- src/any_vec_typed.rs | 86 +++++++++++++---- src/element.rs | 38 ++++---- src/iter.rs | 57 +++++++---- src/lib.rs | 44 +++++++++ src/mem/heap.rs | 113 ++++++++++++++++++++++ src/mem/mod.rs | 73 ++++++++++++++ src/mem/stack.rs | 47 +++++++++ src/ops/drain.rs | 9 +- src/ops/mod.rs | 17 +++- src/ops/pop.rs | 47 +++++++++ src/ops/remove.rs | 12 +-- src/ops/splice.rs | 24 +++-- src/ops/swap_remove.rs | 21 ++-- src/ops/temp.rs | 52 +++++----- tests/any_vec.rs | 76 +++++++++++++++ tests/any_vec_element.rs | 9 +- tests/any_vec_typed.rs | 24 +++++ 24 files changed, 1003 insertions(+), 303 deletions(-) create mode 100644 benches/iter.rs create mode 100644 src/mem/heap.rs create mode 100644 src/mem/mod.rs create mode 100644 src/mem/stack.rs create mode 100644 src/ops/pop.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index d27d5aa..891504a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## Unreleased +### Added +- `pop` +- `is_empty` +- `AnyVec::clone_empty_in` +- `Stack` Mem/Allocator. +- `MemBuilder` + `Mem` = Allocator. +- `reserve` +- `reserve_exact` +- `shrink_to_fit` +- `shrink_to` + ## 0.8.0 ### Added - Added `AnyVec::at` - ergonomic version of `get`. diff --git a/Cargo.toml b/Cargo.toml index 6f78561..642a5c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,4 +37,8 @@ harness = false [[bench]] name = "drain" +harness = false + +[[bench]] +name = "iter" harness = false \ No newline at end of file diff --git a/Readme.md b/Readme.md index a7a927f..6c7383c 100644 --- a/Readme.md +++ b/Readme.md @@ -33,6 +33,8 @@ Only destruct operations have additional overhead of indirect call. } ``` +See [documentation](https://docs.rs/any_vec) for more. + ## Send, Sync, Clone You can make `AnyVec` `Send`able, `Sync`able, `Clone`able: @@ -62,6 +64,38 @@ let v1: AnyVec = AnyVec::new::>(); v2.push(e.lazy_clone()); ``` +## MemBuilder + + `MemBuilder` + `Mem` works like `Allocator` for `AnyVec`. But unlike allocator, + `Mem` container-specialized design allows to perform more optimizations. For example, + it is possible to make stack-allocated `FixedAnyVec` and small-buffer-optimized(SBO) `SmallAnyVec` + from `AnyVec` by just changing `MemBuilder`: + +```rust +type FixedAnyVec = AnyVec>; +let mut any_vec: FixedAnyVec = AnyVec::new::(); + +// This will be on stack, without any allocations. +any_vec.push(AnyValueWrapper::new(String::from("0"))) +``` + + With help of `clone_empty_in` you can use stack allocated, or SBO `AnyVec` + as fast intermediate storage for values of unknown type: + +```rust +fn self_push_first_element(any_vec: &mut AnyVec){ + let mut tmp = any_vec.clone_empty_in(Stack::<256>); + tmp.push(any_vec.at(0).lazy_clone()); + any_vec.push(tmp.pop().unwrap()); +} +``` + + `MemBuilder` interface, being stateful, allow to make `Mem`, which can work with complex custom allocators. + +### Changelog + +See [CHANGELOG.md](CHANGELOG.md) for version differences. + #### N.B. *Currently, minimum rust version is 1.61. This is to simplify implementation. diff --git a/benches/iter.rs b/benches/iter.rs new file mode 100644 index 0000000..389ed80 --- /dev/null +++ b/benches/iter.rs @@ -0,0 +1,58 @@ +mod utils; + +use std::time::{Duration, Instant}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use any_vec::AnyVec; +use crate::utils::bench_custom; + +const SIZE: usize = 10000; + +fn vec_iter() -> Duration { + let mut vec = Vec::new(); + for i in 0..SIZE{ + vec.push(i); + } + + let start = Instant::now(); + let sum: usize = vec.iter().sum(); + black_box(sum); + start.elapsed() +} + +fn any_vec_typed_iter() -> Duration { + let mut any_vec: AnyVec = AnyVec::new::(); + let mut any_vec_typed = any_vec.downcast_mut::().unwrap(); + for i in 0..SIZE{ + any_vec_typed.push(i); + } + + let start = Instant::now(); + let sum: usize = any_vec_typed.iter().sum(); + black_box(sum); + start.elapsed() +} + +fn any_vec_iter() -> Duration { + let mut any_vec: AnyVec = AnyVec::new::(); + for i in 0..SIZE{ + any_vec.downcast_mut::().unwrap() + .push(i); + } + + let start = Instant::now(); + let sum: usize = any_vec.iter() + //.map(|e|e.downcast_ref().unwrap()) + .map(|e|unsafe{e.downcast_ref_unchecked()}) + .sum(); + black_box(sum); + start.elapsed() +} + +pub fn bench_iter(c: &mut Criterion) { + bench_custom(c, "Vec iter", vec_iter); + bench_custom(c, "AnyVecTyped iter", any_vec_typed_iter); + bench_custom(c, "AnyVec iter", any_vec_iter); +} + +criterion_group!(benches, bench_iter); +criterion_main!(benches); \ No newline at end of file diff --git a/src/any_vec.rs b/src/any_vec.rs index 679d02f..646bf0d 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -5,16 +5,17 @@ use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut, Range, RangeBounds}; use std::ptr::NonNull; use std::slice; -use crate::{AnyVecTyped, into_range, ops}; +use crate::{AnyVecTyped, into_range, mem, ops}; use crate::any_value::{AnyValue}; use crate::any_vec_raw::AnyVecRaw; -use crate::ops::{TempValue, Remove, SwapRemove, remove, swap_remove}; +use crate::ops::{TempValue, Remove, SwapRemove, remove, swap_remove, Pop, pop}; use crate::ops::{Drain, Splice, drain, splice}; use crate::any_vec::traits::{None}; use crate::clone_type::{CloneFn, CloneFnTrait, CloneType}; use crate::element::{ElementPointer, Element, ElementMut, ElementRef}; use crate::any_vec_ptr::AnyVecPtr; use crate::iter::{Iter, IterMut, IterRef}; +use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemResizable}; use crate::traits::{Cloneable, Trait}; /// Trait constraints. @@ -93,37 +94,69 @@ impl SatisfyTraits for T{} /// You can make AnyVec [`Send`]-able, [`Sync`]-able, [`Cloneable`], by /// specifying trait constraints: `AnyVec`. See [`traits`]. /// -/// Some operations return [`TempValue`], which internally holds &mut to [`AnyVec`]. +/// Some operations return [`TempValue`], which internally holds &mut to [`AnyVec`]. /// You can drop it, cast to concrete type, or put into another vector. (See [`AnyValue`]) /// /// *`Element: 'static` due to TypeId requirements* -pub struct AnyVec +pub struct AnyVec { - pub(crate) raw: AnyVecRaw, + pub(crate) raw: AnyVecRaw, clone_fn: ::Type, phantom: PhantomData } -impl AnyVec +impl AnyVec { + #[inline] + fn build>(raw: AnyVecRaw) -> Self { + let clone_fn = >::CLONE_FN; + Self{ + raw, + clone_fn: ::new(clone_fn), + phantom: PhantomData + } + } + /// Element should implement requested Traits #[inline] - pub fn new() -> Self - where Element: SatisfyTraits + pub fn new() -> Self + where + T: SatisfyTraits, + M: Default { - Self::with_capacity::(0) + Self::new_in::(Default::default()) } /// Element should implement requested Traits - pub fn with_capacity(capacity: usize) -> Self - where Element: SatisfyTraits + #[inline] + pub fn new_in(mut mem_builder: M) -> Self + where T: SatisfyTraits { - let clone_fn = >::CLONE_FN; - Self{ - raw: AnyVecRaw::with_capacity::(capacity), - clone_fn: ::new(clone_fn), - phantom: PhantomData - } + let mem = mem_builder.build(Layout::new::()); + let raw = AnyVecRaw::new::(mem_builder, mem); + Self::build::(raw) + } + + /// Element should implement requested Traits + #[inline] + pub fn with_capacity(capacity: usize) -> Self + where + T: SatisfyTraits, + M: MemBuilderSizeable, + M: Default + { + Self::with_capacity_in::(capacity, Default::default()) + } + + /// Element should implement requested Traits + pub fn with_capacity_in(capacity: usize, mut mem_builder: M) -> Self + where + T: SatisfyTraits, + M: MemBuilderSizeable + { + let mem = mem_builder.build_with_size(Layout::new::(), capacity); + let raw = AnyVecRaw::new::(mem_builder, mem); + Self::build::(raw) } /// Same as clone, but without data copy. @@ -139,13 +172,50 @@ impl AnyVec } } + #[inline] + pub fn clone_empty_in(&self, mem_builder: NewM) -> AnyVec { + AnyVec { + raw: self.raw.clone_empty_in(mem_builder), + clone_fn: self.clone_fn, + phantom: PhantomData + } + } + #[inline] pub(crate) fn clone_fn(&self) -> Option{ ::get(self.clone_fn) } #[inline] - pub fn downcast_ref(&self) -> Option> { + pub fn reserve(&mut self, additional: usize) + where M::Mem: MemResizable + { + self.raw.reserve(additional) + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) + where M::Mem: MemResizable + { + self.raw.reserve_exact(additional) + } + + #[inline] + pub fn shrink_to_fit(&mut self) + where M::Mem: MemResizable + { + self.raw.shrink_to_fit() + } + + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) + where M::Mem: MemResizable + { + self.raw.shrink_to(min_capacity) + } + + #[inline] + pub fn downcast_ref(&self) -> Option> { if self.element_typeid() == TypeId::of::() { unsafe{ Some(self.downcast_ref_unchecked()) } } else { @@ -154,12 +224,12 @@ impl AnyVec } #[inline] - pub unsafe fn downcast_ref_unchecked(&self) -> AnyVecRef { + pub unsafe fn downcast_ref_unchecked(&self) -> AnyVecRef { AnyVecRef(AnyVecTyped::new(NonNull::from(&self.raw))) } #[inline] - pub fn downcast_mut(&mut self) -> Option> { + pub fn downcast_mut(&mut self) -> Option> { if self.element_typeid() == TypeId::of::() { unsafe{ Some(self.downcast_mut_unchecked()) } } else { @@ -168,7 +238,7 @@ impl AnyVec } #[inline] - pub unsafe fn downcast_mut_unchecked(&mut self) -> AnyVecMut { + pub unsafe fn downcast_mut_unchecked(&mut self) -> AnyVecMut { AnyVecMut(AnyVecTyped::new(NonNull::from(&mut self.raw))) } @@ -178,18 +248,18 @@ impl AnyVec } #[inline] - pub fn iter(&self) -> IterRef{ + pub fn iter(&self) -> IterRef{ Iter::new(AnyVecPtr::from(self), 0, self.len()) } #[inline] - pub fn iter_mut(&mut self) -> IterMut{ + pub fn iter_mut(&mut self) -> IterMut{ let len = self.len(); Iter::new(AnyVecPtr::from(self), 0, len) } #[inline] - unsafe fn get_element(&self, index: usize) -> ManuallyDrop>{ + unsafe fn get_element(&self, index: usize) -> ManuallyDrop>{ let element = NonNull::new_unchecked( self.as_bytes().add(self.element_layout().size() * index) as *mut u8 ); @@ -205,12 +275,12 @@ impl AnyVec /// /// * Panics if index is out of bounds. #[inline] - pub fn at(&self, index: usize) -> ElementRef{ + pub fn at(&self, index: usize) -> ElementRef{ self.get(index).unwrap() } #[inline] - pub fn get(&self, index: usize) -> Option>{ + pub fn get(&self, index: usize) -> Option>{ if index < self.len(){ Some(unsafe{ self.get_unchecked(index) }) } else { @@ -219,7 +289,7 @@ impl AnyVec } #[inline] - pub unsafe fn get_unchecked(&self, index: usize) -> ElementRef{ + pub unsafe fn get_unchecked(&self, index: usize) -> ElementRef{ ElementRef(self.get_element(index)) } @@ -229,12 +299,12 @@ impl AnyVec /// /// * Panics if index is out of bounds. #[inline] - pub fn at_mut(&mut self, index: usize) -> ElementMut{ + pub fn at_mut(&mut self, index: usize) -> ElementMut{ self.get_mut(index).unwrap() } #[inline] - pub fn get_mut(&mut self, index: usize) -> Option>{ + pub fn get_mut(&mut self, index: usize) -> Option>{ if index < self.len(){ Some(unsafe{ self.get_unchecked_mut(index) }) } else { @@ -243,7 +313,7 @@ impl AnyVec } #[inline] - pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> ElementMut { + pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> ElementMut { ElementMut(self.get_element(index)) } @@ -252,6 +322,7 @@ impl AnyVec /// * Panics if type mismatch. /// * Panics if index is out of bounds. /// * Panics if out of memory. + #[inline] pub fn insert(&mut self, index: usize, value: V) { self.raw.type_check(&value); unsafe{ @@ -271,6 +342,24 @@ impl AnyVec } } + /// # Leaking + /// + /// If the returned [`TempValue`] goes out of scope without being dropped (due to + /// [`mem::forget`], for example), the vector will lost and leak last element. + /// + /// [`mem::forget`]: std::mem::forget + /// + #[inline] + pub fn pop(&mut self) -> Option> { + if self.is_empty(){ + None + } else { + Some(TempValue::new( + pop::Pop::new(AnyVecPtr::from(self)) + )) + } + } + /// # Panics /// /// * Panics if index out of bounds. @@ -284,7 +373,7 @@ impl AnyVec /// [`mem::forget`]: std::mem::forget /// #[inline] - pub fn remove(&mut self, index: usize) -> Remove { + pub fn remove(&mut self, index: usize) -> Remove { self.raw.index_check(index); TempValue::new(remove::Remove::new( AnyVecPtr::from(self), @@ -305,7 +394,7 @@ impl AnyVec /// [`mem::forget`]: std::mem::forget /// #[inline] - pub fn swap_remove(&mut self, index: usize) -> SwapRemove { + pub fn swap_remove(&mut self, index: usize) -> SwapRemove { self.raw.index_check(index); TempValue::new(swap_remove::SwapRemove::new( AnyVecPtr::from(self), @@ -333,7 +422,7 @@ impl AnyVec /// [`mem::forget`]: std::mem::forget /// #[inline] - pub fn drain(&mut self, range: impl RangeBounds) -> Drain { + pub fn drain(&mut self, range: impl RangeBounds) -> Drain { let Range{start, end} = into_range(self.len(), range); ops::Iter(drain::Drain::new( AnyVecPtr::from(self), @@ -365,7 +454,7 @@ impl AnyVec /// #[inline] pub fn splice(&mut self, range: impl RangeBounds, replace_with: I) - -> Splice + -> Splice where I::IntoIter: ExactSizeIterator, I::Item: AnyValue @@ -401,15 +490,20 @@ impl AnyVec self.raw.len } + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + #[inline] pub fn capacity(&self) -> usize { self.raw.capacity() } } -unsafe impl Send for AnyVec {} -unsafe impl Sync for AnyVec {} -impl Clone for AnyVec +unsafe impl Send for AnyVec {} +unsafe impl Sync for AnyVec {} +impl Clone for AnyVec { fn clone(&self) -> Self { Self{ @@ -420,9 +514,9 @@ impl Clone for AnyVec } } -impl<'a, Traits: ?Sized + Trait> IntoIterator for &'a AnyVec{ - type Item = ElementRef<'a, Traits>; - type IntoIter = IterRef<'a, Traits>; +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> IntoIterator for &'a AnyVec{ + type Item = ElementRef<'a, Traits, M>; + type IntoIter = IterRef<'a, Traits, M>; #[inline] fn into_iter(self) -> Self::IntoIter { @@ -430,9 +524,9 @@ impl<'a, Traits: ?Sized + Trait> IntoIterator for &'a AnyVec{ } } -impl<'a, Traits: ?Sized + Trait> IntoIterator for &'a mut AnyVec{ - type Item = ElementMut<'a, Traits>; - type IntoIter = IterMut<'a, Traits>; +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> IntoIterator for &'a mut AnyVec{ + type Item = ElementMut<'a, Traits, M>; + type IntoIter = IterMut<'a, Traits, M>; #[inline] fn into_iter(self) -> Self::IntoIter { @@ -446,22 +540,22 @@ impl<'a, Traits: ?Sized + Trait> IntoIterator for &'a mut AnyVec{ /// /// [`AnyVec`]: crate::AnyVec /// [`AnyVec::downcast_ref`]: crate::AnyVec::downcast_ref -pub struct AnyVecRef<'a, T: 'static>(pub(crate) AnyVecTyped<'a, T>); -impl<'a, T: 'static> Clone for AnyVecRef<'a, T>{ +pub struct AnyVecRef<'a, T: 'static, M: MemBuilder + 'a>(pub(crate) AnyVecTyped<'a, T, M>); +impl<'a, T: 'static, M: MemBuilder + 'a> Clone for AnyVecRef<'a, T, M>{ #[inline] fn clone(&self) -> Self { Self(self.0.clone()) } } -impl<'a, T: 'static> Deref for AnyVecRef<'a, T>{ - type Target = AnyVecTyped<'a, T>; +impl<'a, T: 'static, M: MemBuilder + 'a> Deref for AnyVecRef<'a, T, M>{ + type Target = AnyVecTyped<'a, T, M>; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } -impl<'a, T: 'static> IntoIterator for AnyVecRef<'a, T>{ +impl<'a, T: 'static, M: MemBuilder + 'a> IntoIterator for AnyVecRef<'a, T, M>{ type Item = &'a T; type IntoIter = slice::Iter<'a, T>; @@ -477,22 +571,22 @@ impl<'a, T: 'static> IntoIterator for AnyVecRef<'a, T>{ /// /// [`AnyVec`]: crate::AnyVec /// [`AnyVec::downcast_mut`]: crate::AnyVec::downcast_mut -pub struct AnyVecMut<'a, T: 'static>(pub(crate) AnyVecTyped<'a, T>); -impl<'a, T: 'static> Deref for AnyVecMut<'a, T>{ - type Target = AnyVecTyped<'a, T>; +pub struct AnyVecMut<'a, T: 'static, M: MemBuilder + 'a>(pub(crate) AnyVecTyped<'a, T, M>); +impl<'a, T: 'static, M: MemBuilder + 'a> Deref for AnyVecMut<'a, T, M>{ + type Target = AnyVecTyped<'a, T, M>; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } -impl<'a, T: 'static> DerefMut for AnyVecMut<'a, T>{ +impl<'a, T: 'static, M: MemBuilder + 'a> DerefMut for AnyVecMut<'a, T, M>{ #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } -impl<'a, T: 'static> IntoIterator for AnyVecMut<'a, T>{ +impl<'a, T: 'static, M: MemBuilder + 'a> IntoIterator for AnyVecMut<'a, T, M>{ type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; diff --git a/src/any_vec_ptr.rs b/src/any_vec_ptr.rs index 99ec0fa..f059a1c 100644 --- a/src/any_vec_ptr.rs +++ b/src/any_vec_ptr.rs @@ -5,30 +5,33 @@ use std::ptr::NonNull; use crate::any_value::Unknown; use crate::any_vec_raw::AnyVecRaw; use crate::AnyVec; +use crate::mem::{MemBuilder}; use crate::traits::Trait; pub trait IAnyVecRawPtr: Copy{ /// Known element type of AnyVec type Element: 'static/* = Unknown*/; - fn any_vec_raw(&self) -> NonNull; + type M: MemBuilder; + fn any_vec_raw(&self) -> NonNull>; } -pub trait IAnyVecPtr: IAnyVecRawPtr{ - fn any_vec(&self) -> NonNull>; +pub trait IAnyVecPtr: IAnyVecRawPtr{ + type Traits: ?Sized + Trait; + fn any_vec(&self) -> NonNull>; } -pub struct AnyVecRawPtr{ - ptr: NonNull, +pub struct AnyVecRawPtr{ + ptr: NonNull>, phantom: PhantomData<*mut Type> } -impl From> for AnyVecRawPtr{ +impl From>> for AnyVecRawPtr{ #[inline] - fn from(ptr: NonNull) -> Self { + fn from(ptr: NonNull>) -> Self { Self{ptr, phantom: PhantomData} } } -impl Copy for AnyVecRawPtr {} -impl Clone for AnyVecRawPtr { +impl Copy for AnyVecRawPtr {} +impl Clone for AnyVecRawPtr { #[inline] fn clone(&self) -> Self { Self{ @@ -38,56 +41,60 @@ impl Clone for AnyVecRawPtr { } } -impl IAnyVecRawPtr for AnyVecRawPtr{ +impl IAnyVecRawPtr for AnyVecRawPtr{ type Element = Type; + type M = M; #[inline] - fn any_vec_raw(&self) -> NonNull { + fn any_vec_raw(&self) -> NonNull> { self.ptr } } -pub struct AnyVecPtr{ - ptr: NonNull> +pub struct AnyVecPtr{ + ptr: NonNull> } -impl From>> for AnyVecPtr { +impl From>> for AnyVecPtr { #[inline] - fn from(ptr: NonNull>) -> Self { + fn from(ptr: NonNull>) -> Self { Self{ptr} } } -impl From<&mut AnyVec> for AnyVecPtr { +impl From<&mut AnyVec> for AnyVecPtr { #[inline] - fn from(reference: &mut AnyVec) -> Self { + fn from(reference: &mut AnyVec) -> Self { Self{ptr: NonNull::from(reference)} } } -impl From<&AnyVec> for AnyVecPtr { +impl From<&AnyVec> for AnyVecPtr { #[inline] - fn from(reference: &AnyVec) -> Self { + fn from(reference: &AnyVec) -> Self { Self{ptr: NonNull::from(reference)} } } -impl Clone for AnyVecPtr{ +impl Clone for AnyVecPtr{ #[inline] fn clone(&self) -> Self { Self{ptr: self.ptr} } } -impl Copy for AnyVecPtr{} +impl Copy for AnyVecPtr{} -impl IAnyVecRawPtr for AnyVecPtr { +impl IAnyVecRawPtr for AnyVecPtr { type Element = Unknown; + type M = M; #[inline] - fn any_vec_raw(&self) -> NonNull { + fn any_vec_raw(&self) -> NonNull> { NonNull::from(unsafe{&self.ptr.as_ref().raw}) } } -impl IAnyVecPtr for AnyVecPtr { +impl IAnyVecPtr for AnyVecPtr { + type Traits = Traits; + #[inline] - fn any_vec(&self) -> NonNull> { + fn any_vec(&self) -> NonNull> { self.ptr } } @@ -97,6 +104,7 @@ impl IAnyVecPtr for AnyVecPtr { pub(crate) mod utils{ use std::{mem, ptr}; use std::mem::size_of; + use crate::mem::Mem; use crate::any_value::Unknown; use crate::any_vec_ptr::IAnyVecRawPtr; @@ -118,10 +126,10 @@ pub(crate) mod utils{ let any_vec_raw = any_vec_ptr.any_vec_raw().as_mut(); if Unknown::is::(){ - any_vec_raw.mem.as_ptr() + any_vec_raw.mem.as_mut_ptr() .add(any_vec_raw.element_layout().size() * index) } else { - any_vec_raw.mem.as_ptr().cast::() + any_vec_raw.mem.as_mut_ptr().cast::() .add(index) as *mut u8 } } } diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index 51a6f6f..43a601e 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -1,49 +1,42 @@ -use std::{mem, ptr}; -use std::alloc::{alloc, dealloc, handle_alloc_error, Layout, realloc}; +use std::{cmp, mem, ptr}; +use std::alloc::Layout; use std::any::TypeId; -use std::ptr::NonNull; use crate::any_value::{AnyValue, Unknown}; use crate::clone_type::CloneFn; +use crate::mem::{Mem, MemBuilder, MemResizable}; pub type DropFn = fn(ptr: *mut u8, len: usize); -pub struct AnyVecRaw { - pub(crate) mem: NonNull, - capacity: usize, // in elements +pub struct AnyVecRaw { + mem_builder: M,// usually ZST + pub(crate) mem: M::Mem, pub(crate) len: usize, // in elements - element_layout: Layout, // size is aligned type_id: TypeId, // purely for safety checks drop_fn: Option } -impl AnyVecRaw { -/* pub fn new() -> Self { - Self::with_capacity::(0) - } -*/ - pub fn with_capacity(capacity: usize) -> Self { - let mut this = Self{ - mem: NonNull::::dangling(), - capacity: 0, +impl AnyVecRaw { + #[inline] + pub fn new(mem_builder: M, mem: M::Mem) -> Self { + Self{ + mem_builder, + mem, len: 0, - element_layout: Layout::new::(), - type_id: TypeId::of::(), + type_id: TypeId::of::(), drop_fn: - if !mem::needs_drop::(){ + if !mem::needs_drop::(){ None } else{ Some(|mut ptr: *mut u8, len: usize|{ for _ in 0..len{ unsafe{ - ptr::drop_in_place(ptr as *mut Element); - ptr = ptr.add(mem::size_of::()); + ptr::drop_in_place(ptr as *mut T); + ptr = ptr.add(mem::size_of::()); } } }) } - }; - this.set_capacity(capacity); - this + } } #[inline] @@ -52,15 +45,19 @@ impl AnyVecRaw { } #[inline] - pub(crate) fn clone_empty(&self) -> Self{ - Self{ - mem: NonNull::::dangling(), - capacity: 0, + pub(crate) fn clone_empty(&self) -> Self { + self.clone_empty_in(self.mem_builder.clone()) + } + + #[inline] + pub(crate) fn clone_empty_in(&self, mut mem_builder: NewM) -> AnyVecRaw{ + let mem = mem_builder.build(self.element_layout()); + AnyVecRaw{ + mem_builder, + mem, len: 0, - element_layout: self.element_layout, type_id: self.type_id, drop_fn: self.drop_fn, - //clone_fn: self.clone_fn } } @@ -70,20 +67,18 @@ impl AnyVecRaw { let mut cloned = self.clone_empty(); // 2. allocate - // TODO: set only necessary capacity size. - // TODO: implement through expand. - cloned.set_capacity(self.capacity); + cloned.mem.expand(self.len); // 3. copy/clone { let src = self.mem.as_ptr(); - let dst = cloned.mem.as_ptr(); + let dst = cloned.mem.as_mut_ptr(); if let Some(clone_fn) = clone_fn{ (clone_fn)(src, dst, self.len); } else { ptr::copy_nonoverlapping( src, dst, - self.element_layout.size() * self.len + self.element_layout().size() * self.len ); } } @@ -93,51 +88,6 @@ impl AnyVecRaw { cloned } - /// This is the only function, which do allocations/deallocations. - fn set_capacity(&mut self, new_capacity: usize){ - // Never cut - debug_assert!(self.len <= new_capacity); - - if self.capacity == new_capacity { - return; - } - - if self.element_layout.size() != 0 { - unsafe{ - // Non checked mul, because this memory size already allocated. - let mem_layout = Layout::from_size_align_unchecked( - self.element_layout.size() * self.capacity, - self.element_layout.align() - ); - - self.mem = - if new_capacity == 0 { - dealloc(self.mem.as_ptr(), mem_layout); - NonNull::::dangling() - } else { - // mul carefully, to prevent overflow. - let new_mem_size = self.element_layout.size() - .checked_mul(new_capacity).unwrap(); - let new_mem_layout = Layout::from_size_align_unchecked( - new_mem_size, self.element_layout.align() - ); - - if self.capacity == 0 { - // allocate - NonNull::new(alloc(new_mem_layout)) - } else { - // reallocate - NonNull::new(realloc( - self.mem.as_ptr(), mem_layout,new_mem_size - )) - } - .unwrap_or_else(|| handle_alloc_error(new_mem_layout)) - } - } - } - self.capacity = new_capacity; - } - #[inline] pub(crate) fn index_check(&self, index: usize){ assert!(index < self.len, "Index out of range!"); @@ -148,13 +98,51 @@ impl AnyVecRaw { assert_eq!(value.value_typeid(), self.type_id, "Type mismatch!"); } - // TODO: hide and make reserve!! #[cold] #[inline(never)] - pub(crate) fn grow(&mut self){ - self.set_capacity( - if self.capacity == 0 {2} else {self.capacity * 2} - ); + fn expand_one(&mut self){ + self.mem.expand(1); + } + + #[inline] + /*pub(crate)*/ fn reserve_one(&mut self){ + if self.len == self.capacity(){ + self.expand_one(); + } + } + + /// Leave this, for Mem, because implementation need it. + /// If M::Mem does not implement MemResizable, then `expand` + /// will panic, if out of capacity. + #[inline] + pub fn reserve(&mut self, additional: usize) { + let new_len = self.len + additional; + if self.capacity() < new_len{ + self.mem.expand(new_len - self.capacity()); + } + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) + where M::Mem: MemResizable + { + let new_len = self.len + additional; + if self.capacity() < new_len{ + self.mem.expand_exact(new_len - self.capacity()); + } + } + + pub fn shrink_to_fit(&mut self) + where M::Mem: MemResizable + { + self.mem.resize(self.len); + } + + pub fn shrink_to(&mut self, min_capacity: usize) + where M::Mem: MemResizable + { + let new_len = cmp::max(self.len, min_capacity); + self.mem.resize(new_len); } /// # Safety @@ -163,13 +151,11 @@ impl AnyVecRaw { pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { assert!(index <= self.len, "Index out of range!"); - if self.len == self.capacity{ - self.grow(); - } + self.reserve_one(); // Compile time type optimization if !Unknown::is::(){ - let element = self.mem.cast::().as_ptr().add(index); + let element = self.mem.as_mut_ptr().cast::().add(index); // 1. shift right ptr::copy( @@ -181,8 +167,8 @@ impl AnyVecRaw { // 2. write value value.move_into(element as *mut u8); } else { - let element_size = self.element_layout.size(); - let element = self.mem.as_ptr().add(element_size * index); + let element_size = self.element_layout().size(); + let element = self.mem.as_mut_ptr().add(element_size * index); // 1. shift right crate::copy_bytes( @@ -203,17 +189,15 @@ impl AnyVecRaw { /// Type is not checked. #[inline] pub unsafe fn push_unchecked(&mut self, value: V) { - if self.len == self.capacity{ - self.grow(); - } + self.reserve_one(); // Compile time type optimization let element = if !Unknown::is::(){ - self.mem.cast::().as_ptr().add(self.len) as *mut u8 + self.mem.as_mut_ptr().cast::().add(self.len) as *mut u8 } else { - let element_size = self.element_layout.size(); - self.mem.as_ptr().add(element_size * self.len) + let element_size = self.element_layout().size(); + self.mem.as_mut_ptr().add(element_size * self.len) }; value.move_into(element); @@ -230,7 +214,7 @@ impl AnyVecRaw { self.len = 0; if let Some(drop_fn) = self.drop_fn{ - (drop_fn)(self.mem.as_ptr(), len); + (drop_fn)(self.mem.as_mut_ptr(), len); } } @@ -243,18 +227,17 @@ impl AnyVecRaw { /// Element Layout #[inline] pub fn element_layout(&self) -> Layout { - self.element_layout + self.mem.element_layout() } #[inline] pub fn capacity(&self) -> usize { - self.capacity + self.mem.size() } } -impl Drop for AnyVecRaw { +impl Drop for AnyVecRaw { fn drop(&mut self) { self.clear(); - self.set_capacity(0); } } diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index 1e86590..3044b31 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -4,10 +4,11 @@ use std::ptr::NonNull; use std::slice; use crate::any_value::{AnyValue, AnyValueWrapper}; use crate::any_vec_raw::AnyVecRaw; -use crate::ops::{Iter, remove, swap_remove, TempValue}; +use crate::ops::{Iter, pop, remove, swap_remove, TempValue}; use crate::any_vec_ptr::AnyVecRawPtr; use crate::into_range; use crate::iter::ElementIterator; +use crate::mem::{MemBuilder, Mem, MemResizable}; use crate::ops::drain::Drain; use crate::ops::splice::Splice; @@ -20,21 +21,21 @@ use crate::ops::splice::Splice; /// [`AnyVec::downcast_`]: crate::AnyVec::downcast_ref /// [`AnyVecRef`]: crate::AnyVecRef /// [`AnyVecMut`]: crate::AnyVecMut -pub struct AnyVecTyped<'a, T: 'static>{ +pub struct AnyVecTyped<'a, T: 'static, M: MemBuilder + 'a>{ // NonNull - to have one struct for both & and &mut - any_vec: NonNull, + any_vec: NonNull>, phantom: PhantomData<&'a mut T> } -unsafe impl<'a, T: 'static + Send> Send for AnyVecTyped<'a, T> {} -unsafe impl<'a, T: 'static + Sync> Sync for AnyVecTyped<'a, T> {} +unsafe impl<'a, T: 'static + Send, M: MemBuilder> Send for AnyVecTyped<'a, T, M> {} +unsafe impl<'a, T: 'static + Sync, M: MemBuilder> Sync for AnyVecTyped<'a, T, M> {} -impl<'a, T: 'static> AnyVecTyped<'a, T>{ +impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ /// # Safety /// /// Unsafe, because type not checked #[inline] - pub(crate) unsafe fn new(any_vec: NonNull) -> Self { + pub(crate) unsafe fn new(any_vec: NonNull>) -> Self { Self{any_vec, phantom: PhantomData} } @@ -45,15 +46,43 @@ impl<'a, T: 'static> AnyVecTyped<'a, T>{ } #[inline] - fn this(&self) -> &'a AnyVecRaw { + fn this(&self) -> &'a AnyVecRaw { unsafe{ self.any_vec.as_ref() } } #[inline] - fn this_mut(&mut self) -> &'a mut AnyVecRaw { + fn this_mut(&mut self) -> &'a mut AnyVecRaw { unsafe{ self.any_vec.as_mut() } } + #[inline] + pub fn reserve(&mut self, additional: usize) + where M::Mem: MemResizable + { + self.this_mut().reserve(additional) + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) + where M::Mem: MemResizable + { + self.this_mut().reserve_exact(additional) + } + + #[inline] + pub fn shrink_to_fit(&mut self) + where M::Mem: MemResizable + { + self.this_mut().shrink_to_fit() + } + + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) + where M::Mem: MemResizable + { + self.this_mut().shrink_to(min_capacity) + } + #[inline] pub fn insert(&mut self, index: usize, value: T){ unsafe{ @@ -68,12 +97,26 @@ impl<'a, T: 'static> AnyVecTyped<'a, T>{ } } + #[inline] + pub fn pop(&mut self) -> Option { + if self.is_empty(){ + None + } else { + let value = unsafe{ + TempValue::new(pop::Pop::new( + AnyVecRawPtr::::from(self.any_vec) + )).downcast_unchecked::() + }; + Some(value) + } + } + #[inline] pub fn remove(&mut self, index: usize) -> T { self.this().index_check(index); unsafe{ - TempValue::<_>::new(remove::Remove::new( - AnyVecRawPtr::::from(self.any_vec), + TempValue::new(remove::Remove::new( + AnyVecRawPtr::::from(self.any_vec), index )).downcast_unchecked::() } @@ -83,8 +126,8 @@ impl<'a, T: 'static> AnyVecTyped<'a, T>{ pub fn swap_remove(&mut self, index: usize) -> T { self.this().index_check(index); unsafe{ - TempValue::<_>::new(swap_remove::SwapRemove::new( - AnyVecRawPtr::::from(self.any_vec), + TempValue::new(swap_remove::SwapRemove::new( + AnyVecRawPtr::::from(self.any_vec), index )).downcast_unchecked::() } @@ -92,11 +135,11 @@ impl<'a, T: 'static> AnyVecTyped<'a, T>{ #[inline] pub fn drain(&mut self, range: impl RangeBounds) - -> impl ElementIterator + -> impl ElementIterator + 'a { let Range{start, end} = into_range(self.len(), range); Iter(Drain::new( - AnyVecRawPtr::::from(self.any_vec), + AnyVecRawPtr::::from(self.any_vec), start, end )).map(|e| unsafe{ @@ -106,17 +149,17 @@ impl<'a, T: 'static> AnyVecTyped<'a, T>{ #[inline] pub fn splice(&mut self, range: impl RangeBounds, replace_with: I) - -> impl ElementIterator + -> impl ElementIterator + 'a where I: IntoIterator, - I::IntoIter: ExactSizeIterator, + I::IntoIter: ExactSizeIterator + 'a, { let Range{start, end} = into_range(self.len(), range); let replace_with = replace_with.into_iter() .map(|e| AnyValueWrapper::new(e)); Iter(Splice::new( - AnyVecRawPtr::::from(self.any_vec), + AnyVecRawPtr::::from(self.any_vec), start, end, replace_with @@ -190,7 +233,7 @@ impl<'a, T: 'static> AnyVecTyped<'a, T>{ pub fn as_mut_slice(&mut self) -> &'a mut[T] { unsafe{ slice::from_raw_parts_mut( - self.this_mut().mem.as_ptr().cast::(), + self.this_mut().mem.as_mut_ptr().cast::(), self.this().len, ) } @@ -201,6 +244,11 @@ impl<'a, T: 'static> AnyVecTyped<'a, T>{ self.this().len } + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + #[inline] pub fn capacity(&self) -> usize { self.this().capacity() diff --git a/src/element.rs b/src/element.rs index 9a05b4e..34db307 100644 --- a/src/element.rs +++ b/src/element.rs @@ -6,13 +6,13 @@ use std::ptr::NonNull; use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, clone_into}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{AnyVecPtr, IAnyVecPtr, IAnyVecRawPtr}; +use crate::mem; +use crate::mem::MemBuilder; use crate::traits::{Cloneable, None, Trait}; // Typed operations will never use type-erased Element, so there is no // need in type-known-based optimizations. -// TODO: hide. Derive AnyValue staff in Element. -// /// Owning pointer to [`AnyVec`] element. /// /// This is public, just so you can see what [`Element`] can do. @@ -28,7 +28,7 @@ use crate::traits::{Cloneable, None, Trait}; pub struct ElementPointer<'a, AnyVecPtr: IAnyVecRawPtr>{ any_vec_ptr: AnyVecPtr, element: NonNull, - phantom: PhantomData<&'a mut AnyVecRaw> + phantom: PhantomData<&'a mut AnyVecRaw> } impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ @@ -44,7 +44,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ } #[inline] - fn any_vec_raw(&self) -> &'a AnyVecRaw{ + fn any_vec_raw(&self) -> &'a AnyVecRaw{ unsafe { self.any_vec_ptr.any_vec_raw().as_ref() } } @@ -107,8 +107,8 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValue for ElementPointer<'a, AnyVecPtr>{ impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMut for ElementPointer<'a, AnyVecPtr>{} -impl<'a, Traits: ?Sized + Cloneable + Trait> - AnyValueCloneable for ElementPointer<'a, AnyVecPtr> +impl<'a, Traits: ?Sized + Cloneable + Trait, M: MemBuilder> + AnyValueCloneable for ElementPointer<'a, AnyVecPtr> { #[inline] unsafe fn clone_into(&self, out: *mut u8) { @@ -116,14 +116,14 @@ impl<'a, Traits: ?Sized + Cloneable + Trait> } } -unsafe impl<'a, Traits: ?Sized + Send + Trait> Send for ElementPointer<'a, AnyVecPtr>{} -unsafe impl<'a, Traits: ?Sized + Sync + Trait> Sync for ElementPointer<'a, AnyVecPtr>{} +unsafe impl<'a, Traits: ?Sized + Send + Trait, M: MemBuilder> Send for ElementPointer<'a, AnyVecPtr>{} +unsafe impl<'a, Traits: ?Sized + Sync + Trait, M: MemBuilder> Sync for ElementPointer<'a, AnyVecPtr>{} /// [`AnyVec`] element. /// /// [`AnyVec`]: crate::AnyVec -pub type Element<'a, Traits> = ElementPointer<'a, AnyVecPtr>; +pub type Element<'a, Traits = dyn None, M = mem::Default> = ElementPointer<'a, AnyVecPtr>; /// Reference to [`Element`]. @@ -131,18 +131,18 @@ pub type Element<'a, Traits> = ElementPointer<'a, AnyVecPtr>; /// Created by [`AnyVec::get`]. /// /// [`AnyVec::get`]: crate::AnyVec::get -pub struct ElementRef<'a, Traits: ?Sized + Trait = dyn None>( - pub(crate) ManuallyDrop>> +pub struct ElementRef<'a, Traits: ?Sized + Trait = dyn None, M: MemBuilder = mem::Default>( + pub(crate) ManuallyDrop>> ); -impl<'a, Traits: ?Sized + Trait> Deref for ElementRef<'a, Traits>{ - type Target = Element<'a, Traits>; +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Deref for ElementRef<'a, Traits, M>{ + type Target = Element<'a, Traits, M>; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } -impl<'a, Traits: ?Sized + Trait> Clone for ElementRef<'a, Traits>{ +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Clone for ElementRef<'a, Traits, M>{ #[inline] fn clone(&self) -> Self { Self(ManuallyDrop::new(self.0.clone())) @@ -154,18 +154,18 @@ impl<'a, Traits: ?Sized + Trait> Clone for ElementRef<'a, Traits>{ /// Created by [`AnyVec::get_mut`]. /// /// [`AnyVec::get_mut`]: crate::AnyVec::get_mut -pub struct ElementMut<'a, Traits: ?Sized + Trait = dyn None>( - pub(crate) ManuallyDrop>> +pub struct ElementMut<'a, Traits: ?Sized + Trait = dyn None, M: MemBuilder = mem::Default>( + pub(crate) ManuallyDrop>> ); -impl<'a, Traits: ?Sized + Trait> Deref for ElementMut<'a, Traits>{ - type Target = Element<'a, Traits>; +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Deref for ElementMut<'a, Traits, M>{ + type Target = Element<'a, Traits, M>; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } -impl<'a, Traits: ?Sized + Trait> DerefMut for ElementMut<'a, Traits>{ +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> DerefMut for ElementMut<'a, Traits, M>{ #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 diff --git a/src/iter.rs b/src/iter.rs index e7f7bf2..a53eaf0 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -6,6 +6,7 @@ use crate::any_vec_ptr::{AnyVecPtr, IAnyVecRawPtr}; use crate::any_vec_ptr::utils::element_ptr_at; use crate::any_vec_raw::AnyVecRaw; use crate::element::{ElementPointer, ElementMut, ElementRef}; +use crate::mem::MemBuilder; use crate::traits::Trait; // TODO :Additional [`AnyVec`] Iterator operations. @@ -31,18 +32,16 @@ where /// [`Element`]: crate::element::Element /// [`ElementRef`]: crate::element::ElementRef /// [`ElementMut`]: crate::element::ElementMut -#[derive(Clone)] pub struct Iter<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr> = ElementIterItem<'a, AnyVecPtr>> { pub(crate) any_vec_ptr: AnyVecPtr, - // TODO: try pointers, instead pub(crate) index: usize, pub(crate) end: usize, - phantom: PhantomData<(&'a AnyVecRaw, IterItem)> + phantom: PhantomData<(&'a AnyVecRaw, IterItem)> } impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> @@ -54,6 +53,22 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> } } +impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr> + Clone> + Clone +for + Iter<'a, AnyVecPtr, IterItem> +{ + #[inline] + fn clone(&self) -> Self { + Self{ + any_vec_ptr: self.any_vec_ptr, + index: self.index, + end: self.end, + phantom: PhantomData + } + } +} + impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> Iterator for Iter<'a, AnyVecPtr, IterItem> { @@ -117,12 +132,12 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> FusedI // According to https://github.com/rust-lang/rust/issues/93367#issuecomment-1154832012 #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Send + Trait, IterItem: IteratorItem<'a, AnyVecPtr>> Send - for Iter<'a, AnyVecPtr, IterItem> {} +unsafe impl<'a, Traits: ?Sized + Send + Trait, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecPtr>> Send + for Iter<'a, AnyVecPtr, IterItem> {} #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Sync + Trait, IterItem: IteratorItem<'a, AnyVecPtr>> Sync - for Iter<'a, AnyVecPtr, IterItem> {} +unsafe impl<'a, Traits: ?Sized + Sync + Trait, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecPtr>> Sync + for Iter<'a, AnyVecPtr, IterItem> {} pub trait IteratorItem<'a, AnyVecPtr: IAnyVecRawPtr>{ @@ -144,18 +159,18 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> IteratorItem<'a, AnyVecPtr> for ElementIterIt } /// Ref -pub struct ElementRefIterItem<'a, Traits: ?Sized + Trait>( - pub(crate) PhantomData>> +pub struct ElementRefIterItem<'a, Traits: ?Sized + Trait, M: MemBuilder>( + pub(crate) PhantomData>> ); -impl<'a, Traits: ?Sized + Trait> IteratorItem<'a, AnyVecPtr> for ElementRefIterItem<'a, Traits>{ - type Item = ElementRef<'a, Traits>; +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> IteratorItem<'a, AnyVecPtr> for ElementRefIterItem<'a, Traits, M>{ + type Item = ElementRef<'a, Traits, M>; #[inline] - fn element_to_item(element: ElementPointer<'a, AnyVecPtr>) -> Self::Item { + fn element_to_item(element: ElementPointer<'a, AnyVecPtr>) -> Self::Item { ElementRef(ManuallyDrop::new(element)) } } -impl<'a, Traits: ?Sized + Trait> Clone for ElementRefIterItem<'a, Traits>{ +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Clone for ElementRefIterItem<'a, Traits, M>{ fn clone(&self) -> Self { Self(PhantomData) } @@ -163,18 +178,18 @@ impl<'a, Traits: ?Sized + Trait> Clone for ElementRefIterItem<'a, Traits>{ /// Mut -pub struct ElementMutIterItem<'a, Traits: ?Sized + Trait>( - pub(crate) PhantomData>> +pub struct ElementMutIterItem<'a, Traits: ?Sized + Trait, M: MemBuilder>( + pub(crate) PhantomData>> ); -impl<'a, Traits: ?Sized + Trait> IteratorItem<'a, AnyVecPtr> for ElementMutIterItem<'a, Traits>{ - type Item = ElementMut<'a, Traits>; +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> IteratorItem<'a, AnyVecPtr> for ElementMutIterItem<'a, Traits, M>{ + type Item = ElementMut<'a, Traits, M>; #[inline] - fn element_to_item(element: ElementPointer<'a, AnyVecPtr>) -> Self::Item { + fn element_to_item(element: ElementPointer<'a, AnyVecPtr>) -> Self::Item { ElementMut(ManuallyDrop::new(element)) } } -impl<'a, Traits: ?Sized + Trait> Clone for ElementMutIterItem<'a, Traits>{ +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Clone for ElementMutIterItem<'a, Traits, M>{ fn clone(&self) -> Self { Self(PhantomData) } @@ -187,10 +202,10 @@ impl<'a, Traits: ?Sized + Trait> Clone for ElementMutIterItem<'a, Traits>{ /// /// [`AnyVec`]: crate::AnyVec /// [`ElementRef`]: crate::element::ElementRef -pub type IterRef<'a, Traits> = Iter<'a, AnyVecPtr, ElementRefIterItem<'a, Traits>>; +pub type IterRef<'a, Traits, M> = Iter<'a, AnyVecPtr, ElementRefIterItem<'a, Traits, M>>; /// Mutable reference [`AnyVec`] iterator. Return [`ElementMut`] items. /// /// [`AnyVec`]: crate::AnyVec /// [`ElementMut`]: crate::element::ElementMut -pub type IterMut<'a, Traits> = Iter<'a, AnyVecPtr, ElementMutIterItem<'a, Traits>>; \ No newline at end of file +pub type IterMut<'a, Traits, M> = Iter<'a, AnyVecPtr, ElementMutIterItem<'a, Traits, M>>; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 368f857..9e9140f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,6 +74,49 @@ //! v2.push(e.lazy_clone()); //! v2.push(e.lazy_clone()); //! ``` +//! +//! # MemBuilder +//! +//! [`MemBuilder`] + [`Mem`] works like [`Allocator`] for [`AnyVec`]. But unlike allocator, +//! [`Mem`] container-specialized design allows to perform more optimizations. For example, +//! it is possible to make stack-allocated `FixedAnyVec` and small-buffer-optimized(SBO) `SmallAnyVec` +//! from `AnyVec` by just changing [`MemBuilder`]: +//! +//!```rust +//! # use any_vec::any_value::AnyValueWrapper; +//! # use any_vec::AnyVec; +//! # use any_vec::mem::Stack; +//! # use any_vec::traits::None; +//! +//! type FixedAnyVec = AnyVec>; +//! let mut any_vec: FixedAnyVec = AnyVec::new::(); +//! +//! // This will be on stack, without any allocations. +//! any_vec.push(AnyValueWrapper::new(String::from("0"))) +//!``` +//! +//! With help of [`clone_empty_in`] you can use stack allocated, or SBO [`AnyVec`] +//! as fast intermediate storage for values of unknown type: +//! +//!```rust +//! # use any_vec::any_value::{AnyValueCloneable, AnyValueWrapper}; +//! # use any_vec::AnyVec; +//! # use any_vec::mem::Stack; +//! # use any_vec::traits::*; +//! +//! fn self_push_first_element(any_vec: &mut AnyVec){ +//! let mut tmp = any_vec.clone_empty_in(Stack::<256>); +//! tmp.push(any_vec.at(0).lazy_clone()); +//! any_vec.push(tmp.pop().unwrap()); +//! } +//!``` +//! +//! [`MemBuilder`] interface, being stateful, allow to make [`Mem`], which can work with complex custom allocators. +//! +//! [`MemBuilder`]: mem::MemBuilder +//! [`Mem`]: mem::Mem +//! [`Allocator`]: std::alloc::Allocator +//! [`clone_empty_in`]: AnyVec::clone_empty_in mod any_vec; mod clone_type; @@ -86,6 +129,7 @@ pub use crate::any_vec::{AnyVec, AnyVecMut, AnyVecRef, SatisfyTraits, traits}; pub use any_vec_typed::AnyVecTyped; pub use iter::{ElementIterator, Iter, IterRef, IterMut}; +pub mod mem; pub mod any_value; pub mod ops; pub mod element; diff --git a/src/mem/heap.rs b/src/mem/heap.rs new file mode 100644 index 0000000..2634c8a --- /dev/null +++ b/src/mem/heap.rs @@ -0,0 +1,113 @@ +use std::alloc::{alloc, dealloc, handle_alloc_error, Layout, realloc}; +use std::cmp; +use std::ptr::NonNull; +use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemResizable}; + + +/// Heap allocated memory. +#[derive(Default, Clone)] +pub struct Heap; +impl MemBuilder for Heap { + type Mem = HeapMem; + + #[inline] + fn build(&mut self, element_layout: Layout) -> HeapMem { + HeapMem { + mem: NonNull::::dangling(), + size: 0, + element_layout + } + } +} +impl MemBuilderSizeable for Heap{ + #[inline] + fn build_with_size(&mut self, element_layout: Layout, capacity: usize) -> Self::Mem + { + let mut mem = self.build(element_layout); + mem.resize(capacity); + mem + } +} + +pub struct HeapMem { + mem: NonNull, + size: usize, // in elements + element_layout: Layout, // size is aligned +} + +impl Mem for HeapMem { + #[inline] + fn as_ptr(&self) -> *const u8 { + self.mem.as_ptr() + } + + #[inline] + fn as_mut_ptr(&mut self) -> *mut u8 { + self.mem.as_ptr() + } + + #[inline] + fn element_layout(&self) -> Layout { + self.element_layout + } + + #[inline] + fn size(&self) -> usize { + self.size + } + + fn expand(&mut self, additional: usize){ + let requested_size = self.size() + additional; + let new_size = cmp::max(self.size() * 2, requested_size); + self.resize(new_size); + } +} + +impl MemResizable for HeapMem { + fn resize(&mut self, new_size: usize) { + if self.size == new_size{ + return; + } + + if self.element_layout.size() != 0 { + unsafe{ + // Non checked mul, because this memory size already allocated. + let mem_layout = Layout::from_size_align_unchecked( + self.element_layout.size() * self.size, + self.element_layout.align() + ); + + self.mem = + if new_size == 0 { + dealloc(self.mem.as_ptr(), mem_layout); + NonNull::::dangling() + } else { + // mul carefully, to prevent overflow. + let new_mem_size = self.element_layout.size() + .checked_mul(new_size).unwrap(); + let new_mem_layout = Layout::from_size_align_unchecked( + new_mem_size, self.element_layout.align() + ); + + if self.size == 0 { + // allocate + NonNull::new(alloc(new_mem_layout)) + } else { + // reallocate + NonNull::new(realloc( + self.mem.as_ptr(), mem_layout,new_mem_size + )) + } + .unwrap_or_else(|| handle_alloc_error(new_mem_layout)) + } + } + } + self.size = new_size; + } +} + +impl Drop for HeapMem { + fn drop(&mut self) { + self.resize(0); + } +} \ No newline at end of file diff --git a/src/mem/mod.rs b/src/mem/mod.rs new file mode 100644 index 0000000..b488683 --- /dev/null +++ b/src/mem/mod.rs @@ -0,0 +1,73 @@ +mod heap; +mod stack; + +pub use heap::Heap; +pub use stack::Stack; + +pub(crate) type Default = Heap; + +use std::alloc::Layout; + +/// This is [`Mem`] builder. +/// +/// It can be stateful. You can use it like Allocator. +/// Making `MemBuilder` default constructible, allow to use [`AnyVec::new`], without that you +/// limited to [`AnyVec::new_in`]. +/// +/// [`AnyVec::new`]: crate::AnyVec::new +/// [`AnyVec::new_in`]: crate::AnyVec::new_in +pub trait MemBuilder: Clone { + type Mem: Mem; + fn build(&mut self, element_layout: Layout) -> Self::Mem; +} + +/// This allows to use [`AnyVec::with_capacity`] with it. +/// +/// [`AnyVec::with_capacity`]: crate::AnyVec::with_capacity +pub trait MemBuilderSizeable: MemBuilder{ + fn build_with_size(&mut self, element_layout: Layout, capacity: usize) -> Self::Mem; +} + +/// Interface for [`AnyVec`] memory chunk. +/// +/// Responsible for allocation, dealocation, reallocation of the memory chunk. +/// Constructed through [`MemBuilder`]. +/// +/// _`Mem` is fixed capacity memory. Implement [`MemResizable`] if you want it +/// to be resizable._ +/// +/// [`AnyVec`]: crate::AnyVec +pub trait Mem{ + fn as_ptr(&self) -> *const u8; + + fn as_mut_ptr(&mut self) -> *mut u8; + + /// Aligned. + fn element_layout(&self) -> Layout; + + /// In elements. + fn size(&self) -> usize; + + /// Consider, that `expand` is in [`MemResizable`]. + /// Implement this only if your type [`MemResizable`]. + /// + /// It's here, only due to technical reasons (see `AnyVecRaw::reserve`). + fn expand(&mut self, additional: usize){ + drop(additional); + panic!("Can't change capacity!"); + + /*let requested_size = self.size() + additional; + let new_size = cmp::max(self.size() * 2, requested_size); + self.resize(new_size);*/ + } +} + +/// Marker trait for resizable [`Mem`]. +pub trait MemResizable: Mem{ + fn expand_exact(&mut self, additional: usize){ + self.resize(self.size() + additional); + } + + /// Do panic if can't resize. + fn resize(&mut self, new_size: usize); +} \ No newline at end of file diff --git a/src/mem/stack.rs b/src/mem/stack.rs new file mode 100644 index 0000000..acddfdd --- /dev/null +++ b/src/mem/stack.rs @@ -0,0 +1,47 @@ +use std::alloc::Layout; +use std::mem::MaybeUninit; +use crate::mem::{Mem, MemBuilder}; + +/// Fixed capacity on-stack memory. +/// +/// `SIZE` in bytes. +#[derive(Default, Clone)] +pub struct Stack; +impl MemBuilder for Stack{ + type Mem = StackMem; + + #[inline] + fn build(&mut self, element_layout: Layout) -> StackMem { + StackMem{ + mem: MaybeUninit::uninit(), + element_layout + } + } +} + +pub struct StackMem{ + mem: MaybeUninit<[u8; SIZE]>, + element_layout: Layout +} + +impl Mem for StackMem{ + #[inline] + fn as_ptr(&self) -> *const u8 { + unsafe{self.mem.assume_init_ref()}.as_ptr() + } + + #[inline] + fn as_mut_ptr(&mut self) -> *mut u8 { + unsafe{self.mem.assume_init_mut()}.as_mut_ptr() + } + + #[inline] + fn element_layout(&self) -> Layout { + self.element_layout + } + + #[inline] + fn size(&self) -> usize { + SIZE + } +} \ No newline at end of file diff --git a/src/ops/drain.rs b/src/ops/drain.rs index 1861b9b..578522b 100644 --- a/src/ops/drain.rs +++ b/src/ops/drain.rs @@ -1,6 +1,7 @@ use crate::any_vec_ptr::{AnyVecPtr, AnyVecRawPtr, IAnyVecRawPtr}; use crate::iter::Iter; use crate::any_vec_ptr; +use crate::mem::{MemBuilder}; use crate::ops::iter::Iterable; use crate::traits::Trait; @@ -81,11 +82,11 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Drop for Drain<'a, AnyVecPtr> } #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Sync + Trait> Sync for Drain<'a, AnyVecPtr>{} +unsafe impl<'a, Traits: ?Sized + Sync + Trait, M: MemBuilder> Sync for Drain<'a, AnyVecPtr>{} #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Type: Sync> Sync for Drain<'a, AnyVecRawPtr>{} +unsafe impl<'a, Type: Sync, M: MemBuilder> Sync for Drain<'a, AnyVecRawPtr>{} #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Send + Trait> Send for Drain<'a, AnyVecPtr>{} +unsafe impl<'a, Traits: ?Sized + Send + Trait, M: MemBuilder> Send for Drain<'a, AnyVecPtr>{} #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Type: Send> Send for Drain<'a, AnyVecRawPtr>{} \ No newline at end of file +unsafe impl<'a, Type: Send, M: MemBuilder> Send for Drain<'a, AnyVecRawPtr>{} \ No newline at end of file diff --git a/src/ops/mod.rs b/src/ops/mod.rs index 86e84dd..ad475ea 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -4,25 +4,33 @@ pub(crate) mod swap_remove; pub(crate) mod remove; pub(crate) mod drain; pub(crate) mod splice; +pub(crate) mod pop; pub use temp::TempValue; pub use iter::Iter; use crate::any_vec_ptr::AnyVecPtr; +/// Lazily `pop` on consumption/drop. +/// +/// This is created by [`AnyVec::pop`]. +/// +/// [`AnyVec::pop`]: crate::AnyVec::pop +pub type Pop<'a, Traits, M> = TempValue>>; + /// Lazily `remove` element on consumption/drop. /// /// This is created by [`AnyVec::remove`]. /// /// [`AnyVec::remove`]: crate::AnyVec::remove -pub type Remove<'a, Traits> = TempValue>, Traits>; +pub type Remove<'a, Traits, M> = TempValue>>; /// Lazily `swap_remove` element on consumption/drop. /// /// This is created by [`AnyVec::swap_remove`]. /// /// [`AnyVec::swap_remove`]: crate::AnyVec::swap_remove -pub type SwapRemove<'a, Traits> = TempValue>, Traits>; +pub type SwapRemove<'a, Traits, M> = TempValue>>; /// A draining [`ElementIterator`] for [`AnyVec`]. Return [`Element`] items. /// @@ -32,8 +40,9 @@ pub type SwapRemove<'a, Traits> = TempValue = Iter>>; +pub type Drain<'a, Traits, M> = Iter>>; +// TODO: change template arguments order /// A splicing [`ElementIterator`] for [`AnyVec`]. Return [`Element`] items. /// /// This is created by [`AnyVec::splice`]. @@ -42,4 +51,4 @@ pub type Drain<'a, Traits> = Iter>>; /// [`AnyVec::splice`]: crate::AnyVec::splice /// [`Element`]: crate::element::Element /// [`ElementIterator`]: crate::iter::ElementIterator -pub type Splice<'a, Traits, I> = Iter, I>>; \ No newline at end of file +pub type Splice<'a, Traits, M, I> = Iter, I>>; \ No newline at end of file diff --git a/src/ops/pop.rs b/src/ops/pop.rs new file mode 100644 index 0000000..0d883cf --- /dev/null +++ b/src/ops/pop.rs @@ -0,0 +1,47 @@ +use std::marker::PhantomData; +use crate::any_vec_ptr::IAnyVecRawPtr; +use crate::any_vec_ptr::utils::element_ptr_at; +use crate::any_vec_raw::AnyVecRaw; +use crate::ops::temp::Operation; + +pub struct Pop<'a, AnyVecPtr: IAnyVecRawPtr>{ + any_vec_ptr: AnyVecPtr, + phantom: PhantomData<&'a mut AnyVecRaw>, +} + +impl<'a, AnyVecPtr: IAnyVecRawPtr> Pop<'a, AnyVecPtr>{ + #[inline] + pub(crate) fn new(any_vec_ptr: AnyVecPtr) -> Self{ + let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw().as_mut() }; + + // mem::forget and element drop panic "safety". + debug_assert!(any_vec_raw.len > 0); + any_vec_raw.len -= 1; + + Self{ + any_vec_ptr, + phantom: PhantomData + } + } +} + +impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Pop<'a, AnyVecPtr>{ + type AnyVecPtr = AnyVecPtr; + + #[inline] + fn any_vec_ptr(&self) -> Self::AnyVecPtr { + self.any_vec_ptr + } + + #[inline] + fn bytes(&self) -> *const u8 { + let any_vec_raw = unsafe{ self.any_vec_ptr.any_vec_raw().as_ref() }; + let index = any_vec_raw.len; + element_ptr_at(self.any_vec_ptr, index) + } + + #[inline] + fn consume(&mut self) { + // do nothing. + } +} \ No newline at end of file diff --git a/src/ops/remove.rs b/src/ops/remove.rs index ea52cdf..fda9ea9 100644 --- a/src/ops/remove.rs +++ b/src/ops/remove.rs @@ -3,13 +3,14 @@ use std::ptr; use crate::any_value::Unknown; use crate::any_vec_ptr::IAnyVecRawPtr; use crate::any_vec_raw::AnyVecRaw; +use crate::mem::Mem; use crate::ops::temp::Operation; pub struct Remove<'a, AnyVecPtr: IAnyVecRawPtr>{ any_vec_ptr: AnyVecPtr, index: usize, last_index: usize, - phantom: PhantomData<&'a mut AnyVecRaw> + phantom: PhantomData<&'a mut AnyVecRaw> } impl<'a, AnyVecPtr: IAnyVecRawPtr> Remove<'a, AnyVecPtr>{ @@ -26,7 +27,6 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Remove<'a, AnyVecPtr>{ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Remove<'a, AnyVecPtr>{ type AnyVecPtr = AnyVecPtr; - type Type = AnyVecPtr::Element; #[inline] fn any_vec_ptr(&self) -> Self::AnyVecPtr { @@ -37,8 +37,8 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Remove<'a, AnyVecPtr>{ fn bytes(&self) -> *const u8 { unsafe{ let any_vec_raw = self.any_vec_ptr.any_vec_raw().as_ref(); - if !Unknown::is::(){ - any_vec_raw.mem.cast::().as_ptr() + if !Unknown::is::(){ + any_vec_raw.mem.as_ptr().cast::() .add(self.index) as *const u8 } else { any_vec_raw.mem.as_ptr() @@ -51,8 +51,8 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Remove<'a, AnyVecPtr>{ fn consume(&mut self) { unsafe{ // 2. shift everything left - if !Unknown::is::() { - let dst = self.bytes() as *mut Self::Type; + if !Unknown::is::() { + let dst = self.bytes() as *mut AnyVecPtr::Element; let src = dst.add(1); ptr::copy(src, dst,self.last_index - self.index); } else { diff --git a/src/ops/splice.rs b/src/ops/splice.rs index 831212e..5fc1f28 100644 --- a/src/ops/splice.rs +++ b/src/ops/splice.rs @@ -1,6 +1,7 @@ use crate::any_vec_ptr::{AnyVecPtr, AnyVecRawPtr, IAnyVecRawPtr}; use crate::{any_vec_ptr, Iter}; use crate::any_value::AnyValue; +use crate::mem::MemBuilder; use crate::ops::iter::Iterable; use crate::traits::Trait; @@ -77,9 +78,7 @@ where // 0. capacity. { let any_vec_raw = unsafe{any_vec_ptr.any_vec_raw().as_mut()}; - if new_len > any_vec_raw.capacity(){ - any_vec_raw.grow(); - } + any_vec_raw.reserve(new_len); } // 1. drop elements. @@ -119,35 +118,34 @@ where } } + #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Send + Trait, ReplaceIter: ExactSizeIterator> Send +unsafe impl<'a, Traits: ?Sized + Send + Trait, M: MemBuilder, ReplaceIter: ExactSizeIterator> Send for - Splice<'a, AnyVecPtr, ReplaceIter> + Splice<'a, AnyVecPtr, ReplaceIter> where ReplaceIter::Item: AnyValue + Send {} - #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Type: Send, ReplaceIter: ExactSizeIterator> Send +unsafe impl<'a, Type: Send, M: MemBuilder, ReplaceIter: ExactSizeIterator> Send for - Splice<'a, AnyVecRawPtr, ReplaceIter> + Splice<'a, AnyVecRawPtr, ReplaceIter> where ReplaceIter::Item: AnyValue + Send {} #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Sync + Trait, ReplaceIter: ExactSizeIterator> Sync +unsafe impl<'a, Traits: ?Sized + Sync + Trait, M: MemBuilder, ReplaceIter: ExactSizeIterator> Sync for - Splice<'a, AnyVecPtr, ReplaceIter> + Splice<'a, AnyVecPtr, ReplaceIter> where ReplaceIter::Item: AnyValue + Sync {} - #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Type: Sync, ReplaceIter: ExactSizeIterator> Sync +unsafe impl<'a, Type: Sync, M: MemBuilder, ReplaceIter: ExactSizeIterator> Sync for - Splice<'a, AnyVecRawPtr, ReplaceIter> + Splice<'a, AnyVecRawPtr, ReplaceIter> where ReplaceIter::Item: AnyValue + Sync {} diff --git a/src/ops/swap_remove.rs b/src/ops/swap_remove.rs index 21eba22..b929127 100644 --- a/src/ops/swap_remove.rs +++ b/src/ops/swap_remove.rs @@ -4,13 +4,14 @@ use crate::copy_bytes_nonoverlapping; use crate::any_value::Unknown; use crate::any_vec_ptr::IAnyVecRawPtr; use crate::any_vec_raw::AnyVecRaw; +use crate::mem::Mem; use crate::ops::temp::Operation; pub struct SwapRemove<'a, AnyVecPtr: IAnyVecRawPtr>{ any_vec_ptr: AnyVecPtr, element: *mut u8, last_index: usize, - phantom: PhantomData<&'a mut AnyVecRaw>, + phantom: PhantomData<&'a mut AnyVecRaw>, } impl<'a, AnyVecPtr: IAnyVecRawPtr> SwapRemove<'a, AnyVecPtr>{ @@ -24,9 +25,9 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> SwapRemove<'a, AnyVecPtr>{ let element: *mut u8 = unsafe{ if !Unknown::is::(){ - any_vec_raw.mem.cast::().as_ptr().add(index) as *mut u8 + any_vec_raw.mem.as_mut_ptr().cast::().add(index) as *mut u8 } else { - any_vec_raw.mem.as_ptr().add(any_vec_raw.element_layout().size() * index) + any_vec_raw.mem.as_mut_ptr().add(any_vec_raw.element_layout().size() * index) } }; Self{ any_vec_ptr, element, last_index, phantom: PhantomData } @@ -35,7 +36,6 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> SwapRemove<'a, AnyVecPtr>{ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for SwapRemove<'a, AnyVecPtr>{ type AnyVecPtr = AnyVecPtr; - type Type = AnyVecPtr::Element; #[inline] fn any_vec_ptr(&self) -> Self::AnyVecPtr { @@ -53,17 +53,20 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for SwapRemove<'a, AnyVecPtr>{ // 2. overwrite with last element let any_vec_raw = self.any_vec_ptr.any_vec_raw().as_mut(); let last_element = - if !Unknown::is::() { - any_vec_raw.mem.cast::().as_ptr().add(self.last_index) as *const u8 + if !Unknown::is::() { + any_vec_raw.mem.as_ptr().cast::().add(self.last_index) as *const u8 } else { any_vec_raw.mem.as_ptr() .add(any_vec_raw.element_layout().size() * self.last_index) }; if self.element as *const u8 != last_element { - if !Unknown::is::() { - ptr::copy_nonoverlapping - (last_element as *const Self::Type, self.element as *mut Self::Type, 1); + if !Unknown::is::() { + ptr::copy_nonoverlapping( + last_element as *const AnyVecPtr::Element, + self.element as *mut AnyVecPtr::Element, + 1 + ); } else { copy_bytes_nonoverlapping (last_element, self.element, any_vec_raw.element_layout().size()); diff --git a/src/ops/temp.rs b/src/ops/temp.rs index 97f00ef..9661c06 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -1,14 +1,12 @@ use std::any::TypeId; use std::{mem, ptr}; -use std::marker::PhantomData; use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, clone_into, copy_bytes, Unknown}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{IAnyVecPtr, IAnyVecRawPtr}; -use crate::traits::{Cloneable, None, Trait}; +use crate::traits::Cloneable; pub trait Operation { type AnyVecPtr: IAnyVecRawPtr; - type Type: 'static; fn any_vec_ptr(&self) -> Self::AnyVecPtr; @@ -25,28 +23,27 @@ pub trait Operation { /// /// May do some postponed actions on consumption/destruction. /// -pub struct TempValue{ +pub struct TempValue{ op: Op, - phantom: PhantomData } -impl TempValue{ +impl TempValue{ #[inline] pub(crate) fn new(op: Op) -> Self { - Self{op, phantom: PhantomData} + Self{op} } #[inline] - fn any_vec_raw(&self) -> &AnyVecRaw{ + fn any_vec_raw(&self) -> &AnyVecRaw<::M>{ unsafe{ self.op.any_vec_ptr().any_vec_raw().as_ref() } } } -impl AnyValue for TempValue{ - type Type = Op::Type; +impl AnyValue for TempValue{ + type Type = ::Element; #[inline] fn value_typeid(&self) -> TypeId { - let typeid = TypeId::of::(); + let typeid = TypeId::of::(); if typeid == TypeId::of::(){ self.any_vec_raw().element_typeid() } else { @@ -56,10 +53,10 @@ impl AnyValue for TempValue{ #[inline] fn size(&self) -> usize { - if Unknown::is::() { + if Unknown::is::() { self.any_vec_raw().element_layout().size() } else{ - mem::size_of::() + mem::size_of::() } } @@ -76,12 +73,12 @@ impl AnyValue for TempValue{ } } -impl AnyValueMut for TempValue - where Traits: Cloneable, Op::AnyVecPtr : IAnyVecPtr -{} +impl AnyValueMut for TempValue {} -impl AnyValueCloneable for TempValue - where Traits: Cloneable, Op::AnyVecPtr : IAnyVecPtr +impl AnyValueCloneable for TempValue +where + Op::AnyVecPtr: IAnyVecPtr, + ::Traits: Cloneable { #[inline] unsafe fn clone_into(&self, out: *mut u8) { @@ -90,7 +87,7 @@ impl AnyValueCloneable for TempValue Drop for TempValue{ +impl Drop for TempValue{ #[inline] fn drop(&mut self) { unsafe{ @@ -98,17 +95,26 @@ impl Drop for TempValue{ let element = self.op.bytes() as *mut u8; // compile-time check - if Unknown::is::() { + if Unknown::is::<::Type>() { if let Some(drop_fn) = drop_fn{ (drop_fn)(element, 1); } } else { - ptr::drop_in_place(element as *mut Op::Type); + ptr::drop_in_place(element as *mut ::Type); } } self.op.consume(); } } -unsafe impl Send for TempValue {} -unsafe impl Sync for TempValue {} +unsafe impl Send for TempValue +where + Op::AnyVecPtr: IAnyVecPtr, + ::Traits: Send +{} + +unsafe impl Sync for TempValue +where + Op::AnyVecPtr: IAnyVecPtr, + ::Traits: Sync +{} diff --git a/tests/any_vec.rs b/tests/any_vec.rs index 78cc468..5eff875 100644 --- a/tests/any_vec.rs +++ b/tests/any_vec.rs @@ -5,6 +5,7 @@ use std::ptr::NonNull; use itertools::assert_equal; use any_vec::AnyVec; use any_vec::any_value::{AnyValueRaw, AnyValueWrapper}; +use any_vec::mem::Stack; #[allow(dead_code)] unsafe fn any_as_u8_slice(p: &T) -> &[u8] { @@ -283,6 +284,81 @@ fn any_vec_insert_back(){ assert_equal(vec.as_slice().iter().copied(), 0..100); } +#[test] +fn reserve_test(){ + let mut any_vec: AnyVec = AnyVec::new::(); + assert_eq!(any_vec.capacity(), 0); + + any_vec.reserve(4); + assert_eq!(any_vec.capacity(), 4); + + any_vec.reserve(6); + assert_eq!(any_vec.capacity(), 8); +} + +#[test] +fn reserve_exact_test(){ + let mut any_vec: AnyVec = AnyVec::new::(); + assert_eq!(any_vec.capacity(), 0); + + any_vec.reserve_exact(4); + assert_eq!(any_vec.capacity(), 4); + + any_vec.reserve_exact(6); + assert_eq!(any_vec.capacity(), 6); +} + +#[test] +fn shrink_to_fit_test(){ + let mut any_vec: AnyVec = AnyVec::new::(); + assert_eq!(any_vec.capacity(), 0); + + any_vec.reserve_exact(10); + assert_eq!(any_vec.capacity(), 10); + + any_vec.shrink_to_fit(); + assert_eq!(any_vec.capacity(), 0); +} + +#[test] +fn shrink_to_test(){ + let mut any_vec: AnyVec = AnyVec::new::(); + assert_eq!(any_vec.capacity(), 0); + + any_vec.reserve_exact(10); + assert_eq!(any_vec.capacity(), 10); + + any_vec.shrink_to(5); + assert_eq!(any_vec.capacity(), 5); +} + +#[test] +fn mem_stack_test(){ + use any_vec::traits::None; + type FixedAnyVec = AnyVec>; + + let mut any_vec: FixedAnyVec = AnyVec::new::(); + { + let mut vec = any_vec.downcast_mut::().unwrap(); + vec.push(String::from("0")); + vec.push(String::from("1")); + vec.push(String::from("2")); + vec.push(String::from("3")); + } + + // Should fail to compile. + //any_vec.reserve(1); + + assert_eq!(any_vec.capacity(), 512); + assert_eq!(any_vec.len(), 4); + assert_equal(any_vec.downcast_ref::().unwrap(), &[ + String::from("0"), + String::from("1"), + String::from("2"), + String::from("3") + ]); +} + #[test] fn any_vec_into_iter_test() { let mut any_vec: AnyVec = AnyVec::new::(); diff --git a/tests/any_vec_element.rs b/tests/any_vec_element.rs index 85468ed..0e4d379 100644 --- a/tests/any_vec_element.rs +++ b/tests/any_vec_element.rs @@ -4,6 +4,7 @@ use itertools::{assert_equal}; use any_vec::any_value::{AnyValue, AnyValueCloneable, LazyClone}; use any_vec::AnyVec; use any_vec::element::Element; +use any_vec::mem::Stack; use any_vec::traits::{Cloneable, Trait}; #[test] @@ -154,12 +155,14 @@ fn any_vec_push_to_self_test(){ vec.push(String::from("2")); } - let mut intermediate = any_vec.clone_empty(); + let mut intermediate = any_vec.clone_empty_in(Stack::<512>); intermediate.push(any_vec.get(1).unwrap().lazy_clone()); - let e = intermediate.get(0).unwrap(); + let e = intermediate.pop().unwrap(); any_vec.push(e.lazy_clone()); - any_vec.push(e.lazy_clone()); + any_vec.push(e); + + assert!(intermediate.is_empty()); assert_equal( any_vec.downcast_ref::().unwrap().as_slice(), &[ diff --git a/tests/any_vec_typed.rs b/tests/any_vec_typed.rs index 3d0280b..7670e37 100644 --- a/tests/any_vec_typed.rs +++ b/tests/any_vec_typed.rs @@ -1,4 +1,5 @@ use itertools::assert_equal; +use any_vec::any_value::AnyValueWrapper; use any_vec::AnyVec; #[test] @@ -117,6 +118,29 @@ fn any_vec_drain_in_the_middle_test() { ]); } +#[test] +fn any_vec_splice_lifetime_test() { + let mut any_vec: AnyVec = AnyVec::new::(); + any_vec.push(AnyValueWrapper::new(String::from("0"))); + any_vec.push(AnyValueWrapper::new(String::from("1"))); + any_vec.push(AnyValueWrapper::new(String::from("2"))); + any_vec.push(AnyValueWrapper::new(String::from("3"))); + any_vec.push(AnyValueWrapper::new(String::from("4"))); + + // lifetime check ? + { + let mut vec = any_vec.downcast_mut::().unwrap(); + let replace = [ + String::from("100"), + String::from("200") + ]; + let drained = vec.splice(1..4, replace.iter().cloned()); + drained.count(); + drop(replace); + //drained.count(); + } +} + #[test] pub fn downcast_mut_test(){ let mut any_vec: AnyVec = AnyVec::new::(); From 025672831d631f67c75a63c12c0c49637e36759c Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 22 Jun 2022 00:08:30 +0300 Subject: [PATCH 02/35] v0.9.0 --- CHANGELOG.md | 10 +++++----- Cargo.toml | 2 +- Readme.md | 2 +- src/ops/mod.rs | 1 - 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 891504a..8829de8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,16 @@ # Changelog -## Unreleased +## 0.9.0 ### Added -- `pop` -- `is_empty` -- `AnyVec::clone_empty_in` -- `Stack` Mem/Allocator. - `MemBuilder` + `Mem` = Allocator. +- `Stack` Mem/Allocator. +- `AnyVec::clone_empty_in` - `reserve` - `reserve_exact` - `shrink_to_fit` - `shrink_to` +- `pop` +- `is_empty` ## 0.8.0 ### Added diff --git a/Cargo.toml b/Cargo.toml index 642a5c4..5a90a9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "any_vec" authors = ["Andrey Diduh "] license = "MIT OR Apache-2.0" -version = "0.8.0" +version = "0.9.0" edition = "2021" rust-version = "1.61.0" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." diff --git a/Readme.md b/Readme.md index 6c7383c..3ae6a78 100644 --- a/Readme.md +++ b/Readme.md @@ -7,7 +7,7 @@ Type erased vector. All elements have the same type. Designed to be type-erased as far as possible - most of the operations does not know about concrete type. -Only destruct operations have additional overhead of indirect call. +Only type-erased destruct and clone operations have additional overhead of indirect call. # Usage diff --git a/src/ops/mod.rs b/src/ops/mod.rs index ad475ea..c01b623 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -42,7 +42,6 @@ pub type SwapRemove<'a, Traits, M> = TempValue = Iter>>; -// TODO: change template arguments order /// A splicing [`ElementIterator`] for [`AnyVec`]. Return [`Element`] items. /// /// This is created by [`AnyVec::splice`]. From b470d008ec0a3050b94fa3157aa9291e17b05376 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 23 Jun 2022 00:48:28 +0300 Subject: [PATCH 03/35] AnyVec documentation improved. --- src/any_value/mod.rs | 2 + src/any_vec.rs | 131 ++++++++++++++++++++++++++++++++++++++----- src/any_vec_raw.rs | 2 +- src/any_vec_typed.rs | 13 ++--- src/mem/mod.rs | 23 +++++++- 5 files changed, 146 insertions(+), 25 deletions(-) diff --git a/src/any_value/mod.rs b/src/any_value/mod.rs index e90b008..904b292 100644 --- a/src/any_value/mod.rs +++ b/src/any_value/mod.rs @@ -68,6 +68,8 @@ pub trait AnyValue { tmp.assume_init() } + /// Move self into `out`. + /// /// `out` must have at least [`size`] bytes. /// Will do compile-time optimisation if type/size known. /// diff --git a/src/any_vec.rs b/src/any_vec.rs index 646bf0d..4ac346f 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -89,7 +89,7 @@ impl SatisfyTraits for T{} /// Type erased vec-like container. /// All elements have the same type. /// -/// Only destruct operations have indirect call overhead. +/// Only destruct and clone operations have indirect call overhead. /// /// You can make AnyVec [`Send`]-able, [`Sync`]-able, [`Cloneable`], by /// specifying trait constraints: `AnyVec`. See [`traits`]. @@ -117,7 +117,12 @@ impl AnyVec } } - /// Element should implement requested Traits + /// Constructs empty [`AnyVec`] with elements of type `T`, + /// using [`Default`] [`MemBuilder`]. + /// + /// `T` should satisfy requested Traits. + /// + /// Not available, if provided [`MemBuilder`] is not [`Default`]. #[inline] pub fn new() -> Self where @@ -127,7 +132,10 @@ impl AnyVec Self::new_in::(Default::default()) } - /// Element should implement requested Traits + /// Constructs empty [`AnyVec`] with elements of type `T`, + /// using provided `mem_builder`. + /// + /// `T` should satisfy requested Traits. #[inline] pub fn new_in(mut mem_builder: M) -> Self where T: SatisfyTraits @@ -137,7 +145,13 @@ impl AnyVec Self::build::(raw) } - /// Element should implement requested Traits + /// Constructs empty [`AnyVec`] with specified capacity and + /// elements of type `T`, using [`Default`] [`MemBuilder`]. + /// + /// `T` should satisfy requested Traits. + /// + /// Not available, if provided [`MemBuilder`] is not + /// [`MemBuilderSizeable`] and [`Default`]. #[inline] pub fn with_capacity(capacity: usize) -> Self where @@ -148,7 +162,13 @@ impl AnyVec Self::with_capacity_in::(capacity, Default::default()) } - /// Element should implement requested Traits + /// Constructs empty [`AnyVec`] with specified capacity and + /// elements of type `T`, using `mem_builder`. + /// + /// `T` should satisfy requested Traits. + /// + /// Not available, if provided [`MemBuilder`] is not + /// [`MemBuilderSizeable`]. pub fn with_capacity_in(capacity: usize, mut mem_builder: M) -> Self where T: SatisfyTraits, @@ -159,10 +179,10 @@ impl AnyVec Self::build::(raw) } - /// Same as clone, but without data copy. + /// Constructs **empty** [`AnyVec`] with the same elements type, `Traits` and `MemBuilder`. + /// IOW, same as [`clone`], but without elements copy. /// - /// Since it does not copy underlying data, it works with any [`AnyVec`]. - /// Use it to construct [`AnyVec`] of the same type. + /// [`clone`]: Clone::clone #[inline] pub fn clone_empty(&self) -> Self { Self { @@ -172,6 +192,23 @@ impl AnyVec } } + /// Constructs **empty** [`AnyVec`] with the same elements type and `Traits`, + /// but with other `MemBuilder`. + /// + /// Use it to construct intermediate storage, with fast [`MemBuilder`]. + /// + /// # Example + /// + /// ``` + /// # use any_vec::any_value::AnyValueCloneable; + /// # use any_vec::AnyVec; + /// # use any_vec::mem::Stack; + /// # use any_vec::traits::Cloneable; + /// # let mut any_vec: AnyVec = AnyVec::new::(); + /// let mut tmp = any_vec.clone_empty_in(Stack::<256>); + /// tmp.push(any_vec.at(0).lazy_clone()); + /// any_vec.push(tmp.pop().unwrap()); + /// ``` #[inline] pub fn clone_empty_in(&self, mem_builder: NewM) -> AnyVec { AnyVec { @@ -186,6 +223,17 @@ impl AnyVec ::get(self.clone_fn) } + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the given container. More space may be reserved to avoid + /// frequent reallocations. After calling `reserve`, capacity will be + /// greater than or equal to `self.len() + additional`. Exact behavior defined by + /// implementation of [`MemResizable`]. Does nothing if capacity is already sufficient. + /// + /// Not available, if provided [`MemBuilder::Mem`] is not [`MemResizable`]. + /// + /// # Panics + /// + /// [`MemResizable`] implementation may panic - see implementation description. #[inline] pub fn reserve(&mut self, additional: usize) where M::Mem: MemResizable @@ -193,6 +241,23 @@ impl AnyVec self.raw.reserve(additional) } + /// Reserves the minimum capacity for exactly `additional` more elements to + /// be inserted in the given container. After calling `reserve_exact`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Exact behavior defined by implementation of [`MemResizable`]. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the [`Mem`] implementation may grow bigger then requested. + /// Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// Not available, if provided [`MemBuilder::Mem`] is not [`MemResizable`]. + /// + /// # Panics + /// + /// [`MemResizable`] implementation may panic - see implementation description. + /// + /// [`reserve`]: Self::reserve #[inline] pub fn reserve_exact(&mut self, additional: usize) where M::Mem: MemResizable @@ -200,6 +265,14 @@ impl AnyVec self.raw.reserve_exact(additional) } + /// Shrinks the capacity as much as possible. + /// Exact behavior defined by implementation of [`MemResizable`]. + /// + /// Not available, if provided [`MemBuilder::Mem`] is not [`MemResizable`]. + /// + /// # Panics + /// + /// [`MemResizable`] implementation may panic - see implementation description. #[inline] pub fn shrink_to_fit(&mut self) where M::Mem: MemResizable @@ -207,6 +280,18 @@ impl AnyVec self.raw.shrink_to_fit() } + /// Shrinks the capacity of the vector with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. Exact behavior defined by implementation of [`MemResizable`]. + /// + /// If the current capacity is less than the lower limit, this is a no-op. + /// + /// Not available, if provided [`MemBuilder::Mem`] is not [`MemResizable`]. + /// + /// # Panics + /// + /// [`MemResizable`] implementation may panic - see implementation description. #[inline] pub fn shrink_to(&mut self, min_capacity: usize) where M::Mem: MemResizable @@ -214,31 +299,47 @@ impl AnyVec self.raw.shrink_to(min_capacity) } + /// Returns [`AnyVecRef`] - typed view to const AnyVec, + /// if container holds elements of type T, or None if it isn’t. #[inline] - pub fn downcast_ref(&self) -> Option> { - if self.element_typeid() == TypeId::of::() { + pub fn downcast_ref(&self) -> Option> { + if self.element_typeid() == TypeId::of::() { unsafe{ Some(self.downcast_ref_unchecked()) } } else { None } } + /// Returns [`AnyVecRef`] - typed view to const AnyVec. + /// + /// # Safety + /// + /// The container elements must be of type `T`. + /// Calling this method with the incorrect type is undefined behavior. #[inline] - pub unsafe fn downcast_ref_unchecked(&self) -> AnyVecRef { + pub unsafe fn downcast_ref_unchecked(&self) -> AnyVecRef { AnyVecRef(AnyVecTyped::new(NonNull::from(&self.raw))) } + /// Returns [`AnyVecMut`] - typed view to mut AnyVec, + /// if container holds elements of type T, or None if it isn’t. #[inline] - pub fn downcast_mut(&mut self) -> Option> { - if self.element_typeid() == TypeId::of::() { + pub fn downcast_mut(&mut self) -> Option> { + if self.element_typeid() == TypeId::of::() { unsafe{ Some(self.downcast_mut_unchecked()) } } else { None } } + /// Returns [`AnyVecMut`] - typed view to mut AnyVec. + /// + /// # Safety + /// + /// The container elements must be of type `T`. + /// Calling this method with the incorrect type is undefined behavior. #[inline] - pub unsafe fn downcast_mut_unchecked(&mut self) -> AnyVecMut { + pub unsafe fn downcast_mut_unchecked(&mut self) -> AnyVecMut { AnyVecMut(AnyVecTyped::new(NonNull::from(&mut self.raw))) } @@ -293,7 +394,7 @@ impl AnyVec ElementRef(self.get_element(index)) } - /// Return reference to element at `index` with bounds check. + /// Return mutable reference to element at `index` with bounds check. /// /// # Panics /// diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index 43a601e..2dd6a93 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -8,7 +8,7 @@ use crate::mem::{Mem, MemBuilder, MemResizable}; pub type DropFn = fn(ptr: *mut u8, len: usize); pub struct AnyVecRaw { - mem_builder: M,// usually ZST + mem_builder: M, // usually ZST pub(crate) mem: M::Mem, pub(crate) len: usize, // in elements type_id: TypeId, // purely for safety checks diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index 3044b31..e924c30 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -15,7 +15,12 @@ use crate::ops::splice::Splice; /// Concrete type [`AnyVec`] representation. /// /// Created with [`AnyVec::downcast_`]-family. -/// Accessed through [`AnyVecRef`] or [`AnyVecMut`] +/// Accessed through [`AnyVecRef`] or [`AnyVecMut`]. +/// See [`AnyVec`] for documentation. +/// +/// Operations with concrete type are somewhat faster, due to +/// the fact, that compiler are able to optimize harder with full +/// type knowledge. /// /// [`AnyVec`]: crate::AnyVec /// [`AnyVec::downcast_`]: crate::AnyVec::downcast_ref @@ -183,9 +188,6 @@ impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ self.as_mut_slice().iter_mut() } - /// # Panics - /// - /// * Panics if index is out of bounds. #[inline] pub fn at(&self, index: usize) -> &'a T{ self.get(index).unwrap() @@ -201,9 +203,6 @@ impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ self.as_slice().get_unchecked(index) } - /// # Panics - /// - /// * Panics if index is out of bounds. #[inline] pub fn at_mut(&mut self, index: usize) -> &'a mut T{ self.get_mut(index).unwrap() diff --git a/src/mem/mod.rs b/src/mem/mod.rs index b488683..4dad953 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -48,10 +48,19 @@ pub trait Mem{ /// In elements. fn size(&self) -> usize; + /// Expand `Mem` size for **at least** `additional` more elements. + /// Implementation encouraged to avoid frequent reallocations. + /// + /// # Notes + /// /// Consider, that `expand` is in [`MemResizable`]. /// Implement this only if your type [`MemResizable`]. /// /// It's here, only due to technical reasons (see `AnyVecRaw::reserve`). + /// + /// # Panics + /// + /// Implementation may panic, if fail to allocate/reallocate memory. fn expand(&mut self, additional: usize){ drop(additional); panic!("Can't change capacity!"); @@ -62,12 +71,22 @@ pub trait Mem{ } } -/// Marker trait for resizable [`Mem`]. +/// Resizable [`Mem`]. pub trait MemResizable: Mem{ + /// Expand `Mem` size for **exactly** `additional` more elements. + /// Implementation encouraged to be as precise as possible with new memory size. + /// + /// # Panics + /// + /// Implementation may panic, if fail to allocate/reallocate memory. fn expand_exact(&mut self, additional: usize){ self.resize(self.size() + additional); } - /// Do panic if can't resize. + /// Resize memory chunk to specified size. + /// + /// # Panics + /// + /// Implementation may panic, if fail to allocate/reallocate/deallocate memory. fn resize(&mut self, new_size: usize); } \ No newline at end of file From b4d5893e0803de82d4ead4f956398f85583ed214 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 23 Jun 2022 01:18:57 +0300 Subject: [PATCH 04/35] AnyValue description in lib --- Readme.md | 2 +- src/lib.rs | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 3ae6a78..81a9ba8 100644 --- a/Readme.md +++ b/Readme.md @@ -28,7 +28,7 @@ Only type-erased destruct and clone operations have additional overhead of indir other_vec.push(element); // Output 2 1 - for s in vec.downcast_ref::().unwrap().as_slice(){ + for s in vec.downcast_ref::().unwrap(){ println!("{}", s); } ``` diff --git a/src/lib.rs b/src/lib.rs index 9e9140f..41d81f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ //! other_vec.push(element); //! //! // Output 2 1 -//! for s in vec.downcast_ref::().unwrap().as_slice(){ +//! for s in vec.downcast_ref::().unwrap(){ //! println!("{}", s); //! } //! @@ -111,12 +111,29 @@ //! } //!``` //! -//! [`MemBuilder`] interface, being stateful, allow to make [`Mem`], which can work with complex custom allocators. +//! [`MemBuilder`] interface, being stateful, allow to make [`Mem`], +//! which can work with complex custom allocators. //! //! [`MemBuilder`]: mem::MemBuilder //! [`Mem`]: mem::Mem //! [`Allocator`]: std::alloc::Allocator //! [`clone_empty_in`]: AnyVec::clone_empty_in +//! +//! # AnyValue +//! +//! Being type erased, [`AnyVec`] need a way to operate on untyped values safely. +//! Instead of working with plain `*mut u8`, [`AnyVec`] operates with [`AnyValue`]. +//! +//! [`AnyValue`] is trait, which provide operations to work with type erased values. +//! Any type that implement [`AnyValue`] can be used with [`AnyVec`]. +//! [`AnyValue`] interface allows to perform postponed operations on consumption. +//! This trick used heavily by [`AnyVec`] destructive operations, which instead of concrete +//! type return [`AnyValue`], which perform actual operation on value drop. +//! +//! Implementing [`AnyValueMut`] and [`AnyValueCloneable`] makes type mutable and +//! cloneable respectively. +//! +//! [`AnyValueMut`]: crate::any_value::AnyValueMut` mod any_vec; mod clone_type; From 6823dbd189431827f69b3f7717c2484b0331b10e Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 23 Jun 2022 02:28:14 +0300 Subject: [PATCH 05/35] doc test fix --- src/any_vec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/any_vec.rs b/src/any_vec.rs index 4ac346f..1861ba2 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -205,6 +205,7 @@ impl AnyVec /// # use any_vec::mem::Stack; /// # use any_vec::traits::Cloneable; /// # let mut any_vec: AnyVec = AnyVec::new::(); + /// # any_vec.downcast_mut::().unwrap().push(String::from("0")); /// let mut tmp = any_vec.clone_empty_in(Stack::<256>); /// tmp.push(any_vec.at(0).lazy_clone()); /// any_vec.push(tmp.pop().unwrap()); From df7280afeb0e2b95e1b5675a7cd5f8d34e9c0934 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 23 Jun 2022 23:22:49 +0300 Subject: [PATCH 06/35] StackMem::as_ptr UB fix --- CHANGELOG.md | 4 ++++ src/mem/stack.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8829de8..8320677 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.9.1 +### Fixed +- Fixed UB with `StackMem::as_ptr`. + ## 0.9.0 ### Added - `MemBuilder` + `Mem` = Allocator. diff --git a/src/mem/stack.rs b/src/mem/stack.rs index acddfdd..a43e244 100644 --- a/src/mem/stack.rs +++ b/src/mem/stack.rs @@ -27,12 +27,12 @@ pub struct StackMem{ impl Mem for StackMem{ #[inline] fn as_ptr(&self) -> *const u8 { - unsafe{self.mem.assume_init_ref()}.as_ptr() + self.mem.as_ptr() as *const u8 } #[inline] fn as_mut_ptr(&mut self) -> *mut u8 { - unsafe{self.mem.assume_init_mut()}.as_mut_ptr() + self.mem.as_mut_ptr() as *mut u8 } #[inline] From ab1ff41464349ff6d72f02c0c6ef2a1b9d325116 Mon Sep 17 00:00:00 2001 From: tower120 Date: Tue, 28 Jun 2022 13:43:12 +0300 Subject: [PATCH 07/35] Send sync fix + CloneFn refactor --- .github/workflows/ci.yml | 32 +++++++------- CHANGELOG.md | 6 +++ Cargo.toml | 11 ++++- Readme.md | 5 --- benches/clone.rs | 48 ++++++++++++++++++++ benches/element_clone.rs | 88 ++++++++++++++++++++++++++++++++++++ src/any_value/mod.rs | 11 ----- src/any_vec.rs | 12 +++-- src/any_vec_raw.rs | 11 +---- src/any_vec_typed.rs | 8 +++- src/clone_type.rs | 36 +++++++-------- src/element.rs | 24 +++++++--- src/iter.rs | 34 +++++++++++--- src/mem/heap.rs | 14 ++++-- src/ops/drain.rs | 16 +------ src/ops/splice.rs | 38 +--------------- src/ops/temp.rs | 17 ++++--- tests/any_vec_send_sync.rs | 91 ++++++++++++++++++++++++++++++++++++++ 18 files changed, 365 insertions(+), 137 deletions(-) create mode 100644 benches/clone.rs create mode 100644 benches/element_clone.rs create mode 100644 tests/any_vec_send_sync.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55dd1af..63d7f45 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: push: branches: [ main, dev ] pull_request: - branches: [ main ] + branches: [ main, dev ] env: CARGO_TERM_COLOR: always @@ -14,9 +14,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: ATiltedTree/setup-rust@v1 - with: - rust-version: stable + #- uses: ATiltedTree/setup-rust@v1 + # with: + # rust-version: stable - name: Build run: RUSTFLAGS="--deny warnings" cargo build @@ -24,9 +24,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: ATiltedTree/setup-rust@v1 - with: - rust-version: stable + #- uses: ATiltedTree/setup-rust@v1 + # with: + # rust-version: stable - name: Build with all features run: RUSTFLAGS="--deny warnings" cargo build --all-features @@ -34,9 +34,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: ATiltedTree/setup-rust@v1 - with: - rust-version: stable + #- uses: ATiltedTree/setup-rust@v1 + # with: + # rust-version: stable - name: Run tests run: RUSTFLAGS="--deny warnings" cargo test --all-features @@ -55,9 +55,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: ATiltedTree/setup-rust@v1 - with: - rust-version: stable + #- uses: ATiltedTree/setup-rust@v1 + # with: + # rust-version: stable - name: Build benches run: RUSTFLAGS="--deny warnings" cargo build --benches @@ -65,8 +65,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: ATiltedTree/setup-rust@v1 - with: - rust-version: stable + #- uses: ATiltedTree/setup-rust@v1 + # with: + # rust-version: stable - name: Build doc run: RUSTFLAGS="--deny warnings" cargo doc --lib \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8320677..fad9957 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,13 @@ # Changelog ## 0.9.1 +### Changed +- `impls` dependency dropped. +- minimum rust version 1.61 requirement dropped. + ### Fixed +- Empty `HeapMem` used wrong aligned dangling pointer. Fixed. +- `AnyVec` Send/Sync -ability now MemBuilder dependent. - Fixed UB with `StackMem::as_ptr`. ## 0.9.0 diff --git a/Cargo.toml b/Cargo.toml index 5a90a9c..01d0292 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ authors = ["Andrey Diduh "] license = "MIT OR Apache-2.0" version = "0.9.0" edition = "2021" -rust-version = "1.61.0" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." repository = "https://github.com/tower120/any_vec" keywords = ["vec", "any", "container"] @@ -12,12 +11,12 @@ categories = ["data-structures"] exclude = [".github"] [dependencies] -impls = "1.0.3" [dev-dependencies] itertools = "0.10.3" criterion = "0.3.5" rand = "0.8.5" +impls = "1.0.3" [[bench]] name = "insert" @@ -41,4 +40,12 @@ harness = false [[bench]] name = "iter" +harness = false + +[[bench]] +name = "element_clone" +harness = false + +[[bench]] +name = "clone" harness = false \ No newline at end of file diff --git a/Readme.md b/Readme.md index 81a9ba8..d61a58c 100644 --- a/Readme.md +++ b/Readme.md @@ -96,11 +96,6 @@ fn self_push_first_element(any_vec: &mut AnyVec){ See [CHANGELOG.md](CHANGELOG.md) for version differences. -#### N.B. - -*Currently, minimum rust version is 1.61. This is to simplify implementation. -If you need `any_vec` to work on lower rust version - please feel free to make an issue.* - # Known alternatives * [type_erased_vec](https://crates.io/crates/type_erased_vec). Allow to store `Vec` in type erased way, diff --git a/benches/clone.rs b/benches/clone.rs new file mode 100644 index 0000000..e1d79af --- /dev/null +++ b/benches/clone.rs @@ -0,0 +1,48 @@ +mod utils; + +use std::time::{Duration, Instant}; +use criterion::{criterion_group, criterion_main, Criterion, black_box}; +use any_vec::AnyVec; +use any_vec::traits::Cloneable; +use crate::utils::bench_custom; + +const SIZE: usize = 10000; + +// usize is worst case scenario, since it is copyable. +type Element = usize; +static VALUE: Element = 100; + +fn vec_clone() -> Duration { + let mut vec = Vec::new(); + for _ in 0..SIZE{ + vec.push(VALUE.clone()); + } + + let start = Instant::now(); + let other = vec.clone(); + black_box(other); + start.elapsed() +} + + +fn any_vec_clone() -> Duration { + let mut any_vec: AnyVec = AnyVec::new::(); + for _ in 0..SIZE{ + any_vec.downcast_mut::().unwrap() + .push(VALUE.clone()); + } + + let start = Instant::now(); + let other = any_vec.clone(); + black_box(other); + start.elapsed() +} + + +pub fn bench_clone(c: &mut Criterion) { + bench_custom(c, "Vec clone", vec_clone); + bench_custom(c, "AnyVec clone", any_vec_clone); +} + +criterion_group!(benches, bench_clone); +criterion_main!(benches); \ No newline at end of file diff --git a/benches/element_clone.rs b/benches/element_clone.rs new file mode 100644 index 0000000..8c7bccf --- /dev/null +++ b/benches/element_clone.rs @@ -0,0 +1,88 @@ +mod utils; + +use std::time::{Duration, Instant}; +use criterion::{criterion_group, criterion_main, Criterion, black_box}; +use any_vec::any_value::{AnyValue, AnyValueCloneable}; +use any_vec::AnyVec; +use any_vec::traits::Cloneable; +use crate::utils::bench_custom; + +const SIZE: usize = 10000; + +// usize is worst case scenario, since it is copyable. +type Element = usize; +static VALUE: Element = 100; + +fn vec_iter_clone() -> Duration { + let mut vec = Vec::new(); + for _ in 0..SIZE{ + vec.push(VALUE.clone()); + } + + let start = Instant::now(); + let mut sum = 0; + for i in &vec{ + sum += i.clone(); + } + black_box(sum); + start.elapsed() +} + +fn any_vec_iter() -> Duration { + let mut any_vec: AnyVec = AnyVec::new::(); + for _ in 0..SIZE{ + any_vec.downcast_mut::().unwrap() + .push(VALUE.clone()); + } + + let start = Instant::now(); + let mut sum = 0; + for i in &any_vec{ + sum += unsafe{i.downcast_ref_unchecked::()}; + } + black_box(sum); + start.elapsed() +} + +fn any_vec_iter_clone() -> Duration { + let mut any_vec: AnyVec = AnyVec::new::(); + for _ in 0..SIZE{ + any_vec.downcast_mut::().unwrap() + .push(VALUE.clone()); + } + + let start = Instant::now(); + let mut sum = 0; + for i in &any_vec{ + sum += unsafe{i.lazy_clone().downcast_ref_unchecked::()}; + } + black_box(sum); + start.elapsed() +} + +fn any_vec_typed_iter_clone() -> Duration { + let mut any_vec: AnyVec = AnyVec::new::(); + let mut vec = any_vec.downcast_mut::().unwrap(); + for _ in 0..SIZE{ + vec.push(VALUE.clone()); + } + + let start = Instant::now(); + let mut sum = 0; + for i in vec{ + sum += i.clone(); + } + black_box(sum); + start.elapsed() +} + + +pub fn bench_element_clone(c: &mut Criterion) { + bench_custom(c, "Vec iter clone", vec_iter_clone); + bench_custom(c, "AnyVec iter", any_vec_iter); + bench_custom(c, "AnyVec iter clone", any_vec_iter_clone); + bench_custom(c, "AnyVecTyped iter clone", any_vec_typed_iter_clone); +} + +criterion_group!(benches, bench_element_clone); +criterion_main!(benches); \ No newline at end of file diff --git a/src/any_value/mod.rs b/src/any_value/mod.rs index 904b292..a25a314 100644 --- a/src/any_value/mod.rs +++ b/src/any_value/mod.rs @@ -9,7 +9,6 @@ pub use raw::AnyValueRaw; use std::any::TypeId; use std::{mem, ptr}; use std::mem::MaybeUninit; -use crate::clone_type::CloneFn; use crate::copy_bytes_nonoverlapping; /// Marker for unknown type. @@ -132,13 +131,3 @@ pub trait AnyValueCloneable: AnyValue { LazyClone::new(self) } } - -/// Helper function, which utilize type knowledge. -#[inline] -pub(crate) unsafe fn clone_into(any_value: &impl AnyValue, out: *mut u8, clone_fn: Option) { - if let Some(clone_fn) = clone_fn{ - (clone_fn)(any_value.bytes(), out, 1); - } else { - copy_bytes(any_value, out); - } -} \ No newline at end of file diff --git a/src/any_vec.rs b/src/any_vec.rs index 1861ba2..d642358 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -101,7 +101,7 @@ impl SatisfyTraits for T{} pub struct AnyVec { pub(crate) raw: AnyVecRaw, - clone_fn: ::Type, + clone_fn: ::Type, // ZST if Traits: !Cloneable phantom: PhantomData } @@ -220,7 +220,7 @@ impl AnyVec } #[inline] - pub(crate) fn clone_fn(&self) -> Option{ + pub(crate) fn clone_fn(&self) -> CloneFn{ ::get(self.clone_fn) } @@ -603,8 +603,12 @@ impl AnyVec } } -unsafe impl Send for AnyVec {} -unsafe impl Sync for AnyVec {} +unsafe impl Send for AnyVec + where M::Mem: Send +{} +unsafe impl Sync for AnyVec + where M::Mem: Sync +{} impl Clone for AnyVec { fn clone(&self) -> Self { diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index 2dd6a93..a9096a4 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -62,7 +62,7 @@ impl AnyVecRaw { } /// Unsafe, because type cloneability is not checked - pub(crate) unsafe fn clone(&self, clone_fn: Option) -> Self { + pub(crate) unsafe fn clone(&self, clone_fn: CloneFn) -> Self { // 1. construct empty "prototype" let mut cloned = self.clone_empty(); @@ -73,14 +73,7 @@ impl AnyVecRaw { { let src = self.mem.as_ptr(); let dst = cloned.mem.as_mut_ptr(); - if let Some(clone_fn) = clone_fn{ - (clone_fn)(src, dst, self.len); - } else { - ptr::copy_nonoverlapping( - src, dst, - self.element_layout().size() * self.len - ); - } + (clone_fn)(src, dst, self.len); } // 4. set len diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index e924c30..52d13be 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -32,8 +32,12 @@ pub struct AnyVecTyped<'a, T: 'static, M: MemBuilder + 'a>{ phantom: PhantomData<&'a mut T> } -unsafe impl<'a, T: 'static + Send, M: MemBuilder> Send for AnyVecTyped<'a, T, M> {} -unsafe impl<'a, T: 'static + Sync, M: MemBuilder> Sync for AnyVecTyped<'a, T, M> {} +unsafe impl<'a, T: 'static + Send, M: MemBuilder + Send> Send for AnyVecTyped<'a, T, M> + where M::Mem: Send +{} +unsafe impl<'a, T: 'static + Sync, M: MemBuilder + Sync> Sync for AnyVecTyped<'a, T, M> + where M::Mem: Sync +{} impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ /// # Safety diff --git a/src/clone_type.rs b/src/clone_type.rs index 2143230..60aae21 100644 --- a/src/clone_type.rs +++ b/src/clone_type.rs @@ -7,7 +7,7 @@ use crate::traits::*; #[derive(Copy, Clone, Default)] pub struct Empty; -pub type CloneFn = fn(*const u8, *mut u8, usize); +pub type CloneFn = fn(src: *const u8, dst: *mut u8, len: usize); fn clone_fn(src: *const u8, dst: *mut u8, len: usize){ let src = src as *const T; let dst = dst as *mut T; @@ -19,27 +19,23 @@ fn clone_fn(src: *const u8, dst: *mut u8, len: usize){ } } } -const fn get_clone_fn() -> Option{ - if impls::impls!(T: Copy){ - None - } else { - Some(clone_fn::) - } -} +fn nop_fn(_: *const u8, _: *mut u8, _: usize){} + + pub trait CloneFnTrait{ - const CLONE_FN: Option = None; + const CLONE_FN: CloneFn = nop_fn; } impl CloneFnTrait for T{ - const CLONE_FN: Option = get_clone_fn::(); + const CLONE_FN: CloneFn = clone_fn::; } impl CloneFnTrait for T{ - const CLONE_FN: Option = get_clone_fn::(); + const CLONE_FN: CloneFn = clone_fn::; } impl CloneFnTrait for T{ - const CLONE_FN: Option = get_clone_fn::(); + const CLONE_FN: CloneFn = clone_fn::; } impl CloneFnTrait for T{ - const CLONE_FN: Option = get_clone_fn::(); + const CLONE_FN: CloneFn = clone_fn::; } impl CloneFnTrait for T{} impl CloneFnTrait for T{} @@ -51,24 +47,24 @@ impl CloneFnTrait for T{} /// when non-Cloneable. pub trait CloneType{ type Type: Copy; - fn new(f: Option) -> Self::Type; - fn get(f: Self::Type) -> Option; + fn new(f: CloneFn) -> Self::Type; + fn get(f: Self::Type) -> CloneFn; } macro_rules! impl_clone_type_empty { ($t:ty) => { impl CloneType for $t { type Type = Empty; - fn new(_: Option) -> Self::Type{ Empty } - fn get(_: Self::Type) -> Option{ None } + fn new(_: CloneFn) -> Self::Type{ Empty } + fn get(_: Self::Type) -> CloneFn{ nop_fn } } } } macro_rules! impl_clone_type_fn { ($t:ty) => { impl CloneType for $t { - type Type = Option; - fn new(f: Option) -> Self::Type{ f } - fn get(f: Self::Type) -> Option{ f as Option } + type Type = CloneFn; + fn new(f: CloneFn) -> Self::Type{ f } + fn get(f: Self::Type) -> CloneFn{ f as CloneFn } } } } diff --git a/src/element.rs b/src/element.rs index 34db307..527ab9a 100644 --- a/src/element.rs +++ b/src/element.rs @@ -3,10 +3,10 @@ use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; -use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, clone_into}; +use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{AnyVecPtr, IAnyVecPtr, IAnyVecRawPtr}; -use crate::mem; +use crate::{AnyVec, mem}; use crate::mem::MemBuilder; use crate::traits::{Cloneable, None, Trait}; @@ -112,12 +112,26 @@ impl<'a, Traits: ?Sized + Cloneable + Trait, M: MemBuilder> { #[inline] unsafe fn clone_into(&self, out: *mut u8) { - clone_into(self, out, self.any_vec_ptr.any_vec().as_ref().clone_fn()); + let clone_fn = self.any_vec_ptr.any_vec().as_ref().clone_fn(); + (clone_fn)(self.bytes(), out, 1); } } -unsafe impl<'a, Traits: ?Sized + Send + Trait, M: MemBuilder> Send for ElementPointer<'a, AnyVecPtr>{} -unsafe impl<'a, Traits: ?Sized + Sync + Trait, M: MemBuilder> Sync for ElementPointer<'a, AnyVecPtr>{} +unsafe impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Send +for + ElementPointer<'a, AnyVecPtr> +where + AnyVec: Send +{} + +unsafe impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Sync +for + ElementPointer<'a, AnyVecPtr> +where + AnyVec: Sync +{} + +// Do not implement Send/Sync for AnyVecPtrRaw, since it will be casted to concrete type anyway. /// [`AnyVec`] element. diff --git a/src/iter.rs b/src/iter.rs index a53eaf0..c9f6ff1 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -2,9 +2,10 @@ use std::iter::{FusedIterator}; use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ptr::NonNull; -use crate::any_vec_ptr::{AnyVecPtr, IAnyVecRawPtr}; +use crate::any_vec_ptr::{AnyVecPtr, AnyVecRawPtr, IAnyVecRawPtr}; use crate::any_vec_ptr::utils::element_ptr_at; use crate::any_vec_raw::AnyVecRaw; +use crate::{AnyVec, AnyVecTyped}; use crate::element::{ElementPointer, ElementMut, ElementRef}; use crate::mem::MemBuilder; use crate::traits::Trait; @@ -130,14 +131,37 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> FusedI for Iter<'a, AnyVecPtr, IterItem> {} + // According to https://github.com/rust-lang/rust/issues/93367#issuecomment-1154832012 #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Send + Trait, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecPtr>> Send - for Iter<'a, AnyVecPtr, IterItem> {} +unsafe impl<'a, Traits: ?Sized + Trait, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecPtr>> Send +for + Iter<'a, AnyVecPtr, IterItem> +where + AnyVec: Send +{} +#[allow(suspicious_auto_trait_impls)] +unsafe impl<'a, T, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecRawPtr>> Send +for + Iter<'a, AnyVecRawPtr, IterItem> +where + AnyVecTyped<'a, T, M>: Send +{} #[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Sync + Trait, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecPtr>> Sync - for Iter<'a, AnyVecPtr, IterItem> {} +unsafe impl<'a, Traits: ?Sized + Trait, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecPtr>> Sync +for + Iter<'a, AnyVecPtr, IterItem> +where + AnyVec: Sync +{} +#[allow(suspicious_auto_trait_impls)] +unsafe impl<'a, T: Sync, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecRawPtr>> Sync +for + Iter<'a, AnyVecRawPtr, IterItem> +where + AnyVecTyped<'a, T, M>: Sync +{} pub trait IteratorItem<'a, AnyVecPtr: IAnyVecRawPtr>{ diff --git a/src/mem/heap.rs b/src/mem/heap.rs index 2634c8a..d364fd7 100644 --- a/src/mem/heap.rs +++ b/src/mem/heap.rs @@ -3,6 +3,11 @@ use std::cmp; use std::ptr::NonNull; use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemResizable}; +#[inline] +fn dangling(layout: &Layout) -> NonNull{ + //layout.dangling() + unsafe { NonNull::new_unchecked(layout.align() as *mut u8) } +} /// Heap allocated memory. #[derive(Default, Clone)] @@ -13,7 +18,7 @@ impl MemBuilder for Heap { #[inline] fn build(&mut self, element_layout: Layout) -> HeapMem { HeapMem { - mem: NonNull::::dangling(), + mem: dangling(&element_layout), size: 0, element_layout } @@ -80,7 +85,7 @@ impl MemResizable for HeapMem { self.mem = if new_size == 0 { dealloc(self.mem.as_ptr(), mem_layout); - NonNull::::dangling() + dangling(&self.element_layout) } else { // mul carefully, to prevent overflow. let new_mem_size = self.element_layout.size() @@ -110,4 +115,7 @@ impl Drop for HeapMem { fn drop(&mut self) { self.resize(0); } -} \ No newline at end of file +} + +unsafe impl Send for HeapMem{} +unsafe impl Sync for HeapMem{} \ No newline at end of file diff --git a/src/ops/drain.rs b/src/ops/drain.rs index 578522b..e4be11d 100644 --- a/src/ops/drain.rs +++ b/src/ops/drain.rs @@ -1,9 +1,7 @@ -use crate::any_vec_ptr::{AnyVecPtr, AnyVecRawPtr, IAnyVecRawPtr}; +use crate::any_vec_ptr::IAnyVecRawPtr; use crate::iter::Iter; use crate::any_vec_ptr; -use crate::mem::{MemBuilder}; use crate::ops::iter::Iterable; -use crate::traits::Trait; pub struct Drain<'a, AnyVecPtr: IAnyVecRawPtr> { @@ -79,14 +77,4 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Drop for Drain<'a, AnyVecPtr> let any_vec_raw = unsafe{ self.iter.any_vec_ptr.any_vec_raw().as_mut() }; any_vec_raw.len = self.original_len - distance; } -} - -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Sync + Trait, M: MemBuilder> Sync for Drain<'a, AnyVecPtr>{} -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Type: Sync, M: MemBuilder> Sync for Drain<'a, AnyVecRawPtr>{} - -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Send + Trait, M: MemBuilder> Send for Drain<'a, AnyVecPtr>{} -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Type: Send, M: MemBuilder> Send for Drain<'a, AnyVecRawPtr>{} \ No newline at end of file +} \ No newline at end of file diff --git a/src/ops/splice.rs b/src/ops/splice.rs index 5fc1f28..74135e7 100644 --- a/src/ops/splice.rs +++ b/src/ops/splice.rs @@ -1,9 +1,7 @@ -use crate::any_vec_ptr::{AnyVecPtr, AnyVecRawPtr, IAnyVecRawPtr}; +use crate::any_vec_ptr::IAnyVecRawPtr; use crate::{any_vec_ptr, Iter}; use crate::any_value::AnyValue; -use crate::mem::MemBuilder; use crate::ops::iter::Iterable; -use crate::traits::Trait; pub struct Splice<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> where @@ -116,36 +114,4 @@ where any_vec_raw.len = new_len; } } -} - - -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Send + Trait, M: MemBuilder, ReplaceIter: ExactSizeIterator> Send -for - Splice<'a, AnyVecPtr, ReplaceIter> -where - ReplaceIter::Item: AnyValue + Send -{} -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Type: Send, M: MemBuilder, ReplaceIter: ExactSizeIterator> Send -for - Splice<'a, AnyVecRawPtr, ReplaceIter> -where - ReplaceIter::Item: AnyValue + Send -{} - - -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Sync + Trait, M: MemBuilder, ReplaceIter: ExactSizeIterator> Sync -for - Splice<'a, AnyVecPtr, ReplaceIter> -where - ReplaceIter::Item: AnyValue + Sync -{} -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Type: Sync, M: MemBuilder, ReplaceIter: ExactSizeIterator> Sync -for - Splice<'a, AnyVecRawPtr, ReplaceIter> -where - ReplaceIter::Item: AnyValue + Sync -{} +} \ No newline at end of file diff --git a/src/ops/temp.rs b/src/ops/temp.rs index 9661c06..93d238e 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -1,8 +1,9 @@ use std::any::TypeId; use std::{mem, ptr}; -use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, clone_into, copy_bytes, Unknown}; +use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, copy_bytes, Unknown}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{IAnyVecPtr, IAnyVecRawPtr}; +use crate::AnyVec; use crate::traits::Cloneable; pub trait Operation { @@ -82,8 +83,8 @@ where { #[inline] unsafe fn clone_into(&self, out: *mut u8) { - let any_vec = self.op.any_vec_ptr().any_vec().as_ref(); - clone_into(self, out, any_vec.clone_fn()); + let clone_fn = self.op.any_vec_ptr().any_vec().as_ref().clone_fn(); + (clone_fn)(self.bytes(), out, 1); } } @@ -110,11 +111,17 @@ impl Drop for TempValue{ unsafe impl Send for TempValue where Op::AnyVecPtr: IAnyVecPtr, - ::Traits: Send + AnyVec< + ::Traits, + ::M + >: Send {} unsafe impl Sync for TempValue where Op::AnyVecPtr: IAnyVecPtr, - ::Traits: Sync + AnyVec< + ::Traits, + ::M + >: Sync {} diff --git a/tests/any_vec_send_sync.rs b/tests/any_vec_send_sync.rs new file mode 100644 index 0000000..b4b6d42 --- /dev/null +++ b/tests/any_vec_send_sync.rs @@ -0,0 +1,91 @@ +use std::iter; +use impls::impls; +use any_vec::{AnyVec, AnyVecMut, IterMut, IterRef, mem}; +use any_vec::any_value::AnyValueWrapper; +use any_vec::mem::MemBuilder; +use any_vec::ops::Drain; +use any_vec::ops::Splice; +use any_vec::traits::None; + +const fn is_send(_: &impl Send){} +const fn is_sync(_: &impl Sync){} + +#[test] +fn any_vec_heap_send_sync_test() { + fn test_negative() + { + let mut any_vec: AnyVec = AnyVec::new::(); + assert!(!impls!(AnyVec: Send)); + assert!(!impls!(AnyVec: Sync)); + { + let iter: IterRef = any_vec.iter(); + assert!(!impls!(IterRef: Send)); + assert!(!impls!(IterRef: Sync)); + drop(iter); + } + { + let iter: IterMut = any_vec.iter_mut(); + assert!(!impls!(IterMut: Send)); + assert!(!impls!(IterMut: Sync)); + drop(iter); + } + + { + let vec: AnyVecMut = any_vec.downcast_mut::().unwrap(); + assert!(!impls!(AnyVecMut: Send)); + assert!(!impls!(AnyVecMut: Sync)); + drop(vec); + } + + { + let drained: Drain = any_vec.drain(..); + assert!(!impls!(AnyVec: Send)); + assert!(!impls!(AnyVec: Sync)); + drop(drained); + } + { + let drained: Splice>> = + any_vec.splice(.., iter::empty::>()); + assert!(!impls!(Splice>>: Send)); + assert!(!impls!(Splice>>: Sync)); + drop(drained); + } + } + + fn test_positive() + where M::Mem: Sync + Send + { + let mut any_vec: AnyVec = AnyVec::new::(); + is_sync(&any_vec); + is_send(&any_vec); + is_sync(&any_vec.iter()); + is_send(&any_vec.iter()); + is_sync(&any_vec.iter_mut()); + is_send(&any_vec.iter_mut()); + { + let mut vec = any_vec.downcast_mut::().unwrap(); + is_sync(&vec); + is_send(&vec); + is_sync(&vec.iter()); + is_send(&vec.iter()); + is_sync(&vec.iter_mut()); + is_send(&vec.iter_mut()); + } + + { + let drained = any_vec.drain(..); + is_sync(&drained); + is_send(&drained); + } + { + let drained = any_vec.splice(.., [AnyValueWrapper::new(String::new())]); + is_sync(&drained); + is_send(&drained); + } + } + test_positive::(); + test_positive::>(); + + test_negative::(); + test_negative::>(); +} From f16e77beb2da3f51ba88f3be56ac59b46195e5a2 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 28 Jun 2022 13:47:33 +0300 Subject: [PATCH 08/35] v0.9.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 01d0292..18be4e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "any_vec" authors = ["Andrey Diduh "] license = "MIT OR Apache-2.0" -version = "0.9.0" +version = "0.9.1" edition = "2021" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." repository = "https://github.com/tower120/any_vec" From a3684780bce4cabde263f604f4fbb374af18e57b Mon Sep 17 00:00:00 2001 From: tower120 Date: Mon, 4 Jul 2022 15:43:37 +0300 Subject: [PATCH 09/35] AnyVec, AnyVecTyped implements Debug now (#22) --- .github/workflows/ci.yml | 3 ++ CHANGELOG.md | 7 +++++ src/any_vec.rs | 22 +++++++++++++- src/any_vec_ptr.rs | 63 ++++++++++++++++++++++++++++++---------- src/any_vec_typed.rs | 7 +++++ src/element.rs | 4 +-- src/iter.rs | 4 +-- src/lib.rs | 2 ++ src/mem/heap.rs | 10 +++++-- src/ops/drain.rs | 6 ++-- src/ops/pop.rs | 6 ++-- src/ops/remove.rs | 10 +++---- src/ops/splice.rs | 12 ++++---- src/ops/swap_remove.rs | 6 ++-- src/ops/temp.rs | 4 +-- tests/any_vec.rs | 15 ++++++++++ tests/any_vec_typed.rs | 20 +++++++++++++ 17 files changed, 156 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 63d7f45..42ddf8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + #- uses: ATiltedTree/setup-rust@v1 + # with: + # rust-version: stable - uses: actions-rs/toolchain@v1 with: toolchain: nightly diff --git a/CHANGELOG.md b/CHANGELOG.md index fad9957..4d8b7a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased +### Added +- `Debug` implemented for `AnyVec`, `AnyVecTyped`. + +### Fixed +- Stacked Borrow friendly now. + ## 0.9.1 ### Changed - `impls` dependency dropped. diff --git a/src/any_vec.rs b/src/any_vec.rs index d642358..938371f 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -1,5 +1,6 @@ use std::alloc::Layout; use std::any::TypeId; +use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut, Range, RangeBounds}; @@ -31,7 +32,7 @@ use crate::traits::{Cloneable, Trait}; /// ``` pub mod traits{ /// Marker trait, for traits accepted by AnyVec. - pub trait Trait: crate::clone_type::CloneType{} + pub trait Trait: 'static + crate::clone_type::CloneType{} impl Trait for dyn None {} impl Trait for dyn Sync{} impl Trait for dyn Send{} @@ -620,6 +621,15 @@ impl Clone for AnyVec Debug for AnyVec{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("AnyVec") + .field("typeid", &self.element_typeid()) + .field("len", &self.len()) + .finish() + } +} + impl<'a, Traits: ?Sized + Trait, M: MemBuilder> IntoIterator for &'a AnyVec{ type Item = ElementRef<'a, Traits, M>; type IntoIter = IterRef<'a, Traits, M>; @@ -670,6 +680,11 @@ impl<'a, T: 'static, M: MemBuilder + 'a> IntoIterator for AnyVecRef<'a, T, M>{ self.iter() } } +impl<'a, T: 'static + Debug, M: MemBuilder + 'a> Debug for AnyVecRef<'a, T, M>{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} /// Typed view to &mut [`AnyVec`]. /// @@ -700,4 +715,9 @@ impl<'a, T: 'static, M: MemBuilder + 'a> IntoIterator for AnyVecMut<'a, T, M>{ fn into_iter(mut self) -> Self::IntoIter { self.iter_mut() } +} +impl<'a, T: 'static + Debug, M: MemBuilder + 'a> Debug for AnyVecMut<'a, T, M>{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } } \ No newline at end of file diff --git a/src/any_vec_ptr.rs b/src/any_vec_ptr.rs index f059a1c..e187db8 100644 --- a/src/any_vec_ptr.rs +++ b/src/any_vec_ptr.rs @@ -12,11 +12,13 @@ pub trait IAnyVecRawPtr: Copy{ /// Known element type of AnyVec type Element: 'static/* = Unknown*/; type M: MemBuilder; - fn any_vec_raw(&self) -> NonNull>; + unsafe fn any_vec_raw<'a>(&self) -> &'a AnyVecRaw; + unsafe fn any_vec_raw_mut<'a>(&mut self) -> &'a mut AnyVecRaw; } pub trait IAnyVecPtr: IAnyVecRawPtr{ type Traits: ?Sized + Trait; - fn any_vec(&self) -> NonNull>; + unsafe fn any_vec<'a>(&self) -> &'a AnyVec; + unsafe fn any_vec_mut<'a>(&mut self) -> &'a mut AnyVec; } @@ -46,8 +48,13 @@ impl IAnyVecRawPtr for AnyVecRawPtr{ type M = M; #[inline] - fn any_vec_raw(&self) -> NonNull> { - self.ptr + unsafe fn any_vec_raw<'a>(&self) -> &'a AnyVecRaw { + self.ptr.as_ref() + } + + #[inline] + unsafe fn any_vec_raw_mut<'a>(&mut self) -> &'a mut AnyVecRaw { + self.ptr.as_mut() } } @@ -86,16 +93,26 @@ impl IAnyVecRawPtr for AnyVecPtr NonNull> { - NonNull::from(unsafe{&self.ptr.as_ref().raw}) + unsafe fn any_vec_raw<'a>(&self) -> &'a AnyVecRaw { + &self.ptr.as_ref().raw + } + + #[inline] + unsafe fn any_vec_raw_mut<'a>(&mut self) -> &'a mut AnyVecRaw { + &mut self.ptr.as_mut().raw } } impl IAnyVecPtr for AnyVecPtr { type Traits = Traits; #[inline] - fn any_vec(&self) -> NonNull> { - self.ptr + unsafe fn any_vec<'a>(&self) -> &'a AnyVec { + self.ptr.as_ref() + } + + #[inline] + unsafe fn any_vec_mut<'a>(&mut self) -> &'a mut AnyVec { + self.ptr.as_mut() } } @@ -112,7 +129,7 @@ pub(crate) mod utils{ pub fn element_size(any_vec_ptr: AnyVecPtr) -> usize { if Unknown::is::(){ - let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw().as_ref() }; + let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw() }; any_vec_raw.element_layout().size() } else { size_of::() @@ -121,10 +138,23 @@ pub(crate) mod utils{ #[inline] pub fn element_ptr_at(any_vec_ptr: AnyVecPtr, index: usize) - -> *mut u8 + -> *const u8 { unsafe{ - let any_vec_raw = any_vec_ptr.any_vec_raw().as_mut(); + let any_vec_raw = any_vec_ptr.any_vec_raw(); + if Unknown::is::(){ + any_vec_raw.mem.as_ptr() + .add(any_vec_raw.element_layout().size() * index) + } else { + any_vec_raw.mem.as_ptr().cast::() + .add(index) as *const u8 + } + } } + #[inline] + pub fn element_mut_ptr_at(mut any_vec_ptr: AnyVecPtr, index: usize) + -> *mut u8 + { unsafe{ + let any_vec_raw = any_vec_ptr.any_vec_raw_mut(); if Unknown::is::(){ any_vec_raw.mem.as_mut_ptr() .add(any_vec_raw.element_layout().size() * index) @@ -134,14 +164,15 @@ pub(crate) mod utils{ } } } + #[inline] pub unsafe fn move_elements_at (any_vec_ptr: AnyVecPtr, src_index: usize, dst_index: usize, len: usize) { let src = element_ptr_at(any_vec_ptr, src_index); - let dst = element_ptr_at(any_vec_ptr, dst_index); + let dst = element_mut_ptr_at(any_vec_ptr, dst_index); if Unknown::is::(){ - let any_vec_raw = any_vec_ptr.any_vec_raw().as_ref(); + let any_vec_raw = any_vec_ptr.any_vec_raw(); ptr::copy( src, dst, @@ -163,16 +194,16 @@ pub(crate) mod utils{ debug_assert!(start_index <= end_index); if Unknown::is::(){ - let any_vec_raw = any_vec_ptr.any_vec_raw().as_ref(); + let any_vec_raw = any_vec_ptr.any_vec_raw(); if let Some(drop_fn) = any_vec_raw.drop_fn(){ (drop_fn)( - element_ptr_at(any_vec_ptr, start_index), + element_mut_ptr_at(any_vec_ptr, start_index), end_index - start_index ); } } else if mem::needs_drop::(){ // drop as slice. This is marginally faster then one by one. - let start_ptr = element_ptr_at(any_vec_ptr, start_index) as *mut AnyVecPtr::Element; + let start_ptr = element_mut_ptr_at(any_vec_ptr, start_index) as *mut AnyVecPtr::Element; let to_drop = ptr::slice_from_raw_parts_mut(start_ptr, end_index - start_index); ptr::drop_in_place(to_drop); } diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index 52d13be..f181b6d 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -1,3 +1,4 @@ +use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; use std::ops::{Range, RangeBounds}; use std::ptr::NonNull; @@ -258,6 +259,12 @@ impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ } } +impl<'a, T: 'static + Debug, M: MemBuilder> Debug for AnyVecTyped<'a, T, M>{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + (*self.as_slice()).fmt(f) + } +} + // Do not implement Index, since we can't do the same for AnyVec /* impl<'a, T: 'static, I: SliceIndex<[T]>> Index for AnyVecTyped<'a, T> { diff --git a/src/element.rs b/src/element.rs index 527ab9a..df023d1 100644 --- a/src/element.rs +++ b/src/element.rs @@ -45,7 +45,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ #[inline] fn any_vec_raw(&self) -> &'a AnyVecRaw{ - unsafe { self.any_vec_ptr.any_vec_raw().as_ref() } + unsafe { self.any_vec_ptr.any_vec_raw() } } #[inline] @@ -112,7 +112,7 @@ impl<'a, Traits: ?Sized + Cloneable + Trait, M: MemBuilder> { #[inline] unsafe fn clone_into(&self, out: *mut u8) { - let clone_fn = self.any_vec_ptr.any_vec().as_ref().clone_fn(); + let clone_fn = self.any_vec_ptr.any_vec().clone_fn(); (clone_fn)(self.bytes(), out, 1); } } diff --git a/src/iter.rs b/src/iter.rs index c9f6ff1..084d6c2 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -83,7 +83,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> Iterat let element_ptr = element_ptr_at(self.any_vec_ptr, self.index); let element = ElementPointer::new( self.any_vec_ptr, - unsafe{NonNull::new_unchecked(element_ptr)} + unsafe{NonNull::new_unchecked(element_ptr as *mut u8)} ); self.index += 1; @@ -110,7 +110,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> Double let element_ptr = element_ptr_at(self.any_vec_ptr, self.end); let element = ElementPointer::new( self.any_vec_ptr, - unsafe{NonNull::new_unchecked(element_ptr)} + unsafe{NonNull::new_unchecked(element_ptr as *mut u8)} ); Some(IterItem::element_to_item(element)) diff --git a/src/lib.rs b/src/lib.rs index 41d81f7..72fda3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(miri, feature(alloc_layout_extra) )] + //! Type erased vector [`AnyVec`]. Allow to store elements of the same type. //! Have same performance and *operations* as [`std::vec::Vec`]. //! diff --git a/src/mem/heap.rs b/src/mem/heap.rs index d364fd7..b3a856d 100644 --- a/src/mem/heap.rs +++ b/src/mem/heap.rs @@ -5,8 +5,14 @@ use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemResizable}; #[inline] fn dangling(layout: &Layout) -> NonNull{ - //layout.dangling() - unsafe { NonNull::new_unchecked(layout.align() as *mut u8) } + #[cfg(miri)] + { + layout.dangling() + } + #[cfg(not(miri))] + { + unsafe { NonNull::new_unchecked(layout.align() as *mut u8) } + } } /// Heap allocated memory. diff --git a/src/ops/drain.rs b/src/ops/drain.rs index e4be11d..43aa8a0 100644 --- a/src/ops/drain.rs +++ b/src/ops/drain.rs @@ -13,9 +13,9 @@ pub struct Drain<'a, AnyVecPtr: IAnyVecRawPtr> impl<'a, AnyVecPtr: IAnyVecRawPtr> Drain<'a, AnyVecPtr> { #[inline] - pub(crate) fn new(any_vec_ptr: AnyVecPtr, start: usize, end: usize) -> Self { + pub(crate) fn new(mut any_vec_ptr: AnyVecPtr, start: usize, end: usize) -> Self { debug_assert!(start <= end); - let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw().as_mut() }; + let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw_mut() }; let original_len = any_vec_raw.len; debug_assert!(end <= original_len); @@ -74,7 +74,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Drop for Drain<'a, AnyVecPtr> // 3. len let distance = self.iter.end - self.start; - let any_vec_raw = unsafe{ self.iter.any_vec_ptr.any_vec_raw().as_mut() }; + let any_vec_raw = unsafe{ self.iter.any_vec_ptr.any_vec_raw_mut() }; any_vec_raw.len = self.original_len - distance; } } \ No newline at end of file diff --git a/src/ops/pop.rs b/src/ops/pop.rs index 0d883cf..2a26be9 100644 --- a/src/ops/pop.rs +++ b/src/ops/pop.rs @@ -11,8 +11,8 @@ pub struct Pop<'a, AnyVecPtr: IAnyVecRawPtr>{ impl<'a, AnyVecPtr: IAnyVecRawPtr> Pop<'a, AnyVecPtr>{ #[inline] - pub(crate) fn new(any_vec_ptr: AnyVecPtr) -> Self{ - let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw().as_mut() }; + pub(crate) fn new(mut any_vec_ptr: AnyVecPtr) -> Self{ + let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw_mut() }; // mem::forget and element drop panic "safety". debug_assert!(any_vec_raw.len > 0); @@ -35,7 +35,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Pop<'a, AnyVecPtr>{ #[inline] fn bytes(&self) -> *const u8 { - let any_vec_raw = unsafe{ self.any_vec_ptr.any_vec_raw().as_ref() }; + let any_vec_raw = unsafe{ self.any_vec_ptr.any_vec_raw() }; let index = any_vec_raw.len; element_ptr_at(self.any_vec_ptr, index) } diff --git a/src/ops/remove.rs b/src/ops/remove.rs index fda9ea9..8a77733 100644 --- a/src/ops/remove.rs +++ b/src/ops/remove.rs @@ -15,9 +15,9 @@ pub struct Remove<'a, AnyVecPtr: IAnyVecRawPtr>{ impl<'a, AnyVecPtr: IAnyVecRawPtr> Remove<'a, AnyVecPtr>{ #[inline] - pub(crate) fn new(any_vec_ptr: AnyVecPtr, index: usize) -> Self{ + pub(crate) fn new(mut any_vec_ptr: AnyVecPtr, index: usize) -> Self{ // 1. mem::forget and element drop panic "safety". - let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw().as_mut() }; + let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw_mut() }; let last_index = any_vec_raw.len - 1; any_vec_raw.len = index; @@ -36,7 +36,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Remove<'a, AnyVecPtr>{ #[inline] fn bytes(&self) -> *const u8 { unsafe{ - let any_vec_raw = self.any_vec_ptr.any_vec_raw().as_ref(); + let any_vec_raw = self.any_vec_ptr.any_vec_raw(); if !Unknown::is::(){ any_vec_raw.mem.as_ptr().cast::() .add(self.index) as *const u8 @@ -56,7 +56,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Remove<'a, AnyVecPtr>{ let src = dst.add(1); ptr::copy(src, dst,self.last_index - self.index); } else { - let size = self.any_vec_ptr.any_vec_raw().as_ref().element_layout().size(); + let size = self.any_vec_ptr.any_vec_raw().element_layout().size(); let dst = self.bytes() as *mut u8; let src = dst.add(size); crate::copy_bytes(src, dst,size * (self.last_index - self.index)); @@ -64,7 +64,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Remove<'a, AnyVecPtr>{ // 3. shrink len `self.any_vec.len -= 1` { - let any_vec_raw = self.any_vec_ptr.any_vec_raw().as_mut(); + let any_vec_raw = self.any_vec_ptr.any_vec_raw_mut(); any_vec_raw.len = self.last_index; } } diff --git a/src/ops/splice.rs b/src/ops/splice.rs index 74135e7..466bae8 100644 --- a/src/ops/splice.rs +++ b/src/ops/splice.rs @@ -20,11 +20,11 @@ where { #[inline] pub fn new( - any_vec_ptr: AnyVecPtr, start: usize, end: usize, + mut any_vec_ptr: AnyVecPtr, start: usize, end: usize, replace_with: ReplaceIter ) -> Self { debug_assert!(start <= end); - let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw().as_mut() }; + let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw_mut() }; let original_len = any_vec_raw.len; debug_assert!(end <= original_len); @@ -67,7 +67,7 @@ where { fn drop(&mut self) { use any_vec_ptr::utils::*; - let any_vec_ptr = self.iter.any_vec_ptr; + let mut any_vec_ptr = self.iter.any_vec_ptr; let elements_left = self.original_len - self.iter.end; let replace_end = self.start + self.replace_with.len(); @@ -75,7 +75,7 @@ where // 0. capacity. { - let any_vec_raw = unsafe{any_vec_ptr.any_vec_raw().as_mut()}; + let any_vec_raw = unsafe{any_vec_ptr.any_vec_raw_mut()}; any_vec_raw.reserve(new_len); } @@ -101,7 +101,7 @@ where // 3. move replace_with in unsafe{ let element_size = element_size(any_vec_ptr); - let mut ptr = element_ptr_at(any_vec_ptr, self.start); + let mut ptr = element_mut_ptr_at(any_vec_ptr, self.start); while let Some(replace_element) = self.replace_with.next() { replace_element.move_into(ptr); ptr = ptr.add(element_size); @@ -110,7 +110,7 @@ where // 4. restore len { - let any_vec_raw = unsafe{any_vec_ptr.any_vec_raw().as_mut()}; + let any_vec_raw = unsafe{any_vec_ptr.any_vec_raw_mut()}; any_vec_raw.len = new_len; } } diff --git a/src/ops/swap_remove.rs b/src/ops/swap_remove.rs index b929127..5fd5697 100644 --- a/src/ops/swap_remove.rs +++ b/src/ops/swap_remove.rs @@ -16,8 +16,8 @@ pub struct SwapRemove<'a, AnyVecPtr: IAnyVecRawPtr>{ impl<'a, AnyVecPtr: IAnyVecRawPtr> SwapRemove<'a, AnyVecPtr>{ #[inline] - pub(crate) fn new(any_vec_ptr: AnyVecPtr, index: usize) -> Self{ - let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw().as_mut() }; + pub(crate) fn new(mut any_vec_ptr: AnyVecPtr, index: usize) -> Self{ + let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw_mut() }; // 1. mem::forget and element drop panic "safety". let last_index = any_vec_raw.len - 1; @@ -51,7 +51,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for SwapRemove<'a, AnyVecPtr>{ fn consume(&mut self) { unsafe{ // 2. overwrite with last element - let any_vec_raw = self.any_vec_ptr.any_vec_raw().as_mut(); + let any_vec_raw = self.any_vec_ptr.any_vec_raw_mut(); let last_element = if !Unknown::is::() { any_vec_raw.mem.as_ptr().cast::().add(self.last_index) as *const u8 diff --git a/src/ops/temp.rs b/src/ops/temp.rs index 93d238e..4d11d6f 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -35,7 +35,7 @@ impl TempValue{ #[inline] fn any_vec_raw(&self) -> &AnyVecRaw<::M>{ - unsafe{ self.op.any_vec_ptr().any_vec_raw().as_ref() } + unsafe{ self.op.any_vec_ptr().any_vec_raw() } } } @@ -83,7 +83,7 @@ where { #[inline] unsafe fn clone_into(&self, out: *mut u8) { - let clone_fn = self.op.any_vec_ptr().any_vec().as_ref().clone_fn(); + let clone_fn = self.op.any_vec_ptr().any_vec().clone_fn(); (clone_fn)(self.bytes(), out, 1); } } diff --git a/tests/any_vec.rs b/tests/any_vec.rs index 5eff875..c0dcdfe 100644 --- a/tests/any_vec.rs +++ b/tests/any_vec.rs @@ -374,4 +374,19 @@ fn any_vec_into_iter_test() { sum += e.downcast_ref::().unwrap(); } assert_eq!(sum, 111); + + let mut sum = 0; + for mut e in &mut any_vec{ + let value = e.downcast_mut::().unwrap(); + *value *= 10; + sum += *value; + } + assert_eq!(sum, 1110); +} + +#[test] +fn any_vec_debug() { + let any_vec: AnyVec = AnyVec::new::(); + let typeid = TypeId::of::(); + assert_eq!(format!("{any_vec:?}"), format!("AnyVec {{ typeid: {typeid:?}, len: 0 }}")); } \ No newline at end of file diff --git a/tests/any_vec_typed.rs b/tests/any_vec_typed.rs index 7670e37..6fa7047 100644 --- a/tests/any_vec_typed.rs +++ b/tests/any_vec_typed.rs @@ -176,6 +176,26 @@ fn any_vec_into_iter_test() { assert_eq!(sum, 111); } +#[test] +fn any_vec_debug() { + let mut any_vec: AnyVec = AnyVec::new::(); + let mut vec = any_vec.downcast_mut::().unwrap(); + vec.push(1); + vec.push(2); + vec.push(3); + + let mut control_vec = Vec::new(); + control_vec.push(1); + control_vec.push(2); + control_vec.push(3); + + assert_eq!(format!("{vec:?}"), format!("{control_vec:?}")); + drop(vec); + + let vec = any_vec.downcast_ref::().unwrap(); + assert_eq!(format!("{vec:?}"), format!("{control_vec:?}")); +} + /* #[test] fn any_vec_index_test() { From f165fe68a5c64bd838c6f66337ca8b116448fec9 Mon Sep 17 00:00:00 2001 From: tower120 Date: Fri, 8 Jul 2022 16:21:44 +0300 Subject: [PATCH 10/35] AnyValue::as_bytes + AnyValueMut::swap --- CHANGELOG.md | 7 +++++ benches/push.rs | 36 ++++++++++++++-------- src/any_value/lazy_clone.rs | 9 ++---- src/any_value/mod.rs | 59 +++++++++++++++++++++++++++---------- src/any_value/raw.rs | 19 ++++++++---- src/any_value/wrapper.rs | 25 ++++++++++------ src/element.rs | 25 ++++++++++------ src/lib.rs | 1 - src/ops/temp.rs | 39 +++++++++++++++--------- tests/any_value.rs | 57 +++++++++++++++++++++++++++++++++++ 10 files changed, 204 insertions(+), 73 deletions(-) create mode 100644 tests/any_value.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d8b7a6..206d84d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,15 @@ # Changelog ## Unreleased +### Changed +- `AnyValue::bytes()->*const u8` and `AnyValue::size()->usize` replaced with +`AnyValue::as_bytes()->&[u8]`. Same for `AnyValueMut`. +- `AnyValueWrapper` now `AnyValueMut`. +- `AnyValueRaw` now `AnyValueMut`. + ### Added - `Debug` implemented for `AnyVec`, `AnyVecTyped`. +- `AnyValueMut::swap()`. ### Fixed - Stacked Borrow friendly now. diff --git a/benches/push.rs b/benches/push.rs index e6e475f..9748b27 100644 --- a/benches/push.rs +++ b/benches/push.rs @@ -1,35 +1,47 @@ +use std::any::TypeId; +use std::mem::size_of; +use std::ptr::NonNull; use criterion::{criterion_group, criterion_main, Criterion}; +use any_vec::any_value::AnyValueRaw; use any_vec::AnyVec; const SIZE: usize = 10000; +type Element = [u8;128]; +static VALUE: Element = [0;128]; + fn vec_push(){ let mut vec = Vec::new(); - for i in 0..SIZE{ - vec.push(i); + for _ in 0..SIZE{ + vec.push(VALUE.clone()); } } fn any_vec_push(){ - let mut any_vec: AnyVec = AnyVec::new::(); - for i in 0..SIZE{ - let mut vec = any_vec.downcast_mut::().unwrap(); - vec.push(i); + let mut any_vec: AnyVec = AnyVec::new::(); + for _ in 0..SIZE{ + let mut vec = any_vec.downcast_mut::().unwrap(); + vec.push(VALUE.clone()); } } -fn any_vec_push_unchecked(){ - let mut any_vec: AnyVec = AnyVec::new::(); - for i in 0..SIZE{ - let mut vec = unsafe{ any_vec.downcast_mut_unchecked::() }; - vec.push(i); +fn any_vec_push_untyped(){ + let mut any_vec: AnyVec = AnyVec::new::(); + for _ in 0..SIZE{ + let value = VALUE.clone(); + let raw_value = unsafe{AnyValueRaw::new( + NonNull::from(&value).cast::(), + size_of::(), + TypeId::of::() + )}; + any_vec.push(raw_value); } } pub fn bench_push(c: &mut Criterion) { c.bench_function("Vec push", |b|b.iter(||vec_push())); c.bench_function("AnyVec push", |b|b.iter(||any_vec_push())); - c.bench_function("AnyVec push_unchecked", |b|b.iter(||any_vec_push_unchecked())); + c.bench_function("AnyVec push untyped", |b|b.iter(||any_vec_push_untyped())); } criterion_group!(benches, bench_push); diff --git a/src/any_value/lazy_clone.rs b/src/any_value/lazy_clone.rs index af5d41d..edf83ee 100644 --- a/src/any_value/lazy_clone.rs +++ b/src/any_value/lazy_clone.rs @@ -29,13 +29,8 @@ impl<'a, T: AnyValueCloneable> AnyValue for LazyClone<'a, T>{ } #[inline] - fn size(&self) -> usize { - self.value.size() - } - - #[inline] - fn bytes(&self) -> *const u8 { - self.value.bytes() + fn as_bytes(&self) -> &[u8]{ + self.value.as_bytes() } #[inline] diff --git a/src/any_value/mod.rs b/src/any_value/mod.rs index a25a314..880f0a6 100644 --- a/src/any_value/mod.rs +++ b/src/any_value/mod.rs @@ -9,7 +9,7 @@ pub use raw::AnyValueRaw; use std::any::TypeId; use std::{mem, ptr}; use std::mem::MaybeUninit; -use crate::copy_bytes_nonoverlapping; +use crate::{copy_bytes_nonoverlapping, swap_bytes_nonoverlapping}; /// Marker for unknown type. pub struct Unknown; @@ -27,11 +27,8 @@ pub trait AnyValue { fn value_typeid(&self) -> TypeId; - // TODO: Layout instead of size? - /// In bytes. Return compile-time value, whenever possible. - fn size(&self) -> usize; - - fn bytes(&self) -> *const u8; + /// Aligned. + fn as_bytes(&self) -> &[u8]; #[inline] fn downcast_ref(&self) -> Option<&T>{ @@ -44,7 +41,7 @@ pub trait AnyValue { #[inline] unsafe fn downcast_ref_unchecked(&self) -> &T{ - &*(self.bytes() as *const T) + &*(self.as_bytes().as_ptr() as *const T) } #[inline] @@ -69,7 +66,7 @@ pub trait AnyValue { /// Move self into `out`. /// - /// `out` must have at least [`size`] bytes. + /// `out` must have at least `as_bytes().len()` bytes. /// Will do compile-time optimisation if type/size known. /// /// [`size`]: Self::size @@ -87,23 +84,22 @@ pub trait AnyValue { pub(crate) unsafe fn copy_bytes(any_value: &T, out: *mut u8){ if !Unknown::is::() { ptr::copy_nonoverlapping( - any_value.bytes() as *const T::Type, + any_value.as_bytes().as_ptr() as *const T::Type, out as *mut T::Type, 1); } else { + let bytes = any_value.as_bytes(); copy_bytes_nonoverlapping( - any_value.bytes(), + bytes.as_ptr(), out, - any_value.size()); + bytes.len()); } } /// Type erased mutable value interface. pub trait AnyValueMut: AnyValue{ - #[inline] - fn bytes_mut(&mut self) -> *mut u8{ - self.bytes() as *mut u8 - } + + fn as_bytes_mut(&mut self) -> &mut [u8]; #[inline] fn downcast_mut(&mut self) -> Option<&mut T>{ @@ -116,7 +112,38 @@ pub trait AnyValueMut: AnyValue{ #[inline] unsafe fn downcast_mut_unchecked(&mut self) -> &mut T{ - &mut *(self.bytes_mut() as *mut T) + &mut *(self.as_bytes_mut().as_mut_ptr() as *mut T) + } + + /// Swaps underlying values. + /// + /// # Panic + /// + /// Panics, if type mismatch. + #[inline] + fn swap(&mut self, other: &mut Other){ + assert_eq!(self.value_typeid(), other.value_typeid()); + + unsafe{ + if !Unknown::is::() { + mem::swap( + self.downcast_mut_unchecked::(), + other.downcast_mut_unchecked::() + ); + } else if !Unknown::is::() { + mem::swap( + self.downcast_mut_unchecked::(), + other.downcast_mut_unchecked::() + ); + } else { + let bytes = self.as_bytes_mut(); + swap_bytes_nonoverlapping( + bytes.as_mut_ptr(), + other.as_bytes_mut().as_mut_ptr(), + bytes.len() + ); + } + } // unsafe } } diff --git a/src/any_value/raw.rs b/src/any_value/raw.rs index 393693f..4a9e31f 100644 --- a/src/any_value/raw.rs +++ b/src/any_value/raw.rs @@ -1,6 +1,7 @@ use std::any::TypeId; use std::ptr::NonNull; -use crate::any_value::AnyValue; +use std::slice; +use crate::any_value::{AnyValue, AnyValueMut}; use crate::any_value::Unknown; /// Non owning byte ptr wrapper. @@ -47,12 +48,20 @@ impl AnyValue for AnyValueRaw{ } #[inline] - fn size(&self) -> usize { - self.size + fn as_bytes(&self) -> &[u8]{ + unsafe{slice::from_raw_parts( + self.ptr.as_ptr(), + self.size + )} } +} +impl AnyValueMut for AnyValueRaw{ #[inline] - fn bytes(&self) -> *const u8 { - self.ptr.as_ptr() + fn as_bytes_mut(&mut self) -> &mut [u8] { + unsafe{slice::from_raw_parts_mut( + self.ptr.as_ptr(), + self.size + )} } } \ No newline at end of file diff --git a/src/any_value/wrapper.rs b/src/any_value/wrapper.rs index aa556bf..fec3bd1 100644 --- a/src/any_value/wrapper.rs +++ b/src/any_value/wrapper.rs @@ -1,7 +1,7 @@ use std::any::TypeId; use std::mem::{ManuallyDrop, size_of}; -use std::ptr; -use crate::any_value::AnyValue; +use std::{ptr, slice}; +use crate::any_value::{AnyValue, AnyValueMut}; /// Helper struct to convert concrete type to [`AnyValue`]. pub struct AnyValueWrapper{ @@ -22,13 +22,11 @@ impl AnyValue for AnyValueWrapper { } #[inline] - fn size(&self) -> usize { - size_of::() - } - - #[inline] - fn bytes(&self) -> *const u8 { - &self.value as *const _ as *const u8 + fn as_bytes(&self) -> &[u8]{ + unsafe{slice::from_raw_parts( + &self.value as *const _ as *const u8, + size_of::() + )} } #[inline] @@ -39,3 +37,12 @@ impl AnyValue for AnyValueWrapper { ptr::read(ptr) } } +impl AnyValueMut for AnyValueWrapper { + #[inline] + fn as_bytes_mut(&mut self) -> &mut [u8] { + unsafe{slice::from_raw_parts_mut( + &mut self.value as *mut _ as *mut u8, + size_of::() + )} + } +} \ No newline at end of file diff --git a/src/element.rs b/src/element.rs index df023d1..5cf0f92 100644 --- a/src/element.rs +++ b/src/element.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; +use std::slice; use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{AnyVecPtr, IAnyVecPtr, IAnyVecRawPtr}; @@ -59,7 +60,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &'a T{ - &*(self.bytes() as *const T) + &*(self.as_bytes().as_ptr() as *const T) } #[inline] @@ -73,7 +74,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ #[inline] pub unsafe fn downcast_mut_unchecked(&mut self) -> &'a mut T{ - &mut *(self.bytes_mut() as *mut T) + &mut *(self.as_bytes_mut().as_mut_ptr() as *mut T) } } @@ -95,25 +96,31 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValue for ElementPointer<'a, AnyVecPtr>{ } #[inline] - fn size(&self) -> usize { - self.any_vec_raw().element_layout().size() + fn as_bytes(&self) -> &[u8]{ + unsafe{slice::from_raw_parts( + self.element.as_ptr(), + self.any_vec_raw().element_layout().size() + )} } +} +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMut for ElementPointer<'a, AnyVecPtr>{ #[inline] - fn bytes(&self) -> *const u8 { - self.element.as_ptr() + fn as_bytes_mut(&mut self) -> &mut [u8] { + unsafe{slice::from_raw_parts_mut( + self.element.as_ptr(), + self.any_vec_raw().element_layout().size() + )} } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMut for ElementPointer<'a, AnyVecPtr>{} - impl<'a, Traits: ?Sized + Cloneable + Trait, M: MemBuilder> AnyValueCloneable for ElementPointer<'a, AnyVecPtr> { #[inline] unsafe fn clone_into(&self, out: *mut u8) { let clone_fn = self.any_vec_ptr.any_vec().clone_fn(); - (clone_fn)(self.bytes(), out, 1); + (clone_fn)(self.as_bytes().as_ptr(), out, 1); } } diff --git a/src/lib.rs b/src/lib.rs index 72fda3c..e1793ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,7 +192,6 @@ unsafe fn copy_bytes(src: *const u8, dst: *mut u8, count: usize){ // same as copy_bytes_nonoverlapping but for swap_nonoverlapping. -#[allow(dead_code)] #[inline] unsafe fn swap_bytes_nonoverlapping(src: *mut u8, dst: *mut u8, count: usize){ // MIRI hack diff --git a/src/ops/temp.rs b/src/ops/temp.rs index 4d11d6f..b1b8402 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -1,5 +1,5 @@ use std::any::TypeId; -use std::{mem, ptr}; +use std::{mem, ptr, slice}; use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, copy_bytes, Unknown}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{IAnyVecPtr, IAnyVecRawPtr}; @@ -37,6 +37,15 @@ impl TempValue{ fn any_vec_raw(&self) -> &AnyVecRaw<::M>{ unsafe{ self.op.any_vec_ptr().any_vec_raw() } } + + #[inline] + fn bytes_len(&self) -> usize{ + if Unknown::is::<::Element>() { + self.any_vec_raw().element_layout().size() + } else{ + mem::size_of::<::Element>() + } + } } impl AnyValue for TempValue{ @@ -53,17 +62,11 @@ impl AnyValue for TempValue{ } #[inline] - fn size(&self) -> usize { - if Unknown::is::() { - self.any_vec_raw().element_layout().size() - } else{ - mem::size_of::() - } - } - - #[inline] - fn bytes(&self) -> *const u8 { - self.op.bytes() + fn as_bytes(&self) -> &[u8]{ + unsafe{slice::from_raw_parts( + self.op.bytes(), + self.bytes_len() + )} } #[inline] @@ -74,7 +77,15 @@ impl AnyValue for TempValue{ } } -impl AnyValueMut for TempValue {} +impl AnyValueMut for TempValue { + #[inline] + fn as_bytes_mut(&mut self) -> &mut [u8] { + unsafe{slice::from_raw_parts_mut( + self.op.bytes() as *mut u8, + self.bytes_len() + )} + } +} impl AnyValueCloneable for TempValue where @@ -84,7 +95,7 @@ where #[inline] unsafe fn clone_into(&self, out: *mut u8) { let clone_fn = self.op.any_vec_ptr().any_vec().clone_fn(); - (clone_fn)(self.bytes(), out, 1); + (clone_fn)(self.as_bytes().as_ptr(), out, 1); } } diff --git a/tests/any_value.rs b/tests/any_value.rs new file mode 100644 index 0000000..3546821 --- /dev/null +++ b/tests/any_value.rs @@ -0,0 +1,57 @@ +use std::any::TypeId; +use std::mem::size_of; +use std::ptr::NonNull; +use any_vec::any_value::{AnyValue, AnyValueMut, AnyValueRaw, AnyValueWrapper}; + +#[test] +fn swap_test(){ + // typed <-> typed + { + let mut a1 = AnyValueWrapper::new(String::from("1")); + let mut a2 = AnyValueWrapper::new(String::from("2")); + + a1.swap(&mut a2); + assert_eq!(a1.downcast_ref::().unwrap(), &String::from("2")); + assert_eq!(a2.downcast_ref::().unwrap(), &String::from("1")); + } + + // untyped <-> untyped + { + let mut s1 = String::from("1"); + let mut s2 = String::from("2"); + + let mut a1 = unsafe{AnyValueRaw::new( + NonNull::from(&mut s1).cast::(), + size_of::(), + TypeId::of::() + )}; + let mut a2 = unsafe{AnyValueRaw::new( + NonNull::from(&mut s2).cast::(), + size_of::(), + TypeId::of::() + )}; + + a1.swap(&mut a2); + assert_eq!(a1.downcast_ref::().unwrap(), &String::from("2")); + assert_eq!(a2.downcast_ref::().unwrap(), &String::from("1")); + } + + // untyped <-> typed + { + let mut s1 = String::from("1"); + let mut a1 = unsafe{AnyValueRaw::new( + NonNull::from(&mut s1).cast::(), + size_of::(), + TypeId::of::() + )}; + let mut a2 = AnyValueWrapper::new(String::from("2")); + + a1.swap(&mut a2); + assert_eq!(a1.downcast_ref::().unwrap(), &String::from("2")); + assert_eq!(a2.downcast_ref::().unwrap(), &String::from("1")); + + a2.swap(&mut a1); + assert_eq!(a1.downcast_ref::().unwrap(), &String::from("1")); + assert_eq!(a2.downcast_ref::().unwrap(), &String::from("2")); + } +} \ No newline at end of file From 6c115b5fa495ff244bf5ee1b4c9fe0de1930dab0 Mon Sep 17 00:00:00 2001 From: tower120 Date: Sun, 10 Jul 2022 15:45:01 +0300 Subject: [PATCH 11/35] set_len added + refactor --- CHANGELOG.md | 2 ++ src/any_vec.rs | 50 ++++++++++++++++++++++++++++-------------- src/any_vec_ptr.rs | 40 ++++++++++++++++++--------------- src/any_vec_raw.rs | 16 ++++++++++++++ src/any_vec_typed.rs | 19 ++++++++++++++-- src/iter.rs | 10 +++++---- src/ops/pop.rs | 8 ++++--- src/ops/remove.rs | 13 ++--------- src/ops/swap_remove.rs | 27 ++++++++--------------- tests/any_vec.rs | 7 +++--- 10 files changed, 117 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 206d84d..28cf33f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,12 @@ `AnyValue::as_bytes()->&[u8]`. Same for `AnyValueMut`. - `AnyValueWrapper` now `AnyValueMut`. - `AnyValueRaw` now `AnyValueMut`. +- `AnyValue::as_bytes()` now return `&[u8]`. ### Added - `Debug` implemented for `AnyVec`, `AnyVecTyped`. - `AnyValueMut::swap()`. +- `AnyVec`/`AnyVecTyped` `::set_len()`. ### Fixed - Stacked Borrow friendly now. diff --git a/src/any_vec.rs b/src/any_vec.rs index 938371f..0bf3626 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -6,6 +6,7 @@ use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut, Range, RangeBounds}; use std::ptr::NonNull; use std::slice; +use std::slice::{from_raw_parts, from_raw_parts_mut}; use crate::{AnyVecTyped, into_range, mem, ops}; use crate::any_value::{AnyValue}; use crate::any_vec_raw::AnyVecRaw; @@ -13,7 +14,7 @@ use crate::ops::{TempValue, Remove, SwapRemove, remove, swap_remove, Pop, pop}; use crate::ops::{Drain, Splice, drain, splice}; use crate::any_vec::traits::{None}; use crate::clone_type::{CloneFn, CloneFnTrait, CloneType}; -use crate::element::{ElementPointer, Element, ElementMut, ElementRef}; +use crate::element::{ElementPointer, ElementMut, ElementRef}; use crate::any_vec_ptr::AnyVecPtr; use crate::iter::{Iter, IterMut, IterRef}; use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemResizable}; @@ -301,6 +302,11 @@ impl AnyVec self.raw.shrink_to(min_capacity) } + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) { + self.raw.set_len(new_len); + } + /// Returns [`AnyVecRef`] - typed view to const AnyVec, /// if container holds elements of type T, or None if it isn’t. #[inline] @@ -346,8 +352,19 @@ impl AnyVec } #[inline] - pub fn as_bytes(&self) -> *const u8 { - self.raw.mem.as_ptr() + pub fn as_bytes(&self) -> &[u8] { + unsafe{from_raw_parts( + self.raw.mem.as_ptr(), + self.len() + )} + } + + #[inline] + pub fn as_bytes_mut(&mut self) -> &mut [u8]{ + unsafe{from_raw_parts_mut( + self.raw.mem.as_mut_ptr(), + self.len() + )} } #[inline] @@ -361,17 +378,6 @@ impl AnyVec Iter::new(AnyVecPtr::from(self), 0, len) } - #[inline] - unsafe fn get_element(&self, index: usize) -> ManuallyDrop>{ - let element = NonNull::new_unchecked( - self.as_bytes().add(self.element_layout().size() * index) as *mut u8 - ); - ManuallyDrop::new(ElementPointer::new( - AnyVecPtr::from(self), - element - )) - } - /// Return reference to element at `index` with bounds check. /// /// # Panics @@ -393,7 +399,13 @@ impl AnyVec #[inline] pub unsafe fn get_unchecked(&self, index: usize) -> ElementRef{ - ElementRef(self.get_element(index)) + let element_ptr = self.raw.get_unchecked(index) as *mut u8; + ElementRef( + ManuallyDrop::new(ElementPointer::new( + AnyVecPtr::from(self), + NonNull::new_unchecked(element_ptr) + )) + ) } /// Return mutable reference to element at `index` with bounds check. @@ -417,7 +429,13 @@ impl AnyVec #[inline] pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> ElementMut { - ElementMut(self.get_element(index)) + let element_ptr = self.raw.get_unchecked_mut(index); + ElementMut( + ManuallyDrop::new(ElementPointer::new( + AnyVecPtr::from(self), + NonNull::new_unchecked(element_ptr) + )) + ) } /// # Panics diff --git a/src/any_vec_ptr.rs b/src/any_vec_ptr.rs index e187db8..92a9301 100644 --- a/src/any_vec_ptr.rs +++ b/src/any_vec_ptr.rs @@ -118,18 +118,21 @@ impl IAnyVecPtr for AnyVecPtr /// Type knowledge optimized operations. +/// +/// All unsafe, because dereferencing pointer is unsafe. pub(crate) mod utils{ use std::{mem, ptr}; use std::mem::size_of; - use crate::mem::Mem; + use std::ptr::NonNull; use crate::any_value::Unknown; use crate::any_vec_ptr::IAnyVecRawPtr; + use crate::AnyVecTyped; #[inline] - pub fn element_size(any_vec_ptr: AnyVecPtr) -> usize + pub unsafe fn element_size(any_vec_ptr: AnyVecPtr) -> usize { if Unknown::is::(){ - let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw() }; + let any_vec_raw = any_vec_ptr.any_vec_raw(); any_vec_raw.element_layout().size() } else { size_of::() @@ -137,33 +140,34 @@ pub(crate) mod utils{ } #[inline] - pub fn element_ptr_at(any_vec_ptr: AnyVecPtr, index: usize) + pub unsafe fn element_ptr_at(any_vec_ptr: AnyVecPtr, index: usize) -> *const u8 - { unsafe{ + { let any_vec_raw = any_vec_ptr.any_vec_raw(); if Unknown::is::(){ - any_vec_raw.mem.as_ptr() - .add(any_vec_raw.element_layout().size() * index) + any_vec_raw.get_unchecked(index) } else { - any_vec_raw.mem.as_ptr().cast::() - .add(index) as *const u8 + // AnyVecTyped::get_unchecked cause MIRI error + AnyVecTyped::::new(NonNull::from(any_vec_raw)) + .as_ptr().add(index) + as *const _ as *const u8 } - } } + } #[inline] - pub fn element_mut_ptr_at(mut any_vec_ptr: AnyVecPtr, index: usize) + pub unsafe fn element_mut_ptr_at(mut any_vec_ptr: AnyVecPtr, index: usize) -> *mut u8 - { unsafe{ + { let any_vec_raw = any_vec_ptr.any_vec_raw_mut(); if Unknown::is::(){ - any_vec_raw.mem.as_mut_ptr() - .add(any_vec_raw.element_layout().size() * index) + any_vec_raw.get_unchecked_mut(index) } else { - any_vec_raw.mem.as_mut_ptr().cast::() - .add(index) as *mut u8 + // AnyVecTyped::get_unchecked_mut cause MIRI error + AnyVecTyped::::new(NonNull::from(any_vec_raw)) + .as_mut_ptr().add(index) + as *mut _ as *mut u8 } - } } - + } #[inline] pub unsafe fn move_elements_at diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index a9096a4..33113e5 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -91,6 +91,16 @@ impl AnyVecRaw { assert_eq!(value.value_typeid(), self.type_id, "Type mismatch!"); } + #[inline] + pub unsafe fn get_unchecked(&self, index: usize) -> *const u8{ + self.mem.as_ptr().add(self.element_layout().size() * index) + } + + #[inline] + pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> *mut u8{ + self.mem.as_mut_ptr().add(self.element_layout().size() * index) + } + #[cold] #[inline(never)] fn expand_one(&mut self){ @@ -138,6 +148,12 @@ impl AnyVecRaw { self.mem.resize(new_len); } + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) { + debug_assert!(new_len <= self.capacity()); + self.len = new_len; + } + /// # Safety /// /// Type is not checked. diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index f181b6d..55b98fc 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -93,6 +93,11 @@ impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ self.this_mut().shrink_to(min_capacity) } + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) { + self.this_mut().set_len(new_len); + } + #[inline] pub fn insert(&mut self, index: usize, value: T){ unsafe{ @@ -223,11 +228,21 @@ impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ self.as_mut_slice().get_unchecked_mut(index) } + #[inline] + pub fn as_ptr(&self) -> *const T { + self.this().mem.as_ptr().cast::() + } + + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + self.this_mut().mem.as_mut_ptr().cast::() + } + #[inline] pub fn as_slice(&self) -> &'a [T] { unsafe{ slice::from_raw_parts( - self.this().mem.as_ptr().cast::(), + self.as_ptr(), self.this().len, ) } @@ -237,7 +252,7 @@ impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ pub fn as_mut_slice(&mut self) -> &'a mut[T] { unsafe{ slice::from_raw_parts_mut( - self.this_mut().mem.as_mut_ptr().cast::(), + self.as_mut_ptr(), self.this().len, ) } diff --git a/src/iter.rs b/src/iter.rs index 084d6c2..fe93116 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -80,10 +80,11 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> Iterat if self.index == self.end{ None } else { - let element_ptr = element_ptr_at(self.any_vec_ptr, self.index); let element = ElementPointer::new( self.any_vec_ptr, - unsafe{NonNull::new_unchecked(element_ptr as *mut u8)} + unsafe{NonNull::new_unchecked( + element_ptr_at(self.any_vec_ptr, self.index) as *mut u8 + )} ); self.index += 1; @@ -107,10 +108,11 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> Double None } else { self.end -= 1; - let element_ptr = element_ptr_at(self.any_vec_ptr, self.end); let element = ElementPointer::new( self.any_vec_ptr, - unsafe{NonNull::new_unchecked(element_ptr as *mut u8)} + unsafe{NonNull::new_unchecked( + element_ptr_at(self.any_vec_ptr, self.end) as *mut u8 + )} ); Some(IterItem::element_to_item(element)) diff --git a/src/ops/pop.rs b/src/ops/pop.rs index 2a26be9..59c5cba 100644 --- a/src/ops/pop.rs +++ b/src/ops/pop.rs @@ -35,9 +35,11 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Pop<'a, AnyVecPtr>{ #[inline] fn bytes(&self) -> *const u8 { - let any_vec_raw = unsafe{ self.any_vec_ptr.any_vec_raw() }; - let index = any_vec_raw.len; - element_ptr_at(self.any_vec_ptr, index) + unsafe{ + let any_vec_raw = self.any_vec_ptr.any_vec_raw(); + let index = any_vec_raw.len; + element_ptr_at(self.any_vec_ptr, index) + } } #[inline] diff --git a/src/ops/remove.rs b/src/ops/remove.rs index 8a77733..b7e4361 100644 --- a/src/ops/remove.rs +++ b/src/ops/remove.rs @@ -2,8 +2,8 @@ use std::marker::PhantomData; use std::ptr; use crate::any_value::Unknown; use crate::any_vec_ptr::IAnyVecRawPtr; +use crate::any_vec_ptr::utils::element_ptr_at; use crate::any_vec_raw::AnyVecRaw; -use crate::mem::Mem; use crate::ops::temp::Operation; pub struct Remove<'a, AnyVecPtr: IAnyVecRawPtr>{ @@ -35,16 +35,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Remove<'a, AnyVecPtr>{ #[inline] fn bytes(&self) -> *const u8 { - unsafe{ - let any_vec_raw = self.any_vec_ptr.any_vec_raw(); - if !Unknown::is::(){ - any_vec_raw.mem.as_ptr().cast::() - .add(self.index) as *const u8 - } else { - any_vec_raw.mem.as_ptr() - .add(any_vec_raw.element_layout().size() * self.index) - } - } + unsafe{ element_ptr_at(self.any_vec_ptr, self.index) } } #[inline] diff --git a/src/ops/swap_remove.rs b/src/ops/swap_remove.rs index 5fd5697..f6fc563 100644 --- a/src/ops/swap_remove.rs +++ b/src/ops/swap_remove.rs @@ -3,8 +3,8 @@ use std::ptr; use crate::copy_bytes_nonoverlapping; use crate::any_value::Unknown; use crate::any_vec_ptr::IAnyVecRawPtr; +use crate::any_vec_ptr::utils::{element_mut_ptr_at, element_ptr_at}; use crate::any_vec_raw::AnyVecRaw; -use crate::mem::Mem; use crate::ops::temp::Operation; pub struct SwapRemove<'a, AnyVecPtr: IAnyVecRawPtr>{ @@ -17,19 +17,13 @@ pub struct SwapRemove<'a, AnyVecPtr: IAnyVecRawPtr>{ impl<'a, AnyVecPtr: IAnyVecRawPtr> SwapRemove<'a, AnyVecPtr>{ #[inline] pub(crate) fn new(mut any_vec_ptr: AnyVecPtr, index: usize) -> Self{ - let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw_mut() }; + let element = unsafe{ element_mut_ptr_at(any_vec_ptr, index) }; // 1. mem::forget and element drop panic "safety". + let any_vec_raw = unsafe{ any_vec_ptr.any_vec_raw_mut() }; let last_index = any_vec_raw.len - 1; any_vec_raw.len = index; - let element: *mut u8 = unsafe{ - if !Unknown::is::(){ - any_vec_raw.mem.as_mut_ptr().cast::().add(index) as *mut u8 - } else { - any_vec_raw.mem.as_mut_ptr().add(any_vec_raw.element_layout().size() * index) - } - }; Self{ any_vec_ptr, element, last_index, phantom: PhantomData } } } @@ -51,14 +45,8 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for SwapRemove<'a, AnyVecPtr>{ fn consume(&mut self) { unsafe{ // 2. overwrite with last element + let last_element = element_ptr_at(self.any_vec_ptr, self.last_index); let any_vec_raw = self.any_vec_ptr.any_vec_raw_mut(); - let last_element = - if !Unknown::is::() { - any_vec_raw.mem.as_ptr().cast::().add(self.last_index) as *const u8 - } else { - any_vec_raw.mem.as_ptr() - .add(any_vec_raw.element_layout().size() * self.last_index) - }; if self.element as *const u8 != last_element { if !Unknown::is::() { @@ -68,8 +56,11 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for SwapRemove<'a, AnyVecPtr>{ 1 ); } else { - copy_bytes_nonoverlapping - (last_element, self.element, any_vec_raw.element_layout().size()); + copy_bytes_nonoverlapping( + last_element, + self.element, + any_vec_raw.element_layout().size() + ); } } diff --git a/tests/any_vec.rs b/tests/any_vec.rs index c0dcdfe..08689eb 100644 --- a/tests/any_vec.rs +++ b/tests/any_vec.rs @@ -4,7 +4,7 @@ use std::mem::forget; use std::ptr::NonNull; use itertools::assert_equal; use any_vec::AnyVec; -use any_vec::any_value::{AnyValueRaw, AnyValueWrapper}; +use any_vec::any_value::{AnyValueMut, AnyValueRaw, AnyValueWrapper}; use any_vec::mem::Stack; #[allow(dead_code)] @@ -175,7 +175,8 @@ fn any_vec_swap_remove_push_test() { any_vec.push(AnyValueWrapper::new(String::from("4"))); let mut any_vec_other: AnyVec = AnyVec::new::(); - let element = any_vec.swap_remove(1); + let mut element = any_vec.swap_remove(1); + *element.downcast_mut::().unwrap() += "+"; any_vec_other.push(element); assert_equal(any_vec.downcast_ref::().unwrap().as_slice(), &[ @@ -184,7 +185,7 @@ fn any_vec_swap_remove_push_test() { String::from("3"), ]); assert_equal(any_vec_other.downcast_ref::().unwrap().as_slice(), &[ - String::from("1"), + String::from("1+"), ]); } From 3e0879e5643bf3510ba2b71e97fc8b80fca60b33 Mon Sep 17 00:00:00 2001 From: tower120 Date: Sun, 10 Jul 2022 17:08:43 +0300 Subject: [PATCH 12/35] spare_bytes_mut + Stack fix + StackN --- CHANGELOG.md | 2 ++ Readme.md | 2 +- src/any_vec.rs | 14 ++++++++--- src/lib.rs | 4 +-- src/mem/mod.rs | 2 ++ src/mem/stack.rs | 24 ++++++++++++++---- src/mem/stack_n.rs | 51 ++++++++++++++++++++++++++++++++++++++ tests/any_vec.rs | 4 +-- tests/any_vec_send_sync.rs | 4 +-- 9 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 src/mem/stack_n.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 28cf33f..ffbac6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,11 @@ - `Debug` implemented for `AnyVec`, `AnyVecTyped`. - `AnyValueMut::swap()`. - `AnyVec`/`AnyVecTyped` `::set_len()`. +- `mem::StackN` added. ### Fixed - Stacked Borrow friendly now. +- `mem::Stack` capacity fixed. ## 0.9.1 ### Changed diff --git a/Readme.md b/Readme.md index d61a58c..69c9d06 100644 --- a/Readme.md +++ b/Readme.md @@ -84,7 +84,7 @@ any_vec.push(AnyValueWrapper::new(String::from("0"))) ```rust fn self_push_first_element(any_vec: &mut AnyVec){ - let mut tmp = any_vec.clone_empty_in(Stack::<256>); + let mut tmp = any_vec.clone_empty_in(StackN::<1, 256>); tmp.push(any_vec.at(0).lazy_clone()); any_vec.push(tmp.pop().unwrap()); } diff --git a/src/any_vec.rs b/src/any_vec.rs index 0bf3626..8103f11 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -2,7 +2,7 @@ use std::alloc::Layout; use std::any::TypeId; use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; -use std::mem::ManuallyDrop; +use std::mem::{ManuallyDrop, MaybeUninit}; use std::ops::{Deref, DerefMut, Range, RangeBounds}; use std::ptr::NonNull; use std::slice; @@ -355,7 +355,7 @@ impl AnyVec pub fn as_bytes(&self) -> &[u8] { unsafe{from_raw_parts( self.raw.mem.as_ptr(), - self.len() + self.len() * self.element_layout().size() )} } @@ -363,7 +363,15 @@ impl AnyVec pub fn as_bytes_mut(&mut self) -> &mut [u8]{ unsafe{from_raw_parts_mut( self.raw.mem.as_mut_ptr(), - self.len() + self.len() * self.element_layout().size() + )} + } + + #[inline] + pub fn spare_bytes_mut(&mut self) -> &mut [MaybeUninit]{ + unsafe{from_raw_parts_mut( + self.raw.mem.as_mut_ptr().add(self.len()) as *mut MaybeUninit, + (self.capacity() - self.len()) * self.element_layout().size() )} } diff --git a/src/lib.rs b/src/lib.rs index e1793ff..77a8872 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,11 +103,11 @@ //!```rust //! # use any_vec::any_value::{AnyValueCloneable, AnyValueWrapper}; //! # use any_vec::AnyVec; -//! # use any_vec::mem::Stack; +//! # use any_vec::mem::StackN; //! # use any_vec::traits::*; //! //! fn self_push_first_element(any_vec: &mut AnyVec){ -//! let mut tmp = any_vec.clone_empty_in(Stack::<256>); +//! let mut tmp = any_vec.clone_empty_in(StackN::<1, 256>); //! tmp.push(any_vec.at(0).lazy_clone()); //! any_vec.push(tmp.pop().unwrap()); //! } diff --git a/src/mem/mod.rs b/src/mem/mod.rs index 4dad953..a6782b3 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -1,8 +1,10 @@ mod heap; mod stack; +mod stack_n; pub use heap::Heap; pub use stack::Stack; +pub use stack_n::StackN; pub(crate) type Default = Heap; diff --git a/src/mem/stack.rs b/src/mem/stack.rs index a43e244..f1047d3 100644 --- a/src/mem/stack.rs +++ b/src/mem/stack.rs @@ -2,9 +2,14 @@ use std::alloc::Layout; use std::mem::MaybeUninit; use crate::mem::{Mem, MemBuilder}; -/// Fixed capacity on-stack memory. +/// Fixed `SIZE` capacity on-stack memory. /// -/// `SIZE` in bytes. +/// Can contain at most `SIZE` bytes. +/// Upon `build()` real capacity calculated based on `element_layout`. +/// This involves `idiv` operation. You may want to consider [`StackN`] +/// for intermediate storage instead. +/// +/// [`StackN`]: super::StackN #[derive(Default, Clone)] pub struct Stack; impl MemBuilder for Stack{ @@ -12,16 +17,25 @@ impl MemBuilder for Stack{ #[inline] fn build(&mut self, element_layout: Layout) -> StackMem { + let size = + if element_layout.size() == 0{ + usize::MAX + } else{ + SIZE / element_layout.size() + }; + StackMem{ mem: MaybeUninit::uninit(), - element_layout + element_layout, + size } } } pub struct StackMem{ mem: MaybeUninit<[u8; SIZE]>, - element_layout: Layout + element_layout: Layout, + size: usize } impl Mem for StackMem{ @@ -42,6 +56,6 @@ impl Mem for StackMem{ #[inline] fn size(&self) -> usize { - SIZE + self.size } } \ No newline at end of file diff --git a/src/mem/stack_n.rs b/src/mem/stack_n.rs new file mode 100644 index 0000000..d56aa45 --- /dev/null +++ b/src/mem/stack_n.rs @@ -0,0 +1,51 @@ +use std::alloc::Layout; +use std::mem::MaybeUninit; +use crate::mem::{Mem, MemBuilder}; + +/// Fixed `SIZE` capacity on-stack memory for `N` elements. +/// +/// Can contain `N` elements, with total size at most `SIZE` bytes. +/// Unlike [`Stack`] does not involve heavy operations for building. +/// +/// [`Stack`]: super::Stack +#[derive(Default, Clone)] +pub struct StackN; +impl MemBuilder for StackN{ + type Mem = StackNMem; + + #[inline] + fn build(&mut self, element_layout: Layout) -> Self::Mem { + assert!(N*element_layout.size() <= SIZE, "Insufficient storage!"); + StackNMem{ + mem: MaybeUninit::uninit(), + element_layout + } + } +} + +pub struct StackNMem{ + mem: MaybeUninit<[u8; SIZE]>, + element_layout: Layout +} + +impl Mem for StackNMem{ + #[inline] + fn as_ptr(&self) -> *const u8 { + self.mem.as_ptr() as *const u8 + } + + #[inline] + fn as_mut_ptr(&mut self) -> *mut u8 { + self.mem.as_mut_ptr() as *mut u8 + } + + #[inline] + fn element_layout(&self) -> Layout { + self.element_layout + } + + #[inline] + fn size(&self) -> usize { + N + } +} \ No newline at end of file diff --git a/tests/any_vec.rs b/tests/any_vec.rs index 08689eb..bdad307 100644 --- a/tests/any_vec.rs +++ b/tests/any_vec.rs @@ -336,7 +336,7 @@ fn shrink_to_test(){ #[test] fn mem_stack_test(){ use any_vec::traits::None; - type FixedAnyVec = AnyVec>; + type FixedAnyVec = AnyVec>; let mut any_vec: FixedAnyVec = AnyVec::new::(); { @@ -350,7 +350,7 @@ fn mem_stack_test(){ // Should fail to compile. //any_vec.reserve(1); - assert_eq!(any_vec.capacity(), 512); + assert_eq!(any_vec.capacity(), 513/size_of::()); assert_eq!(any_vec.len(), 4); assert_equal(any_vec.downcast_ref::().unwrap(), &[ String::from("0"), diff --git a/tests/any_vec_send_sync.rs b/tests/any_vec_send_sync.rs index b4b6d42..7228e58 100644 --- a/tests/any_vec_send_sync.rs +++ b/tests/any_vec_send_sync.rs @@ -84,8 +84,8 @@ fn any_vec_heap_send_sync_test() { } } test_positive::(); - test_positive::>(); + test_positive::>(); test_negative::(); - test_negative::>(); + test_negative::>(); } From d37f9d00a943a3bd5fa7871ec7a024e4af2e1fa9 Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 10 Jul 2022 17:18:36 +0300 Subject: [PATCH 13/35] v0.10.0 --- CHANGELOG.md | 9 ++++++--- Cargo.toml | 2 +- src/any_vec_typed.rs | 15 +++++++++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffbac6e..613d825 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## 0.10.0 ### Changed - `AnyValue::bytes()->*const u8` and `AnyValue::size()->usize` replaced with `AnyValue::as_bytes()->&[u8]`. Same for `AnyValueMut`. @@ -10,8 +10,11 @@ ### Added - `Debug` implemented for `AnyVec`, `AnyVecTyped`. -- `AnyValueMut::swap()`. -- `AnyVec`/`AnyVecTyped` `::set_len()`. +- `AnyValueMut::swap()` added. +- `AnyVec`/`AnyVecTyped` `::set_len()` added. +- `AnyVec::as_bytes_mut` added. +- `AnyVec::spare_bytes_mut` added. +- `AnyVecTyped::spare_capacity_mut` added. - `mem::StackN` added. ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 18be4e1..b4f7cdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "any_vec" authors = ["Andrey Diduh "] license = "MIT OR Apache-2.0" -version = "0.9.1" +version = "0.10.0" edition = "2021" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." repository = "https://github.com/tower120/any_vec" diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index 55b98fc..d39529a 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -1,5 +1,6 @@ use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; +use std::mem::MaybeUninit; use std::ops::{Range, RangeBounds}; use std::ptr::NonNull; use std::slice; @@ -243,7 +244,7 @@ impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ unsafe{ slice::from_raw_parts( self.as_ptr(), - self.this().len, + self.len(), ) } } @@ -253,7 +254,17 @@ impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ unsafe{ slice::from_raw_parts_mut( self.as_mut_ptr(), - self.this().len, + self.len(), + ) + } + } + + #[inline] + pub fn spare_capacity_mut(&mut self) -> &'a mut[MaybeUninit] { + unsafe { + slice::from_raw_parts_mut( + self.as_mut_ptr().add(self.len()) as *mut MaybeUninit, + self.capacity() - self.len(), ) } } From 5a8e70a4e62c726e9c09d388602421b8509d7ba1 Mon Sep 17 00:00:00 2001 From: tower120 Date: Wed, 13 Jul 2022 11:42:51 +0300 Subject: [PATCH 14/35] Mem raw parts --- .github/workflows/ci.yml | 2 +- CHANGELOG.md | 10 +++ Cargo.toml | 4 ++ benches/push.rs | 6 +- benches/raw_parts.rs | 61 +++++++++++++++++++ src/any_vec.rs | 127 +++++++++++++++++++++++++++++++++++++-- src/any_vec_ptr.rs | 2 +- src/any_vec_raw.rs | 23 +++---- src/clone_type.rs | 12 ++-- src/element.rs | 8 ++- src/lib.rs | 2 +- src/mem/heap.rs | 22 ++++++- src/mem/mod.rs | 8 +++ src/mem/stack_n.rs | 3 + src/ops/temp.rs | 4 +- 15 files changed, 255 insertions(+), 39 deletions(-) create mode 100644 benches/raw_parts.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42ddf8f..dcfc895 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,4 +72,4 @@ jobs: # with: # rust-version: stable - name: Build doc - run: RUSTFLAGS="--deny warnings" cargo doc --lib \ No newline at end of file + run: RUSTDOCFLAGS="--deny warnings" cargo doc --lib \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 613d825..60b3af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## Unreleased +### Added +- `AnyVec::into_raw_parts` / `AnyVec::from_raw_parts` / `RawParts`. +- `MemRawParts`. +- `AnyVec::element_drop`. +- `AnyVec::element_clone`. + +### Changed +- `HeapMem` implements `MemRawParts`. + ## 0.10.0 ### Changed - `AnyValue::bytes()->*const u8` and `AnyValue::size()->usize` replaced with diff --git a/Cargo.toml b/Cargo.toml index b4f7cdb..74c48ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,4 +48,8 @@ harness = false [[bench]] name = "clone" +harness = false + +[[bench]] +name = "raw_parts" harness = false \ No newline at end of file diff --git a/benches/push.rs b/benches/push.rs index 9748b27..8d3d3cb 100644 --- a/benches/push.rs +++ b/benches/push.rs @@ -7,8 +7,8 @@ use any_vec::AnyVec; const SIZE: usize = 10000; -type Element = [u8;128]; -static VALUE: Element = [0;128]; +type Element = (usize, usize); +static VALUE: Element = (0,0); fn vec_push(){ let mut vec = Vec::new(); @@ -19,8 +19,8 @@ fn vec_push(){ fn any_vec_push(){ let mut any_vec: AnyVec = AnyVec::new::(); + let mut vec = any_vec.downcast_mut::().unwrap(); for _ in 0..SIZE{ - let mut vec = any_vec.downcast_mut::().unwrap(); vec.push(VALUE.clone()); } } diff --git a/benches/raw_parts.rs b/benches/raw_parts.rs new file mode 100644 index 0000000..178cb94 --- /dev/null +++ b/benches/raw_parts.rs @@ -0,0 +1,61 @@ +use std::mem; +use criterion::{criterion_group, criterion_main, Criterion}; +use any_vec::AnyVec; + +const SIZE: usize = 10000; + +type Element = (usize, usize, usize, usize); +static VALUE: Element = (0,0,0,0); + +fn vec_push(){ + let mut vec = Vec::new(); + for _ in 0..SIZE{ + vec.push(VALUE.clone()); + } +} + +fn vec_from_raw_parts_push(){ + let mut vec = Vec::new(); + for _ in 0..SIZE{ + let mut vec = unsafe{Vec::from_raw_parts( + vec.as_mut_ptr(), + vec.len(), + vec.capacity() + )}; + vec.push(VALUE.clone()); + mem::forget(vec); + } +} + +fn any_vec_push(){ + let mut any_vec: AnyVec = AnyVec::new::(); + for _ in 0..SIZE{ + let mut vec = any_vec.downcast_mut::().unwrap(); + vec.push(VALUE.clone()); + } +} + +fn any_vec_from_parts_push(){ + let any_vec: AnyVec = AnyVec::new::(); + let raw_parts = any_vec.into_raw_parts(); + + for _ in 0..SIZE{ + let mut any_vec: AnyVec = unsafe{AnyVec::from_raw_parts(raw_parts.clone())}; + let mut vec = any_vec.downcast_mut::().unwrap(); + vec.push(VALUE.clone()); + mem::forget(any_vec); + } + + let any_vec: AnyVec = unsafe{AnyVec::from_raw_parts(raw_parts)}; + drop(any_vec) +} + +pub fn bench_push(c: &mut Criterion) { + c.bench_function("Vec push", |b|b.iter(||vec_push())); + c.bench_function("Vec from_raw_parts push", |b|b.iter(||vec_from_raw_parts_push())); + c.bench_function("AnyVec push", |b|b.iter(||any_vec_push())); + c.bench_function("AnyVec from_raw_parts push", |b|b.iter(||any_vec_from_parts_push())); +} + +criterion_group!(benches, bench_push); +criterion_main!(benches); \ No newline at end of file diff --git a/src/any_vec.rs b/src/any_vec.rs index 8103f11..c759029 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -5,11 +5,11 @@ use std::marker::PhantomData; use std::mem::{ManuallyDrop, MaybeUninit}; use std::ops::{Deref, DerefMut, Range, RangeBounds}; use std::ptr::NonNull; -use std::slice; +use std::{ptr, slice}; use std::slice::{from_raw_parts, from_raw_parts_mut}; use crate::{AnyVecTyped, into_range, mem, ops}; use crate::any_value::{AnyValue}; -use crate::any_vec_raw::AnyVecRaw; +use crate::any_vec_raw::{AnyVecRaw, DropFn}; use crate::ops::{TempValue, Remove, SwapRemove, remove, swap_remove, Pop, pop}; use crate::ops::{Drain, Splice, drain, splice}; use crate::any_vec::traits::{None}; @@ -17,7 +17,7 @@ use crate::clone_type::{CloneFn, CloneFnTrait, CloneType}; use crate::element::{ElementPointer, ElementMut, ElementRef}; use crate::any_vec_ptr::AnyVecPtr; use crate::iter::{Iter, IterMut, IterRef}; -use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemResizable}; +use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemRawParts, MemResizable}; use crate::traits::{Cloneable, Trait}; /// Trait constraints. @@ -87,6 +87,46 @@ impl SatisfyTraits for T{} impl SatisfyTraits for T{} impl SatisfyTraits for T{} +/// [`AnyVec`] raw parts. +/// +/// You can get it with [`AnyVec::into_raw_parts`], or build/edit +/// it manually. And with [`AnyVec::from_raw_parts`], you can construct +/// [`AnyVec`]. +pub struct RawParts +where + M::Mem: MemRawParts +{ + pub mem_builder: M, + pub mem_handle: ::Handle, + pub capacity: usize, + pub len: usize, + pub element_layout: Layout, + pub element_typeid: TypeId, + pub element_drop: Option, + + /// Ignored if non Cloneable. + pub element_clone: CloneFn, +} + +impl Clone for RawParts +where + M::Mem: MemRawParts, + ::Handle: Clone +{ + #[inline] + fn clone(&self) -> Self { + Self{ + mem_builder: self.mem_builder.clone(), + mem_handle: self.mem_handle.clone(), + capacity: self.capacity, + len: self.capacity, + element_layout: self.element_layout, + element_typeid: self.element_typeid, + element_drop: self.element_drop, + element_clone: self.element_clone, + } + } +} /// Type erased vec-like container. /// All elements have the same type. @@ -181,6 +221,65 @@ impl AnyVec Self::build::(raw) } + /// Destructure `AnyVec` into [`RawParts`]. + #[inline] + pub fn into_raw_parts(self) -> RawParts + where + M::Mem: MemRawParts + { + let this = ManuallyDrop::new(self); + + let mem_builder = unsafe{ ptr::read(&this.raw.mem_builder) }; + let mem = unsafe{ ptr::read(&this.raw.mem) }; + let (mem_handle, element_layout, capacity) = mem.into_raw_parts(); + RawParts{ + mem_builder, + mem_handle, + capacity, + len: this.raw.len, + element_layout, + element_typeid: this.raw.type_id, + element_drop: this.raw.drop_fn, + element_clone: this.clone_fn() + } + } + + /// Construct `AnyVec` from previously deconstructed raw parts. + /// + /// # Safety + /// + /// ## Traits + /// + /// Traits validity not checked. `RawParts` of underlying type must implement Traits. + /// It is not safe to opt-in [`Cloneable`], if initial `AnyVec` was not constructed with + /// that trait. + /// + /// ## RawParts + /// + /// `RawParts` validity not checked. + /// + #[inline] + pub unsafe fn from_raw_parts(raw_parts: RawParts) -> Self + where + M::Mem: MemRawParts + { + Self{ + raw: AnyVecRaw{ + mem_builder: raw_parts.mem_builder, + mem: MemRawParts::from_raw_parts( + raw_parts.mem_handle, + raw_parts.element_layout, + raw_parts.capacity + ), + len: raw_parts.len, + type_id: raw_parts.element_typeid, + drop_fn: raw_parts.element_drop + }, + clone_fn: ::new(raw_parts.element_clone), + phantom: PhantomData + } + } + /// Constructs **empty** [`AnyVec`] with the same elements type, `Traits` and `MemBuilder`. /// IOW, same as [`clone`], but without elements copy. /// @@ -605,7 +704,7 @@ impl AnyVec /// Element TypeId #[inline] pub fn element_typeid(&self) -> TypeId{ - self.raw.element_typeid() + self.raw.type_id } /// Element Layout @@ -614,6 +713,26 @@ impl AnyVec self.raw.element_layout() } + /// Element drop function. + /// + /// `len` - elements count. + /// None - drop is not needed. + #[inline] + pub fn element_drop(&self) -> Option { + self.raw.drop_fn + } + + /// Element clone function. + /// + /// `len` - elements count. + #[inline] + pub fn element_clone(&self) -> CloneFn + where + Traits: Cloneable + { + self.clone_fn() + } + #[inline] pub fn len(&self) -> usize { self.raw.len diff --git a/src/any_vec_ptr.rs b/src/any_vec_ptr.rs index 92a9301..001b990 100644 --- a/src/any_vec_ptr.rs +++ b/src/any_vec_ptr.rs @@ -199,7 +199,7 @@ pub(crate) mod utils{ if Unknown::is::(){ let any_vec_raw = any_vec_ptr.any_vec_raw(); - if let Some(drop_fn) = any_vec_raw.drop_fn(){ + if let Some(drop_fn) = any_vec_raw.drop_fn{ (drop_fn)( element_mut_ptr_at(any_vec_ptr, start_index), end_index - start_index diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index 33113e5..13c61e9 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -5,14 +5,14 @@ use crate::any_value::{AnyValue, Unknown}; use crate::clone_type::CloneFn; use crate::mem::{Mem, MemBuilder, MemResizable}; -pub type DropFn = fn(ptr: *mut u8, len: usize); +pub type DropFn = unsafe fn(ptr: *mut u8, len: usize); pub struct AnyVecRaw { - mem_builder: M, // usually ZST + pub(crate) mem_builder: M, // usually ZST pub(crate) mem: M::Mem, pub(crate) len: usize, // in elements - type_id: TypeId, // purely for safety checks - drop_fn: Option + pub(crate) type_id: TypeId, // purely for safety checks + pub(crate) drop_fn: Option } impl AnyVecRaw { @@ -39,11 +39,6 @@ impl AnyVecRaw { } } - #[inline] - pub fn drop_fn(&self) -> Option{ - self.drop_fn - } - #[inline] pub(crate) fn clone_empty(&self) -> Self { self.clone_empty_in(self.mem_builder.clone()) @@ -223,16 +218,12 @@ impl AnyVecRaw { self.len = 0; if let Some(drop_fn) = self.drop_fn{ - (drop_fn)(self.mem.as_mut_ptr(), len); + unsafe{ + (drop_fn)(self.mem.as_mut_ptr(), len); + } } } - /// Element TypeId - #[inline] - pub fn element_typeid(&self) -> TypeId{ - self.type_id - } - /// Element Layout #[inline] pub fn element_layout(&self) -> Layout { diff --git a/src/clone_type.rs b/src/clone_type.rs index 60aae21..b3c46f0 100644 --- a/src/clone_type.rs +++ b/src/clone_type.rs @@ -7,16 +7,14 @@ use crate::traits::*; #[derive(Copy, Clone, Default)] pub struct Empty; -pub type CloneFn = fn(src: *const u8, dst: *mut u8, len: usize); -fn clone_fn(src: *const u8, dst: *mut u8, len: usize){ +pub type CloneFn = unsafe fn(src: *const u8, dst: *mut u8, len: usize); +unsafe fn clone_fn(src: *const u8, dst: *mut u8, len: usize){ let src = src as *const T; let dst = dst as *mut T; for i in 0..len { - unsafe{ - let dst = dst.add(i); - let src = src.add(i); - dst.write((*src).clone()); - } + let dst = dst.add(i); + let src = src.add(i); + dst.write((*src).clone()); } } fn nop_fn(_: *const u8, _: *mut u8, _: usize){} diff --git a/src/element.rs b/src/element.rs index 5cf0f92..45cd310 100644 --- a/src/element.rs +++ b/src/element.rs @@ -81,8 +81,10 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ impl<'a, AnyVecPtr: IAnyVecRawPtr> Drop for ElementPointer<'a, AnyVecPtr>{ #[inline] fn drop(&mut self) { - if let Some(drop_fn) = self.any_vec_raw().drop_fn(){ - (drop_fn)(self.element.as_ptr(), 1); + if let Some(drop_fn) = self.any_vec_raw().drop_fn{ + unsafe{ + (drop_fn)(self.element.as_ptr(), 1); + } } } } @@ -92,7 +94,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValue for ElementPointer<'a, AnyVecPtr>{ #[inline] fn value_typeid(&self) -> TypeId { - self.any_vec_raw().element_typeid() + self.any_vec_raw().type_id } #[inline] diff --git a/src/lib.rs b/src/lib.rs index 77a8872..3bc8a3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,7 +144,7 @@ mod any_vec_raw; mod any_vec_typed; mod iter; -pub use crate::any_vec::{AnyVec, AnyVecMut, AnyVecRef, SatisfyTraits, traits}; +pub use crate::any_vec::{AnyVec, AnyVecMut, AnyVecRef, SatisfyTraits, traits, RawParts}; pub use any_vec_typed::AnyVecTyped; pub use iter::{ElementIterator, Iter, IterRef, IterMut}; diff --git a/src/mem/heap.rs b/src/mem/heap.rs index b3a856d..bb709f0 100644 --- a/src/mem/heap.rs +++ b/src/mem/heap.rs @@ -1,7 +1,8 @@ use std::alloc::{alloc, dealloc, handle_alloc_error, Layout, realloc}; use std::cmp; +use std::mem::ManuallyDrop; use std::ptr::NonNull; -use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemResizable}; +use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemRawParts, MemResizable}; #[inline] fn dangling(layout: &Layout) -> NonNull{ @@ -117,6 +118,25 @@ impl MemResizable for HeapMem { } } +impl MemRawParts for HeapMem{ + type Handle = NonNull; + + #[inline] + fn into_raw_parts(self) -> (Self::Handle, Layout, usize) { + let this = ManuallyDrop::new(self); + (this.mem, this.element_layout, this.size) + } + + #[inline] + unsafe fn from_raw_parts(handle: Self::Handle, element_layout: Layout, size: usize) -> Self { + Self{ + mem: handle, + size, + element_layout + } + } +} + impl Drop for HeapMem { fn drop(&mut self) { self.resize(0); diff --git a/src/mem/mod.rs b/src/mem/mod.rs index a6782b3..d75d7b2 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -91,4 +91,12 @@ pub trait MemResizable: Mem{ /// /// Implementation may panic, if fail to allocate/reallocate/deallocate memory. fn resize(&mut self, new_size: usize); +} + +/// [`Mem`] destructurable into raw parts. +pub trait MemRawParts: Mem{ + type Handle; + + fn into_raw_parts(self) -> (Self::Handle, Layout, usize); + unsafe fn from_raw_parts(handle: Self::Handle, element_layout: Layout, size: usize) -> Self; } \ No newline at end of file diff --git a/src/mem/stack_n.rs b/src/mem/stack_n.rs index d56aa45..5825c06 100644 --- a/src/mem/stack_n.rs +++ b/src/mem/stack_n.rs @@ -7,6 +7,9 @@ use crate::mem::{Mem, MemBuilder}; /// Can contain `N` elements, with total size at most `SIZE` bytes. /// Unlike [`Stack`] does not involve heavy operations for building. /// +/// N.B. It should be `ELEMENT_SIZE` instead of total `SIZE`, but Rust +/// still can't do `N * ELEMENT_SIZE` in generic context. +/// /// [`Stack`]: super::Stack #[derive(Default, Clone)] pub struct StackN; diff --git a/src/ops/temp.rs b/src/ops/temp.rs index b1b8402..79dd4d7 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -55,7 +55,7 @@ impl AnyValue for TempValue{ fn value_typeid(&self) -> TypeId { let typeid = TypeId::of::(); if typeid == TypeId::of::(){ - self.any_vec_raw().element_typeid() + self.any_vec_raw().type_id } else { typeid } @@ -103,7 +103,7 @@ impl Drop for TempValue{ #[inline] fn drop(&mut self) { unsafe{ - let drop_fn = self.any_vec_raw().drop_fn(); + let drop_fn = self.any_vec_raw().drop_fn; let element = self.op.bytes() as *mut u8; // compile-time check From 454c5f34ce70c3959be2d8124b28b635d8a1c57c Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 14 Jul 2022 15:29:13 +0300 Subject: [PATCH 15/35] must_use + inlines --- src/any_vec.rs | 9 +++++++++ src/any_vec_raw.rs | 1 + 2 files changed, 10 insertions(+) diff --git a/src/any_vec.rs b/src/any_vec.rs index c759029..e9d6c9c 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -166,6 +166,7 @@ impl AnyVec /// /// Not available, if provided [`MemBuilder`] is not [`Default`]. #[inline] + #[must_use] pub fn new() -> Self where T: SatisfyTraits, @@ -179,6 +180,7 @@ impl AnyVec /// /// `T` should satisfy requested Traits. #[inline] + #[must_use] pub fn new_in(mut mem_builder: M) -> Self where T: SatisfyTraits { @@ -195,6 +197,7 @@ impl AnyVec /// Not available, if provided [`MemBuilder`] is not /// [`MemBuilderSizeable`] and [`Default`]. #[inline] + #[must_use] pub fn with_capacity(capacity: usize) -> Self where T: SatisfyTraits, @@ -211,6 +214,8 @@ impl AnyVec /// /// Not available, if provided [`MemBuilder`] is not /// [`MemBuilderSizeable`]. + #[inline] + #[must_use] pub fn with_capacity_in(capacity: usize, mut mem_builder: M) -> Self where T: SatisfyTraits, @@ -223,6 +228,7 @@ impl AnyVec /// Destructure `AnyVec` into [`RawParts`]. #[inline] + #[must_use] pub fn into_raw_parts(self) -> RawParts where M::Mem: MemRawParts @@ -259,6 +265,7 @@ impl AnyVec /// `RawParts` validity not checked. /// #[inline] + #[must_use] pub unsafe fn from_raw_parts(raw_parts: RawParts) -> Self where M::Mem: MemRawParts @@ -285,6 +292,7 @@ impl AnyVec /// /// [`clone`]: Clone::clone #[inline] + #[must_use] pub fn clone_empty(&self) -> Self { Self { raw: self.raw.clone_empty(), @@ -312,6 +320,7 @@ impl AnyVec /// any_vec.push(tmp.pop().unwrap()); /// ``` #[inline] + #[must_use] pub fn clone_empty_in(&self, mem_builder: NewM) -> AnyVec { AnyVec { raw: self.raw.clone_empty_in(mem_builder), diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index 13c61e9..dde21de 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -237,6 +237,7 @@ impl AnyVecRaw { } impl Drop for AnyVecRaw { + #[inline] fn drop(&mut self) { self.clear(); } From 0120b707e619bf62a0ad7ac2d57db600300cded9 Mon Sep 17 00:00:00 2001 From: tower120 Date: Fri, 15 Jul 2022 15:29:10 +0300 Subject: [PATCH 16/35] AnyValueUnknown --- CHANGELOG.md | 11 ++++ benches/element_clone.rs | 2 +- src/any_value/lazy_clone.rs | 16 ++--- src/any_value/mod.rs | 119 ++++++++++++++++++++---------------- src/any_value/raw.rs | 72 ++++++++++++++++------ src/any_value/wrapper.rs | 22 ++++--- src/any_vec.rs | 39 +++++++++++- src/any_vec_ptr.rs | 12 ++++ src/any_vec_raw.rs | 9 +-- src/any_vec_typed.rs | 2 +- src/element.rs | 18 +++--- src/lib.rs | 6 ++ src/ops/splice.rs | 6 +- src/ops/temp.rs | 32 +++++----- 14 files changed, 243 insertions(+), 123 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60b3af4..c3ef374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## Unreleased ### Added +#### `AnyValueUnknown` +- `AnyValue` split into `AnyValueUnknown` + `AnyValue`. +- `AnyValueMut` split into `AnyValueMutUnknown` + `AnyValueMut`. +- `AnyVec::push_unchecked(AnyValueUnknown)`. +- `AnyVec::insert_unchecked(usize, AnyValueUnknown)`. +- `AnyValueRawUnknown`. + +#### Raw parts - `AnyVec::into_raw_parts` / `AnyVec::from_raw_parts` / `RawParts`. - `MemRawParts`. - `AnyVec::element_drop`. @@ -10,6 +18,9 @@ ### Changed - `HeapMem` implements `MemRawParts`. +### Fixed +- `AnyVec::splice` now check types. + ## 0.10.0 ### Changed - `AnyValue::bytes()->*const u8` and `AnyValue::size()->usize` replaced with diff --git a/benches/element_clone.rs b/benches/element_clone.rs index 8c7bccf..aee1469 100644 --- a/benches/element_clone.rs +++ b/benches/element_clone.rs @@ -2,7 +2,7 @@ mod utils; use std::time::{Duration, Instant}; use criterion::{criterion_group, criterion_main, Criterion, black_box}; -use any_vec::any_value::{AnyValue, AnyValueCloneable}; +use any_vec::any_value::{AnyValueUnknown, AnyValueCloneable}; use any_vec::AnyVec; use any_vec::traits::Cloneable; use crate::utils::bench_custom; diff --git a/src/any_value/lazy_clone.rs b/src/any_value/lazy_clone.rs index edf83ee..e84f036 100644 --- a/src/any_value/lazy_clone.rs +++ b/src/any_value/lazy_clone.rs @@ -1,5 +1,5 @@ use std::any::TypeId; -use crate::any_value::{AnyValue, AnyValueCloneable}; +use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueUnknown}; /// Makes [`AnyValueCloneable`] actually [`Clone`]able. /// Do clone on consumption. @@ -20,14 +20,9 @@ impl<'a, T: AnyValueCloneable> LazyClone<'a, T>{ } } -impl<'a, T: AnyValueCloneable> AnyValue for LazyClone<'a, T>{ +impl<'a, T: AnyValueCloneable> AnyValueUnknown for LazyClone<'a, T>{ type Type = T::Type; - #[inline] - fn value_typeid(&self) -> TypeId { - self.value.value_typeid() - } - #[inline] fn as_bytes(&self) -> &[u8]{ self.value.as_bytes() @@ -39,6 +34,13 @@ impl<'a, T: AnyValueCloneable> AnyValue for LazyClone<'a, T>{ } } +impl<'a, T: AnyValueCloneable + AnyValue> AnyValue for LazyClone<'a, T>{ + #[inline] + fn value_typeid(&self) -> TypeId { + self.value.value_typeid() + } +} + impl<'a, T: AnyValueCloneable> AnyValueCloneable for LazyClone<'a, T>{ #[inline] unsafe fn clone_into(&self, out: *mut u8) { diff --git a/src/any_value/mod.rs b/src/any_value/mod.rs index 880f0a6..3ccbc80 100644 --- a/src/any_value/mod.rs +++ b/src/any_value/mod.rs @@ -4,7 +4,7 @@ mod lazy_clone; pub use lazy_clone::{LazyClone}; pub use wrapper::AnyValueWrapper; -pub use raw::AnyValueRaw; +pub use raw::{AnyValueRaw, AnyValueRawUnknown}; use std::any::TypeId; use std::{mem, ptr}; @@ -20,43 +20,24 @@ impl Unknown { } } -/// Type erased value interface. -pub trait AnyValue { +/// [`AnyValue`] that does not know it's compiletime or runtime type. +pub trait AnyValueUnknown { /// Concrete type, or [`Unknown`] + /// + /// N.B. This should be in `AnyValue`. It is here due to ergonomic reasons, + /// since Rust does not have impl specialization. type Type: 'static /*= Unknown*/; - fn value_typeid(&self) -> TypeId; - /// Aligned. fn as_bytes(&self) -> &[u8]; #[inline] - fn downcast_ref(&self) -> Option<&T>{ - if self.value_typeid() != TypeId::of::(){ - None - } else { - Some(unsafe{ self.downcast_ref_unchecked::() }) - } - } - - #[inline] - unsafe fn downcast_ref_unchecked(&self) -> &T{ + unsafe fn downcast_ref_unchecked(&self) -> &T{ &*(self.as_bytes().as_ptr() as *const T) } #[inline] - fn downcast(self) -> Option - where Self: Sized - { - if self.value_typeid() != TypeId::of::(){ - None - } else { - Some(unsafe{ self.downcast_unchecked::() }) - } - } - - #[inline] - unsafe fn downcast_unchecked(self) -> T + unsafe fn downcast_unchecked(self) -> T where Self: Sized { let mut tmp = MaybeUninit::::uninit(); @@ -79,9 +60,34 @@ pub trait AnyValue { } } +/// Type erased value interface. +pub trait AnyValue: AnyValueUnknown { + fn value_typeid(&self) -> TypeId; + + #[inline] + fn downcast_ref(&self) -> Option<&T>{ + if self.value_typeid() != TypeId::of::(){ + None + } else { + Some(unsafe{ self.downcast_ref_unchecked::() }) + } + } + + #[inline] + fn downcast(self) -> Option + where Self: Sized + { + if self.value_typeid() != TypeId::of::(){ + None + } else { + Some(unsafe{ self.downcast_unchecked::() }) + } + } +} + /// Helper function, which utilize type knowledge. #[inline] -pub(crate) unsafe fn copy_bytes(any_value: &T, out: *mut u8){ +pub(crate) unsafe fn copy_bytes(any_value: &T, out: *mut u8){ if !Unknown::is::() { ptr::copy_nonoverlapping( any_value.as_bytes().as_ptr() as *const T::Type, @@ -96,35 +102,18 @@ pub(crate) unsafe fn copy_bytes(any_value: &T, out: *mut u8){ } } -/// Type erased mutable value interface. -pub trait AnyValueMut: AnyValue{ - +/// [`AnyValueMut`] that does not know it's compiletime or runtime type. +pub trait AnyValueMutUnknown: AnyValueUnknown { fn as_bytes_mut(&mut self) -> &mut [u8]; #[inline] - fn downcast_mut(&mut self) -> Option<&mut T>{ - if self.value_typeid() != TypeId::of::(){ - None - } else { - Some(unsafe{ self.downcast_mut_unchecked::() }) - } - } - - #[inline] - unsafe fn downcast_mut_unchecked(&mut self) -> &mut T{ + unsafe fn downcast_mut_unchecked(&mut self) -> &mut T{ &mut *(self.as_bytes_mut().as_mut_ptr() as *mut T) } - /// Swaps underlying values. - /// - /// # Panic - /// - /// Panics, if type mismatch. #[inline] - fn swap(&mut self, other: &mut Other){ - assert_eq!(self.value_typeid(), other.value_typeid()); - - unsafe{ + unsafe fn swap_unchecked(&mut self, other: &mut Other){ + // compile-time check if !Unknown::is::() { mem::swap( self.downcast_mut_unchecked::(), @@ -143,12 +132,36 @@ pub trait AnyValueMut: AnyValue{ bytes.len() ); } - } // unsafe } } -/// [`LazyClone`] friendly [`AnyValue`]. -pub trait AnyValueCloneable: AnyValue { +/// Type erased mutable value interface. +pub trait AnyValueMut: AnyValueMutUnknown + AnyValue{ + #[inline] + fn downcast_mut(&mut self) -> Option<&mut T>{ + if self.value_typeid() != TypeId::of::(){ + None + } else { + Some(unsafe{ self.downcast_mut_unchecked::() }) + } + } + + /// Swaps underlying values. + /// + /// # Panic + /// + /// Panics, if type mismatch. + #[inline] + fn swap(&mut self, other: &mut Other){ + assert_eq!(self.value_typeid(), other.value_typeid()); + unsafe{ + self.swap_unchecked(other); + } + } +} + +/// [`LazyClone`] friendly [`AnyValueUnknown`]. +pub trait AnyValueCloneable: AnyValueUnknown { unsafe fn clone_into(&self, out: *mut u8); #[inline] diff --git a/src/any_value/raw.rs b/src/any_value/raw.rs index 4a9e31f..4c33362 100644 --- a/src/any_value/raw.rs +++ b/src/any_value/raw.rs @@ -1,9 +1,44 @@ use std::any::TypeId; use std::ptr::NonNull; use std::slice; -use crate::any_value::{AnyValue, AnyValueMut}; +use crate::any_value::{AnyValue, AnyValueMut, AnyValueMutUnknown, AnyValueUnknown}; use crate::any_value::Unknown; + +/// [`AnyValueRaw`] that does not know it's type. +pub struct AnyValueRawUnknown { + ptr: NonNull, + size: usize, +} + +impl AnyValueRawUnknown { + #[inline] + pub unsafe fn new(ptr: NonNull, size: usize) -> Self{ + Self{ptr, size} + } +} +impl AnyValueUnknown for AnyValueRawUnknown { + type Type = Unknown; + + #[inline] + fn as_bytes(&self) -> &[u8]{ + unsafe{slice::from_raw_parts( + self.ptr.as_ptr(), + self.size + )} + } +} +impl AnyValueMutUnknown for AnyValueRawUnknown { + #[inline] + fn as_bytes_mut(&mut self) -> &mut [u8] { + unsafe{slice::from_raw_parts_mut( + self.ptr.as_ptr(), + self.size + )} + } +} + + /// Non owning byte ptr wrapper. /// Source should be forgotten. /// @@ -27,41 +62,40 @@ use crate::any_value::Unknown; /// any_vec.push(raw_value); /// ``` pub struct AnyValueRaw{ - ptr: NonNull, - size: usize, + raw_unsafe: AnyValueRawUnknown, typeid: TypeId } impl AnyValueRaw{ #[inline] pub unsafe fn new(ptr: NonNull, size: usize, typeid: TypeId) -> Self{ - Self{ptr, size, typeid} + Self{ + raw_unsafe: AnyValueRawUnknown::new(ptr, size), + typeid + } } } - -impl AnyValue for AnyValueRaw{ +impl AnyValueUnknown for AnyValueRaw{ type Type = Unknown; #[inline] - fn value_typeid(&self) -> TypeId { - self.typeid + fn as_bytes(&self) -> &[u8]{ + self.raw_unsafe.as_bytes() } - +} +impl AnyValue for AnyValueRaw{ #[inline] - fn as_bytes(&self) -> &[u8]{ - unsafe{slice::from_raw_parts( - self.ptr.as_ptr(), - self.size - )} + fn value_typeid(&self) -> TypeId { + self.typeid } } - -impl AnyValueMut for AnyValueRaw{ +impl AnyValueMutUnknown for AnyValueRaw{ #[inline] fn as_bytes_mut(&mut self) -> &mut [u8] { unsafe{slice::from_raw_parts_mut( - self.ptr.as_ptr(), - self.size + self.raw_unsafe.ptr.as_ptr(), + self.raw_unsafe.size )} } -} \ No newline at end of file +} +impl AnyValueMut for AnyValueRaw{} \ No newline at end of file diff --git a/src/any_value/wrapper.rs b/src/any_value/wrapper.rs index fec3bd1..cd6b7ea 100644 --- a/src/any_value/wrapper.rs +++ b/src/any_value/wrapper.rs @@ -1,7 +1,7 @@ use std::any::TypeId; use std::mem::{ManuallyDrop, size_of}; use std::{ptr, slice}; -use crate::any_value::{AnyValue, AnyValueMut}; +use crate::any_value::{AnyValue, AnyValueMut, AnyValueMutUnknown, AnyValueUnknown}; /// Helper struct to convert concrete type to [`AnyValue`]. pub struct AnyValueWrapper{ @@ -13,14 +13,9 @@ impl AnyValueWrapper { Self{ value } } } -impl AnyValue for AnyValueWrapper { +impl AnyValueUnknown for AnyValueWrapper { type Type = T; - #[inline] - fn value_typeid(&self) -> TypeId { - TypeId::of::() - } - #[inline] fn as_bytes(&self) -> &[u8]{ unsafe{slice::from_raw_parts( @@ -30,14 +25,20 @@ impl AnyValue for AnyValueWrapper { } #[inline] - unsafe fn downcast_unchecked(self) -> U { + unsafe fn downcast_unchecked(self) -> U { // rust don't see that types are the same after assert. let value = ManuallyDrop::new(self.value); let ptr = &*value as *const T as *const U; ptr::read(ptr) } } -impl AnyValueMut for AnyValueWrapper { +impl AnyValue for AnyValueWrapper { + #[inline] + fn value_typeid(&self) -> TypeId { + TypeId::of::() + } +} +impl AnyValueMutUnknown for AnyValueWrapper { #[inline] fn as_bytes_mut(&mut self) -> &mut [u8] { unsafe{slice::from_raw_parts_mut( @@ -45,4 +46,5 @@ impl AnyValueMut for AnyValueWrapper { size_of::() )} } -} \ No newline at end of file +} +impl AnyValueMut for AnyValueWrapper {} \ No newline at end of file diff --git a/src/any_vec.rs b/src/any_vec.rs index e9d6c9c..0b6d42b 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -8,7 +8,7 @@ use std::ptr::NonNull; use std::{ptr, slice}; use std::slice::{from_raw_parts, from_raw_parts_mut}; use crate::{AnyVecTyped, into_range, mem, ops}; -use crate::any_value::{AnyValue}; +use crate::any_value::{AnyValue, AnyValueUnknown}; use crate::any_vec_raw::{AnyVecRaw, DropFn}; use crate::ops::{TempValue, Remove, SwapRemove, remove, swap_remove, Pop, pop}; use crate::ops::{Drain, Splice, drain, splice}; @@ -567,6 +567,23 @@ impl AnyVec } } + /// Same as [`insert`], but without type checks. + /// + /// # Panics + /// + /// * Panics if index is out of bounds. + /// * Panics if out of memory. + /// + /// # Safety + /// + /// Type not checked. + /// + /// [`insert`]: Self::insert + #[inline] + pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { + self.raw.insert_unchecked(index, value); + } + /// # Panics /// /// * Panics if type mismatch. @@ -579,6 +596,22 @@ impl AnyVec } } + /// Same as [`push`], but without type checks. + /// + /// # Panics + /// + /// Panics if out of memory. + /// + /// # Safety + /// + /// Type not checked. + /// + /// [`push`]: Self::push + #[inline] + pub unsafe fn push_unchecked(&mut self, value: V) { + self.raw.push_unchecked(value); + } + /// # Leaking /// /// If the returned [`TempValue`] goes out of scope without being dropped (due to @@ -599,7 +632,7 @@ impl AnyVec /// # Panics /// - /// * Panics if index out of bounds. + /// Panics if index out of bounds. /// /// # Leaking /// @@ -620,7 +653,7 @@ impl AnyVec /// # Panics /// - /// * Panics if index out of bounds. + /// Panics if index out of bounds. /// /// # Leaking /// diff --git a/src/any_vec_ptr.rs b/src/any_vec_ptr.rs index 001b990..63caaae 100644 --- a/src/any_vec_ptr.rs +++ b/src/any_vec_ptr.rs @@ -122,12 +122,24 @@ impl IAnyVecPtr for AnyVecPtr /// All unsafe, because dereferencing pointer is unsafe. pub(crate) mod utils{ use std::{mem, ptr}; + use std::any::TypeId; use std::mem::size_of; use std::ptr::NonNull; use crate::any_value::Unknown; use crate::any_vec_ptr::IAnyVecRawPtr; use crate::AnyVecTyped; + #[inline] + pub unsafe fn element_typeid(any_vec_ptr: AnyVecPtr) -> TypeId + { + if Unknown::is::(){ + let any_vec_raw = any_vec_ptr.any_vec_raw(); + any_vec_raw.type_id + } else { + TypeId::of::() + } + } + #[inline] pub unsafe fn element_size(any_vec_ptr: AnyVecPtr) -> usize { diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index dde21de..a926b78 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -1,7 +1,8 @@ use std::{cmp, mem, ptr}; use std::alloc::Layout; use std::any::TypeId; -use crate::any_value::{AnyValue, Unknown}; +use crate::any_value::{AnyValue, AnyValueUnknown, Unknown}; +use crate::assert_types_equal; use crate::clone_type::CloneFn; use crate::mem::{Mem, MemBuilder, MemResizable}; @@ -83,7 +84,7 @@ impl AnyVecRaw { #[inline] pub(crate) fn type_check(&self, value: &V){ - assert_eq!(value.value_typeid(), self.type_id, "Type mismatch!"); + assert_types_equal(value.value_typeid(), self.type_id); } #[inline] @@ -152,7 +153,7 @@ impl AnyVecRaw { /// # Safety /// /// Type is not checked. - pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { + pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { assert!(index <= self.len, "Index out of range!"); self.reserve_one(); @@ -192,7 +193,7 @@ impl AnyVecRaw { /// /// Type is not checked. #[inline] - pub unsafe fn push_unchecked(&mut self, value: V) { + pub unsafe fn push_unchecked(&mut self, value: V) { self.reserve_one(); // Compile time type optimization diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index d39529a..28217be 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -4,7 +4,7 @@ use std::mem::MaybeUninit; use std::ops::{Range, RangeBounds}; use std::ptr::NonNull; use std::slice; -use crate::any_value::{AnyValue, AnyValueWrapper}; +use crate::any_value::{AnyValueUnknown, AnyValueWrapper}; use crate::any_vec_raw::AnyVecRaw; use crate::ops::{Iter, pop, remove, swap_remove, TempValue}; use crate::any_vec_ptr::AnyVecRawPtr; diff --git a/src/element.rs b/src/element.rs index 45cd310..d80c49a 100644 --- a/src/element.rs +++ b/src/element.rs @@ -4,7 +4,7 @@ use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; use std::slice; -use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut}; +use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueMutUnknown, AnyValueUnknown}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{AnyVecPtr, IAnyVecPtr, IAnyVecRawPtr}; use crate::{AnyVec, mem}; @@ -89,14 +89,9 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Drop for ElementPointer<'a, AnyVecPtr>{ } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValue for ElementPointer<'a, AnyVecPtr>{ +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueUnknown for ElementPointer<'a, AnyVecPtr>{ type Type = AnyVecPtr::Element; - #[inline] - fn value_typeid(&self) -> TypeId { - self.any_vec_raw().type_id - } - #[inline] fn as_bytes(&self) -> &[u8]{ unsafe{slice::from_raw_parts( @@ -105,8 +100,14 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValue for ElementPointer<'a, AnyVecPtr>{ )} } } +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValue for ElementPointer<'a, AnyVecPtr>{ + #[inline] + fn value_typeid(&self) -> TypeId { + self.any_vec_raw().type_id + } +} -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMut for ElementPointer<'a, AnyVecPtr>{ +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMutUnknown for ElementPointer<'a, AnyVecPtr>{ #[inline] fn as_bytes_mut(&mut self) -> &mut [u8] { unsafe{slice::from_raw_parts_mut( @@ -115,6 +116,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMut for ElementPointer<'a, AnyVecPtr> )} } } +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMut for ElementPointer<'a, AnyVecPtr>{} impl<'a, Traits: ?Sized + Cloneable + Trait, M: MemBuilder> AnyValueCloneable for ElementPointer<'a, AnyVecPtr> diff --git a/src/lib.rs b/src/lib.rs index 3bc8a3a..a5b1609 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,6 +144,7 @@ mod any_vec_raw; mod any_vec_typed; mod iter; +use std::any::TypeId; pub use crate::any_vec::{AnyVec, AnyVecMut, AnyVecRef, SatisfyTraits, traits, RawParts}; pub use any_vec_typed::AnyVecTyped; pub use iter::{ElementIterator, Iter, IterRef, IterMut}; @@ -238,3 +239,8 @@ fn into_range( assert!(end <= len); start..end } + +#[inline] +fn assert_types_equal(t1: TypeId, t2: TypeId){ + assert_eq!(t1, t2, "Type mismatch!"); +} diff --git a/src/ops/splice.rs b/src/ops/splice.rs index 466bae8..f6cab2b 100644 --- a/src/ops/splice.rs +++ b/src/ops/splice.rs @@ -1,6 +1,6 @@ use crate::any_vec_ptr::IAnyVecRawPtr; -use crate::{any_vec_ptr, Iter}; -use crate::any_value::AnyValue; +use crate::{any_vec_ptr, assert_types_equal, Iter}; +use crate::any_value::{AnyValueUnknown, AnyValue}; use crate::ops::iter::Iterable; pub struct Splice<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> @@ -100,9 +100,11 @@ where // 3. move replace_with in unsafe{ + let type_id = element_typeid(any_vec_ptr); let element_size = element_size(any_vec_ptr); let mut ptr = element_mut_ptr_at(any_vec_ptr, self.start); while let Some(replace_element) = self.replace_with.next() { + assert_types_equal(type_id, replace_element.value_typeid()); replace_element.move_into(ptr); ptr = ptr.add(element_size); } diff --git a/src/ops/temp.rs b/src/ops/temp.rs index 79dd4d7..db33a7b 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -1,6 +1,6 @@ use std::any::TypeId; use std::{mem, ptr, slice}; -use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, copy_bytes, Unknown}; +use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueMutUnknown, AnyValueUnknown, copy_bytes, Unknown}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{IAnyVecPtr, IAnyVecRawPtr}; use crate::AnyVec; @@ -48,19 +48,9 @@ impl TempValue{ } } -impl AnyValue for TempValue{ +impl AnyValueUnknown for TempValue{ type Type = ::Element; - #[inline] - fn value_typeid(&self) -> TypeId { - let typeid = TypeId::of::(); - if typeid == TypeId::of::(){ - self.any_vec_raw().type_id - } else { - typeid - } - } - #[inline] fn as_bytes(&self) -> &[u8]{ unsafe{slice::from_raw_parts( @@ -76,8 +66,19 @@ impl AnyValue for TempValue{ mem::forget(self); } } +impl AnyValue for TempValue{ + #[inline] + fn value_typeid(&self) -> TypeId { + let typeid = TypeId::of::(); + if typeid == TypeId::of::(){ + self.any_vec_raw().type_id + } else { + typeid + } + } +} -impl AnyValueMut for TempValue { +impl AnyValueMutUnknown for TempValue { #[inline] fn as_bytes_mut(&mut self) -> &mut [u8] { unsafe{slice::from_raw_parts_mut( @@ -86,6 +87,7 @@ impl AnyValueMut for TempValue { )} } } +impl AnyValueMut for TempValue {} impl AnyValueCloneable for TempValue where @@ -107,12 +109,12 @@ impl Drop for TempValue{ let element = self.op.bytes() as *mut u8; // compile-time check - if Unknown::is::<::Type>() { + if Unknown::is::<::Type>() { if let Some(drop_fn) = drop_fn{ (drop_fn)(element, 1); } } else { - ptr::drop_in_place(element as *mut ::Type); + ptr::drop_in_place(element as *mut ::Type); } } self.op.consume(); From a0480d93c432232e9b64e932206d9ae8e7907089 Mon Sep 17 00:00:00 2001 From: tower120 Date: Fri, 15 Jul 2022 16:57:58 +0300 Subject: [PATCH 17/35] mem::Empty added --- CHANGELOG.md | 1 + src/any_vec.rs | 2 +- src/mem/empty.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/mem/heap.rs | 16 ++-------------- src/mem/mod.rs | 15 +++++++++++++++ src/mem/stack.rs | 2 +- src/mem/stack_n.rs | 2 +- 7 files changed, 65 insertions(+), 17 deletions(-) create mode 100644 src/mem/empty.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c3ef374..971d221 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - `AnyVec::push_unchecked(AnyValueUnknown)`. - `AnyVec::insert_unchecked(usize, AnyValueUnknown)`. - `AnyValueRawUnknown`. +- `mem::Empty`. #### Raw parts - `AnyVec::into_raw_parts` / `AnyVec::from_raw_parts` / `RawParts`. diff --git a/src/any_vec.rs b/src/any_vec.rs index 0b6d42b..a2977ce 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -92,7 +92,7 @@ impl SatisfyTraits for T{} /// You can get it with [`AnyVec::into_raw_parts`], or build/edit /// it manually. And with [`AnyVec::from_raw_parts`], you can construct /// [`AnyVec`]. -pub struct RawParts +pub struct RawParts where M::Mem: MemRawParts { diff --git a/src/mem/empty.rs b/src/mem/empty.rs new file mode 100644 index 0000000..b1b2b2e --- /dev/null +++ b/src/mem/empty.rs @@ -0,0 +1,44 @@ +use std::alloc::Layout; +use crate::mem::{dangling, Mem, MemBuilder}; + +/// Zero-size memory. +/// +/// Contain only element Layout. This can be useful for constructing [`RawParts`] with zero overhead. +/// +/// [`RawParts`]: crate::RawParts +#[derive(Default, Clone, Copy)] +pub struct Empty; +impl MemBuilder for Empty{ + type Mem = EmptyMem; + + #[inline] + fn build(&mut self, element_layout: Layout) -> Self::Mem { + EmptyMem { element_layout } + } +} + +pub struct EmptyMem{ + element_layout: Layout +} + +impl Mem for EmptyMem{ + #[inline] + fn as_ptr(&self) -> *const u8 { + dangling(&self.element_layout).as_ptr() + } + + #[inline] + fn as_mut_ptr(&mut self) -> *mut u8 { + dangling(&self.element_layout).as_ptr() + } + + #[inline] + fn element_layout(&self) -> Layout { + self.element_layout + } + + #[inline] + fn size(&self) -> usize { + 0 + } +} \ No newline at end of file diff --git a/src/mem/heap.rs b/src/mem/heap.rs index bb709f0..32940cc 100644 --- a/src/mem/heap.rs +++ b/src/mem/heap.rs @@ -2,22 +2,10 @@ use std::alloc::{alloc, dealloc, handle_alloc_error, Layout, realloc}; use std::cmp; use std::mem::ManuallyDrop; use std::ptr::NonNull; -use crate::mem::{Mem, MemBuilder, MemBuilderSizeable, MemRawParts, MemResizable}; - -#[inline] -fn dangling(layout: &Layout) -> NonNull{ - #[cfg(miri)] - { - layout.dangling() - } - #[cfg(not(miri))] - { - unsafe { NonNull::new_unchecked(layout.align() as *mut u8) } - } -} +use crate::mem::{dangling, Mem, MemBuilder, MemBuilderSizeable, MemRawParts, MemResizable}; /// Heap allocated memory. -#[derive(Default, Clone)] +#[derive(Default, Clone, Copy)] pub struct Heap; impl MemBuilder for Heap { type Mem = HeapMem; diff --git a/src/mem/mod.rs b/src/mem/mod.rs index d75d7b2..df2e614 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -1,14 +1,17 @@ mod heap; mod stack; mod stack_n; +mod empty; pub use heap::Heap; pub use stack::Stack; pub use stack_n::StackN; +pub use empty::Empty; pub(crate) type Default = Heap; use std::alloc::Layout; +use std::ptr::NonNull; /// This is [`Mem`] builder. /// @@ -99,4 +102,16 @@ pub trait MemRawParts: Mem{ fn into_raw_parts(self) -> (Self::Handle, Layout, usize); unsafe fn from_raw_parts(handle: Self::Handle, element_layout: Layout, size: usize) -> Self; +} + +#[inline] +const fn dangling(layout: &Layout) -> NonNull{ + #[cfg(miri)] + { + layout.dangling() + } + #[cfg(not(miri))] + { + unsafe { NonNull::new_unchecked(layout.align() as *mut u8) } + } } \ No newline at end of file diff --git a/src/mem/stack.rs b/src/mem/stack.rs index f1047d3..57b4e83 100644 --- a/src/mem/stack.rs +++ b/src/mem/stack.rs @@ -10,7 +10,7 @@ use crate::mem::{Mem, MemBuilder}; /// for intermediate storage instead. /// /// [`StackN`]: super::StackN -#[derive(Default, Clone)] +#[derive(Default, Clone, Copy)] pub struct Stack; impl MemBuilder for Stack{ type Mem = StackMem; diff --git a/src/mem/stack_n.rs b/src/mem/stack_n.rs index 5825c06..fd4a4b3 100644 --- a/src/mem/stack_n.rs +++ b/src/mem/stack_n.rs @@ -11,7 +11,7 @@ use crate::mem::{Mem, MemBuilder}; /// still can't do `N * ELEMENT_SIZE` in generic context. /// /// [`Stack`]: super::Stack -#[derive(Default, Clone)] +#[derive(Default, Clone, Copy)] pub struct StackN; impl MemBuilder for StackN{ type Mem = StackNMem; From 75e6ad1e482f02864a5e7f4315e000f9c7e76ac8 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 15 Jul 2022 17:11:27 +0300 Subject: [PATCH 18/35] MemBuilder impl MemRawParts --- src/mem/empty.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/mem/empty.rs b/src/mem/empty.rs index b1b2b2e..da6a995 100644 --- a/src/mem/empty.rs +++ b/src/mem/empty.rs @@ -1,5 +1,5 @@ use std::alloc::Layout; -use crate::mem::{dangling, Mem, MemBuilder}; +use crate::mem::{dangling, Mem, MemBuilder, MemRawParts}; /// Zero-size memory. /// @@ -41,4 +41,22 @@ impl Mem for EmptyMem{ fn size(&self) -> usize { 0 } +} + +impl MemRawParts for EmptyMem{ + type Handle = (); + + #[inline] + fn into_raw_parts(self) -> (Self::Handle, Layout, usize) { + ((), self.element_layout, 0) + } + + /// `size` must be 0. + #[inline] + unsafe fn from_raw_parts(_: Self::Handle, element_layout: Layout, size: usize) -> Self { + debug_assert!(size == 0); + Self{ + element_layout + } + } } \ No newline at end of file From acc4072e7034db9691d7a11577c915eb3a2a8bf3 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 26 Aug 2022 18:21:36 +0300 Subject: [PATCH 19/35] description addde --- src/mem/empty.rs | 1 + src/mem/heap.rs | 1 + src/mem/mod.rs | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/src/mem/empty.rs b/src/mem/empty.rs index da6a995..72e0883 100644 --- a/src/mem/empty.rs +++ b/src/mem/empty.rs @@ -9,6 +9,7 @@ use crate::mem::{dangling, Mem, MemBuilder, MemRawParts}; #[derive(Default, Clone, Copy)] pub struct Empty; impl MemBuilder for Empty{ + /// Implements [`MemRawParts`]. type Mem = EmptyMem; #[inline] diff --git a/src/mem/heap.rs b/src/mem/heap.rs index 32940cc..b0efad4 100644 --- a/src/mem/heap.rs +++ b/src/mem/heap.rs @@ -8,6 +8,7 @@ use crate::mem::{dangling, Mem, MemBuilder, MemBuilderSizeable, MemRawParts, Mem #[derive(Default, Clone, Copy)] pub struct Heap; impl MemBuilder for Heap { + /// Implements [`MemResizable`], [`MemRawParts`]. type Mem = HeapMem; #[inline] diff --git a/src/mem/mod.rs b/src/mem/mod.rs index df2e614..b6dce4e 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -77,6 +77,8 @@ pub trait Mem{ } /// Resizable [`Mem`]. +/// +/// Implemented by [`Heap::Mem`]. pub trait MemResizable: Mem{ /// Expand `Mem` size for **exactly** `additional` more elements. /// Implementation encouraged to be as precise as possible with new memory size. @@ -97,6 +99,8 @@ pub trait MemResizable: Mem{ } /// [`Mem`] destructurable into raw parts. +/// +/// Implemented by [`Heap::Mem`], [`Empty::Mem`]. pub trait MemRawParts: Mem{ type Handle; From d651e0466c920291333650ec562256cbfd7d52e7 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 26 Aug 2022 18:29:25 +0300 Subject: [PATCH 20/35] v0.11.0 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 971d221..a99eb9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## 0.11.0 ### Added #### `AnyValueUnknown` - `AnyValue` split into `AnyValueUnknown` + `AnyValue`. diff --git a/Cargo.toml b/Cargo.toml index 74c48ee..043971b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "any_vec" authors = ["Andrey Diduh "] license = "MIT OR Apache-2.0" -version = "0.10.0" +version = "0.11.0" edition = "2021" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." repository = "https://github.com/tower120/any_vec" From fffdeb80a224d819387d345d12b951925221a7e8 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 26 May 2023 15:45:20 +0300 Subject: [PATCH 21/35] AnyValueRaw description update --- src/any_value/raw.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/any_value/raw.rs b/src/any_value/raw.rs index 4c33362..571eb8e 100644 --- a/src/any_value/raw.rs +++ b/src/any_value/raw.rs @@ -41,6 +41,11 @@ impl AnyValueMutUnknown for AnyValueRawUnknown { /// Non owning byte ptr wrapper. /// Source should be forgotten. +/// Drop for wrapped type will not be called on AnyValueRaw drop. +/// +/// This is useful to fill AnyVec directly from raw bytes, +/// without intermediate casting to concrete type. +/// (You only need runtime data - size and typeid) /// /// # Example /// ```rust From 6f746bf2bee36ef17d515ca546f1107ab9b95ec4 Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 10 Jun 2023 10:21:20 +0300 Subject: [PATCH 22/35] new rust version warnings fix --- benches/drain.rs | 2 +- src/mem/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/benches/drain.rs b/benches/drain.rs index aae7695..3100974 100644 --- a/benches/drain.rs +++ b/benches/drain.rs @@ -49,7 +49,7 @@ fn any_vec_typed_drain() -> Duration { let start = Instant::now(); while any_vec.len() >= DRAIN_SIZE { - any_vec.downcast_mut::().unwrap() + let _ = any_vec.downcast_mut::().unwrap() .drain(0..DRAIN_SIZE); } start.elapsed() diff --git a/src/mem/mod.rs b/src/mem/mod.rs index b6dce4e..6f47efb 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -67,7 +67,7 @@ pub trait Mem{ /// /// Implementation may panic, if fail to allocate/reallocate memory. fn expand(&mut self, additional: usize){ - drop(additional); + let _ = additional; panic!("Can't change capacity!"); /*let requested_size = self.size() + additional; From d80d070a698a845d7a52452b73e9e7739fdaaf18 Mon Sep 17 00:00:00 2001 From: tower120 Date: Sat, 10 Jun 2023 14:43:03 +0300 Subject: [PATCH 23/35] Small refactor --- CHANGELOG.md | 10 ++++++++++ src/any_value/raw.rs | 7 ++++--- src/any_vec.rs | 7 +++++-- src/any_vec_typed.rs | 4 +--- src/element.rs | 42 ++++++++++++++++++++++++++++++---------- src/lib.rs | 2 +- src/ops/mod.rs | 4 ++-- tests/any_vec_element.rs | 9 +++------ 8 files changed, 58 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a99eb9a..851e6f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 0.12.0 +### Added +- `element::ElementReference` trait, implemented both for `ElementRef` and `ElementMut`. + +### Changed +- Documentation clarification. + +### Fixed +- Minor changes, to eliminate warnings with new compiler version. + ## 0.11.0 ### Added #### `AnyValueUnknown` diff --git a/src/any_value/raw.rs b/src/any_value/raw.rs index 571eb8e..44a07eb 100644 --- a/src/any_value/raw.rs +++ b/src/any_value/raw.rs @@ -39,9 +39,10 @@ impl AnyValueMutUnknown for AnyValueRawUnknown { } -/// Non owning byte ptr wrapper. -/// Source should be forgotten. -/// Drop for wrapped type will not be called on AnyValueRaw drop. +/// Non owning byte ptr wrapper for feeding AnyVec. +/// +/// Source should be forgotten, before pushing to AnyVec. +/// Contained value will not be dropped on AnyValueRaw drop. /// /// This is useful to fill AnyVec directly from raw bytes, /// without intermediate casting to concrete type. diff --git a/src/any_vec.rs b/src/any_vec.rs index a2977ce..191910c 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -32,7 +32,10 @@ use crate::traits::{Cloneable, Trait}; /// /// ``` pub mod traits{ - /// Marker trait, for traits accepted by AnyVec. + // TODO: rename to TraitConstraints or Constraints? + /// [`AnyVec`]s trait constraints. + /// + /// [`AnyVec`]: crate::AnyVec pub trait Trait: 'static + crate::clone_type::CloneType{} impl Trait for dyn None {} impl Trait for dyn Sync{} @@ -139,7 +142,7 @@ where /// Some operations return [`TempValue`], which internally holds &mut to [`AnyVec`]. /// You can drop it, cast to concrete type, or put into another vector. (See [`AnyValue`]) /// -/// *`Element: 'static` due to TypeId requirements* +/// *`T: 'static` due to TypeId requirements* pub struct AnyVec { pub(crate) raw: AnyVecRaw, diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index 28217be..7cacd35 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -16,9 +16,7 @@ use crate::ops::splice::Splice; /// Concrete type [`AnyVec`] representation. /// -/// Created with [`AnyVec::downcast_`]-family. -/// Accessed through [`AnyVecRef`] or [`AnyVecMut`]. -/// See [`AnyVec`] for documentation. +/// Obtained by dereferencing [`AnyVecRef`] or [`AnyVecMut`]. /// /// Operations with concrete type are somewhat faster, due to /// the fact, that compiler are able to optimize harder with full diff --git a/src/element.rs b/src/element.rs index d80c49a..fbac007 100644 --- a/src/element.rs +++ b/src/element.rs @@ -11,21 +11,29 @@ use crate::{AnyVec, mem}; use crate::mem::MemBuilder; use crate::traits::{Cloneable, None, Trait}; -// Typed operations will never use type-erased Element, so there is no +// Typed operations will never use type-erased ElementPointer, so there is no // need in type-known-based optimizations. -/// Owning pointer to [`AnyVec`] element. +/// Owning pointer to type-erased [`AnyVec`] element. /// -/// This is public, just so you can see what [`Element`] can do. +/// Obtained by dereferencing [`ElementRef`], [`ElementMut`] or from some +/// destructive [`AnyVec`] operations, like [`drain`] or [`splice`]. +/// +/// # Consuming +/// +/// Whenever you have `ElementPointer` as a value (from destructive [`AnyVec`] operations), +/// you can safely take pointed value, with [`AnyValue::downcast`] or [`AnyValueUnknown::move_into`]. +/// Otherwise, it will be destructed with destruction of `Element`. /// /// # Notes /// -/// `Element` have it's own implementation of `downcast_` family (which return `&'a T`, instead of `&T`). -/// This is done, so you don't have to keep ElementRef/Mut alive, while casting to concrete type. -/// [`AnyValueMut`] implemented too - for the sake of interface compatibility. +/// `ElementPointer` have it's own implementation of `downcast_` family (which return `&'a T`, instead of `&T`). +/// This is done, so you don't have to keep `ElementRef`/`ElementMut` alive, while casting to concrete type. /// /// [`AnyVec`]: crate::AnyVec /// [`AnyVec::get`]: crate::AnyVec::get +/// [`drain`]: crate::AnyVec::drain +/// [`splice`]: crate::AnyVec::splice pub struct ElementPointer<'a, AnyVecPtr: IAnyVecRawPtr>{ any_vec_ptr: AnyVecPtr, element: NonNull, @@ -49,6 +57,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ unsafe { self.any_vec_ptr.any_vec_raw() } } + /// Same as [`AnyValue::downcast_ref`], but return `&'a T`, instead of `&T`. #[inline] pub fn downcast_ref(&self) -> Option<&'a T>{ if self.value_typeid() != TypeId::of::(){ @@ -58,11 +67,13 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ } } + /// Same as [`AnyValueUnknown::downcast_ref_unchecked`], but return `&'a T`, instead of `&T`. #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &'a T{ &*(self.as_bytes().as_ptr() as *const T) } + /// Same as [`AnyValueMut::downcast_mut`], but return `&'a mut T`, instead of `&mut T`. #[inline] pub fn downcast_mut(&mut self) -> Option<&'a mut T>{ if self.value_typeid() != TypeId::of::(){ @@ -72,6 +83,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ } } + /// Same as [`AnyValueMutUnknown::downcast_mut_unchecked`], but return `&'a mut T`, instead of `&mut T`. #[inline] pub unsafe fn downcast_mut_unchecked(&mut self) -> &'a mut T{ &mut *(self.as_bytes_mut().as_mut_ptr() as *mut T) @@ -147,18 +159,27 @@ where /// [`AnyVec`] element. /// +/// See [`ElementPointer`]. +/// /// [`AnyVec`]: crate::AnyVec pub type Element<'a, Traits = dyn None, M = mem::Default> = ElementPointer<'a, AnyVecPtr>; +/// Reference to [`AnyVec`] element. +/// +/// Implemented by [`ElementRef`] and [`ElementMut`]. +pub trait ElementReference<'a, Traits: ?Sized + Trait = dyn None, M: MemBuilder + 'a = mem::Default> + : Deref > +{} -/// Reference to [`Element`]. +/// Reference to [`AnyVec`] element. /// /// Created by [`AnyVec::get`]. /// /// [`AnyVec::get`]: crate::AnyVec::get pub struct ElementRef<'a, Traits: ?Sized + Trait = dyn None, M: MemBuilder = mem::Default>( - pub(crate) ManuallyDrop>> + pub(crate) ManuallyDrop> ); +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> ElementReference<'a, Traits, M> for ElementRef<'a, Traits, M>{} impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Deref for ElementRef<'a, Traits, M>{ type Target = Element<'a, Traits, M>; @@ -174,14 +195,15 @@ impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Clone for ElementRef<'a, Traits, } } -/// Mutable reference to [`Element`]. +/// Mutable reference to [`AnyVec`] element. /// /// Created by [`AnyVec::get_mut`]. /// /// [`AnyVec::get_mut`]: crate::AnyVec::get_mut pub struct ElementMut<'a, Traits: ?Sized + Trait = dyn None, M: MemBuilder = mem::Default>( - pub(crate) ManuallyDrop>> + pub(crate) ManuallyDrop> ); +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> ElementReference<'a, Traits, M> for ElementMut<'a, Traits, M>{} impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Deref for ElementMut<'a, Traits, M>{ type Target = Element<'a, Traits, M>; diff --git a/src/lib.rs b/src/lib.rs index a5b1609..348388b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ //! Type erased vector [`AnyVec`]. Allow to store elements of the same type. //! Have same performance and *operations* as [`std::vec::Vec`]. //! -//! You can downcast type erased [`AnyVec`] to concrete [`AnyVecTyped`] with `downcast`-family. +//! You can downcast type erased [`AnyVec`] to concrete [`AnyVecTyped`] with `downcast`-family. //! Or use [`AnyVec`] type erased operations, which works with [`AnyValue`]. //! //! [`AnyValue`]: any_value::AnyValue diff --git a/src/ops/mod.rs b/src/ops/mod.rs index c01b623..e98ef04 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -32,7 +32,7 @@ pub type Remove<'a, Traits, M> = TempValue = TempValue>>; -/// A draining [`ElementIterator`] for [`AnyVec`]. Return [`Element`] items. +/// A draining [`ElementIterator`] for [`AnyVec`]. Return items as [`Element`]s. /// /// This is created by [`AnyVec::drain`]. /// @@ -42,7 +42,7 @@ pub type SwapRemove<'a, Traits, M> = TempValue = Iter>>; -/// A splicing [`ElementIterator`] for [`AnyVec`]. Return [`Element`] items. +/// A splicing [`ElementIterator`] for [`AnyVec`]. Return items as [`Element`]s. /// /// This is created by [`AnyVec::splice`]. /// diff --git a/tests/any_vec_element.rs b/tests/any_vec_element.rs index 0e4d379..de5c70b 100644 --- a/tests/any_vec_element.rs +++ b/tests/any_vec_element.rs @@ -1,10 +1,9 @@ use std::any::TypeId; -use std::ops::Deref; use itertools::{assert_equal}; use any_vec::any_value::{AnyValue, AnyValueCloneable, LazyClone}; use any_vec::AnyVec; -use any_vec::element::Element; -use any_vec::mem::Stack; +use any_vec::element::ElementReference; +use any_vec::mem::{MemBuilder, Stack}; use any_vec::traits::{Cloneable, Trait}; #[test] @@ -135,9 +134,7 @@ fn any_vec_iter_clone_test(){ vec.push(100); } - fn into_usize<'a, E, Traits: ?Sized + Trait>(e: E) -> &'a usize - where - E: Deref> + fn into_usize<'a, T: ?Sized + Trait, M: MemBuilder + 'a>(e: impl ElementReference<'a, T, M>) -> &'a usize { e.downcast_ref::().unwrap() } From 6291bd08ee0fb210f42b488e4a74c1704317ab56 Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 10 Jun 2023 15:00:14 +0300 Subject: [PATCH 24/35] ElementReference impl for ElementPointer --- CHANGELOG.md | 2 +- src/element.rs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 851e6f3..e8ddbe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 0.12.0 ### Added -- `element::ElementReference` trait, implemented both for `ElementRef` and `ElementMut`. +- `element::ElementReference` trait, implemented both for `ElementRef`, `ElementMut` and &`Element`. ### Changed - Documentation clarification. diff --git a/src/element.rs b/src/element.rs index fbac007..0ee2616 100644 --- a/src/element.rs +++ b/src/element.rs @@ -154,6 +154,11 @@ where AnyVec: Sync {} +impl<'a, Traits: ?Sized + Trait, M: MemBuilder> ElementReference<'a, Traits, M> + for &'a ElementPointer<'a, AnyVecPtr> +{} + + // Do not implement Send/Sync for AnyVecPtrRaw, since it will be casted to concrete type anyway. @@ -166,7 +171,7 @@ pub type Element<'a, Traits = dyn None, M = mem::Default> = ElementPointer<'a, A /// Reference to [`AnyVec`] element. /// -/// Implemented by [`ElementRef`] and [`ElementMut`]. +/// Implemented by [`ElementRef`], [`ElementMut`] and &[`Element`]. pub trait ElementReference<'a, Traits: ?Sized + Trait = dyn None, M: MemBuilder + 'a = mem::Default> : Deref > {} From 7f5901c7f0aa2f436bcb38f7fa2243b55e950b3b Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 10 Jun 2023 15:04:31 +0300 Subject: [PATCH 25/35] v0.12.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 043971b..bf693eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "any_vec" authors = ["Andrey Diduh "] license = "MIT OR Apache-2.0" -version = "0.11.0" +version = "0.12.0" edition = "2021" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." repository = "https://github.com/tower120/any_vec" From f44d9c226b553fb0e6d9ad3032a3e248a29a42e3 Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 10 Jun 2023 15:27:06 +0300 Subject: [PATCH 26/35] readme update --- Readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Readme.md b/Readme.md index 69c9d06..f5aa8be 100644 --- a/Readme.md +++ b/Readme.md @@ -50,6 +50,9 @@ let v2 = v1.clone(); // This will fail to compile. let v1: AnyVec = AnyVec::new::>(); ``` + +Non-Clonable `AnyVec` has a size 1 pointer smaller. + ## LazyClone Whenever possible, `any_vec` type erased elements can be lazily cloned: From d17e43f90d7c138d5022288050545c2715a4ea24 Mon Sep 17 00:00:00 2001 From: tower120 Date: Sun, 16 Jul 2023 01:23:10 +0300 Subject: [PATCH 27/35] any_value refactor w breaking changes --- CHANGELOG.md | 19 +++++ benches/element_clone.rs | 2 +- benches/insert.rs | 8 +- benches/push.rs | 20 ++++- src/any_value/lazy_clone.rs | 19 +++-- src/any_value/mod.rs | 138 +++++++++++++++++++++++-------- src/any_value/raw.rs | 158 ++++++++++++++++++++++-------------- src/any_value/wrapper.rs | 45 +++++----- src/any_vec.rs | 16 ++-- src/any_vec_ptr.rs | 1 + src/any_vec_raw.rs | 30 +++---- src/any_vec_typed.rs | 2 +- src/element.rs | 44 +++++----- src/lib.rs | 20 ++--- src/mem/mod.rs | 1 + src/ops/mod.rs | 6 ++ src/ops/splice.rs | 12 +-- src/ops/temp.rs | 48 +++++------ tests/any_value.rs | 11 ++- tests/any_vec.rs | 16 ++-- tests/any_vec_element.rs | 2 +- tests/any_vec_fuzzy.rs | 2 +- 22 files changed, 392 insertions(+), 228 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8ddbe3..bf16c76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 0.13.0 +### Added +- `AnyVec` now can work with `AnyValuePtr`. + +### Optimized +- `AnyValue`- family downcast now use provided type for compile-time optimization, +instead of potentially unknown underlying type (which disabled optimization technique). + +### Breaking Changes +- Changed AnyValue trait family names: + - `AnyValue` -> `AnyValueTyped`. + - `AnyValueUnknown` -> `AnyValueSized`. + - Introduced `AnyValuePtr`. +- Changed AnyValueRaw non-owning wrappers names: + - `AnyValueRaw` -> `AnyValueRawTyped`. + - `AnyValueRawUnknown` -> `AnyValueRawSized`. + - Introduced `AnyValueRawPtr`. + + ## 0.12.0 ### Added - `element::ElementReference` trait, implemented both for `ElementRef`, `ElementMut` and &`Element`. diff --git a/benches/element_clone.rs b/benches/element_clone.rs index aee1469..da746de 100644 --- a/benches/element_clone.rs +++ b/benches/element_clone.rs @@ -2,7 +2,7 @@ mod utils; use std::time::{Duration, Instant}; use criterion::{criterion_group, criterion_main, Criterion, black_box}; -use any_vec::any_value::{AnyValueUnknown, AnyValueCloneable}; +use any_vec::any_value::{AnyValueCloneable, AnyValuePtr}; use any_vec::AnyVec; use any_vec::traits::Cloneable; use crate::utils::bench_custom; diff --git a/benches/insert.rs b/benches/insert.rs index 0264770..a8480ce 100644 --- a/benches/insert.rs +++ b/benches/insert.rs @@ -2,7 +2,7 @@ use std::any::TypeId; use std::mem::size_of; use std::ptr::NonNull; use criterion::{criterion_group, criterion_main, Criterion}; -use any_vec::any_value::{AnyValueRaw}; +use any_vec::any_value::{AnyValueRawTyped}; use any_vec::AnyVec; const SIZE: usize = 10000; @@ -17,7 +17,8 @@ fn vec_insert_front(){ fn any_vec_insert_front(){ let mut any_vec: AnyVec = AnyVec::new::(); for i in 0..SIZE{ - let raw_value = unsafe{AnyValueRaw::new( + let raw_value = unsafe{ + AnyValueRawTyped::new( NonNull::from(&i).cast::(), size_of::(), TypeId::of::() @@ -44,7 +45,8 @@ fn vec_insert_back(){ fn any_vec_insert_back(){ let mut any_vec: AnyVec = AnyVec::new::(); for i in 0..SIZE{ - let raw_value = unsafe{AnyValueRaw::new( + let raw_value = unsafe{ + AnyValueRawTyped::new( NonNull::from(&i).cast::(), size_of::(), TypeId::of::() diff --git a/benches/push.rs b/benches/push.rs index 8d3d3cb..e0ebf41 100644 --- a/benches/push.rs +++ b/benches/push.rs @@ -2,7 +2,7 @@ use std::any::TypeId; use std::mem::size_of; use std::ptr::NonNull; use criterion::{criterion_group, criterion_main, Criterion}; -use any_vec::any_value::AnyValueRaw; +use any_vec::any_value::{AnyValueRawPtr, AnyValueRawTyped}; use any_vec::AnyVec; const SIZE: usize = 10000; @@ -29,7 +29,8 @@ fn any_vec_push_untyped(){ let mut any_vec: AnyVec = AnyVec::new::(); for _ in 0..SIZE{ let value = VALUE.clone(); - let raw_value = unsafe{AnyValueRaw::new( + let raw_value = unsafe{ + AnyValueRawTyped::new( NonNull::from(&value).cast::(), size_of::(), TypeId::of::() @@ -38,9 +39,24 @@ fn any_vec_push_untyped(){ } } +fn any_vec_push_untyped_unchecked(){ + let mut any_vec: AnyVec = AnyVec::new::(); + for _ in 0..SIZE{ + let value = VALUE.clone(); + let raw_value = unsafe{ + AnyValueRawPtr::new( + NonNull::from(&value).cast::(), + )}; + unsafe{ + any_vec.push_unchecked(raw_value); + } + } +} + pub fn bench_push(c: &mut Criterion) { c.bench_function("Vec push", |b|b.iter(||vec_push())); c.bench_function("AnyVec push", |b|b.iter(||any_vec_push())); + c.bench_function("AnyVec push untyped unchecked", |b|b.iter(||any_vec_push_untyped_unchecked())); c.bench_function("AnyVec push untyped", |b|b.iter(||any_vec_push_untyped())); } diff --git a/src/any_value/lazy_clone.rs b/src/any_value/lazy_clone.rs index e84f036..65a7cd8 100644 --- a/src/any_value/lazy_clone.rs +++ b/src/any_value/lazy_clone.rs @@ -1,5 +1,5 @@ use std::any::TypeId; -use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueUnknown}; +use crate::any_value::{AnyValueTyped, AnyValueCloneable, AnyValueSized, AnyValuePtr}; /// Makes [`AnyValueCloneable`] actually [`Clone`]able. /// Do clone on consumption. @@ -20,21 +20,28 @@ impl<'a, T: AnyValueCloneable> LazyClone<'a, T>{ } } -impl<'a, T: AnyValueCloneable> AnyValueUnknown for LazyClone<'a, T>{ +impl<'a, T: AnyValueCloneable> AnyValuePtr for LazyClone<'a, T> { type Type = T::Type; #[inline] - fn as_bytes(&self) -> &[u8]{ - self.value.as_bytes() + fn as_bytes_ptr(&self) -> *const u8 { + self.value.as_bytes_ptr() } #[inline] - unsafe fn move_into(self, out: *mut u8) { + unsafe fn move_into(self, out: *mut u8, _bytes_size: usize) { self.value.clone_into(out); } } -impl<'a, T: AnyValueCloneable + AnyValue> AnyValue for LazyClone<'a, T>{ +impl<'a, T: AnyValueCloneable + AnyValueSized> AnyValueSized for LazyClone<'a, T>{ + #[inline] + fn size(&self) -> usize { + self.value.size() + } +} + +impl<'a, T: AnyValueCloneable + AnyValueTyped> AnyValueTyped for LazyClone<'a, T>{ #[inline] fn value_typeid(&self) -> TypeId { self.value.value_typeid() diff --git a/src/any_value/mod.rs b/src/any_value/mod.rs index 3ccbc80..494c73c 100644 --- a/src/any_value/mod.rs +++ b/src/any_value/mod.rs @@ -1,14 +1,26 @@ +//! AnyValue is concept of type-erased object, that +//! can be moved around without type knowledge. +//! +//! [AnyValuePtr] -> [AnyValueSized] -> [AnyValueTyped] +//! +//! Some [AnyVec] operations will return [AnyValueTyped], +//! [AnyVec] operations also accept AnyValue as arguments. +//! This allows to move data between [AnyVec]s in +//! fast, safe, type erased way. +//! +//! [AnyVec]: crate::AnyVec + mod wrapper; mod raw; mod lazy_clone; pub use lazy_clone::{LazyClone}; pub use wrapper::AnyValueWrapper; -pub use raw::{AnyValueRaw, AnyValueRawUnknown}; +pub use raw::{AnyValueRawTyped, AnyValueRawSized, AnyValueRawPtr}; use std::any::TypeId; use std::{mem, ptr}; -use std::mem::MaybeUninit; +use std::mem::{MaybeUninit, size_of}; use crate::{copy_bytes_nonoverlapping, swap_bytes_nonoverlapping}; /// Marker for unknown type. @@ -20,48 +32,94 @@ impl Unknown { } } -/// [`AnyValue`] that does not know it's compiletime or runtime type. -pub trait AnyValueUnknown { +/// AnyValue that can provide only object ptr. +pub trait AnyValuePtr { /// Concrete type, or [`Unknown`] /// - /// N.B. This should be in `AnyValue`. It is here due to ergonomic reasons, + /// N.B. This should be in `AnyValueTyped`. It is here due to ergonomic reasons, /// since Rust does not have impl specialization. type Type: 'static /*= Unknown*/; - /// Aligned. - fn as_bytes(&self) -> &[u8]; + /// Aligned address. + fn as_bytes_ptr(&self) -> *const u8; #[inline] unsafe fn downcast_ref_unchecked(&self) -> &T{ - &*(self.as_bytes().as_ptr() as *const T) + &*(self.as_bytes_ptr() as *const T) } #[inline] - unsafe fn downcast_unchecked(self) -> T + unsafe fn downcast_unchecked(self) -> T where Self: Sized { let mut tmp = MaybeUninit::::uninit(); - self.move_into(tmp.as_mut_ptr() as *mut u8); + self.move_into::(tmp.as_mut_ptr() as *mut u8, size_of::()); tmp.assume_init() } /// Move self into `out`. /// - /// `out` must have at least `as_bytes().len()` bytes. /// Will do compile-time optimisation if type/size known. /// - /// [`size`]: Self::size + /// # Safety + /// + /// `bytes_size` must be correct object size. + /// `out` must have at least `bytes_size` bytes. + /// `KnownType` must be correct object type or [Unknown]. + /// + /// Use [move_into] as safe version. #[inline] - unsafe fn move_into(self, out: *mut u8) + unsafe fn move_into(self, out: *mut u8, bytes_size: usize) where Self: Sized { - copy_bytes(&self, out); + copy_bytes::(self.as_bytes_ptr(), out, bytes_size); mem::forget(self); } } -/// Type erased value interface. -pub trait AnyValue: AnyValueUnknown { +/// Move AnyValue into `out` location. +/// +/// If `T` has known [Type] compile time optimizations will be applied. +/// +/// [Type]: AnyValuePtr::Type +#[inline] +pub fn move_into(this: T, out: *mut u8) { + let size = this.as_bytes().len(); + unsafe{ + move_into_w_size::(this, out, size); + } +} + +/// [move_into] but with `bytes_size` hint. +/// +/// In loops, compiler may generate more optimized code, if will +/// know that the same size is used for all moves. +/// Acts the same as [move_into] if [Type] is known. +/// +/// [Type]: AnyValuePtr::Type +#[inline] +pub unsafe fn move_into_w_size(this: T, out: *mut u8, bytes_size: usize) { + copy_bytes::(this.as_bytes_ptr(), out, bytes_size); + mem::forget(this); +} + +/// [AnyValuePtr] that know it's size. +pub trait AnyValueSized: AnyValuePtr { + /// Aligned. + #[inline] + fn as_bytes(&self) -> &[u8]{ + unsafe{std::slice::from_raw_parts( + self.as_bytes_ptr(), + self.size() + )} + } + + /// Aligned. + fn size(&self) -> usize; +} + +/// [AnyValueSized] that know it's type, possibly compiletime. +pub trait AnyValueTyped: AnyValueSized { fn value_typeid(&self) -> TypeId; #[inline] @@ -87,32 +145,46 @@ pub trait AnyValue: AnyValueUnknown { /// Helper function, which utilize type knowledge. #[inline] -pub(crate) unsafe fn copy_bytes(any_value: &T, out: *mut u8){ - if !Unknown::is::() { +pub(crate) unsafe fn copy_bytes( + input: *const u8, out: *mut u8, bytes_size: usize +) { + if !Unknown::is::() { ptr::copy_nonoverlapping( - any_value.as_bytes().as_ptr() as *const T::Type, - out as *mut T::Type, + input as *const KnownType, + out as *mut KnownType, 1); } else { - let bytes = any_value.as_bytes(); copy_bytes_nonoverlapping( - bytes.as_ptr(), + input, out, - bytes.len()); + bytes_size); } } -/// [`AnyValueMut`] that does not know it's compiletime or runtime type. -pub trait AnyValueMutUnknown: AnyValueUnknown { - fn as_bytes_mut(&mut self) -> &mut [u8]; +/// Mutable [AnyValuePtr]. +pub trait AnyValuePtrMut: AnyValuePtr { + // Rust MIRI requires mut pointer to actually come from mut self. + /// Aligned address. + fn as_bytes_mut_ptr(&mut self) -> *mut u8; #[inline] unsafe fn downcast_mut_unchecked(&mut self) -> &mut T{ - &mut *(self.as_bytes_mut().as_mut_ptr() as *mut T) + &mut *(self.as_bytes_mut_ptr() as *mut T) + } +} + +/// Mutable [AnyValueSized]. +pub trait AnyValueSizedMut: AnyValueSized + AnyValuePtrMut { + #[inline] + fn as_bytes_mut(&mut self) -> &mut [u8]{ + unsafe{std::slice::from_raw_parts_mut( + self.as_bytes_mut_ptr(), + self.size() + )} } #[inline] - unsafe fn swap_unchecked(&mut self, other: &mut Other){ + unsafe fn swap_unchecked(&mut self, other: &mut Other){ // compile-time check if !Unknown::is::() { mem::swap( @@ -135,8 +207,8 @@ pub trait AnyValueMutUnknown: AnyValueUnknown { } } -/// Type erased mutable value interface. -pub trait AnyValueMut: AnyValueMutUnknown + AnyValue{ +/// Mutable [AnyValueTyped]. +pub trait AnyValueTypedMut: AnyValueSizedMut + AnyValueTyped { #[inline] fn downcast_mut(&mut self) -> Option<&mut T>{ if self.value_typeid() != TypeId::of::(){ @@ -152,7 +224,7 @@ pub trait AnyValueMut: AnyValueMutUnknown + AnyValue{ /// /// Panics, if type mismatch. #[inline] - fn swap(&mut self, other: &mut Other){ + fn swap(&mut self, other: &mut Other){ assert_eq!(self.value_typeid(), other.value_typeid()); unsafe{ self.swap_unchecked(other); @@ -160,8 +232,8 @@ pub trait AnyValueMut: AnyValueMutUnknown + AnyValue{ } } -/// [`LazyClone`] friendly [`AnyValueUnknown`]. -pub trait AnyValueCloneable: AnyValueUnknown { +/// [`LazyClone`] friendly [`AnyValuePtr`]. +pub trait AnyValueCloneable: AnyValuePtr { unsafe fn clone_into(&self, out: *mut u8); #[inline] diff --git a/src/any_value/raw.rs b/src/any_value/raw.rs index 44a07eb..d8c7e67 100644 --- a/src/any_value/raw.rs +++ b/src/any_value/raw.rs @@ -1,107 +1,141 @@ use std::any::TypeId; use std::ptr::NonNull; -use std::slice; -use crate::any_value::{AnyValue, AnyValueMut, AnyValueMutUnknown, AnyValueUnknown}; +use crate::any_value::{AnyValueTyped, AnyValueTypedMut, AnyValueSizedMut, AnyValueSized, AnyValuePtr, AnyValuePtrMut}; use crate::any_value::Unknown; +/// Non owning byte ptr wrapper for feeding AnyVec. +/// +/// Source should be forgotten, before pushing to AnyVec. +/// Contained value **WILL NOT** be dropped on AnyValueRawPtr drop. +/// +/// This is useful to fill [AnyVec] directly from raw bytes, +/// without intermediate casting to concrete type. +/// +/// # Example +/// ```rust +/// # use std::any::TypeId; +/// # use std::mem; +/// # use std::mem::size_of; +/// # use std::ptr::NonNull; +/// # use any_vec::AnyVec; +/// # use any_vec::any_value::AnyValueRawPtr; +/// let s = String::from("Hello!"); +/// let raw_value = unsafe{AnyValueRawPtr::new( +/// NonNull::from(&s).cast::() +/// )}; +/// mem::forget(s); +/// +/// let mut any_vec: AnyVec = AnyVec::new::(); +/// unsafe{ +/// any_vec.push_unchecked(raw_value); +/// } +/// ``` +/// +/// [AnyVec]: crate::AnyVec +pub struct AnyValueRawPtr { + ptr: NonNull +} + +impl AnyValueRawPtr { + #[inline] + pub unsafe fn new(ptr: NonNull) -> Self{ + Self{ptr} + } +} +impl AnyValuePtr for AnyValueRawPtr { + type Type = Unknown; + + #[inline] + fn as_bytes_ptr(&self) -> *const u8 { + self.ptr.as_ptr() + } +} +impl AnyValuePtrMut for AnyValueRawPtr { + #[inline] + fn as_bytes_mut_ptr(&mut self) -> *mut u8 { + self.ptr.as_ptr() + } +} -/// [`AnyValueRaw`] that does not know it's type. -pub struct AnyValueRawUnknown { + +/// [AnyValueRawPtr] that know it's size. +pub struct AnyValueRawSized { ptr: NonNull, size: usize, } -impl AnyValueRawUnknown { +impl AnyValueRawSized { #[inline] pub unsafe fn new(ptr: NonNull, size: usize) -> Self{ Self{ptr, size} } } -impl AnyValueUnknown for AnyValueRawUnknown { + +impl AnyValuePtr for AnyValueRawSized { type Type = Unknown; #[inline] - fn as_bytes(&self) -> &[u8]{ - unsafe{slice::from_raw_parts( - self.ptr.as_ptr(), - self.size - )} + fn as_bytes_ptr(&self) -> *const u8 { + self.ptr.as_ptr() + } +} +impl AnyValuePtrMut for AnyValueRawSized { + #[inline] + fn as_bytes_mut_ptr(&mut self) -> *mut u8 { + self.ptr.as_ptr() } } -impl AnyValueMutUnknown for AnyValueRawUnknown { +impl AnyValueSized for AnyValueRawSized { #[inline] - fn as_bytes_mut(&mut self) -> &mut [u8] { - unsafe{slice::from_raw_parts_mut( - self.ptr.as_ptr(), - self.size - )} + fn size(&self) -> usize { + self.size } } +impl AnyValueSizedMut for AnyValueRawSized {} -/// Non owning byte ptr wrapper for feeding AnyVec. -/// -/// Source should be forgotten, before pushing to AnyVec. -/// Contained value will not be dropped on AnyValueRaw drop. -/// -/// This is useful to fill AnyVec directly from raw bytes, -/// without intermediate casting to concrete type. -/// (You only need runtime data - size and typeid) -/// -/// # Example -/// ```rust -/// # use std::any::TypeId; -/// # use std::mem; -/// # use std::mem::size_of; -/// # use std::ptr::NonNull; -/// # use any_vec::AnyVec; -/// # use any_vec::any_value::AnyValueRaw; -/// let s = String::from("Hello!"); -/// let raw_value = unsafe{AnyValueRaw::new( -/// NonNull::from(&s).cast::(), -/// size_of::(), -/// TypeId::of::() -/// )}; -/// mem::forget(s); -/// -/// let mut any_vec: AnyVec = AnyVec::new::(); -/// any_vec.push(raw_value); -/// ``` -pub struct AnyValueRaw{ - raw_unsafe: AnyValueRawUnknown, +/// [AnyValueRawSized] that know it's type. +pub struct AnyValueRawTyped { + raw_unsafe: AnyValueRawSized, typeid: TypeId } -impl AnyValueRaw{ +impl AnyValueRawTyped { #[inline] pub unsafe fn new(ptr: NonNull, size: usize, typeid: TypeId) -> Self{ Self{ - raw_unsafe: AnyValueRawUnknown::new(ptr, size), + raw_unsafe: AnyValueRawSized::new(ptr, size), typeid } } } -impl AnyValueUnknown for AnyValueRaw{ + +impl AnyValuePtr for AnyValueRawTyped { type Type = Unknown; #[inline] - fn as_bytes(&self) -> &[u8]{ - self.raw_unsafe.as_bytes() + fn as_bytes_ptr(&self) -> *const u8 { + self.raw_unsafe.ptr.as_ptr() } } -impl AnyValue for AnyValueRaw{ +impl AnyValuePtrMut for AnyValueRawTyped { #[inline] - fn value_typeid(&self) -> TypeId { - self.typeid + fn as_bytes_mut_ptr(&mut self) -> *mut u8 { + self.raw_unsafe.ptr.as_ptr() + } +} +impl AnyValueSized for AnyValueRawTyped { + #[inline] + fn size(&self) -> usize { + self.raw_unsafe.size } } -impl AnyValueMutUnknown for AnyValueRaw{ +impl AnyValueTyped for AnyValueRawTyped { #[inline] - fn as_bytes_mut(&mut self) -> &mut [u8] { - unsafe{slice::from_raw_parts_mut( - self.raw_unsafe.ptr.as_ptr(), - self.raw_unsafe.size - )} + fn value_typeid(&self) -> TypeId { + self.typeid } } -impl AnyValueMut for AnyValueRaw{} \ No newline at end of file + +impl AnyValueSizedMut for AnyValueRawTyped {} +impl AnyValueTypedMut for AnyValueRawTyped {} \ No newline at end of file diff --git a/src/any_value/wrapper.rs b/src/any_value/wrapper.rs index cd6b7ea..39522ad 100644 --- a/src/any_value/wrapper.rs +++ b/src/any_value/wrapper.rs @@ -1,9 +1,8 @@ use std::any::TypeId; -use std::mem::{ManuallyDrop, size_of}; -use std::{ptr, slice}; -use crate::any_value::{AnyValue, AnyValueMut, AnyValueMutUnknown, AnyValueUnknown}; +use std::mem::size_of; +use crate::any_value::{AnyValueTyped, AnyValueTypedMut, AnyValueSizedMut, AnyValueSized, AnyValuePtr, AnyValuePtrMut}; -/// Helper struct to convert concrete type to [`AnyValue`]. +/// Helper struct to convert concrete type to [`AnyValueTypedMut`]. pub struct AnyValueWrapper{ value: T } @@ -13,38 +12,32 @@ impl AnyValueWrapper { Self{ value } } } -impl AnyValueUnknown for AnyValueWrapper { + +impl AnyValuePtr for AnyValueWrapper { type Type = T; #[inline] - fn as_bytes(&self) -> &[u8]{ - unsafe{slice::from_raw_parts( - &self.value as *const _ as *const u8, - size_of::() - )} + fn as_bytes_ptr(&self) -> *const u8 { + &self.value as *const _ as *const u8 } - +} +impl AnyValuePtrMut for AnyValueWrapper { #[inline] - unsafe fn downcast_unchecked(self) -> U { - // rust don't see that types are the same after assert. - let value = ManuallyDrop::new(self.value); - let ptr = &*value as *const T as *const U; - ptr::read(ptr) + fn as_bytes_mut_ptr(&mut self) -> *mut u8 { + &mut self.value as *mut _ as *mut u8 } } -impl AnyValue for AnyValueWrapper { +impl AnyValueSized for AnyValueWrapper { #[inline] - fn value_typeid(&self) -> TypeId { - TypeId::of::() + fn size(&self) -> usize { + size_of::() } } -impl AnyValueMutUnknown for AnyValueWrapper { +impl AnyValueTyped for AnyValueWrapper { #[inline] - fn as_bytes_mut(&mut self) -> &mut [u8] { - unsafe{slice::from_raw_parts_mut( - &mut self.value as *mut _ as *mut u8, - size_of::() - )} + fn value_typeid(&self) -> TypeId { + TypeId::of::() } } -impl AnyValueMut for AnyValueWrapper {} \ No newline at end of file +impl AnyValueSizedMut for AnyValueWrapper {} +impl AnyValueTypedMut for AnyValueWrapper {} \ No newline at end of file diff --git a/src/any_vec.rs b/src/any_vec.rs index 191910c..f7ba840 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -8,7 +8,7 @@ use std::ptr::NonNull; use std::{ptr, slice}; use std::slice::{from_raw_parts, from_raw_parts_mut}; use crate::{AnyVecTyped, into_range, mem, ops}; -use crate::any_value::{AnyValue, AnyValueUnknown}; +use crate::any_value::{AnyValueTyped, AnyValuePtr}; use crate::any_vec_raw::{AnyVecRaw, DropFn}; use crate::ops::{TempValue, Remove, SwapRemove, remove, swap_remove, Pop, pop}; use crate::ops::{Drain, Splice, drain, splice}; @@ -140,9 +140,11 @@ where /// specifying trait constraints: `AnyVec`. See [`traits`]. /// /// Some operations return [`TempValue`], which internally holds &mut to [`AnyVec`]. -/// You can drop it, cast to concrete type, or put into another vector. (See [`AnyValue`]) +/// You can drop it, cast to concrete type, or put into another vector. (See [any_value]) /// /// *`T: 'static` due to TypeId requirements* +/// +/// [any_value]: crate::any_value pub struct AnyVec { pub(crate) raw: AnyVecRaw, @@ -563,7 +565,7 @@ impl AnyVec /// * Panics if index is out of bounds. /// * Panics if out of memory. #[inline] - pub fn insert(&mut self, index: usize, value: V) { + pub fn insert(&mut self, index: usize, value: V) { self.raw.type_check(&value); unsafe{ self.raw.insert_unchecked(index, value); @@ -583,7 +585,7 @@ impl AnyVec /// /// [`insert`]: Self::insert #[inline] - pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { + pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { self.raw.insert_unchecked(index, value); } @@ -592,7 +594,7 @@ impl AnyVec /// * Panics if type mismatch. /// * Panics if out of memory. #[inline] - pub fn push(&mut self, value: V) { + pub fn push(&mut self, value: V) { self.raw.type_check(&value); unsafe{ self.raw.push_unchecked(value); @@ -611,7 +613,7 @@ impl AnyVec /// /// [`push`]: Self::push #[inline] - pub unsafe fn push_unchecked(&mut self, value: V) { + pub unsafe fn push_unchecked(&mut self, value: V) { self.raw.push_unchecked(value); } @@ -730,7 +732,7 @@ impl AnyVec -> Splice where I::IntoIter: ExactSizeIterator, - I::Item: AnyValue + I::Item: AnyValueTyped { let Range{start, end} = into_range(self.len(), range); ops::Iter(splice::Splice::new( diff --git a/src/any_vec_ptr.rs b/src/any_vec_ptr.rs index 63caaae..879544e 100644 --- a/src/any_vec_ptr.rs +++ b/src/any_vec_ptr.rs @@ -140,6 +140,7 @@ pub(crate) mod utils{ } } + /// In bytes. #[inline] pub unsafe fn element_size(any_vec_ptr: AnyVecPtr) -> usize { diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index a926b78..4289834 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -1,7 +1,8 @@ use std::{cmp, mem, ptr}; use std::alloc::Layout; use std::any::TypeId; -use crate::any_value::{AnyValue, AnyValueUnknown, Unknown}; +use std::mem::size_of; +use crate::any_value::{AnyValueTyped, Unknown, AnyValuePtr}; use crate::assert_types_equal; use crate::clone_type::CloneFn; use crate::mem::{Mem, MemBuilder, MemResizable}; @@ -83,7 +84,7 @@ impl AnyVecRaw { } #[inline] - pub(crate) fn type_check(&self, value: &V){ + pub(crate) fn type_check(&self, value: &V){ assert_types_equal(value.value_typeid(), self.type_id); } @@ -153,7 +154,7 @@ impl AnyVecRaw { /// # Safety /// /// Type is not checked. - pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { + pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { assert!(index <= self.len, "Index out of range!"); self.reserve_one(); @@ -170,7 +171,7 @@ impl AnyVecRaw { ); // 2. write value - value.move_into(element as *mut u8); + value.move_into::(element as *mut u8, size_of::()); } else { let element_size = self.element_layout().size(); let element = self.mem.as_mut_ptr().add(element_size * index); @@ -183,7 +184,7 @@ impl AnyVecRaw { ); // 2. write value - value.move_into(element); + value.move_into::(element, element_size); } self.len += 1; @@ -193,19 +194,18 @@ impl AnyVecRaw { /// /// Type is not checked. #[inline] - pub unsafe fn push_unchecked(&mut self, value: V) { + pub unsafe fn push_unchecked(&mut self, value: V) { self.reserve_one(); // Compile time type optimization - let element = - if !Unknown::is::(){ - self.mem.as_mut_ptr().cast::().add(self.len) as *mut u8 - } else { - let element_size = self.element_layout().size(); - self.mem.as_mut_ptr().add(element_size * self.len) - }; - - value.move_into(element); + if !Unknown::is::(){ + let element = self.mem.as_mut_ptr().cast::().add(self.len) as *mut u8; + value.move_into::(element, size_of::()); + } else { + let element_size = self.element_layout().size(); + let element = self.mem.as_mut_ptr().add(element_size * self.len); + value.move_into::(element, element_size); + }; self.len += 1; } diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index 7cacd35..4bf2c96 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -4,7 +4,7 @@ use std::mem::MaybeUninit; use std::ops::{Range, RangeBounds}; use std::ptr::NonNull; use std::slice; -use crate::any_value::{AnyValueUnknown, AnyValueWrapper}; +use crate::any_value::{AnyValuePtr, AnyValueWrapper}; use crate::any_vec_raw::AnyVecRaw; use crate::ops::{Iter, pop, remove, swap_remove, TempValue}; use crate::any_vec_ptr::AnyVecRawPtr; diff --git a/src/element.rs b/src/element.rs index 0ee2616..87d4861 100644 --- a/src/element.rs +++ b/src/element.rs @@ -3,8 +3,7 @@ use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; -use std::slice; -use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueMutUnknown, AnyValueUnknown}; +use crate::any_value::{AnyValueTyped, AnyValueCloneable, AnyValueTypedMut, AnyValueSizedMut, AnyValueSized, AnyValuePtr, AnyValuePtrMut}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{AnyVecPtr, IAnyVecPtr, IAnyVecRawPtr}; use crate::{AnyVec, mem}; @@ -22,7 +21,7 @@ use crate::traits::{Cloneable, None, Trait}; /// # Consuming /// /// Whenever you have `ElementPointer` as a value (from destructive [`AnyVec`] operations), -/// you can safely take pointed value, with [`AnyValue::downcast`] or [`AnyValueUnknown::move_into`]. +/// you can safely take pointed value, with [`AnyValueTyped::downcast`] or [`any_value::move_into`]. /// Otherwise, it will be destructed with destruction of `Element`. /// /// # Notes @@ -34,6 +33,8 @@ use crate::traits::{Cloneable, None, Trait}; /// [`AnyVec::get`]: crate::AnyVec::get /// [`drain`]: crate::AnyVec::drain /// [`splice`]: crate::AnyVec::splice +/// [`any_value`]: crate::any_value +/// [`any_value::move_into`]: crate::any_value::move_into pub struct ElementPointer<'a, AnyVecPtr: IAnyVecRawPtr>{ any_vec_ptr: AnyVecPtr, element: NonNull, @@ -57,7 +58,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ unsafe { self.any_vec_ptr.any_vec_raw() } } - /// Same as [`AnyValue::downcast_ref`], but return `&'a T`, instead of `&T`. + /// Same as [`AnyValueTyped::downcast_ref`], but return `&'a T`, instead of `&T`. #[inline] pub fn downcast_ref(&self) -> Option<&'a T>{ if self.value_typeid() != TypeId::of::(){ @@ -67,13 +68,13 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ } } - /// Same as [`AnyValueUnknown::downcast_ref_unchecked`], but return `&'a T`, instead of `&T`. + /// Same as [`AnyValuePtr::downcast_ref_unchecked`], but return `&'a T`, instead of `&T`. #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &'a T{ &*(self.as_bytes().as_ptr() as *const T) } - /// Same as [`AnyValueMut::downcast_mut`], but return `&'a mut T`, instead of `&mut T`. + /// Same as [`AnyValueTypedMut::downcast_mut`], but return `&'a mut T`, instead of `&mut T`. #[inline] pub fn downcast_mut(&mut self) -> Option<&'a mut T>{ if self.value_typeid() != TypeId::of::(){ @@ -83,7 +84,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ } } - /// Same as [`AnyValueMutUnknown::downcast_mut_unchecked`], but return `&'a mut T`, instead of `&mut T`. + /// Same as [`AnyValuePtrMut::downcast_mut_unchecked`], but return `&'a mut T`, instead of `&mut T`. #[inline] pub unsafe fn downcast_mut_unchecked(&mut self) -> &'a mut T{ &mut *(self.as_bytes_mut().as_mut_ptr() as *mut T) @@ -101,34 +102,35 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Drop for ElementPointer<'a, AnyVecPtr>{ } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueUnknown for ElementPointer<'a, AnyVecPtr>{ +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValuePtr for ElementPointer<'a, AnyVecPtr> { type Type = AnyVecPtr::Element; #[inline] - fn as_bytes(&self) -> &[u8]{ - unsafe{slice::from_raw_parts( - self.element.as_ptr(), - self.any_vec_raw().element_layout().size() - )} + fn as_bytes_ptr(&self) -> *const u8 { + self.element.as_ptr() } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValue for ElementPointer<'a, AnyVecPtr>{ +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueSized for ElementPointer<'a, AnyVecPtr>{ + #[inline] + fn size(&self) -> usize { + self.any_vec_raw().element_layout().size() + } +} +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueTyped for ElementPointer<'a, AnyVecPtr>{ #[inline] fn value_typeid(&self) -> TypeId { self.any_vec_raw().type_id } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMutUnknown for ElementPointer<'a, AnyVecPtr>{ +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValuePtrMut for ElementPointer<'a, AnyVecPtr>{ #[inline] - fn as_bytes_mut(&mut self) -> &mut [u8] { - unsafe{slice::from_raw_parts_mut( - self.element.as_ptr(), - self.any_vec_raw().element_layout().size() - )} + fn as_bytes_mut_ptr(&mut self) -> *mut u8 { + self.element.as_ptr() } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMut for ElementPointer<'a, AnyVecPtr>{} +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueSizedMut for ElementPointer<'a, AnyVecPtr>{} +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueTypedMut for ElementPointer<'a, AnyVecPtr>{} impl<'a, Traits: ?Sized + Cloneable + Trait, M: MemBuilder> AnyValueCloneable for ElementPointer<'a, AnyVecPtr> diff --git a/src/lib.rs b/src/lib.rs index 348388b..cd1985e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,13 +4,11 @@ //! Have same performance and *operations* as [`std::vec::Vec`]. //! //! You can downcast type erased [`AnyVec`] to concrete [`AnyVecTyped`] with `downcast`-family. -//! Or use [`AnyVec`] type erased operations, which works with [`AnyValue`]. -//! -//! [`AnyValue`]: any_value::AnyValue +//! Or use [`AnyVec`] type erased operations, which works with [`any_value`]. //! //! ```rust //! use any_vec::AnyVec; -//! use any_vec::any_value::AnyValue; +//! use any_vec::any_value::AnyValueTyped; //! let mut vec: AnyVec = AnyVec::new::(); //! { //! // Typed operations. @@ -124,18 +122,18 @@ //! # AnyValue //! //! Being type erased, [`AnyVec`] need a way to operate on untyped values safely. -//! Instead of working with plain `*mut u8`, [`AnyVec`] operates with [`AnyValue`]. +//! Instead of working with plain `*mut u8`, [`AnyVec`] operates with [any_value]. //! -//! [`AnyValue`] is trait, which provide operations to work with type erased values. -//! Any type that implement [`AnyValue`] can be used with [`AnyVec`]. -//! [`AnyValue`] interface allows to perform postponed operations on consumption. +//! `AnyValueXXX` is a trait family, which provide operations to work with type erased values. +//! Any type that implements `AnyValueXXX` can be used with [`AnyVec`]. +//! `AnyValueXXX` interface allows to perform postponed operations on consumption. //! This trick used heavily by [`AnyVec`] destructive operations, which instead of concrete -//! type return [`AnyValue`], which perform actual operation on value drop. +//! type return [AnyValueTyped], which perform actual operation on value drop. //! -//! Implementing [`AnyValueMut`] and [`AnyValueCloneable`] makes type mutable and +//! Implementing `AnyValueXXXMut` and [`AnyValueCloneable`] makes type mutable and //! cloneable respectively. //! -//! [`AnyValueMut`]: crate::any_value::AnyValueMut` +//! [AnyValueTyped]: any_value::AnyValueTyped mod any_vec; mod clone_type; diff --git a/src/mem/mod.rs b/src/mem/mod.rs index 6f47efb..b8a2d05 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -62,6 +62,7 @@ pub trait Mem{ /// Implement this only if your type [`MemResizable`]. /// /// It's here, only due to technical reasons (see `AnyVecRaw::reserve`). + /// _Rust does not support specialization_ /// /// # Panics /// diff --git a/src/ops/mod.rs b/src/ops/mod.rs index e98ef04..94b78b3 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -1,3 +1,9 @@ +//! [AnyVec] operations. +//! +//! You don't need, nor can't construct anything from this module manually. +//! +//! [AnyVec]: crate::AnyVec + mod temp; mod iter; pub(crate) mod swap_remove; diff --git a/src/ops/splice.rs b/src/ops/splice.rs index f6cab2b..190c57a 100644 --- a/src/ops/splice.rs +++ b/src/ops/splice.rs @@ -1,11 +1,11 @@ use crate::any_vec_ptr::IAnyVecRawPtr; use crate::{any_vec_ptr, assert_types_equal, Iter}; -use crate::any_value::{AnyValueUnknown, AnyValue}; +use crate::any_value::{AnyValueTyped, move_into_w_size}; use crate::ops::iter::Iterable; pub struct Splice<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> where - ReplaceIter::Item: AnyValue + ReplaceIter::Item: AnyValueTyped { iter: Iter<'a, AnyVecPtr>, start: usize, @@ -16,7 +16,7 @@ where impl<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> Splice<'a, AnyVecPtr, ReplaceIter> where - ReplaceIter::Item: AnyValue + ReplaceIter::Item: AnyValueTyped { #[inline] pub fn new( @@ -44,7 +44,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> Iterable for Splice<'a, AnyVecPtr, ReplaceIter> where - ReplaceIter::Item: AnyValue + ReplaceIter::Item: AnyValueTyped { type Iter = Iter<'a, AnyVecPtr>; @@ -63,7 +63,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> Drop for Splice<'a, AnyVecPtr, ReplaceIter> where - ReplaceIter::Item: AnyValue + ReplaceIter::Item: AnyValueTyped { fn drop(&mut self) { use any_vec_ptr::utils::*; @@ -105,7 +105,7 @@ where let mut ptr = element_mut_ptr_at(any_vec_ptr, self.start); while let Some(replace_element) = self.replace_with.next() { assert_types_equal(type_id, replace_element.value_typeid()); - replace_element.move_into(ptr); + move_into_w_size(replace_element, ptr, element_size); ptr = ptr.add(element_size); } } diff --git a/src/ops/temp.rs b/src/ops/temp.rs index db33a7b..d1e1b64 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -1,6 +1,6 @@ use std::any::TypeId; -use std::{mem, ptr, slice}; -use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueMutUnknown, AnyValueUnknown, copy_bytes, Unknown}; +use std::{mem, ptr}; +use crate::any_value::{AnyValueTyped, AnyValueCloneable, AnyValueTypedMut, AnyValueSizedMut, AnyValueSized, Unknown, AnyValuePtr, copy_bytes, AnyValuePtrMut}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{IAnyVecPtr, IAnyVecRawPtr}; use crate::AnyVec; @@ -48,25 +48,35 @@ impl TempValue{ } } -impl AnyValueUnknown for TempValue{ +impl AnyValuePtr for TempValue { type Type = ::Element; #[inline] - fn as_bytes(&self) -> &[u8]{ - unsafe{slice::from_raw_parts( - self.op.bytes(), - self.bytes_len() - )} + fn as_bytes_ptr(&self) -> *const u8 { + self.op.bytes() } #[inline] - unsafe fn move_into(mut self, out: *mut u8) { - copy_bytes(&self, out); + unsafe fn move_into(mut self, out: *mut u8, bytes_size: usize) { + copy_bytes::(self.as_bytes_ptr(), out, bytes_size); self.op.consume(); mem::forget(self); } } -impl AnyValue for TempValue{ +impl AnyValuePtrMut for TempValue { + #[inline] + fn as_bytes_mut_ptr(&mut self) -> *mut u8 { + // Somehow this is OK with MIRI. + self.op.bytes() as *mut u8 + } +} +impl AnyValueSized for TempValue{ + #[inline] + fn size(&self) -> usize { + self.bytes_len() + } +} +impl AnyValueTyped for TempValue{ #[inline] fn value_typeid(&self) -> TypeId { let typeid = TypeId::of::(); @@ -78,16 +88,8 @@ impl AnyValue for TempValue{ } } -impl AnyValueMutUnknown for TempValue { - #[inline] - fn as_bytes_mut(&mut self) -> &mut [u8] { - unsafe{slice::from_raw_parts_mut( - self.op.bytes() as *mut u8, - self.bytes_len() - )} - } -} -impl AnyValueMut for TempValue {} +impl AnyValueSizedMut for TempValue {} +impl AnyValueTypedMut for TempValue {} impl AnyValueCloneable for TempValue where @@ -109,12 +111,12 @@ impl Drop for TempValue{ let element = self.op.bytes() as *mut u8; // compile-time check - if Unknown::is::<::Type>() { + if Unknown::is::<::Type>() { if let Some(drop_fn) = drop_fn{ (drop_fn)(element, 1); } } else { - ptr::drop_in_place(element as *mut ::Type); + ptr::drop_in_place(element as *mut ::Type); } } self.op.consume(); diff --git a/tests/any_value.rs b/tests/any_value.rs index 3546821..1d0189c 100644 --- a/tests/any_value.rs +++ b/tests/any_value.rs @@ -1,7 +1,7 @@ use std::any::TypeId; use std::mem::size_of; use std::ptr::NonNull; -use any_vec::any_value::{AnyValue, AnyValueMut, AnyValueRaw, AnyValueWrapper}; +use any_vec::any_value::{AnyValueTyped, AnyValueTypedMut, AnyValueRawTyped, AnyValueWrapper}; #[test] fn swap_test(){ @@ -20,12 +20,14 @@ fn swap_test(){ let mut s1 = String::from("1"); let mut s2 = String::from("2"); - let mut a1 = unsafe{AnyValueRaw::new( + let mut a1 = unsafe{ + AnyValueRawTyped::new( NonNull::from(&mut s1).cast::(), size_of::(), TypeId::of::() )}; - let mut a2 = unsafe{AnyValueRaw::new( + let mut a2 = unsafe{ + AnyValueRawTyped::new( NonNull::from(&mut s2).cast::(), size_of::(), TypeId::of::() @@ -39,7 +41,8 @@ fn swap_test(){ // untyped <-> typed { let mut s1 = String::from("1"); - let mut a1 = unsafe{AnyValueRaw::new( + let mut a1 = unsafe{ + AnyValueRawTyped::new( NonNull::from(&mut s1).cast::(), size_of::(), TypeId::of::() diff --git a/tests/any_vec.rs b/tests/any_vec.rs index bdad307..d4efc64 100644 --- a/tests/any_vec.rs +++ b/tests/any_vec.rs @@ -4,7 +4,7 @@ use std::mem::forget; use std::ptr::NonNull; use itertools::assert_equal; use any_vec::AnyVec; -use any_vec::any_value::{AnyValueMut, AnyValueRaw, AnyValueWrapper}; +use any_vec::any_value::{AnyValueTypedMut, AnyValueRawTyped, AnyValueWrapper}; use any_vec::mem::Stack; #[allow(dead_code)] @@ -39,21 +39,21 @@ fn any_value_raw_test() { unsafe{ let str1 = "Hello".to_string(); - any_vec.push(AnyValueRaw::new( + any_vec.push(AnyValueRawTyped::new( NonNull::from(&str1).cast::(), size_of::(), TypeId::of::() )); forget(str1); let str2 = " to ".to_string(); - any_vec.push(AnyValueRaw::new( + any_vec.push(AnyValueRawTyped::new( NonNull::from(&str2).cast::(), size_of::(), TypeId::of::() )); forget(str2); let str3 = "world".to_string(); - any_vec.push(AnyValueRaw::new( + any_vec.push(AnyValueRawTyped::new( NonNull::from(&str3).cast::(), size_of::(), TypeId::of::() )); @@ -107,7 +107,13 @@ fn remove_test() { } // type erased remove - any_vec.remove(2); + { + let mut removed = any_vec.remove(2); + // test temp_mut_access + let str = removed.downcast_mut::().unwrap(); + str.push_str("xxx"); + assert_eq!(str, "2xxx"); + } assert_equal(any_vec.downcast_ref::().unwrap().as_slice(), &[ String::from("0"), String::from("1"), diff --git a/tests/any_vec_element.rs b/tests/any_vec_element.rs index de5c70b..4c93a17 100644 --- a/tests/any_vec_element.rs +++ b/tests/any_vec_element.rs @@ -1,6 +1,6 @@ use std::any::TypeId; use itertools::{assert_equal}; -use any_vec::any_value::{AnyValue, AnyValueCloneable, LazyClone}; +use any_vec::any_value::{AnyValueTyped, AnyValueCloneable, LazyClone}; use any_vec::AnyVec; use any_vec::element::ElementReference; use any_vec::mem::{MemBuilder, Stack}; diff --git a/tests/any_vec_fuzzy.rs b/tests/any_vec_fuzzy.rs index 1968a93..9a40beb 100644 --- a/tests/any_vec_fuzzy.rs +++ b/tests/any_vec_fuzzy.rs @@ -2,7 +2,7 @@ use std::cmp; use std::ops::Range; use itertools::assert_equal; use rand::Rng; -use any_vec::any_value::{AnyValue, AnyValueWrapper}; +use any_vec::any_value::{AnyValueTyped, AnyValueWrapper}; use any_vec::AnyVec; const REPEATS: usize = if cfg!(miri){ 4 }else{ 100 }; From 5f4e692ed00fbf496b12c12f82d6fbfb0a7de82d Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 16 Jul 2023 22:00:03 +0300 Subject: [PATCH 28/35] benchmark update --- benches/push.rs | 39 ++++++++++++++++++++++----------------- src/lib.rs | 11 ++++++++--- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/benches/push.rs b/benches/push.rs index e0ebf41..e34e9f0 100644 --- a/benches/push.rs +++ b/benches/push.rs @@ -8,27 +8,30 @@ use any_vec::AnyVec; const SIZE: usize = 10000; type Element = (usize, usize); -static VALUE: Element = (0,0); +#[inline] +fn make_element(i: usize) -> Element{ + (i,i) +} -fn vec_push(){ +fn vec_push(size: usize){ let mut vec = Vec::new(); - for _ in 0..SIZE{ - vec.push(VALUE.clone()); + for i in 0..size{ + vec.push(make_element(i)); } } -fn any_vec_push(){ +fn any_vec_push(size: usize){ let mut any_vec: AnyVec = AnyVec::new::(); let mut vec = any_vec.downcast_mut::().unwrap(); - for _ in 0..SIZE{ - vec.push(VALUE.clone()); + for i in 0..size{ + vec.push(make_element(i)); } } -fn any_vec_push_untyped(){ +fn any_vec_push_untyped(size: usize){ let mut any_vec: AnyVec = AnyVec::new::(); - for _ in 0..SIZE{ - let value = VALUE.clone(); + for i in 0..size{ + let value = make_element(i); let raw_value = unsafe{ AnyValueRawTyped::new( NonNull::from(&value).cast::(), @@ -39,10 +42,10 @@ fn any_vec_push_untyped(){ } } -fn any_vec_push_untyped_unchecked(){ +fn any_vec_push_untyped_unchecked(size: usize){ let mut any_vec: AnyVec = AnyVec::new::(); - for _ in 0..SIZE{ - let value = VALUE.clone(); + for i in 0..size{ + let value = make_element(i); let raw_value = unsafe{ AnyValueRawPtr::new( NonNull::from(&value).cast::(), @@ -54,10 +57,12 @@ fn any_vec_push_untyped_unchecked(){ } pub fn bench_push(c: &mut Criterion) { - c.bench_function("Vec push", |b|b.iter(||vec_push())); - c.bench_function("AnyVec push", |b|b.iter(||any_vec_push())); - c.bench_function("AnyVec push untyped unchecked", |b|b.iter(||any_vec_push_untyped_unchecked())); - c.bench_function("AnyVec push untyped", |b|b.iter(||any_vec_push_untyped())); + use criterion::black_box; + + c.bench_function("Vec push", |b|b.iter(||vec_push(black_box(SIZE)))); + c.bench_function("AnyVec push", |b|b.iter(||any_vec_push(black_box(SIZE)))); + c.bench_function("AnyVec push untyped unchecked", |b|b.iter(||any_vec_push_untyped_unchecked(black_box(SIZE)))); + c.bench_function("AnyVec push untyped", |b|b.iter(||any_vec_push_untyped(black_box(SIZE)))); } criterion_group!(benches, bench_push); diff --git a/src/lib.rs b/src/lib.rs index cd1985e..2a89c17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -159,9 +159,14 @@ use std::ops::{Bound, Range, RangeBounds}; // when count is runtime value, and count is small. #[inline] unsafe fn copy_bytes_nonoverlapping(src: *const u8, dst: *mut u8, count: usize){ - // MIRI hack + // Somehow, it looks ok now. + // Tracking issue https://github.com/rust-lang/rust/issues/97022 + ptr::copy_nonoverlapping(src, dst, count); + return; + + /*// MIRI hack if cfg!(miri) -// || count >= 128 + // || count >= 128 { ptr::copy_nonoverlapping(src, dst, count); return; @@ -169,7 +174,7 @@ unsafe fn copy_bytes_nonoverlapping(src: *const u8, dst: *mut u8, count: usize){ for i in 0..count{ *dst.add(i) = *src.add(i); - } + }*/ } // This is faster then ptr::copy, From 566f1b737755c05fd0b200b8416ed08cfaa346b9 Mon Sep 17 00:00:00 2001 From: tower120 Date: Fri, 25 Aug 2023 15:31:27 +0300 Subject: [PATCH 29/35] any_value refactor --- .gitignore | 1 + CHANGELOG.md | 17 +++--- benches/element_clone.rs | 2 +- benches/insert.rs | 6 +- benches/push.rs | 6 +- src/any_value/lazy_clone.rs | 12 ++-- src/any_value/mod.rs | 104 +++++++++++++++++++------------- src/any_value/raw.rs | 115 +++++++++++++++++++++++++----------- src/any_value/wrapper.rs | 21 ++++--- src/any_vec.rs | 12 ++-- src/any_vec_raw.rs | 8 +-- src/any_vec_typed.rs | 2 +- src/element.rs | 26 ++++---- src/lib.rs | 21 +++---- src/ops/splice.rs | 12 ++-- src/ops/temp.rs | 18 +++--- tests/any_value.rs | 8 +-- tests/any_vec.rs | 8 +-- tests/any_vec_element.rs | 2 +- tests/any_vec_fuzzy.rs | 2 +- 20 files changed, 241 insertions(+), 162 deletions(-) diff --git a/.gitignore b/.gitignore index 8910b80..0524c17 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.idea +/.vscode /target /Cargo.lock \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index bf16c76..470ebb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,22 +2,21 @@ ## 0.13.0 ### Added -- `AnyVec` now can work with `AnyValuePtr`. +- `AnyVec` now can work with `AnyValueSizeless`. +- `any_value::traits` prelude. ### Optimized - `AnyValue`- family downcast now use provided type for compile-time optimization, instead of potentially unknown underlying type (which disabled optimization technique). ### Breaking Changes -- Changed AnyValue trait family names: - - `AnyValue` -> `AnyValueTyped`. - - `AnyValueUnknown` -> `AnyValueSized`. - - Introduced `AnyValuePtr`. +- `AnyValue` + `AnyValueUnknown` traits broken down into: + - `AnyValueUnknown` -> `AnyValueTypeless`. + - Introduced `AnyValueSizeless` - `AnyValue` that does know size and type. + - Added `any_value::move_out`, `any_value::move_out_w_size` helpers. - Changed AnyValueRaw non-owning wrappers names: - - `AnyValueRaw` -> `AnyValueRawTyped`. - - `AnyValueRawUnknown` -> `AnyValueRawSized`. - - Introduced `AnyValueRawPtr`. - + - `AnyValueRawUnknown` -> `AnyValueTypelessRaw`. + - Introduced `AnyValueSizelessRaw`. ## 0.12.0 ### Added diff --git a/benches/element_clone.rs b/benches/element_clone.rs index da746de..41efc9a 100644 --- a/benches/element_clone.rs +++ b/benches/element_clone.rs @@ -2,7 +2,7 @@ mod utils; use std::time::{Duration, Instant}; use criterion::{criterion_group, criterion_main, Criterion, black_box}; -use any_vec::any_value::{AnyValueCloneable, AnyValuePtr}; +use any_vec::any_value::{AnyValueCloneable, AnyValueSizeless}; use any_vec::AnyVec; use any_vec::traits::Cloneable; use crate::utils::bench_custom; diff --git a/benches/insert.rs b/benches/insert.rs index a8480ce..3656a50 100644 --- a/benches/insert.rs +++ b/benches/insert.rs @@ -2,7 +2,7 @@ use std::any::TypeId; use std::mem::size_of; use std::ptr::NonNull; use criterion::{criterion_group, criterion_main, Criterion}; -use any_vec::any_value::{AnyValueRawTyped}; +use any_vec::any_value::{AnyValueRaw}; use any_vec::AnyVec; const SIZE: usize = 10000; @@ -18,7 +18,7 @@ fn any_vec_insert_front(){ let mut any_vec: AnyVec = AnyVec::new::(); for i in 0..SIZE{ let raw_value = unsafe{ - AnyValueRawTyped::new( + AnyValueRaw::new( NonNull::from(&i).cast::(), size_of::(), TypeId::of::() @@ -46,7 +46,7 @@ fn any_vec_insert_back(){ let mut any_vec: AnyVec = AnyVec::new::(); for i in 0..SIZE{ let raw_value = unsafe{ - AnyValueRawTyped::new( + AnyValueRaw::new( NonNull::from(&i).cast::(), size_of::(), TypeId::of::() diff --git a/benches/push.rs b/benches/push.rs index e34e9f0..ad69c19 100644 --- a/benches/push.rs +++ b/benches/push.rs @@ -2,7 +2,7 @@ use std::any::TypeId; use std::mem::size_of; use std::ptr::NonNull; use criterion::{criterion_group, criterion_main, Criterion}; -use any_vec::any_value::{AnyValueRawPtr, AnyValueRawTyped}; +use any_vec::any_value::{AnyValueSizelessRaw, AnyValueRaw}; use any_vec::AnyVec; const SIZE: usize = 10000; @@ -33,7 +33,7 @@ fn any_vec_push_untyped(size: usize){ for i in 0..size{ let value = make_element(i); let raw_value = unsafe{ - AnyValueRawTyped::new( + AnyValueRaw::new( NonNull::from(&value).cast::(), size_of::(), TypeId::of::() @@ -47,7 +47,7 @@ fn any_vec_push_untyped_unchecked(size: usize){ for i in 0..size{ let value = make_element(i); let raw_value = unsafe{ - AnyValueRawPtr::new( + AnyValueSizelessRaw::new( NonNull::from(&value).cast::(), )}; unsafe{ diff --git a/src/any_value/lazy_clone.rs b/src/any_value/lazy_clone.rs index 65a7cd8..9779507 100644 --- a/src/any_value/lazy_clone.rs +++ b/src/any_value/lazy_clone.rs @@ -1,12 +1,14 @@ use std::any::TypeId; -use crate::any_value::{AnyValueTyped, AnyValueCloneable, AnyValueSized, AnyValuePtr}; +use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueTypeless, AnyValueSizeless}; /// Makes [`AnyValueCloneable`] actually [`Clone`]able. -/// Do clone on consumption. +/// Clone underlying value on consumption. /// /// Source must outlive `LazyClone`. `LazyClone` let you /// take element from one [`AnyVec`] and put it multiple times /// into another, without intermediate copies and cast to concrete type. +/// +/// Can be constructed by calling [AnyValueCloneable::lazy_clone]. /// /// [`AnyVec`]: crate::AnyVec pub struct LazyClone<'a, T: AnyValueCloneable>{ @@ -20,7 +22,7 @@ impl<'a, T: AnyValueCloneable> LazyClone<'a, T>{ } } -impl<'a, T: AnyValueCloneable> AnyValuePtr for LazyClone<'a, T> { +impl<'a, T: AnyValueCloneable> AnyValueSizeless for LazyClone<'a, T> { type Type = T::Type; #[inline] @@ -34,14 +36,14 @@ impl<'a, T: AnyValueCloneable> AnyValuePtr for LazyClone<'a, T> { } } -impl<'a, T: AnyValueCloneable + AnyValueSized> AnyValueSized for LazyClone<'a, T>{ +impl<'a, T: AnyValueCloneable + AnyValueTypeless> AnyValueTypeless for LazyClone<'a, T>{ #[inline] fn size(&self) -> usize { self.value.size() } } -impl<'a, T: AnyValueCloneable + AnyValueTyped> AnyValueTyped for LazyClone<'a, T>{ +impl<'a, T: AnyValueCloneable + AnyValue> AnyValue for LazyClone<'a, T>{ #[inline] fn value_typeid(&self) -> TypeId { self.value.value_typeid() diff --git a/src/any_value/mod.rs b/src/any_value/mod.rs index 494c73c..abe1edf 100644 --- a/src/any_value/mod.rs +++ b/src/any_value/mod.rs @@ -1,22 +1,32 @@ //! AnyValue is concept of type-erased object, that //! can be moved around without type knowledge. +//! +//! With default trait implementation, all "consume" operations +//! boils down to [move_into]. By redefining [move_into] and [Drop][^1] behavior - +//! you can have some additional logic on AnyValue consumption. +//! (Consumption - is any operation that "move out" data from AnyValue) //! -//! [AnyValuePtr] -> [AnyValueSized] -> [AnyValueTyped] +//! [AnyValueSizeless] -> [AnyValueTypeless] -> [AnyValue] //! -//! Some [AnyVec] operations will return [AnyValueTyped], -//! [AnyVec] operations also accept AnyValue as arguments. +//! # Usage +//! +//! Some [AnyVec] operations will accept and return [AnyValue]. //! This allows to move data between [AnyVec]s in //! fast, safe, type erased way. //! +//! [^1]: AnyValue could have blanket implementation for Drop as well, +//! but that is unstable Rust now. +//! //! [AnyVec]: crate::AnyVec +//! [move_into]: AnyValueSizeless::move_into mod wrapper; mod raw; mod lazy_clone; -pub use lazy_clone::{LazyClone}; +pub use lazy_clone::LazyClone; pub use wrapper::AnyValueWrapper; -pub use raw::{AnyValueRawTyped, AnyValueRawSized, AnyValueRawPtr}; +pub use raw::{AnyValueRaw, AnyValueTypelessRaw, AnyValueSizelessRaw}; use std::any::TypeId; use std::{mem, ptr}; @@ -32,8 +42,16 @@ impl Unknown { } } -/// AnyValue that can provide only object ptr. -pub trait AnyValuePtr { +/// Prelude for traits. +pub mod traits{ + pub use super::{AnyValueSizeless, AnyValueSizelessMut}; + pub use super::{AnyValueTypeless, AnyValueTypelessMut}; + pub use super::{AnyValue, AnyValueMut}; + pub use super::AnyValueCloneable; +} + +/// [AnyValue] that doesn't know its size or type, and can provide only object ptr. +pub trait AnyValueSizeless { /// Concrete type, or [`Unknown`] /// /// N.B. This should be in `AnyValueTyped`. It is here due to ergonomic reasons, @@ -59,7 +77,7 @@ pub trait AnyValuePtr { /// Move self into `out`. /// - /// Will do compile-time optimisation if type/size known. + /// Will do compile-time optimization if type/size known. /// /// # Safety /// @@ -67,9 +85,12 @@ pub trait AnyValuePtr { /// `out` must have at least `bytes_size` bytes. /// `KnownType` must be correct object type or [Unknown]. /// - /// Use [move_into] as safe version. + /// # Helpers + /// + /// Due to Rust limitations in generic department, you may found + /// useful helpers [move_out] and [move_out_w_size]. #[inline] - unsafe fn move_into(self, out: *mut u8, bytes_size: usize) + unsafe fn move_into(self, out: *mut u8, bytes_size: usize) where Self: Sized { copy_bytes::(self.as_bytes_ptr(), out, bytes_size); @@ -77,34 +98,33 @@ pub trait AnyValuePtr { } } -/// Move AnyValue into `out` location. +/// Wrapper for AnyValueTypeless around [move_into]. /// -/// If `T` has known [Type] compile time optimizations will be applied. -/// -/// [Type]: AnyValuePtr::Type +/// You may need this because of Rust's generics limitations. +/// +/// [move_into]: AnyValueSizeless::move_into #[inline] -pub fn move_into(this: T, out: *mut u8) { - let size = this.as_bytes().len(); - unsafe{ - move_into_w_size::(this, out, size); - } +pub unsafe fn move_out(this: T, out: *mut u8) { + let size = this.size(); + this.move_into::(out, size); } -/// [move_into] but with `bytes_size` hint. +/// Wrapper for AnyValueSizeless around [move_into]. /// -/// In loops, compiler may generate more optimized code, if will -/// know that the same size is used for all moves. -/// Acts the same as [move_into] if [Type] is known. +/// You may need this because of Rust's generics limitations. /// -/// [Type]: AnyValuePtr::Type +/// N.B. For moving out values of [Unknown] type, of the same size, in tight loops - +/// this may perform faster then [move_out], since compiler will be +/// able to optimize better, knowing that all values have the same size. +/// +/// [move_into]: AnyValueSizeless::move_into #[inline] -pub unsafe fn move_into_w_size(this: T, out: *mut u8, bytes_size: usize) { - copy_bytes::(this.as_bytes_ptr(), out, bytes_size); - mem::forget(this); +pub unsafe fn move_out_w_size(this: T, out: *mut u8, bytes_size: usize) { + this.move_into::(out, bytes_size); } -/// [AnyValuePtr] that know it's size. -pub trait AnyValueSized: AnyValuePtr { +/// [AnyValue] that doesn't know it's type, but know it's size. +pub trait AnyValueTypeless: AnyValueSizeless { /// Aligned. #[inline] fn as_bytes(&self) -> &[u8]{ @@ -118,8 +138,10 @@ pub trait AnyValueSized: AnyValuePtr { fn size(&self) -> usize; } -/// [AnyValueSized] that know it's type, possibly compiletime. -pub trait AnyValueTyped: AnyValueSized { +/// Type erased value interface. +/// +/// Know it's type and size, possibly compile-time. +pub trait AnyValue: AnyValueTypeless { fn value_typeid(&self) -> TypeId; #[inline] @@ -161,8 +183,8 @@ pub(crate) unsafe fn copy_bytes( } } -/// Mutable [AnyValuePtr]. -pub trait AnyValuePtrMut: AnyValuePtr { +/// Mutable [AnyValueSizeless]. +pub trait AnyValueSizelessMut: AnyValueSizeless { // Rust MIRI requires mut pointer to actually come from mut self. /// Aligned address. fn as_bytes_mut_ptr(&mut self) -> *mut u8; @@ -173,8 +195,8 @@ pub trait AnyValuePtrMut: AnyValuePtr { } } -/// Mutable [AnyValueSized]. -pub trait AnyValueSizedMut: AnyValueSized + AnyValuePtrMut { +/// Mutable [AnyValueTypeless]. +pub trait AnyValueTypelessMut: AnyValueTypeless + AnyValueSizelessMut { #[inline] fn as_bytes_mut(&mut self) -> &mut [u8]{ unsafe{std::slice::from_raw_parts_mut( @@ -184,7 +206,7 @@ pub trait AnyValueSizedMut: AnyValueSized + AnyValuePtrMut { } #[inline] - unsafe fn swap_unchecked(&mut self, other: &mut Other){ + unsafe fn swap_unchecked(&mut self, other: &mut Other){ // compile-time check if !Unknown::is::() { mem::swap( @@ -207,8 +229,8 @@ pub trait AnyValueSizedMut: AnyValueSized + AnyValuePtrMut { } } -/// Mutable [AnyValueTyped]. -pub trait AnyValueTypedMut: AnyValueSizedMut + AnyValueTyped { +/// Mutable [AnyValue]. +pub trait AnyValueMut: AnyValueTypelessMut + AnyValue { #[inline] fn downcast_mut(&mut self) -> Option<&mut T>{ if self.value_typeid() != TypeId::of::(){ @@ -224,7 +246,7 @@ pub trait AnyValueTypedMut: AnyValueSizedMut + AnyValueTyped { /// /// Panics, if type mismatch. #[inline] - fn swap(&mut self, other: &mut Other){ + fn swap(&mut self, other: &mut Other){ assert_eq!(self.value_typeid(), other.value_typeid()); unsafe{ self.swap_unchecked(other); @@ -232,8 +254,8 @@ pub trait AnyValueTypedMut: AnyValueSizedMut + AnyValueTyped { } } -/// [`LazyClone`] friendly [`AnyValuePtr`]. -pub trait AnyValueCloneable: AnyValuePtr { +/// [`LazyClone`] friendly [`AnyValueSizeless`]. +pub trait AnyValueCloneable: AnyValueSizeless { unsafe fn clone_into(&self, out: *mut u8); #[inline] diff --git a/src/any_value/raw.rs b/src/any_value/raw.rs index d8c7e67..8742796 100644 --- a/src/any_value/raw.rs +++ b/src/any_value/raw.rs @@ -1,15 +1,12 @@ use std::any::TypeId; use std::ptr::NonNull; -use crate::any_value::{AnyValueTyped, AnyValueTypedMut, AnyValueSizedMut, AnyValueSized, AnyValuePtr, AnyValuePtrMut}; +use crate::any_value::{AnyValue, AnyValueMut, AnyValueTypelessMut, AnyValueTypeless, AnyValueSizeless, AnyValueSizelessMut}; use crate::any_value::Unknown; -/// Non owning byte ptr wrapper for feeding AnyVec. -/// -/// Source should be forgotten, before pushing to AnyVec. -/// Contained value **WILL NOT** be dropped on AnyValueRawPtr drop. -/// -/// This is useful to fill [AnyVec] directly from raw bytes, -/// without intermediate casting to concrete type. +/// [AnyValueSizeless] non-owning byte ptr wrapper, that knows nothing about it's type. +/// +/// Source should be forgotten, before pushing to [AnyVec]. +/// Contained value **WILL NOT** be dropped on wrapper drop. /// /// # Example /// ```rust @@ -18,9 +15,9 @@ use crate::any_value::Unknown; /// # use std::mem::size_of; /// # use std::ptr::NonNull; /// # use any_vec::AnyVec; -/// # use any_vec::any_value::AnyValueRawPtr; +/// # use any_vec::any_value::AnyValueSizelessRaw; /// let s = String::from("Hello!"); -/// let raw_value = unsafe{AnyValueRawPtr::new( +/// let raw_value = unsafe{AnyValueSizelessRaw::new( /// NonNull::from(&s).cast::() /// )}; /// mem::forget(s); @@ -32,17 +29,17 @@ use crate::any_value::Unknown; /// ``` /// /// [AnyVec]: crate::AnyVec -pub struct AnyValueRawPtr { +pub struct AnyValueSizelessRaw { ptr: NonNull } -impl AnyValueRawPtr { +impl AnyValueSizelessRaw { #[inline] pub unsafe fn new(ptr: NonNull) -> Self{ Self{ptr} } } -impl AnyValuePtr for AnyValueRawPtr { +impl AnyValueSizeless for AnyValueSizelessRaw { type Type = Unknown; #[inline] @@ -50,28 +47,53 @@ impl AnyValuePtr for AnyValueRawPtr { self.ptr.as_ptr() } } -impl AnyValuePtrMut for AnyValueRawPtr { +impl AnyValueSizelessMut for AnyValueSizelessRaw { #[inline] fn as_bytes_mut_ptr(&mut self) -> *mut u8 { self.ptr.as_ptr() } } - -/// [AnyValueRawPtr] that know it's size. -pub struct AnyValueRawSized { +/// [AnyValueTypeless] byte ptr wrapper, that know it's type size. +/// +/// Source should be forgotten, before pushing to [AnyVec]. +/// Contained value **WILL NOT** be dropped on wrapper drop. +/// +/// # Example +/// ```rust +/// # use std::any::TypeId; +/// # use std::mem; +/// # use std::mem::size_of; +/// # use std::ptr::NonNull; +/// # use any_vec::AnyVec; +/// # use any_vec::any_value::AnyValueTypelessRaw; +/// let s = String::from("Hello!"); +/// let raw_value = unsafe{AnyValueTypelessRaw::new( +/// NonNull::from(&s).cast::(), +/// size_of::() +/// )}; +/// mem::forget(s); +/// +/// let mut any_vec: AnyVec = AnyVec::new::(); +/// unsafe{ +/// any_vec.push_unchecked(raw_value); +/// } +/// ``` +/// +/// [AnyVec]: crate::AnyVec +pub struct AnyValueTypelessRaw { ptr: NonNull, size: usize, } -impl AnyValueRawSized { +impl AnyValueTypelessRaw { #[inline] pub unsafe fn new(ptr: NonNull, size: usize) -> Self{ Self{ptr, size} } } -impl AnyValuePtr for AnyValueRawSized { +impl AnyValueSizeless for AnyValueTypelessRaw { type Type = Unknown; #[inline] @@ -79,38 +101,65 @@ impl AnyValuePtr for AnyValueRawSized { self.ptr.as_ptr() } } -impl AnyValuePtrMut for AnyValueRawSized { +impl AnyValueSizelessMut for AnyValueTypelessRaw { #[inline] fn as_bytes_mut_ptr(&mut self) -> *mut u8 { self.ptr.as_ptr() } } -impl AnyValueSized for AnyValueRawSized { +impl AnyValueTypeless for AnyValueTypelessRaw { #[inline] fn size(&self) -> usize { self.size } } -impl AnyValueSizedMut for AnyValueRawSized {} +impl AnyValueTypelessMut for AnyValueTypelessRaw {} -/// [AnyValueRawSized] that know it's type. -pub struct AnyValueRawTyped { - raw_unsafe: AnyValueRawSized, +/// [AnyValue] byte ptr wrapper, that know it's type. +/// +/// Source should be forgotten, before pushing to [AnyVec]. +/// Contained value **WILL NOT** be dropped on wrapper drop. +/// +/// # Example +/// ```rust +/// # use std::any::TypeId; +/// # use std::mem; +/// # use std::mem::size_of; +/// # use std::ptr::NonNull; +/// # use any_vec::AnyVec; +/// # use any_vec::any_value::AnyValueRaw; +/// let s = String::from("Hello!"); +/// let raw_value = unsafe{AnyValueRaw::new( +/// NonNull::from(&s).cast::(), +/// size_of::(), +/// TypeId::of::() +/// )}; +/// mem::forget(s); +/// +/// let mut any_vec: AnyVec = AnyVec::new::(); +/// unsafe{ +/// any_vec.push_unchecked(raw_value); +/// } +/// ``` +/// +/// [AnyVec]: crate::AnyVec +pub struct AnyValueRaw { + raw_unsafe: AnyValueTypelessRaw, typeid: TypeId } -impl AnyValueRawTyped { +impl AnyValueRaw { #[inline] pub unsafe fn new(ptr: NonNull, size: usize, typeid: TypeId) -> Self{ Self{ - raw_unsafe: AnyValueRawSized::new(ptr, size), + raw_unsafe: AnyValueTypelessRaw::new(ptr, size), typeid } } } -impl AnyValuePtr for AnyValueRawTyped { +impl AnyValueSizeless for AnyValueRaw { type Type = Unknown; #[inline] @@ -118,24 +167,24 @@ impl AnyValuePtr for AnyValueRawTyped { self.raw_unsafe.ptr.as_ptr() } } -impl AnyValuePtrMut for AnyValueRawTyped { +impl AnyValueSizelessMut for AnyValueRaw { #[inline] fn as_bytes_mut_ptr(&mut self) -> *mut u8 { self.raw_unsafe.ptr.as_ptr() } } -impl AnyValueSized for AnyValueRawTyped { +impl AnyValueTypeless for AnyValueRaw { #[inline] fn size(&self) -> usize { self.raw_unsafe.size } } -impl AnyValueTyped for AnyValueRawTyped { +impl AnyValue for AnyValueRaw { #[inline] fn value_typeid(&self) -> TypeId { self.typeid } } -impl AnyValueSizedMut for AnyValueRawTyped {} -impl AnyValueTypedMut for AnyValueRawTyped {} \ No newline at end of file +impl AnyValueTypelessMut for AnyValueRaw {} +impl AnyValueMut for AnyValueRaw {} \ No newline at end of file diff --git a/src/any_value/wrapper.rs b/src/any_value/wrapper.rs index 39522ad..2095d79 100644 --- a/src/any_value/wrapper.rs +++ b/src/any_value/wrapper.rs @@ -1,8 +1,13 @@ use std::any::TypeId; use std::mem::size_of; -use crate::any_value::{AnyValueTyped, AnyValueTypedMut, AnyValueSizedMut, AnyValueSized, AnyValuePtr, AnyValuePtrMut}; +use crate::any_value::{AnyValue, AnyValueMut, AnyValueTypelessMut, AnyValueTypeless, AnyValueSizeless, AnyValueSizelessMut}; -/// Helper struct to convert concrete type to [`AnyValueTypedMut`]. +/// Helper struct to convert concrete type to [`AnyValueMut`]. +/// +/// Unlike [AnyValueRaw] this one owns underlying value. So, its not +/// special in any way. +/// +/// [AnyValueRaw]: super::AnyValueRaw pub struct AnyValueWrapper{ value: T } @@ -13,7 +18,7 @@ impl AnyValueWrapper { } } -impl AnyValuePtr for AnyValueWrapper { +impl AnyValueSizeless for AnyValueWrapper { type Type = T; #[inline] @@ -21,23 +26,23 @@ impl AnyValuePtr for AnyValueWrapper { &self.value as *const _ as *const u8 } } -impl AnyValuePtrMut for AnyValueWrapper { +impl AnyValueSizelessMut for AnyValueWrapper { #[inline] fn as_bytes_mut_ptr(&mut self) -> *mut u8 { &mut self.value as *mut _ as *mut u8 } } -impl AnyValueSized for AnyValueWrapper { +impl AnyValueTypeless for AnyValueWrapper { #[inline] fn size(&self) -> usize { size_of::() } } -impl AnyValueTyped for AnyValueWrapper { +impl AnyValue for AnyValueWrapper { #[inline] fn value_typeid(&self) -> TypeId { TypeId::of::() } } -impl AnyValueSizedMut for AnyValueWrapper {} -impl AnyValueTypedMut for AnyValueWrapper {} \ No newline at end of file +impl AnyValueTypelessMut for AnyValueWrapper {} +impl AnyValueMut for AnyValueWrapper {} \ No newline at end of file diff --git a/src/any_vec.rs b/src/any_vec.rs index f7ba840..7db7eab 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -8,7 +8,7 @@ use std::ptr::NonNull; use std::{ptr, slice}; use std::slice::{from_raw_parts, from_raw_parts_mut}; use crate::{AnyVecTyped, into_range, mem, ops}; -use crate::any_value::{AnyValueTyped, AnyValuePtr}; +use crate::any_value::{AnyValue, AnyValueSizeless}; use crate::any_vec_raw::{AnyVecRaw, DropFn}; use crate::ops::{TempValue, Remove, SwapRemove, remove, swap_remove, Pop, pop}; use crate::ops::{Drain, Splice, drain, splice}; @@ -565,7 +565,7 @@ impl AnyVec /// * Panics if index is out of bounds. /// * Panics if out of memory. #[inline] - pub fn insert(&mut self, index: usize, value: V) { + pub fn insert(&mut self, index: usize, value: V) { self.raw.type_check(&value); unsafe{ self.raw.insert_unchecked(index, value); @@ -585,7 +585,7 @@ impl AnyVec /// /// [`insert`]: Self::insert #[inline] - pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { + pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { self.raw.insert_unchecked(index, value); } @@ -594,7 +594,7 @@ impl AnyVec /// * Panics if type mismatch. /// * Panics if out of memory. #[inline] - pub fn push(&mut self, value: V) { + pub fn push(&mut self, value: V) { self.raw.type_check(&value); unsafe{ self.raw.push_unchecked(value); @@ -613,7 +613,7 @@ impl AnyVec /// /// [`push`]: Self::push #[inline] - pub unsafe fn push_unchecked(&mut self, value: V) { + pub unsafe fn push_unchecked(&mut self, value: V) { self.raw.push_unchecked(value); } @@ -732,7 +732,7 @@ impl AnyVec -> Splice where I::IntoIter: ExactSizeIterator, - I::Item: AnyValueTyped + I::Item: AnyValue { let Range{start, end} = into_range(self.len(), range); ops::Iter(splice::Splice::new( diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index 4289834..36b8cf4 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -2,7 +2,7 @@ use std::{cmp, mem, ptr}; use std::alloc::Layout; use std::any::TypeId; use std::mem::size_of; -use crate::any_value::{AnyValueTyped, Unknown, AnyValuePtr}; +use crate::any_value::{AnyValue, Unknown, AnyValueSizeless}; use crate::assert_types_equal; use crate::clone_type::CloneFn; use crate::mem::{Mem, MemBuilder, MemResizable}; @@ -84,7 +84,7 @@ impl AnyVecRaw { } #[inline] - pub(crate) fn type_check(&self, value: &V){ + pub(crate) fn type_check(&self, value: &V){ assert_types_equal(value.value_typeid(), self.type_id); } @@ -154,7 +154,7 @@ impl AnyVecRaw { /// # Safety /// /// Type is not checked. - pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { + pub unsafe fn insert_unchecked(&mut self, index: usize, value: V) { assert!(index <= self.len, "Index out of range!"); self.reserve_one(); @@ -194,7 +194,7 @@ impl AnyVecRaw { /// /// Type is not checked. #[inline] - pub unsafe fn push_unchecked(&mut self, value: V) { + pub unsafe fn push_unchecked(&mut self, value: V) { self.reserve_one(); // Compile time type optimization diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index 4bf2c96..1d9120d 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -4,7 +4,7 @@ use std::mem::MaybeUninit; use std::ops::{Range, RangeBounds}; use std::ptr::NonNull; use std::slice; -use crate::any_value::{AnyValuePtr, AnyValueWrapper}; +use crate::any_value::{AnyValueSizeless, AnyValueWrapper}; use crate::any_vec_raw::AnyVecRaw; use crate::ops::{Iter, pop, remove, swap_remove, TempValue}; use crate::any_vec_ptr::AnyVecRawPtr; diff --git a/src/element.rs b/src/element.rs index 87d4861..355bcb5 100644 --- a/src/element.rs +++ b/src/element.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; -use crate::any_value::{AnyValueTyped, AnyValueCloneable, AnyValueTypedMut, AnyValueSizedMut, AnyValueSized, AnyValuePtr, AnyValuePtrMut}; +use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueTypelessMut, AnyValueTypeless, AnyValueSizeless, AnyValueSizelessMut}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{AnyVecPtr, IAnyVecPtr, IAnyVecRawPtr}; use crate::{AnyVec, mem}; @@ -21,7 +21,7 @@ use crate::traits::{Cloneable, None, Trait}; /// # Consuming /// /// Whenever you have `ElementPointer` as a value (from destructive [`AnyVec`] operations), -/// you can safely take pointed value, with [`AnyValueTyped::downcast`] or [`any_value::move_into`]. +/// you can safely take pointed value, with [`AnyValue::downcast`] or [`any_value::move_out`]. /// Otherwise, it will be destructed with destruction of `Element`. /// /// # Notes @@ -34,7 +34,7 @@ use crate::traits::{Cloneable, None, Trait}; /// [`drain`]: crate::AnyVec::drain /// [`splice`]: crate::AnyVec::splice /// [`any_value`]: crate::any_value -/// [`any_value::move_into`]: crate::any_value::move_into +/// [`any_value::move_out`]: crate::any_value::move_out pub struct ElementPointer<'a, AnyVecPtr: IAnyVecRawPtr>{ any_vec_ptr: AnyVecPtr, element: NonNull, @@ -58,7 +58,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ unsafe { self.any_vec_ptr.any_vec_raw() } } - /// Same as [`AnyValueTyped::downcast_ref`], but return `&'a T`, instead of `&T`. + /// Same as [`AnyValue::downcast_ref`], but return `&'a T`, instead of `&T`. #[inline] pub fn downcast_ref(&self) -> Option<&'a T>{ if self.value_typeid() != TypeId::of::(){ @@ -68,13 +68,13 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ } } - /// Same as [`AnyValuePtr::downcast_ref_unchecked`], but return `&'a T`, instead of `&T`. + /// Same as [`AnyValueSizeless::downcast_ref_unchecked`], but return `&'a T`, instead of `&T`. #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &'a T{ &*(self.as_bytes().as_ptr() as *const T) } - /// Same as [`AnyValueTypedMut::downcast_mut`], but return `&'a mut T`, instead of `&mut T`. + /// Same as [`AnyValueMut::downcast_mut`], but return `&'a mut T`, instead of `&mut T`. #[inline] pub fn downcast_mut(&mut self) -> Option<&'a mut T>{ if self.value_typeid() != TypeId::of::(){ @@ -84,7 +84,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> ElementPointer<'a, AnyVecPtr>{ } } - /// Same as [`AnyValuePtrMut::downcast_mut_unchecked`], but return `&'a mut T`, instead of `&mut T`. + /// Same as [`AnyValueSizelessMut::downcast_mut_unchecked`], but return `&'a mut T`, instead of `&mut T`. #[inline] pub unsafe fn downcast_mut_unchecked(&mut self) -> &'a mut T{ &mut *(self.as_bytes_mut().as_mut_ptr() as *mut T) @@ -102,7 +102,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Drop for ElementPointer<'a, AnyVecPtr>{ } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValuePtr for ElementPointer<'a, AnyVecPtr> { +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueSizeless for ElementPointer<'a, AnyVecPtr> { type Type = AnyVecPtr::Element; #[inline] @@ -110,27 +110,27 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValuePtr for ElementPointer<'a, AnyVecPtr> self.element.as_ptr() } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueSized for ElementPointer<'a, AnyVecPtr>{ +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueTypeless for ElementPointer<'a, AnyVecPtr>{ #[inline] fn size(&self) -> usize { self.any_vec_raw().element_layout().size() } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueTyped for ElementPointer<'a, AnyVecPtr>{ +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValue for ElementPointer<'a, AnyVecPtr>{ #[inline] fn value_typeid(&self) -> TypeId { self.any_vec_raw().type_id } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValuePtrMut for ElementPointer<'a, AnyVecPtr>{ +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueSizelessMut for ElementPointer<'a, AnyVecPtr>{ #[inline] fn as_bytes_mut_ptr(&mut self) -> *mut u8 { self.element.as_ptr() } } -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueSizedMut for ElementPointer<'a, AnyVecPtr>{} -impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueTypedMut for ElementPointer<'a, AnyVecPtr>{} +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueTypelessMut for ElementPointer<'a, AnyVecPtr>{} +impl<'a, AnyVecPtr: IAnyVecRawPtr> AnyValueMut for ElementPointer<'a, AnyVecPtr>{} impl<'a, Traits: ?Sized + Cloneable + Trait, M: MemBuilder> AnyValueCloneable for ElementPointer<'a, AnyVecPtr> diff --git a/src/lib.rs b/src/lib.rs index 2a89c17..339bd2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,6 @@ //! //! ```rust //! use any_vec::AnyVec; -//! use any_vec::any_value::AnyValueTyped; //! let mut vec: AnyVec = AnyVec::new::(); //! { //! // Typed operations. @@ -121,19 +120,21 @@ //! //! # AnyValue //! -//! Being type erased, [`AnyVec`] need a way to operate on untyped values safely. -//! Instead of working with plain `*mut u8`, [`AnyVec`] operates with [any_value]. +//! Being type erased, [AnyVec] needs a way to operate on untyped values safely. +//! Instead of working with plain `*mut u8`, [AnyVec] operates with [any_value]. //! -//! `AnyValueXXX` is a trait family, which provide operations to work with type erased values. -//! Any type that implements `AnyValueXXX` can be used with [`AnyVec`]. -//! `AnyValueXXX` interface allows to perform postponed operations on consumption. -//! This trick used heavily by [`AnyVec`] destructive operations, which instead of concrete -//! type return [AnyValueTyped], which perform actual operation on value drop. +//! [AnyValue] is a trait, that provide operations to work with type erased values. +//! Any type that implements [AnyValue] can be used with [AnyVec]. +//! [AnyValue] interface allows to perform postponed operations on consumption. +//! This trick used heavily by [AnyVec] destructive operations, which instead of concrete +//! type return [AnyValue], which perform actual operation on value drop. //! -//! Implementing `AnyValueXXXMut` and [`AnyValueCloneable`] makes type mutable and +//! Implementing [AnyValueMut] and [AnyValueCloneable] makes type mutable and //! cloneable respectively. //! -//! [AnyValueTyped]: any_value::AnyValueTyped +//! [AnyValue]: any_value::AnyValue +//! [AnyValueMut]: any_value::AnyValueMut +//! [AnyValueCloneable]: any_value::AnyValueCloneable mod any_vec; mod clone_type; diff --git a/src/ops/splice.rs b/src/ops/splice.rs index 190c57a..dfc9789 100644 --- a/src/ops/splice.rs +++ b/src/ops/splice.rs @@ -1,11 +1,11 @@ use crate::any_vec_ptr::IAnyVecRawPtr; use crate::{any_vec_ptr, assert_types_equal, Iter}; -use crate::any_value::{AnyValueTyped, move_into_w_size}; +use crate::any_value::{AnyValue, move_out_w_size}; use crate::ops::iter::Iterable; pub struct Splice<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> where - ReplaceIter::Item: AnyValueTyped + ReplaceIter::Item: AnyValue { iter: Iter<'a, AnyVecPtr>, start: usize, @@ -16,7 +16,7 @@ where impl<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> Splice<'a, AnyVecPtr, ReplaceIter> where - ReplaceIter::Item: AnyValueTyped + ReplaceIter::Item: AnyValue { #[inline] pub fn new( @@ -44,7 +44,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> Iterable for Splice<'a, AnyVecPtr, ReplaceIter> where - ReplaceIter::Item: AnyValueTyped + ReplaceIter::Item: AnyValue { type Iter = Iter<'a, AnyVecPtr>; @@ -63,7 +63,7 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> Drop for Splice<'a, AnyVecPtr, ReplaceIter> where - ReplaceIter::Item: AnyValueTyped + ReplaceIter::Item: AnyValue { fn drop(&mut self) { use any_vec_ptr::utils::*; @@ -105,7 +105,7 @@ where let mut ptr = element_mut_ptr_at(any_vec_ptr, self.start); while let Some(replace_element) = self.replace_with.next() { assert_types_equal(type_id, replace_element.value_typeid()); - move_into_w_size(replace_element, ptr, element_size); + move_out_w_size(replace_element, ptr, element_size); ptr = ptr.add(element_size); } } diff --git a/src/ops/temp.rs b/src/ops/temp.rs index d1e1b64..28144b6 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -1,6 +1,6 @@ use std::any::TypeId; use std::{mem, ptr}; -use crate::any_value::{AnyValueTyped, AnyValueCloneable, AnyValueTypedMut, AnyValueSizedMut, AnyValueSized, Unknown, AnyValuePtr, copy_bytes, AnyValuePtrMut}; +use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueTypelessMut, AnyValueTypeless, Unknown, AnyValueSizeless, copy_bytes, AnyValueSizelessMut}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{IAnyVecPtr, IAnyVecRawPtr}; use crate::AnyVec; @@ -48,7 +48,7 @@ impl TempValue{ } } -impl AnyValuePtr for TempValue { +impl AnyValueSizeless for TempValue { type Type = ::Element; #[inline] @@ -63,20 +63,20 @@ impl AnyValuePtr for TempValue { mem::forget(self); } } -impl AnyValuePtrMut for TempValue { +impl AnyValueSizelessMut for TempValue { #[inline] fn as_bytes_mut_ptr(&mut self) -> *mut u8 { // Somehow this is OK with MIRI. self.op.bytes() as *mut u8 } } -impl AnyValueSized for TempValue{ +impl AnyValueTypeless for TempValue{ #[inline] fn size(&self) -> usize { self.bytes_len() } } -impl AnyValueTyped for TempValue{ +impl AnyValue for TempValue{ #[inline] fn value_typeid(&self) -> TypeId { let typeid = TypeId::of::(); @@ -88,8 +88,8 @@ impl AnyValueTyped for TempValue{ } } -impl AnyValueSizedMut for TempValue {} -impl AnyValueTypedMut for TempValue {} +impl AnyValueTypelessMut for TempValue {} +impl AnyValueMut for TempValue {} impl AnyValueCloneable for TempValue where @@ -111,12 +111,12 @@ impl Drop for TempValue{ let element = self.op.bytes() as *mut u8; // compile-time check - if Unknown::is::<::Type>() { + if Unknown::is::<::Type>() { if let Some(drop_fn) = drop_fn{ (drop_fn)(element, 1); } } else { - ptr::drop_in_place(element as *mut ::Type); + ptr::drop_in_place(element as *mut ::Type); } } self.op.consume(); diff --git a/tests/any_value.rs b/tests/any_value.rs index 1d0189c..dc255fe 100644 --- a/tests/any_value.rs +++ b/tests/any_value.rs @@ -1,7 +1,7 @@ use std::any::TypeId; use std::mem::size_of; use std::ptr::NonNull; -use any_vec::any_value::{AnyValueTyped, AnyValueTypedMut, AnyValueRawTyped, AnyValueWrapper}; +use any_vec::any_value::{AnyValue, AnyValueMut, AnyValueRaw, AnyValueWrapper}; #[test] fn swap_test(){ @@ -21,13 +21,13 @@ fn swap_test(){ let mut s2 = String::from("2"); let mut a1 = unsafe{ - AnyValueRawTyped::new( + AnyValueRaw::new( NonNull::from(&mut s1).cast::(), size_of::(), TypeId::of::() )}; let mut a2 = unsafe{ - AnyValueRawTyped::new( + AnyValueRaw::new( NonNull::from(&mut s2).cast::(), size_of::(), TypeId::of::() @@ -42,7 +42,7 @@ fn swap_test(){ { let mut s1 = String::from("1"); let mut a1 = unsafe{ - AnyValueRawTyped::new( + AnyValueRaw::new( NonNull::from(&mut s1).cast::(), size_of::(), TypeId::of::() diff --git a/tests/any_vec.rs b/tests/any_vec.rs index d4efc64..dcd85ab 100644 --- a/tests/any_vec.rs +++ b/tests/any_vec.rs @@ -4,7 +4,7 @@ use std::mem::forget; use std::ptr::NonNull; use itertools::assert_equal; use any_vec::AnyVec; -use any_vec::any_value::{AnyValueTypedMut, AnyValueRawTyped, AnyValueWrapper}; +use any_vec::any_value::{AnyValueMut, AnyValueRaw, AnyValueWrapper}; use any_vec::mem::Stack; #[allow(dead_code)] @@ -39,21 +39,21 @@ fn any_value_raw_test() { unsafe{ let str1 = "Hello".to_string(); - any_vec.push(AnyValueRawTyped::new( + any_vec.push(AnyValueRaw::new( NonNull::from(&str1).cast::(), size_of::(), TypeId::of::() )); forget(str1); let str2 = " to ".to_string(); - any_vec.push(AnyValueRawTyped::new( + any_vec.push(AnyValueRaw::new( NonNull::from(&str2).cast::(), size_of::(), TypeId::of::() )); forget(str2); let str3 = "world".to_string(); - any_vec.push(AnyValueRawTyped::new( + any_vec.push(AnyValueRaw::new( NonNull::from(&str3).cast::(), size_of::(), TypeId::of::() )); diff --git a/tests/any_vec_element.rs b/tests/any_vec_element.rs index 4c93a17..de5c70b 100644 --- a/tests/any_vec_element.rs +++ b/tests/any_vec_element.rs @@ -1,6 +1,6 @@ use std::any::TypeId; use itertools::{assert_equal}; -use any_vec::any_value::{AnyValueTyped, AnyValueCloneable, LazyClone}; +use any_vec::any_value::{AnyValue, AnyValueCloneable, LazyClone}; use any_vec::AnyVec; use any_vec::element::ElementReference; use any_vec::mem::{MemBuilder, Stack}; diff --git a/tests/any_vec_fuzzy.rs b/tests/any_vec_fuzzy.rs index 9a40beb..1968a93 100644 --- a/tests/any_vec_fuzzy.rs +++ b/tests/any_vec_fuzzy.rs @@ -2,7 +2,7 @@ use std::cmp; use std::ops::Range; use itertools::assert_equal; use rand::Rng; -use any_vec::any_value::{AnyValueTyped, AnyValueWrapper}; +use any_vec::any_value::{AnyValue, AnyValueWrapper}; use any_vec::AnyVec; const REPEATS: usize = if cfg!(miri){ 4 }else{ 100 }; From 4e73d03418b0d90489208834d5c18393586fd42b Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 25 Aug 2023 16:12:28 +0300 Subject: [PATCH 30/35] v0.13.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bf693eb..26b646f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "any_vec" authors = ["Andrey Diduh "] license = "MIT OR Apache-2.0" -version = "0.12.0" +version = "0.13.0" edition = "2021" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." repository = "https://github.com/tower120/any_vec" From 0bec11c4aec30dad8ef88cd12a561f44840f9a5a Mon Sep 17 00:00:00 2001 From: tower120 Date: Wed, 8 May 2024 07:28:41 +0300 Subject: [PATCH 31/35] CI update CI update + stable/nightly boundary warning fix --- .github/workflows/ci.yml | 69 +++++++++++++++------------------------- src/element.rs | 4 +-- src/iter.rs | 28 +++++++++------- 3 files changed, 45 insertions(+), 56 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dcfc895..03c5aac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,7 @@ name: CI on: + workflow_dispatch: push: branches: [ main, dev ] pull_request: @@ -11,65 +12,47 @@ env: jobs: build: + name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - #- uses: ATiltedTree/setup-rust@v1 - # with: - # rust-version: stable - - name: Build - run: RUSTFLAGS="--deny warnings" cargo build - - build-all-features: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - #- uses: ATiltedTree/setup-rust@v1 - # with: - # rust-version: stable - - name: Build with all features - run: RUSTFLAGS="--deny warnings" cargo build --all-features + - uses: actions/checkout@v4 + - run: RUSTFLAGS="--deny warnings" cargo build + - run: RUSTFLAGS="--deny warnings" cargo build --all-features tests: + name: Run careful tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - #- uses: ATiltedTree/setup-rust@v1 - # with: - # rust-version: stable - - name: Run tests - run: RUSTFLAGS="--deny warnings" cargo test --all-features + - uses: dtolnay/rust-toolchain@nightly + - uses: taiki-e/install-action@v2 + with: + tool: cargo-careful + - uses: actions/checkout@v4 + - run: RUSTFLAGS="--deny warnings" cargo +nightly careful test + - run: RUSTFLAGS="--deny warnings" cargo +nightly careful test --all-features miri: + name: Miri tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - #- uses: ATiltedTree/setup-rust@v1 - # with: - # rust-version: stable - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@nightly with: - toolchain: nightly - components: miri - - name: Miri tests - run: RUSTFLAGS="--deny warnings" cargo +nightly miri test + toolchain: nightly + components: miri + - uses: actions/checkout@v4 + - run: RUSTFLAGS="--deny warnings" cargo +nightly miri test + - run: RUSTFLAGS="--deny warnings" cargo +nightly miri test --all-features benches: + name: Build benchmarks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - #- uses: ATiltedTree/setup-rust@v1 - # with: - # rust-version: stable - - name: Build benches - run: RUSTFLAGS="--deny warnings" cargo build --benches + - uses: actions/checkout@v4 + - run: RUSTFLAGS="--deny warnings" cargo build --benches doc: + name: Build doc runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - #- uses: ATiltedTree/setup-rust@v1 - # with: - # rust-version: stable - - name: Build doc - run: RUSTDOCFLAGS="--deny warnings" cargo doc --lib \ No newline at end of file + - uses: actions/checkout@v4 + - run: RUSTDOCFLAGS="--deny warnings" cargo doc --lib \ No newline at end of file diff --git a/src/element.rs b/src/element.rs index 355bcb5..4e07f84 100644 --- a/src/element.rs +++ b/src/element.rs @@ -22,12 +22,12 @@ use crate::traits::{Cloneable, None, Trait}; /// /// Whenever you have `ElementPointer` as a value (from destructive [`AnyVec`] operations), /// you can safely take pointed value, with [`AnyValue::downcast`] or [`any_value::move_out`]. -/// Otherwise, it will be destructed with destruction of `Element`. +/// Otherwise, it will be destructed with destruction of [`Element`]. /// /// # Notes /// /// `ElementPointer` have it's own implementation of `downcast_` family (which return `&'a T`, instead of `&T`). -/// This is done, so you don't have to keep `ElementRef`/`ElementMut` alive, while casting to concrete type. +/// This is done, so you don't have to keep [`ElementRef`]/[`ElementMut`] alive, while casting to concrete type. /// /// [`AnyVec`]: crate::AnyVec /// [`AnyVec::get`]: crate::AnyVec::get diff --git a/src/iter.rs b/src/iter.rs index fe93116..cd998ce 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -134,34 +134,42 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr, IterItem: IteratorItem<'a, AnyVecPtr>> FusedI {} -// According to https://github.com/rust-lang/rust/issues/93367#issuecomment-1154832012 -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Trait, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecPtr>> Send +#[allow(renamed_and_removed_lints, suspicious_auto_trait_impls)] +unsafe impl<'a, Traits, M, IterItem> Send for Iter<'a, AnyVecPtr, IterItem> where + Traits: ?Sized + Trait, + M: MemBuilder, + IterItem: IteratorItem<'a, AnyVecPtr>, AnyVec: Send {} -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, T, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecRawPtr>> Send +#[allow(renamed_and_removed_lints, suspicious_auto_trait_impls)] +unsafe impl<'a, T, M, IterItem> Send for Iter<'a, AnyVecRawPtr, IterItem> where + M: MemBuilder, + IterItem: IteratorItem<'a, AnyVecRawPtr>, AnyVecTyped<'a, T, M>: Send {} -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, Traits: ?Sized + Trait, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecPtr>> Sync +unsafe impl<'a, Traits, M, IterItem> Sync for Iter<'a, AnyVecPtr, IterItem> where + Traits: ?Sized + Trait, + M: MemBuilder, + IterItem: IteratorItem<'a, AnyVecPtr>, AnyVec: Sync {} -#[allow(suspicious_auto_trait_impls)] -unsafe impl<'a, T: Sync, M: MemBuilder, IterItem: IteratorItem<'a, AnyVecRawPtr>> Sync +unsafe impl<'a, T, M, IterItem> Sync for Iter<'a, AnyVecRawPtr, IterItem> where + T: Sync, + M: MemBuilder, + IterItem: IteratorItem<'a, AnyVecRawPtr>, AnyVecTyped<'a, T, M>: Sync {} @@ -222,8 +230,6 @@ impl<'a, Traits: ?Sized + Trait, M: MemBuilder> Clone for ElementMutIterItem<'a, } -//pub type Iter<'a, Traits> = IterBase<'a, Traits, ElementIterItem<'a, Traits>>; - /// Reference [`AnyVec`] iterator. Return [`ElementRef`] items. /// /// [`AnyVec`]: crate::AnyVec From 168276ee139d22fe8b3ce0480aadc628586842a4 Mon Sep 17 00:00:00 2001 From: tower120 Date: Wed, 8 May 2024 11:47:45 +0300 Subject: [PATCH 32/35] copy utils refactor --- CHANGELOG.md | 4 +++ src/any_value/mod.rs | 70 ++++++------------------------------ src/element.rs | 4 +-- src/lib.rs | 80 ++++++++++++++---------------------------- src/ops/remove.rs | 4 +-- src/ops/splice.rs | 6 ++-- src/ops/swap_remove.rs | 22 ++++-------- src/ops/temp.rs | 6 ++-- 8 files changed, 58 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 470ebb3..80e2720 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.14.0 +### Removed +- Helpers `any_value::move_out`, `any_value::move_out_w_size` removed as redundant. + ## 0.13.0 ### Added - `AnyVec` now can work with `AnyValueSizeless`. diff --git a/src/any_value/mod.rs b/src/any_value/mod.rs index abe1edf..243f6d5 100644 --- a/src/any_value/mod.rs +++ b/src/any_value/mod.rs @@ -26,12 +26,11 @@ mod lazy_clone; pub use lazy_clone::LazyClone; pub use wrapper::AnyValueWrapper; -pub use raw::{AnyValueRaw, AnyValueTypelessRaw, AnyValueSizelessRaw}; +pub use raw::{AnyValueRaw, AnyValueSizelessRaw, AnyValueTypelessRaw}; use std::any::TypeId; use std::{mem, ptr}; use std::mem::{MaybeUninit, size_of}; -use crate::{copy_bytes_nonoverlapping, swap_bytes_nonoverlapping}; /// Marker for unknown type. pub struct Unknown; @@ -81,48 +80,19 @@ pub trait AnyValueSizeless { /// /// # Safety /// - /// `bytes_size` must be correct object size. - /// `out` must have at least `bytes_size` bytes. - /// `KnownType` must be correct object type or [Unknown]. - /// - /// # Helpers - /// - /// Due to Rust limitations in generic department, you may found - /// useful helpers [move_out] and [move_out_w_size]. + /// - `bytes_size` must be correct object size. + /// - `out` must not overlap with `self`. + /// - `out` must have at least `bytes_size` bytes. + /// - `KnownType` must be correct object type or [Unknown]. #[inline] unsafe fn move_into(self, out: *mut u8, bytes_size: usize) where Self: Sized { - copy_bytes::(self.as_bytes_ptr(), out, bytes_size); + crate::copy_nonoverlapping_value::(self.as_bytes_ptr(), out, bytes_size); mem::forget(self); } } -/// Wrapper for AnyValueTypeless around [move_into]. -/// -/// You may need this because of Rust's generics limitations. -/// -/// [move_into]: AnyValueSizeless::move_into -#[inline] -pub unsafe fn move_out(this: T, out: *mut u8) { - let size = this.size(); - this.move_into::(out, size); -} - -/// Wrapper for AnyValueSizeless around [move_into]. -/// -/// You may need this because of Rust's generics limitations. -/// -/// N.B. For moving out values of [Unknown] type, of the same size, in tight loops - -/// this may perform faster then [move_out], since compiler will be -/// able to optimize better, knowing that all values have the same size. -/// -/// [move_into]: AnyValueSizeless::move_into -#[inline] -pub unsafe fn move_out_w_size(this: T, out: *mut u8, bytes_size: usize) { - this.move_into::(out, bytes_size); -} - /// [AnyValue] that doesn't know it's type, but know it's size. pub trait AnyValueTypeless: AnyValueSizeless { /// Aligned. @@ -165,24 +135,6 @@ pub trait AnyValue: AnyValueTypeless { } } -/// Helper function, which utilize type knowledge. -#[inline] -pub(crate) unsafe fn copy_bytes( - input: *const u8, out: *mut u8, bytes_size: usize -) { - if !Unknown::is::() { - ptr::copy_nonoverlapping( - input as *const KnownType, - out as *mut KnownType, - 1); - } else { - copy_bytes_nonoverlapping( - input, - out, - bytes_size); - } -} - /// Mutable [AnyValueSizeless]. pub trait AnyValueSizelessMut: AnyValueSizeless { // Rust MIRI requires mut pointer to actually come from mut self. @@ -197,7 +149,7 @@ pub trait AnyValueSizelessMut: AnyValueSizeless { /// Mutable [AnyValueTypeless]. pub trait AnyValueTypelessMut: AnyValueTypeless + AnyValueSizelessMut { - #[inline] + #[inline(always)] fn as_bytes_mut(&mut self) -> &mut [u8]{ unsafe{std::slice::from_raw_parts_mut( self.as_bytes_mut_ptr(), @@ -205,7 +157,7 @@ pub trait AnyValueTypelessMut: AnyValueTypeless + AnyValueSizelessMut { )} } - #[inline] + #[inline(always)] unsafe fn swap_unchecked(&mut self, other: &mut Other){ // compile-time check if !Unknown::is::() { @@ -220,7 +172,7 @@ pub trait AnyValueTypelessMut: AnyValueTypeless + AnyValueSizelessMut { ); } else { let bytes = self.as_bytes_mut(); - swap_bytes_nonoverlapping( + ptr::swap_nonoverlapping( bytes.as_mut_ptr(), other.as_bytes_mut().as_mut_ptr(), bytes.len() @@ -231,7 +183,7 @@ pub trait AnyValueTypelessMut: AnyValueTypeless + AnyValueSizelessMut { /// Mutable [AnyValue]. pub trait AnyValueMut: AnyValueTypelessMut + AnyValue { - #[inline] + #[inline(always)] fn downcast_mut(&mut self) -> Option<&mut T>{ if self.value_typeid() != TypeId::of::(){ None @@ -245,7 +197,7 @@ pub trait AnyValueMut: AnyValueTypelessMut + AnyValue { /// # Panic /// /// Panics, if type mismatch. - #[inline] + #[inline(always)] fn swap(&mut self, other: &mut Other){ assert_eq!(self.value_typeid(), other.value_typeid()); unsafe{ diff --git a/src/element.rs b/src/element.rs index 4e07f84..7355174 100644 --- a/src/element.rs +++ b/src/element.rs @@ -21,7 +21,8 @@ use crate::traits::{Cloneable, None, Trait}; /// # Consuming /// /// Whenever you have `ElementPointer` as a value (from destructive [`AnyVec`] operations), -/// you can safely take pointed value, with [`AnyValue::downcast`] or [`any_value::move_out`]. +/// you can safely take pointed value with [`AnyValue::downcast`], or unsafely +/// take its content with [`AnyValueSizeless::move_into`]. /// Otherwise, it will be destructed with destruction of [`Element`]. /// /// # Notes @@ -34,7 +35,6 @@ use crate::traits::{Cloneable, None, Trait}; /// [`drain`]: crate::AnyVec::drain /// [`splice`]: crate::AnyVec::splice /// [`any_value`]: crate::any_value -/// [`any_value::move_out`]: crate::any_value::move_out pub struct ElementPointer<'a, AnyVecPtr: IAnyVecRawPtr>{ any_vec_ptr: AnyVecPtr, element: NonNull, diff --git a/src/lib.rs b/src/lib.rs index 339bd2e..6f19169 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,9 +144,9 @@ mod any_vec_typed; mod iter; use std::any::TypeId; -pub use crate::any_vec::{AnyVec, AnyVecMut, AnyVecRef, SatisfyTraits, traits, RawParts}; +pub use crate::any_vec::{AnyVec, AnyVecMut, AnyVecRef, RawParts, SatisfyTraits, traits}; pub use any_vec_typed::AnyVecTyped; -pub use iter::{ElementIterator, Iter, IterRef, IterMut}; +pub use iter::{ElementIterator, Iter, IterMut, IterRef}; pub mod mem; pub mod any_value; @@ -155,32 +155,13 @@ pub mod element; use std::ptr; use std::ops::{Bound, Range, RangeBounds}; +use crate::any_value::Unknown; -// This is faster then ptr::copy_nonoverlapping, -// when count is runtime value, and count is small. -#[inline] -unsafe fn copy_bytes_nonoverlapping(src: *const u8, dst: *mut u8, count: usize){ - // Somehow, it looks ok now. - // Tracking issue https://github.com/rust-lang/rust/issues/97022 - ptr::copy_nonoverlapping(src, dst, count); - return; - - /*// MIRI hack - if cfg!(miri) - // || count >= 128 - { - ptr::copy_nonoverlapping(src, dst, count); - return; - } - - for i in 0..count{ - *dst.add(i) = *src.add(i); - }*/ -} - -// This is faster then ptr::copy, -// when count is runtime value, and count is small. -#[inline] +/// This is faster then ptr::copy, +/// when count is runtime value, and count is small. +/// +/// Last time benchmarked on nightly 1.80 +#[inline(always)] unsafe fn copy_bytes(src: *const u8, dst: *mut u8, count: usize){ // MIRI hack if cfg!(miri) @@ -195,32 +176,23 @@ unsafe fn copy_bytes(src: *const u8, dst: *mut u8, count: usize){ } } - -// same as copy_bytes_nonoverlapping but for swap_nonoverlapping. -#[inline] -unsafe fn swap_bytes_nonoverlapping(src: *mut u8, dst: *mut u8, count: usize){ - // MIRI hack - if cfg!(miri) { - let mut tmp = Vec::::new(); - tmp.resize(count, 0); - - // src -> tmp - ptr::copy_nonoverlapping(src, tmp.as_mut_ptr(), count); - // dst -> src - ptr::copy_nonoverlapping(dst, src, count); - // tmp -> dst - ptr::copy_nonoverlapping(tmp.as_ptr(), dst, count); - - return; - } - - for i in 0..count{ - let src_pos = src.add(i); - let dst_pos = dst.add(i); - - let tmp = *src_pos; - *src_pos = *dst_pos; - *dst_pos = tmp; +/// One element copy_nonoverlapping, that utilize type knowledge. +#[inline(always)] +pub(crate) unsafe fn copy_nonoverlapping_value( + input: *const u8, out: *mut u8, value_size: usize +) { + if !Unknown::is::() { + ptr::copy_nonoverlapping( + input as *const KnownType, + out as *mut KnownType, + 1 + ); + } else { + ptr::copy_nonoverlapping( + input, + out, + value_size + ); } } @@ -247,4 +219,4 @@ fn into_range( #[inline] fn assert_types_equal(t1: TypeId, t2: TypeId){ assert_eq!(t1, t2, "Type mismatch!"); -} +} \ No newline at end of file diff --git a/src/ops/remove.rs b/src/ops/remove.rs index b7e4361..e7210ec 100644 --- a/src/ops/remove.rs +++ b/src/ops/remove.rs @@ -45,12 +45,12 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Remove<'a, AnyVecPtr>{ if !Unknown::is::() { let dst = self.bytes() as *mut AnyVecPtr::Element; let src = dst.add(1); - ptr::copy(src, dst,self.last_index - self.index); + ptr::copy(src, dst, self.last_index - self.index); } else { let size = self.any_vec_ptr.any_vec_raw().element_layout().size(); let dst = self.bytes() as *mut u8; let src = dst.add(size); - crate::copy_bytes(src, dst,size * (self.last_index - self.index)); + crate::copy_bytes(src, dst, size * (self.last_index - self.index)); } // 3. shrink len `self.any_vec.len -= 1` diff --git a/src/ops/splice.rs b/src/ops/splice.rs index dfc9789..75e925b 100644 --- a/src/ops/splice.rs +++ b/src/ops/splice.rs @@ -1,6 +1,6 @@ use crate::any_vec_ptr::IAnyVecRawPtr; use crate::{any_vec_ptr, assert_types_equal, Iter}; -use crate::any_value::{AnyValue, move_out_w_size}; +use crate::any_value::{AnyValue, AnyValueSizeless}; use crate::ops::iter::Iterable; pub struct Splice<'a, AnyVecPtr: IAnyVecRawPtr, ReplaceIter: ExactSizeIterator> @@ -105,7 +105,9 @@ where let mut ptr = element_mut_ptr_at(any_vec_ptr, self.start); while let Some(replace_element) = self.replace_with.next() { assert_types_equal(type_id, replace_element.value_typeid()); - move_out_w_size(replace_element, ptr, element_size); + replace_element.move_into::< + ::Type + >(ptr, element_size); ptr = ptr.add(element_size); } } diff --git a/src/ops/swap_remove.rs b/src/ops/swap_remove.rs index f6fc563..07b240e 100644 --- a/src/ops/swap_remove.rs +++ b/src/ops/swap_remove.rs @@ -1,7 +1,5 @@ use std::marker::PhantomData; -use std::ptr; -use crate::copy_bytes_nonoverlapping; -use crate::any_value::Unknown; +use crate::copy_nonoverlapping_value; use crate::any_vec_ptr::IAnyVecRawPtr; use crate::any_vec_ptr::utils::{element_mut_ptr_at, element_ptr_at}; use crate::any_vec_raw::AnyVecRaw; @@ -49,19 +47,11 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for SwapRemove<'a, AnyVecPtr>{ let any_vec_raw = self.any_vec_ptr.any_vec_raw_mut(); if self.element as *const u8 != last_element { - if !Unknown::is::() { - ptr::copy_nonoverlapping( - last_element as *const AnyVecPtr::Element, - self.element as *mut AnyVecPtr::Element, - 1 - ); - } else { - copy_bytes_nonoverlapping( - last_element, - self.element, - any_vec_raw.element_layout().size() - ); - } + copy_nonoverlapping_value::( + last_element, + self.element, + any_vec_raw.element_layout().size() + ); } // 3. shrink len `self.any_vec.len -= 1` diff --git a/src/ops/temp.rs b/src/ops/temp.rs index 28144b6..a54794e 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -1,9 +1,9 @@ use std::any::TypeId; use std::{mem, ptr}; -use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueTypelessMut, AnyValueTypeless, Unknown, AnyValueSizeless, copy_bytes, AnyValueSizelessMut}; +use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueSizeless, AnyValueSizelessMut, AnyValueTypeless, AnyValueTypelessMut, Unknown}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{IAnyVecPtr, IAnyVecRawPtr}; -use crate::AnyVec; +use crate::{AnyVec, copy_nonoverlapping_value}; use crate::traits::Cloneable; pub trait Operation { @@ -58,7 +58,7 @@ impl AnyValueSizeless for TempValue { #[inline] unsafe fn move_into(mut self, out: *mut u8, bytes_size: usize) { - copy_bytes::(self.as_bytes_ptr(), out, bytes_size); + copy_nonoverlapping_value::(self.as_bytes_ptr(), out, bytes_size); self.op.consume(); mem::forget(self); } From ebf150059f297220ff71d789f1593427f31f6298 Mon Sep 17 00:00:00 2001 From: tower120 Date: Fri, 10 May 2024 08:51:21 +0300 Subject: [PATCH 33/35] no_std + no_alloc --- .github/workflows/ci.yml | 14 ++++++++++++- CHANGELOG.md | 3 +++ Cargo.toml | 17 ++++++++++++---- Readme.md | 4 ++++ doc.bat | 5 +++++ src/any_value/lazy_clone.rs | 2 +- src/any_value/mod.rs | 10 +++++----- src/any_value/raw.rs | 4 ++-- src/any_value/wrapper.rs | 4 ++-- src/any_vec.rs | 40 ++++++++++++++++++------------------- src/any_vec_ptr.rs | 12 +++++------ src/any_vec_raw.rs | 8 ++++---- src/any_vec_typed.rs | 14 ++++++------- src/element.rs | 10 +++++----- src/iter.rs | 8 ++++---- src/lib.rs | 22 +++++++++++++++----- src/mem/empty.rs | 2 +- src/mem/heap.rs | 10 ++++++---- src/mem/mod.rs | 10 ++++++++-- src/mem/stack.rs | 4 ++-- src/mem/stack_n.rs | 4 ++-- src/ops/iter.rs | 2 +- src/ops/pop.rs | 2 +- src/ops/remove.rs | 4 ++-- src/ops/swap_remove.rs | 2 +- src/ops/temp.rs | 4 ++-- 26 files changed, 137 insertions(+), 84 deletions(-) create mode 100644 doc.bat diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03c5aac..3866d38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,6 +18,7 @@ jobs: - uses: actions/checkout@v4 - run: RUSTFLAGS="--deny warnings" cargo build - run: RUSTFLAGS="--deny warnings" cargo build --all-features + - run: RUSTFLAGS="--deny warnings" cargo build --no-default-features tests: name: Run careful tests @@ -55,4 +56,15 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: RUSTDOCFLAGS="--deny warnings" cargo doc --lib \ No newline at end of file + - run: RUSTDOCFLAGS="--deny warnings" cargo doc --lib --all-features + + docrs: + name: Build docrs + runs-on: ubuntu-latest + steps: + - uses: dtolnay/rust-toolchain@nightly + - uses: actions/checkout@v4 + - run: + RUSTFLAGS="--deny warnings" + RUSTDOCFLAGS="--cfg docsrs" + cargo +nightly doc --lib --all-features \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 80e2720..354d8fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog ## 0.14.0 +### Added +- Now library `no_std` friendly. + ### Removed - Helpers `any_value::move_out`, `any_value::move_out_w_size` removed as redundant. diff --git a/Cargo.toml b/Cargo.toml index 26b646f..1791bb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,15 +6,24 @@ version = "0.13.0" edition = "2021" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." repository = "https://github.com/tower120/any_vec" -keywords = ["vec", "any", "container"] -categories = ["data-structures"] +keywords = ["vec", "any", "container", "no_std"] +categories = ["data-structures", "no-std", "no-std::no-alloc"] exclude = [".github"] +[features] +default = ["alloc"] +# Include alloc crate. This allows to use mem::Heap. +alloc = [] + +[package.metadata.docs.rs] +features = [] +rustdoc-args = ["--cfg", "docsrs"] + [dependencies] [dev-dependencies] -itertools = "0.10.3" -criterion = "0.3.5" +itertools = "0.12.1" +criterion = "0.5.1" rand = "0.8.5" impls = "1.0.3" diff --git a/Readme.md b/Readme.md index f5aa8be..1dd4f57 100644 --- a/Readme.md +++ b/Readme.md @@ -95,6 +95,10 @@ fn self_push_first_element(any_vec: &mut AnyVec){ `MemBuilder` interface, being stateful, allow to make `Mem`, which can work with complex custom allocators. +## no_std + no_alloc + +This is `no_std` library, which can work without `alloc` too. + ### Changelog See [CHANGELOG.md](CHANGELOG.md) for version differences. diff --git a/doc.bat b/doc.bat new file mode 100644 index 0000000..6754b5c --- /dev/null +++ b/doc.bat @@ -0,0 +1,5 @@ +@echo off +setlocal +set RUSTDOCFLAGS=--cfg docsrs +cargo +nightly doc --lib --no-deps %1 +endlocal \ No newline at end of file diff --git a/src/any_value/lazy_clone.rs b/src/any_value/lazy_clone.rs index 9779507..a1170d7 100644 --- a/src/any_value/lazy_clone.rs +++ b/src/any_value/lazy_clone.rs @@ -1,4 +1,4 @@ -use std::any::TypeId; +use core::any::TypeId; use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueTypeless, AnyValueSizeless}; /// Makes [`AnyValueCloneable`] actually [`Clone`]able. diff --git a/src/any_value/mod.rs b/src/any_value/mod.rs index 243f6d5..cf44f7d 100644 --- a/src/any_value/mod.rs +++ b/src/any_value/mod.rs @@ -28,9 +28,9 @@ pub use lazy_clone::LazyClone; pub use wrapper::AnyValueWrapper; pub use raw::{AnyValueRaw, AnyValueSizelessRaw, AnyValueTypelessRaw}; -use std::any::TypeId; -use std::{mem, ptr}; -use std::mem::{MaybeUninit, size_of}; +use core::any::TypeId; +use core::{mem, ptr, slice}; +use core::mem::{MaybeUninit, size_of}; /// Marker for unknown type. pub struct Unknown; @@ -98,7 +98,7 @@ pub trait AnyValueTypeless: AnyValueSizeless { /// Aligned. #[inline] fn as_bytes(&self) -> &[u8]{ - unsafe{std::slice::from_raw_parts( + unsafe{slice::from_raw_parts( self.as_bytes_ptr(), self.size() )} @@ -151,7 +151,7 @@ pub trait AnyValueSizelessMut: AnyValueSizeless { pub trait AnyValueTypelessMut: AnyValueTypeless + AnyValueSizelessMut { #[inline(always)] fn as_bytes_mut(&mut self) -> &mut [u8]{ - unsafe{std::slice::from_raw_parts_mut( + unsafe{slice::from_raw_parts_mut( self.as_bytes_mut_ptr(), self.size() )} diff --git a/src/any_value/raw.rs b/src/any_value/raw.rs index 8742796..6f139fb 100644 --- a/src/any_value/raw.rs +++ b/src/any_value/raw.rs @@ -1,5 +1,5 @@ -use std::any::TypeId; -use std::ptr::NonNull; +use core::any::TypeId; +use core::ptr::NonNull; use crate::any_value::{AnyValue, AnyValueMut, AnyValueTypelessMut, AnyValueTypeless, AnyValueSizeless, AnyValueSizelessMut}; use crate::any_value::Unknown; diff --git a/src/any_value/wrapper.rs b/src/any_value/wrapper.rs index 2095d79..d76694d 100644 --- a/src/any_value/wrapper.rs +++ b/src/any_value/wrapper.rs @@ -1,5 +1,5 @@ -use std::any::TypeId; -use std::mem::size_of; +use core::any::TypeId; +use core::mem::size_of; use crate::any_value::{AnyValue, AnyValueMut, AnyValueTypelessMut, AnyValueTypeless, AnyValueSizeless, AnyValueSizelessMut}; /// Helper struct to convert concrete type to [`AnyValueMut`]. diff --git a/src/any_vec.rs b/src/any_vec.rs index 7db7eab..088d91d 100644 --- a/src/any_vec.rs +++ b/src/any_vec.rs @@ -1,12 +1,12 @@ -use std::alloc::Layout; -use std::any::TypeId; -use std::fmt::{Debug, Formatter}; -use std::marker::PhantomData; -use std::mem::{ManuallyDrop, MaybeUninit}; -use std::ops::{Deref, DerefMut, Range, RangeBounds}; -use std::ptr::NonNull; -use std::{ptr, slice}; -use std::slice::{from_raw_parts, from_raw_parts_mut}; +use core::alloc::Layout; +use core::any::TypeId; +use core::fmt::{Debug, Formatter}; +use core::marker::PhantomData; +use core::mem::{ManuallyDrop, MaybeUninit}; +use core::ops::{Deref, DerefMut, Range, RangeBounds}; +use core::ptr::NonNull; +use core::{fmt, ptr, slice}; +use core::slice::{from_raw_parts, from_raw_parts_mut}; use crate::{AnyVecTyped, into_range, mem, ops}; use crate::any_value::{AnyValue, AnyValueSizeless}; use crate::any_vec_raw::{AnyVecRaw, DropFn}; @@ -49,9 +49,9 @@ pub mod traits{ /// Does not enforce anything. Default. pub trait None {} - pub use std::marker::Sync; + pub use core::marker::Sync; - pub use std::marker::Send; + pub use core::marker::Send; /// Enforce type [`Clone`]-ability. pub trait Cloneable{} @@ -95,7 +95,7 @@ impl SatisfyTraits for T{} /// You can get it with [`AnyVec::into_raw_parts`], or build/edit /// it manually. And with [`AnyVec::from_raw_parts`], you can construct /// [`AnyVec`]. -pub struct RawParts +pub struct RawParts where M::Mem: MemRawParts { @@ -622,7 +622,7 @@ impl AnyVec /// If the returned [`TempValue`] goes out of scope without being dropped (due to /// [`mem::forget`], for example), the vector will lost and leak last element. /// - /// [`mem::forget`]: std::mem::forget + /// [`mem::forget`]: core::mem::forget /// #[inline] pub fn pop(&mut self) -> Option> { @@ -645,7 +645,7 @@ impl AnyVec /// [`mem::forget`], for example), the vector may have lost and leaked /// elements with indices >= index. /// - /// [`mem::forget`]: std::mem::forget + /// [`mem::forget`]: core::mem::forget /// #[inline] pub fn remove(&mut self, index: usize) -> Remove { @@ -666,7 +666,7 @@ impl AnyVec /// [`mem::forget`], for example), the vector may have lost and leaked /// elements with indices >= index. /// - /// [`mem::forget`]: std::mem::forget + /// [`mem::forget`]: core::mem::forget /// #[inline] pub fn swap_remove(&mut self, index: usize) -> SwapRemove { @@ -694,7 +694,7 @@ impl AnyVec /// [`mem::forget`], for example), the vector may have lost and leaked /// elements with indices in and past the range. /// - /// [`mem::forget`]: std::mem::forget + /// [`mem::forget`]: core::mem::forget /// #[inline] pub fn drain(&mut self, range: impl RangeBounds) -> Drain { @@ -725,7 +725,7 @@ impl AnyVec /// [`mem::forget`], for example), the vector may have lost and leaked /// elements with indices in and past the range. /// - /// [`mem::forget`]: std::mem::forget + /// [`mem::forget`]: core::mem::forget /// #[inline] pub fn splice(&mut self, range: impl RangeBounds, replace_with: I) @@ -814,7 +814,7 @@ impl Clone for AnyVec Debug for AnyVec{ - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("AnyVec") .field("typeid", &self.element_typeid()) .field("len", &self.len()) @@ -873,7 +873,7 @@ impl<'a, T: 'static, M: MemBuilder + 'a> IntoIterator for AnyVecRef<'a, T, M>{ } } impl<'a, T: 'static + Debug, M: MemBuilder + 'a> Debug for AnyVecRef<'a, T, M>{ - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } @@ -909,7 +909,7 @@ impl<'a, T: 'static, M: MemBuilder + 'a> IntoIterator for AnyVecMut<'a, T, M>{ } } impl<'a, T: 'static + Debug, M: MemBuilder + 'a> Debug for AnyVecMut<'a, T, M>{ - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } \ No newline at end of file diff --git a/src/any_vec_ptr.rs b/src/any_vec_ptr.rs index 879544e..4f4ade7 100644 --- a/src/any_vec_ptr.rs +++ b/src/any_vec_ptr.rs @@ -1,7 +1,7 @@ //! Type dispatched analog of `enum{*AnyVecRaw, *AnyVec}`. -use std::marker::PhantomData; -use std::ptr::NonNull; +use core::marker::PhantomData; +use core::ptr::NonNull; use crate::any_value::Unknown; use crate::any_vec_raw::AnyVecRaw; use crate::AnyVec; @@ -121,10 +121,10 @@ impl IAnyVecPtr for AnyVecPtr /// /// All unsafe, because dereferencing pointer is unsafe. pub(crate) mod utils{ - use std::{mem, ptr}; - use std::any::TypeId; - use std::mem::size_of; - use std::ptr::NonNull; + use core::{mem, ptr}; + use core::any::TypeId; + use core::mem::size_of; + use core::ptr::NonNull; use crate::any_value::Unknown; use crate::any_vec_ptr::IAnyVecRawPtr; use crate::AnyVecTyped; diff --git a/src/any_vec_raw.rs b/src/any_vec_raw.rs index 36b8cf4..d75d3c5 100644 --- a/src/any_vec_raw.rs +++ b/src/any_vec_raw.rs @@ -1,7 +1,7 @@ -use std::{cmp, mem, ptr}; -use std::alloc::Layout; -use std::any::TypeId; -use std::mem::size_of; +use core::{cmp, mem, ptr}; +use core::alloc::Layout; +use core::any::TypeId; +use core::mem::size_of; use crate::any_value::{AnyValue, Unknown, AnyValueSizeless}; use crate::assert_types_equal; use crate::clone_type::CloneFn; diff --git a/src/any_vec_typed.rs b/src/any_vec_typed.rs index 1d9120d..d2b2f84 100644 --- a/src/any_vec_typed.rs +++ b/src/any_vec_typed.rs @@ -1,9 +1,9 @@ -use std::fmt::{Debug, Formatter}; -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::ops::{Range, RangeBounds}; -use std::ptr::NonNull; -use std::slice; +use core::fmt::{Debug, Formatter}; +use core::marker::PhantomData; +use core::mem::MaybeUninit; +use core::ops::{Range, RangeBounds}; +use core::ptr::NonNull; +use core::{fmt, slice}; use crate::any_value::{AnyValueSizeless, AnyValueWrapper}; use crate::any_vec_raw::AnyVecRaw; use crate::ops::{Iter, pop, remove, swap_remove, TempValue}; @@ -284,7 +284,7 @@ impl<'a, T: 'static, M: MemBuilder + 'a> AnyVecTyped<'a, T, M>{ } impl<'a, T: 'static + Debug, M: MemBuilder> Debug for AnyVecTyped<'a, T, M>{ - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { (*self.as_slice()).fmt(f) } } diff --git a/src/element.rs b/src/element.rs index 7355174..48a3314 100644 --- a/src/element.rs +++ b/src/element.rs @@ -1,8 +1,8 @@ -use std::any::TypeId; -use std::marker::PhantomData; -use std::mem::ManuallyDrop; -use std::ops::{Deref, DerefMut}; -use std::ptr::NonNull; +use core::any::TypeId; +use core::marker::PhantomData; +use core::mem::ManuallyDrop; +use core::ops::{Deref, DerefMut}; +use core::ptr::NonNull; use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueTypelessMut, AnyValueTypeless, AnyValueSizeless, AnyValueSizelessMut}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{AnyVecPtr, IAnyVecPtr, IAnyVecRawPtr}; diff --git a/src/iter.rs b/src/iter.rs index cd998ce..6609b53 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -1,7 +1,7 @@ -use std::iter::{FusedIterator}; -use std::marker::PhantomData; -use std::mem::ManuallyDrop; -use std::ptr::NonNull; +use core::iter::{FusedIterator}; +use core::marker::PhantomData; +use core::mem::ManuallyDrop; +use core::ptr::NonNull; use crate::any_vec_ptr::{AnyVecPtr, AnyVecRawPtr, IAnyVecRawPtr}; use crate::any_vec_ptr::utils::element_ptr_at; use crate::any_vec_raw::AnyVecRaw; diff --git a/src/lib.rs b/src/lib.rs index 6f19169..16e57fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ +#![no_std] #![cfg_attr(miri, feature(alloc_layout_extra) )] +#![cfg_attr(docsrs, feature(doc_cfg))] //! Type erased vector [`AnyVec`]. Allow to store elements of the same type. -//! Have same performance and *operations* as [`std::vec::Vec`]. +//! Have same performance and *operations* as `std::vec::Vec`. //! //! You can downcast type erased [`AnyVec`] to concrete [`AnyVecTyped`] with `downcast`-family. //! Or use [`AnyVec`] type erased operations, which works with [`any_value`]. @@ -115,7 +117,7 @@ //! //! [`MemBuilder`]: mem::MemBuilder //! [`Mem`]: mem::Mem -//! [`Allocator`]: std::alloc::Allocator +//! [`Allocator`]: core::alloc::Allocator //! [`clone_empty_in`]: AnyVec::clone_empty_in //! //! # AnyValue @@ -135,6 +137,16 @@ //! [AnyValue]: any_value::AnyValue //! [AnyValueMut]: any_value::AnyValueMut //! [AnyValueCloneable]: any_value::AnyValueCloneable +//! +//! # No `alloc` +//! +//! This library is `no_std` and can work without `alloc`. +//! For this - disable default `alloc` feature. [mem::Heap] will become unavailable +//! after that, and you'll have to specify [MemBuilder] for [AnyVec]. You can use +//! [mem::Stack], or specify your own [Mem]. +//! +//! [MemBuilder]: mem::MemBuilder +//! [Mem]: mem::Mem mod any_vec; mod clone_type; @@ -143,7 +155,7 @@ mod any_vec_raw; mod any_vec_typed; mod iter; -use std::any::TypeId; +use core::any::TypeId; pub use crate::any_vec::{AnyVec, AnyVecMut, AnyVecRef, RawParts, SatisfyTraits, traits}; pub use any_vec_typed::AnyVecTyped; pub use iter::{ElementIterator, Iter, IterMut, IterRef}; @@ -153,8 +165,8 @@ pub mod any_value; pub mod ops; pub mod element; -use std::ptr; -use std::ops::{Bound, Range, RangeBounds}; +use core::ptr; +use core::ops::{Bound, Range, RangeBounds}; use crate::any_value::Unknown; /// This is faster then ptr::copy, diff --git a/src/mem/empty.rs b/src/mem/empty.rs index 72e0883..c1b5bb6 100644 --- a/src/mem/empty.rs +++ b/src/mem/empty.rs @@ -1,4 +1,4 @@ -use std::alloc::Layout; +use core::alloc::Layout; use crate::mem::{dangling, Mem, MemBuilder, MemRawParts}; /// Zero-size memory. diff --git a/src/mem/heap.rs b/src/mem/heap.rs index b0efad4..d4ff94b 100644 --- a/src/mem/heap.rs +++ b/src/mem/heap.rs @@ -1,7 +1,9 @@ -use std::alloc::{alloc, dealloc, handle_alloc_error, Layout, realloc}; -use std::cmp; -use std::mem::ManuallyDrop; -use std::ptr::NonNull; +extern crate alloc; + +use alloc::alloc::{alloc, dealloc, handle_alloc_error, Layout, realloc}; +use core::cmp; +use core::mem::ManuallyDrop; +use core::ptr::NonNull; use crate::mem::{dangling, Mem, MemBuilder, MemBuilderSizeable, MemRawParts, MemResizable}; /// Heap allocated memory. diff --git a/src/mem/mod.rs b/src/mem/mod.rs index b8a2d05..ada9645 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -1,17 +1,23 @@ +#[cfg(feature="alloc")] mod heap; mod stack; mod stack_n; mod empty; +#[cfg(feature="alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub use heap::Heap; pub use stack::Stack; pub use stack_n::StackN; pub use empty::Empty; +#[cfg(feature="alloc")] pub(crate) type Default = Heap; +#[cfg(not(feature="alloc"))] +pub(crate) type Default = Empty; -use std::alloc::Layout; -use std::ptr::NonNull; +use core::alloc::Layout; +use core::ptr::NonNull; /// This is [`Mem`] builder. /// diff --git a/src/mem/stack.rs b/src/mem/stack.rs index 57b4e83..519b681 100644 --- a/src/mem/stack.rs +++ b/src/mem/stack.rs @@ -1,5 +1,5 @@ -use std::alloc::Layout; -use std::mem::MaybeUninit; +use core::alloc::Layout; +use core::mem::MaybeUninit; use crate::mem::{Mem, MemBuilder}; /// Fixed `SIZE` capacity on-stack memory. diff --git a/src/mem/stack_n.rs b/src/mem/stack_n.rs index fd4a4b3..d06f792 100644 --- a/src/mem/stack_n.rs +++ b/src/mem/stack_n.rs @@ -1,5 +1,5 @@ -use std::alloc::Layout; -use std::mem::MaybeUninit; +use core::alloc::Layout; +use core::mem::MaybeUninit; use crate::mem::{Mem, MemBuilder}; /// Fixed `SIZE` capacity on-stack memory for `N` elements. diff --git a/src/ops/iter.rs b/src/ops/iter.rs index 26fb1c5..3c2fb33 100644 --- a/src/ops/iter.rs +++ b/src/ops/iter.rs @@ -1,4 +1,4 @@ -use std::iter::FusedIterator; +use core::iter::FusedIterator; pub trait Iterable { type Iter: Iterator; diff --git a/src/ops/pop.rs b/src/ops/pop.rs index 59c5cba..579bdc4 100644 --- a/src/ops/pop.rs +++ b/src/ops/pop.rs @@ -1,4 +1,4 @@ -use std::marker::PhantomData; +use core::marker::PhantomData; use crate::any_vec_ptr::IAnyVecRawPtr; use crate::any_vec_ptr::utils::element_ptr_at; use crate::any_vec_raw::AnyVecRaw; diff --git a/src/ops/remove.rs b/src/ops/remove.rs index e7210ec..b7a459e 100644 --- a/src/ops/remove.rs +++ b/src/ops/remove.rs @@ -1,5 +1,5 @@ -use std::marker::PhantomData; -use std::ptr; +use core::marker::PhantomData; +use core::ptr; use crate::any_value::Unknown; use crate::any_vec_ptr::IAnyVecRawPtr; use crate::any_vec_ptr::utils::element_ptr_at; diff --git a/src/ops/swap_remove.rs b/src/ops/swap_remove.rs index 07b240e..946f775 100644 --- a/src/ops/swap_remove.rs +++ b/src/ops/swap_remove.rs @@ -1,4 +1,4 @@ -use std::marker::PhantomData; +use core::marker::PhantomData; use crate::copy_nonoverlapping_value; use crate::any_vec_ptr::IAnyVecRawPtr; use crate::any_vec_ptr::utils::{element_mut_ptr_at, element_ptr_at}; diff --git a/src/ops/temp.rs b/src/ops/temp.rs index a54794e..842eb01 100644 --- a/src/ops/temp.rs +++ b/src/ops/temp.rs @@ -1,5 +1,5 @@ -use std::any::TypeId; -use std::{mem, ptr}; +use core::any::TypeId; +use core::{mem, ptr}; use crate::any_value::{AnyValue, AnyValueCloneable, AnyValueMut, AnyValueSizeless, AnyValueSizelessMut, AnyValueTypeless, AnyValueTypelessMut, Unknown}; use crate::any_vec_raw::AnyVecRaw; use crate::any_vec_ptr::{IAnyVecPtr, IAnyVecRawPtr}; From 4359d22cd6bb5df08a4e626e776d1cd4a870bc98 Mon Sep 17 00:00:00 2001 From: tower120 Date: Fri, 10 May 2024 09:48:47 +0300 Subject: [PATCH 34/35] Readme update --- Cargo.toml | 2 +- Readme.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1791bb9..2f7d1ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "any_vec" authors = ["Andrey Diduh "] license = "MIT OR Apache-2.0" -version = "0.13.0" +version = "0.14.0" edition = "2021" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." repository = "https://github.com/tower120/any_vec" diff --git a/Readme.md b/Readme.md index 1dd4f57..a9e8a4b 100644 --- a/Readme.md +++ b/Readme.md @@ -5,7 +5,9 @@ Type erased vector. All elements have the same type. -Designed to be type-erased as far as possible - most of the operations does not know about concrete type. +Designed to be type-erased as far as possible - most operations do not know a concrete type. +For example, you can move or copy/clone items from one type-erased vector to another, without ever knowing +their type. Or you can erase, swap, move, copy elements inside type-erased vector, etc... Only type-erased destruct and clone operations have additional overhead of indirect call. From db1d0d7e167e8bc92828b10c0ed06198bd175a38 Mon Sep 17 00:00:00 2001 From: tower120 Date: Fri, 10 May 2024 10:05:31 +0300 Subject: [PATCH 35/35] cargo.toml update --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2f7d1ef..307492c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,13 +6,13 @@ version = "0.14.0" edition = "2021" description = "Type erased vector. Most operations can be done without type knowledge. Mostly zero overhead." repository = "https://github.com/tower120/any_vec" -keywords = ["vec", "any", "container", "no_std"] +keywords = ["vec", "any", "container", "type-erasure", "no_std"] categories = ["data-structures", "no-std", "no-std::no-alloc"] exclude = [".github"] [features] default = ["alloc"] -# Include alloc crate. This allows to use mem::Heap. +# Include alloc crate. This allows using mem::Heap. alloc = [] [package.metadata.docs.rs]