hash map (-> 0.18)
This commit is contained in:
@@ -5,7 +5,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "me.alex_s168"
|
group = "me.alex_s168"
|
||||||
version = "0.17"
|
version = "0.18"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
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(
|
class Contents<T> internal constructor(
|
||||||
private val iterable: Iterable<T>
|
private val iterable: Iterable<T>
|
||||||
): 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> =
|
override fun iterator(): Iterator<T> =
|
||||||
iterable.iterator()
|
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
|
16
src/test/kotlin/map.kt
Normal file
16
src/test/kotlin/map.kt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import blitz.collections.I2HashMap
|
||||||
|
import blitz.collections.I2HashMapKey
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
class Maps {
|
||||||
|
@Test
|
||||||
|
fun i2hashmap() {
|
||||||
|
val a = I2HashMap<String>(::mutableListOf)
|
||||||
|
a[a.index(I2HashMapKey(1, 2390))] = "hi"
|
||||||
|
a[a.index(I2HashMapKey(320, 23))] = "bye"
|
||||||
|
a[a.index(I2HashMapKey(320, 25))] = "bye2"
|
||||||
|
a[a.index(I2HashMapKey(32, 344))] = "bye3"
|
||||||
|
println(a.contents)
|
||||||
|
println(a.bucketStats)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user