Skip to content

Commit 32b6fc1

Browse files
committed
auto merge of #14522 : aturon/rust/make_unique, r=alexcrichton,alexcrichton,me
This patch makes `Arc::make_unique` examine the number of weak references as well as strong references, which is required for safety. It also adds a `make_unique` method to the `Rc` type for consistency. Closes #14521.
2 parents 3a10546 + 7889c95 commit 32b6fc1

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

src/liballoc/arc.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ impl<T: Send + Share + Clone> Arc<T> {
152152
#[inline]
153153
#[experimental]
154154
pub fn make_unique<'a>(&'a mut self) -> &'a mut T {
155-
if self.inner().strong.load(atomics::SeqCst) != 1 {
155+
// Note that we hold a strong reference, which also counts as
156+
// a weak reference, so we only clone if there is an
157+
// additional reference of either kind.
158+
if self.inner().strong.load(atomics::SeqCst) != 1 ||
159+
self.inner().weak.load(atomics::SeqCst) != 1 {
156160
*self = Arc::new(self.deref().clone())
157161
}
158162
// This unsafety is ok because we're guaranteed that the pointer
@@ -356,6 +360,20 @@ mod tests {
356360
assert!(*cow1 == *cow2);
357361
}
358362

363+
#[test]
364+
fn test_cowarc_clone_weak() {
365+
let mut cow0 = Arc::new(75u);
366+
let cow1_weak = cow0.downgrade();
367+
368+
assert!(75 == *cow0);
369+
assert!(75 == *cow1_weak.upgrade().unwrap());
370+
371+
*cow0.make_unique() += 1;
372+
373+
assert!(76 == *cow0);
374+
assert!(cow1_weak.upgrade().is_none());
375+
}
376+
359377
#[test]
360378
fn test_live() {
361379
let x = Arc::new(5);

src/liballoc/rc.rs

+88
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,31 @@ impl<T> Rc<T> {
8686
}
8787
}
8888

89+
impl<T: Clone> Rc<T> {
90+
/// Acquires a mutable pointer to the inner contents by guaranteeing that
91+
/// the reference count is one (no sharing is possible).
92+
///
93+
/// This is also referred to as a copy-on-write operation because the inner
94+
/// data is cloned if the reference count is greater than one.
95+
#[inline]
96+
#[experimental]
97+
pub fn make_unique<'a>(&'a mut self) -> &'a mut T {
98+
// Note that we hold a strong reference, which also counts as
99+
// a weak reference, so we only clone if there is an
100+
// additional reference of either kind.
101+
if self.strong() != 1 || self.weak() != 1 {
102+
*self = Rc::new(self.deref().clone())
103+
}
104+
// This unsafety is ok because we're guaranteed that the pointer
105+
// returned is the *only* pointer that will ever be returned to T. Our
106+
// reference count is guaranteed to be 1 at this point, and we required
107+
// the Rc itself to be `mut`, so we're returning the only possible
108+
// reference to the inner data.
109+
let inner = unsafe { &mut *self._ptr };
110+
&mut inner.value
111+
}
112+
}
113+
89114
impl<T> Deref<T> for Rc<T> {
90115
/// Borrow the value contained in the reference-counted box
91116
#[inline(always)]
@@ -234,6 +259,7 @@ impl<T> RcBoxPtr<T> for Weak<T> {
234259
}
235260

236261
#[cfg(test)]
262+
#[allow(experimental)]
237263
mod tests {
238264
use super::{Rc, Weak};
239265
use std::cell::RefCell;
@@ -304,4 +330,66 @@ mod tests {
304330

305331
// hopefully we don't double-free (or leak)...
306332
}
333+
334+
#[test]
335+
fn test_cowrc_clone_make_unique() {
336+
let mut cow0 = Rc::new(75u);
337+
let mut cow1 = cow0.clone();
338+
let mut cow2 = cow1.clone();
339+
340+
assert!(75 == *cow0.make_unique());
341+
assert!(75 == *cow1.make_unique());
342+
assert!(75 == *cow2.make_unique());
343+
344+
*cow0.make_unique() += 1;
345+
*cow1.make_unique() += 2;
346+
*cow2.make_unique() += 3;
347+
348+
assert!(76 == *cow0);
349+
assert!(77 == *cow1);
350+
assert!(78 == *cow2);
351+
352+
// none should point to the same backing memory
353+
assert!(*cow0 != *cow1);
354+
assert!(*cow0 != *cow2);
355+
assert!(*cow1 != *cow2);
356+
}
357+
358+
#[test]
359+
fn test_cowrc_clone_unique2() {
360+
let mut cow0 = Rc::new(75u);
361+
let cow1 = cow0.clone();
362+
let cow2 = cow1.clone();
363+
364+
assert!(75 == *cow0);
365+
assert!(75 == *cow1);
366+
assert!(75 == *cow2);
367+
368+
*cow0.make_unique() += 1;
369+
370+
assert!(76 == *cow0);
371+
assert!(75 == *cow1);
372+
assert!(75 == *cow2);
373+
374+
// cow1 and cow2 should share the same contents
375+
// cow0 should have a unique reference
376+
assert!(*cow0 != *cow1);
377+
assert!(*cow0 != *cow2);
378+
assert!(*cow1 == *cow2);
379+
}
380+
381+
#[test]
382+
fn test_cowrc_clone_weak() {
383+
let mut cow0 = Rc::new(75u);
384+
let cow1_weak = cow0.downgrade();
385+
386+
assert!(75 == *cow0);
387+
assert!(75 == *cow1_weak.upgrade().unwrap());
388+
389+
*cow0.make_unique() += 1;
390+
391+
assert!(76 == *cow0);
392+
assert!(cow1_weak.upgrade().is_none());
393+
}
394+
307395
}

0 commit comments

Comments
 (0)