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