github.com/zeebo/mon@v0.0.0-20211012163247-13d39bdb54fa/inthist/varint.go (about) 1 package inthist 2 3 import ( 4 "encoding/binary" 5 "math/bits" 6 7 "github.com/zeebo/mon/internal/buffer" 8 ) 9 10 // 11 // varint support 12 // 13 14 func varintStats(val uint32) (nbytes uint8, enc uint64) { 15 if val == 0 { 16 return 1, 0 17 } 18 nbytes = (uint8(bits.Len32(val)) - 1) / 7 19 return nbytes + 1, (2*uint64(val)+1)<<(nbytes%64) - 1 20 } 21 22 func fastVarintConsume(val uint64) (nbytes uint8, dec uint32) { 23 nbytes = uint8(bits.TrailingZeros8(^uint8(val)) + 1) 24 val <<= (64 - 8*nbytes) % 64 25 val >>= (64 - 7*nbytes) % 64 26 return nbytes, uint32(val) 27 } 28 29 func safeVarintConsume(buf buffer.T) (uint32, buffer.T, bool) { 30 le := binary.LittleEndian 31 32 rem := buf.Remaining() 33 if rem == 0 { 34 return 0, buf, false 35 } 36 37 // slow path: can't create or use any pointers past the end of the buf 38 out := uint32(*(*byte)(buf.At(0))) 39 nbytes := uint8(bits.TrailingZeros8(^uint8(out))+1) % 8 40 out >>= nbytes 41 42 if uintptr(nbytes) > rem { 43 return 0, buf, false 44 } 45 46 switch nbytes { 47 case 5: 48 out |= le.Uint32((*[4]byte)(buf.At(1))[:]) << 3 49 case 4: 50 out |= uint32(le.Uint16((*[2]byte)(buf.At(1))[:])) << 4 51 out |= uint32(*(*byte)(buf.At(3))) << 20 52 case 3: 53 out |= uint32(le.Uint16((*[2]byte)(buf.At(1))[:])) << 5 54 case 2: 55 out |= uint32(*(*byte)(buf.At(1))) << 6 56 } 57 58 return out, buf.Advance(uintptr(nbytes)), true 59 }