diff --git a/src/lib.rs b/src/lib.rs index 04a45ab..371315e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ use std::{ cmp::{min, PartialEq}, fmt::{self, Debug}, hash::{Hash, Hasher}, - iter::FromIterator, + iter::{DoubleEndedIterator, FromIterator}, mem::{replace, size_of}, ops::{ Bound::{Excluded, Included, Unbounded}, @@ -1101,6 +1101,10 @@ impl<'a, T: Debug + PrimInt> IntoIterator for &'a Vob { } } +// In all of the iterators below, we try to optimise what we expect to be the common cases (all +// bits set or all bits unset) with the general case (random bit patterns). We assume that +// `leading_zeros` and `trailing_zeros` have efficient implementations on most CPUs. + #[derive(Clone)] pub struct IterSetBits<'a, T: 'a> { vob: &'a Vob, @@ -1113,24 +1117,15 @@ impl Iterator for IterSetBits<'_, T> { fn next(&mut self) -> Option { debug_assert!(self.range.end <= self.vob.len); if let Some(i) = self.range.next() { - // This is a long, but fairly fast, way of finding out what the next set bit is. The - // basic problem is that we have no idea where the next set bit is -- but different - // patterns of set bits are most efficiently handled by different code paths. This code - // is thus a compromise: we prioritise two special cases (all bits set; all bits unset) - // for efficiency, and try and make the other possible cases reasonably fast. let mut b = block_offset::(i); let mut v = self.vob.vec[b]; - // If all bits are set, we don't need to do any complicated checks. if v == T::max_value() { return Some(i); } - // At this point we've got a block which might or might not have some bits set. We now - // fall back to the general case. let mut i_off = i % bits_per_block::(); loop { let tz = (v >> i_off).trailing_zeros() as usize; if tz < bits_per_block::() { - // There is a bit set after i_off in the block. let bs = b * bits_per_block::() + i_off + tz; self.range.start = bs + 1; if bs >= self.range.end { @@ -1140,7 +1135,6 @@ impl Iterator for IterSetBits<'_, T> { } b += 1; if b == blocks_required::(self.range.end) { - // We've exhausted the iterator. self.range.start = self.range.end; break; } @@ -1156,6 +1150,38 @@ impl Iterator for IterSetBits<'_, T> { } } +impl DoubleEndedIterator for IterSetBits<'_, T> { + fn next_back(&mut self) -> Option { + if let Some(i) = self.range.next_back() { + let mut b = block_offset::(i); + let mut v = self.vob.vec[b]; + if v == T::max_value() { + return Some(i); + } + let mut i_off = i % bits_per_block::(); + loop { + let lz = (v << (bits_per_block::() - 1 - i_off)).leading_zeros() as usize; + if lz < bits_per_block::() { + let bs = b * bits_per_block::() + i_off - lz; + self.range.end = bs; + if bs < self.range.start { + break; + } + return Some(bs); + } + if b == block_offset::(self.range.start) { + self.range.start = self.range.end; + break; + } + b -= 1; + v = self.vob.vec[b]; + i_off = bits_per_block::() - 1; + } + } + None + } +} + #[derive(Clone)] pub struct IterUnsetBits<'a, T: 'a> { vob: &'a Vob, @@ -1168,19 +1194,11 @@ impl Iterator for IterUnsetBits<'_, T> { fn next(&mut self) -> Option { debug_assert!(self.range.end <= self.vob.len); if let Some(i) = self.range.next() { - // This is a long, but fairly fast, way of finding out what the next usset bit is. The - // basic problem is that we have no idea where the next set bit is -- but different - // patterns of set bits are most efficiently handled by different code paths. This code - // is thus a compromise: we prioritise two special cases (all bits set; all bits unset) - // for efficiency, and try and make the other possible cases reasonably fast. let mut b = block_offset::(i); let mut v = self.vob.vec[b]; - // If no bits are set, we don't need to do any complicated checks. if v == T::zero() { return Some(i); } - // At this point we've got a block which might or might not have some bits unset. We - // now fall back to the general case. let mut i_off = i % bits_per_block::(); loop { let tz = (!v >> i_off).trailing_zeros() as usize; @@ -1189,15 +1207,12 @@ impl Iterator for IterUnsetBits<'_, T> { let bs = b * bits_per_block::() + i_off + tz; self.range.start = bs + 1; if bs >= self.range.end { - // The unset bit is after the range we're looking for, so we've reached - // the end of the iterator. break; } return Some(bs); } b += 1; if b == blocks_required::(self.range.end) { - // We've exhausted the iterator. self.range.start = self.range.end; break; } @@ -1542,6 +1557,7 @@ mod tests { hash::{Hash, Hasher}, iter::FromIterator, mem::size_of, + ops::RangeBounds, }; #[test] @@ -1791,8 +1807,23 @@ mod tests { #[test] fn test_iter_set_bits() { + fn t(v: &Vob, range: R, expected: Vec) + where + R: Clone + RangeBounds, + { + let rev = expected.iter().cloned().rev().collect::>(); + assert_eq!( + v.iter_set_bits(range.clone()).collect::>(), + expected + ); + assert_eq!(v.iter_set_bits(range).rev().collect::>(), rev); + } + + t(&vob![], .., vec![]); + t(&Vob::from_elem(true, 131), .., (0..131).collect::>()); + let mut v1 = vob![false, true, false, true]; - assert_eq!(v1.iter_set_bits(..).collect::>(), vec![1, 3]); + t(&v1, .., vec![1, 3]); v1.resize(127, false); v1.push(true); v1.push(false); @@ -1800,19 +1831,14 @@ mod tests { v1.push(true); v1.resize(256, false); v1.push(true); - assert_eq!( - v1.iter_set_bits(..).collect::>(), - vec![1, 3, 127, 129, 130, 256] - ); - assert_eq!( - v1.iter_set_bits(2..256).collect::>(), - vec![3, 127, 129, 130] - ); - assert_eq!( - v1.iter_set_bits(2..).collect::>(), - vec![3, 127, 129, 130, 256] - ); - assert_eq!(v1.iter_set_bits(..3).collect::>(), vec![1]); + assert_eq!(v1.len(), 257); + t(&v1, .., vec![1, 3, 127, 129, 130, 256]); + t(&v1, 2..257, vec![3, 127, 129, 130, 256]); + t(&v1, 2..256, vec![3, 127, 129, 130]); + t(&v1, 2.., vec![3, 127, 129, 130, 256]); + t(&v1, 1..255, vec![1, 3, 127, 129, 130]); + t(&v1, ..3, vec![1]); + t(&v1, 128.., vec![129, 130, 256]); } #[test]