1
- use std:: mem:: ManuallyDrop ;
1
+ use std:: mem:: { self , ManuallyDrop } ;
2
2
3
3
use crate :: { deallocate_leaves, deallocate_tree_non_leaves, NodePtr , RawIterator , TreeMap } ;
4
4
@@ -17,13 +17,11 @@ pub struct IntoIter<K, V, const PREFIX_LEN: usize> {
17
17
18
18
impl < K , V , const PREFIX_LEN : usize > Drop for IntoIter < K , V , PREFIX_LEN > {
19
19
fn drop ( & mut self ) {
20
- if let Some ( next) = unsafe { self . inner . next ( ) } {
21
- // SAFETY: TODO
22
- unsafe { deallocate_leaves ( next) }
23
- }
20
+ // SAFETY: The `deallocate_tree_non_leaves` function is called earlier on the
21
+ // trie (which we have unique access to), so the leaves will still be allocated.
22
+ unsafe { deallocate_leaves ( mem:: replace ( & mut self . inner , RawIterator :: empty ( ) ) ) }
24
23
25
- // Just to be safe, clear the iterator
26
- self . inner = RawIterator :: empty ( ) ;
24
+ // Just to be safe, clear the iterator size
27
25
self . size = 0 ;
28
26
}
29
27
}
@@ -35,6 +33,8 @@ impl<K, V, const PREFIX_LEN: usize> IntoIter<K, V, PREFIX_LEN> {
35
33
let tree = ManuallyDrop :: new ( tree) ;
36
34
37
35
if let Some ( state) = & tree. state {
36
+ // SAFETY: By construction (and maintained on insert/delete), the `min_leaf` is
37
+ // always before or equal to `max_leaf` in the leaf node order.
38
38
let inner = unsafe { RawIterator :: new ( state. min_leaf , state. max_leaf ) } ;
39
39
40
40
// SAFETY: Since this function takes an owned `TreeMap`, we can assume there is
@@ -58,11 +58,13 @@ impl<K, V, const PREFIX_LEN: usize> Iterator for IntoIter<K, V, PREFIX_LEN> {
58
58
type Item = ( K , V ) ;
59
59
60
60
fn next ( & mut self ) -> Option < Self :: Item > {
61
- // SAFETY: TODO
61
+ // SAFETY: By construction of the `IntoIter` we know that we have ownership over
62
+ // the trie, and there will be no other concurrent access (read or write).
62
63
let leaf_ptr = unsafe { self . inner . next ( ) } ;
63
64
64
65
leaf_ptr. map ( |leaf_ptr| {
65
- // SAFETY: TODO
66
+ // SAFETY: This function is only called once for a given `leaf_ptr` since the
67
+ // iterator will never repeat
66
68
unsafe { NodePtr :: deallocate_node_ptr ( leaf_ptr) } . into_entry ( )
67
69
} )
68
70
}
@@ -74,20 +76,24 @@ impl<K, V, const PREFIX_LEN: usize> Iterator for IntoIter<K, V, PREFIX_LEN> {
74
76
75
77
impl < K , V , const PREFIX_LEN : usize > DoubleEndedIterator for IntoIter < K , V , PREFIX_LEN > {
76
78
fn next_back ( & mut self ) -> Option < Self :: Item > {
77
- // SAFETY: TODO
79
+ // SAFETY: By construction of the `IntoIter` we know that we have ownership over
80
+ // the trie, and there will be no other concurrent access (read or write).
78
81
let leaf_ptr = unsafe { self . inner . next_back ( ) } ;
79
82
80
83
leaf_ptr. map ( |leaf_ptr| {
81
- // SAFETY: TODO
84
+ // SAFETY: This function is only called once for a given `leaf_ptr` since the
85
+ // iterator will never repeat
82
86
unsafe { NodePtr :: deallocate_node_ptr ( leaf_ptr) } . into_entry ( )
83
87
} )
84
88
}
85
89
}
86
90
87
- /// An owning iterator over the keys of a `TreeMap`.
91
+ impl < K , V , const PREFIX_LEN : usize > ExactSizeIterator for IntoIter < K , V , PREFIX_LEN > { }
92
+
93
+ /// An owning iterator over the keys of a [`TreeMap`].
88
94
///
89
95
/// This `struct` is created by the [`crate::TreeMap::into_keys`] method on
90
- /// `TreeMap`. See its documentation for more.
96
+ /// [ `TreeMap`] . See its documentation for more.
91
97
pub struct IntoKeys < K , V , const PREFIX_LEN : usize > ( IntoIter < K , V , PREFIX_LEN > ) ;
92
98
93
99
impl < K , V , const PREFIX_LEN : usize > IntoKeys < K , V , PREFIX_LEN > {
@@ -102,6 +108,10 @@ impl<K, V, const PREFIX_LEN: usize> Iterator for IntoKeys<K, V, PREFIX_LEN> {
102
108
fn next ( & mut self ) -> Option < Self :: Item > {
103
109
Some ( self . 0 . next ( ) ?. 0 )
104
110
}
111
+
112
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
113
+ self . 0 . size_hint ( )
114
+ }
105
115
}
106
116
107
117
impl < K , V , const PREFIX_LEN : usize > DoubleEndedIterator for IntoKeys < K , V , PREFIX_LEN > {
@@ -110,9 +120,11 @@ impl<K, V, const PREFIX_LEN: usize> DoubleEndedIterator for IntoKeys<K, V, PREFI
110
120
}
111
121
}
112
122
113
- /// An owning iterator over the values of a `TreeMap`.
123
+ impl < K , V , const PREFIX_LEN : usize > ExactSizeIterator for IntoKeys < K , V , PREFIX_LEN > { }
124
+
125
+ /// An owning iterator over the values of a [`TreeMap`].
114
126
///
115
- /// This `struct` is created by the [`into_values`] method on `TreeMap`.
127
+ /// This `struct` is created by the [`into_values`] method on [ `TreeMap`] .
116
128
/// See its documentation for more.
117
129
///
118
130
/// [`into_values`]: crate::TreeMap::into_values
@@ -130,10 +142,153 @@ impl<K, V, const PREFIX_LEN: usize> Iterator for IntoValues<K, V, PREFIX_LEN> {
130
142
fn next ( & mut self ) -> Option < Self :: Item > {
131
143
Some ( self . 0 . next ( ) ?. 1 )
132
144
}
145
+
146
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
147
+ self . 0 . size_hint ( )
148
+ }
133
149
}
134
150
135
151
impl < K , V , const PREFIX_LEN : usize > DoubleEndedIterator for IntoValues < K , V , PREFIX_LEN > {
136
152
fn next_back ( & mut self ) -> Option < Self :: Item > {
137
153
Some ( self . 0 . next_back ( ) ?. 1 )
138
154
}
139
155
}
156
+
157
+ impl < K , V , const PREFIX_LEN : usize > ExactSizeIterator for IntoValues < K , V , PREFIX_LEN > { }
158
+
159
+ #[ cfg( test) ]
160
+ mod tests {
161
+ use std:: sync:: {
162
+ atomic:: { AtomicUsize , Ordering } ,
163
+ Arc ,
164
+ } ;
165
+
166
+ use crate :: { AsBytes , NoPrefixesBytes , OrderedBytes } ;
167
+
168
+ use super :: * ;
169
+
170
+ #[ derive( Debug ) ]
171
+ struct DropCounter < T > ( Arc < AtomicUsize > , T ) ;
172
+
173
+ impl < T > DropCounter < T > {
174
+ fn new ( counter : & Arc < AtomicUsize > , value : T ) -> Self {
175
+ counter. fetch_add ( 1 , Ordering :: Relaxed ) ;
176
+ DropCounter ( Arc :: clone ( counter) , value)
177
+ }
178
+ }
179
+
180
+ impl < T > Drop for DropCounter < T > {
181
+ fn drop ( & mut self ) {
182
+ self . 0 . fetch_sub ( 1 , Ordering :: Relaxed ) ;
183
+ }
184
+ }
185
+
186
+ impl < T : Ord > Ord for DropCounter < T > {
187
+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
188
+ self . 1 . cmp ( & other. 1 )
189
+ }
190
+ }
191
+
192
+ impl < T : PartialOrd > PartialOrd for DropCounter < T > {
193
+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
194
+ self . 1 . partial_cmp ( & other. 1 )
195
+ }
196
+ }
197
+
198
+ impl < T : Eq > Eq for DropCounter < T > { }
199
+
200
+ impl < T : PartialEq > PartialEq for DropCounter < T > {
201
+ fn eq ( & self , other : & Self ) -> bool {
202
+ self . 1 == other. 1
203
+ }
204
+ }
205
+
206
+ impl < T : AsBytes > AsBytes for DropCounter < T > {
207
+ fn as_bytes ( & self ) -> & [ u8 ] {
208
+ self . 1 . as_bytes ( )
209
+ }
210
+ }
211
+
212
+ unsafe impl < T : NoPrefixesBytes > NoPrefixesBytes for DropCounter < T > { }
213
+ unsafe impl < T : OrderedBytes + Ord > OrderedBytes for DropCounter < T > { }
214
+
215
+ fn setup_will_deallocate_unconsumed_iter_values (
216
+ drop_counter : & Arc < AtomicUsize > ,
217
+ ) -> TreeMap < DropCounter < [ u8 ; 3 ] > , usize > {
218
+ fn swap < A , B > ( ( a, b) : ( A , B ) ) -> ( B , A ) {
219
+ ( b, a)
220
+ }
221
+
222
+ assert_eq ! ( drop_counter. load( Ordering :: Relaxed ) , 0 ) ;
223
+
224
+ [
225
+ [ 0u8 , 0u8 , 0u8 ] ,
226
+ [ 0 , 0 , u8:: MAX ] ,
227
+ [ 0 , u8:: MAX , 0 ] ,
228
+ [ 0 , u8:: MAX , u8:: MAX ] ,
229
+ [ u8:: MAX , 0 , 0 ] ,
230
+ [ u8:: MAX , 0 , u8:: MAX ] ,
231
+ [ u8:: MAX , u8:: MAX , 0 ] ,
232
+ [ u8:: MAX , u8:: MAX , u8:: MAX ] ,
233
+ ]
234
+ . into_iter ( )
235
+ . map ( |arr| DropCounter :: new ( & drop_counter, arr) )
236
+ . enumerate ( )
237
+ . map ( swap)
238
+ . collect ( )
239
+ }
240
+
241
+ fn check_will_deallocate_unconsumed_iter_values (
242
+ drop_counter : & Arc < AtomicUsize > ,
243
+ mut iter : impl Iterator + DoubleEndedIterator + ExactSizeIterator ,
244
+ ) {
245
+ assert_eq ! ( drop_counter. load( Ordering :: Relaxed ) , 8 ) ;
246
+
247
+ assert_eq ! ( iter. len( ) , 8 ) ;
248
+
249
+ assert_eq ! ( drop_counter. load( Ordering :: Relaxed ) , 8 ) ;
250
+
251
+ let _ = iter. next ( ) . unwrap ( ) ;
252
+ let _ = iter. next_back ( ) . unwrap ( ) ;
253
+
254
+ assert_eq ! ( drop_counter. load( Ordering :: Relaxed ) , 6 ) ;
255
+
256
+ drop ( iter) ;
257
+
258
+ assert_eq ! ( drop_counter. load( Ordering :: Relaxed ) , 0 ) ;
259
+ }
260
+
261
+ #[ test]
262
+ fn into_iter_will_deallocate_unconsumed_iter_values ( ) {
263
+ let drop_counter = Arc :: new ( AtomicUsize :: new ( 0 ) ) ;
264
+
265
+ let tree = setup_will_deallocate_unconsumed_iter_values ( & drop_counter) ;
266
+
267
+ check_will_deallocate_unconsumed_iter_values ( & drop_counter, tree. into_iter ( ) ) ;
268
+ }
269
+
270
+ #[ test]
271
+ fn into_keys_will_deallocate_unconsumed_iter_values ( ) {
272
+ let drop_counter = Arc :: new ( AtomicUsize :: new ( 0 ) ) ;
273
+
274
+ let tree = setup_will_deallocate_unconsumed_iter_values ( & drop_counter) ;
275
+
276
+ check_will_deallocate_unconsumed_iter_values ( & drop_counter, tree. into_keys ( ) ) ;
277
+ }
278
+
279
+ #[ test]
280
+ fn into_values_will_deallocate_unconsumed_iter_values ( ) {
281
+ let drop_counter = Arc :: new ( AtomicUsize :: new ( 0 ) ) ;
282
+
283
+ let tree = setup_will_deallocate_unconsumed_iter_values ( & drop_counter) ;
284
+
285
+ check_will_deallocate_unconsumed_iter_values ( & drop_counter, tree. into_values ( ) ) ;
286
+ }
287
+
288
+ #[ test]
289
+ fn empty_tree_empty_iterator ( ) {
290
+ let tree: TreeMap < u8 , usize > = TreeMap :: new ( ) ;
291
+ let mut it = tree. into_iter ( ) ;
292
+ assert_eq ! ( it. next( ) , None ) ;
293
+ }
294
+ }
0 commit comments