Skip to content

Commit 3ec2210

Browse files
committed
More efficient reading of java.time.Duration and java.time.Period values
1 parent 65e0a2f commit 3ec2210

File tree

3 files changed

+110
-111
lines changed
  • jsoniter-scala-core

3 files changed

+110
-111
lines changed

jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2857,27 +2857,27 @@ final class JsonReader private[jsoniter_scala](
28572857

28582858
private[this] def parseDuration(): Duration = {
28592859
var b = nextByte(head)
2860-
var isNeg = false
2860+
var s = 0
28612861
if (b == '-') {
28622862
b = nextByte(head)
2863-
isNeg = true
2863+
s = -1
28642864
}
2865-
if (b != 'P') durationOrPeriodStartError(isNeg)
2865+
if (b != 'P') durationOrPeriodStartError(s)
28662866
b = nextByte(head)
2867-
var state = 0
2867+
var state = -1
28682868
if (b == 'T') {
28692869
b = nextByte(head)
2870-
state = 1
2870+
state = 0
28712871
}
28722872
var seconds = 0L
28732873
var nano = 0
28742874
while ({
2875-
var isNegX = false
2875+
var sx = s
28762876
if (b == '-') {
28772877
b = nextByte(head)
2878-
isNegX = true
2878+
sx = ~sx
28792879
}
2880-
if (b < '0' || b > '9') durationOrPeriodDigitError(isNegX, state <= 1)
2880+
if (b < '0' || b > '9') durationOrPeriodDigitError(s, sx, state)
28812881
var x1 = '0' - b
28822882
var pos = head
28832883
var buf = this.buf
@@ -2907,22 +2907,22 @@ final class JsonReader private[jsoniter_scala](
29072907
}) durationError(pos)
29082908
pos += 1
29092909
}
2910-
if (!(isNeg ^ isNegX)) {
2910+
if (sx == 0) {
29112911
if (x == -9223372036854775808L) durationError(pos)
29122912
x = -x
29132913
}
2914-
if (b == 'D' && state <= 0) {
2914+
if (b == 'D' && state < 0) {
29152915
if (x < -106751991167300L || x > 106751991167300L) durationError(pos) // -106751991167300L == Long.MinValue / 86400
29162916
seconds = x * 86400
2917-
state = 1
2918-
} else if (b == 'H' && state <= 1) {
2917+
state = 0
2918+
} else if (b == 'H' && state <= 0) {
29192919
if (x < -2562047788015215L || x > 2562047788015215L) durationError(pos) // -2562047788015215L == Long.MinValue / 3600
29202920
seconds = sumSeconds(x * 3600, seconds, pos)
2921-
state = 2
2922-
} else if (b == 'M' && state <= 2) {
2921+
state = 1
2922+
} else if (b == 'M' && state <= 1) {
29232923
if (x < -153722867280912930L || x > 153722867280912930L) durationError(pos) // -153722867280912930L == Long.MinValue / 60
29242924
seconds = sumSeconds(x * 60, seconds, pos)
2925-
state = 3
2925+
state = 2
29262926
} else if (b == '.') {
29272927
pos += 1
29282928
seconds = sumSeconds(x, seconds, pos)
@@ -2940,19 +2940,19 @@ final class JsonReader private[jsoniter_scala](
29402940
pos += 1
29412941
}
29422942
if (b != 'S') nanoError(nanoDigitWeight, 'S', pos)
2943-
if (isNeg ^ isNegX) nano = -nano
2944-
state = 4
2943+
nano = (nano ^ sx) - sx
2944+
state = 3
29452945
} else if (b == 'S') {
29462946
seconds = sumSeconds(x, seconds, pos)
2947-
state = 4
2947+
state = 3
29482948
} else durationError(state, pos)
29492949
b = nextByte(pos + 1)
29502950
b != '"'
29512951
}) {
2952-
if (state == 1) {
2952+
if (state == 0) {
29532953
if (b != 'T') tokensError('T', '"')
29542954
b = nextByte(head)
2955-
} else if (state == 4) tokenError('"')
2955+
} else if (state == 3) tokenError('"')
29562956
}
29572957
Duration.ofSeconds(seconds, nano.toLong)
29582958
}
@@ -3139,21 +3139,21 @@ final class JsonReader private[jsoniter_scala](
31393139

31403140
private[this] def parsePeriod(): Period = {
31413141
var b = nextByte(head)
3142-
var isNeg = false
3142+
var s = 0
31433143
if (b == '-') {
31443144
b = nextByte(head)
3145-
isNeg = true
3145+
s = -1
31463146
}
3147-
if (b != 'P') durationOrPeriodStartError(isNeg)
3147+
if (b != 'P') durationOrPeriodStartError(s)
31483148
b = nextByte(head)
31493149
var years, months, days, state = 0
31503150
while ({
3151-
var isNegX = false
3151+
var sx = s
31523152
if (b == '-') {
31533153
b = nextByte(head)
3154-
isNegX = true
3154+
sx = ~sx
31553155
}
3156-
if (b < '0' || b > '9') durationOrPeriodDigitError(isNegX, state <= 0)
3156+
if (b < '0' || b > '9') durationOrPeriodDigitError(s, sx, state)
31573157
var x = '0' - b
31583158
var pos = head
31593159
var buf = this.buf
@@ -3171,7 +3171,7 @@ final class JsonReader private[jsoniter_scala](
31713171
}) periodError(pos)
31723172
pos += 1
31733173
}
3174-
if (!(isNeg ^ isNegX)) {
3174+
if (sx == 0) {
31753175
if (x == -2147483648) periodError(pos)
31763176
x = -x
31773177
}
@@ -3186,10 +3186,10 @@ final class JsonReader private[jsoniter_scala](
31863186
days = x * 7
31873187
state = 3
31883188
} else if (b == 'D') {
3189-
val ds = x.toLong + days
3190-
days = ds.toInt
3189+
val d = days
3190+
days += x
31913191
state = 4
3192-
if (ds != days) periodError(pos)
3192+
if (((x ^ days) & (d ^ days)) < 0) periodError(pos)
31933193
} else periodError(state, pos)
31943194
b = nextByte(pos + 1)
31953195
b != '"'
@@ -3376,23 +3376,23 @@ final class JsonReader private[jsoniter_scala](
33763376
case _ => "expected 'D' or digit"
33773377
}, pos)
33783378

3379-
private[this] def durationOrPeriodStartError(isNeg: Boolean): Nothing = decodeError {
3380-
if (isNeg) "expected 'P'"
3379+
private[this] def durationOrPeriodStartError(s: Int): Nothing = decodeError {
3380+
if (s < 0) "expected 'P'"
33813381
else "expected 'P' or '-'"
33823382
}
33833383

3384-
private[this] def durationOrPeriodDigitError(isNegX: Boolean, isNumReq: Boolean): Nothing = decodeError {
3385-
if (isNegX) "expected digit"
3386-
else if (isNumReq) "expected '-' or digit"
3384+
private[this] def durationOrPeriodDigitError(s: Int, sx: Int, state: Int): Nothing = decodeError {
3385+
if ((s ^ sx) < 0) "expected digit"
3386+
else if (state <= 0) "expected '-' or digit"
33873387
else "expected '\"' or '-' or digit"
33883388
}
33893389

33903390
private[this] def durationError(pos: Int): Nothing = decodeError("illegal duration", pos)
33913391

33923392
private[this] def durationError(state: Int, pos: Int): Nothing = decodeError(state match {
3393-
case 0 => "expected 'D' or digit"
3394-
case 1 => "expected 'H' or 'M' or 'S or '.' or digit"
3395-
case 2 => "expected 'M' or 'S or '.' or digit"
3393+
case -1 => "expected 'D' or digit"
3394+
case 0 => "expected 'H' or 'M' or 'S or '.' or digit"
3395+
case 1 => "expected 'M' or 'S or '.' or digit"
33963396
case _ => "expected 'S or '.' or digit"
33973397
}, pos)
33983398

@@ -3414,10 +3414,9 @@ final class JsonReader private[jsoniter_scala](
34143414

34153415
private[this] def secondError(pos: Int): Nothing = decodeError("illegal second", pos)
34163416

3417-
private[this] def nanoError(nanoDigitWeight: Int, t: Byte, pos: Int): Nothing = {
3417+
private[this] def nanoError(nanoDigitWeight: Int, t: Byte, pos: Int): Nothing =
34183418
if (nanoDigitWeight == 0) tokenError(t, pos)
3419-
tokenOrDigitError(t, pos)
3420-
}
3419+
else tokenOrDigitError(t, pos)
34213420

34223421
private[this] def timeError(nanoDigitWeight: Int): Nothing = decodeError {
34233422
if (nanoDigitWeight == -2) "expected '.' or '+' or '-' or 'Z'"

jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2885,27 +2885,27 @@ final class JsonReader private[jsoniter_scala](
28852885

28862886
private[this] def parseDuration(): Duration = {
28872887
var b = nextByte(head)
2888-
var isNeg = false
2888+
var s = 0
28892889
if (b == '-') {
28902890
b = nextByte(head)
2891-
isNeg = true
2891+
s = -1
28922892
}
2893-
if (b != 'P') durationOrPeriodStartError(isNeg)
2893+
if (b != 'P') durationOrPeriodStartError(s)
28942894
b = nextByte(head)
2895-
var state = 0
2895+
var state = -1
28962896
if (b == 'T') {
28972897
b = nextByte(head)
2898-
state = 1
2898+
state = 0
28992899
}
29002900
var seconds = 0L
29012901
var nano = 0
29022902
while ({
2903-
var isNegX = false
2903+
var sx = s
29042904
if (b == '-') {
29052905
b = nextByte(head)
2906-
isNegX = true
2906+
sx = ~sx
29072907
}
2908-
if (b < '0' || b > '9') durationOrPeriodDigitError(isNegX, state <= 1)
2908+
if (b < '0' || b > '9') durationOrPeriodDigitError(s, sx, state)
29092909
var x = ('0' - b).toLong
29102910
var pos = head
29112911
var buf = this.buf
@@ -2923,22 +2923,22 @@ final class JsonReader private[jsoniter_scala](
29232923
}) durationError(pos)
29242924
pos += 1
29252925
}
2926-
if (!(isNeg ^ isNegX)) {
2926+
if (sx == 0) {
29272927
if (x == -9223372036854775808L) durationError(pos)
29282928
x = -x
29292929
}
2930-
if (b == 'D' && state <= 0) {
2930+
if (b == 'D' && state < 0) {
29312931
if (x < -106751991167300L || x > 106751991167300L) durationError(pos) // -106751991167300L == Long.MinValue / 86400
29322932
seconds = x * 86400
2933-
state = 1
2934-
} else if (b == 'H' && state <= 1) {
2933+
state = 0
2934+
} else if (b == 'H' && state <= 0) {
29352935
if (x < -2562047788015215L || x > 2562047788015215L) durationError(pos) // -2562047788015215L == Long.MinValue / 3600
29362936
seconds = sumSeconds(x * 3600, seconds, pos)
2937-
state = 2
2938-
} else if (b == 'M' && state <= 2) {
2937+
state = 1
2938+
} else if (b == 'M' && state <= 1) {
29392939
if (x < -153722867280912930L || x > 153722867280912930L) durationError(pos) // -153722867280912930L == Long.MinValue / 60
29402940
seconds = sumSeconds(x * 60, seconds, pos)
2941-
state = 3
2941+
state = 2
29422942
} else if (b == '.') {
29432943
pos += 1
29442944
seconds = sumSeconds(x, seconds, pos)
@@ -2979,19 +2979,19 @@ final class JsonReader private[jsoniter_scala](
29792979
}
29802980
}
29812981
if (b != 'S') nanoError(nanoDigitWeight, 'S', pos)
2982-
if (isNeg ^ isNegX) nano = -nano
2983-
state = 4
2982+
nano = (nano ^ sx) - sx
2983+
state = 3
29842984
} else if (b == 'S') {
29852985
seconds = sumSeconds(x, seconds, pos)
2986-
state = 4
2986+
state = 3
29872987
} else durationError(state, pos)
29882988
b = nextByte(pos + 1)
29892989
b != '"'
29902990
}) {
2991-
if (state == 1) {
2991+
if (state == 0) {
29922992
if (b != 'T') tokensError('T', '"')
29932993
b = nextByte(head)
2994-
} else if (state == 4) tokenError('"')
2994+
} else if (state == 3) tokenError('"')
29952995
}
29962996
Duration.ofSeconds(seconds, nano.toLong)
29972997
}
@@ -3486,21 +3486,21 @@ final class JsonReader private[jsoniter_scala](
34863486

34873487
private[this] def parsePeriod(): Period = {
34883488
var b = nextByte(head)
3489-
var isNeg = false
3489+
var s = 0
34903490
if (b == '-') {
34913491
b = nextByte(head)
3492-
isNeg = true
3492+
s = -1
34933493
}
3494-
if (b != 'P') durationOrPeriodStartError(isNeg)
3494+
if (b != 'P') durationOrPeriodStartError(s)
34953495
b = nextByte(head)
34963496
var years, months, days, state = 0
34973497
while ({
3498-
var isNegX = false
3498+
var sx = s
34993499
if (b == '-') {
35003500
b = nextByte(head)
3501-
isNegX = true
3501+
sx = ~sx
35023502
}
3503-
if (b < '0' || b > '9') durationOrPeriodDigitError(isNegX, state <= 0)
3503+
if (b < '0' || b > '9') durationOrPeriodDigitError(s, sx, state)
35043504
var x = '0' - b
35053505
var pos = head
35063506
var buf = this.buf
@@ -3518,7 +3518,7 @@ final class JsonReader private[jsoniter_scala](
35183518
}) periodError(pos)
35193519
pos += 1
35203520
}
3521-
if (!(isNeg ^ isNegX)) {
3521+
if (sx == 0) {
35223522
if (x == -2147483648) periodError(pos)
35233523
x = -x
35243524
}
@@ -3811,23 +3811,23 @@ final class JsonReader private[jsoniter_scala](
38113811
case _ => "expected 'D' or digit"
38123812
}, pos)
38133813

3814-
private[this] def durationOrPeriodStartError(isNeg: Boolean): Nothing = decodeError {
3815-
if (isNeg) "expected 'P'"
3814+
private[this] def durationOrPeriodStartError(s: Int): Nothing = decodeError {
3815+
if (s < 0) "expected 'P'"
38163816
else "expected 'P' or '-'"
38173817
}
38183818

3819-
private[this] def durationOrPeriodDigitError(isNegX: Boolean, isNumReq: Boolean): Nothing = decodeError {
3820-
if (isNegX) "expected digit"
3821-
else if (isNumReq) "expected '-' or digit"
3819+
private[this] def durationOrPeriodDigitError(s: Int, sx: Int, state: Int): Nothing = decodeError {
3820+
if ((s ^ sx) < 0) "expected digit"
3821+
else if (state <= 0) "expected '-' or digit"
38223822
else "expected '\"' or '-' or digit"
38233823
}
38243824

38253825
private[this] def durationError(pos: Int): Nothing = decodeError("illegal duration", pos)
38263826

38273827
private[this] def durationError(state: Int, pos: Int): Nothing = decodeError(state match {
3828-
case 0 => "expected 'D' or digit"
3829-
case 1 => "expected 'H' or 'M' or 'S or '.' or digit"
3830-
case 2 => "expected 'M' or 'S or '.' or digit"
3828+
case -1 => "expected 'D' or digit"
3829+
case 0 => "expected 'H' or 'M' or 'S or '.' or digit"
3830+
case 1 => "expected 'M' or 'S or '.' or digit"
38313831
case _ => "expected 'S or '.' or digit"
38323832
}, pos)
38333833

0 commit comments

Comments
 (0)