summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMathias <mathias@spray.io>2013-05-13 13:11:37 +0200
committerMathias <mathias@spray.io>2013-05-13 13:32:19 +0200
commit6094c9da1e23ff00fdf9fa4390d2ae4c82c7096c (patch)
tree36a3018eff9810e10ae70c798217f4f42475755d /src
parent8dff7ed4d9635aae3ae17a722fe6f1ea4376a215 (diff)
downloadspray-json-6094c9da1e23ff00fdf9fa4390d2ae4c82c7096c.tar.gz
spray-json-6094c9da1e23ff00fdf9fa4390d2ae4c82c7096c.tar.bz2
spray-json-6094c9da1e23ff00fdf9fa4390d2ae4c82c7096c.zip
Add small performance improvement in JsonPrinter
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/spray/json/JsonPrinter.scala71
1 files changed, 49 insertions, 22 deletions
diff --git a/src/main/scala/spray/json/JsonPrinter.scala b/src/main/scala/spray/json/JsonPrinter.scala
index 258c881..e47989e 100644
--- a/src/main/scala/spray/json/JsonPrinter.scala
+++ b/src/main/scala/spray/json/JsonPrinter.scala
@@ -55,28 +55,35 @@ trait JsonPrinter extends (JsValue => String) {
}
protected def printString(s: String, sb: StringBuilder) {
- @tailrec
- def printEscaped(s: String, ix: Int) {
- if (ix < s.length) {
- s.charAt(ix) match {
- case '"' => sb.append("\\\"")
- case '\\' => sb.append("\\\\")
- case x if 0x20 <= x && x < 0x7F => sb.append(x)
- case '\b' => sb.append("\\b")
- case '\f' => sb.append("\\f")
- case '\n' => sb.append("\\n")
- case '\r' => sb.append("\\r")
- case '\t' => sb.append("\\t")
- case x if x <= 0xF => sb.append("\\u000").append(Integer.toHexString(x))
- case x if x <= 0xFF => sb.append("\\u00").append(Integer.toHexString(x))
- case x if x <= 0xFFF => sb.append("\\u0").append(Integer.toHexString(x))
- case x => sb.append("\\u").append(Integer.toHexString(x))
- }
- printEscaped(s, ix + 1)
- }
- }
+ import JsonPrinter._
+ @tailrec def firstToBeEncoded(ix: Int = 0): Int =
+ if (ix == s.length) -1 else if (requiresEncoding(s.charAt(ix))) ix else firstToBeEncoded(ix + 1)
+
sb.append('"')
- printEscaped(s, 0)
+ firstToBeEncoded() match {
+ case -1 ⇒ sb.append(s)
+ case first ⇒
+ sb.append(s, 0, first)
+ @tailrec def append(ix: Int): Unit =
+ if (ix < s.length) {
+ s.charAt(ix) match {
+ case c if !requiresEncoding(c) => sb.append(c)
+ case '"' => sb.append("\\\"")
+ case '\\' => sb.append("\\\\")
+ case '\b' => sb.append("\\b")
+ case '\f' => sb.append("\\f")
+ case '\n' => sb.append("\\n")
+ case '\r' => sb.append("\\r")
+ case '\t' => sb.append("\\t")
+ case x if x <= 0xF => sb.append("\\u000").append(Integer.toHexString(x))
+ case x if x <= 0xFF => sb.append("\\u00").append(Integer.toHexString(x))
+ case x if x <= 0xFFF => sb.append("\\u0").append(Integer.toHexString(x))
+ case x => sb.append("\\u").append(Integer.toHexString(x))
+ }
+ append(ix + 1)
+ }
+ append(first)
+ }
sb.append('"')
}
@@ -87,4 +94,24 @@ trait JsonPrinter extends (JsValue => String) {
f(a)
}
}
-} \ No newline at end of file
+}
+
+object JsonPrinter {
+ private[this] val mask = new Array[Int](4)
+ private[this] def ascii(c: Char): Int = c & ((c - 127) >> 31) // branchless for `if (c <= 127) c else 0`
+ private[this] def mark(c: Char): Unit = {
+ val b = ascii(c)
+ mask(b >> 5) |= 1 << (b & 0x1F)
+ }
+ private[this] def mark(range: scala.collection.immutable.NumericRange[Char]): Unit = range foreach (mark)
+
+ mark('\u0000' to '\u0019')
+ mark('\u007f')
+ mark('"')
+ mark('\\')
+
+ def requiresEncoding(c: Char): Boolean = {
+ val b = ascii(c)
+ (mask(b >> 5) & (1 << (b & 0x1F))) != 0
+ }
+} \ No newline at end of file