From a9ee02699145d4644883fab25227017f216efe29 Mon Sep 17 00:00:00 2001 From: James Williams Date: Mon, 29 Aug 2022 17:52:23 +0100 Subject: [PATCH] fmt: display contained values when formatting atomic booleans and integers * treat `atomic.{Int32,Int64,Uint32,Uint64}` values as integers when formatting, using the underlying integer value (by calling Load). This has the effect of, for example, formatting an atomic integer type containing 42 as "42", not "{{}, 42}"). * treat `atomic.Bool` values as booleans when formatting, using the contained boolean value (by calling Load). This has the effect of, for example, formatting an true atomic.Bool value containing as "true", not "{{}, 1}" or "{{} %!t(uint32=1)}" as before. Fixes https://github.com/golang/go/issues/54731 --- src/fmt/fmt_test.go | 57 +++++++++++++++++++++++++++++++++++++++++++++ src/fmt/print.go | 21 +++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index aaeac3875a5e67..4f7124e8b9b481 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -13,6 +13,7 @@ import ( "reflect" "runtime" "strings" + "sync/atomic" "testing" "time" "unicode" @@ -39,6 +40,36 @@ type ( renamedComplex128 complex128 ) +func newAtomicInt32(val int32) *atomic.Int32 { + var r atomic.Int32 + r.Store(val) + return &r +} + +func newAtomicUint32(val uint32) *atomic.Uint32 { + var r atomic.Uint32 + r.Store(val) + return &r +} + +func newAtomicInt64(val int64) *atomic.Int64 { + var r atomic.Int64 + r.Store(val) + return &r +} + +func newAtomicUint64(val uint64) *atomic.Uint64 { + var r atomic.Uint64 + r.Store(val) + return &r +} + +func newAtomicBool(val bool) *atomic.Bool { + var r atomic.Bool + r.Store(val) + return &r +} + func TestFmtInterface(t *testing.T) { var i1 any i1 = "abc" @@ -1081,6 +1112,32 @@ var fmtTests = []struct { {"%☠", SI{&[]any{I(1), G(2)}}, "{%!☠(*[]interface {}=&[1 2])}"}, {"%☠", reflect.Value{}, ""}, {"%☠", map[float64]int{NaN: 1}, "map[%!☠(float64=NaN):%!☠(int=1)]"}, + + // atomics + {"%d", newAtomicInt32(25), "25"}, + {"%d", newAtomicInt32(math.MaxInt32), "2147483647"}, + {"%d", newAtomicInt32(-5), "-5"}, + {"%d", newAtomicInt32(math.MinInt32), "-2147483648"}, + + {"%d", newAtomicUint32(19), "19"}, + {"%d", newAtomicUint32(math.MaxUint32), "4294967295"}, + + {"%d", newAtomicInt64(99), "99"}, + {"%d", newAtomicInt64(math.MaxInt64), "9223372036854775807"}, + {"%d", newAtomicInt64(-7), "-7"}, + {"%d", newAtomicInt64(math.MinInt64), "-9223372036854775808"}, + + {"%d", newAtomicUint64(12), "12"}, + {"%d", newAtomicUint64(math.MaxUint64), "18446744073709551615"}, + + {"%t", newAtomicBool(true), "true"}, + {"%t", newAtomicBool(false), "false"}, + + {"%v", newAtomicInt32(42), "42"}, + {"%v", newAtomicUint32(4242), "4242"}, + {"%v", newAtomicInt64(424242), "424242"}, + {"%v", newAtomicUint64(42424242), "42424242"}, + {"%v", newAtomicBool(true), "true"}, } // zeroFill generates zero-filled strings of the specified width. The length diff --git a/src/fmt/print.go b/src/fmt/print.go index 85f70439f3be50..5b85530de13dd1 100644 --- a/src/fmt/print.go +++ b/src/fmt/print.go @@ -11,6 +11,7 @@ import ( "reflect" "strconv" "sync" + "sync/atomic" "unicode/utf8" ) @@ -747,6 +748,26 @@ func (p *pp) printArg(arg any, verb rune) { p.fmtInteger(f, unsigned, verb) case uintptr: p.fmtInteger(uint64(f), unsigned, verb) + case atomic.Int32: + p.fmtInteger(uint64(f.Load()), signed, verb) + case *atomic.Int32: + p.fmtInteger(uint64(f.Load()), signed, verb) + case atomic.Int64: + p.fmtInteger(uint64(f.Load()), signed, verb) + case *atomic.Int64: + p.fmtInteger(uint64(f.Load()), signed, verb) + case atomic.Uint32: + p.fmtInteger(uint64(f.Load()), unsigned, verb) + case *atomic.Uint32: + p.fmtInteger(uint64(f.Load()), unsigned, verb) + case atomic.Uint64: + p.fmtInteger(uint64(f.Load()), unsigned, verb) + case *atomic.Uint64: + p.fmtInteger(uint64(f.Load()), unsigned, verb) + case atomic.Bool: + p.fmtBool(f.Load(), verb) + case *atomic.Bool: + p.fmtBool(f.Load(), verb) case string: p.fmtString(f, verb) case []byte: