Rollup merge of #76640 - fusion-engineering-forks:synconcecell-drop, r=matklad
Simplify SyncOnceCell's `take` and `drop`. Prevents copies by using `assume_init_read` and `assume_init_drop`.
This commit is contained in:
commit
f9b9467866
2 changed files with 14 additions and 26 deletions
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
cell::{Cell, UnsafeCell},
|
cell::{Cell, UnsafeCell},
|
||||||
fmt,
|
fmt,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem::{self, MaybeUninit},
|
mem::MaybeUninit,
|
||||||
ops::{Deref, Drop},
|
ops::{Deref, Drop},
|
||||||
panic::{RefUnwindSafe, UnwindSafe},
|
panic::{RefUnwindSafe, UnwindSafe},
|
||||||
sync::Once,
|
sync::Once,
|
||||||
|
@ -316,13 +316,7 @@ impl<T> SyncOnceCell<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
pub fn into_inner(mut self) -> Option<T> {
|
pub fn into_inner(mut self) -> Option<T> {
|
||||||
// SAFETY: Safe because we immediately free `self` without dropping
|
self.take()
|
||||||
let inner = unsafe { self.take_inner() };
|
|
||||||
|
|
||||||
// Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set
|
|
||||||
// the state to uninitialized.
|
|
||||||
mem::forget(self);
|
|
||||||
inner
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
|
/// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
|
||||||
|
@ -348,22 +342,12 @@ impl<T> SyncOnceCell<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "once_cell", issue = "74465")]
|
#[unstable(feature = "once_cell", issue = "74465")]
|
||||||
pub fn take(&mut self) -> Option<T> {
|
pub fn take(&mut self) -> Option<T> {
|
||||||
mem::take(self).into_inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Takes the wrapped value out of a `SyncOnceCell`.
|
|
||||||
/// Afterwards the cell is no longer initialized.
|
|
||||||
///
|
|
||||||
/// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell
|
|
||||||
/// are valid. Only used by `into_inner` and `drop`.
|
|
||||||
unsafe fn take_inner(&mut self) -> Option<T> {
|
|
||||||
// The mutable reference guarantees there are no other threads that can observe us
|
|
||||||
// taking out the wrapped value.
|
|
||||||
// Right after this function `self` is supposed to be freed, so it makes little sense
|
|
||||||
// to atomically set the state to uninitialized.
|
|
||||||
if self.is_initialized() {
|
if self.is_initialized() {
|
||||||
let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit()));
|
self.once = Once::new();
|
||||||
Some(value.into_inner().assume_init())
|
// SAFETY: `self.value` is initialized and contains a valid `T`.
|
||||||
|
// `self.once` is reset, so `is_initialized()` will be false again
|
||||||
|
// which prevents the value from being read twice.
|
||||||
|
unsafe { Some((&mut *self.value.get()).assume_init_read()) }
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -416,9 +400,12 @@ impl<T> SyncOnceCell<T> {
|
||||||
|
|
||||||
unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
|
unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// SAFETY: The cell is being dropped, so it can't be accessed again.
|
if self.is_initialized() {
|
||||||
// We also don't touch the `T`, which validates our usage of #[may_dangle].
|
// Safety: The cell is initialized and being dropped, so it can't
|
||||||
unsafe { self.take_inner() };
|
// be accessed again. We also don't touch the `T` other than
|
||||||
|
// dropping it, which validates our usage of #[may_dangle].
|
||||||
|
unsafe { (&mut *self.value.get()).assume_init_drop() };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,6 +191,7 @@ struct WaiterQueue<'a> {
|
||||||
|
|
||||||
impl Once {
|
impl Once {
|
||||||
/// Creates a new `Once` value.
|
/// Creates a new `Once` value.
|
||||||
|
#[inline]
|
||||||
#[stable(feature = "once_new", since = "1.2.0")]
|
#[stable(feature = "once_new", since = "1.2.0")]
|
||||||
#[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
|
#[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
|
||||||
pub const fn new() -> Once {
|
pub const fn new() -> Once {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue