Skip to content

Commit 855f9bd

Browse files
committed
Faster skipping of JSON values
1 parent 528e1ac commit 855f9bd

File tree

1 file changed

+42
-24
lines changed
  • zio-json/shared/src/main/scala/zio/json/internal

1 file changed

+42
-24
lines changed

zio-json/shared/src/main/scala/zio/json/internal/lexer.scala

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -103,32 +103,17 @@ object Lexer {
103103
matrix.first(bs)
104104
}
105105

106-
private[this] val ull: Array[Char] = "ull".toCharArray
107106
private[this] val alse: Array[Char] = "alse".toCharArray
108107
private[this] val rue: Array[Char] = "rue".toCharArray
109108

110109
def skipValue(trace: List[JsonError], in: RetractReader): Unit =
111110
(in.nextNonWhitespace(): @switch) match {
112-
case 'n' => readChars(trace, in, ull, "null")
113-
case 'f' => readChars(trace, in, alse, "false")
114-
case 't' => readChars(trace, in, rue, "true")
115-
case '{' =>
116-
if (firstField(trace, in)) {
117-
while ({
118-
{
119-
char(trace, in, '"')
120-
skipString(trace, in)
121-
char(trace, in, ':')
122-
skipValue(trace, in)
123-
}; nextField(trace, in)
124-
}) ()
125-
}
126-
case '[' =>
127-
if (firstArrayElement(in)) {
128-
while ({ skipValue(trace, in); nextArrayElement(trace, in) }) ()
129-
}
111+
case 'n' | 't' => skipFixedChars(in, 3)
112+
case 'f' => skipFixedChars(in, 4)
113+
case '{' => skipObject(in, 0)
114+
case '[' => skipArray(in, 0)
130115
case '"' =>
131-
skipString(trace, in)
116+
skipString(in, evenBackSlashes = true)
132117
case '-' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' =>
133118
skipNumber(in)
134119
case c => throw UnsafeJson(JsonError.Message(s"unexpected '$c'") :: trace)
@@ -139,10 +124,43 @@ object Lexer {
139124
in.retract()
140125
}
141126

142-
def skipString(trace: List[JsonError], in: OneCharReader): Unit = {
143-
val stream = new EscapedString(trace, in)
144-
var i: Int = 0
145-
while ({ i = stream.read(); i != -1 }) ()
127+
def skipString(trace: List[JsonError], in: OneCharReader): Unit =
128+
skipString(in, evenBackSlashes = true)
129+
130+
@tailrec
131+
private def skipFixedChars(in: OneCharReader, n: Int): Unit =
132+
if (n > 0) {
133+
in.readChar()
134+
skipFixedChars(in, n - 1)
135+
}
136+
137+
@tailrec
138+
private def skipString(in: OneCharReader, evenBackSlashes: Boolean): Unit =
139+
if (evenBackSlashes) {
140+
val ch = in.readChar()
141+
if (ch != '"') skipString(in, ch != '\\')
142+
} else skipString(in, evenBackSlashes = true)
143+
144+
@tailrec
145+
private def skipObject(in: OneCharReader, level: Int = 0): Unit = {
146+
val ch = in.readChar()
147+
if (ch == '"') {
148+
skipString(in, evenBackSlashes = true)
149+
skipObject(in, level)
150+
} else if (ch == '{') skipObject(in, level + 1)
151+
else if (ch != '}') skipObject(in, level)
152+
else if (level != 0) skipObject(in, level - 1)
153+
}
154+
155+
@tailrec
156+
private def skipArray(in: OneCharReader, level: Int = 0): Unit = {
157+
val b = in.readChar()
158+
if (b == '"') {
159+
skipString(in, evenBackSlashes = true)
160+
skipArray(in, level)
161+
} else if (b == '[') skipArray(in, level + 1)
162+
else if (b != ']') skipArray(in, level)
163+
else if (level != 0) skipArray(in, level - 1)
146164
}
147165

148166
// useful for embedded documents, e.g. CSV contained inside JSON

0 commit comments

Comments
 (0)