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 }