|
|
import scala.collection.immutable._
object Test extends dotty.runtime.LegacyApp {
def test1(): Unit = {
// test that a HashTrieMap with one leaf element is not created!
val x = HashMap.empty + (1->1) + (2->2)
if(x.getClass.getSimpleName != "HashTrieMap")
println("A hash map containing two non-colliding values should be a HashTrieMap")
val y = x - 1
if(y.getClass.getSimpleName != "HashMap1")
println("A hash map containing one element should always use HashMap1")
}
def test2(): Unit = {
// class that always causes hash collisions
case class Collision(value:Int) { override def hashCode = 0 }
// create a set that should have a collison
val x = HashMap.empty + (Collision(0)->0) + (Collision(1) ->0)
if(x.getClass.getSimpleName != "HashMapCollision1")
println("HashMap of size >1 with collisions should use HashMapCollision")
// remove the collision again by removing all but one element
val y = x - Collision(0)
if(y.getClass.getSimpleName != "HashMap1")
println("HashMap of size 1 should use HashMap1" + y.getClass)
}
def test3(): Unit = {
// finds an int x such that improved(x) differs in the first bit to improved(0),
// which is the worst case for the HashTrieSet
def findWorstCaseInts(): Unit = {
// copy of improve from HashSet
def improve(hcode: Int) = {
var h: Int = hcode + ~(hcode << 9)
h = h ^ (h >>> 14)
h = h + (h << 4)
h ^ (h >>> 10)
}
// find two hashes which have a large separation
val x = 0
var y = 1
val ix = improve(x)
while(y!=0 && improve(y)!=ix+(1<<31))
y+=1
printf("%s %s %x %x\n",x,y,improve(x), improve(y))
}
// this is not done every test run since it would slow down ant test.suite too much.
// findWorstCaseInts()
// two numbers that are immediately adiacent when fed through HashSet.improve
val h0 = 0
val h1 = 1270889724
// h is the hashcode, i is ignored for the hashcode but relevant for equality
case class Collision(h:Int, i:Int) {
override def hashCode = h
}
val a = Collision(h0,0)->0
val b = Collision(h0,1)->0
val c = Collision(h1,0)->0
// create a HashSetCollision1
val x = HashMap(a) + b
if(x.getClass.getSimpleName != "HashMapCollision1")
println("x should be a HashMapCollision")
StructureTests.validate(x)
//StructureTests.printStructure(x)
require(x.size==2 && x.contains(a._1) && x.contains(b._1))
// go from a HashSetCollision1 to a HashTrieSet with maximum depth
val y = x + c
if(y.getClass.getSimpleName != "HashTrieMap")
println("y should be a HashTrieMap")
StructureTests.validate(y)
// StructureTests.printStructure(y)
require(y.size==3 && y.contains(a._1) && y.contains(b._1) && y.contains(c._1))
// go from a HashSet1 directly to a HashTrieSet with maximum depth
val z = HashMap(a) + c
if(y.getClass.getSimpleName != "HashTrieMap")
println("y should be a HashTrieMap")
StructureTests.validate(z)
// StructureTests.printStructure(z)
require(z.size == 2 && z.contains(a._1) && z.contains(c._1))
}
test1()
test2()
test3()
}
package scala.collection.immutable {
object StructureTests {
def printStructure(x:HashMap[_,_], prefix:String=""): Unit = {
x match {
case m:HashMap.HashTrieMap[_,_] =>
println(prefix+m.getClass.getSimpleName + " " + m.size)
m.elems.foreach(child => printStructure(child, prefix + " "))
case m:HashMap.HashMapCollision1[_,_] =>
println(prefix+m.getClass.getSimpleName + " " + m.kvs.size)
case m:HashMap.HashMap1[_,_] =>
println(prefix+m.getClass.getSimpleName + " " + m.head)
case _ =>
println(prefix+"empty")
}
}
def validate(x:HashMap[_,_]): Unit = {
x match {
case m:HashMap.HashTrieMap[_,_] =>
require(m.elems.size>1 || (m.elems.size==1 && m.elems(0).isInstanceOf[HashMap.HashTrieMap[_,_]]))
m.elems.foreach(validate _)
case m:HashMap.HashMapCollision1[_,_] =>
require(m.kvs.size>1)
case m:HashMap.HashMap1[_,_] =>
case _ =>
}
}
}
}
|