Home | History | Annotate | Download | only in big
      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 zeroes 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 			zeroes = 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) + zeroes + 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 zeroes unless precision also specified
    128 			zeroes = 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", zeroes)
    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 }
    229