2011-01-07 10 views
1

Ich muss einige Daten mit einem alten, im Haus entwickelten Algorithmus komprimieren/dekomprimieren. Dort habe ich viele Operationen wie:Bitstream-Bibliothek in Scala

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. 

Kennt jemand so etwas wie ein „Bitstrem“ Klasse in Scala? (Ich habe nichts gefunden und hoffe, dass ich es nicht selbst implementieren musste.)

Dank

Edit: ich die Antwort mit http://www.scala-lang.org/node/8413 kombiniert („The Architecture of Scala Sammlungen“) If jemand muss die 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 
    } 
} 

Antwort

4

Es gibt keinen bestehenden Klasse, die ich bin mir dessen bewusst, aber Sie können die bestehenden Klassen nutzen, mit fast allen der schwierigen Operationen zu helfen. Der Trick besteht darin, Ihre Daten in einen Strom von Ints umzuwandeln (oder Bytes, wenn nicht genügend Speicher vorhanden wäre). Sie können dann alle handlichen Auflistungsmethoden verwenden (z. B. take) und es bleibt nur das Problem, Bits in Speicher umzuwandeln. Aber das ist einfach, wenn Sie die Bits in MSB-Reihenfolge packen.

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 
    } 
    } 
} 

Und dann tun Sie Dinge wie

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))) 

(Sie können entscheiden, ob Sie den Iterator direkt oder als Stream, Liste verwenden möchten, oder was auch immer.)

+0

Dank. Aber ich habe Probleme zu verstehen: "(0 /: ii) ((i, b) => (i << 1) | b)" Speziell die "(0 /: ii)". /: ist das FoldLeft. Das würde sich also in "(0.Folgende (ii))" übersetzen? (Wo ist mein Mystake?) – Fabian

+2

Es übersetzt eigentlich 'ii.foldLeft (0)'. Ein Operator, der mit einem Doppelpunkt endet, wird als eine Methode für sein _right_-Argument interpretiert statt dessen! Was die Falte sagt, ist, gegeben ein Akkumulator "i" und ein neues Bit "b", das Ergebnis (i << 1) | b, das heißt, verschiebe "i" um ein Bit nach links und setze das neue bisschen unten. Die Faltung wendet dies über den gesamten Iterator an. –