mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 03:41:34 +00:00
bitfield: add basic bit field package
Strange as it is but I wasn't able to find any good bit field implementation. Most of them are limited to 64 bits, some allow for wider values (like https://github.com/emef/bitfield) but even they're not that efficient (using bytes instead of wider types). This this minimalistic thing.
This commit is contained in:
parent
b892db9976
commit
a6e25cffde
2 changed files with 106 additions and 0 deletions
64
pkg/util/bitfield/bitfield.go
Normal file
64
pkg/util/bitfield/bitfield.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Package bitfield provides a simple and efficient arbitrary size bit field implementation.
|
||||
It doesn't attempt to cover everything that could be done with bit fields,
|
||||
providing only things used by neo-go.
|
||||
*/
|
||||
package bitfield
|
||||
|
||||
// Field is a bit field represented as a slice of uint64 values.
|
||||
type Field []uint64
|
||||
|
||||
// Bits and bytes count in a basic element of Field.
|
||||
const elemBits = 64
|
||||
const elemBytes = 8
|
||||
|
||||
// New creates a new bit field of specified length. Actual field length
|
||||
// can be rounded to the next multiple of 64, so it's a responsibility
|
||||
// of the user to deal with that.
|
||||
func New(n int) Field {
|
||||
return make(Field, 1+(n-1)/elemBits)
|
||||
}
|
||||
|
||||
// Set sets one bit at specified offset. No bounds checking is done.
|
||||
func (f Field) Set(i int) {
|
||||
addr, offset := (i / elemBits), (i % elemBits)
|
||||
f[addr] |= (1 << offset)
|
||||
}
|
||||
|
||||
// IsSet returns true if the bit with specified offset is set.
|
||||
func (f Field) IsSet(i int) bool {
|
||||
addr, offset := (i / elemBits), (i % elemBits)
|
||||
return (f[addr] & (1 << offset)) != 0
|
||||
}
|
||||
|
||||
// Copy makes a copy of current Field.
|
||||
func (f Field) Copy() Field {
|
||||
fn := make(Field, len(f))
|
||||
copy(fn, f)
|
||||
return fn
|
||||
}
|
||||
|
||||
// And implements logical AND between f's and m's bits saving the result into f.
|
||||
func (f Field) And(m Field) {
|
||||
l := len(m)
|
||||
for i := range f {
|
||||
if i >= l {
|
||||
f[i] = 0
|
||||
continue
|
||||
}
|
||||
f[i] &= m[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Equals compares two Fields and returns true if they're equal.
|
||||
func (f Field) Equals(o Field) bool {
|
||||
if len(f) != len(o) {
|
||||
return false
|
||||
}
|
||||
for i := range f {
|
||||
if f[i] != o[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
42
pkg/util/bitfield/bitfield_test.go
Normal file
42
pkg/util/bitfield/bitfield_test.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package bitfield
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFields(t *testing.T) {
|
||||
a := New(128)
|
||||
b := New(128)
|
||||
a.Set(10)
|
||||
b.Set(10)
|
||||
a.Set(42)
|
||||
b.Set(42)
|
||||
a.Set(100)
|
||||
b.Set(100)
|
||||
require.True(t, a.IsSet(42))
|
||||
require.False(t, b.IsSet(43))
|
||||
|
||||
v := uint64(1<<10 | 1<<42)
|
||||
require.Equal(t, v, a[0])
|
||||
require.Equal(t, v, b[0])
|
||||
|
||||
require.True(t, a.Equals(b))
|
||||
|
||||
c := a.Copy()
|
||||
require.True(t, c.Equals(b))
|
||||
|
||||
z := New(128)
|
||||
c.And(a)
|
||||
require.True(t, c.Equals(b))
|
||||
c.And(z)
|
||||
require.True(t, c.Equals(z))
|
||||
|
||||
c = New(64)
|
||||
c[0] = a[0]
|
||||
require.False(t, c.Equals(a))
|
||||
|
||||
b.And(c)
|
||||
require.False(t, b.Equals(a))
|
||||
}
|
Loading…
Reference in a new issue