2011-01-07 5 views
1

기존의 자체 개발 알고리즘으로 일부 데이터를 압축/압축 해제해야합니다.스칼라의 비트 스트림 라이브러리

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. 

스칼라에서 "Bitstrem"클래스 같은 사람 뭔가를 알고 :이 내가 좋아하는 작업을 많이 가지고? (난 아무것도 발견하고 나 자신에 의해 그것을 구현하지 않았다 희망하지 않았다.)

감사

편집 : 내가 만약 http://www.scala-lang.org/node/8413과 대답 ("스칼라 컬렉션의 구조")를 결합 제가 알고있는 기존의 클래스 없다

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

답변

4

,하지만 당신은 거의 모든 어려운 작업에 도움을 기존의 클래스를 활용할 수 있습니다 : 누군가는 samething이 필요합니다. 트릭은 데이터가 Ints (또는 메모리가 부족할 경우 바이트) 스트림으로 변환하는 것입니다. 그런 다음 모든 편리한 콜렉션 메소드 (예 : take)를 사용할 수 있으며 비트를 메모리로 바꾸는 문제 만 남습니다. 그러나 MSB 순서로 비트를 압축하면 쉽습니다.

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

그리고는 당신은

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

(직접 또는 스트림, 목록, 또는 무엇이든 같이 반복자를 사용할지 여부를 결정할 수 있습니다.)

+0

감사 등의 작업을 수행. 하지만 이해해야 할 문제가 있습니다. "(0/: ii) ((i, b) => (i << 1) | b)"Specialy는 "(0/: ii)"입니다./:는 foldLeft입니다. 그래서 그것은 "(0.foldLeft (ii))"로 해석 될 것입니다. (내 잘못한 부분은 어디입니까?) – Fabian

+2

실제로'ii.foldLeft (0)'로 변환됩니다. 콜론으로 끝나는 연산자는 왼쪽 대신 _right_ 인수에서 메서드로 해석됩니다! 'i'와 새로운 비트 'b'가 주어진 결과, (i << 1) | b를 생성합니다. 즉, 왼쪽으로 한 비트 씩 'i'를 이동시키고 새로운 조금 아래에. 이 폴드는 이터레이터 전체에 적용됩니다. –