github.com/goccy/go-json@v0.10.3-0.20240509105655-5e2ae3f23c1d/internal/encoder/int.go (about) 1 // This files's processing codes are inspired by https://github.com/segmentio/encoding. 2 // The license notation is as follows. 3 // 4 // # MIT License 5 // 6 // Copyright (c) 2019 Segment.io, Inc. 7 // 8 // Permission is hereby granted, free of charge, to any person obtaining a copy 9 // of this software and associated documentation files (the "Software"), to deal 10 // in the Software without restriction, including without limitation the rights 11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 // copies of the Software, and to permit persons to whom the Software is 13 // furnished to do so, subject to the following conditions: 14 // 15 // The above copyright notice and this permission notice shall be included in all 16 // copies or substantial portions of the Software. 17 // 18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 // SOFTWARE. 25 package encoder 26 27 import ( 28 "unsafe" 29 ) 30 31 var endianness int 32 33 func init() { 34 var b [2]byte 35 *(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD) 36 37 switch b[0] { 38 case 0xCD: 39 endianness = 0 // LE 40 case 0xAB: 41 endianness = 1 // BE 42 default: 43 panic("could not determine endianness") 44 } 45 } 46 47 // "00010203...96979899" cast to []uint16 48 var intLELookup = [100]uint16{ 49 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, 50 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, 51 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, 52 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, 53 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, 54 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, 55 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, 56 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, 57 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, 58 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939, 59 } 60 61 var intBELookup = [100]uint16{ 62 0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039, 63 0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139, 64 0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239, 65 0x3330, 0x3331, 0x3332, 0x3333, 0x3334, 0x3335, 0x3336, 0x3337, 0x3338, 0x3339, 66 0x3430, 0x3431, 0x3432, 0x3433, 0x3434, 0x3435, 0x3436, 0x3437, 0x3438, 0x3439, 67 0x3530, 0x3531, 0x3532, 0x3533, 0x3534, 0x3535, 0x3536, 0x3537, 0x3538, 0x3539, 68 0x3630, 0x3631, 0x3632, 0x3633, 0x3634, 0x3635, 0x3636, 0x3637, 0x3638, 0x3639, 69 0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739, 70 0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839, 71 0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939, 72 } 73 74 var intLookup = [2]*[100]uint16{&intLELookup, &intBELookup} 75 76 func numMask(numBitSize uint8) uint64 { 77 return 1<<numBitSize - 1 78 } 79 80 func AppendInt(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte { 81 var u64 uint64 82 switch code.NumBitSize { 83 case 8: 84 u64 = (uint64)(**(**uint8)(unsafe.Pointer(&p))) 85 case 16: 86 u64 = (uint64)(**(**uint16)(unsafe.Pointer(&p))) 87 case 32: 88 u64 = (uint64)(**(**uint32)(unsafe.Pointer(&p))) 89 case 64: 90 u64 = **(**uint64)(unsafe.Pointer(&p)) 91 } 92 mask := numMask(code.NumBitSize) 93 n := u64 & mask 94 negative := (u64>>(code.NumBitSize-1))&1 == 1 95 if !negative { 96 if n < 10 { 97 return append(out, byte(n+'0')) 98 } else if n < 100 { 99 u := intLELookup[n] 100 return append(out, byte(u), byte(u>>8)) 101 } 102 } else { 103 n = -n & mask 104 } 105 106 lookup := intLookup[endianness] 107 108 var b [22]byte 109 u := (*[11]uint16)(unsafe.Pointer(&b)) 110 i := 11 111 112 for n >= 100 { 113 j := n % 100 114 n /= 100 115 i-- 116 u[i] = lookup[j] 117 } 118 119 i-- 120 u[i] = lookup[n] 121 122 i *= 2 // convert to byte index 123 if n < 10 { 124 i++ // remove leading zero 125 } 126 if negative { 127 i-- 128 b[i] = '-' 129 } 130 131 return append(out, b[i:]...) 132 } 133 134 func AppendUint(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte { 135 var u64 uint64 136 switch code.NumBitSize { 137 case 8: 138 u64 = (uint64)(**(**uint8)(unsafe.Pointer(&p))) 139 case 16: 140 u64 = (uint64)(**(**uint16)(unsafe.Pointer(&p))) 141 case 32: 142 u64 = (uint64)(**(**uint32)(unsafe.Pointer(&p))) 143 case 64: 144 u64 = **(**uint64)(unsafe.Pointer(&p)) 145 } 146 mask := numMask(code.NumBitSize) 147 n := u64 & mask 148 if n < 10 { 149 return append(out, byte(n+'0')) 150 } else if n < 100 { 151 u := intLELookup[n] 152 return append(out, byte(u), byte(u>>8)) 153 } 154 155 lookup := intLookup[endianness] 156 157 var b [22]byte 158 u := (*[11]uint16)(unsafe.Pointer(&b)) 159 i := 11 160 161 for n >= 100 { 162 j := n % 100 163 n /= 100 164 i-- 165 u[i] = lookup[j] 166 } 167 168 i-- 169 u[i] = lookup[n] 170 171 i *= 2 // convert to byte index 172 if n < 10 { 173 i++ // remove leading zero 174 } 175 return append(out, b[i:]...) 176 }