aboutsummaryrefslogtreecommitdiff
path: root/src/internal/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/runtime')
-rw-r--r--src/internal/runtime/math/math.go3
-rw-r--r--src/internal/runtime/strconv/atoi.go76
-rw-r--r--src/internal/runtime/strconv/atoi_test.go105
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)
+ }
+ }
+}
+