Skip to content

Commit b8a4187

Browse files
authored
Merge pull request #448 from cuviper/assert_index
Unify index assertions with new util functions
2 parents 571943c + eae6655 commit b8a4187

5 files changed

Lines changed: 45 additions & 53 deletions

File tree

‎src/inner.rs‎

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use core::mem;
1515
use core::ops::RangeBounds;
1616
use hashbrown::hash_table;
1717

18-
use crate::util::simplify_range;
18+
use crate::util::{assert_index_le, assert_index_lt, simplify_range};
1919
use crate::{Bucket, Equivalent, HashValue, TryReserveError};
2020

2121
type Indices = hash_table::HashTable<usize>;
@@ -195,11 +195,7 @@ impl<K, V> Core<K, V> {
195195

196196
#[track_caller]
197197
pub(crate) fn split_off(&mut self, at: usize) -> Self {
198-
let len = self.entries.len();
199-
assert!(
200-
at <= len,
201-
"index out of bounds: the len is {len} but the index is {at}. Expected index <= len"
202-
);
198+
assert_index_le(at, self.len());
203199

204200
self.erase_indices(at, self.entries.len());
205201
let entries = self.entries.split_off(at);
@@ -651,9 +647,10 @@ impl<K, V> Core<K, V> {
651647

652648
#[track_caller]
653649
pub(super) fn move_index(&mut self, from: usize, to: usize) {
650+
assert_index_lt(from, self.len());
654651
let from_hash = self.entries[from].hash;
655652
if from != to {
656-
let _ = self.entries[to]; // explicit bounds check
653+
assert_index_lt(to, self.len());
657654

658655
// Find the bucket index first so we won't lose it among other updated indices.
659656
let bucket = self
@@ -679,13 +676,14 @@ impl<K, V> Core<K, V> {
679676

680677
#[track_caller]
681678
pub(crate) fn swap_indices(&mut self, a: usize, b: usize) {
682-
// If they're equal and in-bounds, there's nothing to do.
683-
if a == b && a < self.entries.len() {
679+
assert_index_lt(a, self.len());
680+
if a == b {
681+
// If they're equal, there's nothing to do.
684682
return;
685683
}
684+
assert_index_lt(b, self.len());
686685

687-
// We'll get a "nice" bounds-check from indexing `entries`,
688-
// and then we expect to find it in the table as well.
686+
// Since the indices are in-bounds, we expect to find them in the table as well.
689687
match self.indices.get_disjoint_mut(
690688
[self.entries[a].hash.get(), self.entries[b].hash.get()],
691689
move |i, &x| if i == 0 { x == a } else { x == b },

‎src/inner/entry.rs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::{Bucket, Core, equal, get_hash};
22
use crate::HashValue;
33
use crate::map::{Entry, IndexedEntry};
4+
use crate::util::assert_index_lt;
45
use core::cmp::Ordering;
56
use core::mem;
67

@@ -199,7 +200,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
199200
#[track_caller]
200201
pub fn move_index(self, to: usize) {
201202
if self.index != to {
202-
let _ = self.map.entries[to]; // explicit bounds check
203+
assert_index_lt(to, self.map.len());
203204
self.map.move_index_inner(self.index, to);
204205
self.update_index(to);
205206
}
@@ -216,6 +217,8 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
216217
#[track_caller]
217218
pub fn swap_indices(self, other: usize) {
218219
if self.index != other {
220+
assert_index_lt(other, self.map.len());
221+
219222
// Since we already know where our bucket is, we only need to find the other.
220223
let hash = self.map.entries[other].hash;
221224
let other_mut = self.map.indices.find_mut(hash.get(), move |&i| i == other);
@@ -376,6 +379,7 @@ impl<'a, K, V> VacantEntry<'a, K, V> {
376379
#[track_caller]
377380
pub fn replace_index(self, index: usize) -> (K, OccupiedEntry<'a, K, V>) {
378381
let Self { map, hash, key } = self;
382+
assert_index_lt(index, map.len());
379383

380384
// NB: This removal and insertion isn't "no grow" (with unreachable hasher)
381385
// because hashbrown's tombstones might force a resize anyway.

‎src/map.rs‎

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use core::ops::{Index, IndexMut, RangeBounds};
4343
use std::hash::RandomState;
4444

4545
use crate::inner::Core;
46-
use crate::util::{third, try_simplify_range};
46+
use crate::util::{assert_index_le, assert_index_lt, third, try_simplify_range};
4747
use crate::{Bucket, Equivalent, GetDisjointMutError, HashValue, TryReserveError};
4848

4949
/// A hash table where the iteration order of the key-value pairs is independent
@@ -595,12 +595,7 @@ where
595595
/// ```
596596
#[track_caller]
597597
pub fn insert_before(&mut self, mut index: usize, key: K, value: V) -> (usize, Option<V>) {
598-
let len = self.len();
599-
600-
assert!(
601-
index <= len,
602-
"index out of bounds: the len is {len} but the index is {index}. Expected index <= len"
603-
);
598+
assert_index_le(index, self.len());
604599

605600
match self.entry(key) {
606601
Entry::Occupied(mut entry) => {
@@ -683,21 +678,13 @@ where
683678
let len = self.len();
684679
match self.entry(key) {
685680
Entry::Occupied(mut entry) => {
686-
assert!(
687-
index < len,
688-
"index out of bounds: the len is {len} but the index is {index}"
689-
);
690-
681+
assert_index_lt(index, len);
691682
let old = mem::replace(entry.get_mut(), value);
692683
entry.move_index(index);
693684
Some(old)
694685
}
695686
Entry::Vacant(entry) => {
696-
assert!(
697-
index <= len,
698-
"index out of bounds: the len is {len} but the index is {index}. Expected index <= len"
699-
);
700-
687+
assert_index_le(index, len);
701688
entry.shift_insert(index, value);
702689
None
703690
}
@@ -721,6 +708,8 @@ where
721708
/// Computes in **O(1)** time (average).
722709
#[track_caller]
723710
pub fn replace_index(&mut self, index: usize, key: K) -> Result<K, (usize, K)> {
711+
assert_index_lt(index, self.len());
712+
724713
// If there's a direct match, we don't even need to hash it.
725714
let entry = &mut self.as_entries_mut()[index];
726715
if key == entry.key {
@@ -1709,14 +1698,8 @@ impl<K, V, S> Index<usize> for IndexMap<K, V, S> {
17091698
///
17101699
/// ***Panics*** if `index` is out of bounds.
17111700
fn index(&self, index: usize) -> &V {
1712-
if let Some((_, value)) = self.get_index(index) {
1713-
value
1714-
} else {
1715-
panic!(
1716-
"index out of bounds: the len is {len} but the index is {index}",
1717-
len = self.len()
1718-
);
1719-
}
1701+
assert_index_lt(index, self.len());
1702+
&self.as_entries()[index].value
17201703
}
17211704
}
17221705

@@ -1754,13 +1737,8 @@ impl<K, V, S> IndexMut<usize> for IndexMap<K, V, S> {
17541737
///
17551738
/// ***Panics*** if `index` is out of bounds.
17561739
fn index_mut(&mut self, index: usize) -> &mut V {
1757-
let len: usize = self.len();
1758-
1759-
if let Some((_, value)) = self.get_index_mut(index) {
1760-
value
1761-
} else {
1762-
panic!("index out of bounds: the len is {len} but the index is {index}");
1763-
}
1740+
assert_index_lt(index, self.len());
1741+
&mut self.as_entries_mut()[index].value
17641742
}
17651743
}
17661744

‎src/set.rs‎

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub use crate::rayon::set as rayon;
2020
#[cfg(feature = "std")]
2121
use std::hash::RandomState;
2222

23-
use crate::util::try_simplify_range;
23+
use crate::util::{assert_index_lt, try_simplify_range};
2424
use alloc::boxed::Box;
2525
use alloc::vec::Vec;
2626
use core::cmp::Ordering;
@@ -1281,14 +1281,8 @@ impl<T, S> Index<usize> for IndexSet<T, S> {
12811281
///
12821282
/// ***Panics*** if `index` is out of bounds.
12831283
fn index(&self, index: usize) -> &T {
1284-
if let Some(value) = self.get_index(index) {
1285-
value
1286-
} else {
1287-
panic!(
1288-
"index out of bounds: the len is {len} but the index is {index}",
1289-
len = self.len()
1290-
);
1291-
}
1284+
assert_index_lt(index, self.len());
1285+
&self.map.as_entries()[index].key
12921286
}
12931287
}
12941288

‎src/util.rs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@ pub(crate) fn third<A, B, C>(t: (A, B, C)) -> C {
44
t.2
55
}
66

7+
#[inline]
8+
#[track_caller]
9+
pub(crate) fn assert_index_lt(index: usize, len: usize) {
10+
assert!(
11+
index < len,
12+
"index out of bounds: the len is {len} but the index is {index}",
13+
);
14+
}
15+
16+
#[inline]
17+
#[track_caller]
18+
pub(crate) fn assert_index_le(index: usize, len: usize) {
19+
assert!(
20+
index <= len,
21+
"index out of bounds: the len is {len} but the index is {index}. Expected index <= len"
22+
);
23+
}
24+
725
#[track_caller]
826
pub(crate) fn simplify_range<R>(range: R, len: usize) -> Range<usize>
927
where

0 commit comments

Comments
 (0)