
scala.reactive.container.ReactHashValMap.scala Maven / Gradle / Ivy
The newest version!
package scala.reactive
package container
import scala.reflect.ClassTag
class ReactHashValMap[@spec(Int, Long, Double) K, @spec(Int, Long, Double) V](
implicit val emptyKey: Arrayable[K],
implicit val emptyVal: Arrayable[V]
) extends ReactContainer[(K, V)] with ReactBuilder[(K, V), ReactHashValMap[K, V]] with ValPairBuilder[K, V, ReactHashValMap[K, V]] {
private var keytable: Array[K] = null
private var valtable: Array[V] = null
private var sz = 0
private[reactive] var insertsEmitter: Reactive.Emitter[(K, V)] = null
private[reactive] var removesEmitter: Reactive.Emitter[(K, V)] = null
protected def init(ek: Arrayable[K], ev: Arrayable[V]) {
keytable = emptyKey.newArray(ReactHashValMap.initSize)
valtable = emptyVal.newArray(ReactHashValMap.initSize)
insertsEmitter = new Reactive.Emitter[(K, V)]
removesEmitter = new Reactive.Emitter[(K, V)]
}
init(emptyKey, emptyVal)
def inserts: Reactive[(K, V)] = insertsEmitter
def removes: Reactive[(K, V)] = removesEmitter
def builder: ReactBuilder[(K, V), ReactHashValMap[K, V]] = this
def +=(kv: (K, V)) = {
insertPair(kv._1, kv._2)
}
def -=(kv: (K, V)) = {
removePair(kv._1, kv._2)
}
def insertPair(k: K, v: V) = {
insert(k, v)
true
}
def removePair(k: K, v: V) = {
delete(k, v) != emptyVal.nil
}
def container = this
val react = new ReactHashValMap.Lifted[K, V](this)
def foreachPair(f: (K, V) => Unit) {
var i = 0
while (i < keytable.length) {
val k = keytable(i)
if (k != emptyKey.nil) {
val v = valtable(i)
f(k, v)
}
i += 1
}
}
def foreach(f: ((K, V)) => Unit) {
foreachPair { (k, v) =>
f((k, v))
}
}
private def lookup(k: K): V = {
var pos = index(k)
val nil = emptyKey.nil
var curr = keytable(pos)
while (curr != nil && curr != k) {
pos = (pos + 1) % keytable.length
curr = keytable(pos)
}
if (curr == nil) emptyVal.nil
else valtable(pos)
}
private def insert(k: K, v: V, notify: Boolean = true): V = {
checkResize()
var pos = index(k)
val nil = emptyKey.nil
var curr = keytable(pos)
assert(k != nil)
while (curr != nil && curr != k) {
pos = (pos + 1) % keytable.length
curr = keytable(pos)
}
val previousValue = valtable(pos)
keytable(pos) = k
valtable(pos) = v
val keyAdded = curr == nil
if (keyAdded) sz += 1
else if (notify && removesEmitter.hasSubscriptions) removesEmitter += (k, previousValue)
if (notify && insertsEmitter.hasSubscriptions) insertsEmitter += (k, v)
previousValue
}
private def delete(k: K, expectedValue: V = emptyVal.nil): V = {
var pos = index(k)
val nil = emptyKey.nil
var curr = keytable(pos)
while (curr != nil && curr != k) {
pos = (pos + 1) % keytable.length
curr = keytable(pos)
}
if (curr == nil) emptyVal.nil
else if (expectedValue == emptyVal.nil || expectedValue == curr) {
val previousValue = valtable(pos)
var h0 = pos
var h1 = (h0 + 1) % keytable.length
while (keytable(h1) != nil) {
val h2 = index(keytable(h1))
if (h2 != h1 && before(h2, h0)) {
keytable(h0) = keytable(h1)
valtable(h0) = valtable(h1)
h0 = h1
}
h1 = (h1 + 1) % keytable.length
}
keytable(h0) = emptyKey.nil
valtable(h0) = emptyVal.nil
sz -= 1
if (removesEmitter.hasSubscriptions) removesEmitter += (k, previousValue)
previousValue
} else emptyVal.nil
}
private def checkResize() {
if (sz * 1000 / ReactHashValMap.loadFactor > keytable.length) {
val okeytable = keytable
val ovaltable = valtable
val ncapacity = keytable.length * 2
keytable = emptyKey.newArray(ncapacity)
valtable = emptyVal.newArray(ncapacity)
sz = 0
var pos = 0
val nil = emptyKey.nil
while (pos < okeytable.length) {
val curr = okeytable(pos)
if (curr != nil) {
insert(curr, ovaltable(pos), false)
}
pos += 1
}
}
}
private def before(i: Int, j: Int) = {
val d = keytable.length >> 1
if (i <= j) j - i < d
else i - j > d
}
private def index(k: K): Int = {
val hc = k.##
math.abs(scala.util.hashing.byteswap32(hc)) % keytable.length
}
def apply(key: K): V = lookup(key) match {
case `emptyVal`.nil => throw new NoSuchElementException("key: " + key)
case v => v
}
def applyOrElse(key: K, otherValue: V): V = lookup(key) match {
case `emptyVal`.nil => otherValue
case v => v
}
def applyOrNil(key: K): V = lookup(key)
def get(key: K): Option[V] = lookup(key) match {
case `emptyVal`.nil => None
case v => Some(v)
}
def contains(key: K): Boolean = lookup(key) match {
case `emptyVal`.nil => false
case v => true
}
def update(key: K, value: V): Unit = insert(key, value)
def remove(key: K): Boolean = delete(key) match {
case `emptyVal`.nil => false
case v => true
}
def clear() {
var pos = 0
val nil = emptyKey.nil
while (pos < keytable.length) {
if (keytable(pos) != nil) {
val k = keytable(pos)
val v = valtable(pos)
keytable(pos) = emptyKey.nil
valtable(pos) = emptyVal.nil
sz -= 1
if (removesEmitter.hasSubscriptions) removesEmitter += ((k, v))
}
pos += 1
}
}
def size: Int = sz
}
object ReactHashValMap {
def apply[@spec(Int, Long, Double) K: Arrayable, V: Arrayable] = new ReactHashValMap[K, V]
class Lifted[@spec(Int, Long, Double) K, @spec(Int, Long, Double) V](val container: ReactHashValMap[K, V]) extends ReactContainer.Lifted[(K, V)]
val initSize = 16
val loadFactor = 400
implicit def factory[@spec(Int, Long, Double) K: Arrayable, @spec(Int, Long, Double) V: Arrayable] = new ReactBuilder.Factory[(K, V), ReactHashValMap[K, V]] {
def apply() = ReactHashValMap[K, V]
}
implicit def valPairFactory[@spec(Int, Long, Double) K: Arrayable, @spec(Int, Long, Double) V: Arrayable] = new ValPairBuilder.Factory[K, V, ReactHashValMap[K, V]] {
def apply() = ReactHashValMap[K, V]
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy