diff --git a/benches/bench.rs b/benches/bench.rs index d5915d4..b78b934 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -42,6 +42,18 @@ fn bench_usize_small(b: &mut Bencher) { }); } +#[bench] +fn bench_to_bytes(b: &mut Bencher) { + let mut bit_vec = BitVec::from_elem(BENCH_BITS, false); + let mut r = small_rng(); + for _ in 0..BENCH_BITS / 10 { + bit_vec.set((r.next_u32() as usize) % BENCH_BITS, true); + } + b.iter(|| { + black_box(bit_vec.to_bytes()); + }); +} + #[bench] fn bench_bit_set_big_fixed(b: &mut Bencher) { let mut r = small_rng(); diff --git a/src/lib.rs b/src/lib.rs index ad32249..a3cc587 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1322,30 +1322,35 @@ impl BitVec { /// assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]); /// ``` pub fn to_bytes(&self) -> Vec { + static REVERSE_TABLE: [u8; 256] = { + let mut tbl = [0u8; 256]; + let mut i: u8 = 0; + loop { + tbl[i as usize] = i.reverse_bits(); + if i == 255 { + break; + } + i += 1; + } + tbl + }; self.ensure_invariant(); - // Oh lord, we're mapping this to bytes bit-by-bit! - fn bit(bit_vec: &BitVec, byte: usize, bit: usize) -> u8 { - let offset = byte * 8 + bit; - if offset >= bit_vec.nbits { - 0 - } else { - (bit_vec[offset] as u8) << (7 - bit) + + let len = self.nbits / 8 + if self.nbits % 8 == 0 { 0 } else { 1 }; + let mut result = Vec::with_capacity(len); + + for byte_idx in 0..len { + let mut byte = 0u8; + for bit_idx in 0..8 { + let offset = byte_idx * 8 + bit_idx; + if offset < self.nbits && self[offset] { + byte |= 1 << bit_idx; + } } + result.push(REVERSE_TABLE[byte as usize]); } - let len = self.nbits / 8 + if self.nbits % 8 == 0 { 0 } else { 1 }; - (0..len) - .map(|i| { - bit(self, i, 0) - | bit(self, i, 1) - | bit(self, i, 2) - | bit(self, i, 3) - | bit(self, i, 4) - | bit(self, i, 5) - | bit(self, i, 6) - | bit(self, i, 7) - }) - .collect() + result } /// Compares a `BitVec` to a slice of `bool`s.