@@ -11,7 +11,7 @@ use core::sync::atomic;
11
11
use core:: sync:: atomic:: Ordering :: { Acquire , Relaxed , Release , SeqCst } ;
12
12
use core:: borrow;
13
13
use core:: fmt;
14
- use core:: cmp:: Ordering ;
14
+ use core:: cmp:: { self , Ordering } ;
15
15
use core:: intrinsics:: abort;
16
16
use core:: mem:: { self , align_of_val, size_of_val} ;
17
17
use core:: ops:: { Deref , Receiver } ;
@@ -1131,10 +1131,48 @@ impl<T: ?Sized> Weak<T> {
1131
1131
}
1132
1132
}
1133
1133
1134
- // Due to the implicit weak pointer added when any strong pointers are
1135
- // around, we cannot implement `weak_count` correctly since it necessarily
1136
- // requires accessing the strong count and weak count in an unsynchronized
1137
- // fashion.
1134
+ /// Gets an approximation of the number of `Weak` pointers pointing to this
1135
+ /// value.
1136
+ ///
1137
+ /// If `self` was created using [`Weak::new`], this will return 0. If not,
1138
+ /// the returned value is at least 1, since `self` still points to the
1139
+ /// value.
1140
+ ///
1141
+ /// # Accuracy
1142
+ ///
1143
+ /// Due to implementation details, the returned value can be off by 1 in
1144
+ /// either direction when other threads are manipulating any `Arc`s or
1145
+ /// `Weak`s pointing to the same value.
1146
+ ///
1147
+ /// [`Weak::new`]: #method.new
1148
+ #[ unstable( feature = "weak_counts" , issue = "0" ) ]
1149
+ pub fn weak_count ( & self ) -> usize {
1150
+ // Due to the implicit weak pointer added when any strong pointers are
1151
+ // around, we cannot implement `weak_count` correctly since it
1152
+ // necessarily requires accessing the strong count and weak count in an
1153
+ // unsynchronized fashion. So this version is a bit racy.
1154
+ if let Some ( inner) = self . inner ( ) {
1155
+ let strong = inner. strong . load ( SeqCst ) ;
1156
+ let weak = inner. weak . load ( SeqCst ) ;
1157
+ if strong == 0 {
1158
+ // If the last `Arc` has *just* been dropped, it might not yet
1159
+ // have removed the implicit weak count, so the value we get
1160
+ // here might be 1 too high.
1161
+ weak
1162
+ } else {
1163
+ // As long as there's still at least 1 `Arc` around, subtract
1164
+ // the implicit weak pointer.
1165
+ // Note that the last `Arc` might get dropped between the 2
1166
+ // loads we do above, removing the implicit weak pointer. This
1167
+ // means that the value might be 1 too low here. In order to not
1168
+ // return 0 here (which would happen if we're the only weak
1169
+ // pointer), we guard against that specifically.
1170
+ cmp:: max ( 1 , weak - 1 )
1171
+ }
1172
+ } else {
1173
+ 0
1174
+ }
1175
+ }
1138
1176
1139
1177
/// Return `None` when the pointer is dangling and there is no allocated `ArcInner`,
1140
1178
/// i.e., this `Weak` was created by `Weak::new`
@@ -1655,6 +1693,33 @@ mod tests {
1655
1693
assert ! ( Arc :: get_mut( & mut x) . is_none( ) ) ;
1656
1694
}
1657
1695
1696
+ #[ test]
1697
+ fn weak_counts ( ) {
1698
+ assert_eq ! ( Weak :: weak_count( & Weak :: <u64 >:: new( ) ) , 0 ) ;
1699
+ assert_eq ! ( Weak :: strong_count( & Weak :: <u64 >:: new( ) ) , 0 ) ;
1700
+
1701
+ let a = Arc :: new ( 0 ) ;
1702
+ let w = Arc :: downgrade ( & a) ;
1703
+ assert_eq ! ( Weak :: strong_count( & w) , 1 ) ;
1704
+ assert_eq ! ( Weak :: weak_count( & w) , 1 ) ;
1705
+ let w2 = w. clone ( ) ;
1706
+ assert_eq ! ( Weak :: strong_count( & w) , 1 ) ;
1707
+ assert_eq ! ( Weak :: weak_count( & w) , 2 ) ;
1708
+ assert_eq ! ( Weak :: strong_count( & w2) , 1 ) ;
1709
+ assert_eq ! ( Weak :: weak_count( & w2) , 2 ) ;
1710
+ drop ( w) ;
1711
+ assert_eq ! ( Weak :: strong_count( & w2) , 1 ) ;
1712
+ assert_eq ! ( Weak :: weak_count( & w2) , 1 ) ;
1713
+ let a2 = a. clone ( ) ;
1714
+ assert_eq ! ( Weak :: strong_count( & w2) , 2 ) ;
1715
+ assert_eq ! ( Weak :: weak_count( & w2) , 1 ) ;
1716
+ drop ( a2) ;
1717
+ drop ( a) ;
1718
+ assert_eq ! ( Weak :: strong_count( & w2) , 0 ) ;
1719
+ assert_eq ! ( Weak :: weak_count( & w2) , 1 ) ;
1720
+ drop ( w2) ;
1721
+ }
1722
+
1658
1723
#[ test]
1659
1724
fn try_unwrap ( ) {
1660
1725
let x = Arc :: new ( 3 ) ;
0 commit comments