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  }