From f09cfccd8f77e0ca4af47ff556995514615a428a Mon Sep 17 00:00:00 2001 From: James Liu Date: Sun, 14 Apr 2024 05:13:06 -0700 Subject: [PATCH] Optimized Clone::clone_from implementation (#127) --- src/block/mod.rs | 5 ++++- src/lib.rs | 31 ++++++++++++++++++++++++++++--- tests/tests.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/block/mod.rs b/src/block/mod.rs index 05de0c8..ae7c222 100644 --- a/src/block/mod.rs +++ b/src/block/mod.rs @@ -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}; @@ -66,7 +69,7 @@ pub use self::wasm::*; impl Block { pub const USIZE_COUNT: usize = core::mem::size_of::() / core::mem::size_of::(); 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::() * 8; #[inline] diff --git a/src/lib.rs b/src/lib.rs index 10a871c..313927a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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()) } } @@ -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. } } @@ -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, diff --git a/tests/tests.rs b/tests/tests.rs index 385cf5d..fcc334d 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -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); +}