Skip to content

Commit

Permalink
Optimized Clone::clone_from implementation (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
james7132 authored Apr 14, 2024
1 parent ca4dd26 commit f09cfcc
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 4 deletions.
5 changes: 4 additions & 1 deletion src/block/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![allow(dead_code)]
// TODO: Remove once the transmutes are fixed
#![allow(unknown_lints)]
#![allow(clippy::missing_transmute_annotations)]

use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
Expand Down Expand Up @@ -66,7 +69,7 @@ pub use self::wasm::*;
impl Block {
pub const USIZE_COUNT: usize = core::mem::size_of::<Self>() / core::mem::size_of::<usize>();
pub const NONE: Self = Self::from_usize_array([0; Self::USIZE_COUNT]);
pub const ALL: Self = Self::from_usize_array([core::usize::MAX; Self::USIZE_COUNT]);
pub const ALL: Self = Self::from_usize_array([usize::MAX; Self::USIZE_COUNT]);
pub const BITS: usize = core::mem::size_of::<Self>() * 8;

#[inline]
Expand Down
31 changes: 28 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,7 @@ impl Hash for FixedBitSet {

impl PartialEq for FixedBitSet {
fn eq(&self, other: &Self) -> bool {
self.as_simd_slice().eq(other.as_simd_slice()) && self.length == other.length
self.length == other.length && self.as_simd_slice().eq(other.as_simd_slice())
}
}

Expand Down Expand Up @@ -1201,9 +1201,9 @@ impl Masks {

Masks {
first_block,
first_mask: usize::max_value() << first_rem,
first_mask: usize::MAX << first_rem,
last_block,
last_mask: (usize::max_value() >> 1) >> (BITS - last_rem - 1),
last_mask: (usize::MAX >> 1) >> (BITS - last_rem - 1),
// this is equivalent to `MAX >> (BITS - x)` with correct semantics when x == 0.
}
}
Expand Down Expand Up @@ -1406,6 +1406,31 @@ impl Clone for FixedBitSet {
fn clone(&self) -> Self {
Self::from_blocks_and_len(Vec::from(self.as_simd_slice()), self.length)
}

#[inline]
fn clone_from(&mut self, source: &Self) {
{
let me = self.as_mut_simd_slice();
let them = source.as_simd_slice();
match me.len().cmp(&them.len()) {
Ordering::Greater => {
let (head, tail) = me.split_at_mut(them.len());
head.copy_from_slice(them);
tail.fill(SimdBlock::NONE);
self.length = source.length;
return;
}
Ordering::Equal => {
me.copy_from_slice(them);
self.length = source.length;
return;
}
// Self is smaller than the source, this requires allocation.
Ordering::Less => {}
}
}
*self = source.clone();
}
}

/// Return **true** if the bit is enabled in the bitset,
Expand Down
27 changes: 27 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,3 +1284,30 @@ fn test_is_full() {
fb.insert_range(..);
assert!(fb.is_full());
}

#[test]
fn clone() {
let mut fb = FixedBitSet::with_capacity(10000);
fb.set(11, true);
fb.set(12, true);
fb.set(7, true);
fb.set(35, true);
fb.set(40, true);
fb.set(77, true);
fb.set(95, true);
fb.set(50, true);
fb.set(99, true);

let fb_clone = fb.clone();
let mut fb_clone_from_smaller = FixedBitSet::with_capacity(1000000);
let mut fb_clone_from_same = FixedBitSet::with_capacity(10000);
let mut fb_clone_from_bigger = FixedBitSet::with_capacity(100);
fb_clone_from_smaller.clone_from(&fb);
fb_clone_from_same.clone_from(&fb);
fb_clone_from_bigger.clone_from(&fb);

assert_eq!(&fb, &fb_clone);
assert_eq!(&fb, &fb_clone_from_smaller);
assert_eq!(&fb, &fb_clone_from_same);
assert_eq!(&fb, &fb_clone_from_bigger);
}

0 comments on commit f09cfcc

Please sign in to comment.