Вопрос

Мне нужно сжать / распаковать некоторые данные со старым, в доме развитый алгоритм. Там у меня много операций, таких как:

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" класса в Scala? (Я ничего не нашел и надеюсь, что мне не пришлось реализовать его самостоятельно.)

Спасибо

Редактировать: я объединил ответ с http://www.scala-lang.org/node/8413. («Архитектура Scala Collections») Если кто-то нуждается в том, что-то:

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
    }
}
Это было полезно?

Решение

Нет никакого существующего класса, о котором я знаю, но вы можете использовать существующие классы, чтобы помочь с почти всеми сложными операциями. Хитрость заключается в том, чтобы превратить ваши данные в поток INT (или байтов, если бы не хватало памяти). Затем вы можете использовать все удобные методы коллекций (например, 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)))

(Вы можете решить, хотите ли вы использовать итератор напрямую или как поток, список или что-то еще.)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top