From c0911ea74b7ce84748a417c78222539e413bdb8c Mon Sep 17 00:00:00 2001 From: Vitalie Ciubotaru Date: Tue, 16 Jul 2019 02:07:07 +0900 Subject: [PATCH] bf: add reverse(), resize(), pos() and rotate() --- vlib/bf/bf.v | 79 ++++++++++++++++++++++++++++++++++++ vlib/bf/bf_test.v | 101 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/vlib/bf/bf.v b/vlib/bf/bf.v index 94c527afbc..be4783c423 100644 --- a/vlib/bf/bf.v +++ b/vlib/bf/bf.v @@ -294,6 +294,26 @@ pub fn hamming (input1 BitField, input2 BitField) int { 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 @@ -360,3 +380,62 @@ pub fn (input BitField) slice(_start int, _end int) BitField { } 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 +} diff --git a/vlib/bf/bf_test.v b/vlib/bf/bf_test.v index 719c14ac96..597dc91a2a 100644 --- a/vlib/bf/bf_test.v +++ b/vlib/bf/bf_test.v @@ -202,3 +202,104 @@ fn test_bf_clearall() { } assert result == 1 } + +fn test_bf_reverse() { + rand.seed(time.now().uni) + len := 80 + mut input := bf.new(len) + for i := 0; i < len; i++ { + if rand.next(2) == 1 { + input.setbit(i) + } + } + check := bf.clone(input) + output := input.reverse() + mut result := 1 + for i := 0; i < len; i++ { + if output.getbit(i) != check.getbit(len - i - 1) { + result = 0 + } + } + assert result == 1 +} + +fn test_bf_resize() { + rand.seed(time.now().uni) + len := 80 + mut input := bf.new(len) + for i := 0; i < 100; i++ { + input.resize(rand.next(input.getsize()) + 1) + input.setbit(input.getsize() - 1) + } + assert input.getbit(input.getsize() - 1) == 1 +} + +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 + **/ + rand.seed(time.now().uni) + len := 80 + mut result := 1 + for i := 1; i < len; i++ { // needle size + for j := 0; j < len - i; j++ { // needle position in the haystack + // create the needle + mut needle := bf.new(i) + + // fill the needle with random values + for k := 0; k < i; k++ { + if rand.next(2) == 1 { + needle.setbit(k) + } + } + + // make sure the needle contains at least one set bit, selected randomly + r := rand.next(i) + needle.setbit(r) + + // create the haystack, make sure it contains the needle + mut haystack := bf.clone(needle) + + // if there is space between the start of the haystack and the sought needle, fill it with zeroes + if j > 0 { + start := bf.new(j) + tmp := bf.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 := bf.new(len - j - i) + tmp2 := bf.join(haystack, end) + haystack = tmp2 + } + + // now let's test + // the result should be equal to j + if haystack.pos(needle) != j { + result = 0 + } + } + } + assert result == 1 +} + +fn test_bf_rotate() { + mut result := 1 + len := 80 + for i := 1; i < 80 && result == 1; i++ { + mut chunk1 := bf.new(i) + chunk2 := bf.new(len - i) + chunk1.setall() + input := bf.join(chunk1, chunk2) + output := input.rotate(i) + if output.getbit(len - i - 1) != 0 || output.getbit(len - i) != 1 { + result = 0 + } + } + assert result == 1 +}