11package dotty .tools .dotc .util
22
33object 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
58
69/** A hash table using open hashing with linear scan which is also very space efficient
710 * at small sizes.
@@ -10,31 +13,28 @@ object HashTable:
1013 * initial size of the table will be the smallest power of two
1114 * that is equal or greater than the given `initialCapacity`.
1215 * 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
1720 * once the number of elements reaches the table's size.
1821 */
1922class 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+
2226 private var used : Int = _
2327 private var limit : Int = _
2428 private var table : Array [AnyRef ] = _
2529 clear()
2630
2731 private def allocate (capacity : Int ) =
2832 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
3034
3135 private def roundToPower (n : Int ) =
3236 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))
3838
3939 /** Remove all elements from this table and set back to initial configuration */
4040 def clear (): Unit =
@@ -44,7 +44,7 @@ class HashTable[Key >: Null <: AnyRef, Value >: Null <: AnyRef]
4444 /** The number of elements in the set */
4545 def size : Int = used
4646
47- private def isDense = limit < MaxDense
47+ private def isDense = limit < DenseLimit
4848
4949 /** Hashcode, by default `System.identityHashCode`, but can be overriden */
5050 protected def hash (x : Key ): Int = System .identityHashCode(x)
@@ -119,7 +119,10 @@ class HashTable[Key >: Null <: AnyRef, Value >: Null <: AnyRef]
119119
120120 private def growTable (): Unit =
121121 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)
123126 if isDense then
124127 Array .copy(oldTable, 0 , table, 0 , oldTable.length)
125128 else
0 commit comments