Line data Source code
1 : /* 2 : Copyright 2013 The Perkeep Authors 3 : 4 : Licensed under the Apache License, Version 2.0 (the "License"); 5 : you may not use this file except in compliance with the License. 6 : You may obtain a copy of the License at 7 : 8 : http://www.apache.org/licenses/LICENSE-2.0 9 : 10 : Unless required by applicable law or agreed to in writing, software 11 : distributed under the License is distributed on an "AS IS" BASIS, 12 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 : See the License for the specific language governing permissions and 14 : limitations under the License. 15 : */ 16 : 17 : package testkeys 18 : 19 : import ( 20 : "strconv" 21 : 22 : "github.com/cockroachdb/errors" 23 : ) 24 : 25 : // parseUintBytes is like strconv.ParseUint, but using a []byte. Use of this 26 : // function avoids an allocation when parsing an integer out of a []byte. 27 : // 28 : // This function is copied from go4.org/strconv. 29 1 : func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) { 30 1 : var cutoff, maxVal uint64 31 1 : 32 1 : if bitSize == 0 { 33 0 : bitSize = int(strconv.IntSize) 34 0 : } 35 : 36 1 : s0 := s 37 1 : switch { 38 0 : case len(s) < 1: 39 0 : err = strconv.ErrSyntax 40 0 : goto Error 41 : 42 1 : case 2 <= base && base <= 36: 43 : // valid base; nothing to do 44 : 45 0 : case base == 0: 46 0 : // Look for octal, hex prefix. 47 0 : switch { 48 0 : case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): 49 0 : base = 16 50 0 : s = s[2:] 51 0 : if len(s) < 1 { 52 0 : err = strconv.ErrSyntax 53 0 : goto Error 54 : } 55 0 : case s[0] == '0': 56 0 : base = 8 57 0 : default: 58 0 : base = 10 59 : } 60 : 61 0 : default: 62 0 : err = errors.New("invalid base " + strconv.Itoa(base)) 63 0 : goto Error 64 : } 65 : 66 1 : n = 0 67 1 : cutoff = cutoff64(base) 68 1 : maxVal = 1<<uint(bitSize) - 1 69 1 : 70 1 : for i := 0; i < len(s); i++ { 71 1 : var v byte 72 1 : d := s[i] 73 1 : switch { 74 1 : case '0' <= d && d <= '9': 75 1 : v = d - '0' 76 0 : case 'a' <= d && d <= 'z': 77 0 : v = d - 'a' + 10 78 0 : case 'A' <= d && d <= 'Z': 79 0 : v = d - 'A' + 10 80 0 : default: 81 0 : n = 0 82 0 : err = strconv.ErrSyntax 83 0 : goto Error 84 : } 85 1 : if int(v) >= base { 86 0 : n = 0 87 0 : err = strconv.ErrSyntax 88 0 : goto Error 89 : } 90 : 91 1 : if n >= cutoff { 92 0 : // n*base overflows 93 0 : n = 1<<64 - 1 94 0 : err = strconv.ErrRange 95 0 : goto Error 96 : } 97 1 : n *= uint64(base) 98 1 : 99 1 : n1 := n + uint64(v) 100 1 : if n1 < n || n1 > maxVal { 101 0 : // n+v overflows 102 0 : n = 1<<64 - 1 103 0 : err = strconv.ErrRange 104 0 : goto Error 105 : } 106 1 : n = n1 107 : } 108 : 109 1 : return n, nil 110 1 : 111 1 : Error: 112 0 : return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err} 113 : } 114 : 115 : // Return the first number n such that n*base >= 1<<64. 116 1 : func cutoff64(base int) uint64 { 117 1 : if base < 2 { 118 0 : return 0 119 0 : } 120 1 : return (1<<64-1)/uint64(base) + 1 121 : }