main.shark.internal.SortedBytesMap.kt Maven / Gradle / Ivy
package shark.internal
import shark.internal.hppc.LongObjectPair
import shark.internal.hppc.to
/**
* A read only map of `id` => `byte array` sorted by id, where `id` is a long if [longIdentifiers]
* is true and an int otherwise. Each entry has a value byte array of size [bytesPerValue].
*
* Instances are created by [UnsortedByteEntries]
*
* [get] and [contains] perform a binary search to locate a specific entry by key.
*/
internal class SortedBytesMap(
private val longIdentifiers: Boolean,
private val bytesPerValue: Int,
private val sortedEntries: ByteArray
) {
private val bytesPerKey = if (longIdentifiers) 8 else 4
private val bytesPerEntry = bytesPerKey + bytesPerValue
val size = sortedEntries.size / bytesPerEntry
operator fun get(key: Long): ByteSubArray? {
val keyIndex = binarySearch(key)
if (keyIndex < 0) {
return null
}
return getAtIndex(keyIndex)
}
fun indexOf(key: Long): Int {
return binarySearch(key)
}
fun getAtIndex(keyIndex: Int): ByteSubArray {
val valueIndex = keyIndex * bytesPerEntry + bytesPerKey
return ByteSubArray(sortedEntries, valueIndex, bytesPerValue, longIdentifiers)
}
operator fun contains(key: Long): Boolean {
val keyIndex = binarySearch(key)
return keyIndex >= 0
}
fun entrySequence(): Sequence> {
return (0 until size).asSequence()
.map { keyIndex ->
val valueIndex = keyIndex * bytesPerEntry + bytesPerKey
keyAt(keyIndex) to ByteSubArray(sortedEntries, valueIndex, bytesPerValue, longIdentifiers)
}
}
private fun binarySearch(
key: Long
): Int {
val startIndex = 0
val endIndex = size
var lo = startIndex
var hi = endIndex - 1
while (lo <= hi) {
val mid = (lo + hi).ushr(1)
val midVal = keyAt(mid)
when {
midVal < key -> lo = mid + 1
midVal > key -> hi = mid - 1
else -> return mid
}
}
return lo.inv()
}
fun keyAt(index: Int): Long {
val keyIndex = index * bytesPerEntry
return if (longIdentifiers) {
sortedEntries.readLong(keyIndex)
} else {
sortedEntries.readInt(keyIndex).toLong()
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy