Skip to content

Commit 1dbcc59

Browse files
committed
Added unchecked_get() and unchecked_set()
Added inline on bits_per_block() and bytes_per_block() Added tests
1 parent 5ce7485 commit 1dbcc59

File tree

2 files changed

+149
-2
lines changed

2 files changed

+149
-2
lines changed

benches/comparative.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ fn comparative(c: &mut Criterion) {
4141

4242
c.bench_function("Vob comparative", |b| {
4343
b.iter(|| {
44-
let mut vob: vob::Vob<u32> = vob::Vob::new_with_storage_type(SIZE);
45-
vob.resize(SIZE, false);
44+
let mut vob = vob::Vob::<u32>::from_elem_with_storage_type(false, SIZE);
4645

4746
// set half of the vob to true
4847
for index in indices.iter().skip(SIZE / 2) {
@@ -58,6 +57,34 @@ fn comparative(c: &mut Criterion) {
5857
})
5958
});
6059

60+
c.bench_function("Vob unchecked comparative", |b| {
61+
b.iter(|| {
62+
let mut vob = vob::Vob::<u32>::from_elem_with_storage_type(false, SIZE);
63+
64+
unsafe {
65+
// set half of the vob to true
66+
for index in indices.iter().skip(SIZE / 2) {
67+
vob.set_unchecked(*index, true);
68+
}
69+
70+
for index in indices.iter().take(SIZE / 2) {
71+
assert!(
72+
!vob.get_unchecked(*index),
73+
"index {} is supposed to be cleared",
74+
index
75+
);
76+
}
77+
for index in indices.iter().skip(SIZE / 2) {
78+
assert!(
79+
vob.get_unchecked(*index),
80+
"index {} is supposed to be set",
81+
index
82+
);
83+
}
84+
}
85+
})
86+
});
87+
6188
c.bench_function("Vec comparative", |b| {
6289
b.iter(|| {
6390
let mut vec: Vec<bool> = vec![false; SIZE];
@@ -75,6 +102,33 @@ fn comparative(c: &mut Criterion) {
75102
}
76103
})
77104
});
105+
106+
c.bench_function("Vec unchecked comparative", |b| {
107+
b.iter(|| {
108+
let mut vec: Vec<bool> = vec![false; SIZE];
109+
unsafe {
110+
// set half of the vec to true
111+
for index in indices.iter().skip(SIZE / 2) {
112+
*vec.get_unchecked_mut(*index) = true;
113+
}
114+
115+
for index in indices.iter().take(SIZE / 2) {
116+
assert!(
117+
!vec.get_unchecked(*index),
118+
"index {} is supposed to be cleared",
119+
index
120+
);
121+
}
122+
for index in indices.iter().skip(SIZE / 2) {
123+
assert!(
124+
vec.get_unchecked(*index),
125+
"index {} is supposed to be set",
126+
index
127+
);
128+
}
129+
}
130+
})
131+
});
78132
}
79133

80134
criterion_group!(benches, comparative);

src/lib.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,32 @@ impl<T: Debug + PrimInt> Vob<T> {
424424
Some(blk & (T::one() << (index % bits_per_block::<T>())) != T::zero())
425425
}
426426

427+
/// Returns the value of the element at position `index`. This is done without doing bounds
428+
/// checking. For a safe alternative see [`get`].
429+
///
430+
/// # Safety
431+
///
432+
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
433+
///
434+
/// You can think of this like `.get(index).unwrap_unchecked()`.
435+
///
436+
/// [`get`]: crate::Vob::get
437+
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
438+
///
439+
/// # Examples
440+
/// ```
441+
/// use vob::Vob;
442+
/// let mut v = Vob::new();
443+
/// v.push(false);
444+
/// unsafe {
445+
/// assert_eq!(v.get_unchecked(0), false);
446+
/// }
447+
/// ```
448+
pub unsafe fn get_unchecked(&self, index: usize) -> bool {
449+
let blk = *self.vec.get_unchecked(block_offset::<T>(index));
450+
blk & (T::one() << (index % bits_per_block::<T>())) != T::zero()
451+
}
452+
427453
/// Sets the value of the element at position `index`. Returns `true` if this led to a change
428454
/// in the underlying storage or `false` otherwise.
429455
///
@@ -460,6 +486,43 @@ impl<T: Debug + PrimInt> Vob<T> {
460486
}
461487
}
462488

489+
/// Sets the value of the element at position `index`. Returns `true` if this led to a change
490+
/// in the underlying storage or `false` otherwise. This is done without doing bounds
491+
/// checking. For a safe alternative see [`set`].
492+
///
493+
/// # Safety
494+
///
495+
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
496+
///
497+
/// [`set`]: crate::Vob::set
498+
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
499+
///
500+
/// # Examples
501+
/// ```
502+
/// use vob::Vob;
503+
/// let mut v = Vob::new();
504+
/// v.push(false);
505+
/// unsafe {
506+
/// v.set_unchecked(0, true);
507+
/// assert_eq!(v.get_unchecked(0), true);
508+
/// assert_eq!(v.set_unchecked(0, false), true);
509+
/// assert_eq!(v.set_unchecked(0, false), false);
510+
/// assert_eq!(v.get_unchecked(0), false);
511+
/// }
512+
/// ```
513+
pub unsafe fn set_unchecked(&mut self, index: usize, value: bool) -> bool {
514+
let msk = T::one() << (index % bits_per_block::<T>());
515+
let off = block_offset::<T>(index);
516+
let old_v = *self.vec.get_unchecked(off);
517+
let new_v = if value { old_v | msk } else { old_v & !msk };
518+
if new_v != old_v {
519+
*self.vec.get_unchecked_mut(off) = new_v;
520+
true
521+
} else {
522+
false
523+
}
524+
}
525+
463526
/// Returns an iterator over the slice.
464527
///
465528
/// # Examples
@@ -1188,11 +1251,13 @@ impl<T: Debug + PrimInt> Iterator for StorageIter<'_, T> {
11881251
}
11891252
}
11901253

1254+
#[inline(always)]
11911255
/// How many bits are stored in each underlying storage block?
11921256
fn bits_per_block<T>() -> usize {
11931257
bytes_per_block::<T>() * 8
11941258
}
11951259

1260+
#[inline(always)]
11961261
/// How many bytes are stored in each underlying storage block?
11971262
fn bytes_per_block<T>() -> usize {
11981263
size_of::<T>()
@@ -1510,11 +1575,18 @@ mod tests {
15101575
assert_eq!(v.get(size_of::<u8>() * 8), Some(true));
15111576
v.set(size_of::<u8>() * 8, false);
15121577
assert_eq!(v.get(size_of::<u8>() * 8), Some(false));
1578+
unsafe {
1579+
assert_eq!(v.get_unchecked(size_of::<u8>() * 8 ), false);
1580+
}
15131581
assert_eq!(v.get(size_of::<u8>() * 8 + 1), None);
15141582
assert_eq!(v.set(size_of::<u8>() * 8, true), true);
15151583
assert_eq!(v.set(size_of::<u8>() * 8, true), false);
15161584
assert_eq!(v.get(size_of::<u8>() * 8 - 1), Some(true));
15171585
assert_eq!(v.get(size_of::<u8>() * 8 - 2), Some(true));
1586+
unsafe {
1587+
assert_eq!(v.get_unchecked(size_of::<u8>() * 8 - 2), true);
1588+
assert_eq!(v.set_unchecked(size_of::<u8>() * 8 - 2, true), false);
1589+
}
15181590
}
15191591

15201592
#[test]
@@ -1565,6 +1637,10 @@ mod tests {
15651637
assert_eq!(v.set(size_of::<usize>() * 8, true), false);
15661638
assert_eq!(v.get(size_of::<usize>() * 8 - 1), Some(true));
15671639
assert_eq!(v.get(size_of::<usize>() * 8 - 2), Some(true));
1640+
unsafe {
1641+
assert_eq!(v.get_unchecked(size_of::<usize>() * 8 - 2), true);
1642+
assert_eq!(v.set_unchecked(size_of::<usize>() * 8 - 2, true), false);
1643+
}
15681644
}
15691645

15701646
#[test]
@@ -1858,6 +1934,23 @@ mod tests {
18581934
}
18591935
}
18601936

1937+
#[test]
1938+
fn test_unchecked() {
1939+
unsafe {
1940+
for len_a in 0..128 {
1941+
let mut a = random_vob(len_a as usize);
1942+
let mut b = a.clone();
1943+
for i in 0..len_a {
1944+
assert_eq!(a.get(i).unwrap(), b.get_unchecked(i));
1945+
assert_eq!(a.set(i,false), b.set_unchecked(i,false));
1946+
assert!(!b.get_unchecked(i));
1947+
assert_eq!(a.set(i,true), b.set_unchecked(i,true));
1948+
assert!(b.get_unchecked(i));
1949+
}
1950+
}
1951+
}
1952+
}
1953+
18611954
#[test]
18621955
fn push_adjusts_vec_correctly() {
18631956
let mut v = Vob::new();

0 commit comments

Comments
 (0)