mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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>
This commit is contained in:
parent
d93bea0e59
commit
76e7bfbb4e
14 changed files with 208 additions and 180 deletions
|
|
@ -53,6 +53,7 @@ var runtimePkgs = []string{
|
||||||
"internal/runtime/gc",
|
"internal/runtime/gc",
|
||||||
"internal/runtime/maps",
|
"internal/runtime/maps",
|
||||||
"internal/runtime/math",
|
"internal/runtime/math",
|
||||||
|
"internal/runtime/strconv",
|
||||||
"internal/runtime/sys",
|
"internal/runtime/sys",
|
||||||
"internal/runtime/syscall",
|
"internal/runtime/syscall",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ var depsRules = `
|
||||||
< internal/runtime/gc
|
< internal/runtime/gc
|
||||||
< internal/runtime/math
|
< internal/runtime/math
|
||||||
< internal/runtime/maps
|
< internal/runtime/maps
|
||||||
|
< internal/runtime/strconv
|
||||||
< runtime
|
< runtime
|
||||||
< sync/atomic
|
< sync/atomic
|
||||||
< internal/sync
|
< internal/sync
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@ import "internal/goarch"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MaxUint32 = ^uint32(0)
|
MaxUint32 = ^uint32(0)
|
||||||
|
MaxUint64 = ^uint64(0)
|
||||||
MaxUintptr = ^uintptr(0)
|
MaxUintptr = ^uintptr(0)
|
||||||
|
|
||||||
|
MaxInt64 = int64(MaxUint64 >> 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
// MulUintptr returns a * b and whether the multiplication overflowed.
|
// MulUintptr returns a * b and whether the multiplication overflowed.
|
||||||
|
|
|
||||||
76
src/internal/runtime/strconv/atoi.go
Normal file
76
src/internal/runtime/strconv/atoi.go
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
105
src/internal/runtime/strconv/atoi_test.go
Normal file
105
src/internal/runtime/strconv/atoi_test.go
Normal file
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -35,8 +35,6 @@ var ReadRandomFailed = &readRandomFailed
|
||||||
|
|
||||||
var Fastlog2 = fastlog2
|
var Fastlog2 = fastlog2
|
||||||
|
|
||||||
var Atoi = atoi
|
|
||||||
var Atoi32 = atoi32
|
|
||||||
var ParseByteCount = parseByteCount
|
var ParseByteCount = parseByteCount
|
||||||
|
|
||||||
var Nanotime = nanotime
|
var Nanotime = nanotime
|
||||||
|
|
|
||||||
|
|
@ -630,7 +630,7 @@ func mallocinit() {
|
||||||
}
|
}
|
||||||
// Initialize the memory limit here because the allocator is going to look at it
|
// Initialize the memory limit here because the allocator is going to look at it
|
||||||
// but we haven't called gcinit yet and we're definitely going to allocate memory before then.
|
// but we haven't called gcinit yet and we're definitely going to allocate memory before then.
|
||||||
gcController.memoryLimit.Store(maxInt64)
|
gcController.memoryLimit.Store(math.MaxInt64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sysAlloc allocates heap arena space for at least n bytes. The
|
// sysAlloc allocates heap arena space for at least n bytes. The
|
||||||
|
|
@ -1816,7 +1816,7 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
|
||||||
func nextSample() int64 {
|
func nextSample() int64 {
|
||||||
if MemProfileRate == 0 {
|
if MemProfileRate == 0 {
|
||||||
// Basically never sample.
|
// Basically never sample.
|
||||||
return maxInt64
|
return math.MaxInt64
|
||||||
}
|
}
|
||||||
if MemProfileRate == 1 {
|
if MemProfileRate == 1 {
|
||||||
// Sample immediately.
|
// Sample immediately.
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"internal/cpu"
|
"internal/cpu"
|
||||||
"internal/goexperiment"
|
"internal/goexperiment"
|
||||||
"internal/runtime/atomic"
|
"internal/runtime/atomic"
|
||||||
|
"internal/runtime/math"
|
||||||
|
"internal/runtime/strconv"
|
||||||
_ "unsafe" // for go:linkname
|
_ "unsafe" // for go:linkname
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1311,7 +1313,7 @@ func readGOGC() int32 {
|
||||||
if p == "off" {
|
if p == "off" {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
if n, ok := atoi32(p); ok {
|
if n, ok := strconv.Atoi32(p); ok {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
return 100
|
return 100
|
||||||
|
|
@ -1355,7 +1357,7 @@ func setMemoryLimit(in int64) (out int64) {
|
||||||
func readGOMEMLIMIT() int64 {
|
func readGOMEMLIMIT() int64 {
|
||||||
p := gogetenv("GOMEMLIMIT")
|
p := gogetenv("GOMEMLIMIT")
|
||||||
if p == "" || p == "off" {
|
if p == "" || p == "off" {
|
||||||
return maxInt64
|
return math.MaxInt64
|
||||||
}
|
}
|
||||||
n, ok := parseByteCount(p)
|
n, ok := parseByteCount(p)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
||||||
|
|
@ -1324,7 +1324,7 @@ HaveSpan:
|
||||||
// that we expect to page in.
|
// that we expect to page in.
|
||||||
inuse := gcController.mappedReady.Load()
|
inuse := gcController.mappedReady.Load()
|
||||||
// Be careful about overflow, especially with uintptrs. Even on 32-bit platforms
|
// Be careful about overflow, especially with uintptrs. Even on 32-bit platforms
|
||||||
// someone can set a really big memory limit that isn't maxInt64.
|
// someone can set a really big memory limit that isn't math.MaxInt64.
|
||||||
if uint64(scav)+inuse > uint64(limit) {
|
if uint64(scav)+inuse > uint64(limit) {
|
||||||
bytesToScavenge = uintptr(uint64(scav) + inuse - uint64(limit))
|
bytesToScavenge = uintptr(uint64(scav) + inuse - uint64(limit))
|
||||||
forceScavenge = true
|
forceScavenge = true
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
"internal/goarch"
|
"internal/goarch"
|
||||||
"internal/runtime/atomic"
|
"internal/runtime/atomic"
|
||||||
|
"internal/runtime/strconv"
|
||||||
"internal/runtime/syscall"
|
"internal/runtime/syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
@ -341,7 +342,7 @@ func getHugePageSize() uintptr {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
n-- // remove trailing newline
|
n-- // remove trailing newline
|
||||||
v, ok := atoi(slicebytetostringtmp((*byte)(ptr), int(n)))
|
v, ok := strconv.Atoi(slicebytetostringtmp((*byte)(ptr), int(n)))
|
||||||
if !ok || v < 0 {
|
if !ok || v < 0 {
|
||||||
v = 0
|
v = 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"internal/goos"
|
"internal/goos"
|
||||||
"internal/runtime/atomic"
|
"internal/runtime/atomic"
|
||||||
"internal/runtime/exithook"
|
"internal/runtime/exithook"
|
||||||
|
"internal/runtime/strconv"
|
||||||
"internal/runtime/sys"
|
"internal/runtime/sys"
|
||||||
"internal/stringslite"
|
"internal/stringslite"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
@ -900,7 +901,7 @@ func schedinit() {
|
||||||
lock(&sched.lock)
|
lock(&sched.lock)
|
||||||
sched.lastpoll.Store(nanotime())
|
sched.lastpoll.Store(nanotime())
|
||||||
procs := ncpu
|
procs := ncpu
|
||||||
if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 {
|
if n, ok := strconv.Atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 {
|
||||||
procs = n
|
procs = n
|
||||||
}
|
}
|
||||||
if procresize(procs) != nil {
|
if procresize(procs) != nil {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"internal/bytealg"
|
"internal/bytealg"
|
||||||
"internal/goarch"
|
"internal/goarch"
|
||||||
"internal/runtime/atomic"
|
"internal/runtime/atomic"
|
||||||
|
"internal/runtime/strconv"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -526,13 +527,13 @@ func parsegodebug(godebug string, seen map[string]bool) {
|
||||||
// is int, not int32, and should only be updated
|
// is int, not int32, and should only be updated
|
||||||
// if specified in GODEBUG.
|
// if specified in GODEBUG.
|
||||||
if seen == nil && key == "memprofilerate" {
|
if seen == nil && key == "memprofilerate" {
|
||||||
if n, ok := atoi(value); ok {
|
if n, ok := strconv.Atoi(value); ok {
|
||||||
MemProfileRate = n
|
MemProfileRate = n
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, v := range dbgvars {
|
for _, v := range dbgvars {
|
||||||
if v.name == key {
|
if v.name == key {
|
||||||
if n, ok := atoi32(value); ok {
|
if n, ok := strconv.Atoi32(value); ok {
|
||||||
if seen == nil && v.value != nil {
|
if seen == nil && v.value != nil {
|
||||||
*v.value = n
|
*v.value = n
|
||||||
} else if v.atomic != nil {
|
} else if v.atomic != nil {
|
||||||
|
|
@ -572,7 +573,7 @@ func setTraceback(level string) {
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
t = tracebackAll
|
t = tracebackAll
|
||||||
if n, ok := atoi(level); ok && n == int(uint32(n)) {
|
if n, ok := strconv.Atoi(level); ok && n == int(uint32(n)) {
|
||||||
t |= uint32(n) << tracebackShift
|
t |= uint32(n) << tracebackShift
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
"internal/bytealg"
|
"internal/bytealg"
|
||||||
"internal/goarch"
|
"internal/goarch"
|
||||||
|
"internal/runtime/math"
|
||||||
|
"internal/runtime/strconv"
|
||||||
"internal/runtime/sys"
|
"internal/runtime/sys"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
@ -391,77 +393,6 @@ func gostringn(p *byte, l int) string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
maxUint64 = ^uint64(0)
|
|
||||||
maxInt64 = int64(maxUint64 >> 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 > 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(maxInt64) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
if neg && un > uint64(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
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseByteCount parses a string that represents a count of bytes.
|
// parseByteCount parses a string that represents a count of bytes.
|
||||||
//
|
//
|
||||||
// s must match the following regular expression:
|
// s must match the following regular expression:
|
||||||
|
|
@ -483,7 +414,7 @@ func parseByteCount(s string) (int64, bool) {
|
||||||
// Handle the easy non-suffix case.
|
// Handle the easy non-suffix case.
|
||||||
last := s[len(s)-1]
|
last := s[len(s)-1]
|
||||||
if last >= '0' && last <= '9' {
|
if last >= '0' && last <= '9' {
|
||||||
n, ok := atoi64(s)
|
n, ok := strconv.Atoi64(s)
|
||||||
if !ok || n < 0 {
|
if !ok || n < 0 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
@ -498,7 +429,7 @@ func parseByteCount(s string) (int64, bool) {
|
||||||
// The one before that must always be a digit or 'i'.
|
// The one before that must always be a digit or 'i'.
|
||||||
if c := s[len(s)-2]; c >= '0' && c <= '9' {
|
if c := s[len(s)-2]; c >= '0' && c <= '9' {
|
||||||
// Trivial 'B' suffix.
|
// Trivial 'B' suffix.
|
||||||
n, ok := atoi64(s[:len(s)-1])
|
n, ok := strconv.Atoi64(s[:len(s)-1])
|
||||||
if !ok || n < 0 {
|
if !ok || n < 0 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
@ -529,17 +460,17 @@ func parseByteCount(s string) (int64, bool) {
|
||||||
for i := 0; i < power; i++ {
|
for i := 0; i < power; i++ {
|
||||||
m *= 1024
|
m *= 1024
|
||||||
}
|
}
|
||||||
n, ok := atoi64(s[:len(s)-3])
|
n, ok := strconv.Atoi64(s[:len(s)-3])
|
||||||
if !ok || n < 0 {
|
if !ok || n < 0 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
un := uint64(n)
|
un := uint64(n)
|
||||||
if un > maxUint64/m {
|
if un > math.MaxUint64/m {
|
||||||
// Overflow.
|
// Overflow.
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
un *= m
|
un *= m
|
||||||
if un > uint64(maxInt64) {
|
if un > uint64(math.MaxInt64) {
|
||||||
// Overflow.
|
// Overflow.
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -390,98 +390,6 @@ func TestString2Slice(t *testing.T) {
|
||||||
|
|
||||||
const intSize = 32 << (^uint(0) >> 63)
|
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 := runtime.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 := runtime.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 := runtime.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseByteCount(t *testing.T) {
|
func TestParseByteCount(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
in string
|
in string
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue