@@ -13,9 +13,8 @@ use hashbrown::raw::RawTable;
13
13
14
14
use crate :: vec:: { Drain , Vec } ;
15
15
use crate :: TryReserveError ;
16
- use core:: cmp;
17
16
use core:: fmt;
18
- use core:: mem:: replace ;
17
+ use core:: mem;
19
18
use core:: ops:: RangeBounds ;
20
19
21
20
use crate :: equivalent:: Equivalent ;
@@ -63,18 +62,18 @@ where
63
62
V : Clone ,
64
63
{
65
64
fn clone ( & self ) -> Self {
66
- let indices = self . indices . clone ( ) ;
67
- let mut entries = Vec :: with_capacity ( indices. capacity ( ) ) ;
68
- entries. clone_from ( & self . entries ) ;
69
- IndexMapCore { indices, entries }
65
+ let mut new = Self :: new ( ) ;
66
+ new. clone_from ( self ) ;
67
+ new
70
68
}
71
69
72
70
fn clone_from ( & mut self , other : & Self ) {
73
71
let hasher = get_hash ( & other. entries ) ;
74
72
self . indices . clone_from_with_hasher ( & other. indices , hasher) ;
75
73
if self . entries . capacity ( ) < other. entries . len ( ) {
76
- // If we must resize, match the indices capacity
77
- 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) ;
78
77
}
79
78
self . entries . clone_from ( & other. entries ) ;
80
79
}
@@ -121,6 +120,9 @@ impl<K, V> Entries for IndexMapCore<K, V> {
121
120
}
122
121
123
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
+
124
126
#[ inline]
125
127
pub ( crate ) const fn new ( ) -> Self {
126
128
IndexMapCore {
@@ -144,7 +146,7 @@ impl<K, V> IndexMapCore<K, V> {
144
146
145
147
#[ inline]
146
148
pub ( crate ) fn capacity ( & self ) -> usize {
147
- cmp :: min ( self . indices . capacity ( ) , self . entries . capacity ( ) )
149
+ Ord :: min ( self . indices . capacity ( ) , self . entries . capacity ( ) )
148
150
}
149
151
150
152
pub ( crate ) fn clear ( & mut self ) {
@@ -194,12 +196,18 @@ impl<K, V> IndexMapCore<K, V> {
194
196
/// Reserve capacity for `additional` more key-value pairs.
195
197
pub ( crate ) fn reserve ( & mut self , additional : usize ) {
196
198
self . indices . reserve ( additional, get_hash ( & self . entries ) ) ;
197
- self . reserve_entries ( ) ;
199
+ self . reserve_entries ( additional ) ;
198
200
}
199
201
200
- /// Reserve entries capacity to match the indices
201
- fn reserve_entries ( & mut self ) {
202
- let additional = self . indices . capacity ( ) - self . entries . len ( ) ;
202
+ /// Reserve entries capacity, rounded up to match the indices
203
+ fn reserve_entries ( & mut self , additional : usize ) {
204
+ // Use a soft-limit on the maximum capacity, but if the caller explicitly
205
+ // requested more, do it and let them have the resulting panic.
206
+ let new_capacity = Ord :: min ( self . indices . capacity ( ) , Self :: MAX_ENTRIES_CAPACITY ) ;
207
+ let try_add = new_capacity - self . entries . len ( ) ;
208
+ if try_add > additional && self . entries . try_reserve_exact ( try_add) . is_ok ( ) {
209
+ return ;
210
+ }
203
211
self . entries . reserve_exact ( additional) ;
204
212
}
205
213
@@ -214,12 +222,18 @@ impl<K, V> IndexMapCore<K, V> {
214
222
self . indices
215
223
. try_reserve ( additional, get_hash ( & self . entries ) )
216
224
. map_err ( TryReserveError :: from_hashbrown) ?;
217
- self . try_reserve_entries ( )
225
+ self . try_reserve_entries ( additional )
218
226
}
219
227
220
- /// Try to reserve entries capacity to match the indices
221
- fn try_reserve_entries ( & mut self ) -> Result < ( ) , TryReserveError > {
222
- let additional = self . indices . capacity ( ) - self . entries . len ( ) ;
228
+ /// Try to reserve entries capacity, rounded up to match the indices
229
+ fn try_reserve_entries ( & mut self , additional : usize ) -> Result < ( ) , TryReserveError > {
230
+ // Use a soft-limit on the maximum capacity, but if the caller explicitly
231
+ // requested more, do it and let them have the resulting error.
232
+ let new_capacity = Ord :: min ( self . indices . capacity ( ) , Self :: MAX_ENTRIES_CAPACITY ) ;
233
+ let try_add = new_capacity - self . entries . len ( ) ;
234
+ if try_add > additional && self . entries . try_reserve_exact ( try_add) . is_ok ( ) {
235
+ return Ok ( ( ) ) ;
236
+ }
223
237
self . entries
224
238
. try_reserve_exact ( additional)
225
239
. map_err ( TryReserveError :: from_alloc)
@@ -261,7 +275,7 @@ impl<K, V> IndexMapCore<K, V> {
261
275
if i == self . entries . capacity ( ) {
262
276
// Reserve our own capacity synced to the indices,
263
277
// rather than letting `Vec::push` just double it.
264
- self . reserve_entries ( ) ;
278
+ self . reserve_entries ( 1 ) ;
265
279
}
266
280
self . entries . push ( Bucket { hash, key, value } ) ;
267
281
i
@@ -281,7 +295,7 @@ impl<K, V> IndexMapCore<K, V> {
281
295
K : Eq ,
282
296
{
283
297
match self . get_index_of ( hash, & key) {
284
- Some ( i) => ( i, Some ( replace ( & mut self . entries [ i] . value , value) ) ) ,
298
+ Some ( i) => ( i, Some ( mem :: replace ( & mut self . entries [ i] . value , value) ) ) ,
285
299
None => ( self . push ( hash, key, value) , None ) ,
286
300
}
287
301
}
@@ -634,7 +648,7 @@ pub use self::raw::OccupiedEntry;
634
648
impl < K , V > OccupiedEntry < ' _ , K , V > {
635
649
/// Sets the value of the entry to `value`, and returns the entry's old value.
636
650
pub fn insert ( & mut self , value : V ) -> V {
637
- replace ( self . get_mut ( ) , value)
651
+ mem :: replace ( self . get_mut ( ) , value)
638
652
}
639
653
640
654
/// Remove the key, value pair stored in the map for this entry, and return the value.
0 commit comments