github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/internal/testkeys/strconv.go (about)

     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  func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
    30  	var cutoff, maxVal uint64
    31  
    32  	if bitSize == 0 {
    33  		bitSize = int(strconv.IntSize)
    34  	}
    35  
    36  	s0 := s
    37  	switch {
    38  	case len(s) < 1:
    39  		err = strconv.ErrSyntax
    40  		goto Error
    41  
    42  	case 2 <= base && base <= 36:
    43  		// valid base; nothing to do
    44  
    45  	case base == 0:
    46  		// Look for octal, hex prefix.
    47  		switch {
    48  		case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
    49  			base = 16
    50  			s = s[2:]
    51  			if len(s) < 1 {
    52  				err = strconv.ErrSyntax
    53  				goto Error
    54  			}
    55  		case s[0] == '0':
    56  			base = 8
    57  		default:
    58  			base = 10
    59  		}
    60  
    61  	default:
    62  		err = errors.New("invalid base " + strconv.Itoa(base))
    63  		goto Error
    64  	}
    65  
    66  	n = 0
    67  	cutoff = cutoff64(base)
    68  	maxVal = 1<<uint(bitSize) - 1
    69  
    70  	for i := 0; i < len(s); i++ {
    71  		var v byte
    72  		d := s[i]
    73  		switch {
    74  		case '0' <= d && d <= '9':
    75  			v = d - '0'
    76  		case 'a' <= d && d <= 'z':
    77  			v = d - 'a' + 10
    78  		case 'A' <= d && d <= 'Z':
    79  			v = d - 'A' + 10
    80  		default:
    81  			n = 0
    82  			err = strconv.ErrSyntax
    83  			goto Error
    84  		}
    85  		if int(v) >= base {
    86  			n = 0
    87  			err = strconv.ErrSyntax
    88  			goto Error
    89  		}
    90  
    91  		if n >= cutoff {
    92  			// n*base overflows
    93  			n = 1<<64 - 1
    94  			err = strconv.ErrRange
    95  			goto Error
    96  		}
    97  		n *= uint64(base)
    98  
    99  		n1 := n + uint64(v)
   100  		if n1 < n || n1 > maxVal {
   101  			// n+v overflows
   102  			n = 1<<64 - 1
   103  			err = strconv.ErrRange
   104  			goto Error
   105  		}
   106  		n = n1
   107  	}
   108  
   109  	return n, nil
   110  
   111  Error:
   112  	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  func cutoff64(base int) uint64 {
   117  	if base < 2 {
   118  		return 0
   119  	}
   120  	return (1<<64-1)/uint64(base) + 1
   121  }