@@ -12,9 +12,9 @@ mod raw;
12
12
use hashbrown:: raw:: RawTable ;
13
13
14
14
use crate :: vec:: { Drain , Vec } ;
15
- use core :: cmp ;
15
+ use crate :: TryReserveError ;
16
16
use core:: fmt;
17
- use core:: mem:: replace ;
17
+ use core:: mem;
18
18
use core:: ops:: RangeBounds ;
19
19
20
20
use crate :: equivalent:: Equivalent ;
@@ -62,18 +62,18 @@ where
62
62
V : Clone ,
63
63
{
64
64
fn clone ( & self ) -> Self {
65
- let indices = self . indices . clone ( ) ;
66
- let mut entries = Vec :: with_capacity ( indices. capacity ( ) ) ;
67
- entries. clone_from ( & self . entries ) ;
68
- IndexMapCore { indices, entries }
65
+ let mut new = Self :: new ( ) ;
66
+ new. clone_from ( self ) ;
67
+ new
69
68
}
70
69
71
70
fn clone_from ( & mut self , other : & Self ) {
72
71
let hasher = get_hash ( & other. entries ) ;
73
72
self . indices . clone_from_with_hasher ( & other. indices , hasher) ;
74
73
if self . entries . capacity ( ) < other. entries . len ( ) {
75
- // If we must resize, match the indices capacity
76
- self . reserve_entries ( ) ;
74
+ // If we must resize, match the indices capacity.
75
+ let additional = other. entries . len ( ) - self . entries . len ( ) ;
76
+ self . reserve_entries ( additional) ;
77
77
}
78
78
self . entries . clone_from ( & other. entries ) ;
79
79
}
@@ -120,6 +120,9 @@ impl<K, V> Entries for IndexMapCore<K, V> {
120
120
}
121
121
122
122
impl < K , V > IndexMapCore < K , V > {
123
+ /// The maximum capacity before the `entries` allocation would exceed `isize::MAX`.
124
+ const MAX_ENTRIES_CAPACITY : usize = ( isize:: MAX as usize ) / mem:: size_of :: < Bucket < K , V > > ( ) ;
125
+
123
126
#[ inline]
124
127
pub ( crate ) const fn new ( ) -> Self {
125
128
IndexMapCore {
@@ -143,7 +146,7 @@ impl<K, V> IndexMapCore<K, V> {
143
146
144
147
#[ inline]
145
148
pub ( crate ) fn capacity ( & self ) -> usize {
146
- cmp :: min ( self . indices . capacity ( ) , self . entries . capacity ( ) )
149
+ Ord :: min ( self . indices . capacity ( ) , self . entries . capacity ( ) )
147
150
}
148
151
149
152
pub ( crate ) fn clear ( & mut self ) {
@@ -193,15 +196,67 @@ impl<K, V> IndexMapCore<K, V> {
193
196
/// Reserve capacity for `additional` more key-value pairs.
194
197
pub ( crate ) fn reserve ( & mut self , additional : usize ) {
195
198
self . indices . reserve ( additional, get_hash ( & self . entries ) ) ;
196
- self . reserve_entries ( ) ;
199
+ // Only grow entries if necessary, since we also round up capacity.
200
+ if additional > self . entries . capacity ( ) - self . entries . len ( ) {
201
+ self . reserve_entries ( additional) ;
202
+ }
203
+ }
204
+
205
+ /// Reserve entries capacity, rounded up to match the indices
206
+ fn reserve_entries ( & mut self , additional : usize ) {
207
+ // Use a soft-limit on the maximum capacity, but if the caller explicitly
208
+ // requested more, do it and let them have the resulting panic.
209
+ let new_capacity = Ord :: min ( self . indices . capacity ( ) , Self :: MAX_ENTRIES_CAPACITY ) ;
210
+ let try_add = new_capacity - self . entries . len ( ) ;
211
+ if try_add > additional && self . entries . try_reserve_exact ( try_add) . is_ok ( ) {
212
+ return ;
213
+ }
214
+ self . entries . reserve_exact ( additional) ;
197
215
}
198
216
199
- /// Reserve entries capacity to match the indices
200
- fn reserve_entries ( & mut self ) {
201
- let additional = self . indices . capacity ( ) - self . entries . len ( ) ;
217
+ /// Reserve capacity for `additional` more key-value pairs, without over-allocating.
218
+ pub ( crate ) fn reserve_exact ( & mut self , additional : usize ) {
219
+ self . indices . reserve ( additional , get_hash ( & self . entries ) ) ;
202
220
self . entries . reserve_exact ( additional) ;
203
221
}
204
222
223
+ /// Try to reserve capacity for `additional` more key-value pairs.
224
+ pub ( crate ) fn try_reserve ( & mut self , additional : usize ) -> Result < ( ) , TryReserveError > {
225
+ self . indices
226
+ . try_reserve ( additional, get_hash ( & self . entries ) )
227
+ . map_err ( TryReserveError :: from_hashbrown) ?;
228
+ // Only grow entries if necessary, since we also round up capacity.
229
+ if additional > self . entries . capacity ( ) - self . entries . len ( ) {
230
+ self . try_reserve_entries ( additional)
231
+ } else {
232
+ Ok ( ( ) )
233
+ }
234
+ }
235
+
236
+ /// Try to reserve entries capacity, rounded up to match the indices
237
+ fn try_reserve_entries ( & mut self , additional : usize ) -> Result < ( ) , TryReserveError > {
238
+ // Use a soft-limit on the maximum capacity, but if the caller explicitly
239
+ // requested more, do it and let them have the resulting error.
240
+ let new_capacity = Ord :: min ( self . indices . capacity ( ) , Self :: MAX_ENTRIES_CAPACITY ) ;
241
+ let try_add = new_capacity - self . entries . len ( ) ;
242
+ if try_add > additional && self . entries . try_reserve_exact ( try_add) . is_ok ( ) {
243
+ return Ok ( ( ) ) ;
244
+ }
245
+ self . entries
246
+ . try_reserve_exact ( additional)
247
+ . map_err ( TryReserveError :: from_alloc)
248
+ }
249
+
250
+ /// Try to reserve capacity for `additional` more key-value pairs, without over-allocating.
251
+ pub ( crate ) fn try_reserve_exact ( & mut self , additional : usize ) -> Result < ( ) , TryReserveError > {
252
+ self . indices
253
+ . try_reserve ( additional, get_hash ( & self . entries ) )
254
+ . map_err ( TryReserveError :: from_hashbrown) ?;
255
+ self . entries
256
+ . try_reserve_exact ( additional)
257
+ . map_err ( TryReserveError :: from_alloc)
258
+ }
259
+
205
260
/// Shrink the capacity of the map with a lower bound
206
261
pub ( crate ) fn shrink_to ( & mut self , min_capacity : usize ) {
207
262
self . indices
@@ -228,7 +283,7 @@ impl<K, V> IndexMapCore<K, V> {
228
283
if i == self . entries . capacity ( ) {
229
284
// Reserve our own capacity synced to the indices,
230
285
// rather than letting `Vec::push` just double it.
231
- self . reserve_entries ( ) ;
286
+ self . reserve_entries ( 1 ) ;
232
287
}
233
288
self . entries . push ( Bucket { hash, key, value } ) ;
234
289
i
@@ -248,7 +303,7 @@ impl<K, V> IndexMapCore<K, V> {
248
303
K : Eq ,
249
304
{
250
305
match self . get_index_of ( hash, & key) {
251
- Some ( i) => ( i, Some ( replace ( & mut self . entries [ i] . value , value) ) ) ,
306
+ Some ( i) => ( i, Some ( mem :: replace ( & mut self . entries [ i] . value , value) ) ) ,
252
307
None => ( self . push ( hash, key, value) , None ) ,
253
308
}
254
309
}
@@ -601,7 +656,7 @@ pub use self::raw::OccupiedEntry;
601
656
impl < K , V > OccupiedEntry < ' _ , K , V > {
602
657
/// Sets the value of the entry to `value`, and returns the entry's old value.
603
658
pub fn insert ( & mut self , value : V ) -> V {
604
- replace ( self . get_mut ( ) , value)
659
+ mem :: replace ( self . get_mut ( ) , value)
605
660
}
606
661
607
662
/// Remove the key, value pair stored in the map for this entry, and return the value.
0 commit comments