github.com/coocood/badger@v1.5.1-0.20200528065104-c02ac3616d04/surf/bits.go (about)

     1  package surf
     2  
     3  import (
     4  	"encoding/binary"
     5  	"math/bits"
     6  	"reflect"
     7  	"unsafe"
     8  )
     9  
    10  const wordSize = 64
    11  
    12  var endian = binary.LittleEndian
    13  
    14  //  A precomputed tabled containing the positions of the set bits in the binary
    15  //  representations of all 8-bit unsigned integers.
    16  //
    17  //  For i: [0, 256) ranging over all 8-bit unsigned integers and for j: [0, 8)
    18  //  ranging over all 0-based bit positions in an 8-bit unsigned integer, the
    19  //  table entry selectInByteLut[i][j] is the 0-based bit position of the j-th set
    20  //  bit in the binary representation of i, or 8 if it has fewer than j set bits.
    21  //
    22  //  Example: i: 17 (b00010001), j: [0, 8)
    23  //    selectInByteLut[b00010001][0] = 0
    24  //    selectInByteLut[b00010001][1] = 4
    25  //    selectInByteLut[b00010001][2] = 8
    26  //    ...
    27  //    selectInByteLut[b00010001][7] = 8
    28  var selectInByteLut [256][8]uint8
    29  
    30  func init() {
    31  	for i := 0; i < 256; i++ {
    32  		for j := 0; j < 8; j++ {
    33  			selectInByteLut[i][j] = selectInByte(i, j)
    34  		}
    35  	}
    36  }
    37  
    38  func findFirstSet(x int) int {
    39  	return bits.TrailingZeros64(uint64(x)) + 1
    40  }
    41  
    42  func selectInByte(i, j int) uint8 {
    43  	r := 0
    44  	for ; j != 0; j-- {
    45  		s := findFirstSet(i)
    46  		r += s
    47  		i >>= s
    48  	}
    49  	if i == 0 {
    50  		return 8
    51  	}
    52  	return uint8(r + findFirstSet(i) - 1)
    53  }
    54  
    55  func select64Broadword(x uint64, nth int64) int64 {
    56  	const (
    57  		onesStep4 = uint64(0x1111111111111111)
    58  		onesStep8 = uint64(0x0101010101010101)
    59  		msbsStep8 = uint64(0x80) * onesStep8
    60  	)
    61  
    62  	k := uint64(nth - 1)
    63  	s := x
    64  	s -= (s & (0xa * onesStep4)) >> 1
    65  	s = (s & (0x3 * onesStep4)) + ((s >> 2) & (0x3 * onesStep4))
    66  	s = (s + (s >> 4)) & (0xf * onesStep8)
    67  	byteSums := s * onesStep8
    68  
    69  	step8 := k * onesStep8
    70  	geqKStep8 := ((step8 | msbsStep8) - byteSums) & msbsStep8
    71  	place := bits.OnesCount64(geqKStep8) * 8
    72  	byteRank := k - (((byteSums << 8) >> place) & uint64(0xff))
    73  	return int64(place + int(selectInByteLut[(x>>place)&0xff][byteRank]))
    74  }
    75  
    76  func popcountBlock(bs []uint64, off, nbits uint32) uint32 {
    77  	if nbits == 0 {
    78  		return 0
    79  	}
    80  
    81  	lastWord := (nbits - 1) / wordSize
    82  	lastBits := (nbits - 1) % wordSize
    83  	var i, p uint32
    84  
    85  	for i = 0; i < lastWord; i++ {
    86  		p += uint32(bits.OnesCount64(bs[off+i]))
    87  	}
    88  	last := bs[off+lastWord] << (wordSize - 1 - lastBits)
    89  	return p + uint32(bits.OnesCount64(last))
    90  }
    91  
    92  func readBit(bs []uint64, pos uint32) bool {
    93  	wordOff := pos / wordSize
    94  	bitsOff := pos % wordSize
    95  	return bs[wordOff]&(uint64(1)<<bitsOff) != 0
    96  }
    97  
    98  func setBit(bs []uint64, pos uint32) {
    99  	wordOff := pos / wordSize
   100  	bitsOff := pos % wordSize
   101  	bs[wordOff] |= uint64(1) << bitsOff
   102  }
   103  
   104  func align(off int64) int64 {
   105  	return (off + 7) & ^int64(7)
   106  }
   107  
   108  func u64SliceToBytes(u []uint64) []byte {
   109  	if len(u) == 0 {
   110  		return nil
   111  	}
   112  	var b []byte
   113  	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
   114  	hdr.Len = len(u) * 8
   115  	hdr.Cap = hdr.Len
   116  	hdr.Data = uintptr(unsafe.Pointer(&u[0]))
   117  	return b
   118  }
   119  
   120  func bytesToU64Slice(b []byte) []uint64 {
   121  	if len(b) == 0 {
   122  		return nil
   123  	}
   124  	var u32s []uint64
   125  	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&u32s))
   126  	hdr.Len = len(b) / 8
   127  	hdr.Cap = hdr.Len
   128  	hdr.Data = uintptr(unsafe.Pointer(&b[0]))
   129  	return u32s
   130  }
   131  func u32SliceToBytes(u []uint32) []byte {
   132  	if len(u) == 0 {
   133  		return nil
   134  	}
   135  	var b []byte
   136  	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
   137  	hdr.Len = len(u) * 4
   138  	hdr.Cap = hdr.Len
   139  	hdr.Data = uintptr(unsafe.Pointer(&u[0]))
   140  	return b
   141  }
   142  
   143  func bytesToU32Slice(b []byte) []uint32 {
   144  	if len(b) == 0 {
   145  		return nil
   146  	}
   147  	var u32s []uint32
   148  	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&u32s))
   149  	hdr.Len = len(b) / 4
   150  	hdr.Cap = hdr.Len
   151  	hdr.Data = uintptr(unsafe.Pointer(&b[0]))
   152  	return u32s
   153  }