github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/codec/number.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package codec 15 16 import ( 17 "encoding/binary" 18 "math" 19 20 "github.com/whtcorpsinc/errors" 21 ) 22 23 const signMask uint64 = 0x8000000000000000 24 25 // EncodeIntToCmpUint make int v to comparable uint type 26 func EncodeIntToCmpUint(v int64) uint64 { 27 return uint64(v) ^ signMask 28 } 29 30 // DecodeCmpUintToInt decodes the u that encoded by EncodeIntToCmpUint 31 func DecodeCmpUintToInt(u uint64) int64 { 32 return int64(u ^ signMask) 33 } 34 35 // EncodeInt appends the encoded value to slice b and returns the appended slice. 36 // EncodeInt guarantees that the encoded value is in ascending order for comparison. 37 func EncodeInt(b []byte, v int64) []byte { 38 var data [8]byte 39 u := EncodeIntToCmpUint(v) 40 binary.BigEndian.PutUint64(data[:], u) 41 return append(b, data[:]...) 42 } 43 44 // EncodeIntDesc appends the encoded value to slice b and returns the appended slice. 45 // EncodeIntDesc guarantees that the encoded value is in descending order for comparison. 46 func EncodeIntDesc(b []byte, v int64) []byte { 47 var data [8]byte 48 u := EncodeIntToCmpUint(v) 49 binary.BigEndian.PutUint64(data[:], ^u) 50 return append(b, data[:]...) 51 } 52 53 // DecodeInt decodes value encoded by EncodeInt before. 54 // It returns the leftover un-decoded slice, decoded value if no error. 55 func DecodeInt(b []byte) ([]byte, int64, error) { 56 if len(b) < 8 { 57 return nil, 0, errors.New("insufficient bytes to decode value") 58 } 59 60 u := binary.BigEndian.Uint64(b[:8]) 61 v := DecodeCmpUintToInt(u) 62 b = b[8:] 63 return b, v, nil 64 } 65 66 // DecodeIntDesc decodes value encoded by EncodeInt before. 67 // It returns the leftover un-decoded slice, decoded value if no error. 68 func DecodeIntDesc(b []byte) ([]byte, int64, error) { 69 if len(b) < 8 { 70 return nil, 0, errors.New("insufficient bytes to decode value") 71 } 72 73 u := binary.BigEndian.Uint64(b[:8]) 74 v := DecodeCmpUintToInt(^u) 75 b = b[8:] 76 return b, v, nil 77 } 78 79 // EncodeUint appends the encoded value to slice b and returns the appended slice. 80 // EncodeUint guarantees that the encoded value is in ascending order for comparison. 81 func EncodeUint(b []byte, v uint64) []byte { 82 var data [8]byte 83 binary.BigEndian.PutUint64(data[:], v) 84 return append(b, data[:]...) 85 } 86 87 // EncodeUintDesc appends the encoded value to slice b and returns the appended slice. 88 // EncodeUintDesc guarantees that the encoded value is in descending order for comparison. 89 func EncodeUintDesc(b []byte, v uint64) []byte { 90 var data [8]byte 91 binary.BigEndian.PutUint64(data[:], ^v) 92 return append(b, data[:]...) 93 } 94 95 // DecodeUint decodes value encoded by EncodeUint before. 96 // It returns the leftover un-decoded slice, decoded value if no error. 97 func DecodeUint(b []byte) ([]byte, uint64, error) { 98 if len(b) < 8 { 99 return nil, 0, errors.New("insufficient bytes to decode value") 100 } 101 102 v := binary.BigEndian.Uint64(b[:8]) 103 b = b[8:] 104 return b, v, nil 105 } 106 107 // DecodeUintDesc decodes value encoded by EncodeInt before. 108 // It returns the leftover un-decoded slice, decoded value if no error. 109 func DecodeUintDesc(b []byte) ([]byte, uint64, error) { 110 if len(b) < 8 { 111 return nil, 0, errors.New("insufficient bytes to decode value") 112 } 113 114 data := b[:8] 115 v := binary.BigEndian.Uint64(data) 116 b = b[8:] 117 return b, ^v, nil 118 } 119 120 // EncodeVarint appends the encoded value to slice b and returns the appended slice. 121 // Note that the encoded result is not memcomparable. 122 func EncodeVarint(b []byte, v int64) []byte { 123 var data [binary.MaxVarintLen64]byte 124 n := binary.PutVarint(data[:], v) 125 return append(b, data[:n]...) 126 } 127 128 // DecodeVarint decodes value encoded by EncodeVarint before. 129 // It returns the leftover un-decoded slice, decoded value if no error. 130 func DecodeVarint(b []byte) ([]byte, int64, error) { 131 v, n := binary.Varint(b) 132 if n > 0 { 133 return b[n:], v, nil 134 } 135 if n < 0 { 136 return nil, 0, errors.New("value larger than 64 bits") 137 } 138 return nil, 0, errors.New("insufficient bytes to decode value") 139 } 140 141 // EncodeUvarint appends the encoded value to slice b and returns the appended slice. 142 // Note that the encoded result is not memcomparable. 143 func EncodeUvarint(b []byte, v uint64) []byte { 144 var data [binary.MaxVarintLen64]byte 145 n := binary.PutUvarint(data[:], v) 146 return append(b, data[:n]...) 147 } 148 149 // DecodeUvarint decodes value encoded by EncodeUvarint before. 150 // It returns the leftover un-decoded slice, decoded value if no error. 151 func DecodeUvarint(b []byte) ([]byte, uint64, error) { 152 v, n := binary.Uvarint(b) 153 if n > 0 { 154 return b[n:], v, nil 155 } 156 if n < 0 { 157 return nil, 0, errors.New("value larger than 64 bits") 158 } 159 return nil, 0, errors.New("insufficient bytes to decode value") 160 } 161 162 const ( 163 negativeTagEnd = 8 // negative tag is (negativeTagEnd - length). 164 positiveTagStart = 0xff - 8 // Positive tag is (positiveTagStart + length). 165 ) 166 167 // EncodeComparableVarint encodes an int64 to a mem-comparable bytes. 168 func EncodeComparableVarint(b []byte, v int64) []byte { 169 if v < 0 { 170 // All negative value has a tag byte prefix (negativeTagEnd - length). 171 // Smaller negative value encodes to more bytes, has smaller tag. 172 if v >= -0xff { 173 return append(b, negativeTagEnd-1, byte(v)) 174 } else if v >= -0xffff { 175 return append(b, negativeTagEnd-2, byte(v>>8), byte(v)) 176 } else if v >= -0xffffff { 177 return append(b, negativeTagEnd-3, byte(v>>16), byte(v>>8), byte(v)) 178 } else if v >= -0xffffffff { 179 return append(b, negativeTagEnd-4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 180 } else if v >= -0xffffffffff { 181 return append(b, negativeTagEnd-5, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 182 } else if v >= -0xffffffffffff { 183 return append(b, negativeTagEnd-6, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), 184 byte(v)) 185 } else if v >= -0xffffffffffffff { 186 return append(b, negativeTagEnd-7, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), 187 byte(v>>8), byte(v)) 188 } 189 return append(b, negativeTagEnd-8, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), 190 byte(v>>16), byte(v>>8), byte(v)) 191 } 192 return EncodeComparableUvarint(b, uint64(v)) 193 } 194 195 // EncodeComparableUvarint encodes uint64 into mem-comparable bytes. 196 func EncodeComparableUvarint(b []byte, v uint64) []byte { 197 // The first byte has 256 values, [0, 7] is reserved for negative tags, 198 // [248, 255] is reserved for larger positive tags, 199 // So we can causetstore value [0, 239] in a single byte. 200 // Values cannot be stored in single byte has a tag byte prefix (positiveTagStart+length). 201 // Larger value encodes to more bytes, has larger tag. 202 if v <= positiveTagStart-negativeTagEnd { 203 return append(b, byte(v)+negativeTagEnd) 204 } else if v <= 0xff { 205 return append(b, positiveTagStart+1, byte(v)) 206 } else if v <= 0xffff { 207 return append(b, positiveTagStart+2, byte(v>>8), byte(v)) 208 } else if v <= 0xffffff { 209 return append(b, positiveTagStart+3, byte(v>>16), byte(v>>8), byte(v)) 210 } else if v <= 0xffffffff { 211 return append(b, positiveTagStart+4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 212 } else if v <= 0xffffffffff { 213 return append(b, positiveTagStart+5, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 214 } else if v <= 0xffffffffffff { 215 return append(b, positiveTagStart+6, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), 216 byte(v)) 217 } else if v <= 0xffffffffffffff { 218 return append(b, positiveTagStart+7, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), 219 byte(v>>8), byte(v)) 220 } 221 return append(b, positiveTagStart+8, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), 222 byte(v>>16), byte(v>>8), byte(v)) 223 } 224 225 var ( 226 errDecodeInsufficient = errors.New("insufficient bytes to decode value") 227 errDecodeInvalid = errors.New("invalid bytes to decode value") 228 ) 229 230 // DecodeComparableUvarint decodes mem-comparable uvarint. 231 func DecodeComparableUvarint(b []byte) ([]byte, uint64, error) { 232 if len(b) == 0 { 233 return nil, 0, errDecodeInsufficient 234 } 235 first := b[0] 236 b = b[1:] 237 if first < negativeTagEnd { 238 return nil, 0, errors.Trace(errDecodeInvalid) 239 } 240 if first <= positiveTagStart { 241 return b, uint64(first) - negativeTagEnd, nil 242 } 243 length := int(first) - positiveTagStart 244 if len(b) < length { 245 return nil, 0, errors.Trace(errDecodeInsufficient) 246 } 247 var v uint64 248 for _, c := range b[:length] { 249 v = (v << 8) | uint64(c) 250 } 251 return b[length:], v, nil 252 } 253 254 // DecodeComparableVarint decodes mem-comparable varint. 255 func DecodeComparableVarint(b []byte) ([]byte, int64, error) { 256 if len(b) == 0 { 257 return nil, 0, errors.Trace(errDecodeInsufficient) 258 } 259 first := b[0] 260 if first >= negativeTagEnd && first <= positiveTagStart { 261 return b, int64(first) - negativeTagEnd, nil 262 } 263 b = b[1:] 264 var length int 265 var v uint64 266 if first < negativeTagEnd { 267 length = negativeTagEnd - int(first) 268 v = math.MaxUint64 // negative value has all bits on by default. 269 } else { 270 length = int(first) - positiveTagStart 271 } 272 if len(b) < length { 273 return nil, 0, errors.Trace(errDecodeInsufficient) 274 } 275 for _, c := range b[:length] { 276 v = (v << 8) | uint64(c) 277 } 278 if first > positiveTagStart && v > math.MaxInt64 { 279 return nil, 0, errors.Trace(errDecodeInvalid) 280 } else if first < negativeTagEnd && v <= math.MaxInt64 { 281 return nil, 0, errors.Trace(errDecodeInvalid) 282 } 283 return b[length:], int64(v), nil 284 }