Home | History | Annotate | Download | only in strconv
      1 // Copyright 2009 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 package strconv
      6 
      7 // FormatUint returns the string representation of i in the given base,
      8 // for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
      9 // for digit values >= 10.
     10 func FormatUint(i uint64, base int) string {
     11 	_, s := formatBits(nil, i, base, false, false)
     12 	return s
     13 }
     14 
     15 // FormatInt returns the string representation of i in the given base,
     16 // for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
     17 // for digit values >= 10.
     18 func FormatInt(i int64, base int) string {
     19 	_, s := formatBits(nil, uint64(i), base, i < 0, false)
     20 	return s
     21 }
     22 
     23 // Itoa is shorthand for FormatInt(int64(i), 10).
     24 func Itoa(i int) string {
     25 	return FormatInt(int64(i), 10)
     26 }
     27 
     28 // AppendInt appends the string form of the integer i,
     29 // as generated by FormatInt, to dst and returns the extended buffer.
     30 func AppendInt(dst []byte, i int64, base int) []byte {
     31 	dst, _ = formatBits(dst, uint64(i), base, i < 0, true)
     32 	return dst
     33 }
     34 
     35 // AppendUint appends the string form of the unsigned integer i,
     36 // as generated by FormatUint, to dst and returns the extended buffer.
     37 func AppendUint(dst []byte, i uint64, base int) []byte {
     38 	dst, _ = formatBits(dst, i, base, false, true)
     39 	return dst
     40 }
     41 
     42 const (
     43 	digits = "0123456789abcdefghijklmnopqrstuvwxyz"
     44 )
     45 
     46 var shifts = [len(digits) + 1]uint{
     47 	1 << 1: 1,
     48 	1 << 2: 2,
     49 	1 << 3: 3,
     50 	1 << 4: 4,
     51 	1 << 5: 5,
     52 }
     53 
     54 // formatBits computes the string representation of u in the given base.
     55 // If neg is set, u is treated as negative int64 value. If append_ is
     56 // set, the string is appended to dst and the resulting byte slice is
     57 // returned as the first result value; otherwise the string is returned
     58 // as the second result value.
     59 //
     60 func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) {
     61 	if base < 2 || base > len(digits) {
     62 		panic("strconv: illegal AppendInt/FormatInt base")
     63 	}
     64 	// 2 <= base && base <= len(digits)
     65 
     66 	var a [64 + 1]byte // +1 for sign of 64bit value in base 2
     67 	i := len(a)
     68 
     69 	if neg {
     70 		u = -u
     71 	}
     72 
     73 	// convert bits
     74 	if base == 10 {
     75 		// common case: use constants for / because
     76 		// the compiler can optimize it into a multiply+shift
     77 
     78 		if ^uintptr(0)>>32 == 0 {
     79 			for u > uint64(^uintptr(0)) {
     80 				q := u / 1e9
     81 				us := uintptr(u - q*1e9) // us % 1e9 fits into a uintptr
     82 				for j := 9; j > 0; j-- {
     83 					i--
     84 					qs := us / 10
     85 					a[i] = byte(us - qs*10 + '0')
     86 					us = qs
     87 				}
     88 				u = q
     89 			}
     90 		}
     91 
     92 		// u guaranteed to fit into a uintptr
     93 		us := uintptr(u)
     94 		for us >= 10 {
     95 			i--
     96 			q := us / 10
     97 			a[i] = byte(us - q*10 + '0')
     98 			us = q
     99 		}
    100 		// u < 10
    101 		i--
    102 		a[i] = byte(us + '0')
    103 
    104 	} else if s := shifts[base]; s > 0 {
    105 		// base is power of 2: use shifts and masks instead of / and %
    106 		b := uint64(base)
    107 		m := uintptr(b) - 1 // == 1<<s - 1
    108 		for u >= b {
    109 			i--
    110 			a[i] = digits[uintptr(u)&m]
    111 			u >>= s
    112 		}
    113 		// u < base
    114 		i--
    115 		a[i] = digits[uintptr(u)]
    116 
    117 	} else {
    118 		// general case
    119 		b := uint64(base)
    120 		for u >= b {
    121 			i--
    122 			q := u / b
    123 			a[i] = digits[uintptr(u-q*b)]
    124 			u = q
    125 		}
    126 		// u < base
    127 		i--
    128 		a[i] = digits[uintptr(u)]
    129 	}
    130 
    131 	// add sign, if any
    132 	if neg {
    133 		i--
    134 		a[i] = '-'
    135 	}
    136 
    137 	if append_ {
    138 		d = append(dst, a[i:]...)
    139 		return
    140 	}
    141 	s = string(a[i:])
    142 	return
    143 }
    144