mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Add Arc::is_unique
This commit is contained in:
parent
48994b1674
commit
2ab403441f
@ -2446,7 +2446,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "arc_unique", since = "1.4.0")]
|
#[stable(feature = "arc_unique", since = "1.4.0")]
|
||||||
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
|
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
|
||||||
if this.is_unique() {
|
if Self::is_unique(this) {
|
||||||
// This unsafety is ok because we're guaranteed that the pointer
|
// This unsafety is ok because we're guaranteed that the pointer
|
||||||
// returned is the *only* pointer that will ever be returned to T. Our
|
// returned is the *only* pointer that will ever be returned to T. Our
|
||||||
// reference count is guaranteed to be 1 at this point, and we required
|
// reference count is guaranteed to be 1 at this point, and we required
|
||||||
@ -2526,11 +2526,64 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
|
|||||||
unsafe { &mut (*this.ptr.as_ptr()).data }
|
unsafe { &mut (*this.ptr.as_ptr()).data }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether this is the unique reference (including weak refs) to
|
/// Determine whether this is the unique reference to the underlying data.
|
||||||
/// the underlying data.
|
|
||||||
///
|
///
|
||||||
/// Note that this requires locking the weak ref count.
|
/// Returns `true` if there are no other `Arc` or [`Weak`] pointers to the same allocation;
|
||||||
fn is_unique(&mut self) -> bool {
|
/// returns `false` otherwise.
|
||||||
|
///
|
||||||
|
/// If this function returns `true`, then is guaranteed to be safe to call [`get_mut_unchecked`]
|
||||||
|
/// on this `Arc`, so long as no clones occur in between.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(arc_is_unique)]
|
||||||
|
///
|
||||||
|
/// use std::sync::Arc;
|
||||||
|
///
|
||||||
|
/// let x = Arc::new(3);
|
||||||
|
/// assert!(Arc::is_unique(&x));
|
||||||
|
///
|
||||||
|
/// let y = Arc::clone(&x);
|
||||||
|
/// assert!(!Arc::is_unique(&x));
|
||||||
|
/// drop(y);
|
||||||
|
///
|
||||||
|
/// // Weak references also count, because they could be upgraded at any time.
|
||||||
|
/// let z = Arc::downgrade(&x);
|
||||||
|
/// assert!(!Arc::is_unique(&x));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Pointer invalidation
|
||||||
|
///
|
||||||
|
/// This function will always return the same value as `Arc::get_mut(arc).is_some()`. However,
|
||||||
|
/// unlike that operation it does not produce any mutable references to the underlying data,
|
||||||
|
/// meaning no pointers to the data inside the `Arc` are invalidated by the call. Thus, the
|
||||||
|
/// following code is valid, even though it would be UB if it used `Arc::get_mut`:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(arc_is_unique)]
|
||||||
|
///
|
||||||
|
/// use std::sync::Arc;
|
||||||
|
///
|
||||||
|
/// let arc = Arc::new(5);
|
||||||
|
/// let pointer: *const i32 = &*arc;
|
||||||
|
/// assert!(Arc::is_unique(&arc));
|
||||||
|
/// assert_eq!(unsafe { *pointer }, 5);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Atomic orderings
|
||||||
|
///
|
||||||
|
/// Concurrent drops to other `Arc` pointers to the same allocation will synchronize with this
|
||||||
|
/// call - that is, this call performs an `Acquire` operation on the underlying strong and weak
|
||||||
|
/// ref counts. This ensures that calling `get_mut_unchecked` is safe.
|
||||||
|
///
|
||||||
|
/// Note that this operation requires locking the weak ref count, so concurrent calls to
|
||||||
|
/// `downgrade` may spin-loop for a short period of time.
|
||||||
|
///
|
||||||
|
/// [`get_mut_unchecked`]: Self::get_mut_unchecked
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "arc_is_unique", issue = "138938")]
|
||||||
|
pub fn is_unique(this: &Self) -> bool {
|
||||||
// lock the weak pointer count if we appear to be the sole weak pointer
|
// lock the weak pointer count if we appear to be the sole weak pointer
|
||||||
// holder.
|
// holder.
|
||||||
//
|
//
|
||||||
@ -2538,16 +2591,16 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
|
|||||||
// writes to `strong` (in particular in `Weak::upgrade`) prior to decrements
|
// writes to `strong` (in particular in `Weak::upgrade`) prior to decrements
|
||||||
// of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
|
// of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
|
||||||
// weak ref was never dropped, the CAS here will fail so we do not care to synchronize.
|
// weak ref was never dropped, the CAS here will fail so we do not care to synchronize.
|
||||||
if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
|
if this.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
|
||||||
// This needs to be an `Acquire` to synchronize with the decrement of the `strong`
|
// This needs to be an `Acquire` to synchronize with the decrement of the `strong`
|
||||||
// counter in `drop` -- the only access that happens when any but the last reference
|
// counter in `drop` -- the only access that happens when any but the last reference
|
||||||
// is being dropped.
|
// is being dropped.
|
||||||
let unique = self.inner().strong.load(Acquire) == 1;
|
let unique = this.inner().strong.load(Acquire) == 1;
|
||||||
|
|
||||||
// The release write here synchronizes with a read in `downgrade`,
|
// The release write here synchronizes with a read in `downgrade`,
|
||||||
// effectively preventing the above read of `strong` from happening
|
// effectively preventing the above read of `strong` from happening
|
||||||
// after the write.
|
// after the write.
|
||||||
self.inner().weak.store(1, Release); // release the lock
|
this.inner().weak.store(1, Release); // release the lock
|
||||||
unique
|
unique
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
Loading…
Reference in New Issue
Block a user