Skip to content

Commit

Permalink
stablize weak pointers and uniqueness ops on Arc
Browse files Browse the repository at this point in the history
  • Loading branch information
Gankra committed Aug 14, 2015
1 parent b9c0fe7 commit d66c0b0
Showing 1 changed file with 44 additions and 50 deletions.
94 changes: 44 additions & 50 deletions src/liballoc/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be
/// used to break cycles between `Arc` pointers.
#[unsafe_no_drop_flag]
#[unstable(feature = "arc_weak",
reason = "Weak pointers may not belong in this module.")]
#[stable(feature = "arc_weak", since = "1.4.0")]
pub struct Weak<T: ?Sized> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
Expand All @@ -161,7 +160,7 @@ struct ArcInner<T: ?Sized> {

// the value usize::MAX acts as a sentinel for temporarily "locking" the
// ability to upgrade weak pointers or downgrade strong ones; this is used
// to avoid races in `make_unique` and `get_mut`.
// to avoid races in `make_mut` and `get_mut`.
weak: atomic::AtomicUsize,

data: T,
Expand Down Expand Up @@ -200,16 +199,13 @@ impl<T: ?Sized> Arc<T> {
/// # Examples
///
/// ```
/// #![feature(arc_weak)]
///
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
///
/// let weak_five = five.downgrade();
/// ```
#[unstable(feature = "arc_weak",
reason = "Weak pointers may not belong in this module.")]
#[stable(feature = "arc_weak", since = "1.4.0")]
pub fn downgrade(&self) -> Weak<T> {
loop {
// This Relaxed is OK because we're checking the value in the CAS
Expand All @@ -234,14 +230,14 @@ impl<T: ?Sized> Arc<T> {

/// Get the number of weak references to this value.
#[inline]
#[unstable(feature = "arc_counts")]
#[unstable(feature = "arc_counts", reason = "not clearly useful, and racy", issue = "27718")]
pub fn weak_count(this: &Arc<T>) -> usize {
this.inner().weak.load(SeqCst) - 1
}

/// Get the number of strong references to this value.
#[inline]
#[unstable(feature = "arc_counts")]
#[unstable(feature = "arc_counts", reason = "not clearly useful, and racy", issue = "27718")]
pub fn strong_count(this: &Arc<T>) -> usize {
this.inner().strong.load(SeqCst)
}
Expand Down Expand Up @@ -330,27 +326,40 @@ impl<T: ?Sized> Deref for Arc<T> {
}

impl<T: Clone> Arc<T> {
/// Make a mutable reference from the given `Arc<T>`.

#[unstable(feature = "renamed_arc_unique", reason = "renamed to make_mut", issue = "27718")]
#[deprecated(since = "1.4.0", reason = "renamed to make_mut")]
pub fn make_unique(this: &mut Arc<T>) -> &mut T {
Arc::make_mut(this)
}

/// Make a mutable reference into the given `Arc<T>` by cloning the inner
/// data if the `Arc<T>` doesn't have one strong reference and no weak
/// references.
///
/// This is also referred to as a copy-on-write operation because the inner
/// data is cloned if the (strong) reference count is greater than one. If
/// we hold the only strong reference, any existing weak references will no
/// longer be upgradeable.
/// This is also referred to as a copy-on-write.
///
/// # Examples
///
/// ```
/// #![feature(arc_unique)]
///
/// use std::sync::Arc;
///
/// let mut five = Arc::new(5);
/// let mut data = Arc::new(5);
///
/// *data.make_mut() += 1; // Won't clone anything
/// let mut other_data = data.clone(); // Won't clone inner data
/// *data.make_mut() += 1; // Clones inner data
/// *data.make_mut() += 1; // Won't clone anything
/// *other_data.make_mut() *= 2; // Won't clone anything
///
/// // Note: data and other_data now point to different numbers
/// assert_eq!(*data, 8);
/// assert_eq!(*other_data, 12);
///
/// let mut_five = Arc::make_unique(&mut five);
/// ```
#[inline]
#[unstable(feature = "arc_unique")]
pub fn make_unique(this: &mut Arc<T>) -> &mut T {
#[stable(feature = "arc_unique", since = "1.4.0")]
pub fn make_mut(this: &mut Arc<T>) -> &mut T {
// Note that we hold both a strong reference and a weak reference.
// Thus, releasing our strong reference only will not, by itself, cause
// the memory to be deallocated.
Expand Down Expand Up @@ -405,29 +414,23 @@ impl<T: Clone> Arc<T> {
}

impl<T: ?Sized> Arc<T> {
/// Returns a mutable reference to the contained value if the `Arc<T>` is unique.
///
/// Returns `None` if the `Arc<T>` is not unique.
/// Returns a mutable reference to the contained value if the `Arc<T>` has
/// one strong reference and no weak references.
///
/// # Examples
///
/// ```
/// #![feature(arc_unique, alloc)]
///
/// extern crate alloc;
/// # fn main() {
/// use alloc::arc::Arc;
/// use std::sync::Arc;
///
/// let mut x = Arc::new(3);
/// *Arc::get_mut(&mut x).unwrap() = 4;
/// assert_eq!(*x, 4);
///
/// let _y = x.clone();
/// assert!(Arc::get_mut(&mut x).is_none());
/// # }
/// ```
#[inline]
#[unstable(feature = "arc_unique")]
#[stable(feature = "arc_unique", since = "1.4.0")]
pub fn get_mut(this: &mut Arc<T>) -> Option<&mut T> {
if this.is_unique() {
// This unsafety is ok because we're guaranteed that the pointer
Expand Down Expand Up @@ -540,8 +543,6 @@ impl<T: ?Sized> Drop for Arc<T> {
}
}

#[unstable(feature = "arc_weak",
reason = "Weak pointers may not belong in this module.")]
impl<T: ?Sized> Weak<T> {
/// Upgrades a weak reference to a strong reference.
///
Expand All @@ -553,8 +554,6 @@ impl<T: ?Sized> Weak<T> {
/// # Examples
///
/// ```
/// #![feature(arc_weak)]
///
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
Expand All @@ -563,6 +562,7 @@ impl<T: ?Sized> Weak<T> {
///
/// let strong_five: Option<Arc<_>> = weak_five.upgrade();
/// ```
#[stable(feature = "arc_weak", since = "1.4.0")]
pub fn upgrade(&self) -> Option<Arc<T>> {
// We use a CAS loop to increment the strong count instead of a
// fetch_add because once the count hits 0 it must never be above 0.
Expand All @@ -588,8 +588,7 @@ impl<T: ?Sized> Weak<T> {
}
}

#[unstable(feature = "arc_weak",
reason = "Weak pointers may not belong in this module.")]
#[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized> Clone for Weak<T> {
/// Makes a clone of the `Weak<T>`.
///
Expand All @@ -598,8 +597,6 @@ impl<T: ?Sized> Clone for Weak<T> {
/// # Examples
///
/// ```
/// #![feature(arc_weak)]
///
/// use std::sync::Arc;
///
/// let weak_five = Arc::new(5).downgrade();
Expand Down Expand Up @@ -632,8 +629,6 @@ impl<T: ?Sized> Drop for Weak<T> {
/// # Examples
///
/// ```
/// #![feature(arc_weak)]
///
/// use std::sync::Arc;
///
/// {
Expand Down Expand Up @@ -891,18 +886,18 @@ mod tests {
}

#[test]
fn test_cowarc_clone_make_unique() {
fn test_cowarc_clone_make_mut() {
let mut cow0 = Arc::new(75);
let mut cow1 = cow0.clone();
let mut cow2 = cow1.clone();

assert!(75 == *Arc::make_unique(&mut cow0));
assert!(75 == *Arc::make_unique(&mut cow1));
assert!(75 == *Arc::make_unique(&mut cow2));
assert!(75 == *Arc::make_mut(&mut cow0));
assert!(75 == *Arc::make_mut(&mut cow1));
assert!(75 == *Arc::make_mut(&mut cow2));

*Arc::make_unique(&mut cow0) += 1;
*Arc::make_unique(&mut cow1) += 2;
*Arc::make_unique(&mut cow2) += 3;
*Arc::make_mut(&mut cow0) += 1;
*Arc::make_mut(&mut cow1) += 2;
*Arc::make_mut(&mut cow2) += 3;

assert!(76 == *cow0);
assert!(77 == *cow1);
Expand All @@ -924,8 +919,7 @@ mod tests {
assert!(75 == *cow1);
assert!(75 == *cow2);

*Arc::make_unique(&mut cow0) += 1;

*Arc::make_mut(&mut cow0) += 1;
assert!(76 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
Expand All @@ -945,7 +939,7 @@ mod tests {
assert!(75 == *cow0);
assert!(75 == *cow1_weak.upgrade().unwrap());

*Arc::make_unique(&mut cow0) += 1;
*Arc::make_mut(&mut cow0) += 1;

assert!(76 == *cow0);
assert!(cow1_weak.upgrade().is_none());
Expand Down

0 comments on commit d66c0b0

Please sign in to comment.