From 713d5e4c92d4c16f7e0a465fa94f8454e72afaca Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Fri, 23 Dec 2022 14:02:39 +0100 Subject: [PATCH 1/5] Setting version to 2.20.1-SNAPSHOT --- version.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sbt b/version.sbt index 52bc12540..a2e122185 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "2.20.0" +ThisBuild / version := "2.20.1-SNAPSHOT" From 0d60ffe6d5c8593bd85c7663b04517d9729353ba Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Sun, 25 Dec 2022 14:27:28 +0100 Subject: [PATCH 2/5] More efficient serialization of time zone offsets + code clean up --- .../jsoniter_scala/core/JsonReader.scala | 34 +++---- .../jsoniter_scala/core/JsonWriter.scala | 59 +++++------- .../jsoniter_scala/core/JsonReader.scala | 48 +++++----- .../jsoniter_scala/core/JsonWriter.scala | 95 +++++++++---------- .../jsoniter_scala/core/JsonReader.scala | 46 ++++----- .../jsoniter_scala/core/JsonWriter.scala | 95 +++++++++---------- 6 files changed, 176 insertions(+), 201 deletions(-) diff --git a/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala b/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala index 809df298a..76da73db3 100644 --- a/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala +++ b/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala @@ -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 = @@ -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) @@ -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 } @@ -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 @@ -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 @@ -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 @@ -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 } } } @@ -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 } } @@ -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) @@ -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) @@ -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 == '[') { @@ -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) } diff --git a/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala b/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala index 5c672fe82..86bf642f9 100644 --- a/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala +++ b/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala @@ -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 } @@ -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) } } } @@ -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 } @@ -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 } @@ -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) } } @@ -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 } diff --git a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala index 6dce1539d..80be2dd4e 100644 --- a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala +++ b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala @@ -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 } @tailrec @@ -858,7 +858,7 @@ final class JsonReader private[jsoniter_scala]( val b3 = (bs >> 16).toByte val b4 = (bs >> 24).toByte 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) @@ -882,9 +882,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 } @@ -1118,7 +1118,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 } private[this] def appendChar(ch: Char, i: Int): Int = { @@ -1460,7 +1460,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 @@ -1601,7 +1601,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 @@ -1646,7 +1646,7 @@ final class JsonReader private[jsoniter_scala]( } private[this] def unsignedMultiplyHigh(x: Long, y: Long): Long = - Math.multiplyHigh(x, y) + x + y // Use implementation that works only when both params are negative + Math.multiplyHigh(x, y) + (x + y) // Use implementation that works only when both params are negative private[this] def parseBigInt(isToken: Boolean, default: BigInt, digitsLimit: Int): BigInt = { var b = @@ -1699,7 +1699,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 } } } @@ -1836,10 +1836,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 } } @@ -2193,7 +2193,7 @@ final class JsonReader private[jsoniter_scala]( } if (b == 'Z') nextByteOrError('"', pos) else { - val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) + val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 @@ -2204,7 +2204,7 @@ final class JsonReader private[jsoniter_scala]( head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) if (offsetTotal > 64800) timezoneOffsetError() // 64800 == 18 * 60 * 60 - if (offsetNeg) offsetTotal = -offsetTotal + if (isNeg) offsetTotal = -offsetTotal secondOfDay -= offsetTotal } Instant.ofEpochSecond(epochDaySeconds + secondOfDay, nano) @@ -2408,7 +2408,7 @@ final class JsonReader private[jsoniter_scala]( nextByteOrError('"', pos) ZoneOffset.UTC } else { - val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) + val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 @@ -2418,7 +2418,7 @@ final class JsonReader private[jsoniter_scala]( offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) - toZoneOffset(offsetNeg, offsetTotal.toInt) + toZoneOffset(isNeg, offsetTotal.toInt) } OffsetDateTime.of(year, monthDay & 0xFF, monthDay >> 24, hourMinute & 0xFF, hourMinute >> 24, second, nano, zoneOffset) } @@ -2500,7 +2500,7 @@ final class JsonReader private[jsoniter_scala]( nextByteOrError('"', pos) ZoneOffset.UTC } else { - val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) + val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 @@ -2510,7 +2510,7 @@ final class JsonReader private[jsoniter_scala]( offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) - toZoneOffset(offsetNeg, offsetTotal.toInt) + toZoneOffset(isNeg, offsetTotal.toInt) } OffsetTime.of(hourMinute & 0xFF, hourMinute >> 24, second, nano, zoneOffset) } @@ -2668,7 +2668,7 @@ final class JsonReader private[jsoniter_scala]( b = nextByte(pos) ZoneOffset.UTC } else { - val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) + val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) nanoDigitWeight = -3 var offsetTotal = 0L if (pos + 7 < tail && { @@ -2692,7 +2692,7 @@ final class JsonReader private[jsoniter_scala]( } } } - toZoneOffset(offsetNeg, offsetTotal.toInt) + toZoneOffset(isNeg, offsetTotal.toInt) } if (b == '"') ZonedDateTime.ofLocal(localDateTime, zoneOffset, null) else if (b == '[') { @@ -2709,7 +2709,7 @@ final class JsonReader private[jsoniter_scala]( nextByteOrError('"', pos) ZoneOffset.UTC } else { - val offsetNeg = b == '-' || (b != '+' && decodeError("expected '+' or '-' or 'Z'")) + val isNeg = b == '-' || (b != '+' && decodeError("expected '+' or '-' or 'Z'")) var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 @@ -2719,7 +2719,7 @@ final class JsonReader private[jsoniter_scala]( offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) - toZoneOffset(offsetNeg, offsetTotal.toInt) + toZoneOffset(isNeg, offsetTotal.toInt) } } @@ -2817,8 +2817,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) } diff --git a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala index 86c82ecec..3df0567c2 100644 --- a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala +++ b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala @@ -1229,7 +1229,7 @@ final class JsonWriter private[jsoniter_scala]( val buf = this.buf val ds = digits buf(pos) = '"' - pos = writeLocalTime(epochSecond - epochDay * 86400, x.getNano, writeLocalDateWithT(year, month, day, pos + 1, buf, ds), buf, ds) + pos = writeLocalTime((epochSecond - epochDay * 86400).toInt, x.getNano, writeLocalDateWithT(year, month, day, pos + 1, buf, ds), buf, ds) ByteArrayAccess.setShort(buf, pos, 0x225A) pos + 2 } @@ -1302,12 +1302,10 @@ final class JsonWriter private[jsoniter_scala]( private[this] def writePeriod(x: Period): Unit = count = { var pos = ensureBufCapacity(39) // 39 == "P-2147483648Y-2147483648M-2147483648D".length + 2 val buf = this.buf - ByteArrayAccess.setShort(buf, pos, 0x5022) - pos += 2 - if (x eq Period.ZERO) { - ByteArrayAccess.setShort(buf, pos, 0x4430) + ByteArrayAccess.setInt(buf, pos, 0x44305022) + if (x eq Period.ZERO) pos += 4 + else { pos += 2 - } else { val ds = digits val years = x.getYears val months = x.getMonths @@ -1385,32 +1383,28 @@ final class JsonWriter private[jsoniter_scala]( private[this] def writeZoneOffset(x: ZoneOffset): Unit = count = { val pos = ensureBufCapacity(12) // 12 == number of bytes in Long and Int val buf = this.buf - var q0 = x.getTotalSeconds - if (q0 == 0) { + var y = x.getTotalSeconds + if (y == 0) { ByteArrayAccess.setInt(buf, pos, 0x225A22) pos + 3 } else { val ds = digits var m = 0x2230303A00002B22L - if (q0 < 0) { - q0 = -q0 + if (y < 0) { + y = -y m = 0x2230303A00002D22L } - val p1 = q0 * 37283 - val q1 = p1 >>> 27 // divide a small positive int by 3600 - m |= ds(q1) << 16 - if ((p1 & 0x7FF8000) == 0) { // check if q0 is divisible by 3600 + y *= 37283 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ + m |= ds(y >>> 27) << 16 + if ((y & 0x7FF8000) == 0) { // check if totalSeconds is divisible by 3600 ByteArrayAccess.setLong(buf, pos, m) pos + 8 } else { - val r1 = q0 - q1 * 3600 - val p2 = r1 * 17477 - val q2 = p2 >> 20 // divide a small positive int by 60 - m |= ds(q2).toLong << 40 - ByteArrayAccess.setLong(buf, pos, m) - if ((p2 & 0xFC000) == 0) pos + 8 // check if r1 is divisible by 60 + y = (y & 0x7FFFFFF) * 15 + ByteArrayAccess.setLong(buf, pos, ds(y >> 25).toLong << 40 | m) + if ((y & 0x1F80000) == 0) pos + 8 // check if totalSeconds is divisible by 60 else { - ByteArrayAccess.setInt(buf, pos + 7, ds(r1 - q2 * 60) << 8 | 0x2200003A) + ByteArrayAccess.setInt(buf, pos + 7, ds((y & 0x1FFFFFF) * 15 >> 23) << 8 | 0x2200003A) pos + 11 } } @@ -1465,13 +1459,13 @@ final class JsonWriter private[jsoniter_scala]( } } - private[this] def writeLocalTime(secsOfDay: Long, nano: Int, pos: Int, buf: Array[Byte], ds: Array[Short]): Int = { - val y1 = secsOfDay * 1193047 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ - val y2 = (y1 & 0xFFFFFFFFL) * 60 - val y3 = (y2 & 0xFFFFFFFFL) * 60 - val d1 = ds((y1 >> 32).toInt) | 0x3A00003A0000L - val d2 = ds((y2 >> 32).toInt).toLong << 24 - val d3 = ds((y3 >> 32).toInt).toLong << 48 + private[this] def writeLocalTime(secsOfDay: Int, nano: Int, pos: Int, buf: Array[Byte], ds: Array[Short]): Int = { + val y1 = secsOfDay * 37283 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ + val y2 = (y1 & 0x7FFFFFF) * 15 + val y3 = (y2 & 0x1FFFFFF) * 15 + val d1 = ds(y1 >>> 27) | 0x3A00003A0000L + val d2 = ds(y2 >> 25).toLong << 24 + val d3 = ds(y3 >> 23).toLong << 48 ByteArrayAccess.setLong(buf, pos, d1 | d2 | d3) if (nano == 0) pos + 8 else writeNanos(nano, pos + 8, buf, ds) @@ -1499,30 +1493,27 @@ final class JsonWriter private[jsoniter_scala]( } private[this] def writeOffset(x: ZoneOffset, pos: Int, buf: Array[Byte], ds: Array[Short]): Int = { - var q0 = x.getTotalSeconds - if (q0 == 0) { + var y = x.getTotalSeconds + if (y == 0) { ByteArrayAccess.setShort(buf, pos, 0x225A) pos + 2 } else { var m = 0x2230303A00002BL - if (q0 < 0) { - q0 = -q0 + if (y < 0) { + y = -y m = 0x2230303A00002DL } - val p1 = q0 * 37283 - val q1 = p1 >>> 27 // divide a small positive int by 3600 - m |= ds(q1) << 8 - if ((p1 & 0x7FF8000) == 0) { // check if q0 is divisible by 3600 + y *= 37283 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ + m |= ds(y >>> 27) << 8 + if ((y & 0x7FF8000) == 0) { // check if totalSeconds is divisible by 3600 ByteArrayAccess.setLong(buf, pos, m) pos + 7 } else { - val r1 = q0 - q1 * 3600 - val p2 = r1 * 17477 - val q2 = p2 >> 20 // divide a small positive int by 60 - ByteArrayAccess.setLong(buf, pos, ds(q2).toLong << 32 | m) - if ((p2 & 0xFC000) == 0) pos + 7 // check if r1 is divisible by 60 + y = (y & 0x7FFFFFF) * 15 + ByteArrayAccess.setLong(buf, pos, ds(y >> 25).toLong << 32 | m) + if ((y & 0x1F80000) == 0) pos + 7 // check if totalSeconds is divisible by 60 else { - ByteArrayAccess.setInt(buf, pos + 6, ds(r1 - q2 * 60) << 8 | 0x2200003A) + ByteArrayAccess.setInt(buf, pos + 6, ds((y & 0x1FFFFFF) * 15 >> 23) << 8 | 0x2200003A) pos + 10 } } @@ -1553,10 +1544,10 @@ final class JsonWriter private[jsoniter_scala]( val y2 = (y1 & 0x7FFFFFFFFFFFL) * 100 val y3 = (y2 & 0x7FFFFFFFFFFFL) * 100 val y4 = (y3 & 0x7FFFFFFFFFFFL) * 100 - val d1 = ds((y1 >>> 47).toInt) - val d2 = ds((y2 >>> 47).toInt) << 16 - val d3 = ds((y3 >>> 47).toInt).toLong << 32 - val d4 = ds((y4 >>> 47).toInt).toLong << 48 + val d1 = ds((y1 >> 47).toInt) + val d2 = ds((y2 >> 47).toInt) << 16 + val d3 = ds((y3 >> 47).toInt).toLong << 32 + val d4 = ds((y4 >> 47).toInt).toLong << 48 ByteArrayAccess.setLong(buf, pos, d1 | d2 | d3 | d4) pos + 8 } @@ -1693,7 +1684,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 } @@ -1810,7 +1801,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 } @@ -1905,11 +1896,11 @@ final class JsonWriter private[jsoniter_scala]( else { val q1 = Math.multiplyHigh(q0, 6189700196426901375L) >>> 25 // divide a positive long by 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) } } diff --git a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala index c8030dd2e..b44d31540 100644 --- a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala +++ b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala @@ -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 } @tailrec @@ -858,7 +858,7 @@ final class JsonReader private[jsoniter_scala]( val b3 = (bs >> 16).toByte val b4 = (bs >> 24).toByte 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) @@ -882,9 +882,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 } @@ -1118,7 +1118,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 } private[this] def appendChar(ch: Char, i: Int): Int = { @@ -1460,7 +1460,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 @@ -1601,7 +1601,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 @@ -1696,7 +1696,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 } } } @@ -1833,10 +1833,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 } } @@ -2190,7 +2190,7 @@ final class JsonReader private[jsoniter_scala]( } if (b == 'Z') nextByteOrError('"', pos) else { - val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) + val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 @@ -2201,7 +2201,7 @@ final class JsonReader private[jsoniter_scala]( head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) if (offsetTotal > 64800) timezoneOffsetError() // 64800 == 18 * 60 * 60 - if (offsetNeg) offsetTotal = -offsetTotal + if (isNeg) offsetTotal = -offsetTotal secondOfDay -= offsetTotal } Instant.ofEpochSecond(epochDaySeconds + secondOfDay, nano) @@ -2405,7 +2405,7 @@ final class JsonReader private[jsoniter_scala]( nextByteOrError('"', pos) ZoneOffset.UTC } else { - val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) + val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 @@ -2415,7 +2415,7 @@ final class JsonReader private[jsoniter_scala]( offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) - toZoneOffset(offsetNeg, offsetTotal.toInt) + toZoneOffset(isNeg, offsetTotal.toInt) } OffsetDateTime.of(year, monthDay & 0xFF, monthDay >> 24, hourMinute & 0xFF, hourMinute >> 24, second, nano, zoneOffset) } @@ -2497,7 +2497,7 @@ final class JsonReader private[jsoniter_scala]( nextByteOrError('"', pos) ZoneOffset.UTC } else { - val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) + val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 @@ -2507,7 +2507,7 @@ final class JsonReader private[jsoniter_scala]( offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) - toZoneOffset(offsetNeg, offsetTotal.toInt) + toZoneOffset(isNeg, offsetTotal.toInt) } OffsetTime.of(hourMinute & 0xFF, hourMinute >> 24, second, nano, zoneOffset) } @@ -2665,7 +2665,7 @@ final class JsonReader private[jsoniter_scala]( b = nextByte(pos) ZoneOffset.UTC } else { - val offsetNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) + val isNeg = b == '-' || (b != '+' && timeError(nanoDigitWeight, pos - 1)) nanoDigitWeight = -3 var offsetTotal = 0L if (pos + 7 < tail && { @@ -2689,7 +2689,7 @@ final class JsonReader private[jsoniter_scala]( } } } - toZoneOffset(offsetNeg, offsetTotal.toInt) + toZoneOffset(isNeg, offsetTotal.toInt) } if (b == '"') ZonedDateTime.ofLocal(localDateTime, zoneOffset, null) else if (b == '[') { @@ -2706,7 +2706,7 @@ final class JsonReader private[jsoniter_scala]( nextByteOrError('"', pos) ZoneOffset.UTC } else { - val offsetNeg = b == '-' || (b != '+' && decodeError("expected '+' or '-' or 'Z'")) + val isNeg = b == '-' || (b != '+' && decodeError("expected '+' or '-' or 'Z'")) var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 @@ -2716,7 +2716,7 @@ final class JsonReader private[jsoniter_scala]( offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) - toZoneOffset(offsetNeg, offsetTotal.toInt) + toZoneOffset(isNeg, offsetTotal.toInt) } } @@ -2814,8 +2814,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) } diff --git a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala index a454c819d..afba0d67c 100644 --- a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala +++ b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala @@ -1229,7 +1229,7 @@ final class JsonWriter private[jsoniter_scala]( val buf = this.buf val ds = digits buf(pos) = '"' - pos = writeLocalTime(epochSecond - epochDay * 86400, x.getNano, writeLocalDateWithT(year, month, day, pos + 1, buf, ds), buf, ds) + pos = writeLocalTime((epochSecond - epochDay * 86400).toInt, x.getNano, writeLocalDateWithT(year, month, day, pos + 1, buf, ds), buf, ds) ByteArrayAccess.setShort(buf, pos, 0x225A) pos + 2 } @@ -1302,12 +1302,10 @@ final class JsonWriter private[jsoniter_scala]( private[this] def writePeriod(x: Period): Unit = count = { var pos = ensureBufCapacity(39) // 39 == "P-2147483648Y-2147483648M-2147483648D".length + 2 val buf = this.buf - ByteArrayAccess.setShort(buf, pos, 0x5022) - pos += 2 - if (x eq Period.ZERO) { - ByteArrayAccess.setShort(buf, pos, 0x4430) + ByteArrayAccess.setInt(buf, pos, 0x44305022) + if (x eq Period.ZERO) pos += 4 + else { pos += 2 - } else { val ds = digits val years = x.getYears val months = x.getMonths @@ -1385,32 +1383,28 @@ final class JsonWriter private[jsoniter_scala]( private[this] def writeZoneOffset(x: ZoneOffset): Unit = count = { val pos = ensureBufCapacity(12) // 12 == number of bytes in Long and Int val buf = this.buf - var q0 = x.getTotalSeconds - if (q0 == 0) { + var y = x.getTotalSeconds + if (y == 0) { ByteArrayAccess.setInt(buf, pos, 0x225A22) pos + 3 } else { val ds = digits var m = 0x2230303A00002B22L - if (q0 < 0) { - q0 = -q0 + if (y < 0) { + y = -y m = 0x2230303A00002D22L } - val p1 = q0 * 37283 - val q1 = p1 >>> 27 // divide a small positive int by 3600 - m |= ds(q1) << 16 - if ((p1 & 0x7FF8000) == 0) { // check if q0 is divisible by 3600 + y *= 37283 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ + m |= ds(y >>> 27) << 16 + if ((y & 0x7FF8000) == 0) { // check if totalSeconds is divisible by 3600 ByteArrayAccess.setLong(buf, pos, m) pos + 8 } else { - val r1 = q0 - q1 * 3600 - val p2 = r1 * 17477 - val q2 = p2 >> 20 // divide a small positive int by 60 - m |= ds(q2).toLong << 40 - ByteArrayAccess.setLong(buf, pos, m) - if ((p2 & 0xFC000) == 0) pos + 8 // check if r1 is divisible by 60 + y = (y & 0x7FFFFFF) * 15 + ByteArrayAccess.setLong(buf, pos, ds(y >> 25).toLong << 40 | m) + if ((y & 0x1F80000) == 0) pos + 8 // check if totalSeconds is divisible by 60 else { - ByteArrayAccess.setInt(buf, pos + 7, ds(r1 - q2 * 60) << 8 | 0x2200003A) + ByteArrayAccess.setInt(buf, pos + 7, ds((y & 0x1FFFFFF) * 15 >> 23) << 8 | 0x2200003A) pos + 11 } } @@ -1465,13 +1459,13 @@ final class JsonWriter private[jsoniter_scala]( } } - private[this] def writeLocalTime(secsOfDay: Long, nano: Int, pos: Int, buf: Array[Byte], ds: Array[Short]): Int = { - val y1 = secsOfDay * 1193047 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ - val y2 = (y1 & 0xFFFFFFFFL) * 60 - val y3 = (y2 & 0xFFFFFFFFL) * 60 - val d1 = ds((y1 >> 32).toInt) | 0x3A00003A0000L - val d2 = ds((y2 >> 32).toInt).toLong << 24 - val d3 = ds((y3 >> 32).toInt).toLong << 48 + private[this] def writeLocalTime(secsOfDay: Int, nano: Int, pos: Int, buf: Array[Byte], ds: Array[Short]): Int = { + val y1 = secsOfDay * 37283 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ + val y2 = (y1 & 0x7FFFFFF) * 15 + val y3 = (y2 & 0x1FFFFFF) * 15 + val d1 = ds(y1 >>> 27) | 0x3A00003A0000L + val d2 = ds(y2 >> 25).toLong << 24 + val d3 = ds(y3 >> 23).toLong << 48 ByteArrayAccess.setLong(buf, pos, d1 | d2 | d3) if (nano == 0) pos + 8 else writeNanos(nano, pos + 8, buf, ds) @@ -1499,30 +1493,27 @@ final class JsonWriter private[jsoniter_scala]( } private[this] def writeOffset(x: ZoneOffset, pos: Int, buf: Array[Byte], ds: Array[Short]): Int = { - var q0 = x.getTotalSeconds - if (q0 == 0) { + var y = x.getTotalSeconds + if (y == 0) { ByteArrayAccess.setShort(buf, pos, 0x225A) pos + 2 } else { var m = 0x2230303A00002BL - if (q0 < 0) { - q0 = -q0 + if (y < 0) { + y = -y m = 0x2230303A00002DL } - val p1 = q0 * 37283 - val q1 = p1 >>> 27 // divide a small positive int by 3600 - m |= ds(q1) << 8 - if ((p1 & 0x7FF8000) == 0) { // check if q0 is divisible by 3600 + y *= 37283 // Based on James Anhalt's algorithm: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ + m |= ds(y >>> 27) << 8 + if ((y & 0x7FF8000) == 0) { // check if totalSeconds is divisible by 3600 ByteArrayAccess.setLong(buf, pos, m) pos + 7 } else { - val r1 = q0 - q1 * 3600 - val p2 = r1 * 17477 - val q2 = p2 >> 20 // divide a small positive int by 60 - ByteArrayAccess.setLong(buf, pos, ds(q2).toLong << 32 | m) - if ((p2 & 0xFC000) == 0) pos + 7 // check if r1 is divisible by 60 + y = (y & 0x7FFFFFF) * 15 + ByteArrayAccess.setLong(buf, pos, ds(y >> 25).toLong << 32 | m) + if ((y & 0x1F80000) == 0) pos + 7 // check if totalSeconds is divisible by 60 else { - ByteArrayAccess.setInt(buf, pos + 6, ds(r1 - q2 * 60) << 8 | 0x2200003A) + ByteArrayAccess.setInt(buf, pos + 6, ds((y & 0x1FFFFFF) * 15 >> 23) << 8 | 0x2200003A) pos + 10 } } @@ -1553,10 +1544,10 @@ final class JsonWriter private[jsoniter_scala]( val y2 = (y1 & 0x7FFFFFFFFFFFL) * 100 val y3 = (y2 & 0x7FFFFFFFFFFFL) * 100 val y4 = (y3 & 0x7FFFFFFFFFFFL) * 100 - val d1 = ds((y1 >>> 47).toInt) - val d2 = ds((y2 >>> 47).toInt) << 16 - val d3 = ds((y3 >>> 47).toInt).toLong << 32 - val d4 = ds((y4 >>> 47).toInt).toLong << 48 + val d1 = ds((y1 >> 47).toInt) + val d2 = ds((y2 >> 47).toInt) << 16 + val d3 = ds((y3 >> 47).toInt).toLong << 32 + val d4 = ds((y4 >> 47).toInt).toLong << 48 ByteArrayAccess.setLong(buf, pos, d1 | d2 | d3 | d4) pos + 8 } @@ -1693,7 +1684,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 } @@ -1810,7 +1801,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 } @@ -1905,11 +1896,11 @@ final class JsonWriter private[jsoniter_scala]( else { val q1 = NativeMath.multiplyHigh(q0, 6189700196426901375L) >>> 25 // divide a positive long by 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) } } From 1e1e97a05f481612d7e5aeb4eebbe1cc59bb50bb Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Wed, 28 Dec 2022 15:31:28 +0100 Subject: [PATCH 3/5] More efficient parsing of small `BigDecimal` values for JVMs and Scala Native --- .../jsoniter_scala/core/JsonReader.scala | 64 ++++++++++++------- .../jsoniter_scala/core/JsonReader.scala | 64 ++++++++++++------- 2 files changed, 80 insertions(+), 48 deletions(-) diff --git a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala index 80be2dd4e..87f3e5310 100644 --- a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala +++ b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala @@ -1735,6 +1735,7 @@ final class JsonReader private[jsoniter_scala]( }) leadingZeroError(pos - 1) } else { digits -= pos + var m, bs = 0L while ((pos + 7 < tail || { digits += pos pos = loadMore(pos) @@ -1742,19 +1743,26 @@ final class JsonReader private[jsoniter_scala]( buf = this.buf pos + 7 < tail }) && { - val bs = ByteArrayAccess.getLong(buf, pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 - ((bs + 0x4646464646464646L | bs - 0x3030303030303030L) & 0x8080808080808080L) == 0 + bs = ByteArrayAccess.getLong(buf, pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 + m = (bs + 0x4646464646464646L | bs - 0x3030303030303030L) & 0x8080808080808080L + m == 0 }) pos += 8 - while ((pos < tail || { - digits += pos - pos = loadMore(pos) - digits -= pos - buf = this.buf - pos < tail - }) && { - b = buf(pos) - b >= '0' && b <= '9' - }) pos += 1 + if (m == 0) { + while ((pos < tail || { + digits += pos + pos = loadMore(pos) + digits -= pos + buf = this.buf + pos < tail + }) && { + b = buf(pos) + b >= '0' && b <= '9' + }) pos += 1 + } else { + val offset = java.lang.Long.numberOfTrailingZeros(m) >> 3 + pos += offset + b = (bs >> (offset << 3)).toByte + } digits += pos } var fracLen, scale = 0 @@ -1762,6 +1770,7 @@ final class JsonReader private[jsoniter_scala]( if (b == '.') { pos += 1 fracLen -= pos + var m, bs = 0L while ((pos + 7 < tail || { fracLen += pos pos = loadMore(pos) @@ -1769,19 +1778,26 @@ final class JsonReader private[jsoniter_scala]( buf = this.buf pos + 7 < tail }) && { - val bs = ByteArrayAccess.getLong(buf, pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 - ((bs + 0x4646464646464646L | bs - 0x3030303030303030L) & 0x8080808080808080L) == 0 + bs = ByteArrayAccess.getLong(buf, pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 + m = (bs + 0x4646464646464646L | bs - 0x3030303030303030L) & 0x8080808080808080L + m == 0 }) pos += 8 - while ((pos < tail || { - fracLen += pos - pos = loadMore(pos) - fracLen -= pos - buf = this.buf - pos < tail - }) && { - b = buf(pos) - b >= '0' && b <= '9' - }) pos += 1 + if (m == 0) { + while ((pos < tail || { + fracLen += pos + pos = loadMore(pos) + fracLen -= pos + buf = this.buf + pos < tail + }) && { + b = buf(pos) + b >= '0' && b <= '9' + }) pos += 1 + } else { + val offset = java.lang.Long.numberOfTrailingZeros(m) >> 3 + pos += offset + b = (bs >> (offset << 3)).toByte + } fracLen += pos digits += fracLen if (fracLen == 0) numberError(pos) diff --git a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala index b44d31540..fa42ce965 100644 --- a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala +++ b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala @@ -1732,6 +1732,7 @@ final class JsonReader private[jsoniter_scala]( }) leadingZeroError(pos - 1) } else { digits -= pos + var m, bs = 0L while ((pos + 7 < tail || { digits += pos pos = loadMore(pos) @@ -1739,19 +1740,26 @@ final class JsonReader private[jsoniter_scala]( buf = this.buf pos + 7 < tail }) && { - val bs = ByteArrayAccess.getLong(buf, pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 - ((bs + 0x4646464646464646L | bs - 0x3030303030303030L) & 0x8080808080808080L) == 0 + bs = ByteArrayAccess.getLong(buf, pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 + m = (bs + 0x4646464646464646L | bs - 0x3030303030303030L) & 0x8080808080808080L + m == 0 }) pos += 8 - while ((pos < tail || { - digits += pos - pos = loadMore(pos) - digits -= pos - buf = this.buf - pos < tail - }) && { - b = buf(pos) - b >= '0' && b <= '9' - }) pos += 1 + if (m == 0) { + while ((pos < tail || { + digits += pos + pos = loadMore(pos) + digits -= pos + buf = this.buf + pos < tail + }) && { + b = buf(pos) + b >= '0' && b <= '9' + }) pos += 1 + } else { + val offset = java.lang.Long.numberOfTrailingZeros(m) >> 3 + pos += offset + b = (bs >> (offset << 3)).toByte + } digits += pos } var fracLen, scale = 0 @@ -1759,6 +1767,7 @@ final class JsonReader private[jsoniter_scala]( if (b == '.') { pos += 1 fracLen -= pos + var m, bs = 0L while ((pos + 7 < tail || { fracLen += pos pos = loadMore(pos) @@ -1766,19 +1775,26 @@ final class JsonReader private[jsoniter_scala]( buf = this.buf pos + 7 < tail }) && { - val bs = ByteArrayAccess.getLong(buf, pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 - ((bs + 0x4646464646464646L | bs - 0x3030303030303030L) & 0x8080808080808080L) == 0 + bs = ByteArrayAccess.getLong(buf, pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 + m = (bs + 0x4646464646464646L | bs - 0x3030303030303030L) & 0x8080808080808080L + m == 0 }) pos += 8 - while ((pos < tail || { - fracLen += pos - pos = loadMore(pos) - fracLen -= pos - buf = this.buf - pos < tail - }) && { - b = buf(pos) - b >= '0' && b <= '9' - }) pos += 1 + if (m == 0) { + while ((pos < tail || { + fracLen += pos + pos = loadMore(pos) + fracLen -= pos + buf = this.buf + pos < tail + }) && { + b = buf(pos) + b >= '0' && b <= '9' + }) pos += 1 + } else { + val offset = java.lang.Long.numberOfTrailingZeros(m) >> 3 + pos += offset + b = (bs >> (offset << 3)).toByte + } fracLen += pos digits += fracLen if (fracLen == 0) numberError(pos) From 0124277289a804ac34c527803086b959baaff685 Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Wed, 28 Dec 2022 19:56:57 +0100 Subject: [PATCH 4/5] Code clean up --- .../jsoniter_scala/core/JsonReader.scala | 16 +-- .../jsoniter_scala/core/JsonWriter.scala | 2 +- .../jsoniter_scala/core/JsonReader.scala | 100 +++++++++--------- .../jsoniter_scala/core/JsonWriter.scala | 2 +- .../jsoniter_scala/core/JsonReader.scala | 100 +++++++++--------- .../jsoniter_scala/core/JsonWriter.scala | 2 +- .../jsoniter_scala/core/GenUtils.scala | 4 +- .../jsoniter_scala/core/JsonWriterSpec.scala | 4 +- 8 files changed, 115 insertions(+), 115 deletions(-) diff --git a/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala b/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala index 76da73db3..4389ea4e9 100644 --- a/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala +++ b/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala @@ -1440,14 +1440,14 @@ final class JsonReader private[jsoniter_scala]( m2 >>>= truncatedBitNum e2 += truncatedBitNum if (savedBitNum >= 0 && halfwayDiff > 0) { - if (m2 == 0x001FFFFFFFFFFFFFL) { - m2 = 0x0010000000000000L + if (m2 == 0x1FFFFFFFFFFFFFL) { + m2 = 0x10000000000000L e2 += 1 } else m2 += 1 } if (e2 == -1074) m2 else if (e2 >= 972) 0x7FF0000000000000L - else e2 + 1075L << 52 | m2 & 0x000FFFFFFFFFFFFFL + else e2 + 1075L << 52 | m2 & 0xFFFFFFFFFFFFFL } else toDouble(from, newMark, pos) } @@ -1581,14 +1581,14 @@ final class JsonReader private[jsoniter_scala]( if (savedBitNum > 0) mf = (m2 >>> truncatedBitNum).toInt e2 += truncatedBitNum if (savedBitNum >= 0 && halfwayDiff > 0) { - if (mf == 0x00FFFFFF) { - mf = 0x00800000 + if (mf == 0xFFFFFF) { + mf = 0x800000 e2 += 1 } else mf += 1 } if (e2 == -149) mf else if (e2 >= 105) 0x7F800000 - else e2 + 150 << 23 | mf & 0x007FFFFF + else e2 + 150 << 23 | mf & 0x7FFFFF } else toFloat(from, newMark, pos) } @@ -2562,8 +2562,8 @@ final class JsonReader private[jsoniter_scala]( val b4 = buf(pos + 3) val cp = b1 << 18 ^ b2 << 12 ^ b3 << 6 ^ b4 ^ 0x381F80 // 0x381F80 == 0xF0.toByte << 18 ^ 0x80.toByte << 12 ^ 0x80.toByte << 6 ^ 0x80.toByte if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80 || - cp < 0x010000 || cp > 0x10FFFF) malformedBytesError(b1, b2, b3, b4, pos) - charBuf(i) = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x010000 >>> 10) + cp < 0x10000 || cp > 0x10FFFF) malformedBytesError(b1, b2, b3, b4, pos) + charBuf(i) = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x10000 >>> 10) charBuf(i + 1) = ((cp & 0x3FF) + 0xDC00).toChar parseEncodedString(i + 2, lim, charBuf, pos + 4) } else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos)) diff --git a/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala b/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala index 86bf642f9..149d277e9 100644 --- a/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala +++ b/jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala @@ -1025,7 +1025,7 @@ final class JsonWriter private[jsoniter_scala]( if (ch1 >= 0xDC00 || from + 1 >= to) illegalSurrogateError() val ch2 = s.charAt(from + 1) if (ch2 < 0xDC00 || ch2 > 0xDFFF) illegalSurrogateError() - val cp = (ch1 << 10) + (ch2 - 56613888) // -56613888 == 0x010000 - (0xD800 << 10) - 0xDC00 + val cp = (ch1 << 10) + (ch2 - 56613888) // -56613888 == 0x10000 - (0xD800 << 10) - 0xDC00 buf(pos) = (cp >> 18 | 0xF0).toByte buf(pos + 1) = (cp >> 12 & 0x3F | 0x80).toByte buf(pos + 2) = (cp >> 6 & 0x3F | 0x80).toByte diff --git a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala index 87f3e5310..fc8ee884d 100644 --- a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala +++ b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala @@ -831,7 +831,7 @@ final class JsonReader private[jsoniter_scala]( val buf = this.buf var year = ByteArrayAccess.getInt(buf, pos) - 0x30303030 if (((year + 0x76767676 | year) & 0x80808080) == 0 && buf(pos + 4) == '-') { // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 - year = (year * 2561 >> 8 & 0x00FF00FF) * 6553601 >> 16 + year = (year * 2561 >> 8 & 0xFF00FF) * 6553601 >> 16 head = pos + 5 year } else parseNon4DigitYearWithByte('-', 10, year + 0x30303030, pos) @@ -843,7 +843,7 @@ final class JsonReader private[jsoniter_scala]( val buf = this.buf var year = ByteArrayAccess.getInt(buf, pos) - 0x30303030 if (((year + 0x76767676 | year) & 0x80808080) == 0 && buf(pos + 4) == t) { // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 - year = (year * 2561 >> 8 & 0x00FF00FF) * 6553601 >> 16 + year = (year * 2561 >> 8 & 0xFF00FF) * 6553601 >> 16 head = pos + 5 year } else parseNon4DigitYearWithByte(t, 9, year + 0x30303030, pos) @@ -990,19 +990,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -1319,7 +1319,7 @@ final class JsonReader private[jsoniter_scala]( if (x < -92233720368L || { dec *= 2561 x *= 100000000 - x -= ((dec >> 8 & 0x000000FF000000FFL) * 4294967296000100L + (dec >> 24 & 0x000000FF000000FFL) * 42949672960001L >> 32) + x -= ((dec >> 8 & 0xFF000000FFL) * 4294967296000100L + (dec >> 24 & 0xFF000000FFL) * 42949672960001L >> 32) x > 0 }) longOverflowError(pos + 2) pos += 8 @@ -1487,14 +1487,14 @@ final class JsonReader private[jsoniter_scala]( m2 >>>= truncatedBitNum e2 += truncatedBitNum if (savedBitNum >= 0 && halfwayDiff > 0) { - if (m2 == 0x001FFFFFFFFFFFFFL) { - m2 = 0x0010000000000000L + if (m2 == 0x1FFFFFFFFFFFFFL) { + m2 = 0x10000000000000L e2 += 1 } else m2 += 1 } if (e2 == -1074) m2 else if (e2 >= 972) 0x7FF0000000000000L - else e2 + 1075L << 52 | m2 & 0x000FFFFFFFFFFFFFL + else e2 + 1075L << 52 | m2 & 0xFFFFFFFFFFFFFL } else toDouble(from, newMark, pos) } @@ -1628,14 +1628,14 @@ final class JsonReader private[jsoniter_scala]( if (savedBitNum > 0) mf = (m2 >>> truncatedBitNum).toInt e2 += truncatedBitNum if (savedBitNum >= 0 && halfwayDiff > 0) { - if (mf == 0x00FFFFFF) { - mf = 0x00800000 + if (mf == 0xFFFFFF) { + mf = 0x800000 e2 += 1 } else mf += 1 } if (e2 == -149) mf else if (e2 >= 105) 0x7F800000 - else e2 + 150 << 23 | mf & 0x007FFFFF + else e2 + 150 << 23 | mf & 0x7FFFFF } else toFloat(from, newMark, pos) } @@ -1896,10 +1896,10 @@ final class JsonReader private[jsoniter_scala]( } val x2 = ({ // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 val dec = (ByteArrayAccess.getLong(buf, pos) - 0x3030303030303030L) * 2561 - (dec >> 8 & 0x000000FF000000FFL) * 42949672960001000L + (dec >> 24 & 0x000000FF000000FFL) * 429496729600010L >> 32 + (dec >> 8 & 0xFF000000FFL) * 42949672960001000L + (dec >> 24 & 0xFF000000FFL) * 429496729600010L >> 32 } + buf(pos + 8)) * 1000000000 + { val dec = (ByteArrayAccess.getLong(buf, pos + 9) - 0x3030303030303030L) * 2561 - (dec >> 8 & 0x000000FF000000FFL) * 42949672960001000L + (dec >> 24 & 0x000000FF000000FFL) * 429496729600010L >> 32 + (dec >> 8 & 0xFF000000FFL) * 42949672960001000L + (dec >> 24 & 0xFF000000FFL) * 429496729600010L >> 32 } + buf(pos + 17) - 48000000048L val q = x1 * 1000000000000000000L var l = q + x2 @@ -1949,10 +1949,10 @@ final class JsonReader private[jsoniter_scala]( while (pos < limit) { x = ({ // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 val dec = (ByteArrayAccess.getLong(buf, pos) - 0x3030303030303030L) * 2561 - (dec >> 8 & 0x000000FF000000FFL) * 42949672960001000L + (dec >> 24 & 0x000000FF000000FFL) * 429496729600010L >> 32 + (dec >> 8 & 0xFF000000FFL) * 42949672960001000L + (dec >> 24 & 0xFF000000FFL) * 429496729600010L >> 32 } + buf(pos + 8)) * 1000000000 + { val dec = (ByteArrayAccess.getLong(buf, pos + 9) - 0x3030303030303030L) * 2561 - (dec >> 8 & 0x000000FF000000FFL) * 42949672960001000L + (dec >> 24 & 0x000000FF000000FFL) * 429496729600010L >> 32 + (dec >> 8 & 0xFF000000FFL) * 42949672960001000L + (dec >> 24 & 0xFF000000FFL) * 429496729600010L >> 32 } + buf(pos + 17) - 48000000048L pos += 18 first = Math.max(first - 8, 0) @@ -2091,19 +2091,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 3 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2176,19 +2176,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2213,10 +2213,10 @@ final class JsonReader private[jsoniter_scala]( var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - (offsetTotal + 0x00060A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && + (offsetTotal + 0x60A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && (offsetTotal & 0xFFF0F0FFF0F0L) == 0x2230303A3030L }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) if (offsetTotal > 64800) timezoneOffsetError() // 64800 == 18 * 60 * 60 @@ -2241,8 +2241,8 @@ final class JsonReader private[jsoniter_scala]( val pos = head if (pos + 7 < tail && { val bs = ByteArrayAccess.getLong(buf, pos) - (bs + 0x00060C00060EL & 0xFFF0F0FFF0F0L) == 0x2230302D3030L && (bs & 0xFFF0F0FFF0F0L) == 0x2230302D3030L && { // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - val monthDay = ((bs & 0x0F03000F01L) * 2561 >> 8).toInt + (bs + 0x60C00060EL & 0xFFF0F0FFF0F0L) == 0x2230302D3030L && (bs & 0xFFF0F0FFF0F0L) == 0x2230302D3030L && { // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 + val monthDay = ((bs & 0xF03000F01L) * 2561 >> 8).toInt month = monthDay & 0xFF day = monthDay >> 24 (month >= 1 && month <= 12) && day != 0 && (day <= 28 || day <= maxDayForYearMonth(year, month)) @@ -2320,7 +2320,7 @@ final class JsonReader private[jsoniter_scala]( val month = monthDay & 0xFF val day = monthDay >> 24 head = pos + 8 - if (((bs + 0x00767C00767E0000L | bs) & 0xFF8080FF8080FFFFL) != 0) monthDayError(pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 + if (((bs + 0x767C00767E0000L | bs) & 0xFF8080FF8080FFFFL) != 0) monthDayError(pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 if (month < 1 || month > 12) monthError(pos + 3) if (day == 0 || (day > 28 && day > maxDayForMonth(month))) dayError(pos + 6) MonthDay.of(month, day) @@ -2330,8 +2330,8 @@ final class JsonReader private[jsoniter_scala]( var monthDay = 0 if (pos + 7 < tail && { val bs = ByteArrayAccess.getLong(buf, pos) - (bs + 0x00060C00060EL & 0xFFF0F0FFF0F0L) == 0x5430302D3030L && (bs & 0xFFF0F0FFF0F0L) == 0x5430302D3030L && { // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - monthDay = ((bs & 0x0F03000F01L) * 2561 >> 8).toInt + (bs + 0x60C00060EL & 0xFFF0F0FFF0F0L) == 0x5430302D3030L && (bs & 0xFFF0F0FFF0F0L) == 0x5430302D3030L && { // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 + monthDay = ((bs & 0xF03000F01L) * 2561 >> 8).toInt val month = monthDay & 0xFF val day = monthDay >> 24 (month >= 1 && month <= 12) && day != 0 && (day <= 28 || day <= maxDayForYearMonth(year, month)) @@ -2388,19 +2388,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2428,10 +2428,10 @@ final class JsonReader private[jsoniter_scala]( var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - (offsetTotal + 0x00060A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && + (offsetTotal + 0x60A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && (offsetTotal & 0xFFF0F0FFF0F0L) == 0x2230303A3030L }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) toZoneOffset(isNeg, offsetTotal.toInt) @@ -2480,19 +2480,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2520,10 +2520,10 @@ final class JsonReader private[jsoniter_scala]( var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - (offsetTotal + 0x00060A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && + (offsetTotal + 0x60A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && (offsetTotal & 0xFFF0F0FFF0F0L) == 0x2230303A3030L }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) toZoneOffset(isNeg, offsetTotal.toInt) @@ -2647,19 +2647,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2690,10 +2690,10 @@ final class JsonReader private[jsoniter_scala]( if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 b = (offsetTotal >> 40).toByte - (offsetTotal + 0x060A00060EL & 0xF0F0FFF0F0L) == 0x30303A3030L && + (offsetTotal + 0x60A00060EL & 0xF0F0FFF0F0L) == 0x30303A3030L && (offsetTotal & 0xF0F0FFF0F0L) == 0x30303A3030L && b != ':' }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else { offsetTotal = parseOffsetHour(pos) * 3600 @@ -2729,10 +2729,10 @@ final class JsonReader private[jsoniter_scala]( var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - (offsetTotal + 0x00060A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && + (offsetTotal + 0x60A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && (offsetTotal & 0xFFF0F0FFF0F0L) == 0x2230303A3030L }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) toZoneOffset(isNeg, offsetTotal.toInt) @@ -2955,10 +2955,10 @@ final class JsonReader private[jsoniter_scala]( private[this] def parseString(i: Int, minLim: Int, charBuf: Array[Char], pos: Int): Int = if (i + 7 < minLim) { // Based on SWAR routine of JSON string parsing: https://github.com/sirthias/borer/blob/fde9d1ce674d151b0fee1dd0c2565020c3f6633a/core/src/main/scala/io/bullet/borer/json/JsonParser.scala#L456 val bs = ByteArrayAccess.getLong(buf, pos) - var m = (bs ^ 0x5D5D5D5D5D5D5D5DL) + 0x0101010101010101L + var m = (bs ^ 0x5D5D5D5D5D5D5D5DL) + 0x101010101010101L charBuf(i) = (bs & 0xFF).toChar charBuf(i + 1) = (bs >> 8 & 0xFF).toChar - m |= (bs ^ 0x2323232323232323L) + 0x0101010101010101L + m |= (bs ^ 0x2323232323232323L) + 0x101010101010101L charBuf(i + 2) = (bs >> 16 & 0xFF).toChar charBuf(i + 3) = (bs >> 24 & 0xFF).toChar m |= bs - 0x2020202020202020L @@ -3054,8 +3054,8 @@ final class JsonReader private[jsoniter_scala]( val b4 = buf(pos + 3) val cp = b1 << 18 ^ b2 << 12 ^ b3 << 6 ^ b4 ^ 0x381F80 // 0x381F80 == 0xF0.toByte << 18 ^ 0x80.toByte << 12 ^ 0x80.toByte << 6 ^ 0x80.toByte if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80 || - cp < 0x010000 || cp > 0x10FFFF) malformedBytesError(b1, b2, b3, b4, pos) - charBuf(i) = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x010000 >>> 10) + cp < 0x10000 || cp > 0x10FFFF) malformedBytesError(b1, b2, b3, b4, pos) + charBuf(i) = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x10000 >>> 10) charBuf(i + 1) = ((cp & 0x3FF) + 0xDC00).toChar parseEncodedString(i + 2, lim, charBuf, pos + 4) } else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos)) diff --git a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala index 3df0567c2..d309c2fda 100644 --- a/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala +++ b/jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala @@ -898,7 +898,7 @@ final class JsonWriter private[jsoniter_scala]( if (ch1 >= 0xDC00 || from + 1 >= to) illegalSurrogateError() val ch2 = s.charAt(from + 1) if (ch2 < 0xDC00 || ch2 > 0xDFFF) illegalSurrogateError() - val cp = (ch1 << 10) + (ch2 - 56613888) // -56613888 == 0x010000 - (0xD800 << 10) - 0xDC00 + val cp = (ch1 << 10) + (ch2 - 56613888) // -56613888 == 0x10000 - (0xD800 << 10) - 0xDC00 ByteArrayAccess.setInt(buf, pos, cp >> 18 | (cp >> 4 & 0x3F00) | (cp << 10 & 0x3F0000) | (cp << 24 & 0x3F000000) | 0x808080F0) writeEncodedString(s, from + 2, to, pos + 4, posLim, escapedChars) } diff --git a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala index fa42ce965..b12492d2f 100644 --- a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala +++ b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala @@ -831,7 +831,7 @@ final class JsonReader private[jsoniter_scala]( val buf = this.buf var year = ByteArrayAccess.getInt(buf, pos) - 0x30303030 if (((year + 0x76767676 | year) & 0x80808080) == 0 && buf(pos + 4) == '-') { // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 - year = (year * 2561 >> 8 & 0x00FF00FF) * 6553601 >> 16 + year = (year * 2561 >> 8 & 0xFF00FF) * 6553601 >> 16 head = pos + 5 year } else parseNon4DigitYearWithByte('-', 10, year + 0x30303030, pos) @@ -843,7 +843,7 @@ final class JsonReader private[jsoniter_scala]( val buf = this.buf var year = ByteArrayAccess.getInt(buf, pos) - 0x30303030 if (((year + 0x76767676 | year) & 0x80808080) == 0 && buf(pos + 4) == t) { // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 - year = (year * 2561 >> 8 & 0x00FF00FF) * 6553601 >> 16 + year = (year * 2561 >> 8 & 0xFF00FF) * 6553601 >> 16 head = pos + 5 year } else parseNon4DigitYearWithByte(t, 9, year + 0x30303030, pos) @@ -990,19 +990,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -1319,7 +1319,7 @@ final class JsonReader private[jsoniter_scala]( if (x < -92233720368L || { dec *= 2561 x *= 100000000 - x -= ((dec >> 8 & 0x000000FF000000FFL) * 4294967296000100L + (dec >> 24 & 0x000000FF000000FFL) * 42949672960001L >> 32) + x -= ((dec >> 8 & 0xFF000000FFL) * 4294967296000100L + (dec >> 24 & 0xFF000000FFL) * 42949672960001L >> 32) x > 0 }) longOverflowError(pos + 2) pos += 8 @@ -1487,14 +1487,14 @@ final class JsonReader private[jsoniter_scala]( m2 >>>= truncatedBitNum e2 += truncatedBitNum if (savedBitNum >= 0 && halfwayDiff > 0) { - if (m2 == 0x001FFFFFFFFFFFFFL) { - m2 = 0x0010000000000000L + if (m2 == 0x1FFFFFFFFFFFFFL) { + m2 = 0x10000000000000L e2 += 1 } else m2 += 1 } if (e2 == -1074) m2 else if (e2 >= 972) 0x7FF0000000000000L - else e2 + 1075L << 52 | m2 & 0x000FFFFFFFFFFFFFL + else e2 + 1075L << 52 | m2 & 0xFFFFFFFFFFFFFL } else toDouble(from, newMark, pos) } @@ -1628,14 +1628,14 @@ final class JsonReader private[jsoniter_scala]( if (savedBitNum > 0) mf = (m2 >>> truncatedBitNum).toInt e2 += truncatedBitNum if (savedBitNum >= 0 && halfwayDiff > 0) { - if (mf == 0x00FFFFFF) { - mf = 0x00800000 + if (mf == 0xFFFFFF) { + mf = 0x800000 e2 += 1 } else mf += 1 } if (e2 == -149) mf else if (e2 >= 105) 0x7F800000 - else e2 + 150 << 23 | mf & 0x007FFFFF + else e2 + 150 << 23 | mf & 0x7FFFFF } else toFloat(from, newMark, pos) } @@ -1893,10 +1893,10 @@ final class JsonReader private[jsoniter_scala]( } val x2 = ({ // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 val dec = (ByteArrayAccess.getLong(buf, pos) - 0x3030303030303030L) * 2561 - (dec >> 8 & 0x000000FF000000FFL) * 42949672960001000L + (dec >> 24 & 0x000000FF000000FFL) * 429496729600010L >> 32 + (dec >> 8 & 0xFF000000FFL) * 42949672960001000L + (dec >> 24 & 0xFF000000FFL) * 429496729600010L >> 32 } + buf(pos + 8)) * 1000000000 + { val dec = (ByteArrayAccess.getLong(buf, pos + 9) - 0x3030303030303030L) * 2561 - (dec >> 8 & 0x000000FF000000FFL) * 42949672960001000L + (dec >> 24 & 0x000000FF000000FFL) * 429496729600010L >> 32 + (dec >> 8 & 0xFF000000FFL) * 42949672960001000L + (dec >> 24 & 0xFF000000FFL) * 429496729600010L >> 32 } + buf(pos + 17) - 48000000048L val q = x1 * 1000000000000000000L var l = q + x2 @@ -1946,10 +1946,10 @@ final class JsonReader private[jsoniter_scala]( while (pos < limit) { x = ({ // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 val dec = (ByteArrayAccess.getLong(buf, pos) - 0x3030303030303030L) * 2561 - (dec >> 8 & 0x000000FF000000FFL) * 42949672960001000L + (dec >> 24 & 0x000000FF000000FFL) * 429496729600010L >> 32 + (dec >> 8 & 0xFF000000FFL) * 42949672960001000L + (dec >> 24 & 0xFF000000FFL) * 429496729600010L >> 32 } + buf(pos + 8)) * 1000000000 + { val dec = (ByteArrayAccess.getLong(buf, pos + 9) - 0x3030303030303030L) * 2561 - (dec >> 8 & 0x000000FF000000FFL) * 42949672960001000L + (dec >> 24 & 0x000000FF000000FFL) * 429496729600010L >> 32 + (dec >> 8 & 0xFF000000FFL) * 42949672960001000L + (dec >> 24 & 0xFF000000FFL) * 429496729600010L >> 32 } + buf(pos + 17) - 48000000048L pos += 18 first = Math.max(first - 8, 0) @@ -2088,19 +2088,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 3 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2173,19 +2173,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2210,10 +2210,10 @@ final class JsonReader private[jsoniter_scala]( var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - (offsetTotal + 0x00060A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && + (offsetTotal + 0x60A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && (offsetTotal & 0xFFF0F0FFF0F0L) == 0x2230303A3030L }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) if (offsetTotal > 64800) timezoneOffsetError() // 64800 == 18 * 60 * 60 @@ -2238,8 +2238,8 @@ final class JsonReader private[jsoniter_scala]( val pos = head if (pos + 7 < tail && { val bs = ByteArrayAccess.getLong(buf, pos) - (bs + 0x00060C00060EL & 0xFFF0F0FFF0F0L) == 0x2230302D3030L && (bs & 0xFFF0F0FFF0F0L) == 0x2230302D3030L && { // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - val monthDay = ((bs & 0x0F03000F01L) * 2561 >> 8).toInt + (bs + 0x60C00060EL & 0xFFF0F0FFF0F0L) == 0x2230302D3030L && (bs & 0xFFF0F0FFF0F0L) == 0x2230302D3030L && { // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 + val monthDay = ((bs & 0xF03000F01L) * 2561 >> 8).toInt month = monthDay & 0xFF day = monthDay >> 24 (month >= 1 && month <= 12) && day != 0 && (day <= 28 || day <= maxDayForYearMonth(year, month)) @@ -2317,7 +2317,7 @@ final class JsonReader private[jsoniter_scala]( val month = monthDay & 0xFF val day = monthDay >> 24 head = pos + 8 - if (((bs + 0x00767C00767E0000L | bs) & 0xFF8080FF8080FFFFL) != 0) monthDayError(pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 + if (((bs + 0x767C00767E0000L | bs) & 0xFF8080FF8080FFFFL) != 0) monthDayError(pos) // Based on the fast parsing of numbers by 8-byte words: https://github.com/wrandelshofer/FastDoubleParser/blob/0903817a765b25e654f02a5a9d4f1476c98a80c9/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastDoubleSimd.java#L114-L130 if (month < 1 || month > 12) monthError(pos + 3) if (day == 0 || (day > 28 && day > maxDayForMonth(month))) dayError(pos + 6) MonthDay.of(month, day) @@ -2327,8 +2327,8 @@ final class JsonReader private[jsoniter_scala]( var monthDay = 0 if (pos + 7 < tail && { val bs = ByteArrayAccess.getLong(buf, pos) - (bs + 0x00060C00060EL & 0xFFF0F0FFF0F0L) == 0x5430302D3030L && (bs & 0xFFF0F0FFF0F0L) == 0x5430302D3030L && { // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - monthDay = ((bs & 0x0F03000F01L) * 2561 >> 8).toInt + (bs + 0x60C00060EL & 0xFFF0F0FFF0F0L) == 0x5430302D3030L && (bs & 0xFFF0F0FFF0F0L) == 0x5430302D3030L && { // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 + monthDay = ((bs & 0xF03000F01L) * 2561 >> 8).toInt val month = monthDay & 0xFF val day = monthDay >> 24 (month >= 1 && month <= 12) && day != 0 && (day <= 28 || day <= maxDayForYearMonth(year, month)) @@ -2385,19 +2385,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2425,10 +2425,10 @@ final class JsonReader private[jsoniter_scala]( var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - (offsetTotal + 0x00060A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && + (offsetTotal + 0x60A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && (offsetTotal & 0xFFF0F0FFF0F0L) == 0x2230303A3030L }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) toZoneOffset(isNeg, offsetTotal.toInt) @@ -2477,19 +2477,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2517,10 +2517,10 @@ final class JsonReader private[jsoniter_scala]( var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - (offsetTotal + 0x00060A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && + (offsetTotal + 0x60A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && (offsetTotal & 0xFFF0F0FFF0F0L) == 0x2230303A3030L }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) toZoneOffset(isNeg, offsetTotal.toInt) @@ -2644,19 +2644,19 @@ final class JsonReader private[jsoniter_scala]( bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano = ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000000 + nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100000 ((bs + 0x767676 | bs) & 0x808080) == 0 } && { - nano += ((bs * 2561 & 0x00FF00FF) * 6553601 >> 16) * 1000 + nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000 pos += 3 bs = ByteArrayAccess.getInt(buf, pos) - 0x303030 nanoDigitWeight = 100 ((bs + 0x767676 | bs) & 0x808080) == 0 }) { - nano += (bs * 2561 & 0x00FF00FF) * 6553601 >> 16 + nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16 pos += 4 b = (bs >> 24).toByte nanoDigitWeight = 0 @@ -2687,10 +2687,10 @@ final class JsonReader private[jsoniter_scala]( if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 b = (offsetTotal >> 40).toByte - (offsetTotal + 0x060A00060EL & 0xF0F0FFF0F0L) == 0x30303A3030L && + (offsetTotal + 0x60A00060EL & 0xF0F0FFF0F0L) == 0x30303A3030L && (offsetTotal & 0xF0F0FFF0F0L) == 0x30303A3030L && b != ':' }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else { offsetTotal = parseOffsetHour(pos) * 3600 @@ -2726,10 +2726,10 @@ final class JsonReader private[jsoniter_scala]( var offsetTotal = 0L if (pos + 7 < tail && { offsetTotal = ByteArrayAccess.getLong(buf, pos) // Based on the fast checking of string for digits by 8-byte words: https://github.com/simdjson/simdjson/blob/7e1893db428936e13457ba0e9a5aac0cdfb7bc15/include/simdjson/generic/numberparsing.h#L344 - (offsetTotal + 0x00060A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && + (offsetTotal + 0x60A00060EL & 0xFFF0F0FFF0F0L) == 0x2230303A3030L && (offsetTotal & 0xFFF0F0FFF0F0L) == 0x2230303A3030L }) { - offsetTotal = ((offsetTotal & 0x0F07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ + offsetTotal = ((offsetTotal & 0xF07000F01L) * 2561 & 0x3F00001F00L) * 1979120931962880L >>> 47 // Based on the fast time string to seconds conversion: https://johnnylee-sde.github.io/Fast-time-string-to-seconds/ head = pos + 6 } else offsetTotal = parseOffsetTotalWithDoubleQuotes(pos) toZoneOffset(isNeg, offsetTotal.toInt) @@ -2952,10 +2952,10 @@ final class JsonReader private[jsoniter_scala]( private[this] def parseString(i: Int, minLim: Int, charBuf: Array[Char], pos: Int): Int = if (i + 7 < minLim) { // Based on SWAR routine of JSON string parsing: https://github.com/sirthias/borer/blob/fde9d1ce674d151b0fee1dd0c2565020c3f6633a/core/src/main/scala/io/bullet/borer/json/JsonParser.scala#L456 val bs = ByteArrayAccess.getLong(buf, pos) - var m = (bs ^ 0x5D5D5D5D5D5D5D5DL) + 0x0101010101010101L + var m = (bs ^ 0x5D5D5D5D5D5D5D5DL) + 0x101010101010101L charBuf(i) = (bs & 0xFF).toChar charBuf(i + 1) = (bs >> 8 & 0xFF).toChar - m |= (bs ^ 0x2323232323232323L) + 0x0101010101010101L + m |= (bs ^ 0x2323232323232323L) + 0x101010101010101L charBuf(i + 2) = (bs >> 16 & 0xFF).toChar charBuf(i + 3) = (bs >> 24 & 0xFF).toChar m |= bs - 0x2020202020202020L @@ -3051,8 +3051,8 @@ final class JsonReader private[jsoniter_scala]( val b4 = buf(pos + 3) val cp = b1 << 18 ^ b2 << 12 ^ b3 << 6 ^ b4 ^ 0x381F80 // 0x381F80 == 0xF0.toByte << 18 ^ 0x80.toByte << 12 ^ 0x80.toByte << 6 ^ 0x80.toByte if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80 || - cp < 0x010000 || cp > 0x10FFFF) malformedBytesError(b1, b2, b3, b4, pos) - charBuf(i) = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x010000 >>> 10) + cp < 0x10000 || cp > 0x10FFFF) malformedBytesError(b1, b2, b3, b4, pos) + charBuf(i) = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x10000 >>> 10) charBuf(i + 1) = ((cp & 0x3FF) + 0xDC00).toChar parseEncodedString(i + 2, lim, charBuf, pos + 4) } else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos)) diff --git a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala index afba0d67c..c5f3e846b 100644 --- a/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala +++ b/jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala @@ -898,7 +898,7 @@ final class JsonWriter private[jsoniter_scala]( if (ch1 >= 0xDC00 || from + 1 >= to) illegalSurrogateError() val ch2 = s.charAt(from + 1) if (ch2 < 0xDC00 || ch2 > 0xDFFF) illegalSurrogateError() - val cp = (ch1 << 10) + (ch2 - 56613888) // -56613888 == 0x010000 - (0xD800 << 10) - 0xDC00 + val cp = (ch1 << 10) + (ch2 - 56613888) // -56613888 == 0x10000 - (0xD800 << 10) - 0xDC00 ByteArrayAccess.setInt(buf, pos, cp >> 18 | (cp >> 4 & 0x3F00) | (cp << 10 & 0x3F0000) | (cp << 24 & 0x3F000000) | 0x808080F0) writeEncodedString(s, from + 2, to, pos + 4, posLim, escapedChars) } diff --git a/jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/GenUtils.scala b/jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/GenUtils.scala index 37264b9f5..cfb2cc957 100644 --- a/jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/GenUtils.scala +++ b/jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/GenUtils.scala @@ -124,10 +124,10 @@ object GenUtils { val genFiniteFloat: Gen[Float] = arbitrary[Float].filter(java.lang.Float.isFinite) val genNonFiniteDouble: Gen[Double] = Gen.oneOf( Gen.oneOf(java.lang.Double.NaN, java.lang.Double.NEGATIVE_INFINITY, java.lang.Double.POSITIVE_INFINITY), - Gen.choose(0L, 0x0007FFFFFFFFFFFFL).map(x => java.lang.Double.longBitsToDouble(x | 0x7FF8000000000000L))) // Double.NaN with error code + Gen.choose(0L, 0x7FFFFFFFFFFFFL).map(x => java.lang.Double.longBitsToDouble(x | 0x7FF8000000000000L))) // Double.NaN with error code val genNonFiniteFloat: Gen[Float] = Gen.oneOf( Gen.oneOf(java.lang.Float.NaN, java.lang.Float.NEGATIVE_INFINITY, java.lang.Float.POSITIVE_INFINITY), - Gen.choose(0, 0x003FFFFF).map(x => java.lang.Float.intBitsToFloat(x | 0x7FC00000))) // Float.NaN with error code + Gen.choose(0, 0x3FFFFF).map(x => java.lang.Float.intBitsToFloat(x | 0x7FC00000))) // Float.NaN with error code def isEscapedAscii(ch: Char): Boolean = ch < ' ' || ch == '\\' || ch == '"' || ch == '\u007f' diff --git a/jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriterSpec.scala b/jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriterSpec.scala index 041b48f82..0c6c389f4 100644 --- a/jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriterSpec.scala +++ b/jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriterSpec.scala @@ -519,7 +519,7 @@ class JsonWriterSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyCh check(1.0f) check(-1.0f) check(1.0E7f) - check(java.lang.Float.intBitsToFloat(0x00800000)) // subnormal + check(java.lang.Float.intBitsToFloat(0x800000)) // subnormal check(9999999.0f) check(0.001f) check(0.0009999999f) @@ -636,7 +636,7 @@ class JsonWriterSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyCh check(-0.0) check(1.0) check(-1.0) - check(java.lang.Double.longBitsToDouble(0x0010000000000000L)) // subnormal + check(java.lang.Double.longBitsToDouble(0x10000000000000L)) // subnormal check(1.0E7) check(9999999.999999998) check(0.001) From ab72951e70dec5f786a50ee8f77ca6c5ec04b22a Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Thu, 29 Dec 2022 11:18:00 +0100 Subject: [PATCH 5/5] Setting version to 2.20.1 --- README.md | 6 +++--- jsoniter-scala-examples/build.sbt | 4 ++-- version.sbt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 04d704569..5e8051c1f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Actions Build](https://github.com/plokhotnyuk/jsoniter-scala/workflows/build/badge.svg)](https://github.com/plokhotnyuk/jsoniter-scala/actions) [![Scala Steward](https://img.shields.io/badge/Scala_Steward-helping-brightgreen.svg?style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org) [![Gitter Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/plokhotnyuk/jsoniter-scala?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Maven Central](https://img.shields.io/badge/maven--central-2.20.0-blue.svg)](https://repo1.maven.org/maven2/com/github/plokhotnyuk/jsoniter-scala/) +[![Maven Central](https://img.shields.io/badge/maven--central-2.20.1-blue.svg)](https://repo1.maven.org/maven2/com/github/plokhotnyuk/jsoniter-scala/) Scala macros for compile-time generation of safe and ultra-fast JSON codecs. @@ -217,9 +217,9 @@ list of dependencies: ```sbt libraryDependencies ++= Seq( // Use the %%% operator instead of %% for Scala.js and Scala Native - "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "2.20.0", + "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "2.20.1", // Use the "provided" scope instead when the "compile-internal" scope is not supported - "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "2.20.0" % "compile-internal" + "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "2.20.1" % "compile-internal" ) ``` diff --git a/jsoniter-scala-examples/build.sbt b/jsoniter-scala-examples/build.sbt index bf4f4a86a..ee63e5206 100644 --- a/jsoniter-scala-examples/build.sbt +++ b/jsoniter-scala-examples/build.sbt @@ -13,9 +13,9 @@ val `jsoniter-scala-examples` = crossProject(JVMPlatform, NativePlatform) assembly / mainClass := Some("com.github.plokhotnyuk.jsoniter_scala.examples.Example01"), libraryDependencySchemes += "com.github.plokhotnyuk.jsoniter-scala" %%% "jsoniter-scala-core" % "always", libraryDependencies ++= Seq( - "com.github.plokhotnyuk.jsoniter-scala" %%% "jsoniter-scala-core" % "2.20.0", + "com.github.plokhotnyuk.jsoniter-scala" %%% "jsoniter-scala-core" % "2.20.1", // Use the "provided" scope instead when the "compile-internal" scope is not supported - "com.github.plokhotnyuk.jsoniter-scala" %%% "jsoniter-scala-macros" % "2.20.0" % "compile-internal" + "com.github.plokhotnyuk.jsoniter-scala" %%% "jsoniter-scala-macros" % "2.20.1" % "compile-internal" ) ) diff --git a/version.sbt b/version.sbt index a2e122185..1d820ef11 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -ThisBuild / version := "2.20.1-SNAPSHOT" +ThisBuild / version := "2.20.1"