boopickle.CodecSize.scala Maven / Gradle / Ivy
The newest version!
package boopickle
import java.nio.charset.CharacterCodingException
import java.nio.{ByteBuffer, ByteOrder}
class DecoderSize(val buf: ByteBuffer) extends Decoder {
val stringCodec: StringCodecBase = StringCodec
/**
* Decodes a single byte
*
* @return
*/
def readByte: Byte = {
buf.get
}
/**
* Decodes a UTF-8 encoded character (1-3 bytes) and produces a single UTF-16 character
*
* @return
*/
def readChar: Char = {
val b0 = buf.get & 0xff
if (b0 < 0x80)
b0.toChar
else if ((b0 & 0xe0) == 0xc0) {
val b1 = buf.get & 0x3f
((b0 & 0x1f) << 6 | b1).toChar
} else if ((b0 & 0xf0) == 0xe0) {
val s0 = buf.get & 0x3f
val s1 = buf.get & 0x3f
((b0 & 0x0f) << 12 | s0 << 6 | s1).toChar
} else
throw new CharacterCodingException
}
/**
* Decodes a 16-bit integer
*/
def readShort: Short = {
buf.getShort
}
/**
* Decodes a 32-bit integer (1-5 bytes) 0XXX XXXX = 0 to 127 1000 XXXX b0 = 128 to 4095 1001 XXXX b0 = -1 to -4095
* 1010 XXXX b0 b1 = 4096 to 1048575 1011 XXXX b0 b1 = -4096 to -1048575 1100 XXXX b0 b1 b2 = 1048576 to 268435455 1101
* XXXX b0 b1 b2 = -1048576 to -268435455 1110 0000 b0 b1 b2 b3 = MinInt to MaxInt 1111 ???? = reserved for special
* codings
*
* @return
*/
def readInt: Int = {
val b = buf.get & 0xff
if ((b & 0x80) != 0) {
// special coding, expand sign bit
val sign = if ((b & 0x10) == 0) 1 else -1
val b0 = b & 0xf
b >> 4 match {
case 0x8 | 0x9 =>
val b1 = buf.get & 0xff
sign * (b0 << 8 | b1)
case 0xa | 0xb =>
val b1 = buf.get & 0xff
val b2 = buf.get & 0xff
sign * (b0 << 16 | b1 << 8 | b2)
case 0xc | 0xd =>
val b1 = buf.get & 0xff
val b2 = buf.get & 0xff
val b3 = buf.get & 0xff
sign * (b0 << 24 | b1 << 16 | b2 << 8 | b3)
case 0xe if b == 0xe0 =>
sign * readRawInt
case _ =>
throw new IllegalArgumentException("Unknown integer coding")
}
} else {
b
}
}
def readRawInt: Int = {
buf.getInt
}
/**
* Decodes a 64-bit integer (1-9 bytes) 0XXX XXXX = 0 to 127 1000 XXXX b0 = 128 to 4095 1001 XXXX b0 = -1 to -4095
* 1010 XXXX b0 b1 = 4096 to 1048575 1011 XXXX b0 b1 = -4096 to -1048575 1100 XXXX b0 b1 b2 = 1048576 to 268435455 1101
* XXXX b0 b1 b2 = -1048576 to -268435455 1110 0000 b0 b1 b2 b3 = MinInt to MaxInt 1110 0001 b0 b1 b2 b3 b4 b5 b6 b7 =
* anything larger 1111 ???? = reserved for special codings
*
* @return
*/
def readLong: Long = {
val b = buf.get & 0xff
if (b != 0xe1) {
buf.position(buf.position() - 1)
readInt.toLong
} else {
readRawLong
}
}
def readRawLong: Long = {
buf.getLong
}
/**
* Decodes a 32-bit integer, or returns the first byte if it doesn't contain a valid encoding marker
*
* @return
*/
def readIntCode: Either[Byte, Int] = {
val b = buf.get & 0xff
if ((b & 0x80) != 0) {
// special coding, expand sign bit
val sign = if ((b & 0x10) == 0) 1 else -1
val b0 = b & 0xf
b >> 4 match {
case 0x8 | 0x9 =>
val b1 = buf.get & 0xff
Right(sign * (b0 << 8 | b1))
case 0xa | 0xb =>
val b1 = buf.get & 0xff
val b2 = buf.get & 0xff
Right(sign * (b0 << 16 | b1 << 8 | b2))
case 0xc | 0xd =>
val b1 = buf.get & 0xff
val b2 = buf.get & 0xff
val b3 = buf.get & 0xff
Right(sign * (b0 << 24 | b1 << 16 | b2 << 8 | b3))
case 0xe if b == 0xe0 =>
Right(sign * readRawInt)
case _ =>
Left((b & 0xf).toByte)
}
} else {
Right(b)
}
}
/**
* Decodes a 64-bit long, or returns the first byte if it doesn't contain a valid encoding marker
*
* @return
*/
def readLongCode: Either[Byte, Long] = {
val b = buf.get & 0xff
if (b != 0xe1) {
buf.position(buf.position() - 1)
readIntCode match {
case Left(x) => Left((x & 0xf).toByte)
case Right(x) => Right(x.toLong)
}
} else
Right(readRawLong)
}
/**
* Decodes a 32-bit float (4 bytes)
*
* @return
*/
def readFloat: Float = {
buf.getFloat
}
/**
* Decodes a 64-bit double (8 bytes)
*
* @return
*/
def readDouble: Double = {
buf.getDouble
}
/**
* Decodes a UTF-8 encoded string
*
* @return
*/
def readString: String = {
// read string length
val len = readInt
stringCodec.decodeFast(len, buf)
}
/**
* Decodes a UTF-8 encoded string whose length is already known
*
* @param len
* Length of the string (in bytes)
* @return
*/
def readString(len: Int): String = {
stringCodec.decodeFast(len, buf)
}
def readByteBuffer: ByteBuffer = {
// length and byte order are encoded into same integer
val sizeBO = readInt
if (sizeBO < 0)
throw new IllegalArgumentException(s"Invalid size $sizeBO for ByteBuffer")
val size = sizeBO >> 1
val byteOrder = if ((sizeBO & 1) == 1) ByteOrder.BIG_ENDIAN else ByteOrder.LITTLE_ENDIAN
// create a copy (sharing content), set correct byte order
val b = buf.slice().order(byteOrder)
buf.position(buf.position() + size)
b.limit(b.position() + size)
b
}
/**
* Decodes an array of Bytes
*/
def readByteArray(): Array[Byte] = readByteArray(readRawInt)
def readByteArray(len: Int): Array[Byte] = {
val array = new Array[Byte](len)
buf.get(array)
array
}
/**
* Decodes an array of Integers
*/
def readIntArray(): Array[Int] = readIntArray(readRawInt)
def readIntArray(len: Int): Array[Int] = {
val array = new Array[Int](len)
var i = 0
while (i < len) {
array(i) = readInt
i += 1
}
array
}
/**
* Decodes an array of Floats
*/
def readFloatArray(): Array[Float] = readFloatArray(readRawInt)
def readFloatArray(len: Int): Array[Float] = {
val array = new Array[Float](len)
buf.asFloatBuffer().get(array)
buf.position(buf.position() + len * 4)
array
}
/**
* Decodes an array of Doubles
*/
def readDoubleArray(): Array[Double] = {
val len = readRawInt
readRawInt // remove padding
readDoubleArray(len)
}
def readDoubleArray(len: Int): Array[Double] = {
val array = new Array[Double](len)
buf.asDoubleBuffer().get(array)
buf.position(buf.position() + len * 8)
array
}
}
class EncoderSize(bufferProvider: BufferProvider = DefaultByteBufferProvider.provider) extends Encoder {
val stringCodec: StringCodecBase = StringCodec
@inline private def alloc(size: Int): ByteBuffer = bufferProvider.alloc(size)
/**
* Encodes a single byte
*
* @param b
* Byte to encode
* @return
*/
def writeByte(b: Byte): Encoder = {
alloc(1).put(b)
this
}
/**
* Encodes a single character using UTF-8 encoding
*
* @param c
* Character to encode
* @return
*/
def writeChar(c: Char): Encoder = {
if (c < 0x80) {
alloc(1).put(c.toByte)
} else if (c < 0x800) {
alloc(2).put((0xc0 | (c >>> 6 & 0x3f)).toByte).put((0x80 | (c & 0x3f)).toByte)
} else {
alloc(3).put((0xe0 | (c >>> 12)).toByte).put((0x80 | (c >>> 6 & 0x3f)).toByte).put((0x80 | (c & 0x3f)).toByte)
}
this
}
/**
* Encodes a short integer
*/
def writeShort(s: Short): Encoder = {
alloc(2).putShort(s)
this
}
/**
* Encodes an integer efficiently in 1 to 5 bytes 0XXX XXXX = 0 to 127 1000 XXXX b0 = 128 to 4095 1001 XXXX b0 = -1
* to -4095 1010 XXXX b0 b1 = 4096 to 1048575 1011 XXXX b0 b1 = -4096 to -1048575 1100 XXXX b0 b1 b2 = 1048575 to
* 268435455 1101 XXXX b0 b1 b2 = -1048575 to -268435455 1110 0000 b0 b1 b2 b3 = MinInt to MaxInt 1111 ???? = reserved for
* special codings
*
* @param i
* Integer to encode
*/
def writeInt(i: Int): Encoder = {
// check for a short number
if (i >= 0 && i < 128) {
alloc(1).put(i.toByte)
} else {
if (i > -268435456 && i < 268435456) {
val mask = i >>> 31 << 4
val a = Math.abs(i)
if (a < 4096) {
alloc(2).put((mask | 0x80 | (a >> 8)).toByte).put((a & 0xff).toByte)
} else if (a < 1048576) {
alloc(3).put((mask | 0xa0 | (a >> 16)).toByte).put(((a >> 8) & 0xff).toByte).put((a & 0xff).toByte)
} else {
alloc(4)
.put((mask | 0xc0 | (a >> 24)).toByte)
.put(((a >> 16) & 0xff).toByte)
.put(((a >> 8) & 0xff).toByte)
.put((a & 0xff).toByte)
}
} else {
alloc(5).put(0xe0.toByte).putInt(i)
}
}
this
}
/**
* Encodes an integer in 32-bits
*
* @param i
* Integer to encode
* @return
*/
def writeRawInt(i: Int): Encoder = {
alloc(4).putInt(i)
this
}
/**
* Encodes a long efficiently in 1 to 9 bytes 0XXX XXXX = 0 to 127 1000 XXXX b0 = 128 to 4095 1001 XXXX b0 = -1 to
* -4096 1010 XXXX b0 b1 = 4096 to 1048575 1011 XXXX b0 b1 = -4096 to -1048575 1100 XXXX b0 b1 b2 = 1048576 to 268435455
* 1101 XXXX b0 b1 b2 = -1048576 to -268435455 1110 0000 b0 b1 b2 b3 = MinInt to MaxInt 1110 0001 b0 b1 b2 b3 b4 b5 b6 b7
* \= anything larger 1111 ???? = reserved for special codings
*
* @param l
* Long to encode
*/
def writeLong(l: Long): Encoder = {
if (l <= Int.MaxValue && l >= Int.MinValue)
writeInt(l.toInt)
else {
alloc(9).put(0xe1.toByte).putLong(l)
}
this
}
/**
* Encodes a long in 64-bits
*
* @param l
* Long to encode
* @return
*/
def writeRawLong(l: Long): Encoder = {
alloc(8).putLong(l)
this
}
/**
* Writes either a code byte (0-15) or an Int
*
* @param intCode
* Integer or a code byte
*/
def writeIntCode(intCode: Either[Byte, Int]): Encoder = {
intCode match {
case Left(code) =>
alloc(1).put((code | 0xf0).toByte)
case Right(i) =>
writeInt(i)
}
this
}
/**
* Writes either a code byte (0-15) or a Long
*
* @param longCode
* Long or a code byte
*/
def writeLongCode(longCode: Either[Byte, Long]): Encoder = {
longCode match {
case Left(code) =>
alloc(1).put((code | 0xf0).toByte)
case Right(l) =>
writeLong(l)
}
this
}
/**
* Encodes a string using UTF8
*
* @param s
* String to encode
* @return
*/
def writeString(s: String): Encoder = {
writeInt(s.length)
val bb = alloc(s.length * 3)
stringCodec.encodeFast(s, bb)
this
}
/**
* Encodes a float as 4 bytes
*
* @param f
* Float to encode
* @return
*/
def writeFloat(f: Float): Encoder = {
alloc(4).putFloat(f)
this
}
/**
* Encodes a double as 8 bytes
*
* @param d
* Double to encode
* @return
*/
def writeDouble(d: Double): Encoder = {
alloc(8).putDouble(d)
this
}
/**
* Encodes a ByteBuffer by writing its length and content
*
* @param bb
* ByteBuffer to encode
* @return
*/
def writeByteBuffer(bb: ByteBuffer): Encoder = {
bb.mark()
val byteOrder = if (bb.order() == ByteOrder.BIG_ENDIAN) 1 else 0
// encode byte order as bit 0 in the length
writeInt(bb.remaining * 2 | byteOrder)
alloc(bb.remaining).put(bb)
bb.reset()
this
}
/**
* Encodes an array of Bytes
*/
def writeByteArray(ba: Array[Byte]): Encoder = {
writeRawInt(ba.length)
alloc(ba.length).put(ba)
this
}
/**
* Encodes an array of Integers
*/
def writeIntArray(ia: Array[Int]): Encoder = {
writeRawInt(ia.length)
ia.foreach(writeInt)
this
}
/**
* Encodes an array of Floats
*/
def writeFloatArray(fa: Array[Float]): Encoder = {
writeRawInt(fa.length)
val bb = alloc(fa.length * 4)
bb.asFloatBuffer().put(fa)
bb.position(bb.position() + fa.length * 4)
this
}
/**
* Encodes an array of Doubles
*/
def writeDoubleArray(da: Array[Double]): Encoder = {
writeRawInt(da.length)
// padding
writeRawInt(0)
val bb = alloc(da.length * 8)
bb.asDoubleBuffer().put(da)
bb.position(bb.position() + da.length * 8)
this
}
/**
* Completes the encoding and returns the ByteBuffer
*
* @return
*/
def asByteBuffer = bufferProvider.asByteBuffer
/**
* Completes the encoding and returns a sequence of ByteBuffers
*
* @return
*/
def asByteBuffers = bufferProvider.asByteBuffers
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy