Removed all generics from Kotlin Protobuf Runtime (as too advanced language feature for target platform)
This commit is contained in:
Generated
+4
-1
@@ -2,8 +2,11 @@
|
|||||||
<module type="JAVA_MODULE" version="4">
|
<module type="JAVA_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="KotlinJavaRuntime">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/kotlin-runtime.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/kotlin-reflect.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/kotlin-runtime-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
</component>
|
||||||
Generated
+6
-1
@@ -1,5 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="EntryPointsManager">
|
||||||
|
<entry_points version="2.0" />
|
||||||
|
</component>
|
||||||
<component name="MavenImportPreferences">
|
<component name="MavenImportPreferences">
|
||||||
<option name="generalSettings">
|
<option name="generalSettings">
|
||||||
<MavenGeneralSettings>
|
<MavenGeneralSettings>
|
||||||
@@ -17,5 +20,7 @@
|
|||||||
<ConfirmationsSetting value="0" id="Add" />
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
<ConfirmationsSetting value="0" id="Remove" />
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_3" default="true" assert-keyword="false" jdk-15="false" />
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="falses" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/test" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/test" type="java-resource" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
@@ -14,153 +14,171 @@ import java.nio.ByteOrder
|
|||||||
// TODO: decide, if we want to optimize for performance (then we have to deal with spaghetti-code)
|
// TODO: decide, if we want to optimize for performance (then we have to deal with spaghetti-code)
|
||||||
class CodedInputStream(input: java.io.InputStream) {
|
class CodedInputStream(input: java.io.InputStream) {
|
||||||
|
|
||||||
data class Field<ValueType> (val fieldNumber: Int, val wireType: WireType, val value: ValueType) // TODO: think about variance
|
|
||||||
|
|
||||||
val bufferedInput: java.io.BufferedInputStream
|
val bufferedInput: java.io.BufferedInputStream
|
||||||
init {
|
init {
|
||||||
bufferedInput = java.io.BufferedInputStream(input) // TODO: Java's realization uses hand-written buffers. Why?
|
bufferedInput = java.io.BufferedInputStream(input) // TODO: Java's realization uses hand-written buffers. Why?
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readInt32(): Field<Int> {
|
fun readInt32(expectedFieldNumber: Int): Int {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.VARINT)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected Varint tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
val value = readRawVarint32()
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType)
|
||||||
return Field<Int>(fieldNumber, wireType, value)
|
return readRawVarint32()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that unsigned integer types are stored as their signed counterparts with top bit
|
// Note that unsigned integer types are stored as their signed counterparts with top bit
|
||||||
// simply stored in the sign bit - similar to Java's protobuf implementation. Hence, all
|
// simply stored in the sign bit - similar to Java's protobuf implementation. Hence, all
|
||||||
// methods, reading unsigned ints simply redirect call to corresponding signed-reading method
|
// methods reading unsigned ints simply redirect call to corresponding signed-reading method
|
||||||
fun readUInt32(): Field<Int> {
|
fun readUInt32(expectedFieldNumber: Int): Int {
|
||||||
return readInt32()
|
return readInt32(expectedFieldNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readInt64(): Field<Long> {
|
fun readInt64(expectedFieldNumber: Int): Long {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.VARINT)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected Varint tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
val value = readRawVarint64()
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, actualWireType, WireType.VARINT)
|
||||||
return Field(fieldNumber, wireType, value)
|
return readRawVarint64()
|
||||||
}
|
}
|
||||||
|
|
||||||
// See note on unsigned integers implementations above
|
// See note on unsigned integers implementations above
|
||||||
fun readUInt64(): Field<Long> {
|
fun readUInt64(expectedFieldNumber: Int): Long {
|
||||||
return readUInt64()
|
return readUInt64(expectedFieldNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readBool(): Field<Boolean> {
|
fun readBool(expectedFieldNumber: Int): Boolean {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.VARINT)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected Varint tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, actualWireType, WireType.VARINT)
|
||||||
val readValue = readRawVarint32()
|
val readValue = readRawVarint32()
|
||||||
val boolValue = when (readValue) {
|
val boolValue = when (readValue) {
|
||||||
0 -> false
|
0 -> false
|
||||||
1 -> true
|
1 -> true
|
||||||
else -> throw InvalidProtocolBufferException("Expected boolean-encoding (1 or 0), got $readValue")
|
else -> throw InvalidProtocolBufferException("Expected boolean-encoding (1 or 0), got $readValue")
|
||||||
}
|
}
|
||||||
|
return boolValue
|
||||||
return Field(fieldNumber, wireType, boolValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reading enums is like reading one int32 number. Caller is responsible for converting this ordinal to enum-object
|
// Reading enums is like reading one int32 number. Caller is responsible for converting this ordinal to enum-object
|
||||||
fun readEnum(): Field<Int> {
|
fun readEnum(expectedFieldNumber: Int): Int {
|
||||||
return readInt32()
|
return readInt32(expectedFieldNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readSInt32(): Field<Int> {
|
fun readSInt32(expectedFieldNumber: Int): Int {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.VARINT)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected Varint tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
val value = readZigZag32()
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType)
|
||||||
return Field(fieldNumber, wireType, value)
|
return readZigZag32()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readSInt64(): Field<Long> {
|
fun readSInt64(expectedFieldNumber: Int): Long {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.VARINT)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected Varint tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
val value = readZigZag64()
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.VARINT, actualWireType)
|
||||||
return Field(fieldNumber, wireType, value)
|
return readZigZag64()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFixed32(): Field<Int> {
|
fun readFixed32(expectedFieldNumber: Int): Int {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.FIX_32)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected FIX_32 tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
val value = readLittleEndianInt()
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_32, actualWireType)
|
||||||
return Field(fieldNumber, wireType, value)
|
return readLittleEndianInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readSFixed32(): Field<Int> {
|
fun readSFixed32(expectedFieldNumber: Int): Int {
|
||||||
return readFixed32()
|
return readFixed32(expectedFieldNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFixed64(): Field<Long> {
|
fun readFixed64(expectedFieldNumber: Int): Long {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.FIX_64)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected FIX_64 tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
val value = readLittleEndianLong()
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_64, actualWireType)
|
||||||
return Field(fieldNumber, wireType, value)
|
return readLittleEndianLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readSFixed64(): Field<Long> {
|
fun readSFixed64(expectedFieldNumber: Int): Long {
|
||||||
return readFixed64()
|
return readFixed64(expectedFieldNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readDouble(): Field<Double> {
|
fun readDouble(expectedFieldNumber: Int): Double {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.FIX_64)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected FIX_64 tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
val value = readLittleEndianDouble()
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_64, actualWireType)
|
||||||
return Field(fieldNumber, wireType, value)
|
return readLittleEndianDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readFloat(): Field<Float> {
|
fun readFloat(expectedFieldNumber: Int): Float {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.FIX_32)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected FIX_64 tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
val value = readLittleEndianFloat()
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.FIX_32, actualWireType)
|
||||||
return Field(fieldNumber, wireType, value)
|
return readLittleEndianFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readString(): Field<String> {
|
fun readString(expectedFieldNumber: Int): String {
|
||||||
val (fieldNumber, wireType) = readAndParseTag()
|
val tag = readTag()
|
||||||
if (wireType != WireType.LENGTH_DELIMITED)
|
val actualFieldNumber = WireFormat.getTagFieldNumber(tag)
|
||||||
throw InvalidProtocolBufferException("Expected LENGTH_DELMITED tag, got ${wireType.name}")
|
val actualWireType = WireFormat.getTagWireType(tag)
|
||||||
|
checkFieldCorrectness(expectedFieldNumber, actualFieldNumber, WireType.LENGTH_DELIMITED, actualWireType)
|
||||||
val length = readRawVarint32()
|
val length = readRawVarint32()
|
||||||
val value = String(readRawBytes(length))
|
val value = String(readRawBytes(length))
|
||||||
return Field(fieldNumber, wireType, value)
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ private methods ==================
|
/** ============ Utility methods ==================
|
||||||
|
* They are left non-private for cases when one wants to implement her/his own protocol format.
|
||||||
|
* Then she/he can re-use low-level methods for operating with raw values, that are not annotated with Protobuf tags.
|
||||||
|
*/
|
||||||
|
|
||||||
private fun readLittleEndianDouble(): Double {
|
fun checkFieldCorrectness(
|
||||||
|
expectedFieldNumber: Int,
|
||||||
|
actualFieldNumber: Int,
|
||||||
|
expectedWireType: WireType,
|
||||||
|
actualWireType: WireType) {
|
||||||
|
if (expectedFieldNumber != actualFieldNumber) {
|
||||||
|
throw InvalidProtocolBufferException(
|
||||||
|
"Error in protocol format: \n " +
|
||||||
|
"Expected field number ${expectedFieldNumber}, got ${actualFieldNumber}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedWireType != actualWireType) {
|
||||||
|
throw InvalidProtocolBufferException("Error in protocol format: \n " +
|
||||||
|
"Expected ${expectedWireType.name} type, got ${actualWireType.name}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readLittleEndianDouble(): Double {
|
||||||
val byteBuffer = ByteBuffer.wrap(readRawBytes(8))
|
val byteBuffer = ByteBuffer.wrap(readRawBytes(8))
|
||||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
return byteBuffer.getDouble(0)
|
return byteBuffer.getDouble(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readLittleEndianFloat(): Float {
|
fun readLittleEndianFloat(): Float {
|
||||||
val byteBuffer = ByteBuffer.wrap(readRawBytes(4))
|
val byteBuffer = ByteBuffer.wrap(readRawBytes(4))
|
||||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
return byteBuffer.getFloat(0)
|
return byteBuffer.getFloat(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readLittleEndianInt(): Int {
|
fun readLittleEndianInt(): Int {
|
||||||
val byteBuffer = ByteBuffer.wrap(readRawBytes(8))
|
val byteBuffer = ByteBuffer.wrap(readRawBytes(8))
|
||||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
return byteBuffer.getInt(0)
|
return byteBuffer.getInt(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readLittleEndianLong(): Long {
|
fun readLittleEndianLong(): Long {
|
||||||
val byteBuffer = ByteBuffer.wrap(readRawBytes(4))
|
val byteBuffer = ByteBuffer.wrap(readRawBytes(4))
|
||||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
return byteBuffer.getLong(0)
|
return byteBuffer.getLong(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readRawBytes(count: Int): ByteArray {
|
fun readRawBytes(count: Int): ByteArray {
|
||||||
val ba = ByteArray(count)
|
val ba = ByteArray(count)
|
||||||
for (i in 0..(count - 1)) {
|
for (i in 0..(count - 1)) {
|
||||||
ba[i] = bufferedInput.read().toByte()
|
ba[i] = bufferedInput.read().toByte()
|
||||||
@@ -168,67 +186,84 @@ class CodedInputStream(input: java.io.InputStream) {
|
|||||||
return ba
|
return ba
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readTag(): Int {
|
// reads tag. Note that it returns 0 for the end of message!
|
||||||
|
fun readTag(): Int {
|
||||||
if (isAtEnd()) {
|
if (isAtEnd()) {
|
||||||
return 0 // we can safely return 0 as sign of end of message, because 0-tags are illegal
|
return 0 // we can safely return 0 as sign of end of message, because 0-tags are illegal
|
||||||
}
|
}
|
||||||
val tag = readRawVarint32()
|
val tag = readRawVarint32()
|
||||||
if (tag == 0) { // if we somehow read 0-tag, then message is corrupted
|
if (tag == 0) { // if we somehow had read 0-tag, then message is corrupted
|
||||||
throw InvalidProtocolBufferException("Invalid tag 0")
|
throw InvalidProtocolBufferException("Invalid tag 0")
|
||||||
}
|
}
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readAndParseTag(): Pair<Int, WireType> {
|
// reads varint not larger than 32-bit integer according to protobuf varint-encoding
|
||||||
val tag = readTag()
|
fun readRawVarint32(): Int {
|
||||||
return Pair(WireFormat.getTagFieldNumber(tag), WireFormat.getTagWireType(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun readRawVarint32(): Int {
|
|
||||||
var done: Boolean = false
|
var done: Boolean = false
|
||||||
var result: Int = 0
|
var result: Int = 0
|
||||||
var step: Int = 0
|
var step: Int = 0
|
||||||
while (!done) {
|
while (!done) {
|
||||||
val byte: Int = bufferedInput.read()
|
val byte: Int = bufferedInput.read()
|
||||||
result = result or ((byte and 127) shl (7 * step))
|
result = result or
|
||||||
|
(
|
||||||
|
(byte and VARINT_INFO_BITS_MASK)
|
||||||
|
shl
|
||||||
|
(VARINT_INFO_BITS_COUNT * step)
|
||||||
|
)
|
||||||
step++
|
step++
|
||||||
if ((byte and 128) == 0) {
|
if ((byte and VARINT_UTIL_BIT_MASK) == 0) {
|
||||||
done = true
|
done = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readRawVarint64(): Long {
|
// reads varint not larger than 64-bit integer according to protobuf varint-encoding
|
||||||
|
fun readRawVarint64(): Long {
|
||||||
var done: Boolean = false
|
var done: Boolean = false
|
||||||
var result: Long = 0
|
var result: Long = 0
|
||||||
var step: Int = 0
|
var step: Int = 0
|
||||||
while (!done) {
|
while (!done) {
|
||||||
val byte: Int = bufferedInput.read()
|
val byte: Int = bufferedInput.read()
|
||||||
result = result or ((byte and 127).toLong() shl (7 * step))
|
result = result or
|
||||||
|
(
|
||||||
|
(byte and VARINT_INFO_BITS_MASK).toLong()
|
||||||
|
shl
|
||||||
|
(VARINT_INFO_BITS_COUNT * step)
|
||||||
|
)
|
||||||
step++
|
step++
|
||||||
if ((byte and 128) == 0 || byte == -1) {
|
if ((byte and VARINT_UTIL_BIT_MASK) == 0 || byte == -1) {
|
||||||
done = true
|
done = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readZigZag32(): Int {
|
// reads zig-zag encoded integer not larger than 32-bit long
|
||||||
|
fun readZigZag32(): Int {
|
||||||
val value = readRawVarint32()
|
val value = readRawVarint32()
|
||||||
return (value shr 1) xor (-(value and 1))
|
return (value shr 1) xor (-(value and 1)) // bit magic for decoding zig-zag number
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readZigZag64(): Long {
|
// reads zig-zag encoded integer not larger than 64-bit long
|
||||||
|
fun readZigZag64(): Long {
|
||||||
val value = readRawVarint64()
|
val value = readRawVarint64()
|
||||||
return (value shr 1) xor (-(value and 1L))
|
return (value shr 1) xor (-(value and 1L)) // bit magic for decoding zig-zag number
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isAtEnd(): Boolean {
|
// checks if at least one more byte can be read from underlying input stream
|
||||||
|
fun isAtEnd(): Boolean {
|
||||||
bufferedInput.mark(1)
|
bufferedInput.mark(1)
|
||||||
val byte = bufferedInput.read()
|
val byte = bufferedInput.read()
|
||||||
bufferedInput.reset()
|
bufferedInput.reset()
|
||||||
return byte == -1
|
return byte == -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// couple of constants for magic numbers
|
||||||
|
val VARINT_INFO_BITS_COUNT: Int = 7
|
||||||
|
val VARINT_INFO_BITS_MASK: Int = 0b01111111 // mask for separating lowest 7 bits, where actual information stored
|
||||||
|
val VARINT_UTIL_BIT_MASK: Int = 0b10000000 // mask for separating highest bit, that indicates next byte presence
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,14 +116,23 @@ class CodedOutputStream(val output: java.io.OutputStream) {
|
|||||||
|
|
||||||
fun writeVarint32(value: Int) {
|
fun writeVarint32(value: Int) {
|
||||||
var curValue = value
|
var curValue = value
|
||||||
|
|
||||||
|
// we have at most 32 information bits. With overhead of 1 bit per 7 bits we need at most 5 bytes for encoding
|
||||||
val res = ByteArray(5)
|
val res = ByteArray(5)
|
||||||
|
|
||||||
var resSize = 0
|
var resSize = 0
|
||||||
do {
|
do {
|
||||||
var curByte = (curValue and 127)
|
// encode current 7 bits
|
||||||
curValue = curValue ushr 7
|
var curByte = (curValue and VARINT_INFO_BITS_MASK)
|
||||||
|
|
||||||
|
// discard encoded bits. Note that unsigned shift is needed for cases with negative numbers
|
||||||
|
curValue = curValue ushr VARINT_INFO_BITS_COUNT
|
||||||
|
|
||||||
|
// check if there will be next byte in encoding and set util bit if needed
|
||||||
if (curValue != 0) {
|
if (curValue != 0) {
|
||||||
curByte = curByte or 128
|
curByte = curByte or VARINT_UTIL_BIT_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
res[resSize] = curByte.toByte()
|
res[resSize] = curByte.toByte()
|
||||||
resSize++
|
resSize++
|
||||||
} while(curValue != 0)
|
} while(curValue != 0)
|
||||||
@@ -132,13 +141,21 @@ class CodedOutputStream(val output: java.io.OutputStream) {
|
|||||||
|
|
||||||
fun writeVarint64(value: Long) {
|
fun writeVarint64(value: Long) {
|
||||||
var curValue = value
|
var curValue = value
|
||||||
val res = ByteArray(10) // we reserve 10 bytes for the cases when value was negative int32/int64
|
|
||||||
|
// we have at most 64 information bits. With overhead of 1 bit per 7 bits we need at most 10 bytes for encoding
|
||||||
|
val res = ByteArray(10)
|
||||||
|
|
||||||
var resSize = 0
|
var resSize = 0
|
||||||
while(curValue != 0L) {
|
while(curValue != 0L) {
|
||||||
var curByte = (curValue and 127L)
|
// encode current 7 bits
|
||||||
curValue = curValue ushr 7
|
var curByte = (curValue and VARINT_INFO_BITS_MASK.toLong())
|
||||||
|
|
||||||
|
// discard encoded bits. Note that unsigned shift is needed for cases with negative numbers
|
||||||
|
curValue = curValue ushr VARINT_INFO_BITS_COUNT
|
||||||
|
|
||||||
|
// check if there will be next byte and set util bit if needed
|
||||||
if (curValue != 0L) {
|
if (curValue != 0L) {
|
||||||
curByte = curByte or 128L
|
curByte = curByte or VARINT_UTIL_BIT_MASK.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
res[resSize] = curByte.toByte()
|
res[resSize] = curByte.toByte()
|
||||||
@@ -146,4 +163,9 @@ class CodedOutputStream(val output: java.io.OutputStream) {
|
|||||||
}
|
}
|
||||||
output.write(res, 0, resSize)
|
output.write(res, 0, resSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// couple of constants for magic numbers
|
||||||
|
val VARINT_INFO_BITS_COUNT: Int = 7
|
||||||
|
val VARINT_INFO_BITS_MASK: Int = 0b01111111 // mask for separating lowest 7 bits, where actual information stored
|
||||||
|
val VARINT_UTIL_BIT_MASK: Int = 0b10000000 // mask for separating highest bit, that indicates next byte presence
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ class PersonMessage(val name: String, val id: Long, val hasCat: Boolean) // : Me
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readFrom(input: CodedInputStream) : PersonMessage {
|
fun readFrom(input: CodedInputStream) : PersonMessage {
|
||||||
val newName = input.readString().value
|
val newName = input.readString(1)
|
||||||
val newId = input.readInt64().value
|
val newId = input.readInt64(2)
|
||||||
val newHasCatFlag = input.readBool().value
|
val newHasCatFlag = input.readBool(3)
|
||||||
return PersonMessage(newName, newId, newHasCatFlag)
|
return PersonMessage(newName, newId, newHasCatFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,15 @@ fun testTrivialPositiveVarInts() {
|
|||||||
outs.writeInt64(9, -32132132132131L)
|
outs.writeInt64(9, -32132132132131L)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(1, 42, ins.readInt32())
|
assertSuccessfulRead(42, ins.readInt32(1))
|
||||||
assertSuccessfulRead(42, 1, ins.readInt32())
|
assertSuccessfulRead(1, ins.readInt32(16))
|
||||||
assertSuccessfulRead(2, -2, ins.readInt32())
|
assertSuccessfulRead(-2, ins.readInt32(2))
|
||||||
assertSuccessfulRead(3, -21321, ins.readInt32())
|
assertSuccessfulRead(-21321, ins.readInt32(3))
|
||||||
assertSuccessfulRead(5, 42L, ins.readInt64())
|
assertSuccessfulRead(42L, ins.readInt64(5))
|
||||||
assertSuccessfulRead(6, 1232132131212321L, ins.readInt64())
|
assertSuccessfulRead(1232132131212321L, ins.readInt64(6))
|
||||||
assertSuccessfulRead(7, -2, ins.readInt64())
|
assertSuccessfulRead(-2, ins.readInt64(7))
|
||||||
assertSuccessfulRead(8, -21321L, ins.readInt64())
|
assertSuccessfulRead(-21321L, ins.readInt64(8))
|
||||||
assertSuccessfulRead(9, -32132132132131L, ins.readInt64())
|
assertSuccessfulRead(-32132132132131L, ins.readInt64(9))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -38,8 +38,8 @@ fun testMinPossibleVarInts() {
|
|||||||
outs.writeInt64(2, Long.MIN_VALUE)
|
outs.writeInt64(2, Long.MIN_VALUE)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(1, Int.MIN_VALUE, ins.readInt32())
|
assertSuccessfulRead(Int.MIN_VALUE, ins.readInt32(1))
|
||||||
assertSuccessfulRead(2, Long.MIN_VALUE, ins.readInt64())
|
assertSuccessfulRead(Long.MIN_VALUE, ins.readInt64(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testMaxPossibleVarInts() {
|
fun testMaxPossibleVarInts() {
|
||||||
@@ -49,8 +49,8 @@ fun testMaxPossibleVarInts() {
|
|||||||
outs.writeInt64(2, Long.MAX_VALUE)
|
outs.writeInt64(2, Long.MAX_VALUE)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(1, Int.MAX_VALUE, ins.readInt32())
|
assertSuccessfulRead(Int.MAX_VALUE, ins.readInt32(1))
|
||||||
assertSuccessfulRead(2, Long.MAX_VALUE, ins.readInt64())
|
assertSuccessfulRead(Long.MAX_VALUE, ins.readInt64(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testMaxPossibleFieldNumber() {
|
fun testMaxPossibleFieldNumber() {
|
||||||
@@ -59,7 +59,7 @@ fun testMaxPossibleFieldNumber() {
|
|||||||
outs.writeInt64(536870911, Long.MAX_VALUE)
|
outs.writeInt64(536870911, Long.MAX_VALUE)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(536870911, Long.MAX_VALUE, ins.readInt64())
|
assertSuccessfulRead(Long.MAX_VALUE, ins.readInt64(536870911))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testZigZag32() {
|
fun testZigZag32() {
|
||||||
@@ -70,9 +70,9 @@ fun testZigZag32() {
|
|||||||
outs.writeSInt32(4, -12345675)
|
outs.writeSInt32(4, -12345675)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(5, -213123, ins.readSInt32())
|
assertSuccessfulRead(-213123, ins.readSInt32(5))
|
||||||
assertSuccessfulRead(1, 3123123, ins.readSInt32())
|
assertSuccessfulRead(3123123, ins.readSInt32(1))
|
||||||
assertSuccessfulRead(4, -12345675, ins.readSInt32())
|
assertSuccessfulRead(-12345675, ins.readSInt32(4))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testZigZag64() {
|
fun testZigZag64() {
|
||||||
@@ -85,11 +85,11 @@ fun testZigZag64() {
|
|||||||
outs.writeSInt64(42, 483567314231L)
|
outs.writeSInt64(42, 483567314231L)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(5, -213123L, ins.readSInt64())
|
assertSuccessfulRead(-213123L, ins.readSInt64(5))
|
||||||
assertSuccessfulRead(1, 3123123L, ins.readSInt64())
|
assertSuccessfulRead(3123123L, ins.readSInt64(1))
|
||||||
assertSuccessfulRead(4, -12345675L, ins.readSInt64())
|
assertSuccessfulRead(-12345675L, ins.readSInt64(4))
|
||||||
assertSuccessfulRead(12, -123456789012L, ins.readSInt64())
|
assertSuccessfulRead(-123456789012L, ins.readSInt64(12))
|
||||||
assertSuccessfulRead(42, 483567314231L, ins.readSInt64())
|
assertSuccessfulRead(483567314231L, ins.readSInt64(42))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testBoolean() {
|
fun testBoolean() {
|
||||||
@@ -99,8 +99,8 @@ fun testBoolean() {
|
|||||||
outs.writeBool(2, false)
|
outs.writeBool(2, false)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(1, true, ins.readBool())
|
assertSuccessfulRead(true, ins.readBool(1))
|
||||||
assertSuccessfulRead(2, false, ins.readBool())
|
assertSuccessfulRead(false, ins.readBool(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testEnum() {
|
fun testEnum() {
|
||||||
@@ -110,8 +110,8 @@ fun testEnum() {
|
|||||||
outs.writeEnum(2, WireType.FIX_64.ordinal)
|
outs.writeEnum(2, WireType.FIX_64.ordinal)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(1, WireType.END_GROUP.ordinal, ins.readEnum())
|
assertSuccessfulRead(WireType.END_GROUP.ordinal, ins.readEnum(1))
|
||||||
assertSuccessfulRead(2, WireType.FIX_64.ordinal, ins.readEnum())
|
assertSuccessfulRead(WireType.FIX_64.ordinal, ins.readEnum(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testFloatAndDouble() {
|
fun testFloatAndDouble() {
|
||||||
@@ -122,9 +122,9 @@ fun testFloatAndDouble() {
|
|||||||
outs.writeFloat(14, -1.32131321f)
|
outs.writeFloat(14, -1.32131321f)
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(42, 123212.34282, ins.readDouble())
|
assertSuccessfulRead(123212.34282, ins.readDouble(42))
|
||||||
assertSuccessfulRead(15, Math.PI, ins.readDouble())
|
assertSuccessfulRead(Math.PI, ins.readDouble(15))
|
||||||
assertSuccessfulRead(14, -1.32131321f, ins.readFloat())
|
assertSuccessfulRead(-1.32131321f, ins.readFloat(14))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testStrings() {
|
fun testStrings() {
|
||||||
@@ -134,14 +134,12 @@ fun testStrings() {
|
|||||||
outs.writeString(15, """!@#$%^&*()QWERTYUI выфвфывфы""")
|
outs.writeString(15, """!@#$%^&*()QWERTYUI выфвфывфы""")
|
||||||
|
|
||||||
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
val ins = CodedInputStream(ByteArrayInputStream(s.toByteArray()))
|
||||||
assertSuccessfulRead(42, "dasddasd asd ", ins.readString())
|
assertSuccessfulRead("dasddasd asd ", ins.readString(42))
|
||||||
assertSuccessfulRead(15, """!@#$%^&*()QWERTYUI выфвфывфы""", ins.readString())
|
assertSuccessfulRead("""!@#$%^&*()QWERTYUI выфвфывфы""", ins.readString(15))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> assertSuccessfulRead(fieldNumber: Int, value: T, field: CodedInputStream.Field<T>) {
|
fun <T> assertSuccessfulRead(value: T, actualValue: T) {
|
||||||
assert(field.fieldNumber == fieldNumber)
|
assert(actualValue == value)
|
||||||
assert(field.wireType == WireType.VARINT)
|
|
||||||
assert(field.value == value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user