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