github.com/matrixorigin/matrixone@v1.2.0/pkg/txn/trace/format.go (about) 1 // Copyright 2024 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package trace 16 17 import ( 18 "math/bits" 19 ) 20 21 const fastSmalls = true // enable fast path for small integers 22 23 // AppendInt appends the string form of the integer i, 24 // as generated by FormatInt, to dst and returns the extended buffer. 25 func AppendInt(dst []byte, i int64, base int) []byte { 26 if fastSmalls && 0 <= i && i < nSmalls && base == 10 { 27 return append(dst, small(int(i))...) 28 } 29 dst = formatBits(dst, uint64(i), base, i < 0, true) 30 return dst 31 } 32 33 // AppendUint appends the string form of the unsigned integer i, 34 // as generated by FormatUint, to dst and returns the extended buffer. 35 func AppendUint(dst []byte, i uint64, base int) []byte { 36 if fastSmalls && i < nSmalls && base == 10 { 37 return append(dst, small(int(i))...) 38 } 39 dst = formatBits(dst, i, base, false, true) 40 return dst 41 } 42 43 // small returns the string for an i with 0 <= i < nSmalls. 44 func small(i int) string { 45 if i < 10 { 46 return digits[i : i+1] 47 } 48 return smallsString[i*2 : i*2+2] 49 } 50 51 const nSmalls = 100 52 53 const smallsString = "00010203040506070809" + 54 "10111213141516171819" + 55 "20212223242526272829" + 56 "30313233343536373839" + 57 "40414243444546474849" + 58 "50515253545556575859" + 59 "60616263646566676869" + 60 "70717273747576777879" + 61 "80818283848586878889" + 62 "90919293949596979899" 63 64 const host32bit = ^uint(0)>>32 == 0 65 66 const digits = "0123456789abcdefghijklmnopqrstuvwxyz" 67 68 // formatBits computes the string representation of u in the given base. 69 // If neg is set, u is treated as negative int64 value. If append_ is 70 // set, the string is appended to dst and the resulting byte slice is 71 // returned as the first result value; otherwise the string is returned 72 // as the second result value. 73 func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte) { 74 if base < 2 || base > len(digits) { 75 panic("strconv: illegal AppendInt/FormatInt base") 76 } 77 // 2 <= base && base <= len(digits) 78 79 var a [64 + 1]byte // +1 for sign of 64bit value in base 2 80 i := len(a) 81 82 if neg { 83 u = -u 84 } 85 86 // convert bits 87 // We use uint values where we can because those will 88 // fit into a single register even on a 32bit machine. 89 if base == 10 { 90 // common case: use constants for / because 91 // the compiler can optimize it into a multiply+shift 92 93 if host32bit { 94 // convert the lower digits using 32bit operations 95 for u >= 1e9 { 96 // Avoid using r = a%b in addition to q = a/b 97 // since 64bit division and modulo operations 98 // are calculated by runtime functions on 32bit machines. 99 q := u / 1e9 100 us := uint(u - q*1e9) // u % 1e9 fits into a uint 101 for j := 4; j > 0; j-- { 102 is := us % 100 * 2 103 us /= 100 104 i -= 2 105 a[i+1] = smallsString[is+1] 106 a[i+0] = smallsString[is+0] 107 } 108 109 // us < 10, since it contains the last digit 110 // from the initial 9-digit us. 111 i-- 112 a[i] = smallsString[us*2+1] 113 114 u = q 115 } 116 // u < 1e9 117 } 118 119 // u guaranteed to fit into a uint 120 us := uint(u) 121 for us >= 100 { 122 is := us % 100 * 2 123 us /= 100 124 i -= 2 125 a[i+1] = smallsString[is+1] 126 a[i+0] = smallsString[is+0] 127 } 128 129 // us < 100 130 is := us * 2 131 i-- 132 a[i] = smallsString[is+1] 133 if us >= 10 { 134 i-- 135 a[i] = smallsString[is] 136 } 137 138 } else if isPowerOfTwo(base) { 139 // Use shifts and masks instead of / and %. 140 // Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 36. 141 // The largest power of 2 below or equal to 36 is 32, which is 1 << 5; 142 // i.e., the largest possible shift count is 5. By &-ind that value with 143 // the constant 7 we tell the compiler that the shift count is always 144 // less than 8 which is smaller than any register width. This allows 145 // the compiler to generate better code for the shift operation. 146 shift := uint(bits.TrailingZeros(uint(base))) & 7 147 b := uint64(base) 148 m := uint(base) - 1 // == 1<<shift - 1 149 for u >= b { 150 i-- 151 a[i] = digits[uint(u)&m] 152 u >>= shift 153 } 154 // u < base 155 i-- 156 a[i] = digits[uint(u)] 157 } else { 158 // general case 159 b := uint64(base) 160 for u >= b { 161 i-- 162 // Avoid using r = a%b in addition to q = a/b 163 // since 64bit division and modulo operations 164 // are calculated by runtime functions on 32bit machines. 165 q := u / b 166 a[i] = digits[uint(u-q*b)] 167 u = q 168 } 169 // u < base 170 i-- 171 a[i] = digits[uint(u)] 172 } 173 174 // add sign, if any 175 if neg { 176 i-- 177 a[i] = '-' 178 } 179 180 if append_ { 181 d = append(dst, a[i:]...) 182 return 183 } 184 return 185 } 186 187 func isPowerOfTwo(x int) bool { 188 return x&(x-1) == 0 189 }