Skip to content

Commit f29b4fb

Browse files
committed
Auto merge of #56696 - jonas-schievink:weak-counts, r=alexcrichton
Implement Weak::{strong_count, weak_count} The counters are also useful on `Weak`, not just on strong references (`Rc` or `Arc`). In situations where there are still strong references around, you can also get these counts by temporarily upgrading and adjusting the values accordingly. Using the methods introduced here is simpler to do, less error-prone (since you can't forget to adjust the counts), can also be used when no strong references are around anymore, and might be more efficient due to not having to temporarily create an `Rc`. This is mainly useful in assertions or tests of complex data structures. Data structures might have internal invariants that make them the sole owner of a `Weak` pointer, and an assertion on the weak count could be used to ensure that this indeed happens as expected. Due to the presence of `Weak::upgrade`, the `strong_count` becomes less useful, but it still seems worthwhile to mirror the API of `Rc`. TODO: * [X] Tracking issue - #57977 Closes #50158
2 parents 63505b8 + 0d314f0 commit f29b4fb

File tree

2 files changed

+142
-1
lines changed

2 files changed

+142
-1
lines changed

src/liballoc/rc.rs

+59
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,38 @@ impl<T: ?Sized> Weak<T> {
13051305
}
13061306
}
13071307

1308+
/// Gets the number of strong (`Rc`) pointers pointing to this value.
1309+
///
1310+
/// If `self` was created using [`Weak::new`], this will return 0.
1311+
///
1312+
/// [`Weak::new`]: #method.new
1313+
#[unstable(feature = "weak_counts", issue = "57977")]
1314+
pub fn strong_count(&self) -> usize {
1315+
if let Some(inner) = self.inner() {
1316+
inner.strong()
1317+
} else {
1318+
0
1319+
}
1320+
}
1321+
1322+
/// Gets the number of `Weak` pointers pointing to this value.
1323+
///
1324+
/// If `self` was created using [`Weak::new`], this will return `None`. If
1325+
/// not, the returned value is at least 1, since `self` still points to the
1326+
/// value.
1327+
///
1328+
/// [`Weak::new`]: #method.new
1329+
#[unstable(feature = "weak_counts", issue = "57977")]
1330+
pub fn weak_count(&self) -> Option<usize> {
1331+
self.inner().map(|inner| {
1332+
if inner.strong() > 0 {
1333+
inner.weak() - 1 // subtract the implicit weak ptr
1334+
} else {
1335+
inner.weak()
1336+
}
1337+
})
1338+
}
1339+
13081340
/// Return `None` when the pointer is dangling and there is no allocated `RcBox`,
13091341
/// i.e., this `Weak` was created by `Weak::new`
13101342
#[inline]
@@ -1643,6 +1675,33 @@ mod tests {
16431675
drop(c);
16441676
}
16451677

1678+
#[test]
1679+
fn weak_counts() {
1680+
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
1681+
assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
1682+
1683+
let a = Rc::new(0);
1684+
let w = Rc::downgrade(&a);
1685+
assert_eq!(Weak::strong_count(&w), 1);
1686+
assert_eq!(Weak::weak_count(&w), Some(1));
1687+
let w2 = w.clone();
1688+
assert_eq!(Weak::strong_count(&w), 1);
1689+
assert_eq!(Weak::weak_count(&w), Some(2));
1690+
assert_eq!(Weak::strong_count(&w2), 1);
1691+
assert_eq!(Weak::weak_count(&w2), Some(2));
1692+
drop(w);
1693+
assert_eq!(Weak::strong_count(&w2), 1);
1694+
assert_eq!(Weak::weak_count(&w2), Some(1));
1695+
let a2 = a.clone();
1696+
assert_eq!(Weak::strong_count(&w2), 2);
1697+
assert_eq!(Weak::weak_count(&w2), Some(1));
1698+
drop(a2);
1699+
drop(a);
1700+
assert_eq!(Weak::strong_count(&w2), 0);
1701+
assert_eq!(Weak::weak_count(&w2), Some(1));
1702+
drop(w2);
1703+
}
1704+
16461705
#[test]
16471706
fn try_unwrap() {
16481707
let x = Rc::new(3);

src/liballoc/sync.rs

+83-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use core::sync::atomic;
1111
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
1212
use core::borrow;
1313
use core::fmt;
14-
use core::cmp::Ordering;
14+
use core::cmp::{self, Ordering};
1515
use core::intrinsics::abort;
1616
use core::mem::{self, align_of_val, size_of_val};
1717
use core::ops::{Deref, Receiver};
@@ -1138,6 +1138,61 @@ impl<T: ?Sized> Weak<T> {
11381138
}
11391139
}
11401140

1141+
/// Gets the number of strong (`Arc`) pointers pointing to this value.
1142+
///
1143+
/// If `self` was created using [`Weak::new`], this will return 0.
1144+
///
1145+
/// [`Weak::new`]: #method.new
1146+
#[unstable(feature = "weak_counts", issue = "57977")]
1147+
pub fn strong_count(&self) -> usize {
1148+
if let Some(inner) = self.inner() {
1149+
inner.strong.load(SeqCst)
1150+
} else {
1151+
0
1152+
}
1153+
}
1154+
1155+
/// Gets an approximation of the number of `Weak` pointers pointing to this
1156+
/// value.
1157+
///
1158+
/// If `self` was created using [`Weak::new`], this will return 0. If not,
1159+
/// the returned value is at least 1, since `self` still points to the
1160+
/// value.
1161+
///
1162+
/// # Accuracy
1163+
///
1164+
/// Due to implementation details, the returned value can be off by 1 in
1165+
/// either direction when other threads are manipulating any `Arc`s or
1166+
/// `Weak`s pointing to the same value.
1167+
///
1168+
/// [`Weak::new`]: #method.new
1169+
#[unstable(feature = "weak_counts", issue = "57977")]
1170+
pub fn weak_count(&self) -> Option<usize> {
1171+
// Due to the implicit weak pointer added when any strong pointers are
1172+
// around, we cannot implement `weak_count` correctly since it
1173+
// necessarily requires accessing the strong count and weak count in an
1174+
// unsynchronized fashion. So this version is a bit racy.
1175+
self.inner().map(|inner| {
1176+
let strong = inner.strong.load(SeqCst);
1177+
let weak = inner.weak.load(SeqCst);
1178+
if strong == 0 {
1179+
// If the last `Arc` has *just* been dropped, it might not yet
1180+
// have removed the implicit weak count, so the value we get
1181+
// here might be 1 too high.
1182+
weak
1183+
} else {
1184+
// As long as there's still at least 1 `Arc` around, subtract
1185+
// the implicit weak pointer.
1186+
// Note that the last `Arc` might get dropped between the 2
1187+
// loads we do above, removing the implicit weak pointer. This
1188+
// means that the value might be 1 too low here. In order to not
1189+
// return 0 here (which would happen if we're the only weak
1190+
// pointer), we guard against that specifically.
1191+
cmp::max(1, weak - 1)
1192+
}
1193+
})
1194+
}
1195+
11411196
/// Return `None` when the pointer is dangling and there is no allocated `ArcInner`,
11421197
/// i.e., this `Weak` was created by `Weak::new`
11431198
#[inline]
@@ -1657,6 +1712,33 @@ mod tests {
16571712
assert!(Arc::get_mut(&mut x).is_none());
16581713
}
16591714

1715+
#[test]
1716+
fn weak_counts() {
1717+
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
1718+
assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
1719+
1720+
let a = Arc::new(0);
1721+
let w = Arc::downgrade(&a);
1722+
assert_eq!(Weak::strong_count(&w), 1);
1723+
assert_eq!(Weak::weak_count(&w), Some(1));
1724+
let w2 = w.clone();
1725+
assert_eq!(Weak::strong_count(&w), 1);
1726+
assert_eq!(Weak::weak_count(&w), Some(2));
1727+
assert_eq!(Weak::strong_count(&w2), 1);
1728+
assert_eq!(Weak::weak_count(&w2), Some(2));
1729+
drop(w);
1730+
assert_eq!(Weak::strong_count(&w2), 1);
1731+
assert_eq!(Weak::weak_count(&w2), Some(1));
1732+
let a2 = a.clone();
1733+
assert_eq!(Weak::strong_count(&w2), 2);
1734+
assert_eq!(Weak::weak_count(&w2), Some(1));
1735+
drop(a2);
1736+
drop(a);
1737+
assert_eq!(Weak::strong_count(&w2), 0);
1738+
assert_eq!(Weak::weak_count(&w2), Some(1));
1739+
drop(w2);
1740+
}
1741+
16601742
#[test]
16611743
fn try_unwrap() {
16621744
let x = Arc::new(3);

0 commit comments

Comments
 (0)