aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/Hashable.scala
blob: e4510c53e6c16248fcee5f73bbb87315d385de90 (plain) (tree)





























                                                                           
                                                 
 
                                                                  
                                                             
 
                                                                            
 
                                                                    




                                                      
                                                                                




                                                           
                                                                           












                                                 
                                                                                     
























                                                                         
 



                                                             

                                                           
                                             
 



                                             
 
package dotty.tools.dotc
package core

import Types._
import scala.util.hashing.{ MurmurHash3 => hashing }

object Hashable {

  /** A hash value indicating that the underlying type is not
   *  cached in uniques.
   */
  final val NotCached = 0

  /** An alternative value returned from `hash` if the
   *  computed hashCode would be `NotCached`.
   */
  private[core] final val NotCachedAlt = Int.MinValue

  /** A value that indicates that the hash code is unknown
   */
  private[core] final val HashUnknown = 1234

  /** An alternative value if computeHash would otherwise yield HashUnknown
   */
  private[core] final val HashUnknownAlt = 4321
}

trait Hashable {
  import Hashable._

  protected def hashSeed: Int = getClass.hashCode

  protected final def finishHash(hashCode: Int, arity: Int): Int =
    avoidSpecialHashes(hashing.finalizeHash(hashCode, arity))

  final def identityHash = avoidSpecialHashes(System.identityHashCode(this))

  protected def finishHash(seed: Int, arity: Int, tp: Type): Int = {
    val elemHash = tp.hash
    if (elemHash == NotCached) return NotCached
    finishHash(hashing.mix(seed, elemHash), arity + 1)
  }

  protected def finishHash(seed: Int, arity: Int, tp1: Type, tp2: Type): Int = {
    val elemHash = tp1.hash
    if (elemHash == NotCached) return NotCached
    finishHash(hashing.mix(seed, elemHash), arity + 1, tp2)
  }

  protected def finishHash(seed: Int, arity: Int, tps: List[Type]): Int = {
    var h = seed
    var xs = tps
    var len = arity
    while (xs.nonEmpty) {
      val elemHash = xs.head.hash
      if (elemHash == NotCached) return NotCached
      h = hashing.mix(h, elemHash)
      xs = xs.tail
      len += 1
    }
    finishHash(h, len)
  }

  protected def finishHash(seed: Int, arity: Int, tp: Type, tps: List[Type]): Int = {
    val elemHash = tp.hash
    if (elemHash == NotCached) return NotCached
    finishHash(hashing.mix(seed, elemHash), arity + 1, tps)
  }

  protected final def doHash(x: Any): Int =
    finishHash(hashing.mix(hashSeed, x.hashCode), 1)

  protected final def doHash(tp: Type): Int =
    finishHash(hashSeed, 0, tp)

  protected final def doHash(x1: Any, tp2: Type): Int =
    finishHash(hashing.mix(hashSeed, x1.hashCode), 1, tp2)

  protected final def doHash(tp1: Type, tp2: Type): Int =
    finishHash(hashSeed, 0, tp1, tp2)

  protected final def doHash(x1: Any, tp2: Type, tp3: Type): Int =
    finishHash(hashing.mix(hashSeed, x1.hashCode), 1, tp2, tp3)

  protected final def doHash(tp1: Type, tps2: List[Type]): Int =
    finishHash(hashSeed, 0, tp1, tps2)

  protected final def doHash(x1: Any, tp2: Type, tps3: List[Type]): Int =
    finishHash(hashing.mix(hashSeed, x1.hashCode), 1, tp2, tps3)


  protected final def doHash(x1: Int, x2: Int): Int =
    finishHash(hashing.mix(hashing.mix(hashSeed, x1), x2), 1)

  protected final def addDelta(elemHash: Int, delta: Int) =
    if (elemHash == NotCached) NotCached
    else avoidSpecialHashes(elemHash + delta)

  private def avoidSpecialHashes(h: Int) =
    if (h == NotCached) NotCachedAlt
    else if (h == HashUnknown) HashUnknownAlt
    else h
}