diff --git a/benches/bench.rs b/benches/bench.rs index 36372eb..871714e 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(test)] +#![feature(hint_assert_unchecked)] extern crate bit_vec; extern crate rand; @@ -76,6 +77,60 @@ fn bench_bit_set_small(b: &mut Bencher) { }); } +#[bench] +fn bench_bit_get_checked_small(b: &mut Bencher) { + let mut r = small_rng(); + let size = 200; + let mut bit_vec = BitVec::from_elem(size, false); + for _ in 0..20 { + bit_vec.set((r.next_u32() as usize) % size, true); + } + let bit_vec = black_box(bit_vec); + b.iter(|| { + for _ in 0..100 { + black_box(bit_vec.get((r.next_u32() as usize) % size)); + } + }); +} + +#[bench] +fn bench_bit_get_unchecked_small(b: &mut Bencher) { + let mut r = small_rng(); + let size = 200; + let mut bit_vec = BitVec::from_elem(size, false); + for _ in 0..20 { + bit_vec.set((r.next_u32() as usize) % size, true); + } + let bit_vec = black_box(bit_vec); + b.iter(|| { + for _ in 0..100 { + unsafe { + black_box(bit_vec.get_unchecked((r.next_u32() as usize) % size)); + } + } + }); +} + +#[bench] +fn bench_bit_get_unchecked_small_assume(b: &mut Bencher) { + let mut r = small_rng(); + let size = 200; + let mut bit_vec = BitVec::from_elem(size, false); + for _ in 0..20 { + bit_vec.set((r.next_u32() as usize) % size, true); + } + let bit_vec = black_box(bit_vec); + b.iter(|| { + for _ in 0..100 { + unsafe { + let idx = (r.next_u32() as usize) % size; + ::std::hint::assert_unchecked(!(idx >= bit_vec.len())); + black_box(bit_vec.get(idx)); + } + } + }); +} + #[bench] fn bench_bit_vec_big_or(b: &mut Bencher) { let mut b1 = BitVec::from_elem(BENCH_BITS, false); diff --git a/src/lib.rs b/src/lib.rs index 74702f2..bd9b333 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -554,14 +554,33 @@ impl BitVec { .map(|&block| (block & (B::one() << b)) != B::zero()) } + /// Retrieves the value at index `i`, without doing bounds checking. + /// + /// For a safe alternative, see `get`. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is undefined behavior + /// even if the resulting reference is not used. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b01100000]); + /// unsafe { + /// assert_eq!(bv.get_unchecked(0), false); + /// assert_eq!(bv.get_unchecked(1), true); + /// } + /// ``` #[inline] - pub fn get_unchecked(&self, i: usize) -> bool { + pub unsafe fn get_unchecked(&self, i: usize) -> bool { self.ensure_invariant(); let w = i / B::bits(); let b = i % B::bits(); - self.storage.get(w).map(|&block| - (block & (B::one() << b)) != B::zero() - ).unwrap() + let block = *self.storage.get_unchecked(w); + block & (B::one() << b) != B::zero() } /// Sets the value of a bit at an index `i`.