Source file src/math/big/intconv.go

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

View as plain text