Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ jobs:
- 11
- 21
os:
- macos-14
- windows-2022
- ubuntu-22.04-arm
- ubuntu-22.04
fail-fast: false
Expand All @@ -41,6 +43,7 @@ jobs:
- name: Setup Scala with SBT
uses: coursier/setup-action@v1
with:
jvm: temurin:${{ matrix.java }}
apps: sbt
- name: Setup Node.js
uses: actions/setup-node@v4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2287,7 +2287,7 @@ final class JsonReader private[jsoniter_scala](
else if (e10 >= 310) Double.PositiveInfinity
else {
var shift = java.lang.Long.numberOfLeadingZeros(m10)
var m2 = NativeMath.unsignedMultiplyHigh(pow10Mantissas(e10 + 343), m10 << shift)
var m2 = unsignedMultiplyHigh(pow10Mantissas(e10 + 343), m10 << shift) // FIXME: Use Math.unsignedMultiplyHigh after dropping of JDK 17 support
var e2 = (e10 * 108853 >> 15) - shift + 1 // (e10 * Math.log(10) / Math.log(2)).toInt - shift + 1
shift = java.lang.Long.numberOfLeadingZeros(m2)
m2 <<= shift
Expand Down Expand Up @@ -2435,7 +2435,7 @@ final class JsonReader private[jsoniter_scala](
else if (e10 >= 39) Float.PositiveInfinity
else {
var shift = java.lang.Long.numberOfLeadingZeros(m10)
var m2 = NativeMath.unsignedMultiplyHigh(pow10Mantissas(e10 + 343), m10 << shift)
var m2 = unsignedMultiplyHigh(pow10Mantissas(e10 + 343), m10 << shift) // FIXME: Use Math.unsignedMultiplyHigh after dropping of JDK 17 support
var e2 = (e10 * 108853 >> 15) - shift + 1 // (e10 * Math.log(10) / Math.log(2)).toInt - shift + 1
shift = java.lang.Long.numberOfLeadingZeros(m2)
m2 <<= shift
Expand Down Expand Up @@ -2469,6 +2469,9 @@ final class JsonReader private[jsoniter_scala](
java.lang.Float.parseFloat(new String(buf, 0, offset, pos - offset))
}

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

def readBigInt(isToken: Boolean, default: BigInt, digitsLimit: Int): BigInt = {
var b =
if (isToken) nextToken(head)
Expand Down Expand Up @@ -2837,7 +2840,7 @@ final class JsonReader private[jsoniter_scala](
i -= 8
i >= first
}) {
x = NativeMath.unsignedMultiplyHigh(m, q) + ((~x & mq) >>> 63)
x = Math.multiplyHigh(m, q) + (m >> 63 & q) + ((~x & mq) >>> 63) // TODO: when dropping JDK 17 support replace by Math.unsignedMultiplyHigh(m, q) + ((~x & mq) >>> 63)
}
}
var i = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1560,7 +1560,7 @@ final class JsonWriter private[jsoniter_scala](
pos += digitCount(exp)
count = pos
} else {
q = NativeMath.multiplyHigh(exp, 6189700196426901375L) >>> 25 // divide a positive long by 100000000
q = Math.multiplyHigh(exp, 6189700196426901375L) >>> 25 // divide a positive long by 100000000
pos += digitCount(q)
count = write8Digits(exp - q * 100000000L, pos, buf, ds)
}
Expand Down Expand Up @@ -1696,7 +1696,7 @@ final class JsonWriter private[jsoniter_scala](
var hours = 0L
var secsOfHour = totalSecs.toInt
if (totalSecs >= 3600) {
hours = NativeMath.multiplyHigh(totalSecs >> 4, 655884233731895169L) >> 3 // divide a positive long by 3600
hours = Math.multiplyHigh(totalSecs >> 4, 655884233731895169L) >> 3 // divide a positive long by 3600
secsOfHour = (totalSecs - hours * 3600).toInt
}
val minutes = secsOfHour * 17477 >> 20 // divide a small positive int by 60
Expand All @@ -1713,7 +1713,7 @@ final class JsonWriter private[jsoniter_scala](
lastPos += digitCount(hours)
pos = lastPos
} else {
q = NativeMath.multiplyHigh(hours, 6189700196426901375L) >>> 25 // divide a positive long by 100000000
q = Math.multiplyHigh(hours, 6189700196426901375L) >>> 25 // divide a positive long by 100000000
lastPos += digitCount(q)
pos = write8Digits(hours - q * 100000000L, lastPos, buf, ds)
}
Expand Down Expand Up @@ -1766,9 +1766,9 @@ final class JsonWriter private[jsoniter_scala](
val epochSecond = x.getEpochSecond
if (epochSecond < 0) writeBeforeEpochInstant(epochSecond, x.getNano)
else {
val epochDay = NativeMath.multiplyHigh(epochSecond, 1749024623285053783L) >> 13 // epochSecond / 86400
val epochDay = Math.multiplyHigh(epochSecond, 1749024623285053783L) >> 13 // epochSecond / 86400
val marchZeroDay = epochDay + 719468 // 719468 == 719528 - 60 == days 0000 to 1970 - days 1st Jan to 1st Mar
var year = (NativeMath.multiplyHigh(marchZeroDay * 400 + 591, 4137408090565272301L) >> 15).toInt // ((marchZeroDay * 400 + 591) / 146097).toInt
var year = (Math.multiplyHigh(marchZeroDay * 400 + 591, 4137408090565272301L) >> 15).toInt // ((marchZeroDay * 400 + 591) / 146097).toInt
var days = year * 365L
var year1374389535 = year * 1374389535L
var century = (year1374389535 >> 37).toInt
Expand All @@ -1790,11 +1790,11 @@ final class JsonWriter private[jsoniter_scala](
}

private[this] def writeBeforeEpochInstant(epochSecond: Long, nano: Int): Unit = {
val epochDay = (NativeMath.multiplyHigh(epochSecond - 86399, 1749024623285053783L) >> 13) + 1 // (epochSecond - 86399) / 86400
val epochDay = (Math.multiplyHigh(epochSecond - 86399, 1749024623285053783L) >> 13) + 1 // (epochSecond - 86399) / 86400
var marchZeroDay = epochDay + 719468 // 719468 == 719528 - 60 == days 0000 to 1970 - days 1st Jan to 1st Mar
val adjust400YearCycles = ((marchZeroDay + 1) * 7525902 >> 40).toInt // ((marchZeroDay + 1) / 146097).toInt - 1
marchZeroDay -= adjust400YearCycles * 146097L
var year = (NativeMath.multiplyHigh(marchZeroDay * 400 + 591, 4137408090565272301L) >> 15).toInt // ((marchZeroDay * 400 + 591) / 146097).toInt
var year = (Math.multiplyHigh(marchZeroDay * 400 + 591, 4137408090565272301L) >> 15).toInt // ((marchZeroDay * 400 + 591) / 146097).toInt
var days = year * 365L
var year1374389535 = year * 1374389535L
var century = (year1374389535 >> 37).toInt
Expand Down Expand Up @@ -2140,8 +2140,8 @@ final class JsonWriter private[jsoniter_scala](

private[this] def write18Digits(x: Long, pos: Int, buf: Array[Byte], ds: Array[Short]): Int = {
val m1 = 6189700196426901375L
val q1 = NativeMath.multiplyHigh(x, m1) >>> 25 // divide a positive long by 100000000
val q2 = NativeMath.multiplyHigh(q1, m1) >>> 25 // divide a positive long by 100000000
val q1 = Math.multiplyHigh(x, m1) >>> 25 // divide a positive long by 100000000
val q2 = Math.multiplyHigh(q1, m1) >>> 25 // divide a positive long by 100000000
ByteArrayAccess.setShort(buf, pos, ds(q2.toInt))
write8Digits(x - q1 * 100000000L, write8Digits(q1 - q2 * 100000000L, pos + 2, buf, ds), buf, ds)
}
Expand Down Expand Up @@ -2230,13 +2230,13 @@ final class JsonWriter private[jsoniter_scala](
pos = lastPos
} else {
val m2 = 6189700196426901375L
val q1 = NativeMath.multiplyHigh(q0, m2) >>> 25 // divide a positive long by 100000000
val q1 = Math.multiplyHigh(q0, m2) >>> 25 // divide a positive long by 100000000
if (q1 < m1) {
q2 = q1
lastPos += digitCount(q1)
pos = lastPos
} else {
q2 = NativeMath.multiplyHigh(q1, m2) >>> 25 // divide a small positive long by 100000000
q2 = Math.multiplyHigh(q1, m2) >>> 25 // divide a small positive long by 100000000
lastPos += digitCount(q2)
pos = write8Digits(q1 - q2 * m1, lastPos, buf, ds)
}
Expand Down Expand Up @@ -2354,7 +2354,7 @@ final class JsonWriter private[jsoniter_scala](
}

private[this] def rop(g: Long, cp: Int): Int = {
val x = NativeMath.multiplyHigh(g, cp.toLong << 32)
val x = Math.multiplyHigh(g, cp.toLong << 32)
(x >>> 31).toInt | -x.toInt >>> 31
}

Expand Down Expand Up @@ -2407,7 +2407,7 @@ final class JsonWriter private[jsoniter_scala](
val vbr = rop(g1, g0, cb + 2 << h) - vbCorr
var diff = 0
if (vb < 400 || {
m10 = NativeMath.multiplyHigh(vb, 461168601842738792L) // divide a positive long by 40
m10 = Math.multiplyHigh(vb, 461168601842738792L) // divide a positive long by 40
val vb40 = m10 * 40
diff = (vbl - vb40).toInt
((vb40 - vbr).toInt + 40 ^ diff) >= 0
Expand Down Expand Up @@ -2470,8 +2470,8 @@ final class JsonWriter private[jsoniter_scala](
}

private[this] def rop(g1: Long, g0: Long, cp: Long): Long = {
val x = NativeMath.multiplyHigh(g0, cp) + (g1 * cp >>> 1)
NativeMath.multiplyHigh(g1, cp) + (x >>> 63) | (-x ^ x) >>> 63
val x = Math.multiplyHigh(g0, cp) + (g1 * cp >>> 1)
Math.multiplyHigh(g1, cp) + (x >>> 63) | (-x ^ x) >>> 63
}

// Adoption of a nice trick from Daniel Lemire's blog that works for numbers up to 10^18:
Expand All @@ -2483,7 +2483,7 @@ final class JsonWriter private[jsoniter_scala](
var pos = p
var posLim = pl
if (q0 != x) {
val q1 = (NativeMath.multiplyHigh(x, 6189700196426901375L) >>> 25).toInt // divide a positive long by 100000000
val q1 = (Math.multiplyHigh(x, 6189700196426901375L) >>> 25).toInt // divide a positive long by 100000000
val r1 = (x - q1 * 100000000L).toInt
val posm8 = pos - 8
if (r1 == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ class JsonWriterSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyCh
}

Array(
1405345091900L, // See: https://github.com/plokhotnyuk/jsoniter-scala/issues/1247
6950401124099999999L,
7379897853799999999L,
7809394583499999999L,
Expand Down