Question

I need to compress/decompress some Data with a old, in house developed Algorithm. There i have a lot of operations like:

if the next bit is 0 take the following 6 Bits and interpret them as an Int
if the next bits are 10 take the following 9 Bits and interpret them as an Int 
etc.

Knows somebody something like a "Bitstrem" class in Scala? (I didn't found anything and hope that i didn't have to implement it by myself.)

Thanks

Edit: I combined the answer with http://www.scala-lang.org/node/8413 ("The Architecture of Scala Collections") If somebody needs the samething:

abstract class Bit
object Bit {
  val fromInt: Int => Bit = Array(Low, High)
  val toInt: Bit => Int = Map(Low -> 0, High -> 1)
}

case object High extends Bit
case object Low extends Bit

import collection.IndexedSeqLike
import collection.mutable.{Builder, ArrayBuffer}
import collection.generic.CanBuildFrom
import collection.IndexedSeq

// IndexedSeqLike implements all concrete methods of IndexedSeq
// with newBuilder. (methods like take, filter, drop)
final class BitSeq private (val bits: Array[Int], val length: Int)
         extends IndexedSeq[Bit]
         with IndexedSeqLike[Bit, BitSeq]
{
  import BitSeq._

  // Mandatory for IndexedSeqLike
  override protected[this] def newBuilder: Builder[Bit, BitSeq] =
    BitSeq.newBuilder

  //Mandatory for IndexedSeq
  def apply(idx: Int): Bit = {
    if(idx < 0 || length <= idx)
      throw new IndexOutOfBoundsException
    Bit.fromInt(bits(idx/N) >> (idx % N) & M)
  }


}

object BitSeq {

  // Bits per Int
  private val N = 32

  // Bitmask to isolate a bit
  private val M = 0x01


  def fromSeq(buf: Seq[Bit]): BitSeq = {
    val bits = new Array[Int]((buf.length + N - 1) / N)
    for(i <- 0 until buf.length) {
      bits(i/N) |= Bit.toInt(buf(i)) << (i % N)
    }
    new BitSeq(bits, buf.length)
  }

  def apply(bits: Bit*) = fromSeq(bits)

  def newBuilder: Builder[Bit, BitSeq] = new ArrayBuffer mapResult fromSeq

  // Needed for map etc. (BitSeq map {:Bit} should return a BitSeq)
  implicit def canBuilderFrom: CanBuildFrom[BitSeq, Bit, BitSeq] =
    new CanBuildFrom[BitSeq, Bit, BitSeq] {
      def apply(): Builder[Bit, BitSeq] = newBuilder
      def apply(from: BitSeq): Builder[Bit, BitSeq] = newBuilder
    }
}
Was it helpful?

Solution

There isn't any existing class that I'm aware of, but you can leverage the existing classes to help out with almost all of the difficult operations. The trick is to turn your data into a stream of Ints (or Bytes if there wouldn't be enough memory). You then can use all the handy collections methods (e.g. take) and only are left with the problem of turning bits into memory. But that's easy if you pack the bits in MSB order.

object BitExample {
  def bitInt(ii: Iterator[Int]): Int = (0 /: ii)((i,b) => (i<<1)|b)
  def bitInt(ii: Iterable[Int]): Int = bitInt(ii.iterator)

  class ArrayBits(bytes: Array[Byte]) extends Iterator[Int] {
    private[this] var buffer = 0
    private[this] var index,shift = -1
    def hasNext = (shift > 0) || (index+1 < bytes.length)
    def next = {
      if (shift <= 0) {
        index += 1
        buffer = bytes(index) & 0xFF
        shift = 7
      }
      else shift -= 1
      (buffer >> shift) & 0x1
    }
  }
}

And then you do things like

import BitExample._
val compressed = new ArrayBits( Array[Byte](14,29,126) ).toStream
val headless = compressed.dropWhile(_ == 0)
val (test,rest) = headless.splitAt(3)
if (bitInt(test) > 4) println(bitInt(rest.take(6)))

(You can decide whether you want to use the iterator directly or as a stream, list, or whatever.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top