Skip to content

Commit 5cf099a

Browse files
authored
Use usize as the Block instead of u32 (#74)
Changed Block to be an alias on usize instead of u32, which should use 2x fewer instructions for similar length bit sets on 64-bit machines. This allows us to skip more in sparse bitsets. This partially addresses #73. Though full SIMD support is probably more desirable here.
1 parent 78a268d commit 5cf099a

2 files changed

Lines changed: 32 additions & 36 deletions

File tree

benches/benches.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
extern crate test;
44
extern crate fixedbitset;
55
use test::Bencher;
6-
use fixedbitset::{FixedBitSet};
6+
use fixedbitset::{FixedBitSet, Block};
77
use std::mem::size_of;
88

99
#[inline]
@@ -18,8 +18,8 @@ fn iter_ones_using_contains<F: FnMut(usize)>(fb: &FixedBitSet, f: &mut F) {
1818
#[inline]
1919
fn iter_ones_using_slice_directly<F: FnMut(usize)>(fb: &FixedBitSet, f: &mut F) {
2020
for (block_idx, &block) in fb.as_slice().iter().enumerate() {
21-
let mut bit_pos = block_idx * size_of::<u32>() * 8;
22-
let mut block: u32 = block;
21+
let mut bit_pos = block_idx * size_of::<Block>() * 8;
22+
let mut block: Block = block;
2323

2424
while block != 0 {
2525
if (block & 1) == 1 {

src/lib.rs

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ use std::cmp::{Ord, Ordering};
3737
use std::iter::{Chain, FromIterator};
3838
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Index};
3939

40-
const BITS: usize = 32;
41-
type Block = u32;
40+
const BITS: usize = std::mem::size_of::<Block>() * 8;
41+
pub type Block = usize;
4242

4343
#[inline]
44-
fn div_rem(x: usize, d: usize) -> (usize, usize) {
45-
(x / d, x % d)
44+
fn div_rem(x: usize) -> (usize, usize) {
45+
(x / BITS, x % BITS)
4646
}
4747

4848
/// `FixedBitSet` is a simple fixed size set of bits that each can
@@ -73,7 +73,7 @@ impl FixedBitSet {
7373
/// Create a new **FixedBitSet** with a specific number of bits,
7474
/// all initially clear.
7575
pub fn with_capacity(bits: usize) -> Self {
76-
let (mut blocks, rem) = div_rem(bits, BITS);
76+
let (mut blocks, rem) = div_rem(bits);
7777
blocks += (rem > 0) as usize;
7878
FixedBitSet {
7979
data: vec![0; blocks],
@@ -95,15 +95,15 @@ impl FixedBitSet {
9595
/// assert_eq!(format!("{:b}", bs), "0010");
9696
/// ```
9797
pub fn with_capacity_and_blocks<I: IntoIterator<Item = Block>>(bits: usize, blocks: I) -> Self {
98-
let (mut n_blocks, rem) = div_rem(bits, BITS);
98+
let (mut n_blocks, rem) = div_rem(bits);
9999
n_blocks += (rem > 0) as usize;
100100
let mut data: Vec<Block> = blocks.into_iter().collect();
101101
// Pad data with zeros if smaller or truncate if larger
102102
if data.len() != n_blocks {
103103
data.resize(n_blocks, 0);
104104
}
105105
// Disable bits in blocks beyond capacity
106-
let end = data.len() * 32;
106+
let end = data.len() * BITS;
107107
for (block, mask) in Masks::new(bits..end, end) {
108108
unsafe {
109109
*data.get_unchecked_mut(block) &= !mask;
@@ -114,7 +114,7 @@ impl FixedBitSet {
114114

115115
/// Grow capacity to **bits**, all new bits initialized to zero
116116
pub fn grow(&mut self, bits: usize) {
117-
let (mut blocks, rem) = div_rem(bits, BITS);
117+
let (mut blocks, rem) = div_rem(bits);
118118
blocks += (rem > 0) as usize;
119119
if bits > self.length {
120120
self.length = bits;
@@ -185,7 +185,7 @@ impl FixedBitSet {
185185
/// Note: Also available with index syntax: `bitset[bit]`.
186186
#[inline]
187187
pub fn contains(&self, bit: usize) -> bool {
188-
let (block, i) = div_rem(bit, BITS);
188+
let (block, i) = div_rem(bit);
189189
match self.data.get(block) {
190190
None => false,
191191
Some(b) => (b & (1 << i)) != 0,
@@ -211,7 +211,7 @@ impl FixedBitSet {
211211
bit,
212212
self.length
213213
);
214-
let (block, i) = div_rem(bit, BITS);
214+
let (block, i) = div_rem(bit);
215215
unsafe {
216216
*self.data.get_unchecked_mut(block) |= 1 << i;
217217
}
@@ -228,7 +228,7 @@ impl FixedBitSet {
228228
bit,
229229
self.length
230230
);
231-
let (block, i) = div_rem(bit, BITS);
231+
let (block, i) = div_rem(bit);
232232
unsafe {
233233
let word = self.data.get_unchecked_mut(block);
234234
let prev = *word & (1 << i) != 0;
@@ -247,7 +247,7 @@ impl FixedBitSet {
247247
bit,
248248
self.length
249249
);
250-
let (block, i) = div_rem(bit, BITS);
250+
let (block, i) = div_rem(bit);
251251
unsafe {
252252
*self.data.get_unchecked_mut(block) ^= 1 << i;
253253
}
@@ -261,7 +261,7 @@ impl FixedBitSet {
261261
bit,
262262
self.length
263263
);
264-
let (block, i) = div_rem(bit, BITS);
264+
let (block, i) = div_rem(bit);
265265
unsafe {
266266
let elt = self.data.get_unchecked_mut(block);
267267
if enabled {
@@ -283,7 +283,7 @@ impl FixedBitSet {
283283
to,
284284
self.length
285285
);
286-
let (to_block, t) = div_rem(to, BITS);
286+
let (to_block, t) = div_rem(to);
287287
let enabled = self.contains(from);
288288
unsafe {
289289
let to_elt = self.data.get_unchecked_mut(to_block);
@@ -352,16 +352,16 @@ impl FixedBitSet {
352352
}
353353
}
354354

355-
/// View the bitset as a slice of `u32` blocks
355+
/// View the bitset as a slice of `Block` blocks
356356
#[inline]
357-
pub fn as_slice(&self) -> &[u32] {
357+
pub fn as_slice(&self) -> &[Block] {
358358
&self.data
359359
}
360360

361-
/// View the bitset as a mutable slice of `u32` blocks. Writing past the bitlength in the last
361+
/// View the bitset as a mutable slice of `Block` blocks. Writing past the bitlength in the last
362362
/// will cause `contains` to return potentially incorrect results for bits past the bitlength.
363363
#[inline]
364-
pub fn as_mut_slice(&mut self) -> &mut [u32] {
364+
pub fn as_mut_slice(&mut self) -> &mut [Block] {
365365
&mut self.data
366366
}
367367

@@ -374,12 +374,12 @@ impl FixedBitSet {
374374
Some((&block, rem)) => Ones {
375375
bitset: block,
376376
block_idx: 0,
377-
remaining_blocks: rem,
377+
remaining_blocks: rem.iter(),
378378
},
379379
None => Ones {
380380
bitset: 0,
381381
block_idx: 0,
382-
remaining_blocks: &[],
382+
remaining_blocks: [].iter(),
383383
},
384384
}
385385
}
@@ -615,8 +615,8 @@ impl Masks {
615615
length
616616
);
617617

618-
let (first_block, first_rem) = div_rem(start, BITS);
619-
let (last_block, last_rem) = div_rem(end, BITS);
618+
let (first_block, first_rem) = div_rem(start);
619+
let (last_block, last_rem) = div_rem(end);
620620

621621
Masks {
622622
first_block: first_block as usize,
@@ -660,7 +660,7 @@ impl Iterator for Masks {
660660
pub struct Ones<'a> {
661661
bitset: Block,
662662
block_idx: usize,
663-
remaining_blocks: &'a [Block],
663+
remaining_blocks: std::slice::Iter<'a, Block>,
664664
}
665665

666666
impl<'a> Iterator for Ones<'a> {
@@ -669,17 +669,13 @@ impl<'a> Iterator for Ones<'a> {
669669
#[inline]
670670
fn next(&mut self) -> Option<Self::Item> {
671671
while self.bitset == 0 {
672-
if self.remaining_blocks.is_empty() {
673-
return None;
674-
}
675-
self.bitset = self.remaining_blocks[0];
676-
self.remaining_blocks = &self.remaining_blocks[1..];
677-
self.block_idx += 1;
672+
self.bitset = *self.remaining_blocks.next()?;
673+
self.block_idx += BITS;
678674
}
679675
let t = self.bitset & (0 as Block).wrapping_sub(self.bitset);
680676
let r = self.bitset.trailing_zeros() as usize;
681677
self.bitset ^= t;
682-
Some(self.block_idx * BITS + r)
678+
Some(self.block_idx + r)
683679
}
684680
}
685681

@@ -860,7 +856,7 @@ mod tests {
860856

861857
#[test]
862858
fn with_blocks() {
863-
let fb = FixedBitSet::with_capacity_and_blocks(50, vec![8u32, 0u32]);
859+
let fb = FixedBitSet::with_capacity_and_blocks(50, vec![8, 0]);
864860
assert!(fb.contains(3));
865861

866862
let ones: Vec<_> = fb.ones().collect();
@@ -869,14 +865,14 @@ mod tests {
869865

870866
#[test]
871867
fn with_blocks_too_small() {
872-
let mut fb = FixedBitSet::with_capacity_and_blocks(500, vec![8u32, 0u32]);
868+
let mut fb = FixedBitSet::with_capacity_and_blocks(500, vec![8, 0]);
873869
fb.insert(400);
874870
assert!(fb.contains(400));
875871
}
876872

877873
#[test]
878874
fn with_blocks_too_big() {
879-
let fb = FixedBitSet::with_capacity_and_blocks(1, vec![8u32]);
875+
let fb = FixedBitSet::with_capacity_and_blocks(1, vec![8]);
880876

881877
// since capacity is 1, 3 shouldn't be set here
882878
assert!(!fb.contains(3));

0 commit comments

Comments
 (0)