github.com/zeebo/mon@v0.0.0-20211012163247-13d39bdb54fa/floathist/varint.go (about) 1 package floathist 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math/bits" 7 8 "github.com/zeebo/mon/internal/buffer" 9 ) 10 11 // 12 // varint support 13 // 14 15 func varintAppend(dst *[9]byte, val uint64) (nbytes uintptr) { 16 nbytes = 575*uintptr(bits.Len64(val))/4096 + 1 17 18 if nbytes < 9 { 19 enc := val<<nbytes + 1<<((nbytes-1)&63) - 1 20 *(*uint64)(ptr(&dst[0])) = enc // annoying 21 return 22 } 23 24 dst[0] = 0xff 25 *(*uint64)(ptr(&dst[1])) = val // annoying 26 return 27 } 28 29 func fastVarintConsume(src *[9]byte) (nbytes uintptr, dec uint64) { 30 nbytes = uintptr(bits.TrailingZeros8(^src[0])) + 1 31 32 if nbytes < 9 { 33 dec = *(*uint64)(ptr(&src[0])) >> nbytes // annoying 34 dec &= 1<<((8*nbytes-nbytes)&63) - 1 35 return 36 } 37 38 dec = *(*uint64)(ptr(&src[1])) // annoying 39 return 40 } 41 42 func safeVarintConsume(buf buffer.T) (uint64, buffer.T, bool) { 43 le := binary.LittleEndian 44 45 rem := buf.Remaining() 46 if rem == 0 { 47 return 0, buf, false 48 } 49 50 // slow path: can't create or use any pointers past the end of the buf 51 out := uint64(*buf.Front()) 52 nbytes := uint8(bits.TrailingZeros8(^uint8(out)) + 1) 53 out >>= nbytes 54 55 if uintptr(nbytes) > rem { 56 return 0, buf, false 57 } 58 59 switch nbytes { 60 case 9: 61 out |= le.Uint64((*[8]byte)(buf.At(1))[:]) 62 case 8: 63 out |= uint64(le.Uint32((*[4]byte)(buf.At(1))[:])) 64 out |= uint64(le.Uint32((*[4]byte)(buf.At(4))[:])) << 24 65 case 7: 66 out |= uint64(le.Uint32((*[4]byte)(buf.At(1))[:])) << 1 67 out |= uint64(le.Uint16((*[2]byte)(buf.At(5))[:])) << 33 68 case 6: 69 out |= uint64(le.Uint32((*[4]byte)(buf.At(1))[:])) << 2 70 out |= uint64(*(*byte)(buf.At(5))) << 34 71 case 5: 72 out |= uint64(le.Uint32((*[4]byte)(buf.At(1))[:])) << 3 73 case 4: 74 out |= uint64(le.Uint16((*[2]byte)(buf.At(1))[:])) << 4 75 out |= uint64(*(*byte)(buf.At(3))) << 20 76 case 3: 77 out |= uint64(le.Uint16((*[2]byte)(buf.At(1))[:])) << 5 78 case 2: 79 out |= uint64(*(*byte)(buf.At(1))) << 6 80 } 81 82 return out, buf.Advance(uintptr(nbytes)), true 83 } 84 85 // 86 // we use direct uint64 writes because the inliner hates binary.LittleEndian :( 87 // 88 89 func init() { 90 var b1, b2 [9]byte 91 binary.LittleEndian.PutUint64(b1[1:9], 0x0102030405060708) 92 *(*uint64)(ptr(&b2[1])) = 0x0102030405060708 93 if b1 != b2 { 94 panic(fmt.Sprintf("not on little-endian machine: %x != %x", b1, b2)) 95 } 96 }