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