diff --git a/vlib/bf/bf.v b/vlib/bf/bf.v new file mode 100644 index 0000000000..585a1be24c --- /dev/null +++ b/vlib/bf/bf.v @@ -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 +} \ No newline at end of file diff --git a/vlib/bf/bf_test.v b/vlib/bf/bf_test.v new file mode 100644 index 0000000000..832849db63 --- /dev/null +++ b/vlib/bf/bf_test.v @@ -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 +}