Skip to content

Commit 951ea47

Browse files
bors[bot]PatrickNortontaiki-e
authored
Merge #701
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 <[email protected]> Co-authored-by: Taiki Endo <[email protected]>
2 parents 78b7ac3 + 3419a6f commit 951ea47

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

crossbeam-epoch/src/atomic.rs

+76
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,52 @@ impl<T: ?Sized + Pointable> Atomic<T> {
877877
Owned::from_usize(self.data.into_inner())
878878
}
879879
}
880+
881+
/// Takes ownership of the pointee if it is non-null.
882+
///
883+
/// This consumes the atomic and converts it into [`Owned`]. As [`Atomic`] doesn't have a
884+
/// destructor and doesn't drop the pointee while [`Owned`] does, this is suitable for
885+
/// destructors of data structures.
886+
///
887+
/// # Safety
888+
///
889+
/// This method may be called only if the pointer is valid and nobody else is holding a
890+
/// reference to the same object, or the pointer is null.
891+
///
892+
/// # Examples
893+
///
894+
/// ```rust
895+
/// # use std::mem;
896+
/// # use crossbeam_epoch::Atomic;
897+
/// struct DataStructure {
898+
/// ptr: Atomic<usize>,
899+
/// }
900+
///
901+
/// impl Drop for DataStructure {
902+
/// fn drop(&mut self) {
903+
/// // By now the DataStructure lives only in our thread and we are sure we don't hold
904+
/// // any Shared or & to it ourselves, but it may be null, so we have to be careful.
905+
/// let old = mem::replace(&mut self.ptr, Atomic::null());
906+
/// unsafe {
907+
/// if let Option::Some(x) = old.try_into_owned() {
908+
/// drop(x)
909+
/// }
910+
/// }
911+
/// }
912+
/// }
913+
/// ```
914+
pub unsafe fn try_into_owned(self) -> Option<Owned<T>> {
915+
// FIXME: See self.into_owned()
916+
#[cfg(crossbeam_loom)]
917+
let data = self.data.unsync_load();
918+
#[cfg(not(crossbeam_loom))]
919+
let data = self.data.into_inner();
920+
if decompose_tag::<T>(data).0 == 0 {
921+
Option::None
922+
} else {
923+
Option::Some(Owned::from_usize(data))
924+
}
925+
}
880926
}
881927

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

1530+
/// Takes ownership of the pointee if it is not null.
1531+
///
1532+
/// # Safety
1533+
///
1534+
/// This method may be called only if the pointer is valid and nobody else is holding a
1535+
/// reference to the same object, or if the pointer is null.
1536+
///
1537+
/// # Examples
1538+
///
1539+
/// ```
1540+
/// use crossbeam_epoch::{self as epoch, Atomic};
1541+
/// use std::sync::atomic::Ordering::SeqCst;
1542+
///
1543+
/// let a = Atomic::new(1234);
1544+
/// unsafe {
1545+
/// let guard = &epoch::unprotected();
1546+
/// let p = a.load(SeqCst, guard);
1547+
/// if let Option::Some(x) = p.try_into_owned() {
1548+
/// drop(x);
1549+
/// }
1550+
/// }
1551+
/// ```
1552+
pub unsafe fn try_into_owned(self) -> Option<Owned<T>> {
1553+
if self.is_null() {
1554+
Option::None
1555+
} else {
1556+
Option::Some(Owned::from_usize(self.data))
1557+
}
1558+
}
1559+
14841560
/// Returns the tag stored within the pointer.
14851561
///
14861562
/// # Examples

0 commit comments

Comments
 (0)