bf: add a module implementing operations with bit arrays (#1049)

pull/1056/head
Vitalie Ciubotaru 2019-07-10 04:11:09 +09:00 committed by Alexander Medvednikov
parent 26af513e1b
commit c4fcfcec88
2 changed files with 224 additions and 0 deletions

179
vlib/bf/bf.v 100644
View File

@ -0,0 +1,179 @@
module bf
struct BitField {
mut:
size int
//field *u32
field []u32
}
/* helper functions */
const (
SLOT_SIZE = 32
)
fn bitmask(bitnr int) u32 {
return u32(1 << (bitnr % SLOT_SIZE))
}
fn bitslot(size int) int {
return size / SLOT_SIZE
}
fn bitget(instance BitField, bitnr int) int {
return (instance.field[bitslot(bitnr)] >> u32(bitnr % SLOT_SIZE)) & 1
}
fn bitset(instance BitField, bitnr int) {
instance.field[bitslot(bitnr)] = instance.field[bitslot(bitnr)] | bitmask(bitnr)
}
fn bitclear(instance BitField, bitnr int) {
instance.field[bitslot(bitnr)] = instance.field[bitslot(bitnr)] & ~bitmask(bitnr)
}
fn bittoggle(instance BitField, bitnr int) {
instance.field[bitslot(bitnr)] = instance.field[bitslot(bitnr)] ^ bitmask(bitnr)
}
/*
#define BITTEST(a, b) ((a)->field[BITSLOT(b)] & BITMASK(b))
*/
fn min(input1 int, input2 int) int {
if input1 < input2 {
return input1
}
else {
return input2
}
}
fn bitnslots(length int) int {
return (length - 1) / SLOT_SIZE + 1
}
fn cleartail(instance BitField) {
tail := instance.size % SLOT_SIZE
if tail != 0 {
/* create a mask for the tail */
mask := u32((1 << tail) - 1)
/* clear the extra bits */
instance.field[bitnslots(instance.size) - 1] = instance.field[bitnslots(instance.size) - 1] & mask
}
}
/* public functions */
pub fn new(size int) BitField {
output := BitField{
size: size
//field: *u32(calloc(bitnslots(size) * SLOT_SIZE / 8))
field: [u32(0); bitnslots(size)]
}
return output
}
/*
pub fn del(instance *BitField) {
free(instance.field)
free(instance)
}
*/
pub fn (instance BitField) getbit(bitnr int) int {
if bitnr >= instance.size {return 0}
return bitget(instance, bitnr)
}
pub fn (instance mut BitField) setbit(bitnr int) {
if bitnr >= instance.size {return}
bitset(instance, bitnr)
}
pub fn (instance mut BitField) clearbit(bitnr int) {
if bitnr >= instance.size {return}
bitclear(instance, bitnr)
}
pub fn (instance mut BitField) togglebit(bitnr int) {
if bitnr >= instance.size {return}
bittoggle(instance, bitnr)
}
pub fn bfand(input1 BitField, input2 BitField) BitField {
size := min(input1.size, input2.size)
bitnslots := bitnslots(size)
mut output := new(size)
mut i := 0
for i < bitnslots {
output.field[i] = input1.field[i] & input2.field[i]
i++
}
cleartail(output)
return output
}
pub fn bfnot(input BitField) BitField {
size := input.size
bitnslots := bitnslots(size)
mut output := new(size)
mut i := 0
for i < bitnslots {
output.field[i] = ~input.field[i]
i++
}
cleartail(output)
return output
}
pub fn bfor(input1 BitField, input2 BitField) BitField {
size := min(input1.size, input2.size)
bitnslots := bitnslots(size)
mut output := new(size)
mut i := 0
for i < bitnslots {
output.field[i] = input1.field[i] | input2.field[i]
i++
}
cleartail(output)
return output
}
pub fn bfxor(input1 BitField, input2 BitField) BitField {
size := min(input1.size, input2.size)
bitnslots := bitnslots(size)
mut output := new(size)
mut i := 0
for i < bitnslots {
output.field[i] = input1.field[i] ^ input2.field[i]
i++
}
cleartail(output)
return output
}
pub fn print(instance BitField) {
mut i := 0
for i < instance.size {
if instance.getbit(i) == 1 {
print('1')
}
else {
print('0')
}
i++
}
}
pub fn (instance BitField) getsize() int {
return instance.size
}
pub fn clone(input BitField) BitField {
bitnslots := bitnslots(input.size)
mut output := new(input.size)
mut i := 0
for i < bitnslots {
output.field[i] = input.field[i]
i++
}
return output
}

45
vlib/bf/bf_test.v 100644
View File

@ -0,0 +1,45 @@
import bf
import rand
fn test_bf_new_size() {
instance := bf.new(5)
assert instance.getsize() == 5
}
fn test_bf_set_clear_toggle_get() {
mut instance := bf.new(5)
instance.setbit(4)
assert instance.getbit(4) == 1
instance.clearbit(4)
assert instance.getbit(4) == 0
instance.togglebit(4)
assert instance.getbit(4) == 1
}
fn test_bf_and_not_or_xor() {
rand.seed()
len := 80
mut input1 := bf.new(len)
mut input2 := bf.new(len)
mut i := 0
for i < len {
if rand.next(2) == 1 {
input1.setbit(i)
}
if rand.next(2) == 1{
input2.setbit(i)
}
i++
}
output1 := bf.bfxor(input1, input2)
bfand := bf.bfand(input1, input2)
bfor := bf.bfor(input1, input2)
bfnot := bf.bfnot(bfand)
output2 := bf.bfand(bfor, bfnot)
mut result := 1
for i < len {
if output1.getbit(i) != output2.getbit(i) {result = 0}
}
assert result == 1
}