@@ -34,13 +34,9 @@ use super::table::BucketState::{
34
34
Full ,
35
35
} ;
36
36
37
- const INITIAL_LOG2_CAP : usize = 5 ;
38
- const INITIAL_CAPACITY : usize = 1 << INITIAL_LOG2_CAP ; // 2^5
37
+ const MIN_NONZERO_RAW_CAPACITY : usize = 32 ; // must be a power of two
39
38
40
- /// The default behavior of HashMap implements a load factor of 90.9%.
41
- /// This behavior is characterized by the following condition:
42
- ///
43
- /// - if size > 0.909 * capacity: grow the map
39
+ /// The default behavior of HashMap implements a maximum load factor of 90.9%.
44
40
#[ derive( Clone ) ]
45
41
struct DefaultResizePolicy ;
46
42
@@ -49,40 +45,35 @@ impl DefaultResizePolicy {
49
45
DefaultResizePolicy
50
46
}
51
47
48
+ /// A hash map's "capacity" is the number of elements it can hold without
49
+ /// being resized. Its "raw capacity" is the number of slots required to
50
+ /// provide that capacity, accounting for maximum loading. The raw capacity
51
+ /// is always zero or a power of two.
52
52
#[ inline]
53
- fn min_capacity ( & self , usable_size : usize ) -> usize {
54
- // Here, we are rephrasing the logic by specifying the lower limit
55
- // on capacity:
56
- //
57
- // - if `cap < size * 1.1`: grow the map
58
- usable_size * 11 / 10
53
+ fn raw_capacity ( & self , len : usize ) -> usize {
54
+ if len == 0 {
55
+ 0
56
+ } else {
57
+ // 1. Account for loading: `raw_capacity >= len * 1.1`.
58
+ // 2. Ensure it is a power of two.
59
+ // 3. Ensure it is at least the minimum size.
60
+ let mut raw_cap = len * 11 / 10 ;
61
+ assert ! ( raw_cap >= len, "raw_cap overflow" ) ;
62
+ raw_cap = raw_cap. checked_next_power_of_two ( ) . expect ( "raw_capacity overflow" ) ;
63
+ raw_cap = max ( MIN_NONZERO_RAW_CAPACITY , raw_cap) ;
64
+ raw_cap
65
+ }
59
66
}
60
67
61
- /// An inverse of `min_capacity`, approximately .
68
+ /// The capacity of the given raw capacity .
62
69
#[ inline]
63
- fn usable_capacity ( & self , cap : usize ) -> usize {
64
- // As the number of entries approaches usable capacity,
65
- // min_capacity(size) must be smaller than the internal capacity,
66
- // so that the map is not resized:
67
- // `min_capacity(usable_capacity(x)) <= x`.
68
- // The left-hand side can only be smaller due to flooring by integer
69
- // division.
70
- //
70
+ fn capacity ( & self , raw_cap : usize ) -> usize {
71
71
// This doesn't have to be checked for overflow since allocation size
72
72
// in bytes will overflow earlier than multiplication by 10.
73
73
//
74
74
// As per https://github.com/rust-lang/rust/pull/30991 this is updated
75
- // to be: (cap * den + den - 1) / num
76
- ( cap * 10 + 10 - 1 ) / 11
77
- }
78
- }
79
-
80
- #[ test]
81
- fn test_resize_policy ( ) {
82
- let rp = DefaultResizePolicy ;
83
- for n in 0 ..1000 {
84
- assert ! ( rp. min_capacity( rp. usable_capacity( n) ) <= n) ;
85
- assert ! ( rp. usable_capacity( rp. min_capacity( n) ) <= n) ;
75
+ // to be: (raw_cap * den + den - 1) / num
76
+ ( raw_cap * 10 + 10 - 1 ) / 11
86
77
}
87
78
}
88
79
@@ -510,11 +501,11 @@ impl<K, V, S> HashMap<K, V, S>
510
501
511
502
// The caller should ensure that invariants by Robin Hood Hashing hold.
512
503
fn insert_hashed_ordered ( & mut self , hash : SafeHash , k : K , v : V ) {
513
- let cap = self . table . capacity ( ) ;
504
+ let raw_cap = self . raw_capacity ( ) ;
514
505
let mut buckets = Bucket :: new ( & mut self . table , hash) ;
515
506
let ib = buckets. index ( ) ;
516
507
517
- while buckets. index ( ) != ib + cap {
508
+ while buckets. index ( ) != ib + raw_cap {
518
509
// We don't need to compare hashes for value swap.
519
510
// Not even DIBs for Robin Hood.
520
511
buckets = match buckets. peek ( ) {
@@ -545,7 +536,10 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
545
536
Default :: default ( )
546
537
}
547
538
548
- /// Creates an empty `HashMap` with the given initial capacity.
539
+ /// Creates an empty `HashMap` with the specified capacity.
540
+ ///
541
+ /// The hash map will be able to hold at least `capacity` elements without
542
+ /// reallocating. If `capacity` is 0, the hash map will not allocate.
549
543
///
550
544
/// # Examples
551
545
///
@@ -593,9 +587,11 @@ impl<K, V, S> HashMap<K, V, S>
593
587
}
594
588
}
595
589
596
- /// Creates an empty `HashMap` with space for at least `capacity `
597
- /// elements, using `hasher` to hash the keys.
590
+ /// Creates an empty `HashMap` with the specified capacity, using `hasher `
591
+ /// to hash the keys.
598
592
///
593
+ /// The hash map will be able to hold at least `capacity` elements without
594
+ /// reallocating. If `capacity` is 0, the hash map will not allocate.
599
595
/// Warning: `hasher` is normally randomly generated, and
600
596
/// is designed to allow HashMaps to be resistant to attacks that
601
597
/// cause many collisions and very poor performance. Setting it
@@ -616,13 +612,11 @@ impl<K, V, S> HashMap<K, V, S>
616
612
pub fn with_capacity_and_hasher ( capacity : usize , hash_builder : S )
617
613
-> HashMap < K , V , S > {
618
614
let resize_policy = DefaultResizePolicy :: new ( ) ;
619
- let min_cap = max ( INITIAL_CAPACITY , resize_policy. min_capacity ( capacity) ) ;
620
- let internal_cap = min_cap. checked_next_power_of_two ( ) . expect ( "capacity overflow" ) ;
621
- assert ! ( internal_cap >= capacity, "capacity overflow" ) ;
615
+ let raw_cap = resize_policy. raw_capacity ( capacity) ;
622
616
HashMap {
623
617
hash_builder : hash_builder,
624
618
resize_policy : resize_policy,
625
- table : RawTable :: new ( internal_cap ) ,
619
+ table : RawTable :: new ( raw_cap ) ,
626
620
}
627
621
}
628
622
@@ -647,7 +641,13 @@ impl<K, V, S> HashMap<K, V, S>
647
641
#[ inline]
648
642
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
649
643
pub fn capacity ( & self ) -> usize {
650
- self . resize_policy . usable_capacity ( self . table . capacity ( ) )
644
+ self . resize_policy . capacity ( self . raw_capacity ( ) )
645
+ }
646
+
647
+ /// Returns the hash map's raw capacity.
648
+ #[ inline]
649
+ fn raw_capacity ( & self ) -> usize {
650
+ self . table . capacity ( )
651
651
}
652
652
653
653
/// Reserves capacity for at least `additional` more elements to be inserted
@@ -667,28 +667,23 @@ impl<K, V, S> HashMap<K, V, S>
667
667
/// ```
668
668
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
669
669
pub fn reserve ( & mut self , additional : usize ) {
670
- let new_size = self . len ( ) . checked_add ( additional) . expect ( "capacity overflow" ) ;
671
- let min_cap = self . resize_policy . min_capacity ( new_size) ;
672
-
673
- // An invalid value shouldn't make us run out of space. This includes
674
- // an overflow check.
675
- assert ! ( new_size <= min_cap) ;
676
-
677
- if self . table . capacity ( ) < min_cap {
678
- let new_capacity = max ( min_cap. next_power_of_two ( ) , INITIAL_CAPACITY ) ;
679
- self . resize ( new_capacity) ;
670
+ let min_cap = self . len ( ) . checked_add ( additional) . expect ( "reserve overflow" ) ;
671
+ if self . capacity ( ) < min_cap {
672
+ let raw_cap = self . resize_policy . raw_capacity ( min_cap) ;
673
+ self . resize ( raw_cap) ;
680
674
}
681
675
}
682
676
683
- /// Resizes the internal vectors to a new capacity. It's your responsibility to:
684
- /// 1) Make sure the new capacity is enough for all the elements, accounting
677
+ /// Resizes the internal vectors to a new capacity. It's your
678
+ /// responsibility to:
679
+ /// 1) Ensure `new_raw_cap` is enough for all the elements, accounting
685
680
/// for the load factor.
686
- /// 2) Ensure `new_capacity ` is a power of two or zero.
687
- fn resize ( & mut self , new_capacity : usize ) {
688
- assert ! ( self . table. size( ) <= new_capacity ) ;
689
- assert ! ( new_capacity . is_power_of_two( ) || new_capacity == 0 ) ;
681
+ /// 2) Ensure `new_raw_cap ` is a power of two or zero.
682
+ fn resize ( & mut self , new_raw_cap : usize ) {
683
+ assert ! ( self . table. size( ) <= new_raw_cap ) ;
684
+ assert ! ( new_raw_cap . is_power_of_two( ) || new_raw_cap == 0 ) ;
690
685
691
- let mut old_table = replace ( & mut self . table , RawTable :: new ( new_capacity ) ) ;
686
+ let mut old_table = replace ( & mut self . table , RawTable :: new ( new_raw_cap ) ) ;
692
687
let old_size = old_table. size ( ) ;
693
688
694
689
if old_table. capacity ( ) == 0 || old_table. size ( ) == 0 {
@@ -778,14 +773,9 @@ impl<K, V, S> HashMap<K, V, S>
778
773
/// ```
779
774
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
780
775
pub fn shrink_to_fit ( & mut self ) {
781
- let min_capacity = self . resize_policy . min_capacity ( self . len ( ) ) ;
782
- let min_capacity = max ( min_capacity. next_power_of_two ( ) , INITIAL_CAPACITY ) ;
783
-
784
- // An invalid value shouldn't make us run out of space.
785
- debug_assert ! ( self . len( ) <= min_capacity) ;
786
-
787
- if self . table . capacity ( ) != min_capacity {
788
- let old_table = replace ( & mut self . table , RawTable :: new ( min_capacity) ) ;
776
+ let new_raw_cap = self . resize_policy . raw_capacity ( self . len ( ) ) ;
777
+ if self . raw_capacity ( ) != new_raw_cap {
778
+ let old_table = replace ( & mut self . table , RawTable :: new ( new_raw_cap) ) ;
789
779
let old_size = old_table. size ( ) ;
790
780
791
781
// Shrink the table. Naive algorithm for resizing:
@@ -2092,7 +2082,7 @@ mod test_map {
2092
2082
use rand:: { thread_rng, Rng } ;
2093
2083
2094
2084
#[ test]
2095
- fn test_create_capacities ( ) {
2085
+ fn test_zero_capacities ( ) {
2096
2086
type HM = HashMap < i32 , i32 > ;
2097
2087
2098
2088
let m = HM :: new ( ) ;
@@ -2103,6 +2093,24 @@ mod test_map {
2103
2093
2104
2094
let m = HM :: with_hasher ( RandomState :: new ( ) ) ;
2105
2095
assert_eq ! ( m. capacity( ) , 0 ) ;
2096
+
2097
+ let m = HM :: with_capacity ( 0 ) ;
2098
+ assert_eq ! ( m. capacity( ) , 0 ) ;
2099
+
2100
+ let m = HM :: with_capacity_and_hasher ( 0 , RandomState :: new ( ) ) ;
2101
+ assert_eq ! ( m. capacity( ) , 0 ) ;
2102
+
2103
+ let mut m = HM :: new ( ) ;
2104
+ m. insert ( 1 , 1 ) ;
2105
+ m. insert ( 2 , 2 ) ;
2106
+ m. remove ( & 1 ) ;
2107
+ m. remove ( & 2 ) ;
2108
+ m. shrink_to_fit ( ) ;
2109
+ assert_eq ! ( m. capacity( ) , 0 ) ;
2110
+
2111
+ let mut m = HM :: new ( ) ;
2112
+ m. reserve ( 0 ) ;
2113
+ assert_eq ! ( m. capacity( ) , 0 ) ;
2106
2114
}
2107
2115
2108
2116
#[ test]
@@ -2562,8 +2570,8 @@ mod test_map {
2562
2570
assert ! ( m. is_empty( ) ) ;
2563
2571
2564
2572
let mut i = 0 ;
2565
- let old_cap = m. table . capacity ( ) ;
2566
- while old_cap == m. table . capacity ( ) {
2573
+ let old_raw_cap = m. raw_capacity ( ) ;
2574
+ while old_raw_cap == m. raw_capacity ( ) {
2567
2575
m. insert ( i, i) ;
2568
2576
i += 1 ;
2569
2577
}
@@ -2577,55 +2585,55 @@ mod test_map {
2577
2585
let mut m = HashMap :: new ( ) ;
2578
2586
2579
2587
assert_eq ! ( m. len( ) , 0 ) ;
2580
- assert_eq ! ( m. table . capacity ( ) , 0 ) ;
2588
+ assert_eq ! ( m. raw_capacity ( ) , 0 ) ;
2581
2589
assert ! ( m. is_empty( ) ) ;
2582
2590
2583
2591
m. insert ( 0 , 0 ) ;
2584
2592
m. remove ( & 0 ) ;
2585
2593
assert ! ( m. is_empty( ) ) ;
2586
- let initial_cap = m. table . capacity ( ) ;
2587
- m. reserve ( initial_cap ) ;
2588
- let cap = m. table . capacity ( ) ;
2594
+ let initial_raw_cap = m. raw_capacity ( ) ;
2595
+ m. reserve ( initial_raw_cap ) ;
2596
+ let raw_cap = m. raw_capacity ( ) ;
2589
2597
2590
- assert_eq ! ( cap , initial_cap * 2 ) ;
2598
+ assert_eq ! ( raw_cap , initial_raw_cap * 2 ) ;
2591
2599
2592
2600
let mut i = 0 ;
2593
- for _ in 0 ..cap * 3 / 4 {
2601
+ for _ in 0 ..raw_cap * 3 / 4 {
2594
2602
m. insert ( i, i) ;
2595
2603
i += 1 ;
2596
2604
}
2597
2605
// three quarters full
2598
2606
2599
2607
assert_eq ! ( m. len( ) , i) ;
2600
- assert_eq ! ( m. table . capacity ( ) , cap ) ;
2608
+ assert_eq ! ( m. raw_capacity ( ) , raw_cap ) ;
2601
2609
2602
- for _ in 0 ..cap / 4 {
2610
+ for _ in 0 ..raw_cap / 4 {
2603
2611
m. insert ( i, i) ;
2604
2612
i += 1 ;
2605
2613
}
2606
2614
// half full
2607
2615
2608
- let new_cap = m. table . capacity ( ) ;
2609
- assert_eq ! ( new_cap , cap * 2 ) ;
2616
+ let new_raw_cap = m. raw_capacity ( ) ;
2617
+ assert_eq ! ( new_raw_cap , raw_cap * 2 ) ;
2610
2618
2611
- for _ in 0 ..cap / 2 - 1 {
2619
+ for _ in 0 ..raw_cap / 2 - 1 {
2612
2620
i -= 1 ;
2613
2621
m. remove ( & i) ;
2614
- assert_eq ! ( m. table . capacity ( ) , new_cap ) ;
2622
+ assert_eq ! ( m. raw_capacity ( ) , new_raw_cap ) ;
2615
2623
}
2616
2624
// A little more than one quarter full.
2617
2625
m. shrink_to_fit ( ) ;
2618
- assert_eq ! ( m. table . capacity ( ) , cap ) ;
2626
+ assert_eq ! ( m. raw_capacity ( ) , raw_cap ) ;
2619
2627
// again, a little more than half full
2620
- for _ in 0 ..cap / 2 - 1 {
2628
+ for _ in 0 ..raw_cap / 2 - 1 {
2621
2629
i -= 1 ;
2622
2630
m. remove ( & i) ;
2623
2631
}
2624
2632
m. shrink_to_fit ( ) ;
2625
2633
2626
2634
assert_eq ! ( m. len( ) , i) ;
2627
2635
assert ! ( !m. is_empty( ) ) ;
2628
- assert_eq ! ( m. table . capacity ( ) , initial_cap ) ;
2636
+ assert_eq ! ( m. raw_capacity ( ) , initial_raw_cap ) ;
2629
2637
}
2630
2638
2631
2639
#[ test]
0 commit comments