@@ -7,6 +7,25 @@ use std::hash::Hash;
77use std:: iter:: FromIterator ;
88use std:: ops:: Index ;
99
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+
1029/// Small-storage-optimized implementation of a map.
1130///
1231/// Stores elements in a small array up to a certain length
@@ -26,7 +45,7 @@ use std::ops::Index;
2645/// Vacant/Occupied entries and related
2746#[ derive( Clone ) ]
2847pub enum SsoHashMap < K , V > {
29- Array ( ArrayVec < [ ( K , V ) ; 8 ] > ) ,
48+ Array ( ArrayVec < [ ( K , V ) ; SSO_ARRAY_SIZE ] > ) ,
3049 Map ( FxHashMap < K , V > ) ,
3150}
3251
@@ -39,9 +58,8 @@ impl<K, V> SsoHashMap<K, V> {
3958
4059 /// Creates an empty `SsoHashMap` with the specified capacity.
4160 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 ( )
4563 } else {
4664 SsoHashMap :: Map ( FxHashMap :: with_capacity_and_hasher ( cap, Default :: default ( ) ) )
4765 }
@@ -59,7 +77,7 @@ impl<K, V> SsoHashMap<K, V> {
5977 /// Returns the number of elements the map can hold without reallocating.
6078 pub fn capacity ( & self ) -> usize {
6179 match self {
62- SsoHashMap :: Array ( array ) => array . capacity ( ) ,
80+ SsoHashMap :: Array ( _ ) => SSO_ARRAY_SIZE ,
6381 SsoHashMap :: Map ( map) => map. capacity ( ) ,
6482 }
6583 }
@@ -149,7 +167,7 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> {
149167 pub fn reserve ( & mut self , additional : usize ) {
150168 match self {
151169 SsoHashMap :: Array ( array) => {
152- if array . capacity ( ) < ( array. len ( ) + additional) {
170+ if SSO_ARRAY_SIZE < ( array. len ( ) + additional) {
153171 let mut map: FxHashMap < K , V > = array. drain ( ..) . collect ( ) ;
154172 map. reserve ( additional) ;
155173 * self = SsoHashMap :: Map ( map) ;
@@ -164,10 +182,8 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> {
164182 /// and possibly leaving some space in accordance with the resize policy.
165183 pub fn shrink_to_fit ( & mut self ) {
166184 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 ( ) ) ;
171187 } else {
172188 map. shrink_to_fit ( ) ;
173189 }
@@ -361,7 +377,7 @@ impl<K: Eq + Hash, V> Extend<(K, V)> for SsoHashMap<K, V> {
361377 fn extend_reserve ( & mut self , additional : usize ) {
362378 match self {
363379 SsoHashMap :: Array ( array) => {
364- if array . capacity ( ) < ( array. len ( ) + additional) {
380+ if SSO_ARRAY_SIZE < ( array. len ( ) + additional) {
365381 let mut map: FxHashMap < K , V > = array. drain ( ..) . collect ( ) ;
366382 map. extend_reserve ( additional) ;
367383 * self = SsoHashMap :: Map ( map) ;
@@ -517,8 +533,9 @@ impl<'a, K: Eq + Hash, V> Entry<'a, K, V> {
517533 let index = if let Some ( index) = found_index {
518534 index
519535 } else {
536+ let index = array. len ( ) ;
520537 array. try_push ( ( self . key , default ( ) ) ) . unwrap ( ) ;
521- array . len ( ) - 1
538+ index
522539 } ;
523540 & mut array[ index] . 1
524541 }
0 commit comments