...

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

View as plain text