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  }