Skip to content

Synchronize WeakHashSet with scalac #5594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 11, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 20 additions & 25 deletions compiler/src/dotty/tools/dotc/util/WeakHashSet.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/** Taken from the original implementation of WeakHashSet in scala-reflect
*
* @author: Eugene Burmako
*/
package dotty.tools.dotc.util

import java.lang.ref.{WeakReference, ReferenceQueue}
import java.lang.ref.{ReferenceQueue, WeakReference}

import scala.annotation.tailrec
import scala.collection.mutable.{Set => MSet}
import scala.collection.mutable

/**
* A HashSet where the elements are stored weakly. Elements in this set are eligible for GC if no other
Expand All @@ -18,7 +17,7 @@ import scala.collection.mutable.{Set => MSet}
* This set implementation is not in general thread safe without external concurrency control. However it behaves
* properly when GC concurrently collects elements in this set.
*/
final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadFactor: Double) extends Set[A] with Function1[A, Boolean] with MSet[A] {
final class WeakHashSet[A <: AnyRef](initialCapacity: Int, loadFactor: Double) extends mutable.Set[A] {

import WeakHashSet._

Expand Down Expand Up @@ -63,6 +62,8 @@ final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadF

private[this] def computeThreshold: Int = (table.size * loadFactor).ceil.toInt

def get(elem: A): Option[A] = Option(findEntry(elem))

/**
* find the bucket associated with an element's hash code
*/
Expand Down Expand Up @@ -146,8 +147,10 @@ final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadF
tableLoop(0)
}

def contains(elem: A): Boolean = findEntry(elem) ne null

// from scala.reflect.internal.Set, find an element or null if it isn't contained
override def findEntry(elem: A): A = elem match {
def findEntry(elem: A): A = elem match {
case null => throw new NullPointerException("WeakHashSet cannot hold nulls")
case _ => {
removeStaleEntries()
Expand Down Expand Up @@ -198,15 +201,15 @@ final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadF
}

// add an element to this set unless it's already in there and return this set
override def +(elem: A): this.type = elem match {
override def += (elem: A): this.type = elem match {
case null => throw new NullPointerException("WeakHashSet cannot hold nulls")
case _ => {
removeStaleEntries()
val hash = elem.hashCode
val bucket = bucketFor(hash)
val oldHead = table(bucket)

def add() = {
def add(): Unit = {
table(bucket) = new Entry(elem, hash, oldHead, queue)
count += 1
if (count > threshold) resize()
Expand All @@ -224,13 +227,8 @@ final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadF
}
}

def +=(elem: A): this.type = this + elem

// from scala.reflect.internal.Set
override def addEntry(x: A): Unit = { this += x }

// remove an element from this set and return this set
override def -(elem: A): this.type = elem match {
override def -= (elem: A): this.type = elem match {
case null => this
case _ => {
removeStaleEntries()
Expand All @@ -250,8 +248,6 @@ final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadF
}
}

def -=(elem: A): this.type = this - elem

// empty this set
override def clear(): Unit = {
table = new Array[Entry[A]](table.size)
Expand All @@ -272,8 +268,7 @@ final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadF
count
}

override def apply(x: A): Boolean = this contains x

override def isEmpty: Boolean = size == 0
override def foreach[U](f: A => U): Unit = iterator foreach f

// It has the `()` because iterator runs `removeStaleEntries()`
Expand All @@ -283,7 +278,7 @@ final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadF
override def iterator: Iterator[A] = {
removeStaleEntries()

new Iterator[A] {
new collection.AbstractIterator[A] {

/**
* the bucket currently being examined. Initially it's set past the last bucket and will be decremented
Expand Down Expand Up @@ -342,7 +337,7 @@ final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadF
* the entries must be stable. If any are garbage collected during validation
* then an assertion may inappropriately fire.
*/
def fullyValidate: Unit = {
def fullyValidate(): Unit = {
var computedCount = 0
var bucket = 0
while (bucket < table.size) {
Expand All @@ -368,7 +363,7 @@ final class WeakHashSet[A >: Null <: AnyRef](val initialCapacity: Int, val loadF
/**
* Produces a diagnostic dump of the table that underlies this hash set.
*/
def dump: IndexedSeq[Any] = table.deep
def dump: String = java.util.Arrays.toString(table.asInstanceOf[Array[AnyRef]])

/**
* Number of buckets that hold collisions. Useful for diagnosing performance issues.
Expand Down Expand Up @@ -401,9 +396,9 @@ object WeakHashSet {
*/
private class Entry[A](element: A, val hash:Int, var tail: Entry[A], queue: ReferenceQueue[A]) extends WeakReference[A](element, queue)

val defaultInitialCapacity: Int = 16
val defaultLoadFactor: Double = .75
private final val defaultInitialCapacity = 16
private final val defaultLoadFactor = .75

def apply[A >: Null <: AnyRef](initialCapacity: Int = WeakHashSet.defaultInitialCapacity, loadFactor: Double = WeakHashSet.defaultLoadFactor): WeakHashSet[A] =
new WeakHashSet[A](initialCapacity, defaultLoadFactor)
def apply[A <: AnyRef](initialCapacity: Int = defaultInitialCapacity, loadFactor: Double = defaultLoadFactor): WeakHashSet[A] =
new WeakHashSet(initialCapacity, loadFactor)
}