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  }