From c5c310280fc8285d14127b583398672a6248d847 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 18 Dec 2020 21:47:24 +0200 Subject: [PATCH] bitfield: fix bf.from_bytes/1 ( now, bf.from_bytes(b) == bf.from_str(bf.from_bytes(b).str()) ) --- vlib/bitfield/bitfield.v | 162 ++++++++++++++++++---------------- vlib/bitfield/bitfield_test.v | 89 ++++++++----------- 2 files changed, 123 insertions(+), 128 deletions(-) diff --git a/vlib/bitfield/bitfield.v b/vlib/bitfield/bitfield.v index 9875ec1c57..99add985d2 100644 --- a/vlib/bitfield/bitfield.v +++ b/vlib/bitfield/bitfield.v @@ -12,11 +12,10 @@ Bit arrays are stored in data structures called 'BitField'. The structure is 'opaque', i.e. its internals are not available to the end user. This module provides API (functions and methods) for accessing and modifying bit arrays. */ - pub struct BitField { mut: - size int - //field *u32 + size int + // field *u32 field []u32 } @@ -26,12 +25,36 @@ const ( ) // public functions - // from_bytes() converts a byte array into a bitfield. pub fn from_bytes(input []byte) BitField { mut output := new(input.len * 8) for i, b in input { - output.field[i / 4] |= u32(b) << ((i % 4) * 8) + mut ob := byte(0) + if b & 0b10000000 > 0 { + ob |= 0b00000001 + } + if b & 0b01000000 > 0 { + ob |= 0b00000010 + } + if b & 0b00100000 > 0 { + ob |= 0b00000100 + } + if b & 0b00010000 > 0 { + ob |= 0b00001000 + } + if b & 0b00001000 > 0 { + ob |= 0b00010000 + } + if b & 0b00000100 > 0 { + ob |= 0b00100000 + } + if b & 0b00000010 > 0 { + ob |= 0b01000000 + } + if b & 0b00000001 > 0 { + ob |= 0b10000000 + } + output.field[i / 4] |= u32(ob) << ((i % 4) * 8) } return output } @@ -40,7 +63,7 @@ pub fn from_bytes(input []byte) BitField { // array. Any character different from '0' is treated as '1'. pub fn from_str(input string) BitField { mut output := new(input.len) - for i in 0..input.len { + for i in 0 .. input.len { if input[i] != `0` { output.set_bit(i) } @@ -52,11 +75,10 @@ pub fn from_str(input string) BitField { // return the string pub fn (input BitField) str() string { mut output := '' - for i in 0..input.size { + for i in 0 .. input.size { if input.get_bit(i) == 1 { output = output + '1' - } - else { + } else { output = output + '0' } } @@ -67,18 +89,18 @@ pub fn (input BitField) str() string { pub fn new(size int) BitField { output := BitField{ size: size - //field: *u32(calloc(zbitnslots(size) * slot_size / 8)) - field: []u32{len:zbitnslots(size)} + // field: *u32(calloc(zbitnslots(size) * slot_size / 8)) + field: []u32{len: zbitnslots(size)} } return output } + /* pub fn del(instance *BitField) { free(instance.field) free(instance) } */ - // get_bit returns the value (0 or 1) of bit number 'bit_nr' (count from 0). pub fn (instance BitField) get_bit(bitnr int) int { if bitnr >= instance.size { @@ -105,7 +127,7 @@ pub fn (mut instance BitField) clear_bit(bitnr int) { // set_all sets all bits in the array to 1. pub fn (mut instance BitField) set_all() { - for i in 0..zbitnslots(instance.size) { + for i in 0 .. zbitnslots(instance.size) { instance.field[i] = u32(-1) } instance.clear_tail() @@ -113,7 +135,7 @@ pub fn (mut instance BitField) set_all() { // clear_all clears (sets to zero) all bits in the array. pub fn (mut instance BitField) clear_all() { - for i in 0..zbitnslots(instance.size) { + for i in 0 .. zbitnslots(instance.size) { instance.field[i] = u32(0) } } @@ -134,7 +156,7 @@ pub fn bf_and(input1 BitField, input2 BitField) BitField { size := min(input1.size, input2.size) bitnslots := zbitnslots(size) mut output := new(size) - for i in 0..bitnslots { + for i in 0 .. bitnslots { output.field[i] = input1.field[i] & input2.field[i] } output.clear_tail() @@ -146,7 +168,7 @@ pub fn bf_not(input BitField) BitField { size := input.size bitnslots := zbitnslots(size) mut output := new(size) - for i in 0..bitnslots { + for i in 0 .. bitnslots { output.field[i] = ~input.field[i] } output.clear_tail() @@ -160,7 +182,7 @@ pub fn bf_or(input1 BitField, input2 BitField) BitField { size := min(input1.size, input2.size) bitnslots := zbitnslots(size) mut output := new(size) - for i in 0..bitnslots { + for i in 0 .. bitnslots { output.field[i] = input1.field[i] | input2.field[i] } output.clear_tail() @@ -174,7 +196,7 @@ pub fn bf_xor(input1 BitField, input2 BitField) BitField { size := min(input1.size, input2.size) bitnslots := zbitnslots(size) mut output := new(size) - for i in 0..bitnslots { + for i in 0 .. bitnslots { output.field[i] = input1.field[i] ^ input2.field[i] } output.clear_tail() @@ -186,21 +208,17 @@ 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 in 0..zbitnslots(input1.size) { + for i in 0 .. zbitnslots(input1.size) { 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 in 0..zbitnslots(input2.size) { - output.field[i + offset_slot] |= - u32(input2.field[i] << u32(offset_bit)) + for i in 0 .. zbitnslots(input2.size) { + output.field[i + offset_slot] |= u32(input2.field[i] << u32(offset_bit)) } - /* - * If offset_bit is not zero, additional operations are needed. + * 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 @@ -211,16 +229,14 @@ pub fn join(input1 BitField, input2 BitField) BitField { * the last slot of output is greater than the nr of bits in the second * input. * If offset_bit is zero, no additional copies needed. - */ + */ if (output_size - 1) % slot_size < (input2.size - 1) % slot_size { - for i in 0..zbitnslots(input2.size) { - output.field[i + offset_slot + 1] |= - u32(input2.field[i] >> u32(slot_size - offset_bit)) + for i in 0 .. zbitnslots(input2.size) { + 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 in 0..zbitnslots(input2.size) - 1 { - output.field[i + offset_slot + 1] |= - u32(input2.field[i] >> u32(slot_size - offset_bit)) + for i in 0 .. zbitnslots(input2.size) - 1 { + output.field[i + offset_slot + 1] |= u32(input2.field[i] >> u32(slot_size - offset_bit)) } } return output @@ -235,7 +251,7 @@ pub fn (instance BitField) get_size() int { pub fn (instance BitField) clone() BitField { bitnslots := zbitnslots(instance.size) mut output := new(instance.size) - for i in 0..bitnslots { + for i in 0 .. bitnslots { output.field[i] = instance.field[i] } return output @@ -244,9 +260,13 @@ pub fn (instance BitField) clone() BitField { // cmp compares two bit arrays bit by bit and returns 'true' if they are // identical by length and contents and 'false' otherwise. pub fn (instance BitField) cmp(input BitField) bool { - if instance.size != input.size {return false} - for i in 0..zbitnslots(instance.size) { - if instance.field[i] != input.field[i] {return false} + if instance.size != input.size { + return false + } + for i in 0 .. zbitnslots(instance.size) { + if instance.field[i] != input.field[i] { + return false + } } return true } @@ -257,14 +277,14 @@ pub fn (instance BitField) pop_count() int { bitnslots := zbitnslots(size) tail := size % slot_size mut count := 0 - for i in 0..bitnslots - 1 { - for j in 0..slot_size { + for i in 0 .. bitnslots - 1 { + for j in 0 .. slot_size { if u32(instance.field[i] >> u32(j)) & u32(1) == u32(1) { count++ } } } - for j in 0..tail { + for j in 0 .. tail { if u32(instance.field[bitnslots - 1] >> u32(j)) & u32(1) == u32(1) { count++ } @@ -284,7 +304,6 @@ 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 @@ -312,54 +331,42 @@ pub fn (input BitField) slice(_start int, _end int) BitField { 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 := zbitnslots(end - start) - if output_slots > 1 { if start_offset != 0 { - for i in 0..output_slots - 1 { - 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)) + for i in 0 .. output_slots - 1 { + 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 in 0..output_slots - 1 { - output.field[i] = - u32(input.field[start_slot + i]) + } else { + for i in 0 .. output_slots - 1 { + 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)) + 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] |= mask - } - else if start_offset == 0 { + } else if start_offset == 0 { mut mask := u32(0) if end_offset == slot_size - 1 { mask = u32(-1) - } - else { + } 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) + 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] |= mask @@ -373,15 +380,15 @@ pub fn (instance BitField) reverse() BitField { size := instance.size bitnslots := zbitnslots(size) mut output := new(size) - for i:= 0; i < (bitnslots - 1); i++ { - for j in 0..slot_size { + for i := 0; i < (bitnslots - 1); i++ { + for j in 0 .. slot_size { if u32(instance.field[i] >> u32(j)) & u32(1) == u32(1) { output.set_bit(size - i * slot_size - j - 1) } } } bits_in_last_input_slot := (size - 1) % slot_size + 1 - for j in 0..bits_in_last_input_slot { + for j in 0 .. bits_in_last_input_slot { if u32(instance.field[bitnslots - 1] >> u32(j)) & u32(1) == u32(1) { output.set_bit(bits_in_last_input_slot - j - 1) } @@ -394,7 +401,7 @@ pub fn (mut instance BitField) resize(new_size int) { new_bitnslots := zbitnslots(new_size) old_size := instance.size old_bitnslots := zbitnslots(old_size) - mut field := []u32{len:new_bitnslots} + mut field := []u32{len: new_bitnslots} for i := 0; i < old_bitnslots && i < new_bitnslots; i++ { field[i] = instance.field[i] } @@ -408,14 +415,15 @@ pub fn (mut instance BitField) resize(new_size int) { // rotate circular-shifts the bits by 'offset' positions (move // 'offset' bit to 0, 'offset+1' bit to 1, and so on). 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 @@ -424,7 +432,6 @@ pub fn (instance BitField) rotate(offset int) BitField { 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) @@ -432,14 +439,14 @@ pub fn (instance BitField) rotate(offset int) BitField { } // Internal functions - fn (mut instance BitField) clear_tail() { 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[zbitnslots(instance.size) - 1] = instance.field[zbitnslots(instance.size) - 1] & mask + instance.field[zbitnslots(instance.size) - 1] = instance.field[zbitnslots(instance.size) - + 1] & mask } } @@ -454,8 +461,7 @@ fn bitslot(size int) int { fn min(input1 int, input2 int) int { if input1 < input2 { return input1 - } - else { + } else { return input2 } } diff --git a/vlib/bitfield/bitfield_test.v b/vlib/bitfield/bitfield_test.v index 6b305758a6..b5f4e864fa 100644 --- a/vlib/bitfield/bitfield_test.v +++ b/vlib/bitfield/bitfield_test.v @@ -1,5 +1,4 @@ import bitfield - import rand fn test_bf_new_size() { @@ -26,7 +25,7 @@ fn test_bf_and_not_or_xor() { if rand.intn(2) == 1 { input1.set_bit(i) } - if rand.intn(2) == 1{ + if rand.intn(2) == 1 { input2.set_bit(i) } i++ @@ -38,7 +37,9 @@ fn test_bf_and_not_or_xor() { output2 := bitfield.bf_and(bf_or, bf_not) mut result := 1 for i < len { - if output1.get_bit(i) != output2.get_bit(i) {result = 0} + if output1.get_bit(i) != output2.get_bit(i) { + result = 0 + } } assert result == 1 } @@ -46,7 +47,7 @@ fn test_bf_and_not_or_xor() { fn test_clone_cmp() { len := 80 mut input := bitfield.new(len) - for i in 0..len { + for i in 0 .. len { if rand.intn(2) == 1 { input.set_bit(i) } @@ -59,7 +60,7 @@ fn test_clone_cmp() { fn test_slice_join() { len := 80 mut input := bitfield.new(len) - for i in 0..len { + for i in 0 .. len { if rand.intn(2) == 1 { input.set_bit(i) } @@ -82,7 +83,7 @@ fn test_pop_count() { len := 80 mut count0 := 0 mut input := bitfield.new(len) - for i in 0..len { + for i in 0 .. len { if rand.intn(2) == 1 { input.set_bit(i) count0++ @@ -97,7 +98,7 @@ fn test_hamming() { mut count := 0 mut input1 := bitfield.new(len) mut input2 := bitfield.new(len) - for i in 0..len { + for i in 0 .. len { match rand.intn(4) { 0, 1 { input1.set_bit(i) @@ -111,40 +112,33 @@ fn test_hamming() { input1.set_bit(i) input2.set_bit(i) } - else { - - } + else {} } } assert count == bitfield.hamming(input1, input2) } fn test_bf_from_bytes() { - input := [byte(0xF0), byte(0x0F), byte(0xF0), byte(0xFF)] - output := bitfield.from_bytes(input) - mut result := 1 - for i in 0..input.len * 8 { - if (input[i / 8] >> (i % 8)) & 1 != output.get_bit(i) { - result = 0 - } - } - assert result == 1 + input := [byte(0x01), 0xF0, 0x0F, 0xF0, 0xFF] + output := bitfield.from_bytes(input).str() + assert output == '00000001' + '11110000' + '00001111' + '11110000' + '11111111' + newoutput := bitfield.from_str(output).str() + assert newoutput == output } fn test_bf_from_str() { len := 80 mut input := '' - for _ in 0..len { + for _ in 0 .. len { if rand.intn(2) == 1 { input = input + '1' - } - else { + } else { input = input + '0' } } output := bitfield.from_str(input) mut result := 1 - for i in 0..len { + for i in 0 .. len { if input[i] != output.get_bit(i) + 48 { result = 0 } @@ -155,23 +149,22 @@ fn test_bf_from_str() { fn test_bf_bf2str() { len := 80 mut input := bitfield.new(len) - for i in 0..len { + for i in 0 .. len { if rand.intn(2) == 1 { input.set_bit(i) } } mut check := '' - for i in 0..len { + for i in 0 .. len { if input.get_bit(i) == 1 { check = check + '1' - } - else { + } else { check = check + '0' } } output := input.str() mut result := 1 - for i in 0..len { + for i in 0 .. len { if check[i] != output[i] { result = 0 } @@ -184,7 +177,7 @@ fn test_bf_set_all() { mut input := bitfield.new(len) input.set_all() mut result := 1 - for i in 0..len { + for i in 0 .. len { if input.get_bit(i) != 1 { result = 0 } @@ -195,14 +188,14 @@ fn test_bf_set_all() { fn test_bf_clear_all() { len := 80 mut input := bitfield.new(len) - for i in 0..len { + for i in 0 .. len { if rand.intn(2) == 1 { input.set_bit(i) } } input.clear_all() mut result := 1 - for i in 0..len { + for i in 0 .. len { if input.get_bit(i) != 0 { result = 0 } @@ -213,7 +206,7 @@ fn test_bf_clear_all() { fn test_bf_reverse() { len := 80 mut input := bitfield.new(len) - for i in 0..len { + for i in 0 .. len { if rand.intn(2) == 1 { input.set_bit(i) } @@ -221,7 +214,7 @@ fn test_bf_reverse() { check := input.clone() output := input.reverse() mut result := 1 - for i in 0..len { + for i in 0 .. len { if output.get_bit(i) != check.get_bit(len - i - 1) { result = 0 } @@ -232,7 +225,7 @@ fn test_bf_reverse() { fn test_bf_resize() { len := 80 mut input := bitfield.new(rand.intn(len) + 1) - for _ in 0..100 { + for _ in 0 .. 100 { input.resize(rand.intn(len) + 1) input.set_bit(input.get_size() - 1) } @@ -240,48 +233,44 @@ fn test_bf_resize() { } fn test_bf_pos() { - /** + /* + * * set haystack size to 80 * test different sizes of needle, from 1 to 80 * test different positions of needle, from 0 to where it fits * all haystacks here contain exactly one instanse of needle, * so search should return non-negative-values - **/ + * + */ len := 80 mut result := 1 - for i := 1; i < len; i++ { // needle size - for j in 0..len - i { // needle position in the haystack + for i := 1; i < len; i++ { // needle size + for j in 0 .. len - i { // needle position in the haystack // create the needle mut needle := bitfield.new(i) - // fill the needle with random values - for k in 0..i { + for k in 0 .. i { if rand.intn(2) == 1 { needle.set_bit(k) } } - // make sure the needle contains at least one set bit, selected randomly r := rand.intn(i) needle.set_bit(r) - // create the haystack, make sure it contains the needle mut haystack := needle.clone() - // if there is space between the start of the haystack and the sought needle, fill it with zeroes if j > 0 { start := bitfield.new(j) tmp := bitfield.join(start, haystack) haystack = tmp } - // if there is space between the sought needle and the end of haystack, fill it with zeroes if j + i < len { end := bitfield.new(len - j - i) tmp2 := bitfield.join(haystack, end) haystack = tmp2 } - // now let's test // the result should be equal to j if haystack.pos(needle) != j { @@ -308,13 +297,13 @@ fn test_bf_rotate() { assert result == 1 } -fn test_bf_printing(){ +fn test_bf_printing() { len := 80 mut input := bitfield.new(len) - for i in 0..len { - if rand.intn(2) == 0 { - input.set_bit(i) - } + for i in 0 .. len { + if rand.intn(2) == 0 { + input.set_bit(i) + } } // the following should convert the bitfield input into a string automatically println(input)