diff --git a/compiler/src/dotty/tools/dotc/util/LinearSet.scala b/compiler/src/dotty/tools/dotc/util/LinearSet.scala index 13db1af8c613..075985029923 100644 --- a/compiler/src/dotty/tools/dotc/util/LinearSet.scala +++ b/compiler/src/dotty/tools/dotc/util/LinearSet.scala @@ -1,7 +1,7 @@ package dotty.tools.dotc.util import collection.immutable -/** A linear set is a set here after a `+` the previous set value cannot be +/** A linear set is a set where after a `+` the previous set value cannot be * used anymore. The set is implemented as an immutable set for sizes <= 4 * and as a HashSet for larger sizes. */ diff --git a/tests/pos-with-compiler/benchSets.scala b/tests/pos-with-compiler/benchSets.scala new file mode 100644 index 000000000000..8619318956f9 --- /dev/null +++ b/tests/pos-with-compiler/benchSets.scala @@ -0,0 +1,192 @@ +type Elem = Object + +def newElem() = new Object() + +val MissFactor = 2 + +val Runs = 100 // number of runs to warm-up, and then number of runs to test +val ItersPerRun = 1000 +val elems = Array.fill(1024 * MissFactor)(newElem()) + +def testJava = + val set = java.util.HashMap[Elem, Elem]() + var count = 0 + var iter = 0 + while iter < ItersPerRun do + var i = 0 + while i < elems.length do + val e = elems(i) + if i % MissFactor == 0 then + set.put(e, e) + i += 1 + while i > 0 do + i -= 1 + val v = set.get(elems(i)) + if v != null then + count += 1 + iter += 1 + count + +def testJavaId = + val set = java.util.IdentityHashMap[Elem, Elem]() + var count = 0 + var iter = 0 + while iter < ItersPerRun do + var i = 0 + while i < elems.length do + val e = elems(i) + if i % MissFactor == 0 then + set.put(e, e) + i += 1 + while i > 0 do + i -= 1 + val v = set.get(elems(i)) + if v != null then + count += 1 + iter += 1 + count + +def testScalaMap = + val set = scala.collection.mutable.HashMap[Elem, Elem]() + var count = 0 + var iter = 0 + while iter < ItersPerRun do + var i = 0 + while i < elems.length do + val e = elems(i) + if i % MissFactor == 0 then + set.update(e, e) + i += 1 + while i > 0 do + i -= 1 + set.get(elems(i)) match + case Some(_) => count += 1 + case None => + iter += 1 + count + +def testAnyRefMap = + val set = scala.collection.mutable.AnyRefMap[Elem, Elem]() + var count = 0 + var iter = 0 + while iter < ItersPerRun do + var i = 0 + while i < elems.length do + val e = elems(i) + if i % MissFactor == 0 then + set.update(e, e) + i += 1 + while i > 0 do + i -= 1 + val v = set.getOrNull(elems(i)) + if v != null then + count += 1 + iter += 1 + count + +def testDottyMap = + val set = dotty.tools.dotc.util.HashMap[Elem, Elem](128) + var count = 0 + var iter = 0 + while iter < ItersPerRun do + var i = 0 + while i < elems.length do + val e = elems(i) + if i % MissFactor == 0 then + set.update(e, e) + i += 1 + while i > 0 do + i -= 1 + val v = set.lookup(elems(i)) + if v != null then + count += 1 + iter += 1 + count + +def testDottySet = + val set = dotty.tools.dotc.util.HashSet[Elem](64) + var count = 0 + var iter = 0 + while iter < ItersPerRun do + var i = 0 + while i < elems.length do + val e = elems(i) + if i % MissFactor == 0 then + set += e + i += 1 + while i > 0 do + i -= 1 + if set.contains(elems(i)) then + count += 1 + iter += 1 + count + +def testScalaSet = + val set = scala.collection.mutable.HashSet[Elem]() + var count = 0 + var iter = 0 + while iter < ItersPerRun do + var i = 0 + while i < elems.length do + val e = elems(i) + if i % MissFactor == 0 then + set += e + i += 1 + while i > 0 do + i -= 1 + if set.contains(elems(i)) then + count += 1 + iter += 1 + count + +def testLinearSet = + var set = dotty.tools.dotc.util.LinearSet.empty[Elem] + var count = 0 + var iter = 0 + while iter < ItersPerRun do + var i = 0 + while i < elems.length do + val e = elems(i) + if i % MissFactor == 0 then + set += e + i += 1 + while i > 0 do + i -= 1 + if set.contains(elems(i)) then + count += 1 + iter += 1 + count + +val expected = (elems.size / MissFactor) * ItersPerRun + +def profile(name: String, op: => Int) = + System.gc() + for i <- 0 until 100 do assert(op == expected) + val start = System.nanoTime() + var count = 0 + for i <- 0 until 100 do count += op + //println(count) + assert(count == expected * Runs) + println(s"$name took ${(System.nanoTime().toDouble - start)/1_000_000} ms") + +@main def Test = + + profile("dotty.tools.dotc.LinearSet", testLinearSet) + profile("dotty.tools.dotc.HashSet ", testDottySet) + profile("dotty.tools.dotc.HashMap ", testDottyMap) + profile("scala.collection.HashSet ", testScalaSet) + profile("scala.collection.AnyRefMap", testAnyRefMap) + profile("scala.collection.HashMap ", testScalaMap) + profile("java.util.IdentityHashMap ", testJavaId) + profile("java.util.HashMap ", testJava) + + profile("java.util.HashMap ", testJava) + profile("java.util.IdentityHashMap ", testJavaId) + profile("scala.collection.HashMap ", testScalaMap) + profile("scala.collection.AnyRefMap", testAnyRefMap) + profile("scala.collection.HashSet ", testScalaSet) + profile("dotty.tools.dotc.HashMap ", testDottyMap) + profile("dotty.tools.dotc.HashSet ", testDottySet) + profile("dotty.tools.dotc.LinearSet", testLinearSet) + + diff --git a/tests/pos/cm/ConfManagement.scala b/tests/pos/cm/ConfManagement.scala deleted file mode 100644 index 276918537c9e..000000000000 --- a/tests/pos/cm/ConfManagement.scala +++ /dev/null @@ -1,25 +0,0 @@ -package cm - -case class Person(name: String) -case class Paper(title: String, authors: List[Person], body: String) - -class Viewers(val persons: Set[Person]) - -class ConfManagement(papers: List[Paper], realScore: Map[Paper, Int]) { - - private def hasConflict(ps1: Set[Person], ps2: Iterable[Person]) = - ps2.exists(ps1 contains _) - - def viewers(implicit vs: Viewers): Set[Person] = - vs.persons - - def score(paper: Paper)(implicit vs: Viewers): Int = - if (hasConflict(viewers, paper.authors)) -100 - else realScore(paper) - - def viewRankings(implicit vs: Viewers): List[Paper] = - papers.sortBy(score(_)) - - def delegateTo[T](query: Viewers => T, p: Person)(implicit vs: Viewers): T = - query(new Viewers(viewers + p)) -} \ No newline at end of file diff --git a/tests/run/ConfManagement.check b/tests/run/ConfManagement.check new file mode 100644 index 000000000000..b40e701f2318 --- /dev/null +++ b/tests/run/ConfManagement.check @@ -0,0 +1,4 @@ +Peters + +Smith +Smith, Peters diff --git a/tests/run/ConfManagement.scala b/tests/run/ConfManagement.scala new file mode 100644 index 000000000000..f73445b5af08 --- /dev/null +++ b/tests/run/ConfManagement.scala @@ -0,0 +1,83 @@ +case class Person(name: String) +case class Paper(title: String, authors: List[Person], body: String) + +object ConfManagement: + opaque type Viewers = Set[Person] + def viewers(using vs: Viewers) = vs + type Viewed[T] = Viewers ?=> T + + class Conference(ratings: (Paper, Int)*): + private val realScore = ratings.toMap + + def papers: List[Paper] = ratings.map(_._1).toList + + def score(paper: Paper): Viewed[Int] = + if viewers.intersect(paper.authors.toSet).nonEmpty then -100 + else realScore(paper) + + def rankings: Viewed[List[Paper]] = + papers.sortBy(score(_)).reverse + + def ask[T](p: Person, query: Viewed[T]) = + query(using Set(p)) + + def delegateTo[T](p: Person, query: Viewed[T]): Viewed[T] = + query(using viewers + p) + end Conference +end ConfManagement + +import ConfManagement._ + +val Smith = Person("Smith") +val Peters = Person("Peters") +val Abel = Person("Abel") +val Black = Person("Black") +val Ed = Person("Ed") + +val conf = Conference( + Paper( + title = "How to grow beans", + authors = List(Smith, Peters), + body = "..." + ) -> 92, + Paper( + title = "Organic gardening", + authors = List(Abel, Peters), + body = "..." + ) -> 83, + Paper( + title = "Composting done right", + authors = List(Black, Smith), + body = "..." + ) -> 99, + Paper( + title = "The secret life of snails", + authors = List(Ed), + body = "..." + ) -> 77 +) + +def highlyRankedProlificAuthors(asking: Person): Set[Person] = + def query: Viewed[Set[Person]] = + val highlyRanked = + conf.rankings.takeWhile(conf.score(_) > 80).toSet + for + p1 <- highlyRanked + p2 <- highlyRanked + author <- p1.authors + if p1 != p2 && p2.authors.contains(author) + yield author + conf.ask(asking, query) + +def testAs(person: Person) = + println( + highlyRankedProlificAuthors(asking = person) + .map(_.name) + .mkString(", ")) + +@main def Test = + testAs(Black) + testAs(Smith) + testAs(Abel) + testAs(Ed) +