a flat bitset
This commit is contained in:
@ -1,58 +0,0 @@
|
||||
package ecs
|
||||
|
||||
type BitSetLike interface {
|
||||
Set(i Index) (old bool)
|
||||
Unset(i Index) (old bool)
|
||||
Contains(i Index) bool
|
||||
And(other BitSetLike) (result BitSetLike)
|
||||
AndNot(other BitSetLike) (result BitSetLike)
|
||||
Range(f func(eid Index))
|
||||
}
|
||||
|
||||
type BitSet struct {
|
||||
// TODO: this is not a BitSet, I'm just testing
|
||||
values map[Index]struct{}
|
||||
}
|
||||
|
||||
func (b BitSet) Set(i Index) (old bool) {
|
||||
_, old = b.values[i]
|
||||
b.values[i] = struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
func (b BitSet) Unset(i Index) (old bool) {
|
||||
_, old = b.values[i]
|
||||
delete(b.values, i)
|
||||
return
|
||||
}
|
||||
|
||||
func (b BitSet) Contains(i Index) bool {
|
||||
_, contains := b.values[i]
|
||||
return contains
|
||||
}
|
||||
|
||||
func (b BitSet) And(other BitSetLike) BitSetLike {
|
||||
result := BitSet{values: make(map[Index]struct{})}
|
||||
for i := range b.values {
|
||||
if other.Contains(i) {
|
||||
result.values[i] = struct{}{}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (b BitSet) AndNot(other BitSetLike) BitSetLike {
|
||||
result := BitSet{values: make(map[Index]struct{})}
|
||||
for i := range b.values {
|
||||
if !other.Contains(i) {
|
||||
result.values[i] = struct{}{}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (b BitSet) Range(f func(eid Index)) {
|
||||
for i := range b.values {
|
||||
f(i)
|
||||
}
|
||||
}
|
92
server/ecs/bitset.go
Normal file
92
server/ecs/bitset.go
Normal file
@ -0,0 +1,92 @@
|
||||
package ecs
|
||||
|
||||
import (
|
||||
"golang.org/x/exp/constraints"
|
||||
"math/bits"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const uintsize = uint(unsafe.Sizeof(BitSet{}.values[0]))
|
||||
|
||||
type BitSet struct {
|
||||
// TODO: this is not a BitSet, I'm just testing
|
||||
values []uint
|
||||
}
|
||||
|
||||
func (b *BitSet) Set(i Index) (old bool) {
|
||||
index := uint(i) / uintsize
|
||||
offset := uint(i) % uintsize
|
||||
if index >= uint(len(b.values)) {
|
||||
if index < uint(cap(b.values)) {
|
||||
b.values = b.values[:index]
|
||||
} else {
|
||||
newValues := make([]uint, index+1)
|
||||
copy(newValues, b.values)
|
||||
b.values = newValues
|
||||
}
|
||||
}
|
||||
v := &b.values[index]
|
||||
mask := uint(1 << offset)
|
||||
old = *v&mask != 0
|
||||
*v |= mask
|
||||
return
|
||||
}
|
||||
|
||||
func (b *BitSet) Unset(i Index) (old bool) {
|
||||
index := uint(i) / uintsize
|
||||
offset := uint(i) % uintsize
|
||||
if index < uint(len(b.values)) {
|
||||
v := &b.values[index]
|
||||
mask := uint(1 << offset)
|
||||
old = *v&mask != 0
|
||||
*v &= ^mask
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *BitSet) Contains(i Index) bool {
|
||||
index := uint(i) / uintsize
|
||||
offset := uint(i) % uintsize
|
||||
return index < uint(len(b.values)) && b.values[index]&(1<<offset) != 0
|
||||
}
|
||||
|
||||
func (b *BitSet) And(other *BitSet) *BitSet {
|
||||
result := BitSet{values: make([]uint, min(len(b.values), len(other.values)))}
|
||||
for i := range b.values {
|
||||
result.values[i] = b.values[i] & other.values[i]
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
func (b *BitSet) AndNot(other BitSet) *BitSet {
|
||||
result := BitSet{values: make([]uint, max(len(b.values), len(other.values)))}
|
||||
for i := range b.values {
|
||||
result.values[i] = b.values[i] & ^other.values[i]
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
func (b *BitSet) Range(f func(eid Index)) {
|
||||
for i, v := range b.values {
|
||||
base := int(unsafe.Sizeof(v)) * i
|
||||
for v != 0 {
|
||||
p := bits.TrailingZeros(v)
|
||||
f(Index(base + p))
|
||||
v ^= 1 << p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func max[T constraints.Integer](a, b T) T {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func min[T constraints.Integer](a, b T) T {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
28
server/ecs/bitset_test.go
Normal file
28
server/ecs/bitset_test.go
Normal file
@ -0,0 +1,28 @@
|
||||
package ecs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBitSet_And(t *testing.T) {
|
||||
var set1, set2 BitSet
|
||||
|
||||
set1.Set(1)
|
||||
set1.Set(3)
|
||||
set1.Set(40)
|
||||
|
||||
set2.Set(2)
|
||||
set2.Set(3)
|
||||
set2.Set(9)
|
||||
set2.Set(40)
|
||||
|
||||
var results []Index
|
||||
set1.And(&set2).Range(func(eid Index) {
|
||||
results = append(results, eid)
|
||||
})
|
||||
want := []Index{3, 40}
|
||||
if !reflect.DeepEqual(results, want) {
|
||||
t.Errorf("want %v, got: %v", want, results)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user