├── LICENSE ├── README.md ├── decimal.go ├── extfloat.go ├── float.go ├── go.mod ├── printer_test.go └── printers.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 CloudyKit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fastprinter 2 | FastPrinter supports write values in io.Writer without allocation 3 | -------------------------------------------------------------------------------- /decimal.go: -------------------------------------------------------------------------------- 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 | // Multiprecision decimal numbers. 6 | // For floating-point formatting only; not general purpose. 7 | // Only operations are assign and (binary) left/right shift. 8 | // Can do binary floating point in multiprecision decimal precisely 9 | // because 2 divides 10; cannot do decimal floating point 10 | // in multiprecision binary precisely. 11 | 12 | package fastprinter 13 | 14 | type decimal struct { 15 | d [800]byte // digits, big-endian representation 16 | nd int // number of digits used 17 | dp int // decimal point 18 | neg bool 19 | trunc bool // discarded nonzero digits beyond d[:nd] 20 | } 21 | 22 | // trim trailing zeros from number. 23 | // (They are meaningless; the decimal point is tracked 24 | // independent of the number of digits.) 25 | func trim(a *decimal) { 26 | for a.nd > 0 && a.d[a.nd-1] == '0' { 27 | a.nd-- 28 | } 29 | if a.nd == 0 { 30 | a.dp = 0 31 | } 32 | } 33 | 34 | // Assign v to a. 35 | func (a *decimal) Assign(v uint64) { 36 | var buf [24]byte 37 | 38 | // Write reversed decimal in buf. 39 | n := 0 40 | for v > 0 { 41 | v1 := v / 10 42 | v -= 10 * v1 43 | buf[n] = byte(v + '0') 44 | n++ 45 | v = v1 46 | } 47 | 48 | // Reverse again to produce forward decimal in a.d. 49 | a.nd = 0 50 | for n--; n >= 0; n-- { 51 | a.d[a.nd] = buf[n] 52 | a.nd++ 53 | } 54 | a.dp = a.nd 55 | trim(a) 56 | } 57 | 58 | // Maximum shift that we can do in one pass without overflow. 59 | // A uint has 32 or 64 bits, and we have to be able to accommodate 9<> 63) 61 | const maxShift = uintSize - 4 62 | 63 | // Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow. 64 | func rightShift(a *decimal, k uint) { 65 | r := 0 // read pointer 66 | w := 0 // write pointer 67 | 68 | // Pick up enough leading digits to cover first shift. 69 | var n uint 70 | for ; n>>k == 0; r++ { 71 | if r >= a.nd { 72 | if n == 0 { 73 | // a == 0; shouldn't get here, but handle anyway. 74 | a.nd = 0 75 | return 76 | } 77 | for n>>k == 0 { 78 | n = n * 10 79 | r++ 80 | } 81 | break 82 | } 83 | c := uint(a.d[r]) 84 | n = n*10 + c - '0' 85 | } 86 | a.dp -= r - 1 87 | 88 | // Pick up a digit, put down a digit. 89 | for ; r < a.nd; r++ { 90 | c := uint(a.d[r]) 91 | dig := n >> k 92 | n -= dig << k 93 | a.d[w] = byte(dig + '0') 94 | w++ 95 | n = n*10 + c - '0' 96 | } 97 | 98 | // Put down extra digits. 99 | for n > 0 { 100 | dig := n >> k 101 | n -= dig << k 102 | if w < len(a.d) { 103 | a.d[w] = byte(dig + '0') 104 | w++ 105 | } else if dig > 0 { 106 | a.trunc = true 107 | } 108 | n = n * 10 109 | } 110 | 111 | a.nd = w 112 | trim(a) 113 | } 114 | 115 | // Cheat sheet for left shift: table indexed by shift count giving 116 | // number of new digits that will be introduced by that shift. 117 | // 118 | // For example, leftcheats[4] = {2, "625"}. That means that 119 | // if we are shifting by 4 (multiplying by 16), it will add 2 digits 120 | // when the string prefix is "625" through "999", and one fewer digit 121 | // if the string prefix is "000" through "624". 122 | // 123 | // Credit for this trick goes to Ken. 124 | 125 | type leftCheat struct { 126 | delta int // number of new digits 127 | cutoff string // minus one digit if original < a. 128 | } 129 | 130 | var leftcheats = []leftCheat{ 131 | // Leading digits of 1/2^i = 5^i. 132 | // 5^23 is not an exact 64-bit floating point number, 133 | // so have to use bc for the math. 134 | // Go up to 60 to be large enough for 32bit and 64bit platforms. 135 | /* 136 | seq 60 | sed 's/^/5^/' | bc | 137 | awk 'BEGIN{ print "\t{ 0, \"\" }," } 138 | { 139 | log2 = log(2)/log(10) 140 | printf("\t{ %d, \"%s\" },\t// * %d\n", 141 | int(log2*NR+1), $0, 2**NR) 142 | }' 143 | */ 144 | {0, ""}, 145 | {1, "5"}, // * 2 146 | {1, "25"}, // * 4 147 | {1, "125"}, // * 8 148 | {2, "625"}, // * 16 149 | {2, "3125"}, // * 32 150 | {2, "15625"}, // * 64 151 | {3, "78125"}, // * 128 152 | {3, "390625"}, // * 256 153 | {3, "1953125"}, // * 512 154 | {4, "9765625"}, // * 1024 155 | {4, "48828125"}, // * 2048 156 | {4, "244140625"}, // * 4096 157 | {4, "1220703125"}, // * 8192 158 | {5, "6103515625"}, // * 16384 159 | {5, "30517578125"}, // * 32768 160 | {5, "152587890625"}, // * 65536 161 | {6, "762939453125"}, // * 131072 162 | {6, "3814697265625"}, // * 262144 163 | {6, "19073486328125"}, // * 524288 164 | {7, "95367431640625"}, // * 1048576 165 | {7, "476837158203125"}, // * 2097152 166 | {7, "2384185791015625"}, // * 4194304 167 | {7, "11920928955078125"}, // * 8388608 168 | {8, "59604644775390625"}, // * 16777216 169 | {8, "298023223876953125"}, // * 33554432 170 | {8, "1490116119384765625"}, // * 67108864 171 | {9, "7450580596923828125"}, // * 134217728 172 | {9, "37252902984619140625"}, // * 268435456 173 | {9, "186264514923095703125"}, // * 536870912 174 | {10, "931322574615478515625"}, // * 1073741824 175 | {10, "4656612873077392578125"}, // * 2147483648 176 | {10, "23283064365386962890625"}, // * 4294967296 177 | {10, "116415321826934814453125"}, // * 8589934592 178 | {11, "582076609134674072265625"}, // * 17179869184 179 | {11, "2910383045673370361328125"}, // * 34359738368 180 | {11, "14551915228366851806640625"}, // * 68719476736 181 | {12, "72759576141834259033203125"}, // * 137438953472 182 | {12, "363797880709171295166015625"}, // * 274877906944 183 | {12, "1818989403545856475830078125"}, // * 549755813888 184 | {13, "9094947017729282379150390625"}, // * 1099511627776 185 | {13, "45474735088646411895751953125"}, // * 2199023255552 186 | {13, "227373675443232059478759765625"}, // * 4398046511104 187 | {13, "1136868377216160297393798828125"}, // * 8796093022208 188 | {14, "5684341886080801486968994140625"}, // * 17592186044416 189 | {14, "28421709430404007434844970703125"}, // * 35184372088832 190 | {14, "142108547152020037174224853515625"}, // * 70368744177664 191 | {15, "710542735760100185871124267578125"}, // * 140737488355328 192 | {15, "3552713678800500929355621337890625"}, // * 281474976710656 193 | {15, "17763568394002504646778106689453125"}, // * 562949953421312 194 | {16, "88817841970012523233890533447265625"}, // * 1125899906842624 195 | {16, "444089209850062616169452667236328125"}, // * 2251799813685248 196 | {16, "2220446049250313080847263336181640625"}, // * 4503599627370496 197 | {16, "11102230246251565404236316680908203125"}, // * 9007199254740992 198 | {17, "55511151231257827021181583404541015625"}, // * 18014398509481984 199 | {17, "277555756156289135105907917022705078125"}, // * 36028797018963968 200 | {17, "1387778780781445675529539585113525390625"}, // * 72057594037927936 201 | {18, "6938893903907228377647697925567626953125"}, // * 144115188075855872 202 | {18, "34694469519536141888238489627838134765625"}, // * 288230376151711744 203 | {18, "173472347597680709441192448139190673828125"}, // * 576460752303423488 204 | {19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976 205 | } 206 | 207 | // Is the leading prefix of b lexicographically less than s? 208 | func prefixIsLessThan(b []byte, s string) bool { 209 | for i := 0; i < len(s); i++ { 210 | if i >= len(b) { 211 | return true 212 | } 213 | if b[i] != s[i] { 214 | return b[i] < s[i] 215 | } 216 | } 217 | return false 218 | } 219 | 220 | // Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow. 221 | func leftShift(a *decimal, k uint) { 222 | delta := leftcheats[k].delta 223 | if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) { 224 | delta-- 225 | } 226 | 227 | r := a.nd // read index 228 | w := a.nd + delta // write index 229 | 230 | // Pick up a digit, put down a digit. 231 | var n uint 232 | for r--; r >= 0; r-- { 233 | n += (uint(a.d[r]) - '0') << k 234 | quo := n / 10 235 | rem := n - 10*quo 236 | w-- 237 | if w < len(a.d) { 238 | a.d[w] = byte(rem + '0') 239 | } else if rem != 0 { 240 | a.trunc = true 241 | } 242 | n = quo 243 | } 244 | 245 | // Put down extra digits. 246 | for n > 0 { 247 | quo := n / 10 248 | rem := n - 10*quo 249 | w-- 250 | if w < len(a.d) { 251 | a.d[w] = byte(rem + '0') 252 | } else if rem != 0 { 253 | a.trunc = true 254 | } 255 | n = quo 256 | } 257 | 258 | a.nd += delta 259 | if a.nd >= len(a.d) { 260 | a.nd = len(a.d) 261 | } 262 | a.dp += delta 263 | trim(a) 264 | } 265 | 266 | // Binary shift left (k > 0) or right (k < 0). 267 | func (a *decimal) Shift(k int) { 268 | switch { 269 | case a.nd == 0: 270 | // nothing to do: a == 0 271 | case k > 0: 272 | for k > maxShift { 273 | leftShift(a, maxShift) 274 | k -= maxShift 275 | } 276 | leftShift(a, uint(k)) 277 | case k < 0: 278 | for k < -maxShift { 279 | rightShift(a, maxShift) 280 | k += maxShift 281 | } 282 | rightShift(a, uint(-k)) 283 | } 284 | } 285 | 286 | // If we chop a at nd digits, should we round up? 287 | func shouldRoundUp(a *decimal, nd int) bool { 288 | if nd < 0 || nd >= a.nd { 289 | return false 290 | } 291 | if a.d[nd] == '5' && nd+1 == a.nd { 292 | // exactly halfway - round to even 293 | // if we truncated, a little higher than what's recorded - always round up 294 | if a.trunc { 295 | return true 296 | } 297 | return nd > 0 && (a.d[nd-1]-'0')%2 != 0 298 | } 299 | // not halfway - digit tells all 300 | return a.d[nd] >= '5' 301 | } 302 | 303 | // Round a to nd digits (or fewer). 304 | // If nd is zero, it means we're rounding 305 | // just to the left of the digits, as in 306 | // 0.09 -> 0.1. 307 | func (a *decimal) Round(nd int) { 308 | if nd < 0 || nd >= a.nd { 309 | return 310 | } 311 | if shouldRoundUp(a, nd) { 312 | a.RoundUp(nd) 313 | } else { 314 | a.RoundDown(nd) 315 | } 316 | } 317 | 318 | // Round a down to nd digits (or fewer). 319 | func (a *decimal) RoundDown(nd int) { 320 | if nd < 0 || nd >= a.nd { 321 | return 322 | } 323 | a.nd = nd 324 | trim(a) 325 | } 326 | 327 | // Round a up to nd digits (or fewer). 328 | func (a *decimal) RoundUp(nd int) { 329 | if nd < 0 || nd >= a.nd { 330 | return 331 | } 332 | 333 | // round up 334 | for i := nd - 1; i >= 0; i-- { 335 | c := a.d[i] 336 | if c < '9' { 337 | // can stop after this digit 338 | a.d[i]++ 339 | a.nd = i + 1 340 | return 341 | } 342 | } 343 | 344 | // Number is all 9s. 345 | // Change to single 1 with adjusted decimal point. 346 | a.d[0] = '1' 347 | a.nd = 1 348 | a.dp++ 349 | } 350 | 351 | // Extract integer part, rounded appropriately. 352 | // No guarantees about overflow. 353 | func (a *decimal) RoundedInteger() uint64 { 354 | if a.dp > 20 { 355 | return 0xFFFFFFFFFFFFFFFF 356 | } 357 | var i int 358 | n := uint64(0) 359 | for i = 0; i < a.dp && i < a.nd; i++ { 360 | n = n*10 + uint64(a.d[i]-'0') 361 | } 362 | for ; i < a.dp; i++ { 363 | n *= 10 364 | } 365 | if shouldRoundUp(a, a.dp) { 366 | n++ 367 | } 368 | return n 369 | } 370 | -------------------------------------------------------------------------------- /extfloat.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 fastprinter 6 | 7 | // An extFloat represents an extended floating-point number, with more 8 | // precision than a float64. It does not try to save bits: the 9 | // number represented by the structure is mant*(2^exp), with a negative 10 | // sign if neg is true. 11 | type extFloat struct { 12 | mant uint64 13 | exp int 14 | neg bool 15 | } 16 | 17 | // Powers of ten taken from double-conversion library. 18 | // http://code.google.com/p/double-conversion/ 19 | const ( 20 | firstPowerOfTen = -348 21 | stepPowerOfTen = 8 22 | ) 23 | 24 | var smallPowersOfTen = [...]extFloat{ 25 | {1 << 63, -63, false}, // 1 26 | {0xa << 60, -60, false}, // 1e1 27 | {0x64 << 57, -57, false}, // 1e2 28 | {0x3e8 << 54, -54, false}, // 1e3 29 | {0x2710 << 50, -50, false}, // 1e4 30 | {0x186a0 << 47, -47, false}, // 1e5 31 | {0xf4240 << 44, -44, false}, // 1e6 32 | {0x989680 << 40, -40, false}, // 1e7 33 | } 34 | 35 | var powersOfTen = [...]extFloat{ 36 | {0xfa8fd5a0081c0288, -1220, false}, // 10^-348 37 | {0xbaaee17fa23ebf76, -1193, false}, // 10^-340 38 | {0x8b16fb203055ac76, -1166, false}, // 10^-332 39 | {0xcf42894a5dce35ea, -1140, false}, // 10^-324 40 | {0x9a6bb0aa55653b2d, -1113, false}, // 10^-316 41 | {0xe61acf033d1a45df, -1087, false}, // 10^-308 42 | {0xab70fe17c79ac6ca, -1060, false}, // 10^-300 43 | {0xff77b1fcbebcdc4f, -1034, false}, // 10^-292 44 | {0xbe5691ef416bd60c, -1007, false}, // 10^-284 45 | {0x8dd01fad907ffc3c, -980, false}, // 10^-276 46 | {0xd3515c2831559a83, -954, false}, // 10^-268 47 | {0x9d71ac8fada6c9b5, -927, false}, // 10^-260 48 | {0xea9c227723ee8bcb, -901, false}, // 10^-252 49 | {0xaecc49914078536d, -874, false}, // 10^-244 50 | {0x823c12795db6ce57, -847, false}, // 10^-236 51 | {0xc21094364dfb5637, -821, false}, // 10^-228 52 | {0x9096ea6f3848984f, -794, false}, // 10^-220 53 | {0xd77485cb25823ac7, -768, false}, // 10^-212 54 | {0xa086cfcd97bf97f4, -741, false}, // 10^-204 55 | {0xef340a98172aace5, -715, false}, // 10^-196 56 | {0xb23867fb2a35b28e, -688, false}, // 10^-188 57 | {0x84c8d4dfd2c63f3b, -661, false}, // 10^-180 58 | {0xc5dd44271ad3cdba, -635, false}, // 10^-172 59 | {0x936b9fcebb25c996, -608, false}, // 10^-164 60 | {0xdbac6c247d62a584, -582, false}, // 10^-156 61 | {0xa3ab66580d5fdaf6, -555, false}, // 10^-148 62 | {0xf3e2f893dec3f126, -529, false}, // 10^-140 63 | {0xb5b5ada8aaff80b8, -502, false}, // 10^-132 64 | {0x87625f056c7c4a8b, -475, false}, // 10^-124 65 | {0xc9bcff6034c13053, -449, false}, // 10^-116 66 | {0x964e858c91ba2655, -422, false}, // 10^-108 67 | {0xdff9772470297ebd, -396, false}, // 10^-100 68 | {0xa6dfbd9fb8e5b88f, -369, false}, // 10^-92 69 | {0xf8a95fcf88747d94, -343, false}, // 10^-84 70 | {0xb94470938fa89bcf, -316, false}, // 10^-76 71 | {0x8a08f0f8bf0f156b, -289, false}, // 10^-68 72 | {0xcdb02555653131b6, -263, false}, // 10^-60 73 | {0x993fe2c6d07b7fac, -236, false}, // 10^-52 74 | {0xe45c10c42a2b3b06, -210, false}, // 10^-44 75 | {0xaa242499697392d3, -183, false}, // 10^-36 76 | {0xfd87b5f28300ca0e, -157, false}, // 10^-28 77 | {0xbce5086492111aeb, -130, false}, // 10^-20 78 | {0x8cbccc096f5088cc, -103, false}, // 10^-12 79 | {0xd1b71758e219652c, -77, false}, // 10^-4 80 | {0x9c40000000000000, -50, false}, // 10^4 81 | {0xe8d4a51000000000, -24, false}, // 10^12 82 | {0xad78ebc5ac620000, 3, false}, // 10^20 83 | {0x813f3978f8940984, 30, false}, // 10^28 84 | {0xc097ce7bc90715b3, 56, false}, // 10^36 85 | {0x8f7e32ce7bea5c70, 83, false}, // 10^44 86 | {0xd5d238a4abe98068, 109, false}, // 10^52 87 | {0x9f4f2726179a2245, 136, false}, // 10^60 88 | {0xed63a231d4c4fb27, 162, false}, // 10^68 89 | {0xb0de65388cc8ada8, 189, false}, // 10^76 90 | {0x83c7088e1aab65db, 216, false}, // 10^84 91 | {0xc45d1df942711d9a, 242, false}, // 10^92 92 | {0x924d692ca61be758, 269, false}, // 10^100 93 | {0xda01ee641a708dea, 295, false}, // 10^108 94 | {0xa26da3999aef774a, 322, false}, // 10^116 95 | {0xf209787bb47d6b85, 348, false}, // 10^124 96 | {0xb454e4a179dd1877, 375, false}, // 10^132 97 | {0x865b86925b9bc5c2, 402, false}, // 10^140 98 | {0xc83553c5c8965d3d, 428, false}, // 10^148 99 | {0x952ab45cfa97a0b3, 455, false}, // 10^156 100 | {0xde469fbd99a05fe3, 481, false}, // 10^164 101 | {0xa59bc234db398c25, 508, false}, // 10^172 102 | {0xf6c69a72a3989f5c, 534, false}, // 10^180 103 | {0xb7dcbf5354e9bece, 561, false}, // 10^188 104 | {0x88fcf317f22241e2, 588, false}, // 10^196 105 | {0xcc20ce9bd35c78a5, 614, false}, // 10^204 106 | {0x98165af37b2153df, 641, false}, // 10^212 107 | {0xe2a0b5dc971f303a, 667, false}, // 10^220 108 | {0xa8d9d1535ce3b396, 694, false}, // 10^228 109 | {0xfb9b7cd9a4a7443c, 720, false}, // 10^236 110 | {0xbb764c4ca7a44410, 747, false}, // 10^244 111 | {0x8bab8eefb6409c1a, 774, false}, // 10^252 112 | {0xd01fef10a657842c, 800, false}, // 10^260 113 | {0x9b10a4e5e9913129, 827, false}, // 10^268 114 | {0xe7109bfba19c0c9d, 853, false}, // 10^276 115 | {0xac2820d9623bf429, 880, false}, // 10^284 116 | {0x80444b5e7aa7cf85, 907, false}, // 10^292 117 | {0xbf21e44003acdd2d, 933, false}, // 10^300 118 | {0x8e679c2f5e44ff8f, 960, false}, // 10^308 119 | {0xd433179d9c8cb841, 986, false}, // 10^316 120 | {0x9e19db92b4e31ba9, 1013, false}, // 10^324 121 | {0xeb96bf6ebadf77d9, 1039, false}, // 10^332 122 | {0xaf87023b9bf0ee6b, 1066, false}, // 10^340 123 | } 124 | 125 | // floatBits returns the bits of the float64 that best approximates 126 | // the extFloat passed as receiver. Overflow is set to true if 127 | // the resulting float64 is ±Inf. 128 | func (f *extFloat) floatBits(flt *floatInfo) (bits uint64, overflow bool) { 129 | f.Normalize() 130 | 131 | exp := f.exp + 63 132 | 133 | // Exponent too small. 134 | if exp < flt.bias+1 { 135 | n := flt.bias + 1 - exp 136 | f.mant >>= uint(n) 137 | exp += n 138 | } 139 | 140 | // Extract 1+flt.mantbits bits from the 64-bit mantissa. 141 | mant := f.mant >> (63 - flt.mantbits) 142 | if f.mant&(1<<(62-flt.mantbits)) != 0 { 143 | // Round up. 144 | mant += 1 145 | } 146 | 147 | // Rounding might have added a bit; shift down. 148 | if mant == 2<>= 1 150 | exp++ 151 | } 152 | 153 | // Infinities. 154 | if exp-flt.bias >= 1<>uint(-f.exp))<>= uint(-f.exp) 183 | f.exp = 0 184 | return *f, *f 185 | } 186 | expBiased := exp - flt.bias 187 | 188 | upper = extFloat{mant: 2*f.mant + 1, exp: f.exp - 1, neg: f.neg} 189 | if mant != 1<>(64-32) == 0 { 205 | mant <<= 32 206 | exp -= 32 207 | } 208 | if mant>>(64-16) == 0 { 209 | mant <<= 16 210 | exp -= 16 211 | } 212 | if mant>>(64-8) == 0 { 213 | mant <<= 8 214 | exp -= 8 215 | } 216 | if mant>>(64-4) == 0 { 217 | mant <<= 4 218 | exp -= 4 219 | } 220 | if mant>>(64-2) == 0 { 221 | mant <<= 2 222 | exp -= 2 223 | } 224 | if mant>>(64-1) == 0 { 225 | mant <<= 1 226 | exp -= 1 227 | } 228 | shift = uint(f.exp - exp) 229 | f.mant, f.exp = mant, exp 230 | return 231 | } 232 | 233 | // Multiply sets f to the product f*g: the result is correctly rounded, 234 | // but not normalized. 235 | func (f *extFloat) Multiply(g extFloat) { 236 | fhi, flo := f.mant>>32, uint64(uint32(f.mant)) 237 | ghi, glo := g.mant>>32, uint64(uint32(g.mant)) 238 | 239 | // Cross products. 240 | cross1 := fhi * glo 241 | cross2 := flo * ghi 242 | 243 | // f.mant*g.mant is fhi*ghi << 64 + (cross1+cross2) << 32 + flo*glo 244 | f.mant = fhi*ghi + (cross1 >> 32) + (cross2 >> 32) 245 | rem := uint64(uint32(cross1)) + uint64(uint32(cross2)) + ((flo * glo) >> 32) 246 | // Round up. 247 | rem += (1 << 31) 248 | 249 | f.mant += (rem >> 32) 250 | f.exp = f.exp + g.exp + 64 251 | } 252 | 253 | var uint64pow10 = [...]uint64{ 254 | 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 255 | 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 256 | } 257 | 258 | // AssignDecimal sets f to an approximate value mantissa*10^exp. It 259 | // reports whether the value represented by f is guaranteed to be the 260 | // best approximation of d after being rounded to a float64 or 261 | // float32 depending on flt. 262 | func (f *extFloat) AssignDecimal(mantissa uint64, exp10 int, neg bool, trunc bool, flt *floatInfo) (ok bool) { 263 | const uint64digits = 19 264 | const errorscale = 8 265 | errors := 0 // An upper bound for error, computed in errorscale*ulp. 266 | if trunc { 267 | // the decimal number was truncated. 268 | errors += errorscale / 2 269 | } 270 | 271 | f.mant = mantissa 272 | f.exp = 0 273 | f.neg = neg 274 | 275 | // Multiply by powers of ten. 276 | i := (exp10 - firstPowerOfTen) / stepPowerOfTen 277 | if exp10 < firstPowerOfTen || i >= len(powersOfTen) { 278 | return false 279 | } 280 | adjExp := (exp10 - firstPowerOfTen) % stepPowerOfTen 281 | 282 | // We multiply by exp%step 283 | if adjExp < uint64digits && mantissa < uint64pow10[uint64digits-adjExp] { 284 | // We can multiply the mantissa exactly. 285 | f.mant *= uint64pow10[adjExp] 286 | f.Normalize() 287 | } else { 288 | f.Normalize() 289 | f.Multiply(smallPowersOfTen[adjExp]) 290 | errors += errorscale / 2 291 | } 292 | 293 | // We multiply by 10 to the exp - exp%step. 294 | f.Multiply(powersOfTen[i]) 295 | if errors > 0 { 296 | errors += 1 297 | } 298 | errors += errorscale / 2 299 | 300 | // Normalize 301 | shift := f.Normalize() 302 | errors <<= shift 303 | 304 | // Now f is a good approximation of the decimal. 305 | // Check whether the error is too large: that is, if the mantissa 306 | // is perturbated by the error, the resulting float64 will change. 307 | // The 64 bits mantissa is 1 + 52 bits for float64 + 11 extra bits. 308 | // 309 | // In many cases the approximation will be good enough. 310 | denormalExp := flt.bias - 63 311 | var extrabits uint 312 | if f.exp <= denormalExp { 313 | // f.mant * 2^f.exp is smaller than 2^(flt.bias+1). 314 | extrabits = uint(63 - flt.mantbits + 1 + uint(denormalExp-f.exp)) 315 | } else { 316 | extrabits = uint(63 - flt.mantbits) 317 | } 318 | 319 | halfway := uint64(1) << (extrabits - 1) 320 | mant_extra := f.mant & (1< expMax: 355 | i-- 356 | default: 357 | break Loop 358 | } 359 | } 360 | // Apply the desired decimal shift on f. It will have exponent 361 | // in the desired range. This is multiplication by 10^-exp10. 362 | f.Multiply(powersOfTen[i]) 363 | 364 | return -(firstPowerOfTen + i*stepPowerOfTen), i 365 | } 366 | 367 | // frexp10Many applies a common shift by a power of ten to a, b, c. 368 | func frexp10Many(a, b, c *extFloat) (exp10 int) { 369 | exp10, i := c.frexp10() 370 | a.Multiply(powersOfTen[i]) 371 | b.Multiply(powersOfTen[i]) 372 | return 373 | } 374 | 375 | // FixedDecimal stores in d the first n significant digits 376 | // of the decimal representation of f. It returns false 377 | // if it cannot be sure of the answer. 378 | func (f *extFloat) FixedDecimal(d *decimalSlice, n int) bool { 379 | if f.mant == 0 { 380 | d.nd = 0 381 | d.dp = 0 382 | d.neg = f.neg 383 | return true 384 | } 385 | if n == 0 { 386 | panic("strconv: internal error: extFloat.FixedDecimal called with n == 0") 387 | } 388 | // Multiply by an appropriate power of ten to have a reasonable 389 | // number to process. 390 | f.Normalize() 391 | exp10, _ := f.frexp10() 392 | 393 | shift := uint(-f.exp) 394 | integer := uint32(f.mant >> shift) 395 | fraction := f.mant - (uint64(integer) << shift) 396 | ε := uint64(1) // ε is the uncertainty we have on the mantissa of f. 397 | 398 | // Write exactly n digits to d. 399 | needed := n // how many digits are left to write. 400 | integerDigits := 0 // the number of decimal digits of integer. 401 | pow10 := uint64(1) // the power of ten by which f was scaled. 402 | for i, pow := 0, uint64(1); i < 20; i++ { 403 | if pow > uint64(integer) { 404 | integerDigits = i 405 | break 406 | } 407 | pow *= 10 408 | } 409 | rest := integer 410 | if integerDigits > needed { 411 | // the integral part is already large, trim the last digits. 412 | pow10 = uint64pow10[integerDigits-needed] 413 | integer /= uint32(pow10) 414 | rest -= integer * uint32(pow10) 415 | } else { 416 | rest = 0 417 | } 418 | 419 | // Write the digits of integer: the digits of rest are omitted. 420 | var buf [32]byte 421 | pos := len(buf) 422 | for v := integer; v > 0; { 423 | v1 := v / 10 424 | v -= 10 * v1 425 | pos-- 426 | buf[pos] = byte(v + '0') 427 | v = v1 428 | } 429 | for i := pos; i < len(buf); i++ { 430 | d.d[i-pos] = buf[i] 431 | } 432 | nd := len(buf) - pos 433 | d.nd = nd 434 | d.dp = integerDigits + exp10 435 | needed -= nd 436 | 437 | if needed > 0 { 438 | if rest != 0 || pow10 != 1 { 439 | panic("strconv: internal error, rest != 0 but needed > 0") 440 | } 441 | // Emit digits for the fractional part. Each time, 10*fraction 442 | // fits in a uint64 without overflow. 443 | for needed > 0 { 444 | fraction *= 10 445 | ε *= 10 // the uncertainty scales as we multiply by ten. 446 | if 2*ε > 1<> shift 451 | d.d[nd] = byte(digit + '0') 452 | fraction -= digit << shift 453 | nd++ 454 | needed-- 455 | } 456 | d.nd = nd 457 | } 458 | 459 | // We have written a truncation of f (a numerator / 10^d.dp). The remaining part 460 | // can be interpreted as a small number (< 1) to be added to the last digit of the 461 | // numerator. 462 | // 463 | // If rest > 0, the amount is: 464 | // (rest< 0 guarantees that pow10 << shift does not overflow a uint64. 467 | // 468 | // If rest = 0, pow10 == 1 and the amount is 469 | // fraction / (1 << shift) 470 | // fraction being known with a ±ε uncertainty. 471 | // 472 | // We pass this information to the rounding routine for adjustment. 473 | 474 | ok := adjustLastDigitFixed(d, uint64(rest)<= 0; i-- { 480 | if d.d[i] != '0' { 481 | d.nd = i + 1 482 | break 483 | } 484 | } 485 | return true 486 | } 487 | 488 | // adjustLastDigitFixed assumes d contains the representation of the integral part 489 | // of some number, whose fractional part is num / (den << shift). The numerator 490 | // num is only known up to an uncertainty of size ε, assumed to be less than 491 | // (den << shift)/2. 492 | // 493 | // It will increase the last digit by one to account for correct rounding, typically 494 | // when the fractional part is greater than 1/2, and will return false if ε is such 495 | // that no correct answer can be given. 496 | func adjustLastDigitFixed(d *decimalSlice, num, den uint64, shift uint, ε uint64) bool { 497 | if num > den< den< den< (den< den<= 0; i-- { 510 | if d.d[i] == '9' { 511 | d.nd-- 512 | } else { 513 | break 514 | } 515 | } 516 | if i < 0 { 517 | d.d[0] = '1' 518 | d.nd = 1 519 | d.dp++ 520 | } else { 521 | d.d[i]++ 522 | } 523 | return true 524 | } 525 | return false 526 | } 527 | 528 | // ShortestDecimal stores in d the shortest decimal representation of f 529 | // which belongs to the open interval (lower, upper), where f is supposed 530 | // to lie. It returns false whenever the result is unsure. The implementation 531 | // uses the Grisu3 algorithm. 532 | func (f *extFloat) ShortestDecimal(d *decimalSlice, lower, upper *extFloat) bool { 533 | if f.mant == 0 { 534 | d.nd = 0 535 | d.dp = 0 536 | d.neg = f.neg 537 | return true 538 | } 539 | if f.exp == 0 && *lower == *f && *lower == *upper { 540 | // an exact integer. 541 | var buf [24]byte 542 | n := len(buf) - 1 543 | for v := f.mant; v > 0; { 544 | v1 := v / 10 545 | v -= 10 * v1 546 | buf[n] = byte(v + '0') 547 | n-- 548 | v = v1 549 | } 550 | nd := len(buf) - n - 1 551 | for i := 0; i < nd; i++ { 552 | d.d[i] = buf[n+1+i] 553 | } 554 | d.nd, d.dp = nd, nd 555 | for d.nd > 0 && d.d[d.nd-1] == '0' { 556 | d.nd-- 557 | } 558 | if d.nd == 0 { 559 | d.dp = 0 560 | } 561 | d.neg = f.neg 562 | return true 563 | } 564 | upper.Normalize() 565 | // Uniformize exponents. 566 | if f.exp > upper.exp { 567 | f.mant <<= uint(f.exp - upper.exp) 568 | f.exp = upper.exp 569 | } 570 | if lower.exp > upper.exp { 571 | lower.mant <<= uint(lower.exp - upper.exp) 572 | lower.exp = upper.exp 573 | } 574 | 575 | exp10 := frexp10Many(lower, f, upper) 576 | // Take a safety margin due to rounding in frexp10Many, but we lose precision. 577 | upper.mant++ 578 | lower.mant-- 579 | 580 | // The shortest representation of f is either rounded up or down, but 581 | // in any case, it is a truncation of upper. 582 | shift := uint(-upper.exp) 583 | integer := uint32(upper.mant >> shift) 584 | fraction := upper.mant - (uint64(integer) << shift) 585 | 586 | // How far we can go down from upper until the result is wrong. 587 | allowance := upper.mant - lower.mant 588 | // How far we should go to get a very precise result. 589 | targetDiff := upper.mant - f.mant 590 | 591 | // Count integral digits: there are at most 10. 592 | var integerDigits int 593 | for i, pow := 0, uint64(1); i < 20; i++ { 594 | if pow > uint64(integer) { 595 | integerDigits = i 596 | break 597 | } 598 | pow *= 10 599 | } 600 | for i := 0; i < integerDigits; i++ { 601 | pow := uint64pow10[integerDigits-i-1] 602 | digit := integer / uint32(pow) 603 | d.d[i] = byte(digit + '0') 604 | integer -= digit * uint32(pow) 605 | // evaluate whether we should stop. 606 | if currentDiff := uint64(integer)<> shift) 627 | d.d[d.nd] = byte(digit + '0') 628 | d.nd++ 629 | fraction -= uint64(digit) << shift 630 | if fraction < allowance*multiplier { 631 | // We are in the admissible range. Note that if allowance is about to 632 | // overflow, that is, allowance > 2^64/10, the condition is automatically 633 | // true due to the limited range of fraction. 634 | return adjustLastDigit(d, 635 | fraction, targetDiff*multiplier, allowance*multiplier, 636 | 1< maxDiff-ulpBinary { 659 | // we went too far 660 | return false 661 | } 662 | if d.nd == 1 && d.d[0] == '0' { 663 | // the number has actually reached zero. 664 | d.nd = 0 665 | d.dp = 0 666 | } 667 | return true 668 | } 669 | -------------------------------------------------------------------------------- /float.go: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2017 José Santos 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package fastprinter 24 | 25 | import ( 26 | "io" 27 | "math" 28 | ) 29 | 30 | type floatInfo struct { 31 | mantbits uint 32 | expbits uint 33 | bias int 34 | } 35 | 36 | var ( 37 | float64info = floatInfo{52, 11, -1023} 38 | floatNaN = []byte("Nan") 39 | floatNinf = []byte("-Inf") 40 | floatPinf = []byte("+Inf") 41 | pool_floatBuffer = newByteSliceBufferPool(800) 42 | ) 43 | 44 | func PrintFloat(w io.Writer, f float64) (int, error) { 45 | return PrintFloatPrecision(w, f, -1) 46 | } 47 | 48 | func PrintFloatPrecision(dst io.Writer, val float64, prec int) (int, error) { 49 | var bits uint64 50 | var flt *floatInfo 51 | 52 | bits = math.Float64bits(val) 53 | flt = &float64info 54 | 55 | neg := bits>>(flt.expbits+flt.mantbits) != 0 56 | exp := int(bits>>flt.mantbits) & (1< 2^(exp-mantbits), 141 | // or equivalently log2(10)*(dp-nd) > exp-mantbits. 142 | // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32). 143 | minexp := flt.bias + 1 // minimum possible exponent 144 | if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) { 145 | // The number is already shortest. 146 | return 147 | } 148 | 149 | // d = mant << (exp - mantbits) 150 | // Next highest floating point number is mant+1 << exp-mantbits. 151 | // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1. 152 | upper := new(decimal) 153 | upper.Assign(mant*2 + 1) 154 | upper.Shift(exp - int(flt.mantbits) - 1) 155 | 156 | // d = mant << (exp - mantbits) 157 | // Next lowest floating point number is mant-1 << exp-mantbits, 158 | // unless mant-1 drops the significant bit and exp is not the minimum exp, 159 | // in which case the next lowest is mant*2-1 << exp-mantbits-1. 160 | // Either way, call it mantlo << explo-mantbits. 161 | // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1. 162 | var mantlo uint64 163 | var explo int 164 | if mant > 1< 0 { 236 | m := min(d.nd, d.dp) 237 | copy(a.bytes[i:], d.d[:m]) 238 | i += m 239 | for ; m < d.dp; m++ { 240 | a.bytes[i] = '0' 241 | i++ 242 | } 243 | } else { 244 | a.bytes[i] = '0' 245 | i++ 246 | } 247 | 248 | // fraction 249 | if prec > 0 { 250 | a.bytes[i] = '.' 251 | i++ 252 | for j := 0; j < prec; j++ { 253 | ch := byte('0') 254 | if j := d.dp + j; 0 <= j && j < d.nd { 255 | ch = d.d[j] 256 | } 257 | a.bytes[i] = ch 258 | i++ 259 | } 260 | } 261 | n, err = dst.Write(a.bytes[0:i]) 262 | pool_floatBuffer.Put(a) 263 | return 264 | } 265 | 266 | func min(a, b int) int { 267 | if a < b { 268 | return a 269 | } 270 | return b 271 | } 272 | 273 | func max(a, b int) int { 274 | if a > b { 275 | return a 276 | } 277 | return b 278 | } 279 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/CloudyKit/fastprinter 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /printer_test.go: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2017 José Santos 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package fastprinter 24 | 25 | import ( 26 | "fmt" 27 | "io" 28 | "math" 29 | "reflect" 30 | "strings" 31 | "testing" 32 | ) 33 | 34 | type devNull struct{} 35 | 36 | func (*devNull) Write(_ []byte) (int, error) { 37 | return 0, nil 38 | } 39 | 40 | var ww io.Writer = (*devNull)(nil) 41 | 42 | type testWriter struct { 43 | main [stringBufferSize * 64]byte 44 | bytes []byte 45 | } 46 | 47 | func newTestWriter() *testWriter { 48 | ww := new(testWriter) 49 | ww.reset() 50 | return ww 51 | } 52 | 53 | func (w *testWriter) Write(b []byte) (n int, err error) { 54 | w.bytes = append(w.bytes, b...) 55 | n = len(b) 56 | return 57 | } 58 | 59 | func (w *testWriter) reset() { 60 | w.bytes = w.main[:0] 61 | } 62 | 63 | func (w *testWriter) Assert(m string) { 64 | if string(w.bytes) != m { 65 | panic(fmt.Errorf("expected value is %s got %s", m, string(w.bytes))) 66 | } 67 | w.reset() 68 | } 69 | 70 | func (w *testWriter) String() string { 71 | defer w.reset() 72 | return string(w.bytes) 73 | } 74 | 75 | var w = newTestWriter() 76 | 77 | func TestPrintBool(t *testing.T) { 78 | 79 | allocsPerRun := testing.AllocsPerRun(3000, func() { 80 | PrintBool(w, true) 81 | w.Assert("true") 82 | PrintBool(w, false) 83 | w.Assert("false") 84 | }) 85 | 86 | if allocsPerRun > 0 { 87 | t.Errorf("PrintBool is allocating %f", allocsPerRun) 88 | } 89 | } 90 | 91 | var bigString = strings.Repeat("Hello World!", stringBufferSize) 92 | 93 | func TestPrintString(t *testing.T) { 94 | 95 | allocsPerRun := testing.AllocsPerRun(3000, func() { 96 | const value = "Hello World" 97 | PrintString(w, value) 98 | w.Assert(value) 99 | PrintString(w, bigString) 100 | w.Assert(bigString) 101 | }) 102 | 103 | if allocsPerRun > 0 { 104 | t.Errorf("PrintString is allocating %f", allocsPerRun) 105 | } 106 | 107 | } 108 | 109 | func TestPrintFloat(t *testing.T) { 110 | 111 | allocsPerRun := testing.AllocsPerRun(5000, func() { 112 | PrintFloat(w, 44.4) 113 | w.Assert("44.4") 114 | PrintFloat(w, math.Pi) 115 | w.Assert("3.141592653589793") 116 | PrintFloatPrecision(w, math.Pi, 2) 117 | w.Assert("3.14") 118 | PrintFloatPrecision(w, math.Pi, 2) 119 | w.Assert("3.14") 120 | PrintFloatPrecision(w, -1.23, 2) 121 | w.Assert("-1.23") 122 | PrintFloatPrecision(w, 1.23, 2) 123 | w.Assert("1.23") 124 | }) 125 | 126 | if allocsPerRun > 0 { 127 | t.Errorf("PrintFloat is allocating %f", allocsPerRun) 128 | } 129 | } 130 | 131 | func TestPrintBytes(t *testing.T) { 132 | 133 | hellobytes := []byte("Hello world!!") 134 | 135 | allocsPerRun := testing.AllocsPerRun(5000, func() { 136 | PrintValue(w, reflect.ValueOf(&hellobytes).Elem()) 137 | w.Assert("Hello world!!") 138 | }) 139 | 140 | if allocsPerRun > 0 { 141 | t.Errorf("PrintValue is allocating %f", allocsPerRun) 142 | } 143 | } 144 | 145 | func TestPrintInt(t *testing.T) { 146 | 147 | allocsPerRun := testing.AllocsPerRun(3000, func() { 148 | PrintInt(w, -300) 149 | w.Assert("-300") 150 | PrintUint(w, 300) 151 | w.Assert("300") 152 | }) 153 | 154 | if allocsPerRun > 0 { 155 | t.Errorf("Print(u)Int is allocating %f", allocsPerRun) 156 | } 157 | } 158 | 159 | func BenchmarkPrintInt(b *testing.B) { 160 | for i := 0; i < b.N; i++ { 161 | PrintInt(ww, 9000000000) 162 | } 163 | } 164 | 165 | func BenchmarkPrintFloat(b *testing.B) { 166 | for i := 0; i < b.N; i++ { 167 | PrintFloat(ww, 9000.000000) 168 | } 169 | } 170 | 171 | func BenchmarkPrintFloatPrec(b *testing.B) { 172 | for i := 0; i < b.N; i++ { 173 | PrintFloatPrecision(ww, 9000.000000, 5) 174 | } 175 | } 176 | 177 | func BenchmarkPrintString(b *testing.B) { 178 | for i := 0; i < b.N; i++ { 179 | PrintString(ww, "-------------------------------------------------------------------------------") 180 | } 181 | } 182 | 183 | func BenchmarkPrintIntFmt(b *testing.B) { 184 | for i := 0; i < b.N; i++ { 185 | fmt.Fprint(ww, 9000000000) 186 | } 187 | } 188 | 189 | func BenchmarkPrintFloatFmt(b *testing.B) { 190 | for i := 0; i < b.N; i++ { 191 | fmt.Fprint(ww, 9000.000000) 192 | } 193 | } 194 | 195 | func BenchmarkPrintStringFmt(b *testing.B) { 196 | for i := 0; i < b.N; i++ { 197 | fmt.Fprint(ww, "-------------------------------------------------------------------------------") 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /printers.go: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2017 José Santos 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package fastprinter 24 | 25 | import ( 26 | "fmt" 27 | "io" 28 | "reflect" 29 | "sync" 30 | ) 31 | 32 | const ( 33 | stringBufferSize = 4096 34 | integerBufferSize = 20 35 | ) 36 | 37 | var ( 38 | _trueBytes = ([]byte)("true") 39 | _falseBytes = ([]byte)("false") 40 | 41 | pool_integerBuffer = newByteSliceBufferPool(integerBufferSize) 42 | pool_stringBuffer = newByteSliceBufferPool(stringBufferSize) 43 | 44 | errorType = reflect.TypeOf((*error)(nil)).Elem() 45 | fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() 46 | ) 47 | 48 | type byteSliceBuffer struct { 49 | bytes []byte 50 | } 51 | 52 | func newByteSliceBufferPool(size int) sync.Pool { 53 | return sync.Pool{ 54 | New: func() interface{} { 55 | return &byteSliceBuffer{make([]byte, size, size)} 56 | }, 57 | } 58 | } 59 | 60 | func Print(w io.Writer, i interface{}) (int, error) { 61 | return PrintValue(w, reflect.ValueOf(i)) 62 | } 63 | 64 | func PrintPtr(w io.Writer, i interface{}) (int, error) { 65 | return PrintValue(w, reflect.ValueOf(i).Elem()) 66 | } 67 | 68 | func PrintBool(w io.Writer, b bool) (int, error) { 69 | if b { 70 | return w.Write(_trueBytes) 71 | } 72 | return w.Write(_falseBytes) 73 | } 74 | 75 | func PrintString(ww io.Writer, st string) (c int, err error) { 76 | if st == "" { 77 | return 0, nil 78 | } 79 | 80 | numI := len(st) / stringBufferSize 81 | nextBucket := 0 82 | written := 0 83 | 84 | a := pool_stringBuffer.Get().(*byteSliceBuffer) 85 | for i := 0; i < numI; i++ { 86 | copy(a.bytes[:], st[nextBucket:nextBucket+stringBufferSize]) 87 | nextBucket += stringBufferSize 88 | written, err = ww.Write(a.bytes[:]) 89 | c += written 90 | if err != nil { 91 | return 92 | } 93 | } 94 | 95 | smallBucket := len(st) % stringBufferSize 96 | if smallBucket > 0 { 97 | copy(a.bytes[:], st[nextBucket:]) 98 | written, err = ww.Write(a.bytes[:smallBucket]) 99 | c += written 100 | } 101 | pool_stringBuffer.Put(a) 102 | return 103 | } 104 | 105 | func PrintUint(w io.Writer, i uint64) (int, error) { 106 | return formatBits(w, i, false) 107 | } 108 | 109 | func PrintInt(w io.Writer, i int64) (int, error) { 110 | return formatBits(w, uint64(i), i < 0) 111 | } 112 | 113 | // formatBits computes the string representation of u in the given base. 114 | // If neg is set, u is treated as negative int64 value. 115 | // Extracted from std package strconv 116 | func formatBits(dst io.Writer, u uint64, neg bool) (int, error) { 117 | 118 | var a = pool_integerBuffer.Get().(*byteSliceBuffer) 119 | 120 | i := integerBufferSize 121 | 122 | if neg { 123 | u = -u 124 | } 125 | 126 | // common case: use constants for / because 127 | // the compiler can optimize it into a multiply+shift 128 | 129 | if ^uintptr(0)>>32 == 0 { 130 | for u > uint64(^uintptr(0)) { 131 | q := u / 1e9 132 | us := uintptr(u - q*1e9) // us % 1e9 fits into a uintptr 133 | for j := 9; j > 0; j-- { 134 | i-- 135 | qs := us / 10 136 | a.bytes[i] = byte(us - qs*10 + '0') 137 | us = qs 138 | } 139 | u = q 140 | } 141 | } 142 | 143 | // u guaranteed to fit into a uintptr 144 | us := uintptr(u) 145 | for us >= 10 { 146 | i-- 147 | q := us / 10 148 | a.bytes[i] = byte(us - q*10 + '0') 149 | us = q 150 | } 151 | // u < 10 152 | i-- 153 | a.bytes[i] = byte(us + '0') 154 | 155 | // add sign, if any 156 | if neg { 157 | i-- 158 | a.bytes[i] = '-' 159 | } 160 | counter, err := dst.Write(a.bytes[i:]) 161 | pool_integerBuffer.Put(a) 162 | return counter, err 163 | } 164 | 165 | // PrintValue prints a reflect.Value 166 | func PrintValue(w io.Writer, v reflect.Value) (int, error) { 167 | v = maybeDereference(v, 2) 168 | 169 | if v.Type().Implements(fmtStringerType) { 170 | return PrintString(w, v.Interface().(fmt.Stringer).String()) 171 | } 172 | 173 | if v.Type().Implements(errorType) { 174 | return PrintString(w, v.Interface().(error).Error()) 175 | } 176 | 177 | k := v.Kind() 178 | 179 | if k == reflect.String { 180 | return PrintString(w, v.String()) 181 | } 182 | 183 | if k >= reflect.Int && k <= reflect.Int64 { 184 | return PrintInt(w, v.Int()) 185 | } 186 | 187 | if k >= reflect.Uint && k <= reflect.Uint64 { 188 | return PrintUint(w, v.Uint()) 189 | } 190 | 191 | if k == reflect.Float64 || k == reflect.Float32 { 192 | return PrintFloat(w, v.Float()) 193 | } 194 | 195 | if k == reflect.Bool { 196 | return PrintBool(w, v.Bool()) 197 | } 198 | 199 | if k == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 { 200 | return w.Write(v.Bytes()) 201 | } 202 | 203 | return fmt.Fprint(w, v.Interface()) 204 | } 205 | 206 | // dereference a certain depth of pointer indirection 207 | func maybeDereference(v reflect.Value, depth int) reflect.Value { 208 | if depth <= 0 { 209 | return v 210 | } 211 | 212 | if !v.IsValid() { 213 | return v 214 | } 215 | 216 | if v.Kind() != reflect.Ptr || v.IsNil() { 217 | return v 218 | } 219 | 220 | if v.Type().Implements(fmtStringerType) || v.Type().Implements(errorType) { 221 | return v 222 | } 223 | 224 | return maybeDereference(reflect.Indirect(v), depth-1) 225 | } 226 | --------------------------------------------------------------------------------