1
1
package dotty .tools .dotc .util
2
2
3
3
object HashTable :
4
- inline val MaxDense = 8
4
+ /** The number of elements up to which dense packing is used.
5
+ * If the number of elements reaches `DenseLimit` a hash table is used instead
6
+ */
7
+ inline val DenseLimit = 8
5
8
6
9
/** A hash table using open hashing with linear scan which is also very space efficient
7
10
* at small sizes.
@@ -10,31 +13,28 @@ object HashTable:
10
13
* initial size of the table will be the smallest power of two
11
14
* that is equal or greater than the given `initialCapacity`.
12
15
* Minimum value is 4.
13
- * @param loadFactor The maximum fraction of used elements relative to capacity .
14
- * The hash table will be re-sized once the number of elements exceeds
15
- * the current size of the hash table multiplied by loadFactor .
16
- * However, a table of size up to MaxDense will be re-sized to only
16
+ * @param capacityMultiple The minimum multiple of capacity relative to used elements .
17
+ * The hash table will be re-sized once the number of elements
18
+ * multiplied by capacityMultiple exceeds the current size of the hash table.
19
+ * However, a table of size up to DenseLimit will be re-sized only
17
20
* once the number of elements reaches the table's size.
18
21
*/
19
22
class HashTable [Key >: Null <: AnyRef , Value >: Null <: AnyRef ]
20
- (initialCapacity : Int = 8 : Int , loadFactor : Float = 0.33f ):
21
- import HashTable .MaxDense
23
+ (initialCapacity : Int = 8 , capacityMultiple : Int = 3 ):
24
+ import HashTable .DenseLimit
25
+
22
26
private var used : Int = _
23
27
private var limit : Int = _
24
28
private var table : Array [AnyRef ] = _
25
29
clear()
26
30
27
31
private def allocate (capacity : Int ) =
28
32
table = new Array [AnyRef ](capacity * 2 )
29
- limit = if capacity <= MaxDense then capacity - 1 else ( capacity * loadFactor).toInt
33
+ limit = if capacity <= DenseLimit then capacity - 1 else capacity / capacityMultiple
30
34
31
35
private def roundToPower (n : Int ) =
32
36
if Integer .bitCount(n) == 1 then n
33
- else
34
- def recur (n : Int ): Int =
35
- if n == 1 then 2
36
- else recur(n >>> 1 ) << 1
37
- recur(n)
37
+ else 1 << (32 - Integer .numberOfLeadingZeros(n))
38
38
39
39
/** Remove all elements from this table and set back to initial configuration */
40
40
def clear (): Unit =
@@ -44,7 +44,7 @@ class HashTable[Key >: Null <: AnyRef, Value >: Null <: AnyRef]
44
44
/** The number of elements in the set */
45
45
def size : Int = used
46
46
47
- private def isDense = limit < MaxDense
47
+ private def isDense = limit < DenseLimit
48
48
49
49
/** Hashcode, by default `System.identityHashCode`, but can be overriden */
50
50
protected def hash (x : Key ): Int = System .identityHashCode(x)
@@ -119,7 +119,10 @@ class HashTable[Key >: Null <: AnyRef, Value >: Null <: AnyRef]
119
119
120
120
private def growTable (): Unit =
121
121
val oldTable = table
122
- allocate(table.length)
122
+ val newLength =
123
+ if oldTable.length == DenseLimit then DenseLimit * 2 * roundToPower(capacityMultiple)
124
+ else table.length
125
+ allocate(newLength)
123
126
if isDense then
124
127
Array .copy(oldTable, 0 , table, 0 , oldTable.length)
125
128
else
0 commit comments