module bf struct BitField { mut: size int //field *u32 field []u32 } // helper functions const ( SLOT_SIZE = 32 ) fn bitmask(bitnr int) u32 { return u32(u32(1) << u32(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 str2bf(input string) BitField { mut output := new(input.len) for i := 0; i < input.len; i++ { if input[i] != 48 { output.setbit(i) } } return output } pub fn (input BitField) string() string { mut output := '' for i := 0; i < input.size; i++ { if input.getbit(i) == 1 { output = output + '1' } else { output = output + '0' } } return output } 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) setall() { for i := 0; i < bitnslots(instance.size); i++ { instance.field[i] = u32(-1) } cleartail(instance) } pub fn (instance mut BitField) clearall() { for i := 0; i < bitnslots(instance.size); i++ { instance.field[i] = u32(0) } } 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 join(input1 BitField, input2 BitField) BitField { output_size := input1.size + input2.size mut output := new(output_size) // copy the first input to output as is for i := 0; i < bitnslots(input1.size); i++ { output.field[i] = input1.field[i] } // find offset bit and offset slot offset_bit := input1.size % SLOT_SIZE offset_slot := input1.size / SLOT_SIZE for i := 0; i < bitnslots(input2.size); i++ { output.field[i + offset_slot] = output.field[i + offset_slot] | u32(input2.field[i] << u32(offset_bit)) } /* * If offset_bit is not zero, additional operations are needed. * Number of iterations depends on the nr of slots in output. Two * options: * (a) nr of slots in output is the sum of inputs' slots. In this * case, the nr of bits in the last slot of output is less than the * nr of bits in second input (i.e. ), OR * (b) nr of slots of output is the sum of inputs' slots less one * (i.e. less iterations needed). In this case, the nr of bits in * the last slot of output is greater than the nr of bits in second * input. * If offset_bit is zero, no additional copies needed. */ if (output_size - 1) % SLOT_SIZE < (input2.size - 1) % SLOT_SIZE { for i := 0; i < bitnslots(input2.size); i++ { output.field[i + offset_slot + 1] = output.field[i + offset_slot + 1] | u32(input2.field[i] >> u32(SLOT_SIZE - offset_bit)) } } else if (output_size - 1) % SLOT_SIZE > (input2.size - 1) % SLOT_SIZE { for i := 0; i < bitnslots(input2.size) - 1; i++ { output.field[i + offset_slot + 1] = output.field[i + offset_slot + 1] | u32(input2.field[i] >> u32(SLOT_SIZE - offset_bit)) } } 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 } pub fn cmp(input1 BitField, input2 BitField) bool { if input1.size != input2.size {return false} for i := 0; i < bitnslots(input1.size); i++ { if input1.field[i] != input2.field[i] {return false} } return true } pub fn (instance BitField) popcount() int { size := instance.size bitnslots := bitnslots(size) tail := size % SLOT_SIZE mut count := 0 for i := 0; i < bitnslots - 1; i++ { for j := 0; j < SLOT_SIZE; j++ { if u32(instance.field[i] >> u32(j)) & u32(1) == u32(1) { count++ } } } for j := 0; j < tail; j++ { if u32(instance.field[bitnslots - 1] >> u32(j)) & u32(1) == u32(1) { count++ } } return count } pub fn hamming (input1 BitField, input2 BitField) int { input_xored := bfxor(input1, input2) return input_xored.popcount() } pub fn (haystack BitField) pos(needle BitField) int { heystack_size := haystack.size needle_size := needle.size diff := heystack_size - needle_size // needle longer than haystack; return error code -2 if diff < 0 { return -2 } for i := 0; i <= diff; i++ { needle_candidate := haystack.slice(i, needle_size + i) if cmp(needle_candidate, needle) { // needle matches a sub-array of haystack; return starting position of the sub-array return i } } // nothing matched; return -1 return -1 } pub fn (input BitField) slice(_start int, _end int) BitField { // boundary checks mut start := _start mut end := _end if end > input.size { end = input.size // or panic? } if start > end { start = end // or panic? } mut output := new(end - start) start_offset := start % SLOT_SIZE end_offset := (end - 1) % SLOT_SIZE start_slot := start / SLOT_SIZE end_slot := (end - 1) / SLOT_SIZE output_slots := bitnslots(end - start) if output_slots > 1 { if start_offset != 0 { for i := 0; i < output_slots - 1; i++ { output.field[i] = u32(input.field[start_slot + i] >> u32(start_offset)) output.field[i] = output.field[i] | u32(input.field[start_slot + i + 1] << u32(SLOT_SIZE - start_offset)) } } else { for i := 0; i < output_slots - 1; i++ { output.field[i] = u32(input.field[start_slot + i]) } } } if start_offset > end_offset { output.field[(end - start - 1) / SLOT_SIZE] = u32(input.field[end_slot - 1] >> u32(start_offset)) mut mask := u32((1 << (end_offset + 1)) - 1) mask = input.field[end_slot] & mask mask = u32(mask << u32(SLOT_SIZE - start_offset)) output.field[(end - start - 1) / SLOT_SIZE] = output.field[(end - start - 1) / SLOT_SIZE] | mask } else if start_offset == 0 { mut mask := u32(0) if end_offset == SLOT_SIZE - 1 { mask = u32(-1) } else { mask = u32(u32(1) << u32(end_offset + 1)) mask = mask - u32(1) } output.field[(end - start - 1) / SLOT_SIZE] = (input.field[end_slot] & mask) } else { mut mask := u32(((1 << (end_offset - start_offset + 1)) - 1) << start_offset) mask = input.field[end_slot] & mask mask = u32(mask >> u32(start_offset)) output.field[(end - start - 1) / SLOT_SIZE] = output.field[(end - start - 1) / SLOT_SIZE] | mask } return output } pub fn (instance mut BitField) reverse() BitField { size := instance.size bitnslots := bitnslots(size) mut output := new(size) for i:= 0; i < (bitnslots - 1); i++ { for j := 0; j < SLOT_SIZE; j++ { if u32(instance.field[i] >> u32(j)) & u32(1) == u32(1) { bitset(output, size - i * SLOT_SIZE - j - 1) } } } bits_in_last_input_slot := (size - 1) % SLOT_SIZE + 1 for j := 0; j < bits_in_last_input_slot; j++ { if u32(instance.field[bitnslots - 1] >> u32(j)) & u32(1) == u32(1) { bitset(output, bits_in_last_input_slot - j - 1) } } return output } pub fn (instance mut BitField) resize(size int) { bitnslots := bitnslots(size) old_size := instance.size old_bitnslots := bitnslots(old_size) mut field := [u32(0); bitnslots] for i := 0; i < old_bitnslots && i < bitnslots; i++ { field[i] = instance.field[i] } instance.field = field instance.size = size if size < old_size && size % SLOT_SIZE != 0 { cleartail(instance) } } pub fn (instance BitField) rotate(offset int) BitField { /** * This function "cuts" the bitfield into two and swaps them. * If the offset is positive, the cutting point is counted from the * beginning of the bit array, otherwise from the end. **/ size := instance.size // removing extra rotations mut offset_internal := offset % size if (offset_internal == 0) { // nothing to shift return instance } if offset_internal < 0 { offset_internal = offset_internal + size } first_chunk := instance.slice(0, offset_internal) second_chunk := instance.slice(offset_internal, size) output := join(second_chunk, first_chunk) return output }