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  }