@@ -7,6 +7,25 @@ use std::hash::Hash;
7
7
use std:: iter:: FromIterator ;
8
8
use std:: ops:: Index ;
9
9
10
+ // For pointer-sized arguments arrays
11
+ // are faster than set/map for up to 64
12
+ // arguments.
13
+ //
14
+ // On the other hand such a big array
15
+ // hurts cache performance, makes passing
16
+ // sso structures around very expensive.
17
+ //
18
+ // Biggest performance benefit is gained
19
+ // for reasonably small arrays that stay
20
+ // small in vast majority of cases.
21
+ //
22
+ // '8' is choosen as a sane default, to be
23
+ // reevaluated later.
24
+ //
25
+ // Note: As of now ArrayVec design prevents
26
+ // us from making it user-customizable.
27
+ const SSO_ARRAY_SIZE : usize = 8 ;
28
+
10
29
/// Small-storage-optimized implementation of a map.
11
30
///
12
31
/// Stores elements in a small array up to a certain length
@@ -26,7 +45,7 @@ use std::ops::Index;
26
45
/// Vacant/Occupied entries and related
27
46
#[ derive( Clone ) ]
28
47
pub enum SsoHashMap < K , V > {
29
- Array ( ArrayVec < [ ( K , V ) ; 8 ] > ) ,
48
+ Array ( ArrayVec < [ ( K , V ) ; SSO_ARRAY_SIZE ] > ) ,
30
49
Map ( FxHashMap < K , V > ) ,
31
50
}
32
51
@@ -39,9 +58,8 @@ impl<K, V> SsoHashMap<K, V> {
39
58
40
59
/// Creates an empty `SsoHashMap` with the specified capacity.
41
60
pub fn with_capacity ( cap : usize ) -> Self {
42
- let array = ArrayVec :: new ( ) ;
43
- if array. capacity ( ) >= cap {
44
- SsoHashMap :: Array ( array)
61
+ if cap <= SSO_ARRAY_SIZE {
62
+ Self :: new ( )
45
63
} else {
46
64
SsoHashMap :: Map ( FxHashMap :: with_capacity_and_hasher ( cap, Default :: default ( ) ) )
47
65
}
@@ -59,7 +77,7 @@ impl<K, V> SsoHashMap<K, V> {
59
77
/// Returns the number of elements the map can hold without reallocating.
60
78
pub fn capacity ( & self ) -> usize {
61
79
match self {
62
- SsoHashMap :: Array ( array ) => array . capacity ( ) ,
80
+ SsoHashMap :: Array ( _ ) => SSO_ARRAY_SIZE ,
63
81
SsoHashMap :: Map ( map) => map. capacity ( ) ,
64
82
}
65
83
}
@@ -149,7 +167,7 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> {
149
167
pub fn reserve ( & mut self , additional : usize ) {
150
168
match self {
151
169
SsoHashMap :: Array ( array) => {
152
- if array . capacity ( ) < ( array. len ( ) + additional) {
170
+ if SSO_ARRAY_SIZE < ( array. len ( ) + additional) {
153
171
let mut map: FxHashMap < K , V > = array. drain ( ..) . collect ( ) ;
154
172
map. reserve ( additional) ;
155
173
* self = SsoHashMap :: Map ( map) ;
@@ -164,10 +182,8 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> {
164
182
/// and possibly leaving some space in accordance with the resize policy.
165
183
pub fn shrink_to_fit ( & mut self ) {
166
184
if let SsoHashMap :: Map ( map) = self {
167
- let mut array = ArrayVec :: new ( ) ;
168
- if map. len ( ) <= array. capacity ( ) {
169
- array. extend ( map. drain ( ) ) ;
170
- * self = SsoHashMap :: Array ( array) ;
185
+ if map. len ( ) <= SSO_ARRAY_SIZE {
186
+ * self = SsoHashMap :: Array ( map. drain ( ) . collect ( ) ) ;
171
187
} else {
172
188
map. shrink_to_fit ( ) ;
173
189
}
@@ -361,7 +377,7 @@ impl<K: Eq + Hash, V> Extend<(K, V)> for SsoHashMap<K, V> {
361
377
fn extend_reserve ( & mut self , additional : usize ) {
362
378
match self {
363
379
SsoHashMap :: Array ( array) => {
364
- if array . capacity ( ) < ( array. len ( ) + additional) {
380
+ if SSO_ARRAY_SIZE < ( array. len ( ) + additional) {
365
381
let mut map: FxHashMap < K , V > = array. drain ( ..) . collect ( ) ;
366
382
map. extend_reserve ( additional) ;
367
383
* self = SsoHashMap :: Map ( map) ;
@@ -517,8 +533,9 @@ impl<'a, K: Eq + Hash, V> Entry<'a, K, V> {
517
533
let index = if let Some ( index) = found_index {
518
534
index
519
535
} else {
536
+ let index = array. len ( ) ;
520
537
array. try_push ( ( self . key , default ( ) ) ) . unwrap ( ) ;
521
- array . len ( ) - 1
538
+ index
522
539
} ;
523
540
& mut array[ index] . 1
524
541
}
0 commit comments