Skip to content

Commit 0744343

Browse files
gzliudankaralabe
andcommitted
log: fix formatting of big.Int (ethereum#22679)
* log: fix formatting of big.Int The implementation of formatLogfmtBigInt had two issues: it crashed when the number was actually large enough to hit the big integer case, and modified the big.Int while formatting it. * log: don't call FormatLogfmtInt64 for int16 * log: separate from decimals back, not front Co-authored-by: Péter Szilágyi <[email protected]>
1 parent aedfea6 commit 0744343

File tree

2 files changed

+54
-24
lines changed

2 files changed

+54
-24
lines changed

log/format.go

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -357,20 +357,23 @@ func formatLogfmtValue(value interface{}, term bool) string {
357357
return strconv.FormatFloat(float64(v), floatFormat, 3, 64)
358358
case float64:
359359
return strconv.FormatFloat(v, floatFormat, 3, 64)
360-
case int8, uint8:
361-
return fmt.Sprintf("%d", value)
362-
case int:
363-
return FormatLogfmtInt64(int64(v))
360+
case int8:
361+
return strconv.FormatInt(int64(v), 10)
362+
case uint8:
363+
return strconv.FormatInt(int64(v), 10)
364364
case int16:
365+
return strconv.FormatInt(int64(v), 10)
366+
case uint16:
367+
return strconv.FormatInt(int64(v), 10)
368+
// Larger integers get thousands separators.
369+
case int:
365370
return FormatLogfmtInt64(int64(v))
366371
case int32:
367372
return FormatLogfmtInt64(int64(v))
368373
case int64:
369374
return FormatLogfmtInt64(v)
370375
case uint:
371376
return FormatLogfmtUint64(uint64(v))
372-
case uint16:
373-
return FormatLogfmtUint64(uint64(v))
374377
case uint32:
375378
return FormatLogfmtUint64(uint64(v))
376379
case uint64:
@@ -382,15 +385,15 @@ func formatLogfmtValue(value interface{}, term bool) string {
382385
}
383386
}
384387

385-
// FormatLogfmtInt64 formats a potentially big number in a friendlier split format.
388+
// FormatLogfmtInt64 formats n with thousand separators.
386389
func FormatLogfmtInt64(n int64) string {
387390
if n < 0 {
388391
return formatLogfmtUint64(uint64(-n), true)
389392
}
390393
return formatLogfmtUint64(uint64(n), false)
391394
}
392395

393-
// FormatLogfmtUint64 formats a potentially big number in a friendlier split format.
396+
// FormatLogfmtUint64 formats n with thousand separators.
394397
func FormatLogfmtUint64(n uint64) string {
395398
return formatLogfmtUint64(n, false)
396399
}
@@ -429,31 +432,38 @@ func formatLogfmtUint64(n uint64, neg bool) string {
429432
return string(out[i+1:])
430433
}
431434

432-
var big1000 = big.NewInt(1000)
433-
434-
// formatLogfmtBigInt formats a potentially gigantic number in a friendlier split
435-
// format.
435+
// formatLogfmtBigInt formats n with thousand separators.
436436
func formatLogfmtBigInt(n *big.Int) string {
437-
// Most number don't need fancy handling, just downcast
438437
if n.IsUint64() {
439438
return FormatLogfmtUint64(n.Uint64())
440439
}
441440
if n.IsInt64() {
442441
return FormatLogfmtInt64(n.Int64())
443442
}
444-
// Ok, huge number needs huge effort
445-
groups := make([]string, 0, 8) // random initial size to cover most cases
446-
for n.Cmp(big1000) >= 0 {
447-
_, mod := n.DivMod(n, big1000, nil)
448-
groups = append(groups, fmt.Sprintf("%03d", mod))
449-
}
450-
groups = append(groups, n.String())
451443

452-
last := len(groups) - 1
453-
for i := 0; i < len(groups)/2; i++ {
454-
groups[i], groups[last-i] = groups[last-i], groups[i]
444+
var (
445+
text = n.String()
446+
buf = make([]byte, len(text)+len(text)/3)
447+
comma = 0
448+
i = len(buf) - 1
449+
)
450+
for j := len(text) - 1; j >= 0; j, i = j-1, i-1 {
451+
c := text[j]
452+
453+
switch {
454+
case c == '-':
455+
buf[i] = c
456+
case comma == 3:
457+
buf[i] = ','
458+
i--
459+
comma = 0
460+
fallthrough
461+
default:
462+
buf[i] = c
463+
comma++
464+
}
455465
}
456-
return strings.Join(groups, ",")
466+
return string(buf[i+1:])
457467
}
458468

459469
// escapeString checks if the provided string needs escaping/quoting, and

log/format_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package log
22

33
import (
44
"math"
5+
"math/big"
56
"math/rand"
67
"testing"
78
)
@@ -58,6 +59,25 @@ func TestPrettyUint64(t *testing.T) {
5859
}
5960
}
6061

62+
func TestPrettyBigInt(t *testing.T) {
63+
tests := []struct {
64+
int string
65+
s string
66+
}{
67+
{"111222333444555678999", "111,222,333,444,555,678,999"},
68+
{"-111222333444555678999", "-111,222,333,444,555,678,999"},
69+
{"11122233344455567899900", "11,122,233,344,455,567,899,900"},
70+
{"-11122233344455567899900", "-11,122,233,344,455,567,899,900"},
71+
}
72+
73+
for _, tt := range tests {
74+
v, _ := new(big.Int).SetString(tt.int, 10)
75+
if have := formatLogfmtBigInt(v); have != tt.s {
76+
t.Errorf("invalid output %s, want %s", have, tt.s)
77+
}
78+
}
79+
}
80+
6181
var sink string
6282

6383
func BenchmarkPrettyInt64Logfmt(b *testing.B) {

0 commit comments

Comments
 (0)