Skip to content

Commit

Permalink
More efficient serialization of time zone offsets + code clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
plokhotnyuk committed Dec 28, 2022
1 parent 713d5e4 commit 0d60ffe
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 201 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ final class JsonReader private[jsoniter_scala](
val x = new Array[Byte](len)
System.arraycopy(buf, from, x, 0, len)
x
} finally if (mark != 0 || oldMark < 0) mark = oldMark
} finally if (mark > oldMark) mark = oldMark
}

def readNullOrError[@sp A](default: A, msg: String): A =
Expand Down Expand Up @@ -828,7 +828,7 @@ final class JsonReader private[jsoniter_scala](
val b3 = buf(pos + 2)
val b4 = buf(pos + 3)
val b5 = buf(pos + 4)
val yearNeg = b1 == '-' || (b1 != '+' && decodeError("expected '-' or '+' or digit", pos))
val isNeg = b1 == '-' || (b1 != '+' && decodeError("expected '-' or '+' or digit", pos))
if (b2 < '0' || b2 > '9') digitError(pos + 1)
if (b3 < '0' || b3 > '9') digitError(pos + 2)
if (b4 < '0' || b4 > '9') digitError(pos + 3)
Expand All @@ -852,9 +852,9 @@ final class JsonReader private[jsoniter_scala](
pos += 1
}
head = pos + 1
if (yearNeg && year == 0 || yearDigits == 10 && year > 1000000000) yearError(pos - 1)
if (b != t) yearError(t, maxDigits, pos, yearNeg, yearDigits)
if (yearNeg) year = -year
if (isNeg && year == 0 || yearDigits == 10 && year > 1000000000) yearError(pos - 1)
if (b != t) yearError(t, maxDigits, pos, isNeg, yearDigits)
if (isNeg) year = -year
if (year >= 0 && year < 10000) digitError(pos)
year
}
Expand Down Expand Up @@ -1064,7 +1064,7 @@ final class JsonReader private[jsoniter_scala](
zoneId
} catch {
case ex: DateTimeException => timezoneError(ex)
} finally if (mark != 0 || oldMark < 0) mark = oldMark
} finally if (mark > oldMark) mark = oldMark
}

@tailrec
Expand Down Expand Up @@ -1413,7 +1413,7 @@ final class JsonReader private[jsoniter_scala](
} else toDouble(m10, e10, from, newMark, pos)
if (isNeg) x = -x
x
} finally if (mark != 0 || oldMark < 0) mark = oldMark
} finally if (mark > oldMark) mark = oldMark
}

// Based on the 'Moderate Path' algorithm from the awesome library of Alexander Huszagh: https://github.com/Alexhuszagh/rust-lexical
Expand Down Expand Up @@ -1554,7 +1554,7 @@ final class JsonReader private[jsoniter_scala](
} else toFloat(m10, e10, from, newMark, pos)
if (isNeg) x = -x
x
} finally if (mark != 0 || oldMark < 0) mark = oldMark
} finally if (mark > oldMark) mark = oldMark
}

// Based on the 'Moderate Path' algorithm from the awesome library of Alexander Huszagh: https://github.com/Alexhuszagh/rust-lexical
Expand Down Expand Up @@ -1645,7 +1645,7 @@ final class JsonReader private[jsoniter_scala](
if (mark == 0) from -= newMark
if (pos - from >= digitsLimit) digitsLimitError(from + digitsLimit - 1)
new BigInt(toBigDecimal(buf, from, pos, isNeg, 0).unscaledValue)
} finally if (mark != 0 || oldMark < 0) mark = oldMark
} finally if (mark > oldMark) mark = oldMark
}
}
}
Expand Down Expand Up @@ -1762,10 +1762,10 @@ final class JsonReader private[jsoniter_scala](
} else toBigDecimal(buf, from, fracLimit, isNeg, scale)
.add(toBigDecimal(buf, fracPos, limit, isNeg, scale + fracLen))
} else toBigDecimal(buf, from, from + digits, isNeg, scale)
if (digits > mc.getPrecision) x = x.plus(mc)
if (mc.getPrecision < digits) x = x.plus(mc)
if (Math.abs(x.scale) >= scaleLimit) scaleLimitError()
new BigDecimal(x, mc)
} finally if (mark != 0 || oldMark < 0) mark = oldMark
} finally if (mark > oldMark) mark = oldMark
}
}

Expand Down Expand Up @@ -2016,10 +2016,10 @@ final class JsonReader private[jsoniter_scala](
}
if (b == 'Z') nextByteOrError('"', head)
else {
val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight))
val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight))
var offsetTotal = parseOffsetTotalWithDoubleQuotes(head)
if (offsetTotal > 64800) timezoneOffsetError() // 64800 == 18 * 60 * 60
if (offsetNeg) offsetTotal = -offsetTotal
if (isNeg) offsetTotal = -offsetTotal
epochSecond -= offsetTotal
}
Instant.ofEpochSecond(epochSecond, nano)
Expand Down Expand Up @@ -2264,7 +2264,7 @@ final class JsonReader private[jsoniter_scala](
b = nextByte(head)
ZoneOffset.UTC
} else {
val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight))
val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight))
nanoDigitWeight = -3
var offsetTotal = parseOffsetHour(head) * 3600
b = nextByte(head)
Expand All @@ -2277,7 +2277,7 @@ final class JsonReader private[jsoniter_scala](
b = nextByte(head)
}
}
toZoneOffset(offsetNeg, offsetTotal)
toZoneOffset(isNeg, offsetTotal)
}
if (b == '"') ZonedDateTime.ofLocal(localDateTime, zoneOffset, null)
else if (b == '[') {
Expand Down Expand Up @@ -2378,8 +2378,8 @@ final class JsonReader private[jsoniter_scala](
case 3 => "expected 'S or '.' or digit"
}, pos)

private[this] def yearError(t: Byte, maxDigits: Int, pos: Int, yearNeg: Boolean, yearDigits: Int): Nothing = {
if (!yearNeg && yearDigits == 4) digitError(pos)
private[this] def yearError(t: Byte, maxDigits: Int, pos: Int, isNeg: Boolean, yearDigits: Int): Nothing = {
if (!isNeg && yearDigits == 4) digitError(pos)
if (yearDigits == maxDigits) tokenError(t, pos)
tokenOrDigitError(t, pos)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1622,14 +1622,13 @@ final class JsonWriter private[jsoniter_scala](
}

private[this] def writeLocalTime(secsOfDay: Int, nano: Int, p: Int, buf: Array[Byte], ds: Array[Short]): Int = {
val hour = secsOfDay * 37283 >>> 27 // divide a small positive int by 3600
var pos = write2Digits(hour, p, buf, ds)
var y = secsOfDay * 37283 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/
var pos = write2Digits(y >>> 27, p, buf, ds)
buf(pos) = ':'
val secsOfHour = secsOfDay - hour * 3600
val minute = secsOfHour * 17477 >> 20 // divide a small positive int by 60
pos = write2Digits(minute, pos + 1, buf, ds)
y = (y & 0x7FFFFFF) * 15
pos = write2Digits(y >> 25, pos + 1, buf, ds)
buf(pos) = ':'
pos = write2Digits(secsOfHour - minute * 60, pos + 1, buf, ds)
pos = write2Digits(((y & 0x1FFFFFF) * 15) >> 23, pos + 1, buf, ds)
if (nano != 0) writeNanos(nano, pos, buf, ds)
else pos
}
Expand Down Expand Up @@ -1658,36 +1657,30 @@ final class JsonWriter private[jsoniter_scala](
}

private[this] def writeOffset(x: ZoneOffset, p: Int, buf: Array[Byte], ds: Array[Short]): Int = {
val totalSeconds = x.getTotalSeconds
if (totalSeconds == 0) {
var y = x.getTotalSeconds
if (y == 0) {
buf(p) = 'Z'
p + 1
} else {
val q0 =
if (totalSeconds > 0) {
buf(p) = '+'
totalSeconds
} else {
buf(p) = '-'
-totalSeconds
}
val p1 = q0 * 37283
val q1 = p1 >>> 27 // divide a small positive int by 3600
var pos = write2Digits(q1, p + 1, buf, ds)
if (y > 0) buf(p) = '+'
else {
buf(p) = '-'
y = -y
}
y *= 37283 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/
var pos = write2Digits(y >>> 27, p + 1, buf, ds)
buf(pos) = ':'
if ((p1 & 0x7FF8000) == 0) { // check if q0 is divisible by 3600
if ((y & 0x7FF8000) == 0) { // check if totalSeconds is divisible by 3600
buf(pos + 1) = '0'
buf(pos + 2) = '0'
pos + 3
} else {
val r1 = q0 - q1 * 3600
val p2 = r1 * 17477
val q2 = p2 >> 20 // divide a small positive int by 60
pos = write2Digits(q2, pos + 1, buf, ds)
if ((p2 & 0xFC000) == 0) pos // check if r1 is divisible by 60
y = (y & 0x7FFFFFF) * 15
pos = write2Digits(y >> 25, pos + 1, buf, ds)
if ((y & 0x1F80000) == 0) pos // check if totalSeconds is divisible by 60
else {
buf(pos) = ':'
write2Digits(r1 - q2 * 60, pos + 1, buf, ds)
write2Digits((y & 0x1FFFFFF) * 15 >> 23, pos + 1, buf, ds)
}
}
}
Expand Down Expand Up @@ -1861,7 +1854,7 @@ final class JsonWriter private[jsoniter_scala](
expShift = 1
}
} else if (ieeeExponent == 255) illegalNumberError(x)
if (ieeeMantissa == 0 && ieeeExponent > 1) {
else if (ieeeMantissa == 0 && ieeeExponent > 1) {
expCorr = 131007
cblShift = 1
}
Expand Down Expand Up @@ -1985,7 +1978,7 @@ final class JsonWriter private[jsoniter_scala](
expShift = 1
}
} else if (ieeeExponent == 2047) illegalNumberError(x)
if (ieeeMantissa == 0 && ieeeExponent > 1) {
else if (ieeeMantissa == 0 && ieeeExponent > 1) {
expCorr = 131007
cblShift = 1
}
Expand Down Expand Up @@ -2106,11 +2099,11 @@ final class JsonWriter private[jsoniter_scala](
else {
val q1 = q0 / 100000000
val r1 = (q0 - q1 * 100000000).toInt
if (r1 == 0) writeSignificantFractionDigits(q1.toInt, pos - 8, posLim, buf, ds)
val posm8 = pos - 8
if (r1 == 0) writeSignificantFractionDigits(q1.toInt, posm8, posLim, buf, ds)
else {
val lastPos = writeSignificantFractionDigits(r1, pos, pos - 8, buf, ds)
writeFractionDigits(q1.toInt, pos - 8, posLim, buf, ds)
lastPos
writeFractionDigits(q1.toInt, posm8, posLim, buf, ds)
writeSignificantFractionDigits(r1, pos, posm8, buf, ds)
}
}

Expand All @@ -2129,7 +2122,7 @@ final class JsonWriter private[jsoniter_scala](
val d = ds(r1)
buf(pos - 1) = d.toByte
var lastPos = pos
if (d > 12345) { // 12345 == ('0' << 8) | '9'
if (d > 0x3039) {
buf(pos) = (d >> 8).toByte
lastPos += 1
}
Expand Down
Loading

0 comments on commit 0d60ffe

Please sign in to comment.