Skip to content

Commit

Permalink
copy utils refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
tower120 authored May 8, 2024
1 parent 0bec11c commit 168276e
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 138 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
70 changes: 11 additions & 59 deletions src/any_value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<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 @@ -165,24 +135,6 @@ pub trait AnyValue: AnyValueTypeless {
}
}

/// Helper function, which utilize type knowledge.
#[inline]
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 {
copy_bytes_nonoverlapping(
input,
out,
bytes_size);
}
}

/// Mutable [AnyValueSizeless].
pub trait AnyValueSizelessMut: AnyValueSizeless {
// Rust MIRI requires mut pointer to actually come from mut self.
Expand All @@ -197,15 +149,15 @@ 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(),
self.size()
)}
}

#[inline]
#[inline(always)]
unsafe fn swap_unchecked<Other: AnyValueMut>(&mut self, other: &mut Other){
// compile-time check
if !Unknown::is::<Self::Type>() {
Expand All @@ -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()
Expand All @@ -231,7 +183,7 @@ pub trait AnyValueTypelessMut: AnyValueTypeless + AnyValueSizelessMut {

/// Mutable [AnyValue].
pub trait AnyValueMut: AnyValueTypelessMut + AnyValue {
#[inline]
#[inline(always)]
fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T>{
if self.value_typeid() != TypeId::of::<T>(){
None
Expand All @@ -245,7 +197,7 @@ pub trait AnyValueMut: AnyValueTypelessMut + AnyValue {
/// # Panic
///
/// Panics, if type mismatch.
#[inline]
#[inline(always)]
fn swap<Other: AnyValueMut>(&mut self, other: &mut Other){
assert_eq!(self.value_typeid(), other.value_typeid());
unsafe{
Expand Down
4 changes: 2 additions & 2 deletions 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 [`AnyValueSizeless::move_into`].
/// Otherwise, it will be destructed with destruction of [`Element`].
///
/// # Notes
Expand All @@ -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<u8>,
Expand Down
80 changes: 26 additions & 54 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,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)
Expand All @@ -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::<u8>::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<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
);
}
}

Expand All @@ -247,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
22 changes: 6 additions & 16 deletions src/ops/swap_remove.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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::<AnyVecPtr::Element>() {
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::<AnyVecPtr::Element>(
last_element,
self.element,
any_vec_raw.element_layout().size()
);
}

// 3. shrink len `self.any_vec.len -= 1`
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 168276e

Please sign in to comment.