From 4b1c980512c9b8411a0bbdbadec78cacc7a9608c Mon Sep 17 00:00:00 2001 From: upstream Date: Wed, 23 Sep 2026 06:12:58 +0200 Subject: [PATCH] Upstream kelindar/bitmap state of the touched files before 65a39020a6 --- bitmap.go | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 bitmap.go diff --git a/bitmap.go b/bitmap.go new file mode 100644 index 0000000..d2276fb --- /dev/null +++ b/bitmap.go @@ -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 +}