Skip to content
This repository was archived by the owner on Feb 20, 2019. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/src/main/scala/pickling/Compat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ object Compat {
c.Expr[Unit](bundle.pickleInto[T](builder.tree))
}

def PickleMacros_pickleTo[T: c.WeakTypeTag](c: Context)(output: c.Expr[Output[_]])(format: c.Expr[PickleFormat]): c.Expr[Unit] = {
def PickleMacros_pickleTo[T: c.WeakTypeTag, S](c: Context)(output: c.Expr[S])(format: c.Expr[PickleFormat]): c.Expr[Unit] = {
val c0: c.type = c
val bundle = new { val c: c0.type = c0 } with PickleMacros
c.Expr[Unit](bundle.pickleTo[T](output.tree)(format.tree))
Expand Down
70 changes: 0 additions & 70 deletions core/src/main/scala/pickling/Output.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,76 +12,6 @@ trait Output[T] {

}

class OutputStreamOutput(out: OutputStream) extends ArrayOutput[Byte] {
def result(): Array[Byte] =
null

def +=(obj: Byte) =
out.write(obj.asInstanceOf[Int])

def put(obj: Array[Byte]): this.type = {
out.write(obj)
this
}
}

// Array output with a few more methods for performance
abstract class ArrayOutput[T: ClassTag] extends Output[Array[T]] {
// Put a single T
def +=(obj: T): Unit
// Allocate a new array.
def target(len: Int): (Array[T], Int) =
(Array.ofDim[T](len), 0)
// Flush the allocated array by target().
def flush(arr: Array[T]): Unit =
this.put(arr)
}


class ByteArrayBufferOutput extends ArrayOutput[Byte] {

private val buf =
ArrayBuffer[Byte]()

def result(): Array[Byte] =
buf.toArray

def +=(obj: Byte) =
buf += obj

def put(obj: Array[Byte]): this.type = {
buf ++= obj
this
}
}

class ByteArrayOutput(len: Int) extends ArrayOutput[Byte] {

private var pos = 0
private val arr = Array.ofDim[Byte](len)

def result(): Array[Byte] =
arr

def +=(obj: Byte) = {
arr(pos) = obj
pos = pos + 1
}

def put(obj: Array[Byte]): this.type = {
// target() should be used to avoid double copy
throw new java.lang.IllegalStateException
}

override def target(len: Int) = {
val oldpos = pos
pos = pos + len
(arr, oldpos)
}

override def flush(arr: Array[Byte]) = { /*noop*/ }
}

class StringOutput extends Output[String] {

private val buf =
Expand Down
216 changes: 216 additions & 0 deletions core/src/main/scala/pickling/binary/BinaryInput.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package scala.pickling.binary

import scala.reflect.ClassTag

abstract class BinaryInput {

def getByte(): Byte

def getChar(): Char

def getShort(): Short

def getInt(): Int

def getLong(): Long

def getFloat(): Float

def getDouble(): Double

def getBytes(target: Array[Byte], len: Int): Unit

////////////////////////
// Derived operations //
////////////////////////

def getBoolean(): Boolean = {
getByte() != 0
}

def getString(): String = {
val array = getByteArray
new String(array, "UTF-8")
}

private val chunkSize = 1024
private val chunk = Array.ofDim[Byte](chunkSize)

protected def getArrayByChunk[T <: AnyVal: ClassTag](offset: Long, eltSize: Int): Array[T] = {
val size = getIntWithLookahead
val array = Array.ofDim[T](size)
var toCopy = size * eltSize
var destOffset = offset
while (toCopy > 0) {
val byteLen = math.min(chunkSize, toCopy)
getBytes(chunk, byteLen)
UnsafeMemory.unsafe.copyMemory(chunk, UnsafeMemory.byteArrayOffset, array, destOffset, byteLen)
toCopy -= byteLen
destOffset += byteLen
}
array
}

def getByteArray(): Array[Byte] = {
val size = getIntWithLookahead
val array = Array.ofDim[Byte](size)
getBytes(array, size)
array
}

def getBooleanArray(): Array[Boolean] = getArrayByChunk[Boolean](UnsafeMemory.booleanArrayOffset, 1)
def getCharArray(): Array[Char] = getArrayByChunk[Char](UnsafeMemory.charArrayOffset, 2)
def getShortArray(): Array[Short] = getArrayByChunk[Short](UnsafeMemory.shortArrayOffset, 2)
def getIntArray(): Array[Int] = getArrayByChunk[Int](UnsafeMemory.intArrayOffset, 4)
def getFloatArray(): Array[Float] = getArrayByChunk[Float](UnsafeMemory.floatArrayOffset, 4)
def getLongArray(): Array[Long] = getArrayByChunk[Long](UnsafeMemory.longArrayOffset, 8)
def getDoubleArray(): Array[Double] = getArrayByChunk[Double](UnsafeMemory.doubleArrayOffset, 8)

protected var lookahead: Option[Byte] = None

def setLookahead(b: Byte) {
lookahead = Some(b)
}

def getIntWithLookahead() = {
lookahead match {
case Some(b) =>
var i = b << 24
i |= (getByte.toInt << 16) & 0xFF0000
i |= (getByte.toInt << 8) & 0xFF00
i |= (getByte.toInt) & 0xFF
lookahead = None
i
case None =>
getInt
}
}

def getStringWithLookahead(la: Byte): String = {
val oldLa = lookahead
setLookahead(la)
val res = getString
lookahead = oldLa
res
}

}

class ByteBufferInput(buffer: java.nio.ByteBuffer) extends BinaryInput {

import java.nio.ByteOrder
assert(buffer.order == ByteOrder.BIG_ENDIAN)

def getByte() = buffer.get

def getChar() = buffer.getChar

def getShort() = buffer.getShort

def getInt() = buffer.getInt

def getLong() = buffer.getLong

def getFloat() = buffer.getFloat

def getDouble() = buffer.getDouble

def getBytes(target: Array[Byte], len: Int): Unit = {
buffer.get(target, 0, len)
}

}

class ByteArrayInput(data: Array[Byte]) extends BinaryInput {

private var idx = 0

def getByte() = {
val res = data(idx)
idx += 1
res
}

def getChar() = {
var res = 0
res |= data(idx ) << 8
res |= data(idx+1).toInt & 0xFF
idx += 2
res.asInstanceOf[Char]
}

def getShort() = {
var res = 0
res |= data(idx ) << 8
res |= data(idx+1).toInt & 0xFF
idx += 2
res.asInstanceOf[Short]
}

def getInt() = {
var res = (0: Int)
res |= (data(idx ) << 24)
res |= (data(idx+1) << 16) & 0xFF0000
res |= (data(idx+2) << 8 ) & 0xFF00
res |= (data(idx+3) ) & 0xFF
idx += 4
res
}

def getLong() = {
var res = (0: Long)
res |= (data(idx ).toLong << 56) & 0xFFFFFFFFFFFFFFFFL
res |= (data(idx+1).toLong << 48) & 0x00FFFFFFFFFFFFFFL
res |= (data(idx+2).toLong << 40) & 0x0000FFFFFFFFFFFFL
res |= (data(idx+3).toLong << 32) & 0x000000FFFFFFFFFFL
res |= (data(idx+4).toLong << 24) & 0x00000000FFFFFFFFL
res |= (data(idx+5).toLong << 16) & 0x0000000000FFFFFFL
res |= (data(idx+6).toLong << 8 ) & 0x000000000000FFFFL
res |= (data(idx+7).toLong ) & 0x00000000000000FFL
idx += 8
res
}

def getFloat() = {
val r = getInt()
java.lang.Float.intBitsToFloat(r)
}

def getDouble() = {
val r = getLong()
java.lang.Double.longBitsToDouble(r)
}

def getBytes(target: Array[Byte], len: Int): Unit = {
UnsafeMemory.unsafe.copyMemory(data, UnsafeMemory.byteArrayOffset + idx, target, UnsafeMemory.byteArrayOffset, len)
idx += len
}

//override array for faster copy (get rid of ckunk)
override protected def getArrayByChunk[T <: AnyVal: ClassTag](offset: Long, eltSize: Int): Array[T] = {
val size = getIntWithLookahead
val array = Array.ofDim[T](size)
var toCopy = size * eltSize
UnsafeMemory.unsafe.copyMemory(data, UnsafeMemory.byteArrayOffset + idx, array, offset, toCopy)
idx += toCopy
array
}

}

class StreamInput(stream: java.io.InputStream) extends BinaryInput {
val ds = new java.io.DataInputStream(stream)
def getByte() = ds.readByte()
def getChar() = ds.readChar()
def getShort() = ds.readShort()
def getInt() = ds.readInt()
def getLong() = ds.readLong()
def getFloat() = ds.readFloat()
def getDouble() = ds.readDouble()

def getBytes(target: Array[Byte], len: Int): Unit = {
ds.readFully(target, 0, len)
}
//TODO check endianness

}
Loading