return &NumError{fn, str, errors.New("invalid base " + Itoa(base))}
}
+func bitSizeError(fn, str string, bitSize int) *NumError {
+ return &NumError{fn, str, errors.New("invalid bit size " + Itoa(bitSize))}
+}
+
const intSize = 32 << (^uint(0) >> 63)
// IntSize is the size in bits of an int or uint value.
func ParseUint(s string, base int, bitSize int) (uint64, error) {
const fnParseUint = "ParseUint"
- if bitSize == 0 {
- bitSize = int(IntSize)
- }
-
if len(s) == 0 {
return 0, syntaxError(fnParseUint, s)
}
return 0, baseError(fnParseUint, s0, base)
}
+ if bitSize == 0 {
+ bitSize = int(IntSize)
+ } else if bitSize < 0 || bitSize > 64 {
+ return 0, bitSizeError(fnParseUint, s0, bitSize)
+ }
+
// Cutoff is the smallest number such that cutoff*base > maxUint64.
// Use compile-time constants for common cases.
var cutoff uint64
return n, nil
}
-// ParseInt interprets a string s in the given base (2 to 36) and
-// returns the corresponding value i. If base == 0, the base is
-// implied by the string's prefix: base 16 for "0x", base 8 for
-// "0", and base 10 otherwise.
+// ParseInt interprets a string s in the given base (0, 2 to 36) and
+// bit size (0 to 64) and returns the corresponding value i.
+//
+// If base == 0, the base is implied by the string's prefix:
+// base 16 for "0x", base 8 for "0", and base 10 otherwise.
+// For bases 1, below 0 or above 36 an error is returned.
//
// The bitSize argument specifies the integer type
// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
// correspond to int, int8, int16, int32, and int64.
+// For a bitSize below 0 or above 64 an error is returned.
//
// The errors that ParseInt returns have concrete type *NumError
// and include err.Num = s. If s is empty or contains invalid
func ParseInt(s string, base int, bitSize int) (i int64, err error) {
const fnParseInt = "ParseInt"
- if bitSize == 0 {
- bitSize = int(IntSize)
- }
-
// Empty string bad.
if len(s) == 0 {
return 0, syntaxError(fnParseInt, s)
err.(*NumError).Num = s0
return 0, err
}
+
+ if bitSize == 0 {
+ bitSize = int(IntSize)
+ }
+
cutoff := uint64(1 << uint(bitSize-1))
if !neg && un >= cutoff {
return int64(cutoff - 1), rangeError(fnParseInt, s0)
}
}
+func bitSizeErrStub(name string, bitSize int) error {
+ return BitSizeError(name, "0", bitSize)
+}
+
+func baseErrStub(name string, base int) error {
+ return BaseError(name, "0", base)
+}
+
+func noErrStub(name string, arg int) error {
+ return nil
+}
+
+type parseErrorTest struct {
+ arg int
+ errStub func(name string, arg int) error
+}
+
+var parseBitSizeTests = []parseErrorTest{
+ {-1, bitSizeErrStub},
+ {0, noErrStub},
+ {64, noErrStub},
+ {65, bitSizeErrStub},
+}
+
+var parseBaseTests = []parseErrorTest{
+ {-1, baseErrStub},
+ {0, noErrStub},
+ {1, baseErrStub},
+ {2, noErrStub},
+ {36, noErrStub},
+ {37, baseErrStub},
+}
+
+func TestParseIntBitSize(t *testing.T) {
+ for i := range parseBitSizeTests {
+ test := &parseBitSizeTests[i]
+ testErr := test.errStub("ParseInt", test.arg)
+ _, err := ParseInt("0", 0, test.arg)
+ if !reflect.DeepEqual(testErr, err) {
+ t.Errorf("ParseInt(\"0\", 0, %v) = 0, %v want 0, %v",
+ test.arg, err, testErr)
+ }
+ }
+}
+
+func TestParseUintBitSize(t *testing.T) {
+ for i := range parseBitSizeTests {
+ test := &parseBitSizeTests[i]
+ testErr := test.errStub("ParseUint", test.arg)
+ _, err := ParseUint("0", 0, test.arg)
+ if !reflect.DeepEqual(testErr, err) {
+ t.Errorf("ParseUint(\"0\", 0, %v) = 0, %v want 0, %v",
+ test.arg, err, testErr)
+ }
+ }
+}
+
+func TestParseIntBase(t *testing.T) {
+ for i := range parseBaseTests {
+ test := &parseBaseTests[i]
+ testErr := test.errStub("ParseInt", test.arg)
+ _, err := ParseInt("0", test.arg, 0)
+ if !reflect.DeepEqual(testErr, err) {
+ t.Errorf("ParseInt(\"0\", %v, 0) = 0, %v want 0, %v",
+ test.arg, err, testErr)
+ }
+ }
+}
+
+func TestParseUintBase(t *testing.T) {
+ for i := range parseBaseTests {
+ test := &parseBaseTests[i]
+ testErr := test.errStub("ParseUint", test.arg)
+ _, err := ParseUint("0", test.arg, 0)
+ if !reflect.DeepEqual(testErr, err) {
+ t.Errorf("ParseUint(\"0\", %v, 0) = 0, %v want 0, %v",
+ test.arg, err, testErr)
+ }
+ }
+}
+
func TestNumError(t *testing.T) {
for _, test := range numErrorTests {
err := &NumError{