use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
use core::borrow;
use core::fmt;
-use core::cmp::Ordering;
+use core::cmp::{self, Ordering};
use core::intrinsics::abort;
use core::mem::{self, align_of_val, size_of_val};
use core::ops::{Deref, Receiver};
}
}
- // Due to the implicit weak pointer added when any strong pointers are
- // around, we cannot implement `weak_count` correctly since it necessarily
- // requires accessing the strong count and weak count in an unsynchronized
- // fashion.
+ /// Gets an approximation of the number of `Weak` pointers pointing to this
+ /// value.
+ ///
+ /// If `self` was created using [`Weak::new`], this will return 0. If not,
+ /// the returned value is at least 1, since `self` still points to the
+ /// value.
+ ///
+ /// # Accuracy
+ ///
+ /// Due to implementation details, the returned value can be off by 1 in
+ /// either direction when other threads are manipulating any `Arc`s or
+ /// `Weak`s pointing to the same value.
+ ///
+ /// [`Weak::new`]: #method.new
+ #[unstable(feature = "weak_counts", issue = "0")]
+ pub fn weak_count(&self) -> usize {
+ // Due to the implicit weak pointer added when any strong pointers are
+ // around, we cannot implement `weak_count` correctly since it
+ // necessarily requires accessing the strong count and weak count in an
+ // unsynchronized fashion. So this version is a bit racy.
+ if let Some(inner) = self.inner() {
+ let strong = inner.strong.load(SeqCst);
+ let weak = inner.weak.load(SeqCst);
+ if strong == 0 {
+ // If the last `Arc` has *just* been dropped, it might not yet
+ // have removed the implicit weak count, so the value we get
+ // here might be 1 too high.
+ weak
+ } else {
+ // As long as there's still at least 1 `Arc` around, subtract
+ // the implicit weak pointer.
+ // Note that the last `Arc` might get dropped between the 2
+ // loads we do above, removing the implicit weak pointer. This
+ // means that the value might be 1 too low here. In order to not
+ // return 0 here (which would happen if we're the only weak
+ // pointer), we guard against that specifically.
+ cmp::max(1, weak - 1)
+ }
+ } else {
+ 0
+ }
+ }
/// Return `None` when the pointer is dangling and there is no allocated `ArcInner`,
/// i.e., this `Weak` was created by `Weak::new`
assert!(Arc::get_mut(&mut x).is_none());
}
+ #[test]
+ fn weak_counts() {
+ assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
+ assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
+
+ let a = Arc::new(0);
+ let w = Arc::downgrade(&a);
+ assert_eq!(Weak::strong_count(&w), 1);
+ assert_eq!(Weak::weak_count(&w), 1);
+ let w2 = w.clone();
+ assert_eq!(Weak::strong_count(&w), 1);
+ assert_eq!(Weak::weak_count(&w), 2);
+ assert_eq!(Weak::strong_count(&w2), 1);
+ assert_eq!(Weak::weak_count(&w2), 2);
+ drop(w);
+ assert_eq!(Weak::strong_count(&w2), 1);
+ assert_eq!(Weak::weak_count(&w2), 1);
+ let a2 = a.clone();
+ assert_eq!(Weak::strong_count(&w2), 2);
+ assert_eq!(Weak::weak_count(&w2), 1);
+ drop(a2);
+ drop(a);
+ assert_eq!(Weak::strong_count(&w2), 0);
+ assert_eq!(Weak::weak_count(&w2), 1);
+ drop(w2);
+ }
+
#[test]
fn try_unwrap() {
let x = Arc::new(3);