diff options
| author | Michael Pratt <mpratt@google.com> | 2025-05-14 15:53:58 -0400 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-05-19 12:46:19 -0700 |
| commit | 76e7bfbb4e3a6114a33c7dba666fdd26698bedc5 (patch) | |
| tree | a3c5738900dba5ff5e40f43ddda7dcb14b9ddae2 /src/internal/runtime | |
| parent | d93bea0e59e51c2d85e69f28f09726b5c9fc81d2 (diff) | |
| download | go-76e7bfbb4e3a6114a33c7dba666fdd26698bedc5.tar.xz | |
runtime: move atoi to internal/runtime/strconv
Moving to a smaller package allows its use in other internal/runtime
packages.
This isn't internal/strconvlite since it can't be used directly by
strconv.
For #73193.
Change-Id: I6a6a636c9c8b3f06b5fd6c07fe9dd5a7a37d1429
Reviewed-on: https://go-review.googlesource.com/c/go/+/672697
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/internal/runtime')
| -rw-r--r-- | src/internal/runtime/math/math.go | 3 | ||||
| -rw-r--r-- | src/internal/runtime/strconv/atoi.go | 76 | ||||
| -rw-r--r-- | src/internal/runtime/strconv/atoi_test.go | 105 |
3 files changed, 184 insertions, 0 deletions
diff --git a/src/internal/runtime/math/math.go b/src/internal/runtime/math/math.go index e0fdc3438d..7b616cff79 100644 --- a/src/internal/runtime/math/math.go +++ b/src/internal/runtime/math/math.go @@ -8,7 +8,10 @@ import "internal/goarch" const ( MaxUint32 = ^uint32(0) + MaxUint64 = ^uint64(0) MaxUintptr = ^uintptr(0) + + MaxInt64 = int64(MaxUint64 >> 1) ) // MulUintptr returns a * b and whether the multiplication overflowed. diff --git a/src/internal/runtime/strconv/atoi.go b/src/internal/runtime/strconv/atoi.go new file mode 100644 index 0000000000..87b3faf6d5 --- /dev/null +++ b/src/internal/runtime/strconv/atoi.go @@ -0,0 +1,76 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "internal/runtime/math" +) + +// Atoi64 parses an int64 from a string s. +// The bool result reports whether s is a number +// representable by a value of type int64. +func Atoi64(s string) (int64, bool) { + if s == "" { + return 0, false + } + + neg := false + if s[0] == '-' { + neg = true + s = s[1:] + } + + un := uint64(0) + for i := 0; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + return 0, false + } + if un > math.MaxUint64/10 { + // overflow + return 0, false + } + un *= 10 + un1 := un + uint64(c) - '0' + if un1 < un { + // overflow + return 0, false + } + un = un1 + } + + if !neg && un > uint64(math.MaxInt64) { + return 0, false + } + if neg && un > uint64(math.MaxInt64)+1 { + return 0, false + } + + n := int64(un) + if neg { + n = -n + } + + return n, true +} + +// Atoi is like Atoi64 but for integers +// that fit into an int. +func Atoi(s string) (int, bool) { + if n, ok := Atoi64(s); n == int64(int(n)) { + return int(n), ok + } + return 0, false +} + +// Atoi32 is like Atoi but for integers +// that fit into an int32. +func Atoi32(s string) (int32, bool) { + if n, ok := Atoi64(s); n == int64(int32(n)) { + return int32(n), ok + } + return 0, false +} + diff --git a/src/internal/runtime/strconv/atoi_test.go b/src/internal/runtime/strconv/atoi_test.go new file mode 100644 index 0000000000..49cd6f160a --- /dev/null +++ b/src/internal/runtime/strconv/atoi_test.go @@ -0,0 +1,105 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + "internal/runtime/strconv" + "testing" +) + +const intSize = 32 << (^uint(0) >> 63) + +type atoi64Test struct { + in string + out int64 + ok bool +} + +var atoi64tests = []atoi64Test{ + {"", 0, false}, + {"0", 0, true}, + {"-0", 0, true}, + {"1", 1, true}, + {"-1", -1, true}, + {"12345", 12345, true}, + {"-12345", -12345, true}, + {"012345", 12345, true}, + {"-012345", -12345, true}, + {"12345x", 0, false}, + {"-12345x", 0, false}, + {"98765432100", 98765432100, true}, + {"-98765432100", -98765432100, true}, + {"20496382327982653440", 0, false}, + {"-20496382327982653440", 0, false}, + {"9223372036854775807", 1<<63 - 1, true}, + {"-9223372036854775807", -(1<<63 - 1), true}, + {"9223372036854775808", 0, false}, + {"-9223372036854775808", -1 << 63, true}, + {"9223372036854775809", 0, false}, + {"-9223372036854775809", 0, false}, +} + +func TestAtoi(t *testing.T) { + switch intSize { + case 32: + for i := range atoi32tests { + test := &atoi32tests[i] + out, ok := strconv.Atoi(test.in) + if test.out != int32(out) || test.ok != ok { + t.Errorf("Atoi(%q) = (%v, %v) want (%v, %v)", + test.in, out, ok, test.out, test.ok) + } + } + case 64: + for i := range atoi64tests { + test := &atoi64tests[i] + out, ok := strconv.Atoi(test.in) + if test.out != int64(out) || test.ok != ok { + t.Errorf("Atoi(%q) = (%v, %v) want (%v, %v)", + test.in, out, ok, test.out, test.ok) + } + } + } +} + +type atoi32Test struct { + in string + out int32 + ok bool +} + +var atoi32tests = []atoi32Test{ + {"", 0, false}, + {"0", 0, true}, + {"-0", 0, true}, + {"1", 1, true}, + {"-1", -1, true}, + {"12345", 12345, true}, + {"-12345", -12345, true}, + {"012345", 12345, true}, + {"-012345", -12345, true}, + {"12345x", 0, false}, + {"-12345x", 0, false}, + {"987654321", 987654321, true}, + {"-987654321", -987654321, true}, + {"2147483647", 1<<31 - 1, true}, + {"-2147483647", -(1<<31 - 1), true}, + {"2147483648", 0, false}, + {"-2147483648", -1 << 31, true}, + {"2147483649", 0, false}, + {"-2147483649", 0, false}, +} + +func TestAtoi32(t *testing.T) { + for i := range atoi32tests { + test := &atoi32tests[i] + out, ok := strconv.Atoi32(test.in) + if test.out != out || test.ok != ok { + t.Errorf("Atoi32(%q) = (%v, %v) want (%v, %v)", + test.in, out, ok, test.out, test.ok) + } + } +} + |
