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

org.hammerlab.math.VarNum.scala Maven / Gradle / Ivy

The newest version!
package org.hammerlab.math

import java.io.{ InputStream, OutputStream }

/**
 * Serialization wrapper for [[Long]]s which burns one bit per byte indicating whether any more bytes follow.
 *
 * Can utilize less serialized space than naively writing 8-byte [[Long]]s in datasets where absolute values tend to be
 * less than 2^48 more often than they are ≥ 2^55.
 *
 * [[Long]]'s absolute values correspond to the following number of serialized bytes:
 *
 *   [   0,  2^6): 1 byte
 *   [ 2^6, 2^13): 2 bytes
 *   [2^13, 2^20): 3 bytes
 *   [2^20, 2^27): 4 bytes
 *   [2^27, 2^34): 5 bytes
 *   [2^34, 2^41): 6 bytes
 *   [2^41, 2^48): 7 bytes
 *   [2^48, 2^55): 8 bytes
 *   [2^55, 2^63): 9 bytes
 *
 * The first byte, in addition to its most significant bit indicating whether any more bites follow, uses its
 * second-most-significant bit to represent the sign of the [[Long]].
 */
object VarNum {
  def write(output: OutputStream, l: Long): Unit = {
    var n = l
    var more = true
    var total = 0
    while (more) {
      if (total == 56) {
        output.write(n.toByte)
        more = false
      } else {
        val b =
          if (total == 0) {
            val byte =
              if (n < 0) {
                n = -n
                (n & 0x3F).toByte | 0x40
              } else {
                (n & 0x3F).toByte
              }

            n = n >> 6
            byte
          } else {
            val byte = (n & 0x7F).toByte
            n = n >> 7
            byte
          }

        total += 7
        more = n > 0
        output.write(b | (if (more) 0x80 else 0).toByte)
      }
    }
  }

  def read(input: InputStream): Long = {
    var l = 0L
    var bits = 0
    val readBytes = Array[Byte](0)
    var negate = false
    while (bits < 63) {
      input.read(readBytes)
      val b = readBytes(0)
      if (bits == 55) {
        l += ((b & 0xffL) << bits)
        bits += 8
      } else {
        if (bits == 0) {
          negate = (b & 0x40) > 0
          l += (b & 0x3FL)
          bits += 6
        } else {
          l += (b & 0x7FL) << bits
          bits += 7
        }

        if ((b & 0x80) == 0) {
          bits = 63
        }
      }
    }
    if (negate)
      -l
    else
      l
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy