Shuffle locations for Deref

Remove both `strong_count` and `weak_count` from `Weak`s and make the
methods bare functions so as not to cause trouble with `deref`.
This commit is contained in:
Alexander Light 2014-11-21 17:56:33 -05:00
parent 4c36ad01e7
commit 69861df831
2 changed files with 59 additions and 94 deletions

View File

@ -117,18 +117,18 @@ impl<T> Arc<T> {
// these contents.
unsafe { &*self._ptr }
}
/// Get the number of weak references to this value.
#[inline]
#[experimental]
pub fn weak_count(&self) -> uint { self.inner().weak.load(atomic::SeqCst) - 1 }
/// Get the number of strong references to this value.
#[inline]
#[experimental]
pub fn strong_count(&self) -> uint { self.inner().strong.load(atomic::SeqCst) }
}
/// Get the number of weak references to this value.
#[inline]
#[experimental]
pub fn weak_count<T>(this: &Arc<T>) -> uint { this.inner().weak.load(atomic::SeqCst) - 1 }
/// Get the number of strong references to this value.
#[inline]
#[experimental]
pub fn strong_count<T>(this: &Arc<T>) -> uint { this.inner().strong.load(atomic::SeqCst) }
#[unstable = "waiting on stability of Clone"]
impl<T> Clone for Arc<T> {
/// Duplicate an atomically reference counted wrapper.
@ -257,29 +257,6 @@ impl<T: Sync + Send> Weak<T> {
// See comments above for why this is "safe"
unsafe { &*self._ptr }
}
// Why is there no `weak_count()`?
//
// It is not possible to determine the number of weak references with only a weak reference
// accurately in a wait-free manner. This is because we have a data-race with the last strong
// reference's `drop` method. If that operation pauses between decrementing the strong
// reference count to 0 and removing the implicit weak reference that the strong references
// share then we will incorrectly think there is one more weak reference then there really is.
//
// We cannot get around this without making parts of this object no longer wait-free, since we
// would either need to use locks to get mutual exclusion with `drop` or make it so that the
// weak and strong reference counts can be modified atomically together. The first option
// destroys wait-freedom by adding a lock and the second (in addition to being annoying to
// implement) would make many operations (at least `downgrade` and both `clone`s) go from being
// wait-free to merely lock-free, as we would need to do a manual CAS loop to get around other
// threads modifying the other value in each of these cases.
/// Get the number of strong references to this value.
///
/// If this function returns 0 then the value has been freed.
#[inline]
#[experimental]
pub fn strong_count(&self) -> uint { self.inner().strong.load(atomic::SeqCst) }
}
#[experimental = "Weak pointers may not belong in this module."]
@ -354,7 +331,7 @@ mod tests {
use std::sync::atomic;
use std::task;
use std::vec::Vec;
use super::{Arc, Weak};
use super::{Arc, Weak, weak_count, strong_count};
use std::sync::Mutex;
struct Canary(*mut atomic::AtomicUint);
@ -501,38 +478,40 @@ mod tests {
#[test]
fn test_strong_count() {
let a = Arc::new(0u32);
assert!(a.strong_count() == 1);
assert!(strong_count(&a) == 1);
let w = a.downgrade();
assert!(a.strong_count() == 1);
assert!(strong_count(&a) == 1);
let b = w.upgrade().expect("");
assert!(b.strong_count() == 2);
assert!(a.strong_count() == 2);
assert!(strong_count(&b) == 2);
assert!(strong_count(&a) == 2);
drop(w);
drop(a);
assert!(b.strong_count() == 1);
assert!(strong_count(&b) == 1);
let c = b.clone();
assert!(b.strong_count() == 2);
assert!(c.strong_count() == 2);
assert!(strong_count(&b) == 2);
assert!(strong_count(&c) == 2);
}
#[test]
fn test_weak_count() {
let a = Arc::new(0u32);
assert!(a.strong_count() == 1);
assert!(a.weak_count() == 0);
assert!(strong_count(&a) == 1);
assert!(weak_count(&a) == 0);
let w = a.downgrade();
assert!(a.strong_count() == 1);
assert!(w.strong_count() == 1);
assert!(a.weak_count() == 1);
assert!(strong_count(&a) == 1);
assert!(weak_count(&a) == 1);
let x = w.clone();
assert!(weak_count(&a) == 2);
drop(w);
assert!(a.strong_count() == 1);
assert!(a.weak_count() == 0);
drop(x);
assert!(strong_count(&a) == 1);
assert!(weak_count(&a) == 0);
let c = a.clone();
assert!(a.strong_count() == 2);
assert!(a.weak_count() == 0);
assert!(strong_count(&a) == 2);
assert!(weak_count(&a) == 0);
let d = c.downgrade();
assert!(c.weak_count() == 1);
assert!(c.strong_count() == 2);
assert!(weak_count(&c) == 1);
assert!(strong_count(&c) == 2);
drop(a);
drop(c);

View File

@ -211,18 +211,18 @@ impl<T> Rc<T> {
_noshare: marker::NoSync
}
}
/// Get the number of weak references to this value.
#[inline]
#[experimental]
pub fn weak_count(&self) -> uint { self.weak() - 1 }
/// Get the number of strong references to this value.
#[inline]
#[experimental]
pub fn strong_count(&self) -> uint { self.strong() }
}
/// Get the number of weak references to this value.
#[inline]
#[experimental]
pub fn weak_count<T>(this: &Rc<T>) -> uint { this.weak() - 1 }
/// Get the number of strong references to this value.
#[inline]
#[experimental]
pub fn strong_count<T>(this: &Rc<T>) -> uint { this.strong() }
/// Returns true if the `Rc` currently has unique ownership.
///
/// Unique ownership means that there are no other `Rc` or `Weak` values
@ -230,7 +230,7 @@ impl<T> Rc<T> {
#[inline]
#[experimental]
pub fn is_unique<T>(rc: &Rc<T>) -> bool {
rc.weak_count() == 0 && rc.strong_count() == 1
weak_count(rc) == 0 && strong_count(rc) == 1
}
/// Unwraps the contained value if the `Rc` has unique ownership.
@ -433,20 +433,6 @@ impl<T> Weak<T> {
Some(Rc { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync })
}
}
/// Get the number of weak references to this value.
#[inline]
#[experimental]
pub fn weak_count(&self) -> uint {
if self.strong() != 0 { self.weak() - 1 } else { self.weak() }
}
/// Get the number of strong references to this value.
///
/// If this function returns 0 then the value has been freed.
#[inline]
#[experimental]
pub fn strong_count(&self) -> uint { self.strong() }
}
#[unsafe_destructor]
@ -512,7 +498,7 @@ impl<T> RcBoxPtr<T> for Weak<T> {
#[cfg(test)]
#[allow(experimental)]
mod tests {
use super::{Rc, Weak};
use super::{Rc, Weak, weak_count, strong_count};
use std::cell::RefCell;
use std::option::{Option, Some, None};
use std::result::{Err, Ok};
@ -592,35 +578,35 @@ mod tests {
#[test]
fn test_strong_count() {
let a = Rc::new(0u32);
assert!(a.strong_count() == 1);
assert!(strong_count(&a) == 1);
let w = a.downgrade();
assert!(a.strong_count() == 1);
assert!(strong_count(&a) == 1);
let b = w.upgrade().expect("upgrade of live rc failed");
assert!(b.strong_count() == 2);
assert!(a.strong_count() == 2);
assert!(strong_count(&b) == 2);
assert!(strong_count(&a) == 2);
drop(w);
drop(a);
assert!(b.strong_count() == 1);
assert!(strong_count(&b) == 1);
let c = b.clone();
assert!(b.strong_count() == 2);
assert!(c.strong_count() == 2);
assert!(strong_count(&b) == 2);
assert!(strong_count(&c) == 2);
}
#[test]
fn test_weak_count() {
let a = Rc::new(0u32);
assert!(a.strong_count() == 1);
assert!(a.weak_count() == 0);
assert!(strong_count(&a) == 1);
assert!(weak_count(&a) == 0);
let w = a.downgrade();
assert!(a.strong_count() == 1);
assert!(w.weak_count() == 1);
assert!(strong_count(&a) == 1);
assert!(weak_count(&a) == 1);
drop(w);
assert!(a.strong_count() == 1);
assert!(a.weak_count() == 0);
assert!(strong_count(&a) == 1);
assert!(weak_count(&a) == 0);
let c = a.clone();
assert!(a.strong_count() == 2);
assert!(a.weak_count() == 0);
assert!(c.downgrade().weak_count() == 1);
assert!(strong_count(&a) == 2);
assert!(weak_count(&a) == 0);
drop(c);
}
#[test]