github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekamath/bitset_private.go (about) 1 // Copyright © 2021. All rights reserved. 2 // Author: Ilya Stroy. 3 // Contacts: iyuryevich@pm.me, https://github.com/qioalice 4 // License: https://opensource.org/licenses/MIT 5 6 package ekamath 7 8 import ( 9 "math/bits" 10 "reflect" 11 "unsafe" 12 ) 13 14 //goland:noinspection GoSnakeCaseUsage 15 const ( 16 _BITSET_MINIMUM_CAPACITY = 128 17 _BITSET_MINIMUM_CAPACITY_BYTES = _BITSET_MINIMUM_CAPACITY >> 3 // 16 18 19 _BITSET_BITS_PER_CHUNK = bits.UintSize // 32 or 64 20 _BITSET_BYTES_PER_CHUNK = _BITSET_BITS_PER_CHUNK >> 3 21 22 _BITSET_CHUNK_OFFSET = 4 + (_BITSET_BITS_PER_CHUNK >> 5) // 5 or 6 23 _BITSET_CHUNK_MASK = _BITSET_BITS_PER_CHUNK - 1 // 31 or 63 24 25 _BITSET_MASK_FULL = ^uint(0) 26 ) 27 28 // Returns a chunk number of the current BitSet. 29 func (bs *BitSet) chunkSize() uint { 30 return uint(len(bs.bs)) 31 } 32 33 // Returns a chunk capacity of the current BitSet. 34 func (bs *BitSet) chunkCapacity() uint { 35 return uint(cap(bs.bs)) 36 } 37 38 // Reports whether BitSet can contain a bit with provided index. 39 // It includes IsValid() call, so you don't need to call it explicitly. 40 func (bs *BitSet) isValidIdx(idx uint, lowerBound uint, skipUpperBoundCheck bool) bool { 41 return bs.IsValid() && idx >= lowerBound && 42 (skipUpperBoundCheck || bsChunksForBits(idx+1) <= bs.chunkSize()) 43 } 44 45 // Returns a next upped or downed bit index depends on `f`. 46 func (bs *BitSet) nextGeneric(idx uint, isDown bool) (uint, bool) { 47 48 chunk, offset := uint(0), uint(0) 49 if idx != 0 { 50 chunk, offset = bsFromIdx(idx) 51 } 52 53 v := bs.bs[chunk] >> offset 54 if isDown { 55 v = ^v 56 } 57 if n := bs1stUp(v); n < _BITSET_BITS_PER_CHUNK-offset { 58 return bsToIdx(chunk, offset+n) + 1, true 59 } 60 61 for i, n := chunk+1, uint(len(bs.bs)); i < n; i++ { 62 v := bs.bs[i] 63 if isDown { 64 v = ^v 65 } 66 if n := bs1stUp(v); n != _BITSET_BITS_PER_CHUNK { 67 return bsToIdx(i, n) + 1, true 68 } 69 } 70 71 return idx, false 72 } 73 74 // Returns a prev upped or downed bit index depends on `f1`, `f2`. 75 func (bs *BitSet) prevGeneric(idx uint, isDown bool) (uint, bool) { 76 77 chunk, offset := bsFromIdx(idx) 78 79 v := bs.bs[chunk] << (_BITSET_BITS_PER_CHUNK - offset + 1) 80 if isDown { 81 v = ^v 82 } 83 if n := bsLastUp(v); n < _BITSET_BITS_PER_CHUNK-offset { 84 return bsToIdx(chunk, offset-n-1), true 85 } 86 87 for i := int(chunk) - 1; i >= 0; i-- { 88 v := bs.bs[i] 89 if isDown { 90 v = ^v 91 } 92 if n := bsLastUp(v); n != _BITSET_BITS_PER_CHUNK { 93 return bsToIdx(uint(i), _BITSET_BITS_PER_CHUNK-n), true 94 } 95 } 96 97 return idx, false 98 } 99 100 // Returns a number of bits that are upped (set to 1). 101 func bsCountOnes(n uint) uint { 102 return uint(bits.OnesCount(n)) 103 } 104 105 // Returns a minimum number of chunks that is required to store `n` bits. 106 func bsChunksForBits(n uint) uint { 107 108 c := n >> _BITSET_CHUNK_OFFSET 109 110 if n&_BITSET_CHUNK_MASK != 0 { 111 c += 1 112 } 113 114 return c 115 } 116 117 // Returns a byte number (starting from 0) and bit offset (starting from 0) 118 // for the provided index. 119 func bsFromIdx(n uint) (chunk, offset uint) { 120 return n >> _BITSET_CHUNK_OFFSET, n & _BITSET_CHUNK_MASK 121 } 122 123 // Returns an index inside a bitset (starting from 1) 124 // for the provided chunk (byte number, starting from 0) 125 // and offset (bit offset, starting from 0). 126 func bsToIdx(chunk, offset uint) uint { 127 return (chunk << _BITSET_CHUNK_OFFSET) | (offset & _BITSET_CHUNK_MASK) 128 } 129 130 // Returns an index (starting from 0) of 1st upped (set to 1) bit. 131 // If there's no such bits, _BITSET_BITS_PER_CHUNK is returned. 132 func bs1stUp(n uint) uint { 133 return uint(bits.TrailingZeros(n)) 134 } 135 136 // Returns an index (starting from 0) of 1st downed (set to 0) bit. 137 // If there's no such bits, _BITSET_BITS_PER_CHUNK is returned. 138 func bsLastUp(n uint) uint { 139 return uint(bits.LeadingZeros(n)) 140 } 141 142 // Returns a []byte that has the same bytes that provided BitSet's underlying data. 143 // 144 // **UNSAFE** 145 // Highly unsafe! User MUST NOT modify returned object. 146 func bsUnsafeToBytesSlice(bsData []uint) []byte { 147 148 var ret []byte 149 150 shOrig := (*reflect.SliceHeader)(unsafe.Pointer(&bsData)) 151 shRet := (*reflect.SliceHeader)(unsafe.Pointer(&ret)) 152 153 shRet.Data = shOrig.Data 154 shRet.Len = shOrig.Len * _BITSET_BYTES_PER_CHUNK 155 shRet.Cap = shOrig.Cap * _BITSET_BYTES_PER_CHUNK 156 157 return ret 158 } 159 160 // Returns a BitSet's underlying data that has the same bytes as provided. 161 // 162 // **UNSAFE** 163 // Highly unsafe! User MUST NOT use `data` object after passing here. 164 // 165 // WARNING! 166 // The length of `data` must be compatible with the bytes consumption 167 // of underlying chunk slice. 168 func bsUnsafeFromBytesSlice(data []byte) []uint { 169 170 var ret []uint 171 172 shOrig := (*reflect.SliceHeader)(unsafe.Pointer(&data)) 173 shRet := (*reflect.SliceHeader)(unsafe.Pointer(&ret)) 174 175 shRet.Data = shOrig.Data 176 shRet.Len = shOrig.Len / _BITSET_BYTES_PER_CHUNK 177 shRet.Cap = shOrig.Cap / _BITSET_BYTES_PER_CHUNK 178 179 return ret 180 }