github.com/go-eden/common@v0.1.15-0.20210617133546-059099253264/efmt/efmt_formatter.go (about)

     1  package efmt
     2  
     3  import (
     4  	"strconv"
     5  	"unicode/utf8"
     6  )
     7  
     8  // flags placed in a separate struct for easy clearing.
     9  type formatFlags struct {
    10  	widPresent  bool
    11  	precPresent bool
    12  	minus       bool
    13  	plus        bool
    14  	sharp       bool
    15  	space       bool
    16  	zero        bool
    17  
    18  	// For the formats %+v %#v, we set the plusV/sharpV flags
    19  	// and clear the plus/sharp flags since %+v and %#v are in effect
    20  	// different, flagless formats set at the top level.
    21  	plusV  bool
    22  	sharpV bool
    23  }
    24  
    25  // A formatter is the raw formatter used by Printf etc.
    26  // It prints into a buffer that must be set up separately.
    27  type formatter struct {
    28  	buf *buffer
    29  
    30  	formatFlags
    31  
    32  	wid  int // width
    33  	prec int // precision
    34  
    35  	// intbuf is large enough to store %b of an int64 with a sign and
    36  	// avoids padding at the end of the struct on 32 bit architectures.
    37  	intbuf [68]byte
    38  }
    39  
    40  func (f *formatter) clearflags() {
    41  	f.formatFlags = formatFlags{}
    42  }
    43  
    44  func (f *formatter) init(buf *buffer) {
    45  	f.buf = buf
    46  	f.clearflags()
    47  }
    48  
    49  // writePadding generates n bytes of padding.
    50  func (f *formatter) writePadding(n int) {
    51  	if n <= 0 { // No padding bytes needed.
    52  		return
    53  	}
    54  	buf := *f.buf
    55  	oldLen := len(buf)
    56  	newLen := oldLen + n
    57  	// Make enough room for padding.
    58  	if newLen > cap(buf) {
    59  		buf = make(buffer, cap(buf)*2+n)
    60  		copy(buf, *f.buf)
    61  	}
    62  	// Decide which byte the padding should be filled with.
    63  	padByte := byte(' ')
    64  	if f.zero {
    65  		padByte = byte('0')
    66  	}
    67  	// Fill padding with padByte.
    68  	padding := buf[oldLen:newLen]
    69  	for i := range padding {
    70  		padding[i] = padByte
    71  	}
    72  	*f.buf = buf[:newLen]
    73  }
    74  
    75  // pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
    76  func (f *formatter) pad(b []byte) {
    77  	if !f.widPresent || f.wid == 0 {
    78  		f.buf.write(b)
    79  		return
    80  	}
    81  	width := f.wid - utf8.RuneCount(b)
    82  	if !f.minus {
    83  		// left padding
    84  		f.writePadding(width)
    85  		f.buf.write(b)
    86  	} else {
    87  		// right padding
    88  		f.buf.write(b)
    89  		f.writePadding(width)
    90  	}
    91  }
    92  
    93  // padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
    94  func (f *formatter) padString(s string) {
    95  	if !f.widPresent || f.wid == 0 {
    96  		f.buf.writeString(s)
    97  		return
    98  	}
    99  	width := f.wid - utf8.RuneCountInString(s)
   100  	if !f.minus {
   101  		// left padding
   102  		f.writePadding(width)
   103  		f.buf.writeString(s)
   104  	} else {
   105  		// right padding
   106  		f.buf.writeString(s)
   107  		f.writePadding(width)
   108  	}
   109  }
   110  
   111  // fmtBoolean formats a boolean.
   112  func (f *formatter) fmtBoolean(v bool) {
   113  	if v {
   114  		f.padString("true")
   115  	} else {
   116  		f.padString("false")
   117  	}
   118  }
   119  
   120  // fmtUnicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'".
   121  func (f *formatter) fmtUnicode(u uint64) {
   122  	buf := f.intbuf[0:]
   123  
   124  	// With default precision set the maximum needed buf length is 18
   125  	// for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits
   126  	// into the already allocated intbuf with a capacity of 68 bytes.
   127  	prec := 4
   128  	if f.precPresent && f.prec > 4 {
   129  		prec = f.prec
   130  		// Compute space needed for "U+" , number, " '", character, "'".
   131  		width := 2 + prec + 2 + utf8.UTFMax + 1
   132  		if width > len(buf) {
   133  			buf = make([]byte, width)
   134  		}
   135  	}
   136  
   137  	// Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left.
   138  	i := len(buf)
   139  
   140  	// For %#U we want to add a space and a quoted character at the end of the buffer.
   141  	if f.sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) {
   142  		i--
   143  		buf[i] = '\''
   144  		i -= utf8.RuneLen(rune(u))
   145  		utf8.EncodeRune(buf[i:], rune(u))
   146  		i--
   147  		buf[i] = '\''
   148  		i--
   149  		buf[i] = ' '
   150  	}
   151  	// Format the Unicode code point u as a hexadecimal number.
   152  	for u >= 16 {
   153  		i--
   154  		buf[i] = udigits[u&0xF]
   155  		prec--
   156  		u >>= 4
   157  	}
   158  	i--
   159  	buf[i] = udigits[u]
   160  	prec--
   161  	// Add zeros in front of the number until requested precision is reached.
   162  	for prec > 0 {
   163  		i--
   164  		buf[i] = '0'
   165  		prec--
   166  	}
   167  	// Add a leading "U+".
   168  	i--
   169  	buf[i] = '+'
   170  	i--
   171  	buf[i] = 'U'
   172  
   173  	oldZero := f.zero
   174  	f.zero = false
   175  	f.pad(buf[i:])
   176  	f.zero = oldZero
   177  }
   178  
   179  // fmtInteger formats signed and unsigned integers.
   180  func (f *formatter) fmtInteger(u uint64, base int, isSigned bool, verb rune, digits string) {
   181  	negative := isSigned && int64(u) < 0
   182  	if negative {
   183  		u = -u
   184  	}
   185  
   186  	buf := f.intbuf[0:]
   187  	// The already allocated f.intbuf with a capacity of 68 bytes
   188  	// is large enough for integer formatting when no precision or width is set.
   189  	if f.widPresent || f.precPresent {
   190  		// Account 3 extra bytes for possible addition of a sign and "0x".
   191  		width := 3 + f.wid + f.prec // wid and prec are always positive.
   192  		if width > len(buf) {
   193  			// We're going to need a bigger boat.
   194  			buf = make([]byte, width)
   195  		}
   196  	}
   197  
   198  	// Two ways to ask for extra leading zero digits: %.3d or %03d.
   199  	// If both are specified the f.zero flag is ignored and
   200  	// padding with spaces is used instead.
   201  	prec := 0
   202  	if f.precPresent {
   203  		prec = f.prec
   204  		// Precision of 0 and value of 0 means "print nothing" but padding.
   205  		if prec == 0 && u == 0 {
   206  			oldZero := f.zero
   207  			f.zero = false
   208  			f.writePadding(f.wid)
   209  			f.zero = oldZero
   210  			return
   211  		}
   212  	} else if f.zero && f.widPresent {
   213  		prec = f.wid
   214  		if negative || f.plus || f.space {
   215  			prec-- // leave room for sign
   216  		}
   217  	}
   218  
   219  	// Because printing is easier right-to-left: format u into buf, ending at buf[i].
   220  	// We could make things marginally faster by splitting the 32-bit case out
   221  	// into a separate block but it's not worth the duplication, so u has 64 bits.
   222  	i := len(buf)
   223  	// Use constants for the division and modulo for more efficient code.
   224  	// Switch cases ordered by popularity.
   225  	switch base {
   226  	case 10:
   227  		for u >= 10 {
   228  			i--
   229  			next := u / 10
   230  			buf[i] = byte('0' + u - next*10)
   231  			u = next
   232  		}
   233  	case 16:
   234  		for u >= 16 {
   235  			i--
   236  			buf[i] = digits[u&0xF]
   237  			u >>= 4
   238  		}
   239  	case 8:
   240  		for u >= 8 {
   241  			i--
   242  			buf[i] = byte('0' + u&7)
   243  			u >>= 3
   244  		}
   245  	case 2:
   246  		for u >= 2 {
   247  			i--
   248  			buf[i] = byte('0' + u&1)
   249  			u >>= 1
   250  		}
   251  	default:
   252  		panic("fmt: unknown base; can't happen")
   253  	}
   254  	i--
   255  	buf[i] = digits[u]
   256  	for i > 0 && prec > len(buf)-i {
   257  		i--
   258  		buf[i] = '0'
   259  	}
   260  
   261  	// Various prefixes: 0x, -, etc.
   262  	if f.sharp {
   263  		switch base {
   264  		case 2:
   265  			// Add a leading 0b.
   266  			i--
   267  			buf[i] = 'b'
   268  			i--
   269  			buf[i] = '0'
   270  		case 8:
   271  			if buf[i] != '0' {
   272  				i--
   273  				buf[i] = '0'
   274  			}
   275  		case 16:
   276  			// Add a leading 0x or 0X.
   277  			i--
   278  			buf[i] = digits[16]
   279  			i--
   280  			buf[i] = '0'
   281  		}
   282  	}
   283  	if verb == 'O' {
   284  		i--
   285  		buf[i] = 'o'
   286  		i--
   287  		buf[i] = '0'
   288  	}
   289  
   290  	if negative {
   291  		i--
   292  		buf[i] = '-'
   293  	} else if f.plus {
   294  		i--
   295  		buf[i] = '+'
   296  	} else if f.space {
   297  		i--
   298  		buf[i] = ' '
   299  	}
   300  
   301  	// Left padding with zeros has already been handled like precision earlier
   302  	// or the f.zero flag is ignored due to an explicitly set precision.
   303  	oldZero := f.zero
   304  	f.zero = false
   305  	f.pad(buf[i:])
   306  	f.zero = oldZero
   307  }
   308  
   309  // truncate truncates the string s to the specified precision, if present.
   310  func (f *formatter) truncateString(s string) string {
   311  	if f.precPresent {
   312  		n := f.prec
   313  		for i := range s {
   314  			n--
   315  			if n < 0 {
   316  				return s[:i]
   317  			}
   318  		}
   319  	}
   320  	return s
   321  }
   322  
   323  // truncate truncates the byte slice b as a string of the specified precision, if present.
   324  func (f *formatter) truncate(b []byte) []byte {
   325  	if f.precPresent {
   326  		n := f.prec
   327  		for i := 0; i < len(b); {
   328  			n--
   329  			if n < 0 {
   330  				return b[:i]
   331  			}
   332  			wid := 1
   333  			if b[i] >= utf8.RuneSelf {
   334  				_, wid = utf8.DecodeRune(b[i:])
   335  			}
   336  			i += wid
   337  		}
   338  	}
   339  	return b
   340  }
   341  
   342  // fmtS formats a string.
   343  func (f *formatter) fmtS(s string) {
   344  	s = f.truncateString(s)
   345  	f.padString(s)
   346  }
   347  
   348  // fmtBs formats the byte slice b as if it was formatted as string with fmtS.
   349  func (f *formatter) fmtBs(b []byte) {
   350  	b = f.truncate(b)
   351  	f.pad(b)
   352  }
   353  
   354  // fmtSbx formats a string or byte slice as a hexadecimal encoding of its bytes.
   355  func (f *formatter) fmtSbx(s string, b []byte, digits string) {
   356  	length := len(b)
   357  	if b == nil {
   358  		// No byte slice present. Assume string s should be encoded.
   359  		length = len(s)
   360  	}
   361  	// Set length to not process more bytes than the precision demands.
   362  	if f.precPresent && f.prec < length {
   363  		length = f.prec
   364  	}
   365  	// Compute width of the encoding taking into account the f.sharp and f.space flag.
   366  	width := 2 * length
   367  	if width > 0 {
   368  		if f.space {
   369  			// Each element encoded by two hexadecimals will get a leading 0x or 0X.
   370  			if f.sharp {
   371  				width *= 2
   372  			}
   373  			// Elements will be separated by a space.
   374  			width += length - 1
   375  		} else if f.sharp {
   376  			// Only a leading 0x or 0X will be added for the whole string.
   377  			width += 2
   378  		}
   379  	} else { // The byte slice or string that should be encoded is empty.
   380  		if f.widPresent {
   381  			f.writePadding(f.wid)
   382  		}
   383  		return
   384  	}
   385  	// Handle padding to the left.
   386  	if f.widPresent && f.wid > width && !f.minus {
   387  		f.writePadding(f.wid - width)
   388  	}
   389  	// Write the encoding directly into the output buffer.
   390  	buf := *f.buf
   391  	if f.sharp {
   392  		// Add leading 0x or 0X.
   393  		buf = append(buf, '0', digits[16])
   394  	}
   395  	var c byte
   396  	for i := 0; i < length; i++ {
   397  		if f.space && i > 0 {
   398  			// Separate elements with a space.
   399  			buf = append(buf, ' ')
   400  			if f.sharp {
   401  				// Add leading 0x or 0X for each element.
   402  				buf = append(buf, '0', digits[16])
   403  			}
   404  		}
   405  		if b != nil {
   406  			c = b[i] // Take a byte from the input byte slice.
   407  		} else {
   408  			c = s[i] // Take a byte from the input string.
   409  		}
   410  		// Encode each byte as two hexadecimal digits.
   411  		buf = append(buf, digits[c>>4], digits[c&0xF])
   412  	}
   413  	*f.buf = buf
   414  	// Handle padding to the right.
   415  	if f.widPresent && f.wid > width && f.minus {
   416  		f.writePadding(f.wid - width)
   417  	}
   418  }
   419  
   420  // fmtSx formats a string as a hexadecimal encoding of its bytes.
   421  func (f *formatter) fmtSx(s, digits string) {
   422  	f.fmtSbx(s, nil, digits)
   423  }
   424  
   425  // fmtBx formats a byte slice as a hexadecimal encoding of its bytes.
   426  func (f *formatter) fmtBx(b []byte, digits string) {
   427  	f.fmtSbx("", b, digits)
   428  }
   429  
   430  // fmtQ formats a string as a double-quoted, escaped Go string constant.
   431  // If f.sharp is set a raw (backquoted) string may be returned instead
   432  // if the string does not contain any control characters other than tab.
   433  func (f *formatter) fmtQ(s string) {
   434  	s = f.truncateString(s)
   435  	if f.sharp && strconv.CanBackquote(s) {
   436  		f.padString("`" + s + "`")
   437  		return
   438  	}
   439  	buf := f.intbuf[:0]
   440  	if f.plus {
   441  		f.pad(strconv.AppendQuoteToASCII(buf, s))
   442  	} else {
   443  		f.pad(strconv.AppendQuote(buf, s))
   444  	}
   445  }
   446  
   447  // fmtC formats an integer as a Unicode character.
   448  // If the character is not valid Unicode, it will print '\ufffd'.
   449  func (f *formatter) fmtC(c uint64) {
   450  	r := rune(c)
   451  	if c > utf8.MaxRune {
   452  		r = utf8.RuneError
   453  	}
   454  	buf := f.intbuf[:0]
   455  	w := utf8.EncodeRune(buf[:utf8.UTFMax], r)
   456  	f.pad(buf[:w])
   457  }
   458  
   459  // fmtQc formats an integer as a single-quoted, escaped Go character constant.
   460  // If the character is not valid Unicode, it will print '\ufffd'.
   461  func (f *formatter) fmtQc(c uint64) {
   462  	r := rune(c)
   463  	if c > utf8.MaxRune {
   464  		r = utf8.RuneError
   465  	}
   466  	buf := f.intbuf[:0]
   467  	if f.plus {
   468  		f.pad(strconv.AppendQuoteRuneToASCII(buf, r))
   469  	} else {
   470  		f.pad(strconv.AppendQuoteRune(buf, r))
   471  	}
   472  }
   473  
   474  // fmtFloat formats a float64. It assumes that verb is a valid format specifier
   475  // for strconv.AppendFloat and therefore fits into a byte.
   476  func (f *formatter) fmtFloat(v float64, size int, verb rune, prec int) {
   477  	// Explicit precision in format specifier overrules default precision.
   478  	if f.precPresent {
   479  		prec = f.prec
   480  	}
   481  	// Format number, reserving space for leading + sign if needed.
   482  	num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size)
   483  	if num[1] == '-' || num[1] == '+' {
   484  		num = num[1:]
   485  	} else {
   486  		num[0] = '+'
   487  	}
   488  	// f.space means to add a leading space instead of a "+" sign unless
   489  	// the sign is explicitly asked for by f.plus.
   490  	if f.space && num[0] == '+' && !f.plus {
   491  		num[0] = ' '
   492  	}
   493  	// Special handling for infinities and NaN,
   494  	// which don't look like a number so shouldn't be padded with zeros.
   495  	if num[1] == 'I' || num[1] == 'N' {
   496  		oldZero := f.zero
   497  		f.zero = false
   498  		// Remove sign before NaN if not asked for.
   499  		if num[1] == 'N' && !f.space && !f.plus {
   500  			num = num[1:]
   501  		}
   502  		f.pad(num)
   503  		f.zero = oldZero
   504  		return
   505  	}
   506  	// The sharp flag forces printing a decimal point for non-binary formats
   507  	// and retains trailing zeros, which we may need to restore.
   508  	if f.sharp && verb != 'b' {
   509  		digits := 0
   510  		switch verb {
   511  		case 'v', 'g', 'G', 'x':
   512  			digits = prec
   513  			// If no precision is set explicitly use a precision of 6.
   514  			if digits == -1 {
   515  				digits = 6
   516  			}
   517  		}
   518  
   519  		// Buffer pre-allocated with enough room for
   520  		// exponent notations of the form "e+123" or "p-1023".
   521  		var tailBuf [6]byte
   522  		tail := tailBuf[:0]
   523  
   524  		hasDecimalPoint := false
   525  		sawNonzeroDigit := false
   526  		// Starting from i = 1 to skip sign at num[0].
   527  		for i := 1; i < len(num); i++ {
   528  			switch num[i] {
   529  			case '.':
   530  				hasDecimalPoint = true
   531  			case 'p', 'P':
   532  				tail = append(tail, num[i:]...)
   533  				num = num[:i]
   534  			case 'e', 'E':
   535  				if verb != 'x' && verb != 'X' {
   536  					tail = append(tail, num[i:]...)
   537  					num = num[:i]
   538  					break
   539  				}
   540  				fallthrough
   541  			default:
   542  				if num[i] != '0' {
   543  					sawNonzeroDigit = true
   544  				}
   545  				// Count significant digits after the first non-zero digit.
   546  				if sawNonzeroDigit {
   547  					digits--
   548  				}
   549  			}
   550  		}
   551  		if !hasDecimalPoint {
   552  			// Leading digit 0 should contribute once to digits.
   553  			if len(num) == 2 && num[1] == '0' {
   554  				digits--
   555  			}
   556  			num = append(num, '.')
   557  		}
   558  		for digits > 0 {
   559  			num = append(num, '0')
   560  			digits--
   561  		}
   562  		num = append(num, tail...)
   563  	}
   564  	// We want a sign if asked for and if the sign is not positive.
   565  	if f.plus || num[0] != '+' {
   566  		// If we're zero padding to the left we want the sign before the leading zeros.
   567  		// Achieve this by writing the sign out and then padding the unsigned number.
   568  		if f.zero && f.widPresent && f.wid > len(num) {
   569  			f.buf.writeByte(num[0])
   570  			f.writePadding(f.wid - len(num))
   571  			f.buf.write(num[1:])
   572  			return
   573  		}
   574  		f.pad(num)
   575  		return
   576  	}
   577  	// No sign to show and the number is positive; just print the unsigned number.
   578  	f.pad(num[1:])
   579  }