Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimized Clone::clone_from implementation #127

Merged
merged 5 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}