Skip to content

Instantly share code, notes, and snippets.

@ajaychandran
Last active December 23, 2016 01:41
Show Gist options
  • Save ajaychandran/92b5eeade99d0855b066 to your computer and use it in GitHub Desktop.
Save ajaychandran/92b5eeade99d0855b066 to your computer and use it in GitHub Desktop.

Revisions

  1. ajaychandran revised this gist Jun 4, 2015. 1 changed file with 9 additions and 3 deletions.
    12 changes: 9 additions & 3 deletions DelimitedCodec.scala
    Original file line number Diff line number Diff line change
    @@ -19,7 +19,14 @@ object DelimitedCodec {
    case Attempt.Failure(err) => return Attempt.failure(err.pushContext(buf.size.toString))
    }
    }
    Attempt.successful(buf.reduce(_ ++ delimiter ++ _))
    def merge(offset: Int, size: Int): BitVector = size match {
    case 0 => BitVector.empty
    case 1 => buf(offset)
    case n =>
    val half = size / 2
    merge(offset, half) ++ delimiter ++ merge(offset + half, half + (if (size % 2 == 0) 0 else 1))
    }
    Attempt.successful(merge(0, buf.size))
    }

    /**
    @@ -42,11 +49,10 @@ object DelimitedCodec {
    next = remaining.take(i)
    remaining = remaining.drop(i + delimiter.size)
    }
    dec.decode(remaining) match {
    dec.decode(next) match {
    case Attempt.Successful(DecodeResult(value, rest)) =>
    bldr += value
    count += 1
    remaining = rest
    case Attempt.Failure(err) =>
    error = Some(err.pushContext(count.toString))
    remaining = BitVector.empty
  2. ajaychandran created this gist Jun 4, 2015.
    73 changes: 73 additions & 0 deletions DelimitedCodec.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,73 @@
    package scodec.codecs

    import scala.language.higherKinds

    import scodec._
    import scodec.bits.BitVector

    object DelimitedCodec {

    /**
    * Encodes all elements of the specified sequence and concatenates the results separated by `delimiter`,
    * or returns the first encountered error.
    */
    final def encode[A](enc: Encoder[A], delimiter: BitVector)(seq: collection.immutable.Seq[A]): Attempt[BitVector] = {
    val buf = new collection.mutable.ArrayBuffer[BitVector](seq.size)
    seq foreach { a =>
    enc.encode(a) match {
    case Attempt.Successful(aa) => buf += aa
    case Attempt.Failure(err) => return Attempt.failure(err.pushContext(buf.size.toString))
    }
    }
    Attempt.successful(buf.reduce(_ ++ delimiter ++ _))
    }

    /**
    * Repeatedly decodes values of type `A`, separated by `delimiter`, from the specified vector and
    * returns a collection of the specified type.
    * Terminates when no more bits are available in the vector. Exits upon first decoding error.
    */
    final def decode[F[_], A](dec: Decoder[A], delimiter: BitVector)(buffer: BitVector)(implicit cbf: collection.generic.CanBuildFrom[F[A], A, F[A]]): Attempt[DecodeResult[F[A]]] = {
    val bldr = cbf()
    var remaining = buffer
    var next = BitVector.empty
    var count = 0
    var error: Option[Err] = None
    while (remaining.nonEmpty) {
    buffer.indexOfSlice(delimiter) match {
    case -1 =>
    next = remaining
    remaining = BitVector.empty
    case i =>
    next = remaining.take(i)
    remaining = remaining.drop(i + delimiter.size)
    }
    dec.decode(remaining) match {
    case Attempt.Successful(DecodeResult(value, rest)) =>
    bldr += value
    count += 1
    remaining = rest
    case Attempt.Failure(err) =>
    error = Some(err.pushContext(count.toString))
    remaining = BitVector.empty
    }
    }
    Attempt.fromErrOption(error, DecodeResult(bldr.result, remaining))
    }
    }

    private[codecs] class VectorDelimitedCodec[A](delimiter: BitVector, codec: Codec[A]) extends Codec[Vector[A]] {
    def encode(value: Vector[A]): Attempt[BitVector] = DelimitedCodec.encode(codec, delimiter)(value)

    def sizeBound: SizeBound = SizeBound.unknown

    def decode(bits: BitVector): Attempt[DecodeResult[Vector[A]]] = DelimitedCodec.decode[Vector, A](codec, delimiter)(bits)
    }

    private[codecs] class ListDelimitedCodec[A](delimiter: BitVector, codec: Codec[A]) extends Codec[List[A]] {
    def encode(value: List[A]): Attempt[BitVector] = DelimitedCodec.encode(codec, delimiter)(value)

    def sizeBound: SizeBound = SizeBound.unknown

    def decode(bits: BitVector): Attempt[DecodeResult[List[A]]] = DelimitedCodec.decode[List, A](codec, delimiter)(bits)
    }