github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/uint256/utils.gno (about) 1 package uint256 2 3 // lower(c) is a lower-case letter if and only if 4 // c is either that lower-case letter or the equivalent upper-case letter. 5 // Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. 6 // Note that lower of non-letters can produce other non-letters. 7 func lower(c byte) byte { 8 return c | ('x' - 'X') 9 } 10 11 // underscoreOK reports whether the underscores in s are allowed. 12 // Checking them in this one function lets all the parsers skip over them simply. 13 // Underscore must appear only between digits or between a base prefix and a digit. 14 func underscoreOK(s string) bool { 15 // saw tracks the last character (class) we saw: 16 // ^ for beginning of number, 17 // 0 for a digit or base prefix, 18 // _ for an underscore, 19 // ! for none of the above. 20 saw := '^' 21 i := 0 22 23 // Optional sign. 24 if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { 25 s = s[1:] 26 } 27 28 // Optional base prefix. 29 hex := false 30 if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { 31 i = 2 32 saw = '0' // base prefix counts as a digit for "underscore as digit separator" 33 hex = lower(s[1]) == 'x' 34 } 35 36 // Number proper. 37 for ; i < len(s); i++ { 38 // Digits are always okay. 39 if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' { 40 saw = '0' 41 continue 42 } 43 // Underscore must follow digit. 44 if s[i] == '_' { 45 if saw != '0' { 46 return false 47 } 48 saw = '_' 49 continue 50 } 51 // Underscore must also be followed by digit. 52 if saw == '_' { 53 return false 54 } 55 // Saw non-digit, non-underscore. 56 saw = '!' 57 } 58 return saw != '_' 59 } 60 61 func checkNumberS(input string) error { 62 const fn = "UnmarshalText" 63 l := len(input) 64 if l == 0 { 65 return errEmptyString(fn, input) 66 } 67 if l < 2 || input[0] != '0' || 68 (input[1] != 'x' && input[1] != 'X') { 69 return errMissingPrefix(fn, input) 70 } 71 if l == 2 { 72 return errEmptyNumber(fn, input) 73 } 74 if len(input) > 3 && input[2] == '0' { 75 return errLeadingZero(fn, input) 76 } 77 return nil 78 } 79 80 // ParseUint is like ParseUint but for unsigned numbers. 81 // 82 // A sign prefix is not permitted. 83 func parseUint(s string, base int, bitSize int) (uint64, error) { 84 const fnParseUint = "ParseUint" 85 86 if s == "" { 87 return 0, errSyntax(fnParseUint, s) 88 } 89 90 base0 := base == 0 91 92 s0 := s 93 switch { 94 case 2 <= base && base <= 36: 95 // valid base; nothing to do 96 97 case base == 0: 98 // Look for octal, hex prefix. 99 base = 10 100 if s[0] == '0' { 101 switch { 102 case len(s) >= 3 && lower(s[1]) == 'b': 103 base = 2 104 s = s[2:] 105 case len(s) >= 3 && lower(s[1]) == 'o': 106 base = 8 107 s = s[2:] 108 case len(s) >= 3 && lower(s[1]) == 'x': 109 base = 16 110 s = s[2:] 111 default: 112 base = 8 113 s = s[1:] 114 } 115 } 116 117 default: 118 return 0, errInvalidBase(fnParseUint, base) 119 } 120 121 if bitSize == 0 { 122 bitSize = uintSize 123 } else if bitSize < 0 || bitSize > 64 { 124 return 0, errInvalidBitSize(fnParseUint, bitSize) 125 } 126 127 // Cutoff is the smallest number such that cutoff*base > maxUint64. 128 // Use compile-time constants for common cases. 129 var cutoff uint64 130 switch base { 131 case 10: 132 cutoff = MaxUint64/10 + 1 133 case 16: 134 cutoff = MaxUint64/16 + 1 135 default: 136 cutoff = MaxUint64/uint64(base) + 1 137 } 138 139 maxVal := uint64(1)<<uint(bitSize) - 1 140 141 underscores := false 142 var n uint64 143 for _, c := range []byte(s) { 144 var d byte 145 switch { 146 case c == '_' && base0: 147 underscores = true 148 continue 149 case '0' <= c && c <= '9': 150 d = c - '0' 151 case 'a' <= lower(c) && lower(c) <= 'z': 152 d = lower(c) - 'a' + 10 153 default: 154 return 0, errSyntax(fnParseUint, s0) 155 } 156 157 if d >= byte(base) { 158 return 0, errSyntax(fnParseUint, s0) 159 } 160 161 if n >= cutoff { 162 // n*base overflows 163 return maxVal, errRange(fnParseUint, s0) 164 } 165 n *= uint64(base) 166 167 n1 := n + uint64(d) 168 if n1 < n || n1 > maxVal { 169 // n+d overflows 170 return maxVal, errRange(fnParseUint, s0) 171 } 172 n = n1 173 } 174 175 if underscores && !underscoreOK(s0) { 176 return 0, errSyntax(fnParseUint, s0) 177 } 178 179 return n, nil 180 }