github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/big/intconv.go (about) 1 // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/big/intconv.go 2 3 // Copyright 2015 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 // This file implements int-to-string conversion functions. 8 9 package big 10 11 import ( 12 "errors" 13 "fmt" 14 "io" 15 ) 16 17 func (x *Int) String() string { 18 switch { 19 case x == nil: 20 return "<nil>" 21 case x.neg: 22 return "-" + x.abs.decimalString() 23 } 24 return x.abs.decimalString() 25 } 26 27 func charset(ch rune) string { 28 switch ch { 29 case 'b': 30 return lowercaseDigits[0:2] 31 case 'o': 32 return lowercaseDigits[0:8] 33 case 'd', 's', 'v': 34 return lowercaseDigits[0:10] 35 case 'x': 36 return lowercaseDigits[0:16] 37 case 'X': 38 return uppercaseDigits[0:16] 39 } 40 return "" // unknown format 41 } 42 43 // write count copies of text to s 44 func writeMultiple(s fmt.State, text string, count int) { 45 if len(text) > 0 { 46 b := []byte(text) 47 for ; count > 0; count-- { 48 s.Write(b) 49 } 50 } 51 } 52 53 // Format is a support routine for fmt.Formatter. It accepts 54 // the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x' 55 // (lowercase hexadecimal), and 'X' (uppercase hexadecimal). 56 // Also supported are the full suite of package fmt's format 57 // verbs for integral types, including '+', '-', and ' ' 58 // for sign control, '#' for leading zero in octal and for 59 // hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X" 60 // respectively, specification of minimum digits precision, 61 // output field width, space or zero padding, and left or 62 // right justification. 63 // 64 func (x *Int) Format(s fmt.State, ch rune) { 65 cs := charset(ch) 66 67 // special cases 68 switch { 69 case cs == "": 70 // unknown format 71 fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String()) 72 return 73 case x == nil: 74 fmt.Fprint(s, "<nil>") 75 return 76 } 77 78 // determine sign character 79 sign := "" 80 switch { 81 case x.neg: 82 sign = "-" 83 case s.Flag('+'): // supersedes ' ' when both specified 84 sign = "+" 85 case s.Flag(' '): 86 sign = " " 87 } 88 89 // determine prefix characters for indicating output base 90 prefix := "" 91 if s.Flag('#') { 92 switch ch { 93 case 'o': // octal 94 prefix = "0" 95 case 'x': // hexadecimal 96 prefix = "0x" 97 case 'X': 98 prefix = "0X" 99 } 100 } 101 102 // determine digits with base set by len(cs) and digit characters from cs 103 digits := x.abs.string(cs) 104 105 // number of characters for the three classes of number padding 106 var left int // space characters to left of digits for right justification ("%8d") 107 var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d") 108 var right int // space characters to right of digits for left justification ("%-8d") 109 110 // determine number padding from precision: the least number of digits to output 111 precision, precisionSet := s.Precision() 112 if precisionSet { 113 switch { 114 case len(digits) < precision: 115 zeroes = precision - len(digits) // count of zero padding 116 case digits == "0" && precision == 0: 117 return // print nothing if zero value (x == 0) and zero precision ("." or ".0") 118 } 119 } 120 121 // determine field pad from width: the least number of characters to output 122 length := len(sign) + len(prefix) + zeroes + len(digits) 123 if width, widthSet := s.Width(); widthSet && length < width { // pad as specified 124 switch d := width - length; { 125 case s.Flag('-'): 126 // pad on the right with spaces; supersedes '0' when both specified 127 right = d 128 case s.Flag('0') && !precisionSet: 129 // pad with zeroes unless precision also specified 130 zeroes = d 131 default: 132 // pad on the left with spaces 133 left = d 134 } 135 } 136 137 // print number as [left pad][sign][prefix][zero pad][digits][right pad] 138 writeMultiple(s, " ", left) 139 writeMultiple(s, sign, 1) 140 writeMultiple(s, prefix, 1) 141 writeMultiple(s, "0", zeroes) 142 writeMultiple(s, digits, 1) 143 writeMultiple(s, " ", right) 144 } 145 146 // scan sets z to the integer value corresponding to the longest possible prefix 147 // read from r representing a signed integer number in a given conversion base. 148 // It returns z, the actual conversion base used, and an error, if any. In the 149 // error case, the value of z is undefined but the returned value is nil. The 150 // syntax follows the syntax of integer literals in Go. 151 // 152 // The base argument must be 0 or a value from 2 through MaxBase. If the base 153 // is 0, the string prefix determines the actual conversion base. A prefix of 154 // ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a 155 // ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. 156 // 157 func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) { 158 // determine sign 159 neg, err := scanSign(r) 160 if err != nil { 161 return nil, 0, err 162 } 163 164 // determine mantissa 165 z.abs, base, _, err = z.abs.scan(r, base, false) 166 if err != nil { 167 return nil, base, err 168 } 169 z.neg = len(z.abs) > 0 && neg // 0 has no sign 170 171 return z, base, nil 172 } 173 174 func scanSign(r io.ByteScanner) (neg bool, err error) { 175 var ch byte 176 if ch, err = r.ReadByte(); err != nil { 177 return false, err 178 } 179 switch ch { 180 case '-': 181 neg = true 182 case '+': 183 // nothing to do 184 default: 185 r.UnreadByte() 186 } 187 return 188 } 189 190 // byteReader is a local wrapper around fmt.ScanState; 191 // it implements the ByteReader interface. 192 type byteReader struct { 193 fmt.ScanState 194 } 195 196 func (r byteReader) ReadByte() (byte, error) { 197 ch, size, err := r.ReadRune() 198 if size != 1 && err == nil { 199 err = fmt.Errorf("invalid rune %#U", ch) 200 } 201 return byte(ch), err 202 } 203 204 func (r byteReader) UnreadByte() error { 205 return r.UnreadRune() 206 } 207 208 // Scan is a support routine for fmt.Scanner; it sets z to the value of 209 // the scanned number. It accepts the formats 'b' (binary), 'o' (octal), 210 // 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal). 211 func (z *Int) Scan(s fmt.ScanState, ch rune) error { 212 s.SkipSpace() // skip leading space characters 213 base := 0 214 switch ch { 215 case 'b': 216 base = 2 217 case 'o': 218 base = 8 219 case 'd': 220 base = 10 221 case 'x', 'X': 222 base = 16 223 case 's', 'v': 224 // let scan determine the base 225 default: 226 return errors.New("Int.Scan: invalid verb") 227 } 228 _, _, err := z.scan(byteReader{s}, base) 229 return err 230 }