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