Update dependencies
This commit is contained in:
160
vendor/github.com/gaissmai/bart/internal/sparse/array.go
generated
vendored
Normal file
160
vendor/github.com/gaissmai/bart/internal/sparse/array.go
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
// Copyright (c) 2024 Karl Gaissmaier
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// package sparse implements a generic sparse array
|
||||
// with popcount compression.
|
||||
package sparse
|
||||
|
||||
import (
|
||||
"github.com/gaissmai/bart/internal/bitset"
|
||||
)
|
||||
|
||||
// Array, a generic implementation of a sparse array
|
||||
// with popcount compression and payload T.
|
||||
type Array[T any] struct {
|
||||
bitset.BitSet
|
||||
Items []T
|
||||
}
|
||||
|
||||
// Get the value at i from sparse array.
|
||||
//
|
||||
// example: Array.Get(5) -> Array.Items[1]
|
||||
//
|
||||
// ⬇
|
||||
// BitSet: [0|0|1|0|0|1|0|1|...] <- 3 bits set
|
||||
// Items: [*|*|*] <- len(Items) = 3
|
||||
// ⬆
|
||||
//
|
||||
// BitSet.Test(5): true
|
||||
// BitSet.popcount(5): 2, for interval [0,5]
|
||||
// BitSet.Rank0(5): 1, equal popcount(5)-1
|
||||
func (s *Array[T]) Get(i uint) (value T, ok bool) {
|
||||
if s.Test(i) {
|
||||
return s.Items[s.Rank0(i)], true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MustGet, use it only after a successful test
|
||||
// or the behavior is undefined, maybe it panics.
|
||||
func (s *Array[T]) MustGet(i uint) T {
|
||||
return s.Items[s.Rank0(i)]
|
||||
}
|
||||
|
||||
// UpdateAt or set the value at i via callback. The new value is returned
|
||||
// and true if the value was already present.
|
||||
func (s *Array[T]) UpdateAt(i uint, cb func(T, bool) T) (newValue T, wasPresent bool) {
|
||||
var rank0 int
|
||||
|
||||
// if already set, get current value
|
||||
var oldValue T
|
||||
|
||||
if wasPresent = s.Test(i); wasPresent {
|
||||
rank0 = s.Rank0(i)
|
||||
oldValue = s.Items[rank0]
|
||||
}
|
||||
|
||||
// callback function to get updated or new value
|
||||
newValue = cb(oldValue, wasPresent)
|
||||
|
||||
// already set, update and return value
|
||||
if wasPresent {
|
||||
s.Items[rank0] = newValue
|
||||
|
||||
return newValue, wasPresent
|
||||
}
|
||||
|
||||
// new value, insert into bitset ...
|
||||
s.BitSet = s.Set(i)
|
||||
|
||||
// bitset has changed, recalc rank
|
||||
rank0 = s.Rank0(i)
|
||||
|
||||
// ... and insert value into slice
|
||||
s.insertItem(rank0, newValue)
|
||||
|
||||
return newValue, wasPresent
|
||||
}
|
||||
|
||||
// Len returns the number of items in sparse array.
|
||||
func (s *Array[T]) Len() int {
|
||||
return len(s.Items)
|
||||
}
|
||||
|
||||
// Copy returns a shallow copy of the Array.
|
||||
// The elements are copied using assignment, this is no deep clone.
|
||||
func (s *Array[T]) Copy() *Array[T] {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Array[T]{
|
||||
BitSet: s.BitSet.Clone(),
|
||||
Items: append(s.Items[:0:0], s.Items...),
|
||||
}
|
||||
}
|
||||
|
||||
// InsertAt a value at i into the sparse array.
|
||||
// If the value already exists, overwrite it with val and return true.
|
||||
func (s *Array[T]) InsertAt(i uint, value T) (exists bool) {
|
||||
// slot exists, overwrite value
|
||||
if s.Len() != 0 && s.Test(i) {
|
||||
s.Items[s.Rank0(i)] = value
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// new, insert into bitset ...
|
||||
s.BitSet = s.Set(i)
|
||||
|
||||
// ... and slice
|
||||
s.insertItem(s.Rank0(i), value)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// DeleteAt a value at i from the sparse array, zeroes the tail.
|
||||
func (s *Array[T]) DeleteAt(i uint) (value T, exists bool) {
|
||||
if s.Len() == 0 || !s.Test(i) {
|
||||
return
|
||||
}
|
||||
|
||||
rank0 := s.Rank0(i)
|
||||
value = s.Items[rank0]
|
||||
|
||||
// delete from slice
|
||||
s.deleteItem(rank0)
|
||||
|
||||
// delete from bitset
|
||||
s.BitSet = s.Clear(i)
|
||||
|
||||
return value, true
|
||||
}
|
||||
|
||||
// insertItem inserts the item at index i, shift the rest one pos right
|
||||
//
|
||||
// It panics if i is out of range.
|
||||
func (s *Array[T]) insertItem(i int, item T) {
|
||||
if len(s.Items) < cap(s.Items) {
|
||||
s.Items = s.Items[:len(s.Items)+1] // fast resize, no alloc
|
||||
} else {
|
||||
var zero T
|
||||
s.Items = append(s.Items, zero) // append one item, mostly enlarge cap by more than one item
|
||||
}
|
||||
|
||||
copy(s.Items[i+1:], s.Items[i:])
|
||||
s.Items[i] = item
|
||||
}
|
||||
|
||||
// deleteItem at index i, shift the rest one pos left and clears the tail item
|
||||
//
|
||||
// It panics if i is out of range.
|
||||
func (s *Array[T]) deleteItem(i int) {
|
||||
var zero T
|
||||
|
||||
nl := len(s.Items) - 1 // new len
|
||||
copy(s.Items[i:], s.Items[i+1:]) // overwrite item at [i]
|
||||
|
||||
s.Items[nl] = zero // clear the tail item
|
||||
s.Items = s.Items[:nl] // new len, keep cap is unchanged
|
||||
}
|
||||
Reference in New Issue
Block a user