Skip to content

Commit 7c9b6d7

Browse files
committed
Add and for less branching in PackedOption
1 parent 2b54655 commit 7c9b6d7

File tree

4 files changed

+49
-6
lines changed

4 files changed

+49
-6
lines changed

crates/bevy_ecs/src/archetype.rs

+4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub struct AddBundle {
5555
impl NoneValue for ArchetypeId {
5656
const NONE_VALUE: Self = ArchetypeId::invalid();
5757

58+
#[inline]
5859
fn is_none_value(&self) -> bool {
5960
*self == Self::NONE_VALUE
6061
}
@@ -66,6 +67,7 @@ impl NoneValue for AddBundle {
6667
bundle_status: Vec::new(),
6768
};
6869

70+
#[inline]
6971
fn is_none_value(&self) -> bool {
7072
self.archetype_id.is_none_value()
7173
}
@@ -154,6 +156,7 @@ impl NoneValue for ArchetypeComponentInfo {
154156
archetype_component_id: ArchetypeComponentId::NONE_VALUE,
155157
};
156158

159+
#[inline]
157160
fn is_none_value(&self) -> bool {
158161
self.archetype_component_id.is_none_value()
159162
}
@@ -407,6 +410,7 @@ impl SparseSetIndex for ArchetypeComponentId {
407410
impl NoneValue for ArchetypeComponentId {
408411
const NONE_VALUE: Self = Self::invalid();
409412

413+
#[inline]
410414
fn is_none_value(&self) -> bool {
411415
*self == Self::invalid()
412416
}

crates/bevy_ecs/src/storage/sparse_set.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ impl ComponentSparseSet {
200200
/// it exists). It is the caller's responsibility to drop the returned ptr (if Some is
201201
/// returned).
202202
pub fn remove_and_forget(&mut self, entity: Entity) -> Option<*mut u8> {
203-
self.sparse.remove(entity).expand().map(|dense_index| {
203+
self.sparse.remove(entity).map_option(|dense_index| {
204204
// SAFE: unique access to ticks
205205
unsafe {
206206
(*self.ticks.get()).swap_remove(dense_index);
@@ -218,7 +218,11 @@ impl ComponentSparseSet {
218218
}
219219

220220
pub fn remove(&mut self, entity: Entity) -> bool {
221-
if let Some(dense_index) = self.sparse.remove(entity).expand() {
221+
let dense_index = self.sparse.remove(entity);
222+
223+
if dense_index.is_some() {
224+
// SAFE: `dense_index` is a some value.
225+
let dense_index = unsafe { dense_index.unwrap_unchecked() };
222226
self.ticks.get_mut().swap_remove(dense_index);
223227
self.entities.swap_remove(dense_index);
224228
let is_last = dense_index == self.dense.len() - 1;
@@ -360,7 +364,7 @@ impl<I: SparseSetIndex, V> SparseSet<I, V> {
360364
}
361365

362366
pub fn remove(&mut self, index: I) -> Option<V> {
363-
self.sparse.remove(index).expand().map(|dense_index| {
367+
self.sparse.remove(index).map_option(|dense_index| {
364368
let is_last = dense_index == self.dense.len() - 1;
365369
let value = self.dense.swap_remove(dense_index);
366370
self.indices.swap_remove(dense_index);

crates/bevy_ecs/src/world/entity_ref.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -303,15 +303,24 @@ impl<'w> EntityMut<'w> {
303303
let bundle_info = self.world.bundles.init_info::<T>(components);
304304
let old_location = self.location;
305305
let new_archetype_id = unsafe {
306-
remove_bundle_from_archetype(
306+
let archetype_id = remove_bundle_from_archetype(
307307
archetypes,
308308
storages,
309309
components,
310310
old_location.archetype_id,
311311
bundle_info,
312312
false,
313-
)
314-
.expand()?
313+
);
314+
315+
if archetype_id.is_some() {
316+
#[allow(unused_unsafe)]
317+
// SAFE: `archetype_id` is some.
318+
unsafe {
319+
archetype_id.unwrap_unchecked()
320+
}
321+
} else {
322+
return None;
323+
}
315324
};
316325

317326
if new_archetype_id == old_location.archetype_id {

crates/bevy_utils/src/packed_option.rs

+26
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ macro_rules! impl_max_none_value {
99
$(impl NoneValue for $ty {
1010
const NONE_VALUE: Self = <$ty>::MAX;
1111

12+
#[inline]
1213
fn is_none_value(&self) -> bool {
1314
*self == Self::NONE_VALUE
1415
}
@@ -48,6 +49,21 @@ impl<T: NoneValue> PackedOption<T> {
4849
self.expand().unwrap()
4950
}
5051

52+
/// Returns the contained value, consuming `self`,
53+
/// without checking that the value is not `[None]`.
54+
///
55+
/// # Safety
56+
/// Calling this method on [`None`] is *[undefined behavior]*.
57+
#[inline]
58+
#[track_caller]
59+
pub unsafe fn unwrap_unchecked(self) -> T {
60+
debug_assert!(
61+
self.is_some(),
62+
"Trying to call `unwrap_unchecked` on a `PackedOption` in a `None` state."
63+
);
64+
self.0
65+
}
66+
5167
/// Returns the contained `Some` value, consuming the `self` value.
5268
/// Panics with `msg` if self is `None`.
5369
#[inline]
@@ -88,6 +104,16 @@ impl<T: NoneValue> PackedOption<T> {
88104
}
89105
}
90106

107+
/// Maps a `PackedOption<T>` to `Option<U>` by applying a function to the contained value.
108+
#[inline]
109+
pub fn map_option<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
110+
if self.is_some() {
111+
Some(f(self.0))
112+
} else {
113+
None
114+
}
115+
}
116+
91117
/// Takes the value out of the packed option, leaveing `None` in its place.
92118
pub fn take(&mut self) -> PackedOption<T> {
93119
std::mem::take(self)

0 commit comments

Comments
 (0)