All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dotty.tools.dotc.util.EqHashSet.scala Maven / Gradle / Ivy

package dotty.tools.dotc.util

import dotty.tools.uncheckedNN

object EqHashSet:

  def from[T](xs: IterableOnce[T]): EqHashSet[T] =
    val set = new EqHashSet[T]()
    set ++= xs
    set

/** A hash set that allows some privileged protected access to its internals
 *  @param  initialCapacity  Indicates the initial number of slots in the hash table.
 *                           The actual number of slots is always a power of 2, so the
 *                           initial size of the table will be the smallest power of two
 *                           that is equal or greater than the given `initialCapacity`.
 *                           Minimum value is 4.
 *  @param  capacityMultiple The minimum multiple of capacity relative to used elements.
 *                           The hash table will be re-sized once the number of elements
 *                           multiplied by capacityMultiple exceeds the current size of the hash table.
 *                           However, a table of size up to DenseLimit will be re-sized only
 *                           once the number of elements reaches the table's size.
 */
class EqHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int = 2) extends GenericHashSet[T](initialCapacity, capacityMultiple) {
  import GenericHashSet.DenseLimit

  /** System's identity hashcode left shifted by 1 */
  final def hash(key: T): Int =
    System.identityHashCode(key) << 1

  /** reference equality */
  final def isEqual(x: T, y: T): Boolean = x.asInstanceOf[AnyRef] eq y.asInstanceOf[AnyRef]

  /** Turn hashcode `x` into a table index */
  private def index(x: Int): Int = x & (table.length - 1)

  private def firstIndex(x: T) = if isDense then 0 else index(hash(x))
  private def nextIndex(idx: Int) =
    Stats.record(statsItem("miss"))
    index(idx + 1)

  private def entryAt(idx: Int): T | Null = table(idx).asInstanceOf[T | Null]
  private def setEntry(idx: Int, x: T) = table(idx) = x.asInstanceOf[AnyRef | Null]

  override def lookup(x: T): T | Null =
    Stats.record(statsItem("lookup"))
    var idx = firstIndex(x)
    var e: T | Null = entryAt(idx)
    while e != null do
      if isEqual(e.uncheckedNN, x) then return e
      idx = nextIndex(idx)
      e = entryAt(idx)
    null

  /** Add entry at `x` at index `idx` */
  private def addEntryAt(idx: Int, x: T): T =
    Stats.record(statsItem("addEntryAt"))
    setEntry(idx, x)
    used += 1
    if used > limit then growTable()
    x

  /** attempts to put `x` in the Set, if it was not entered before, return true, else return false. */
  override def add(x: T): Boolean =
    Stats.record(statsItem("enter"))
    var idx = firstIndex(x)
    var e: T | Null = entryAt(idx)
    while e != null do
      if isEqual(e.uncheckedNN, x) then return false // already entered
      idx = nextIndex(idx)
      e = entryAt(idx)
    addEntryAt(idx, x)
    true // first entry

  override def put(x: T): T =
    Stats.record(statsItem("put"))
    var idx = firstIndex(x)
    var e: T | Null = entryAt(idx)
    while e != null do
      // TODO: remove uncheckedNN when explicit-nulls is enabled for regule compiling
      if isEqual(e.uncheckedNN, x) then return e.uncheckedNN
      idx = nextIndex(idx)
      e = entryAt(idx)
    addEntryAt(idx, x)

  override def +=(x: T): Unit = put(x)

  private def addOld(x: T) =
    Stats.record(statsItem("re-enter"))
    var idx = firstIndex(x)
    var e = entryAt(idx)
    while e != null do
      idx = nextIndex(idx)
      e = entryAt(idx)
    setEntry(idx, x)

  override def copyFrom(oldTable: Array[AnyRef | Null]): Unit =
    if isDense then
      Array.copy(oldTable, 0, table, 0, oldTable.length)
    else
      var idx = 0
      while idx < oldTable.length do
        val e: T | Null = oldTable(idx).asInstanceOf[T | Null]
        if e != null then addOld(e.uncheckedNN)
        idx += 1
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy