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 }