Skip to content

Commit

Permalink
Optimize JsonReader further -- don't make conditional array lookups w…
Browse files Browse the repository at this point in the history
…here they are not really necessary

It gives solid 5-10% of throughpuut
  • Loading branch information
qwwdfsad committed Feb 18, 2021
1 parent e9d4d3e commit 9fd2412
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal class JsonParser(
}

private fun readArray(): JsonElement {
var lastToken = reader.consumeNextToken(TC_BEGIN_LIST)
var lastToken = reader.consumeNextToken()
// Prohibit leading comma
if (reader.peekNextToken() == TC_COMMA) reader.fail("Unexpected leading comma")
val result = arrayListOf<JsonElement>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ internal class JsonReader(private val source: String) {
private var length = 0 // length of string
private var buf = CharArray(16) // only used for strings with escapes

// TODO consider replacing usages of this method in JsonParser with char overload
fun consumeNextToken(expected: Byte): Byte {
val token = consumeNextToken()
if (token != expected) {
Expand All @@ -174,6 +175,17 @@ internal class JsonReader(private val source: String) {
return token
}

fun consumeNextToken(expected: Char) {
val source = source
while (currentPosition < source.length) {
val c = source[currentPosition++]
if (c == ' ' || c == '\n' || c == '\r' || c == '\t') continue
if (c == expected) return
fail(charToTokenClass(expected))
}
fail(charToTokenClass(expected)) // EOF
}

private fun fail(expectedToken: Byte) {
// We know that the token was consumed prior to this call
// Slow path, never called in normal code, can avoid optimizing it
Expand Down Expand Up @@ -288,7 +300,6 @@ internal class JsonReader(private val source: String) {
}
val startPosition = currentPosition - 1
var lastPosition = currentPosition
length = 0
var char = source[currentPosition] // Avoid two double checks visible in the profiler
while (char != STRING) {
if (char == STRING_ESC) {
Expand All @@ -308,7 +319,10 @@ internal class JsonReader(private val source: String) {
} else {
// some escaped chars were there
appendRange(source, lastPosition, currentPosition)
buf.concatToString(0, length)
val l = length
length = 0
buf.concatToString(0, l)

}
this.currentPosition = currentPosition + 1
return string
Expand All @@ -325,14 +339,17 @@ internal class JsonReader(private val source: String) {
* `indexOf` for escape symbol. It works almost 20% faster for both large and small JSON strings.
*/
fun consumeKeyString(): String {
consumeNextToken(TC_STRING)
consumeNextToken(STRING)
val current = currentPosition
val closingQuote = source.indexOf('"', current)
if (closingQuote == -1) fail(TC_STRING) // Better error message?
// TODO explain
for (i in current until closingQuote) {
// Encountered escape sequence, should fallback to "slow" path
if (source[i] == '\\') TODO()
if (source[i] == '\\') {
TODO()
break
}
}
this.currentPosition = closingQuote + 1
return source.substring(current, closingQuote)
Expand Down Expand Up @@ -493,8 +510,7 @@ internal class JsonReader(private val source: String) {
++current
hasChars = current != source.length
val digit = ch - '0'
if (digit !in 0..9)
fail("Unexpected symbol '$ch' in numeric literal")
if (digit !in 0..9) fail("Unexpected symbol '$ch' in numeric literal")
accumulator = accumulator * 10 - digit
if (accumulator > 0) fail("Numeric value overflow")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal open class StreamingJsonDecoder(

override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
val newMode = json.switchMode(descriptor)
reader.consumeNextToken(newMode.beginTc)
reader.consumeNextToken(newMode.begin)
checkLeadingComma()
return when (newMode) {
// In fact resets current index that these modes rely on
Expand All @@ -52,7 +52,7 @@ internal open class StreamingJsonDecoder(
}

override fun endStructure(descriptor: SerialDescriptor) {
reader.consumeNextToken(mode.endTc)
reader.consumeNextToken(mode.end)
}

override fun decodeNotNullMark(): Boolean {
Expand Down Expand Up @@ -86,7 +86,7 @@ internal open class StreamingJsonDecoder(
hasComma = reader.tryConsumeComma()
}
} else {
reader.consumeNextToken(TC_COLON)
reader.consumeNextToken(COLON)
}

return if (reader.canConsumeValue()) {
Expand Down Expand Up @@ -126,7 +126,7 @@ internal open class StreamingJsonDecoder(
while (reader.canConsumeValue()) { // TODO: consider merging comma consumption and this check
hasComma = false
val key = decodeStringKey()
reader.consumeNextToken(TC_COLON)
reader.consumeNextToken(COLON)
val index = descriptor.getElementIndex(key)
val isUnknown = if (index != UNKNOWN_NAME) {
if (configuration.coerceInputValues && coerceInputValue(descriptor, index)) {
Expand Down

0 comments on commit 9fd2412

Please sign in to comment.