All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.shark.internal.SortedBytesMap.kt Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-8
Show newest version
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