github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/big/intconv.go (about)

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