Skip to content

Commit

Permalink
Merge #701
Browse files Browse the repository at this point in the history
701: Add {Atomic, Shared}::try_into_owned r=taiki-e a=PatrickNorton

Sometimes, I have run into times when I have had an `Atomic` which I know to be either null or valid, and I want to convert it into an `Owned`. As far as I can tell, there is no way to do this without converting through a `Shared`, which comes at the const of an additional atomic load. This pull request also adds the same method to `Shared` for symmetry.

This pull request adds the following methods:
```rust
impl<T: ?Sized + Pointable> Owned<T> {
	pub unsafe fn try_into_owned(self) -> Option<Owned<T>>;
}

impl<T: ?Sized + Pointable> Shared<'_, T> {
	pub unsafe fn try_into_owned(self) -> Option<Owned<T>>;
}
```

Co-authored-by: Patrick Norton <patrick.147.norton@gmail.com>
  • Loading branch information
bors[bot] and PatrickNorton committed May 28, 2022
2 parents 78b7ac3 + a7fe969 commit 26c770a
Showing 1 changed file with 76 additions and 0 deletions.
76 changes: 76 additions & 0 deletions crossbeam-epoch/src/atomic.rs
Expand Up @@ -877,6 +877,52 @@ impl<T: ?Sized + Pointable> Atomic<T> {
Owned::from_usize(self.data.into_inner())
}
}

/// Takes ownership of the pointee if it is non-null.
///
/// This consumes the atomic and converts it into [`Owned`]. As [`Atomic`] doesn't have a
/// destructor and doesn't drop the pointee while [`Owned`] does, this is suitable for
/// destructors of data structures.
///
/// # Safety
///
/// This method may be called only if the pointer is valid and nobody else is holding a
/// reference to the same object, or the pointer is null..
///
/// # Examples
///
/// ```rust
/// # use std::mem;
/// # use crossbeam_epoch::Atomic;
/// struct DataStructure {
/// ptr: Atomic<usize>,
/// }
///
/// impl Drop for DataStructure {
/// fn drop(&mut self) {
/// // By now the DataStructure lives only in our thread and we are sure we don't hold
/// // any Shared or & to it ourselves, but it may be null, so we have to be careful.
/// let old = mem::replace(&mut self.ptr, Atomic::null());
/// unsafe {
/// if let Option::Some(x) = old.try_into_owned() {
/// drop(x)
/// }
/// }
/// }
/// }
/// ```
pub unsafe fn try_into_owned(self) -> Option<Owned<T>> {
// FIXME: See self.into_owned()
#[cfg(crossbeam_loom)]
let data = self.data.unsync_load();
#[cfg(not(crossbeam_loom))]
let data = self.data.into_inner();
if decompose_tag::<T>(data).0 == 0 {
Option::None
} else {
Option::Some(Owned::from_usize(data))
}
}
}

impl<T: ?Sized + Pointable> fmt::Debug for Atomic<T> {
Expand Down Expand Up @@ -1481,6 +1527,36 @@ impl<'g, T: ?Sized + Pointable> Shared<'g, T> {
Owned::from_usize(self.data)
}

/// Takes ownership of the pointee if it is not null.
///
/// # Safety
///
/// This method may be called only if the pointer is valid and nobody else is holding a
/// reference to the same object, or if the pointer is null.
///
/// # Examples
///
/// ```
/// use crossbeam_epoch::{self as epoch, Atomic};
/// use std::sync::atomic::Ordering::SeqCst;
///
/// let a = Atomic::new(1234);
/// unsafe {
/// let guard = &epoch::unprotected();
/// let p = a.load(SeqCst, guard);
/// if let Option::Some(x) = p.try_into_owned() {
/// drop(x);
/// }
/// }
/// ```
pub unsafe fn try_into_owned(self) -> Option<Owned<T>> {
if self.is_null() {
Option::None
} else {
Option::Some(Owned::from_usize(self.data))
}
}

/// Returns the tag stored within the pointer.
///
/// # Examples
Expand Down

0 comments on commit 26c770a

Please sign in to comment.