Skip to content

Commit 42c5c70

Browse files
committed
hoist overflow check from for each num to on usage
This was done to have less branches in the hot path for numbers, thus has little to no impact on shorter inputs, still a ~5% improvement: After the change: goos: linux goarch: amd64 pkg: github.com/xnacly/go-iso8601-duration cpu: AMD Ryzen 7 3700X 8-Core Processor BenchmarkDuration/P0D-16 100000000 10.01 ns/op BenchmarkDuration/PT15H-16 100000000 11.81 ns/op BenchmarkDuration/P1W-16 100000000 10.19 ns/op BenchmarkDuration/P15W-16 120588932 9.779 ns/op BenchmarkDuration/P1Y15W-16 86265106 13.76 ns/op BenchmarkDuration/P15Y-16 122859478 9.910 ns/op BenchmarkDuration/P15Y3M-16 77137617 14.32 ns/op BenchmarkDuration/P15Y3M41D-16 60263616 20.74 ns/op BenchmarkDuration/PT15M-16 96869085 12.30 ns/op BenchmarkDuration/PT15M10S-16 63139969 18.33 ns/op BenchmarkDuration/P3Y6M4DT12H30M5S-16 29586862 39.14 ns/op PASS ok github.com/xnacly/go-iso8601-duration 14.812s Before the change: goos: linux goarch: amd64 pkg: github.com/xnacly/go-iso8601-duration cpu: AMD Ryzen 7 3700X 8-Core Processor BenchmarkDuration/P0D-16 120725466 9.931 ns/op 0 B/o 0 allocs/op BenchmarkDuration/PT15H-16 92520681 11.67 ns/op 0 B/o 0 allocs/op BenchmarkDuration/P1W-16 100000000 10.15 ns/op 0 B/o 0 allocs/op BenchmarkDuration/P15W-16 100000000 10.26 ns/op 0 B/o 0 allocs/op BenchmarkDuration/P1Y15W-16 82810779 14.83 ns/op 0 B/o 0 allocs/op BenchmarkDuration/P15Y-16 120902158 10.29 ns/op 0 B/o 0 allocs/op BenchmarkDuration/P15Y3M-16 75393909 15.68 ns/op 0 B/o 0 allocs/op BenchmarkDuration/P15Y3M41D-16 56214748 22.31 ns/op 0 B/o 0 allocs/op BenchmarkDuration/PT15M-16 91787005 12.85 ns/op 0 B/o 0 allocs/op BenchmarkDuration/PT15M10S-16 53683030 19.45 ns/op 0 B/o 0 allocs/op BenchmarkDuration/P3Y6M4DT12H30M5S-16 28636116 42.47 ns/op 0 B/op 0 allocs/op PASS ok github.com/xnacly/go-iso8601-duration 14.860s
1 parent 7c68f81 commit 42c5c70

1 file changed

Lines changed: 20 additions & 26 deletions

File tree

duration.go

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func From(s string) (Duration, error) {
101101
}
102102

103103
curState := stateStart
104-
var num int64
104+
var num uint64
105105
var hasNum bool
106106

107107
for col, b := range []byte(s) {
@@ -122,96 +122,90 @@ func From(s string) (Duration, error) {
122122
if b == 'T' {
123123
curState = stateT
124124
} else if '0' <= b && b <= '9' {
125-
num = (num * 10) + int64(b-'0')
125+
num = (num * 10) + uint64(b-'0')
126126
hasNum = true
127127
curState = stateNumber
128128
} else {
129129
return duration, wrapErr(MissingNumber, col)
130130
}
131131
case stateNumber:
132132
if '0' <= b && b <= '9' {
133-
digit := int64(b - '0')
134-
if num > (math.MaxInt64-digit)/10 {
135-
return duration, DesignatorNumberTooLarge
136-
}
137-
num = (num * 10) + digit
133+
num = (num * 10) + uint64(b-'0')
138134
hasNum = true
139135
curState = stateNumber
140136
} else {
141137
if !hasNum {
142138
return duration, wrapErr(MissingNumber, col)
143139
}
140+
141+
if num > math.MaxInt64 {
142+
return duration, DesignatorNumberTooLarge
143+
}
144+
144145
switch b {
145146
case 'Y':
146147
if duration.year != 0 {
147148
return duration, wrapErr(DuplicateDesignator, col)
148149
}
149-
duration.year = num
150+
duration.year = int64(num)
150151
case 'M':
151152
if duration.month != 0 {
152153
return duration, wrapErr(DuplicateDesignator, col)
153154
}
154-
duration.month = num
155+
duration.month = int64(num)
155156
case 'W':
156157
if duration.week != 0 {
157158
return duration, wrapErr(DuplicateDesignator, col)
158159
}
159-
duration.week = num
160+
duration.week = int64(num)
160161
case 'D':
161162
if duration.day != 0 {
162163
return duration, wrapErr(DuplicateDesignator, col)
163164
}
164-
duration.day = num
165+
duration.day = int64(num)
165166
default:
166-
167167
return duration, wrapErr(UnknownDesignator, col)
168168
}
169169
num = 0
170170
curState = stateDesignator
171171
}
172172
case stateT, stateTDesignator:
173173
if '0' <= b && b <= '9' {
174-
digit := int64(b - '0')
175-
if num > (math.MaxInt64-digit)/10 {
176-
return duration, DesignatorNumberTooLarge
177-
}
178-
num = (num * 10) + digit
174+
num = (num * 10) + uint64(b-'0')
179175
hasNum = true
180176
curState = stateTNumber
181177
} else {
182178
return duration, wrapErr(MissingNumber, col)
183179
}
184180
case stateTNumber:
185181
if '0' <= b && b <= '9' {
186-
digit := int64(b - '0')
187-
if num > (math.MaxInt64-digit)/10 {
188-
return duration, DesignatorNumberTooLarge
189-
}
190-
num = (num * 10) + digit
182+
num = (num * 10) + uint64(b-'0')
191183
hasNum = true
192184
curState = stateTNumber
193185
} else {
194186
if !hasNum {
195187
return duration, wrapErr(MissingNumber, col)
196188
}
189+
if num > math.MaxInt64 {
190+
return duration, DesignatorNumberTooLarge
191+
}
197192
switch b {
198193
case 'H':
199194
if duration.hour != 0 {
200195
return duration, wrapErr(DuplicateDesignator, col)
201196
}
202-
duration.hour = num
197+
duration.hour = int64(num)
203198
case 'M':
204199
if duration.minute != 0 {
205200
return duration, wrapErr(DuplicateDesignator, col)
206201
}
207-
duration.minute = num
202+
duration.minute = int64(num)
208203
case 'S':
209204
if duration.second != 0 {
210205
return duration, wrapErr(DuplicateDesignator, col)
211206
}
212-
duration.second = num
207+
duration.second = int64(num)
213208
default:
214-
215209
return duration, wrapErr(UnknownDesignator, col)
216210
}
217211
num = 0

0 commit comments

Comments
 (0)