From ce02fffccd68a2bafc6bf456242e4f289c65f6fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20K=C3=B6ster?= Date: Tue, 17 Oct 2023 15:55:01 +0200 Subject: [PATCH 01/11] first step --- src/lib.rs | 60 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b34e11d..1cd9843 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -410,14 +410,21 @@ impl FixedBitSet { #[inline] pub fn ones(&self) -> Ones { match self.as_slice().split_first() { - Some((&block, rem)) => Ones { - bitset: block, - block_idx: 0, - remaining_blocks: rem.iter(), - }, + Some((&first_block, rem)) => { + let (&last_block, rem) = rem.split_last().unwrap_or((&0, rem)); + Ones { + bitset_front: first_block, + bitset_back: last_block, + block_idx_front: 0, + block_idx_back: self.length, + remaining_blocks: rem.iter(), + } + } None => Ones { - bitset: 0, - block_idx: 0, + bitset_front: 0, + bitset_back: 0, + block_idx_front: 0, + block_idx_back: 0, remaining_blocks: [].iter(), }, } @@ -764,28 +771,49 @@ impl ExactSizeIterator for Masks {} /// /// This struct is created by the [`FixedBitSet::ones`] method. pub struct Ones<'a> { - bitset: Block, - block_idx: usize, + bitset_front: Block, + bitset_back: Block, + block_idx_front: usize, + block_idx_back: usize, remaining_blocks: std::slice::Iter<'a, Block>, } +impl<'a> DoubleEndedIterator for Ones<'a> { + fn next_back(&mut self) -> Option { + todo!() + } +} + impl<'a> Iterator for Ones<'a> { type Item = usize; // the bit position of the '1' #[inline] fn next(&mut self) -> Option { - while self.bitset == 0 { - self.bitset = *self.remaining_blocks.next()?; - self.block_idx += BITS; + let mut active_block: &mut Block = &mut self.bitset_front; + while *active_block == 0 { + match self.remaining_blocks.next() { + None => { + if self.bitset_back != 0 { + active_block = &mut self.bitset_back; + } else { + return None; + } + } + Some(next_block) => { + *active_block = *next_block; + } + }; + self.block_idx_front += BITS; } - let t = self.bitset & (0 as Block).wrapping_sub(self.bitset); - let r = self.bitset.trailing_zeros() as usize; - self.bitset ^= t; - Some(self.block_idx + r) + let t = *active_block & (0 as Block).wrapping_sub(*active_block); + let r = active_block.trailing_zeros() as usize; + self.bitset_front ^= t; + Some(self.block_idx_front + r) } #[inline] fn size_hint(&self) -> (usize, Option) { + // todo check if + 1 or +2 is needed (0, Some(self.remaining_blocks.as_slice().len() * BITS)) } } From 98df931506363e671dd0abce8578dd55e34a0147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20K=C3=B6ster?= Date: Tue, 17 Oct 2023 17:13:57 +0200 Subject: [PATCH 02/11] first working test --- src/lib.rs | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1cd9843..a698544 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -416,7 +416,7 @@ impl FixedBitSet { bitset_front: first_block, bitset_back: last_block, block_idx_front: 0, - block_idx_back: self.length, + block_idx_back: (1 + rem.len()) * BITS, remaining_blocks: rem.iter(), } } @@ -780,7 +780,32 @@ pub struct Ones<'a> { impl<'a> DoubleEndedIterator for Ones<'a> { fn next_back(&mut self) -> Option { - todo!() + let mut active_block: &mut Block = &mut self.bitset_back; + while *active_block == 0 { + match self.remaining_blocks.next_back() { + None => { + if self.bitset_front != 0 { + self.bitset_back = 0; + self.block_idx_back = self.block_idx_front; + active_block = &mut self.bitset_front; + } else { + return None; + } + } + Some(next_block) => { + *active_block = *next_block; + self.block_idx_back -= BITS; + } + }; + } + /* Identify the first non zero bit */ + let bit_idx = active_block.leading_zeros(); + + /* set that bit to zero */ + let mask = !((1 as Block) << (BITS as u32 - bit_idx - 1)); + active_block.bitand_assign(mask); + + Some(self.block_idx_back + BITS - bit_idx as usize - 1) } } @@ -794,6 +819,8 @@ impl<'a> Iterator for Ones<'a> { match self.remaining_blocks.next() { None => { if self.bitset_back != 0 { + self.bitset_front = 0; + self.block_idx_front = self.block_idx_back; active_block = &mut self.bitset_back; } else { return None; @@ -801,13 +828,13 @@ impl<'a> Iterator for Ones<'a> { } Some(next_block) => { *active_block = *next_block; + self.block_idx_front += BITS; } }; - self.block_idx_front += BITS; } let t = *active_block & (0 as Block).wrapping_sub(*active_block); let r = active_block.trailing_zeros() as usize; - self.bitset_front ^= t; + *active_block ^= t; Some(self.block_idx_front + r) } @@ -1175,8 +1202,13 @@ mod tests { fb.set(99, true); let ones: Vec<_> = fb.ones().collect(); + let ones_rev: Vec<_> = fb.ones().rev().collect(); + + let mut known_result = vec![7, 11, 12, 35, 40, 50, 77, 95, 99]; - assert_eq!(vec![7, 11, 12, 35, 40, 50, 77, 95, 99], ones); + assert_eq!(known_result, ones); + known_result.reverse(); + assert_eq!(known_result, ones_rev); } #[test] @@ -1659,7 +1691,7 @@ mod tests { let b = b_ones.iter().cloned().collect::(); a |= b; let res = a.ones().collect::>(); - assert!(res == a_or_b); + assert_eq!(res, a_or_b); } #[test] From 91f4d13b3b1e5bf6b120aa4c3aca1732067968de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20K=C3=B6ster?= Date: Tue, 17 Oct 2023 17:27:40 +0200 Subject: [PATCH 03/11] alternating test added --- src/lib.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index a698544..9fbe922 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1188,6 +1188,35 @@ mod tests { assert_eq!(fb.count_ones(8..), 8); } + /* Helper for testing double ended iterator */ + struct Alternating { + iter: I, + front: bool, + } + + impl Iterator for Alternating { + type Item = I::Item; + + fn next(&mut self) -> Option { + if self.front { + self.front = false; + self.iter.next() + } else { + self.front = true; + self.iter.next_back() + } + } + } + trait AlternatingExt: Iterator + DoubleEndedIterator + Sized { + fn alternate(self) -> Alternating { + Alternating { + iter: self, + front: true, + } + } + } + impl AlternatingExt for I {} + #[test] fn ones() { let mut fb = FixedBitSet::with_capacity(100); @@ -1203,12 +1232,15 @@ mod tests { let ones: Vec<_> = fb.ones().collect(); let ones_rev: Vec<_> = fb.ones().rev().collect(); + let ones_alternating: Vec<_> = fb.ones().alternate().collect(); let mut known_result = vec![7, 11, 12, 35, 40, 50, 77, 95, 99]; assert_eq!(known_result, ones); known_result.reverse(); assert_eq!(known_result, ones_rev); + let known_result: Vec<_> = known_result.into_iter().rev().alternate().collect(); + assert_eq!(known_result, ones_alternating); } #[test] @@ -1221,7 +1253,13 @@ mod tests { } let ones: Vec<_> = fb.ones().collect(); let expected: Vec<_> = (from..to).collect(); + let ones_rev: Vec<_> = fb.ones().rev().collect(); + let expected_rev: Vec<_> = (from..to).rev().collect(); + let ones_rev_alt: Vec<_> = fb.ones().rev().alternate().collect(); + let expected_rev_alt: Vec<_> = (from..to).rev().alternate().collect(); assert_eq!(expected, ones); + assert_eq!(expected_rev, ones_rev); + assert_eq!(expected_rev_alt, ones_rev_alt); } for i in 0..100 { From 88df2e7b9db30dedd6c0cd527e478b045dbd55db Mon Sep 17 00:00:00 2001 From: till Date: Tue, 17 Oct 2023 21:57:49 +0200 Subject: [PATCH 04/11] try branching --- src/lib.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9fbe922..1d76bf6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -814,27 +814,30 @@ impl<'a> Iterator for Ones<'a> { #[inline] fn next(&mut self) -> Option { - let mut active_block: &mut Block = &mut self.bitset_front; - while *active_block == 0 { + //let mut active_block: &mut Block = &mut self.bitset_front; + while self.bitset_front == 0 { match self.remaining_blocks.next() { None => { if self.bitset_back != 0 { self.bitset_front = 0; self.block_idx_front = self.block_idx_back; - active_block = &mut self.bitset_back; + let t = self.bitset_back & (0 as Block).wrapping_sub(self.bitset_back); + let r = self.bitset_back.trailing_zeros() as usize; + self.bitset_back ^= t; + return Some(self.block_idx_back + r); } else { return None; } } Some(next_block) => { - *active_block = *next_block; + self.bitset_front = *next_block; self.block_idx_front += BITS; } }; } - let t = *active_block & (0 as Block).wrapping_sub(*active_block); - let r = active_block.trailing_zeros() as usize; - *active_block ^= t; + let t = self.bitset_front & (0 as Block).wrapping_sub(self.bitset_front); + let r = self.bitset_front.trailing_zeros() as usize; + self.bitset_front ^= t; Some(self.block_idx_front + r) } @@ -1848,7 +1851,7 @@ mod tests { tmp }; - assert!(ones == expected); + assert_eq!(ones, expected); } #[test] From e573488ae81418cbbe37b17871345028a9bc188d Mon Sep 17 00:00:00 2001 From: till Date: Tue, 17 Oct 2023 22:16:38 +0200 Subject: [PATCH 05/11] op change --- src/lib.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1d76bf6..8dea2af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -814,31 +814,31 @@ impl<'a> Iterator for Ones<'a> { #[inline] fn next(&mut self) -> Option { - //let mut active_block: &mut Block = &mut self.bitset_front; while self.bitset_front == 0 { match self.remaining_blocks.next() { + Some(next_block) => { + self.bitset_front = *next_block; + self.block_idx_front += BITS; + } None => { if self.bitset_back != 0 { self.bitset_front = 0; - self.block_idx_front = self.block_idx_back; - let t = self.bitset_back & (0 as Block).wrapping_sub(self.bitset_back); - let r = self.bitset_back.trailing_zeros() as usize; - self.bitset_back ^= t; - return Some(self.block_idx_back + r); + let bit_idx = self.bitset_back.trailing_zeros(); + let mask = !((1 as Block) << (bit_idx)); + self.bitset_back.bitand_assign(mask); + return Some(self.block_idx_back + bit_idx as Block); } else { return None; } } - Some(next_block) => { - self.bitset_front = *next_block; - self.block_idx_front += BITS; - } + }; } - let t = self.bitset_front & (0 as Block).wrapping_sub(self.bitset_front); - let r = self.bitset_front.trailing_zeros() as usize; - self.bitset_front ^= t; - Some(self.block_idx_front + r) + let bit_idx = self.bitset_front.trailing_zeros(); + let mask = !((1 as Block) << (bit_idx)); + self.bitset_front.bitand_assign(mask); + + Some(self.block_idx_front + bit_idx as Block) } #[inline] From 66c90a873c7624fb6c825c6a005035e6a7af5304 Mon Sep 17 00:00:00 2001 From: till Date: Tue, 17 Oct 2023 22:29:59 +0200 Subject: [PATCH 06/11] add different test --- benches/benches/benches.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/benches/benches/benches.rs b/benches/benches/benches.rs index 3165707..97286ba 100644 --- a/benches/benches/benches.rs +++ b/benches/benches/benches.rs @@ -55,6 +55,25 @@ fn iter_ones_all_zeros(c: &mut Criterion) { }); } +fn iter_ones_sparse(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb = FixedBitSet::with_capacity(N); + for i in 0..N{ + if i % 2 == 0{ + fb.insert(i); + } + } + c.bench_function("iter_ones/sparse", |b| { + b.iter(|| { + let mut count = 0; + for _ in fb.ones() { + count += 1; + } + count + }) + }); +} + fn iter_ones_all_ones(c: &mut Criterion) { const N: usize = 1_000_000; let mut fb = FixedBitSet::with_capacity(N); @@ -163,6 +182,7 @@ criterion_group!( iter_ones_using_contains_all_zeros, iter_ones_using_contains_all_ones, iter_ones_all_zeros, + iter_ones_sparse, iter_ones_all_ones, insert_range, insert, From 23014b8889fce31ad8badb37243c9948a9492701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20K=C3=B6ster?= Date: Wed, 18 Oct 2023 11:25:49 +0200 Subject: [PATCH 07/11] separate --- benches/benches/benches.rs | 17 +++++++++++++++-- src/lib.rs | 36 ++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/benches/benches/benches.rs b/benches/benches/benches.rs index 97286ba..42a2dc9 100644 --- a/benches/benches/benches.rs +++ b/benches/benches/benches.rs @@ -58,8 +58,8 @@ fn iter_ones_all_zeros(c: &mut Criterion) { fn iter_ones_sparse(c: &mut Criterion) { const N: usize = 1_000_000; let mut fb = FixedBitSet::with_capacity(N); - for i in 0..N{ - if i % 2 == 0{ + for i in 0..N { + if i % 2 == 0 { fb.insert(i); } } @@ -177,8 +177,21 @@ fn count_ones(c: &mut Criterion) { }); } +fn bitchange(c: &mut Criterion) { + let mut val: fixedbitset::Block = 1234; + c.bench_function("bitops/change_last_bit", |b| { + b.iter(|| { + val += 1; + val = val.rotate_left(10); + fixedbitset::Ones::last_positive_bit_and_unset(&mut val); + black_box(val) + }) + }); +} + criterion_group!( benches, + bitchange, iter_ones_using_contains_all_zeros, iter_ones_using_contains_all_ones, iter_ones_all_zeros, diff --git a/src/lib.rs b/src/lib.rs index 8dea2af..acd1a2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -778,6 +778,21 @@ pub struct Ones<'a> { remaining_blocks: std::slice::Iter<'a, Block>, } +impl<'a> Ones<'a> { + pub fn last_positive_bit_and_unset(n: &mut Block) -> usize { + // Find the last set bit using x & -x + let last_bit = *n & n.wrapping_neg(); + + // Find the position of the last set bit + let position = last_bit.trailing_zeros(); + + // Unset the last set bit using x & (x - 1) + *n &= *n - 1; + + position as usize + } +} + impl<'a> DoubleEndedIterator for Ones<'a> { fn next_back(&mut self) -> Option { let mut active_block: &mut Block = &mut self.bitset_back; @@ -817,28 +832,25 @@ impl<'a> Iterator for Ones<'a> { while self.bitset_front == 0 { match self.remaining_blocks.next() { Some(next_block) => { - self.bitset_front = *next_block; - self.block_idx_front += BITS; - } + self.bitset_front = *next_block; + self.block_idx_front += BITS; + } None => { if self.bitset_back != 0 { self.bitset_front = 0; - let bit_idx = self.bitset_back.trailing_zeros(); - let mask = !((1 as Block) << (bit_idx)); - self.bitset_back.bitand_assign(mask); - return Some(self.block_idx_back + bit_idx as Block); + + return Some( + self.block_idx_back + + Self::last_positive_bit_and_unset(&mut self.bitset_back), + ); } else { return None; } } - }; } - let bit_idx = self.bitset_front.trailing_zeros(); - let mask = !((1 as Block) << (bit_idx)); - self.bitset_front.bitand_assign(mask); - Some(self.block_idx_front + bit_idx as Block) + Some(self.block_idx_front + Self::last_positive_bit_and_unset(&mut self.bitset_front)) } #[inline] From 89566dad7c411fb572b8067d3902ec2c904089d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20K=C3=B6ster?= Date: Wed, 18 Oct 2023 11:32:44 +0200 Subject: [PATCH 08/11] performance via inlining --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index acd1a2e..f636bfa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -779,6 +779,7 @@ pub struct Ones<'a> { } impl<'a> Ones<'a> { + #[inline] pub fn last_positive_bit_and_unset(n: &mut Block) -> usize { // Find the last set bit using x & -x let last_bit = *n & n.wrapping_neg(); @@ -786,7 +787,7 @@ impl<'a> Ones<'a> { // Find the position of the last set bit let position = last_bit.trailing_zeros(); - // Unset the last set bit using x & (x - 1) + // Unset the last set bit *n &= *n - 1; position as usize From 2853cec7ef9c4d7e06f2661e8f45c086c3b1e365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20K=C3=B6ster?= Date: Wed, 18 Oct 2023 12:53:10 +0200 Subject: [PATCH 09/11] add size_hint test --- src/lib.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f636bfa..1e87194 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -838,6 +838,8 @@ impl<'a> Iterator for Ones<'a> { } None => { if self.bitset_back != 0 { + // not needed for iteration, but for size_hint + self.block_idx_front = self.block_idx_back; self.bitset_front = 0; return Some( @@ -856,8 +858,10 @@ impl<'a> Iterator for Ones<'a> { #[inline] fn size_hint(&self) -> (usize, Option) { - // todo check if + 1 or +2 is needed - (0, Some(self.remaining_blocks.as_slice().len() * BITS)) + ( + 0, + (Some(self.block_idx_back - self.block_idx_front + 2 * BITS)), + ) } } @@ -1205,14 +1209,19 @@ mod tests { } /* Helper for testing double ended iterator */ + #[cfg(test)] struct Alternating { iter: I, front: bool, } + #[cfg(test)] impl Iterator for Alternating { type Item = I::Item; + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } fn next(&mut self) -> Option { if self.front { self.front = false; @@ -1223,6 +1232,7 @@ mod tests { } } } + #[cfg(test)] trait AlternatingExt: Iterator + DoubleEndedIterator + Sized { fn alternate(self) -> Alternating { Alternating { @@ -1231,6 +1241,8 @@ mod tests { } } } + + #[cfg(test)] impl AlternatingExt for I {} #[test] @@ -1259,6 +1271,50 @@ mod tests { assert_eq!(known_result, ones_alternating); } + #[test] + fn size_hint() { + for s in 0..1000 { + let mut bitset = FixedBitSet::with_capacity(s); + bitset.insert_range(..); + let mut t = s; + let mut iter = bitset.ones().rev(); + loop { + match iter.next() { + None => break, + Some(_) => { + t -= 1; + assert!(iter.size_hint().1.unwrap() >= t); + // factor two, because we have first block and last block + assert!(iter.size_hint().1.unwrap() <= t + 2 * BITS); + } + } + } + assert_eq!(t, 0); + } + } + + #[test] + fn size_hint_alternate() { + for s in 0..1000 { + let mut bitset = FixedBitSet::with_capacity(s); + bitset.insert_range(..); + let mut t = s; + let mut iter = bitset.ones().alternate(); + loop { + match iter.next() { + None => break, + Some(_) => { + t -= 1; + //println!("{:?} < {}", iter.size_hint(), t); + assert!(iter.size_hint().1.unwrap() >= t); + assert!(iter.size_hint().1.unwrap() <= t + 3 * BITS); + } + } + } + assert_eq!(t, 0); + } + } + #[test] fn iter_ones_range() { fn test_range(from: usize, to: usize, capa: usize) { From ffefedfd18b4f120c3203779f42a4e2c9e3fd25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20K=C3=B6ster?= Date: Wed, 18 Oct 2023 13:30:41 +0200 Subject: [PATCH 10/11] add new version for rev --- src/lib.rs | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1e87194..dbbac74 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -792,36 +792,48 @@ impl<'a> Ones<'a> { position as usize } + + #[inline] + pub fn first_positive_bit_and_unset(n: &mut Block) -> usize { + /* Identify the first non zero bit */ + let bit_idx = n.leading_zeros(); + + /* set that bit to zero */ + let mask = !((1 as Block) << (BITS as u32 - bit_idx - 1)); + n.bitand_assign(mask); + + bit_idx as usize + } } impl<'a> DoubleEndedIterator for Ones<'a> { fn next_back(&mut self) -> Option { - let mut active_block: &mut Block = &mut self.bitset_back; - while *active_block == 0 { + while self.bitset_back == 0 { match self.remaining_blocks.next_back() { None => { if self.bitset_front != 0 { self.bitset_back = 0; self.block_idx_back = self.block_idx_front; - active_block = &mut self.bitset_front; + return Some( + self.block_idx_front + BITS + - Self::first_positive_bit_and_unset(&mut self.bitset_front) + - 1, + ); } else { return None; } } Some(next_block) => { - *active_block = *next_block; + self.bitset_back = *next_block; self.block_idx_back -= BITS; } }; } - /* Identify the first non zero bit */ - let bit_idx = active_block.leading_zeros(); - /* set that bit to zero */ - let mask = !((1 as Block) << (BITS as u32 - bit_idx - 1)); - active_block.bitand_assign(mask); - - Some(self.block_idx_back + BITS - bit_idx as usize - 1) + Some( + self.block_idx_back - Self::first_positive_bit_and_unset(&mut self.bitset_back) + BITS + - 1, + ) } } @@ -1090,6 +1102,12 @@ mod tests { let ones: Vec<_> = fb.ones().collect(); assert_eq!(ones.len(), 1); + + let ones: Vec<_> = fb.ones().rev().collect(); + assert_eq!(ones.len(), 1); + + let ones: Vec<_> = fb.ones().rev().alternate().collect(); + assert_eq!(ones.len(), 1); } #[test] From 37eaf055e53fc91daa7c9558de8779a01bdc4e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20K=C3=B6ster?= Date: Wed, 18 Oct 2023 13:52:33 +0200 Subject: [PATCH 11/11] fix bench --- benches/benches/benches.rs | 28 ++++++++++++++++------------ src/lib.rs | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/benches/benches/benches.rs b/benches/benches/benches.rs index 42a2dc9..0e7dbc5 100644 --- a/benches/benches/benches.rs +++ b/benches/benches/benches.rs @@ -90,6 +90,22 @@ fn iter_ones_all_ones(c: &mut Criterion) { }); } +fn iter_ones_all_ones_rev(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb = FixedBitSet::with_capacity(N); + fb.insert_range(..); + + c.bench_function("iter_ones/all_ones", |b| { + b.iter(|| { + let mut count = 0; + for _ in fb.ones().rev() { + count += 1; + } + count + }) + }); +} + fn insert_range(c: &mut Criterion) { const N: usize = 1_000_000; let mut fb = FixedBitSet::with_capacity(N); @@ -177,18 +193,6 @@ fn count_ones(c: &mut Criterion) { }); } -fn bitchange(c: &mut Criterion) { - let mut val: fixedbitset::Block = 1234; - c.bench_function("bitops/change_last_bit", |b| { - b.iter(|| { - val += 1; - val = val.rotate_left(10); - fixedbitset::Ones::last_positive_bit_and_unset(&mut val); - black_box(val) - }) - }); -} - criterion_group!( benches, bitchange, diff --git a/src/lib.rs b/src/lib.rs index dbbac74..af8084f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -794,7 +794,7 @@ impl<'a> Ones<'a> { } #[inline] - pub fn first_positive_bit_and_unset(n: &mut Block) -> usize { + fn first_positive_bit_and_unset(n: &mut Block) -> usize { /* Identify the first non zero bit */ let bit_idx = n.leading_zeros();