Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Arc::try_unique #23844

Merged
merged 1 commit into from
Apr 2, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 50 additions & 6 deletions src/liballoc/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,38 @@ pub fn weak_count<T>(this: &Arc<T>) -> usize { this.inner().weak.load(SeqCst) -
#[unstable(feature = "alloc")]
pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst) }


/// Try accessing a mutable reference to the contents behind an unique `Arc<T>`.
///
/// The access is granted only if this is the only reference to the object.
/// Otherwise, `None` is returned.
///
/// # Examples
///
/// ```
/// # #![feature(alloc)]
/// use std::alloc::arc;
///
/// let mut four = arc::Arc::new(4);
///
/// arc::unique(&mut four).map(|num| *num = 5);
/// ```
#[inline]
#[unstable(feature = "alloc")]
pub fn unique<T>(this: &mut Arc<T>) -> Option<&mut T> {
if strong_count(this) == 1 && weak_count(this) == 0 {
// This unsafety is ok because we're guaranteed that the pointer
// 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
// the Arc itself to be `mut`, so we're returning the only possible
// reference to the inner data.
let inner = unsafe { &mut **this._ptr };
Some(&mut inner.data)
}else {
None
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Clone for Arc<T> {
/// Makes a clone of the `Arc<T>`.
Expand Down Expand Up @@ -312,11 +344,8 @@ impl<T: Send + Sync + Clone> Arc<T> {
self.inner().weak.load(SeqCst) != 1 {
*self = Arc::new((**self).clone())
}
// This unsafety is ok because we're guaranteed that the pointer
// 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
// the Arc itself to be `mut`, so we're returning the only possible
// reference to the inner data.
// As with `unique()`, the unsafety is ok because our reference was
// either unique to begin with, or became one upon cloning the contents.
let inner = unsafe { &mut **self._ptr };
&mut inner.data
}
Expand Down Expand Up @@ -659,7 +688,7 @@ mod tests {
use std::sync::atomic::Ordering::{Acquire, SeqCst};
use std::thread;
use std::vec::Vec;
use super::{Arc, Weak, weak_count, strong_count};
use super::{Arc, Weak, weak_count, strong_count, unique};
use std::sync::Mutex;

struct Canary(*mut atomic::AtomicUsize);
Expand Down Expand Up @@ -695,6 +724,21 @@ mod tests {
assert_eq!((*arc_v)[4], 5);
}

#[test]
fn test_arc_unique() {
let mut x = Arc::new(10);
assert!(unique(&mut x).is_some());
{
let y = x.clone();
assert!(unique(&mut x).is_none());
}
{
let z = x.downgrade();
assert!(unique(&mut x).is_none());
}
assert!(unique(&mut x).is_some());
}

#[test]
fn test_cowarc_clone_make_unique() {
let mut cow0 = Arc::new(75);
Expand Down