Skip to content

Commit

Permalink
copy_nonoverlapping_value refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
tower120 committed May 8, 2024
1 parent 2affe62 commit 7ae9f08
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 72 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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`.
Expand Down
61 changes: 6 additions & 55 deletions src/any_value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ 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};
Expand Down Expand Up @@ -80,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<KnownType:'static /*= Self::Type*/>(self, out: *mut u8, bytes_size: usize)
where Self: Sized
{
copy_bytes::<KnownType>(self.as_bytes_ptr(), out, bytes_size);
crate::copy_nonoverlapping_value::<KnownType>(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<T: AnyValueTypeless>(this: T, out: *mut u8) {
let size = this.size();
this.move_into::<T::Type>(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<T: AnyValueSizeless>(this: T, out: *mut u8, bytes_size: usize) {
this.move_into::<T::Type>(out, bytes_size);
}

/// [AnyValue] that doesn't know it's type, but know it's size.
pub trait AnyValueTypeless: AnyValueSizeless {
/// Aligned.
Expand Down Expand Up @@ -164,26 +135,6 @@ pub trait AnyValue: AnyValueTypeless {
}
}

/// Helper function, which utilize type knowledge.
#[inline(always)]
pub(crate) unsafe fn copy_bytes<KnownType: 'static>(
input: *const u8, out: *mut u8, bytes_size: usize
) {
if !Unknown::is::<KnownType>() {
ptr::copy_nonoverlapping(
input as *const KnownType,
out as *mut KnownType,
1
);
} else {
ptr::copy_nonoverlapping(
input,
out,
bytes_size
);
}
}

/// Mutable [AnyValueSizeless].
pub trait AnyValueSizelessMut: AnyValueSizeless {
// Rust MIRI requires mut pointer to actually come from mut self.
Expand Down
3 changes: 2 additions & 1 deletion src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 [`AnyValue::move_into`].
/// Otherwise, it will be destructed with destruction of [`Element`].
///
/// # Notes
Expand Down
36 changes: 29 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -155,11 +155,13 @@ pub mod element;

use std::ptr;
use std::ops::{Bound, Range, RangeBounds};
use crate::any_value::Unknown;

// TODO: remove
// 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)
Expand All @@ -174,6 +176,26 @@ unsafe fn copy_bytes(src: *const u8, dst: *mut u8, count: usize){
}
}

/// One element copy_nonoverlapping, that utilize type knowledge.
#[inline(always)]
pub(crate) unsafe fn copy_nonoverlapping_value<KnownType: 'static>(
input: *const u8, out: *mut u8, value_size: usize
) {
if !Unknown::is::<KnownType>() {
ptr::copy_nonoverlapping(
input as *const KnownType,
out as *mut KnownType,
1
);
} else {
ptr::copy_nonoverlapping(
input,
out,
value_size
);
}
}

#[inline]
fn into_range(
len: usize,
Expand All @@ -197,4 +219,4 @@ fn into_range(
#[inline]
fn assert_types_equal(t1: TypeId, t2: TypeId){
assert_eq!(t1, t2, "Type mismatch!");
}
}
4 changes: 2 additions & 2 deletions src/ops/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ impl<'a, AnyVecPtr: IAnyVecRawPtr> Operation for Remove<'a, AnyVecPtr>{
if !Unknown::is::<AnyVecPtr::Element>() {
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`
Expand Down
6 changes: 4 additions & 2 deletions src/ops/splice.rs
Original file line number Diff line number Diff line change
@@ -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>
Expand Down Expand Up @@ -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::<
<ReplaceIter::Item as AnyValueSizeless>::Type
>(ptr, element_size);
ptr = ptr.add(element_size);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/ops/swap_remove.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::marker::PhantomData;
use crate::any_value::copy_bytes;
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;
Expand Down Expand Up @@ -47,7 +47,7 @@ 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 {
copy_bytes::<AnyVecPtr::Element>(
copy_nonoverlapping_value::<AnyVecPtr::Element>(
last_element,
self.element,
any_vec_raw.element_layout().size()
Expand Down
6 changes: 3 additions & 3 deletions src/ops/temp.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -58,7 +58,7 @@ impl<Op: Operation> AnyValueSizeless for TempValue<Op> {

#[inline]
unsafe fn move_into<KnownType:'static /*= Unknown*/>(mut self, out: *mut u8, bytes_size: usize) {
copy_bytes::<KnownType>(self.as_bytes_ptr(), out, bytes_size);
copy_nonoverlapping_value::<KnownType>(self.as_bytes_ptr(), out, bytes_size);
self.op.consume();
mem::forget(self);
}
Expand Down

0 comments on commit 7ae9f08

Please sign in to comment.