Upstream kelindar/bitmap state of the touched files before 65a39020a6
This commit is contained in:
1 parent
4c67b4458d
commit
4b1c980512
1 file changed
+252
@@ -0,0 +1,252 @@
|
||||
// Copyright (c) Roman Atachiants and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
package bitmap
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
"unsafe"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
isUnsupported = iota
|
||||
isAccelerated
|
||||
isAVX512
|
||||
)
|
||||
|
||||
// Hardware contains the resolved acceleration level
|
||||
var hardware = levelOf(cpuid.CPU)
|
||||
|
||||
// levelOf returns the hardware acceleration level
|
||||
func levelOf(cpu cpuid.CPUInfo) int {
|
||||
switch {
|
||||
case cpu.Supports(cpuid.AVX512F) && cpu.Supports(cpuid.AVX512DQ) && cpu.Supports(cpuid.AVX512BW):
|
||||
return isAVX512
|
||||
case cpu.Supports(cpuid.AVX2) && cpu.Supports(cpuid.FMA3):
|
||||
return isAccelerated
|
||||
case cpu.Supports(cpuid.ASIMD):
|
||||
return isAccelerated
|
||||
default:
|
||||
return isUnsupported
|
||||
}
|
||||
}
|
||||
|
||||
// Bitmap represents a scalar-backed bitmap index
|
||||
type Bitmap []uint64
|
||||
|
||||
// Set sets the bit x in the bitmap and grows it if necessary.
|
||||
func (dst *Bitmap) Set(x uint32) {
|
||||
blkAt := int(x >> 6)
|
||||
bitAt := int(x % 64)
|
||||
if size := len(*dst); blkAt >= size {
|
||||
dst.grow(blkAt)
|
||||
}
|
||||
|
||||
(*dst)[blkAt] |= (1 << bitAt)
|
||||
}
|
||||
|
||||
// Remove removes the bit x from the bitmap, but does not shrink it.
|
||||
func (dst *Bitmap) Remove(x uint32) {
|
||||
if blkAt := int(x >> 6); blkAt < len(*dst) {
|
||||
bitAt := int(x % 64)
|
||||
(*dst)[blkAt] &^= (1 << bitAt)
|
||||
}
|
||||
}
|
||||
|
||||
// Contains checks whether a value is contained in the bitmap or not.
|
||||
func (dst Bitmap) Contains(x uint32) bool {
|
||||
blkAt := int(x >> 6)
|
||||
if size := len(dst); blkAt >= size {
|
||||
return false
|
||||
}
|
||||
|
||||
bitAt := int(x % 64)
|
||||
return (dst[blkAt] & (1 << bitAt)) > 0
|
||||
}
|
||||
|
||||
// Ones sets the entire bitmap to one.
|
||||
func (dst Bitmap) Ones() {
|
||||
for i := 0; i < len(dst); i++ {
|
||||
dst[i] = 0xffffffffffffffff
|
||||
}
|
||||
}
|
||||
|
||||
// Min get the smallest value stored in this bitmap, assuming the bitmap is not empty.
|
||||
func (dst Bitmap) Min() (uint32, bool) {
|
||||
for blkAt, blk := range dst {
|
||||
if blk != 0x0 {
|
||||
return uint32(blkAt<<6 + bits.TrailingZeros64(blk)), true
|
||||
}
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Max get the largest value stored in this bitmap, assuming the bitmap is not empty.
|
||||
func (dst Bitmap) Max() (uint32, bool) {
|
||||
var blk uint64
|
||||
for blkAt := len(dst) - 1; blkAt >= 0; blkAt-- {
|
||||
if blk = dst[blkAt]; blk != 0x0 {
|
||||
return uint32(blkAt<<6 + (63 - bits.LeadingZeros64(blk))), true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// MinZero finds the first zero bit and returns its index, assuming the bitmap is not empty.
|
||||
func (dst Bitmap) MinZero() (uint32, bool) {
|
||||
for blkAt, blk := range dst {
|
||||
if blk != 0xffffffffffffffff {
|
||||
return uint32(blkAt<<6 + bits.TrailingZeros64(^blk)), true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// MaxZero get the last zero bit and return its index, assuming bitmap is not empty
|
||||
func (dst Bitmap) MaxZero() (uint32, bool) {
|
||||
var blk uint64
|
||||
for blkAt := len(dst) - 1; blkAt >= 0; blkAt-- {
|
||||
if blk = dst[blkAt]; blk != 0xffffffffffffffff {
|
||||
return uint32(blkAt<<6 + (63 - bits.LeadingZeros64(^blk))), true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// CountTo counts the number of elements in the bitmap up until the specified index. If until
|
||||
// is math.MaxUint32, it will return the count. The count is non-inclusive of the index.
|
||||
func (dst Bitmap) CountTo(until uint32) int {
|
||||
if len(dst) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if maxUntil := uint32(len(dst) << 6); until > maxUntil {
|
||||
until = maxUntil
|
||||
}
|
||||
|
||||
// Figure out the index of the last block
|
||||
blkUntil := until >> 6
|
||||
bitUntil := until % 64
|
||||
|
||||
// Count the bits right before the last block
|
||||
sum := dst[:blkUntil].Count()
|
||||
|
||||
// Count the bits at the end
|
||||
if bitUntil > 0 {
|
||||
sum += bits.OnesCount64(dst[blkUntil] << (64 - uint64(bitUntil)))
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// Grow grows the bitmap size until we reach the desired bit.
|
||||
func (dst *Bitmap) Grow(desiredBit uint32) {
|
||||
dst.grow(int(desiredBit >> 6))
|
||||
}
|
||||
|
||||
// grow grows the size of the bitmap until we reach the desired block offset
|
||||
func (dst *Bitmap) grow(blkAt int) {
|
||||
if len(*dst) > blkAt {
|
||||
return
|
||||
}
|
||||
|
||||
// If there's space, resize the slice without copying.
|
||||
if cap(*dst) > blkAt {
|
||||
*dst = (*dst)[:blkAt+1]
|
||||
return
|
||||
}
|
||||
|
||||
old := *dst
|
||||
*dst = make(Bitmap, blkAt+1, resize(cap(old), blkAt+1))
|
||||
copy(*dst, old)
|
||||
}
|
||||
|
||||
// shrink shrinks the size of the bitmap and resets to zero
|
||||
func (dst *Bitmap) shrink(length int) {
|
||||
until := len(*dst)
|
||||
for i := length; i < until; i++ {
|
||||
(*dst)[i] = 0
|
||||
}
|
||||
|
||||
// Trim without reallocating
|
||||
*dst = (*dst)[:length]
|
||||
}
|
||||
|
||||
// minlen calculates the minimum length of all of the bitmaps
|
||||
func minlen(a, b Bitmap, extra []Bitmap) int {
|
||||
size := minint(len(a), len(b))
|
||||
for _, v := range extra {
|
||||
if m := minint(len(a), len(v)); m < size {
|
||||
size = m
|
||||
}
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// maxlen calculates the maximum length of all of the bitmaps
|
||||
func maxlen(a, b Bitmap, extra []Bitmap) int {
|
||||
size := maxint(len(a), len(b))
|
||||
for _, v := range extra {
|
||||
if m := maxint(len(a), len(v)); m > size {
|
||||
size = m
|
||||
}
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// maxint returns a maximum of two integers without branches.
|
||||
func maxint(v1, v2 int) int {
|
||||
return v1 - ((v1 - v2) & ((v1 - v2) >> 31))
|
||||
}
|
||||
|
||||
// minint returns a minimum of two integers without branches.
|
||||
func minint(v1, v2 int) int {
|
||||
return v2 + ((v1 - v2) & ((v1 - v2) >> 31))
|
||||
}
|
||||
|
||||
// resize calculates the new required capacity and a new index
|
||||
func resize(capacity, v int) int {
|
||||
const threshold = 256
|
||||
if v < threshold {
|
||||
v |= v >> 1
|
||||
v |= v >> 2
|
||||
v |= v >> 4
|
||||
v |= v >> 8
|
||||
v |= v >> 16
|
||||
v++
|
||||
return int(v)
|
||||
}
|
||||
|
||||
if capacity < threshold {
|
||||
capacity = threshold
|
||||
}
|
||||
|
||||
for 0 < capacity && capacity < (v+1) {
|
||||
capacity += (capacity + 3*threshold) / 4
|
||||
}
|
||||
return capacity
|
||||
}
|
||||
|
||||
// dimensionsOf returns a uint64 containing the packed dimensions
|
||||
func dimensionsOf(n, m int) uint64 {
|
||||
return uint64(n) | (uint64(m) << 32)
|
||||
}
|
||||
|
||||
// pointersOf returns a pointer to an array containing pointers to the
|
||||
// first element of each bitmap and the maximum length of all bitmaps
|
||||
func pointersOf(other Bitmap, extra []Bitmap) (unsafe.Pointer, int) {
|
||||
out := make([]unsafe.Pointer, len(extra)+1)
|
||||
out[0] = unsafe.Pointer(&other[0])
|
||||
max := 0
|
||||
|
||||
for i := range extra {
|
||||
out[i+1] = unsafe.Pointer(&extra[i][0])
|
||||
if len(extra[i]) > max {
|
||||
max = len(extra[i])
|
||||
}
|
||||
}
|
||||
|
||||
return unsafe.Pointer(&out[0]), max
|
||||
}
|
||||
Reference in new issue
Block a user