hash map (-> 0.18)
This commit is contained in:
45
src/main/kotlin/blitz/collections/BlitzHashMap.kt
Normal file
45
src/main/kotlin/blitz/collections/BlitzHashMap.kt
Normal file
@@ -0,0 +1,45 @@
|
||||
package blitz.collections
|
||||
|
||||
class BlitzHashMap<K, V>(
|
||||
private val bucketCount: Int = 16,
|
||||
private val bucketSrc: DynBuckets<K, V>,
|
||||
private val hash: (K) -> Int,
|
||||
): BlitzMap<K, V, BlitzHashMap.Index<K, V>> {
|
||||
private val buckets = Array(bucketCount) { bucketSrc.new() }
|
||||
|
||||
override fun index(key: K): Index<K,V> =
|
||||
IndexImpl(buckets[hash(key) % bucketCount], key)
|
||||
|
||||
private inline fun index(idx: Index<K,V>) =
|
||||
idx as IndexImpl
|
||||
|
||||
override operator fun get(idx: Index<K,V>): V? =
|
||||
index(idx).let { idx ->
|
||||
bucketSrc.get(idx.bucket, idx.key)
|
||||
}
|
||||
|
||||
override operator fun set(idx: Index<K,V>, value: V?) {
|
||||
index(idx).let { idx ->
|
||||
if (value == null) {
|
||||
bucketSrc.remove(idx.bucket, idx.key)
|
||||
} else {
|
||||
bucketSrc.set(idx.bucket, idx.key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface Index<K,V>
|
||||
|
||||
private class IndexImpl<K,V>(
|
||||
val bucket: Any?,
|
||||
val key: K,
|
||||
): Index<K,V>
|
||||
|
||||
override val contents: Contents<Pair<K, V>>
|
||||
get() = buckets
|
||||
.map { bucketSrc.contents(it) }
|
||||
.reduce { acc, pairs -> acc + pairs }
|
||||
|
||||
val bucketStats
|
||||
get() = Contents(buckets.map { bucketSrc.contents(it).count() })
|
||||
}
|
11
src/main/kotlin/blitz/collections/BlitzMap.kt
Normal file
11
src/main/kotlin/blitz/collections/BlitzMap.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package blitz.collections
|
||||
|
||||
interface BlitzMap<K,V,I> {
|
||||
fun index(key: K): I
|
||||
operator fun get(index: I): V?
|
||||
operator fun set(index: I, value: V?)
|
||||
val contents: Contents<Pair<K,V>>
|
||||
}
|
||||
|
||||
fun <K,V,I> BlitzMap<K,V,I>.remove(index: I) =
|
||||
set(index, null)
|
75
src/main/kotlin/blitz/collections/Buckets.kt
Normal file
75
src/main/kotlin/blitz/collections/Buckets.kt
Normal file
@@ -0,0 +1,75 @@
|
||||
package blitz.collections
|
||||
|
||||
interface Buckets<K, V, B> {
|
||||
fun new(): B
|
||||
fun get(bucket: B, key: K): V?
|
||||
fun set(bucket: B, key: K, value: V)
|
||||
fun remove(bucket: B, key: K)
|
||||
fun contents(bucket: B): Contents<Pair<K,V>>
|
||||
}
|
||||
|
||||
class DynBucketsT<K, V, B>(
|
||||
private val parent: Buckets<K, V, B>
|
||||
): Buckets<K, V, Any?> {
|
||||
override fun new(): Any? =
|
||||
parent.new()
|
||||
|
||||
override fun contents(bucket: Any?): Contents<Pair<K, V>> =
|
||||
parent.contents(bucket as B)
|
||||
|
||||
override fun remove(bucket: Any?, key: K) =
|
||||
parent.remove(bucket as B, key)
|
||||
|
||||
override fun set(bucket: Any?, key: K, value: V) =
|
||||
parent.set(bucket as B, key, value)
|
||||
|
||||
override fun get(bucket: Any?, key: K): V? =
|
||||
parent.get(bucket as B, key)
|
||||
}
|
||||
|
||||
typealias DynBuckets<K,V> = DynBucketsT<K,V,*>
|
||||
|
||||
class ListBuckets<K, V>(
|
||||
private val eq: (K, K) -> Boolean = { a, b -> a == b },
|
||||
private val construct: () -> MutableList<ListBuckets.Entry<K, V>>
|
||||
): Buckets<K, V, MutableList<ListBuckets.Entry<K, V>>> {
|
||||
class Entry<K, V>(val key: K, var value: V): Comparable<ListBuckets.Entry<K, V>> {
|
||||
override fun compareTo(other: ListBuckets.Entry<K, V>): Int =
|
||||
(key as? Comparable<K>)?.compareTo(other.key) ?: 0
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
key == other
|
||||
}
|
||||
|
||||
private fun entry(bucket: MutableList<Entry<K, V>>, key: K) =
|
||||
bucket.firstOrNull { eq(it.key, key) }
|
||||
|
||||
override fun get(bucket: MutableList<Entry<K, V>>, key: K): V? =
|
||||
entry(bucket, key)?.value
|
||||
|
||||
override fun set(bucket: MutableList<Entry<K, V>>, key: K, value: V) {
|
||||
val entry = entry(bucket, key)
|
||||
if (entry != null) {
|
||||
entry.value = value
|
||||
} else {
|
||||
bucket.add(Entry(key, value))
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(bucket: MutableList<Entry<K, V>>, key: K) {
|
||||
entry(bucket, key)?.let(bucket::remove)
|
||||
}
|
||||
|
||||
override fun new(): MutableList<Entry<K, V>> =
|
||||
construct()
|
||||
|
||||
override fun contents(bucket: MutableList<Entry<K, V>>): Contents<Pair<K, V>> =
|
||||
bucket.map { it.key to it.value }.contents
|
||||
}
|
||||
|
||||
fun <K: Comparable<K>, V> SortedListBuckets(
|
||||
underlying: () -> MutableList<ListBuckets.Entry<K, V>>,
|
||||
eq: (K, K) -> Boolean = { a, b -> a == b },
|
||||
) = ListBuckets(eq) {
|
||||
SortedList(underlying()) { it }
|
||||
}
|
@@ -3,6 +3,13 @@ package blitz.collections
|
||||
class Contents<T> internal constructor(
|
||||
private val iterable: Iterable<T>
|
||||
): Iterable<T> {
|
||||
operator fun plus(other: Contents<T>): Contents<T> {
|
||||
val li = mutableListOf<T>()
|
||||
li.addAll(this)
|
||||
li.addAll(other)
|
||||
return li.contents
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<T> =
|
||||
iterable.iterator()
|
||||
|
||||
|
28
src/main/kotlin/blitz/collections/I2HashMap.kt
Normal file
28
src/main/kotlin/blitz/collections/I2HashMap.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
package blitz.collections
|
||||
|
||||
import blitz.math.cantor
|
||||
|
||||
class I2HashMapKey(
|
||||
val a: Int,
|
||||
val b: Int
|
||||
): Comparable<I2HashMapKey> {
|
||||
val cantorHash = cantor(a, b)
|
||||
override fun toString() =
|
||||
"($a, $b)"
|
||||
override fun hashCode(): Int =
|
||||
cantorHash
|
||||
override fun equals(other: Any?) =
|
||||
other is I2HashMapKey && other.a == a && other.b == b
|
||||
override fun compareTo(other: I2HashMapKey): Int =
|
||||
cantorHash.compareTo(other.cantorHash)
|
||||
}
|
||||
|
||||
fun <V> I2HashMap(
|
||||
underlying: () -> MutableList<ListBuckets.Entry<I2HashMapKey, V>>,
|
||||
bucketCount: Int = 16,
|
||||
): BlitzHashMap<I2HashMapKey, V> =
|
||||
BlitzHashMap(
|
||||
bucketCount,
|
||||
DynBuckets(SortedListBuckets(underlying)),
|
||||
I2HashMapKey::cantorHash
|
||||
)
|
29
src/main/kotlin/blitz/collections/I3HashMap.kt
Normal file
29
src/main/kotlin/blitz/collections/I3HashMap.kt
Normal file
@@ -0,0 +1,29 @@
|
||||
package blitz.collections
|
||||
|
||||
import blitz.math.cantor
|
||||
|
||||
class I3HashMapKey(
|
||||
val a: Int,
|
||||
val b: Int,
|
||||
val c: Int,
|
||||
): Comparable<I3HashMapKey> {
|
||||
val cantorHash = cantor(a, cantor(b, c))
|
||||
override fun toString() =
|
||||
"($a, $b, $c)"
|
||||
override fun hashCode(): Int =
|
||||
cantorHash
|
||||
override fun equals(other: Any?) =
|
||||
other is I3HashMapKey && other.a == a && other.b == b && other.c == c
|
||||
override fun compareTo(other: I3HashMapKey): Int =
|
||||
cantorHash.compareTo(other.cantorHash)
|
||||
}
|
||||
|
||||
fun <V> I3HashMap(
|
||||
underlying: () -> MutableList<ListBuckets.Entry<I3HashMapKey, V>>,
|
||||
bucketCount: Int = 16,
|
||||
): BlitzHashMap<I3HashMapKey, V> =
|
||||
BlitzHashMap(
|
||||
bucketCount,
|
||||
DynBuckets(SortedListBuckets(underlying)),
|
||||
I3HashMapKey::cantorHash
|
||||
)
|
4
src/main/kotlin/blitz/math/Cantor.kt
Normal file
4
src/main/kotlin/blitz/math/Cantor.kt
Normal file
@@ -0,0 +1,4 @@
|
||||
package blitz.math
|
||||
|
||||
fun cantor(a: Int, b: Int) =
|
||||
(a + b + 1) * (a + b) / 2 + b
|
Reference in New Issue
Block a user