Skip to content

Commit 8e03579

Browse files
committed
move get_disjoint_mut impl to separate file to work around lexer error in old rust versions
1 parent 1fc6fee commit 8e03579

File tree

2 files changed

+70
-58
lines changed

2 files changed

+70
-58
lines changed

src/get_disjoint_mut.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use crate::Slab;
2+
3+
use core::mem::MaybeUninit;
4+
5+
#[derive(Debug, Clone, PartialEq, Eq)]
6+
/// The error type returned by [`Slab::get_disjoint_mut`].
7+
pub enum GetDisjointMutError {
8+
/// An index provided was not associated with a value.
9+
IndexVacant,
10+
11+
/// An index provided was out-of-bounds for the slab.
12+
IndexOutOfBounds,
13+
14+
/// Two indices provided were overlapping.
15+
OverlappingIndices,
16+
}
17+
18+
impl<T> Slab<T> {
19+
/// Returns mutable references to many indices at once.
20+
/// Returns [`GetDisjointMutError`] if the indices are out of bounds,
21+
/// overlapping, or vacant.
22+
#[cfg(not(slab_no_const_generics))]
23+
pub fn get_disjoint_mut<const N: usize>(
24+
&mut self,
25+
keys: [usize; N],
26+
) -> Result<[&mut T; N], GetDisjointMutError> {
27+
use crate::Entry;
28+
29+
let entries_cap = self.entries.capacity();
30+
31+
// NB: The optimizer should inline the loops into a sequence
32+
// of instructions without additional branching.
33+
for (i, &key) in keys.iter().enumerate() {
34+
if key >= entries_cap {
35+
return Err(GetDisjointMutError::IndexOutOfBounds);
36+
}
37+
for &prev_key in &keys[..i] {
38+
if key == prev_key {
39+
return Err(GetDisjointMutError::OverlappingIndices);
40+
}
41+
}
42+
}
43+
44+
let mut res = MaybeUninit::<[&mut T; N]>::uninit();
45+
let res_ptr = res.as_mut_ptr() as *mut &mut T;
46+
47+
let entries_ptr = self.entries.as_mut_ptr();
48+
49+
for (i, &key) in keys.iter().enumerate() {
50+
// SAFETY: we made sure above that this key is in bounds.
51+
match unsafe { &mut *entries_ptr.add(key) } {
52+
Entry::Vacant(_) => return Err(GetDisjointMutError::IndexVacant),
53+
Entry::Occupied(entry) => {
54+
// SAFETY: `res` and `keys` both have N elements so `i` must be in bounds.
55+
// We checked above that all selected `entry`s are distinct.
56+
unsafe { res_ptr.add(i).write(entry) };
57+
}
58+
}
59+
}
60+
// SAFETY: the loop above only terminates successfully if it initialized
61+
// all elements of this array.
62+
Ok(unsafe { res.assume_init() })
63+
}
64+
}

src/lib.rs

+6-58
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,16 @@ extern crate std as alloc;
121121
#[cfg(feature = "serde")]
122122
mod serde;
123123

124+
#[cfg(not(slab_no_const_generics))]
125+
mod get_disjoint_mut;
126+
127+
#[cfg(not(slab_no_const_generics))]
128+
pub use get_disjoint_mut::GetDisjointMutError;
129+
124130
mod builder;
125131

126132
use alloc::vec::{self, Vec};
127133
use core::iter::{self, FromIterator, FusedIterator};
128-
use core::mem::MaybeUninit;
129134
use core::{fmt, mem, ops, slice};
130135

131136
/// Pre-allocated storage for a uniform data type
@@ -237,19 +242,6 @@ enum Entry<T> {
237242
Occupied(T),
238243
}
239244

240-
#[derive(Debug, Clone, PartialEq, Eq)]
241-
/// The error type returned by [`Slab::get_disjoint_mut`].
242-
pub enum GetDisjointMutError {
243-
/// An index provided was not associated with a value.
244-
IndexVacant,
245-
246-
/// An index provided was out-of-bounds for the slab.
247-
IndexOutOfBounds,
248-
249-
/// Two indices provided were overlapping.
250-
OverlappingIndices,
251-
}
252-
253245
impl<T> Slab<T> {
254246
/// Construct a new, empty `Slab`.
255247
///
@@ -807,50 +799,6 @@ impl<T> Slab<T> {
807799
}
808800
}
809801

810-
/// Returns mutable references to many indices at once.
811-
/// Returns [`GetDisjointMutError`] if the indices are out of bounds,
812-
/// overlapping, or vacant.
813-
#[cfg(not(slab_no_const_generics))]
814-
pub fn get_disjoint_mut<const N: usize>(
815-
&mut self,
816-
keys: [usize; N],
817-
) -> Result<[&mut T; N], GetDisjointMutError> {
818-
let entries_cap = self.entries.capacity();
819-
820-
// NB: The optimizer should inline the loops into a sequence
821-
// of instructions without additional branching.
822-
for (i, &key) in keys.iter().enumerate() {
823-
if key >= entries_cap {
824-
return Err(GetDisjointMutError::IndexOutOfBounds);
825-
}
826-
for &prev_key in &keys[..i] {
827-
if key == prev_key {
828-
return Err(GetDisjointMutError::OverlappingIndices);
829-
}
830-
}
831-
}
832-
833-
let mut res = MaybeUninit::<[&mut T; N]>::uninit();
834-
let res_ptr = res.as_mut_ptr() as *mut &mut T;
835-
836-
let entries_ptr = self.entries.as_mut_ptr();
837-
838-
for (i, &key) in keys.iter().enumerate() {
839-
// SAFETY: we made sure above that this key is in bounds.
840-
match unsafe { &mut *entries_ptr.add(key) } {
841-
Entry::Vacant(_) => return Err(GetDisjointMutError::IndexVacant),
842-
Entry::Occupied(entry) => {
843-
// SAFETY: `res` and `keys` both have N elements so `i` must be in bounds.
844-
// We checked above that all selected `entry`s are distinct.
845-
unsafe { res_ptr.add(i).write(entry) };
846-
}
847-
}
848-
}
849-
// SAFETY: the loop above only terminates successfully if it initialized
850-
// all elements of this array.
851-
Ok(unsafe { res.assume_init() })
852-
}
853-
854802
/// Return a reference to the value associated with the given key without
855803
/// performing bounds checking.
856804
///

0 commit comments

Comments
 (0)