#![feature(test)] extern crate test; use bitvec::prelude::*; use test::{ bench::black_box, Bencher, }; #[bench] fn ref_iter(b: &mut Bencher) { b.iter(|| { let src = [1, 2, 3].repeat(100); let bits = BitSlice::::from_slice(black_box(&src)); // assert_eq!(bits.len(), 24); // assert_eq!(bits.as_slice().len(), 3); // assert!(bits[7]); // src[0] == 0b0000_0001 // assert!(bits[14]); // src[1] == 0b0000_0010 // assert!(bits[22]); // src[2] == 0b0000_0011 // assert!(bits[23]); let mut count = 0; for bit in bits.iter() { count += black_box(*bit as u32); } println!("{}", count); }); } #[bench] fn val_iter(b: &mut Bencher) { b.iter(|| { struct Viter { ptr: *const T, end: *const T, bit_ptr: T, bit_end: T, } impl Viter { const LAST_BIT: u8 = 1_u8.rotate_right(1); } macro_rules! is_empty { ($self:ident) => {{ $self.ptr == $self.end && $self.bit_ptr == $self.bit_end }}; } impl Iterator for Viter { type Item=bool; fn next(&mut self) -> Option { if is_empty!(self) { None } else { let old = unsafe { let old = (*self.ptr & self.bit_ptr) != 0; if self.bit_ptr == 1 { self.bit_ptr = Self::LAST_BIT; self.ptr = self.ptr.offset(1); } else { self.bit_ptr >>= 1; } old }; Some(old) } } } fn valiter(sli: &BitSlice) -> Viter { Viter { ptr: sli.as_ptr(), end: unsafe { sli.as_ptr().offset(sli.len() as isize / 8 + (sli.len() % 8 == 0) as isize) }, // This should (and could) be computed but for this small bench it's const. bit_ptr: Viter::::LAST_BIT, bit_end: 1, } } let src = [4, 5, 6].repeat(100); let bits = BitSlice::::from_slice(black_box(&src)); // assert_eq!(bits.len(), 24); // assert_eq!(bits.as_slice().len(), 3); // assert!(bits[7]); // src[0] == 0b0000_0001 // assert!(bits[14]); // src[1] == 0b0000_0010 // assert!(bits[22]); // src[2] == 0b0000_0011 // assert!(bits[23]); let mut count = 0; for bit in valiter(bits) { count += black_box(bit as u32); } println!("{}", count); }); } #[bench] fn fast_ref_iter(b: &mut Bencher) { b.iter(|| { struct Viter<'a, T> { ptr: *const T, end: *const T, bit_ptr: T, bit_end: T, _marker: std::marker::PhantomData<&'a T>, } impl Viter<'_, u8> { const LAST_BIT: u8 = 1_u8.rotate_right(1); } macro_rules! is_empty { ($self:ident) => {{ $self.ptr == $self.end && $self.bit_ptr == $self.bit_end }}; } impl<'a> Iterator for Viter<'a, u8> { type Item= &'a bool; fn next(&mut self) -> Option { if is_empty!(self) { None } else { let old = unsafe { let old = (*self.ptr & self.bit_ptr) != 0; if self.bit_ptr == 1 { self.bit_ptr = Self::LAST_BIT; self.ptr = self.ptr.offset(1); } else { self.bit_ptr >>= 1; } old }; Some(if old {&true}else{&false}) } } } fn valiter(sli: &BitSlice) -> Viter { Viter { ptr: sli.as_ptr(), end: unsafe { sli.as_ptr().offset(sli.len() as isize / 8 + (sli.len() % 8 == 0) as isize) }, // This should (and could) be computed but for this small bench it's const. bit_ptr: Viter::::LAST_BIT, bit_end: 1, _marker: std::marker::PhantomData, } } let src = [7, 8, 9].repeat(100); let bits = BitSlice::::from_slice(black_box(&src)); // assert_eq!(bits.len(), 24); // assert_eq!(bits.as_slice().len(), 3); // assert!(bits[7]); // src[0] == 0b0000_0001 // assert!(bits[14]); // src[1] == 0b0000_0010 // assert!(bits[22]); // src[2] == 0b0000_0011 // assert!(bits[23]); let mut count = 0; for bit in valiter(bits) { count += black_box(*bit as u32); } println!("{}", count); }); } #[cfg(test)] mod tests { use bitvec::prelude::*; #[test] fn iter_benches() { let src = [1, 2, 3].repeat(100); let bits = BitSlice::::from_slice((&src)); let mut count = 0; for bit in bits.iter() { count += (*bit as u32); } println!("{}", count); assert_eq!(count, (src[0].count_ones() + src[1].count_ones() + src[2].count_ones()) * 100); struct Viter { ptr: *const T, end: *const T, bit_ptr: T, bit_end: T, } impl Viter { const LAST_BIT: u8 = 1_u8.rotate_right(1); } macro_rules! is_empty { ($self:ident) => {{ $self.ptr == $self.end && $self.bit_ptr == $self.bit_end }}; } impl Iterator for Viter { type Item=bool; fn next(&mut self) -> Option { if is_empty!(self) { None } else { let old = unsafe { let old = (*self.ptr & self.bit_ptr) != 0; if self.bit_ptr == 1 { self.bit_ptr = Self::LAST_BIT; self.ptr = self.ptr.offset(1); } else { self.bit_ptr >>= 1; } old }; Some(old) } } } fn valiter(sli: &BitSlice) -> Viter { Viter { ptr: sli.as_ptr(), end: unsafe { sli.as_ptr().offset(sli.len() as isize / 8 + (sli.len() % 8 == 0) as isize) }, // This should (and could) be computed but for this small bench it's const. bit_ptr: Viter::::LAST_BIT, bit_end: 1, } } let src = [4, 5, 6].repeat(100); let bits = BitSlice::::from_slice((&src)); // assert_eq!(bits.len(), 24); // assert_eq!(bits.as_slice().len(), 3); // assert!(bits[7]); // src[0] == 0b0000_0001 // assert!(bits[14]); // src[1] == 0b0000_0010 // assert!(bits[22]); // src[2] == 0b0000_0011 // assert!(bits[23]); let mut count = 0; for bit in valiter(bits) { count += (bit as u32); } println!("{}", count); assert_eq!(count, (src[0].count_ones() + src[1].count_ones() + src[2].count_ones()) * 100); struct Viter_ref<'a, T> { ptr: *const T, end: *const T, bit_ptr: T, bit_end: T, _marker: std::marker::PhantomData<&'a T>, } impl Viter_ref<'_, u8> { const LAST_BIT: u8 = 1_u8.rotate_right(1); } macro_rules! is_empty { ($self:ident) => {{ $self.ptr == $self.end && $self.bit_ptr == $self.bit_end }}; } impl<'a> Iterator for Viter_ref<'a, u8> { type Item= &'a bool; fn next(&mut self) -> Option { if is_empty!(self) { None } else { let old = unsafe { let old = (*self.ptr & self.bit_ptr) != 0; if self.bit_ptr == 1 { self.bit_ptr = Self::LAST_BIT; self.ptr = self.ptr.offset(1); } else { self.bit_ptr >>= 1; } old }; Some(if old {&true}else{&false}) } } } fn valiter_ref(sli: &BitSlice) -> Viter_ref { Viter_ref { ptr: sli.as_ptr(), end: unsafe { sli.as_ptr().offset(sli.len() as isize / 8 + (sli.len() % 8 == 0) as isize) }, // This should (and could) be computed but for this small bench it's const. bit_ptr: Viter_ref::::LAST_BIT, bit_end: 1, _marker: std::marker::PhantomData, } } let src = [7, 8, 9].repeat(100); let bits = BitSlice::::from_slice((&src)); // assert_eq!(bits.len(), 24); // assert_eq!(bits.as_slice().len(), 3); // assert!(bits[7]); // src[0] == 0b0000_0001 // assert!(bits[14]); // src[1] == 0b0000_0010 // assert!(bits[22]); // src[2] == 0b0000_0011 // assert!(bits[23]); let mut count = 0; for bit in valiter_ref(bits) { count += (*bit as u32); } println!("{}", count); assert_eq!(count, (src[0].count_ones() + src[1].count_ones() + src[2].count_ones()) * 100); } }