v2 / vlib / bitfield / bitfield.v
650 lines · 602 sloc · 17.85 KB · dbc9754a36c72c440032cd219112f72510a72c03
Raw
1module bitfield
2
3/*
4bitfield is a module for
5manipulating arrays of bits, i.e. series of zeroes and ones spread across an
6array of storage units (unsigned 32-bit integers).
7
8BitField structure
9------------------
10
11Bit arrays are stored in data structures called 'BitField'. The structure is
12'opaque', i.e. its internals are not available to the end user. This module
13provides API (functions and methods) for accessing and modifying bit arrays.
14*/
15pub struct BitField {
16mut:
17 size int
18 // field *u32
19 field []u32
20}
21
22// helper functions
23const slot_size = 32
24
25// from_bytes converts a byte array into a bitfield.
26// [0x0F, 0x01] => 0000 1111 0000 0001
27pub fn from_bytes(input []u8) BitField {
28 mut output := new(input.len * 8)
29 for i, b in input {
30 mut ob := u8(0)
31 if b & 0b10000000 > 0 {
32 ob |= 0b00000001
33 }
34 if b & 0b01000000 > 0 {
35 ob |= 0b00000010
36 }
37 if b & 0b00100000 > 0 {
38 ob |= 0b00000100
39 }
40 if b & 0b00010000 > 0 {
41 ob |= 0b00001000
42 }
43 if b & 0b00001000 > 0 {
44 ob |= 0b00010000
45 }
46 if b & 0b00000100 > 0 {
47 ob |= 0b00100000
48 }
49 if b & 0b00000010 > 0 {
50 ob |= 0b01000000
51 }
52 if b & 0b00000001 > 0 {
53 ob |= 0b10000000
54 }
55 output.field[i / 4] |= u32(ob) << ((i % 4) * 8)
56 }
57 return output
58}
59
60// from_bytes_lowest_bits_first converts a byte array into a bitfield.
61// For example: [0x0F, 0x01] => 1111 0000 1000 0000
62pub fn from_bytes_lowest_bits_first(input []u8) BitField {
63 mut output := new(input.len * 8)
64 for i, b in input {
65 output.field[i / 4] |= u32(b) << ((i % 4) * 8)
66 }
67 return output
68}
69
70// from_str converts a string of characters ('0' and '1') to a bitfield.
71// Any character different from '0' is treated as '1'.
72pub fn from_str(input string) BitField {
73 mut output := new(input.len)
74 for i in 0 .. input.len {
75 if input[i] != `0` {
76 output.set_bit(i)
77 }
78 }
79 return output
80}
81
82// str converts the bit array to a string of characters ('0' and '1').
83pub fn (input BitField) str() string {
84 mut output := ''
85 for i in 0 .. input.size {
86 if input.get_bit(i) == 1 {
87 output = output + '1'
88 } else {
89 output = output + '0'
90 }
91 }
92 return output
93}
94
95// new creates an empty bit array capable of storing 'size' bits.
96pub fn new(size int) BitField {
97 output := BitField{
98 size: size
99 // field: *u32(calloc(zbitnslots(size) * slot_size / 8))
100 field: []u32{len: zbitnslots(size)}
101 }
102 return output
103}
104
105// frees the memory allocated for the bitfield instance.
106@[unsafe]
107pub fn (instance &BitField) free() {
108 unsafe {
109 instance.field.free()
110 }
111}
112
113// get_bit returns the value (0 or 1) of bit number 'bit_nr' (count from 0).
114@[inline]
115pub fn (instance BitField) get_bit(bitnr int) int {
116 if bitnr >= instance.size {
117 return 0
118 }
119 return int((instance.field[bitslot(bitnr)] >> (bitnr % slot_size)) & u32(1))
120}
121
122// set_bit sets bit number 'bit_nr' to 1 (count from 0).
123@[inline]
124pub fn (mut instance BitField) set_bit(bitnr int) {
125 if bitnr >= instance.size {
126 return
127 }
128 instance.field[bitslot(bitnr)] |= bitmask(bitnr)
129}
130
131// clear_bit clears (sets to zero) bit number 'bit_nr' (count from 0).
132@[inline]
133pub fn (mut instance BitField) clear_bit(bitnr int) {
134 if bitnr >= instance.size {
135 return
136 }
137 instance.field[bitslot(bitnr)] &= ~bitmask(bitnr)
138}
139
140// extract returns the value converted from a slice of bit numbers from 'start' by the length of 'len'.
141// For example 0101 . extract(1, 2) => 0b10
142pub fn (instance BitField) extract(start int, len int) u64 {
143 // panic?
144 if start < 0 {
145 return 0
146 }
147 mut output := u64(0)
148 for i in 0 .. len {
149 output |= u64(instance.get_bit(start + len - i - 1)) << i
150 }
151 return output
152}
153
154// insert sets bit numbers from 'start' to 'len' length with the value converted from the number 'value'.
155// For example 0000.insert(1, 2, 0b10) => 0100
156pub fn (mut instance BitField) insert[T](start int, len int, _value T) {
157 // panic?
158 if start < 0 {
159 return
160 }
161 mut value := _value
162 for i in 0 .. len {
163 pos := start + len - i - 1
164 if value & 1 == 1 {
165 instance.set_bit(pos)
166 } else {
167 instance.clear_bit(pos)
168 }
169 value >>= 1
170 }
171}
172
173// extract returns the value converted from a slice of bit numbers from 'start' by the length of 'len'.
174// For example 0101.extract_lowest_bits_first(1, 2) => 0b01
175pub fn (instance BitField) extract_lowest_bits_first(start int, len int) u64 {
176 // panic?
177 if start < 0 {
178 return 0
179 }
180 mut output := u64(0)
181 for i in 0 .. len {
182 output |= u64(instance.get_bit(start + i)) << i
183 }
184 return output
185}
186
187// insert sets bit numbers from 'start' to 'len' length with the value converted from the number 'value'.
188// For example 0000.insert_lowest_bits_first(1, 2, 0b10) => 0010
189pub fn (mut instance BitField) insert_lowest_bits_first[T](start int, len int, _value T) {
190 // panic?
191 if start < 0 {
192 return
193 }
194 mut value := _value
195 for pos in start .. start + len {
196 if value & 1 == 1 {
197 instance.set_bit(pos)
198 } else {
199 instance.clear_bit(pos)
200 }
201 value >>= 1
202 }
203}
204
205// set_all sets all bits in the array to 1.
206pub fn (mut instance BitField) set_all() {
207 for i in 0 .. zbitnslots(instance.size) {
208 instance.field[i] = u32(0xFFFF_FFFF)
209 }
210 instance.clear_tail()
211}
212
213// clear_all clears (sets to zero) all bits in the array.
214pub fn (mut instance BitField) clear_all() {
215 for i in 0 .. zbitnslots(instance.size) {
216 instance.field[i] = u32(0)
217 }
218}
219
220// toggle_bit changes the value (from 0 to 1 or from 1 to 0) of bit number 'bit_nr'.
221@[inline]
222pub fn (mut instance BitField) toggle_bit(bitnr int) {
223 if bitnr >= instance.size {
224 return
225 }
226 instance.field[bitslot(bitnr)] ^= bitmask(bitnr)
227}
228
229// set_if sets bit number 'bit_nr' to 1 (count from 0) if `cond` is true or clear the bit.
230@[inline]
231pub fn (mut instance BitField) set_if(cond bool, bitnr int) {
232 if bitnr >= instance.size {
233 return
234 }
235 if cond {
236 instance.field[bitslot(bitnr)] |= bitmask(bitnr)
237 } else {
238 instance.field[bitslot(bitnr)] &= ~bitmask(bitnr)
239 }
240}
241
242// toggle_bits changes the value (from 0 to 1 or from 1 to 0) of bits.
243// Example: mut bf := bitfield.new(10); bf.toggle_bits(1,3,5,7); assert bf.str() == '0101010100'
244@[inline]
245pub fn (mut instance BitField) toggle_bits(a ...int) {
246 for bitnr in a {
247 if bitnr >= instance.size {
248 return
249 }
250 instance.field[bitslot(bitnr)] ^= bitmask(bitnr)
251 }
252}
253
254// set_bits sets multiple bits in the array to 1.
255// Example: mut bf := bitfield.new(10); bf.set_bits(1,3,5,7); assert bf.str() == '0101010100'
256@[inline]
257pub fn (mut instance BitField) set_bits(a ...int) {
258 for bitnr in a {
259 if bitnr >= instance.size {
260 return
261 }
262 instance.field[bitslot(bitnr)] |= bitmask(bitnr)
263 }
264}
265
266// clear_bits clear multiple bits in the array to 0.
267// Example: mut bf := bitfield.from_str('1111111111111'); bf.clear_bits(1,2,5,6,7); assert bf.str() == '1001100011111'
268@[inline]
269pub fn (mut instance BitField) clear_bits(a ...int) {
270 for bitnr in a {
271 if bitnr >= instance.size {
272 return
273 }
274 instance.field[bitslot(bitnr)] &= ~bitmask(bitnr)
275 }
276}
277
278// has test if *at least one* of the bits is set.
279// Example: mut bf := bitfield.from_str('111111100000000'); assert bf.has(1,3,5,7)
280@[inline]
281pub fn (mut instance BitField) has(a ...int) bool {
282 for bitnr in a {
283 if bitnr >= instance.size {
284 return false
285 }
286 if int((instance.field[bitslot(bitnr)] >> (bitnr % slot_size)) & u32(1)) == 1 {
287 return true
288 }
289 }
290 return false
291}
292
293// all test if *all* of the bits are set.
294// Example: mut bf := bitfield.from_str('111111100000000'); assert !bf.all(1,3,5,7)
295@[inline]
296pub fn (mut instance BitField) all(a ...int) bool {
297 for bitnr in a {
298 if bitnr >= instance.size {
299 return false
300 }
301 if int((instance.field[bitslot(bitnr)] >> (bitnr % slot_size)) & u32(1)) == 0 {
302 return false
303 }
304 }
305 return true
306}
307
308// bf_and performs logical AND operation on every pair of bits from 'input1' and 'input2'.
309// It returns the result as a new array. If inputs differ in size, the tail of the longer one is ignored.
310pub fn bf_and(input1 BitField, input2 BitField) BitField {
311 size := min(input1.size, input2.size)
312 bitnslots := zbitnslots(size)
313 mut output := new(size)
314 for i in 0 .. bitnslots {
315 output.field[i] = input1.field[i] & input2.field[i]
316 }
317 output.clear_tail()
318 return output
319}
320
321// bf_not toggles all bits in a bit array and returns the result as a new array.
322pub fn bf_not(input BitField) BitField {
323 size := input.size
324 bitnslots := zbitnslots(size)
325 mut output := new(size)
326 for i in 0 .. bitnslots {
327 output.field[i] = ~input.field[i]
328 }
329 output.clear_tail()
330 return output
331}
332
333// bf_or performs logical OR operation on every pair of bits from 'input1' and 'input2'.
334// It returns the result as a new array. If inputs differ in size, the tail of the longer one is ignored.
335pub fn bf_or(input1 BitField, input2 BitField) BitField {
336 size := min(input1.size, input2.size)
337 bitnslots := zbitnslots(size)
338 mut output := new(size)
339 for i in 0 .. bitnslots {
340 output.field[i] = input1.field[i] | input2.field[i]
341 }
342 output.clear_tail()
343 return output
344}
345
346// bf_xor perform logical XOR operation on every pair of bits from 'input1' and 'input2'.
347// It returns the result as a new array. If inputs differ in size, the tail of the longer one is ignored.
348pub fn bf_xor(input1 BitField, input2 BitField) BitField {
349 size := min(input1.size, input2.size)
350 bitnslots := zbitnslots(size)
351 mut output := new(size)
352 for i in 0 .. bitnslots {
353 output.field[i] = input1.field[i] ^ input2.field[i]
354 }
355 output.clear_tail()
356 return output
357}
358
359// join concatenates two bit arrays and returns the result as a new array.
360pub fn join(input1 BitField, input2 BitField) BitField {
361 output_size := input1.size + input2.size
362 mut output := new(output_size)
363 // copy the first input to output as is
364 for i in 0 .. zbitnslots(input1.size) {
365 output.field[i] = input1.field[i]
366 }
367 // find offset bit and offset slot
368 offset_bit := input1.size % slot_size
369 offset_slot := input1.size / slot_size
370 for i in 0 .. zbitnslots(input2.size) {
371 output.field[i + offset_slot] |= u32(input2.field[i] << u32(offset_bit))
372 }
373 /*
374 * If offset_bit is not zero, additional operations are needed.
375 * Number of iterations depends on the nr of slots in output. Two
376 * options:
377 * (a) nr of slots in output is the sum of inputs' slots. In this
378 * case, the nr of bits in the last slot of output is less than the
379 * nr of bits in the second input (i.e. ), OR
380 * (b) nr of slots of output is the sum of inputs' slots less one
381 * (i.e. less iterations needed). In this case, the nr of bits in
382 * the last slot of output is greater than the nr of bits in the second
383 * input.
384 * If offset_bit is zero, no additional copies needed.
385 */
386 if (output_size - 1) % slot_size < (input2.size - 1) % slot_size {
387 for i in 0 .. zbitnslots(input2.size) {
388 output.field[i + offset_slot + 1] |= u32(input2.field[i] >> u32(slot_size - offset_bit))
389 }
390 } else if (output_size - 1) % slot_size > (input2.size - 1) % slot_size {
391 for i in 0 .. zbitnslots(input2.size) - 1 {
392 output.field[i + offset_slot + 1] |= u32(input2.field[i] >> u32(slot_size - offset_bit))
393 }
394 }
395 return output
396}
397
398// get_size returns the number of bits the array can hold.
399@[inline]
400pub fn (instance BitField) get_size() int {
401 return instance.size
402}
403
404// clone creates a copy of a bit array.
405pub fn (instance BitField) clone() BitField {
406 bitnslots := zbitnslots(instance.size)
407 mut output := new(instance.size)
408 for i in 0 .. bitnslots {
409 output.field[i] = instance.field[i]
410 }
411 return output
412}
413
414// == compares 2 bitfields, and returns true when they are equal.
415pub fn (a BitField) == (b BitField) bool {
416 if a.size != b.size {
417 return false
418 }
419 for i in 0 .. zbitnslots(a.size) {
420 if a.field[i] != b.field[i] {
421 return false
422 }
423 }
424 return true
425}
426
427// pop_count returns the number of set bits (ones) in the array.
428pub fn (instance BitField) pop_count() int {
429 size := instance.size
430 bitnslots := zbitnslots(size)
431 mut count := 0
432 for i in 0 .. bitnslots {
433 for j in 0 .. slot_size {
434 if u32(instance.field[i] >> u32(j)) & u32(1) == u32(1) {
435 count++
436 }
437 }
438 }
439 return count
440}
441
442// hamming computes the Hamming distance between two bit arrays.
443@[inline]
444pub fn hamming(input1 BitField, input2 BitField) int {
445 input_xored := bf_xor(input1, input2)
446 return input_xored.pop_count()
447}
448
449// pos checks if the array contains a sub-array 'needle'.
450// It returns its position if it does, -1 if it does not, and -2 on error.
451pub fn (haystack BitField) pos(needle BitField) int {
452 heystack_size := haystack.size
453 needle_size := needle.size
454 diff := heystack_size - needle_size
455 // needle longer than haystack; return error code -2
456 if diff < 0 {
457 return -2
458 }
459 for i := 0; i <= diff; i++ {
460 needle_candidate := haystack.slice(i, needle_size + i)
461 if needle_candidate == needle {
462 // needle matches a sub-array of haystack; return starting position of the sub-array
463 return i
464 }
465 }
466 // nothing matched; return -1
467 return -1
468}
469
470// slice returns a sub-array of bits between 'start_bit_nr' (included) and 'end_bit_nr' (excluded).
471pub fn (input BitField) slice(_start int, _end int) BitField {
472 // boundary checks
473 mut start := _start
474 mut end := _end
475 if end > input.size {
476 end = input.size // or panic?
477 }
478 if start > end {
479 start = end // or panic?
480 }
481 mut output := new(end - start)
482 start_offset := start % slot_size
483 end_offset := (end - 1) % slot_size
484 start_slot := start / slot_size
485 end_slot := (end - 1) / slot_size
486 output_slots := zbitnslots(end - start)
487 if output_slots > 1 {
488 if start_offset != 0 {
489 for i in 0 .. output_slots - 1 {
490 output.field[i] = u32(input.field[start_slot + i] >> u32(start_offset))
491 output.field[i] = output.field[i] | u32(input.field[start_slot + i + 1] << u32(slot_size - start_offset))
492 }
493 } else {
494 for i in 0 .. output_slots - 1 {
495 output.field[i] = u32(input.field[start_slot + i])
496 }
497 }
498 }
499 if start_offset > end_offset {
500 output.field[(end - start - 1) / slot_size] = u32(input.field[end_slot - 1] >> u32(start_offset))
501 mut mask := u32((1 << (end_offset + 1)) - 1)
502 mask = input.field[end_slot] & mask
503 mask = u32(mask << u32(slot_size - start_offset))
504 output.field[(end - start - 1) / slot_size] |= mask
505 } else if start_offset == 0 {
506 mut mask := u32(0)
507 if end_offset == slot_size - 1 {
508 mask = u32(-1)
509 } else {
510 mask = u32(u32(1) << u32(end_offset + 1))
511 mask = mask - u32(1)
512 }
513 output.field[(end - start - 1) / slot_size] = (input.field[end_slot] & mask)
514 } else {
515 mut mask := u32(((1 << (end_offset - start_offset + 1)) - 1) << start_offset)
516 mask = input.field[end_slot] & mask
517 mask = u32(mask >> u32(start_offset))
518 output.field[(end - start - 1) / slot_size] |= mask
519 }
520 return output
521}
522
523// reverse reverses the order of bits in the array (swap the first with the last, the second with the last but one and so on).
524pub fn (instance BitField) reverse() BitField {
525 size := instance.size
526 bitnslots := zbitnslots(size)
527 mut output := new(size)
528 for i := 0; i < (bitnslots - 1); i++ {
529 for j in 0 .. slot_size {
530 if u32(instance.field[i] >> u32(j)) & u32(1) == u32(1) {
531 output.set_bit(size - i * slot_size - j - 1)
532 }
533 }
534 }
535 bits_in_last_input_slot := (size - 1) % slot_size + 1
536 for j in 0 .. bits_in_last_input_slot {
537 if u32(instance.field[bitnslots - 1] >> u32(j)) & u32(1) == u32(1) {
538 output.set_bit(bits_in_last_input_slot - j - 1)
539 }
540 }
541 return output
542}
543
544// resize changes the size of the bit array to 'new_size'.
545pub fn (mut instance BitField) resize(new_size int) {
546 new_bitnslots := zbitnslots(new_size)
547 old_size := instance.size
548 old_bitnslots := zbitnslots(old_size)
549 mut field := []u32{len: new_bitnslots}
550 for i := 0; i < old_bitnslots && i < new_bitnslots; i++ {
551 field[i] = instance.field[i]
552 }
553 instance.field = field.clone()
554 instance.size = new_size
555 if new_size < old_size && new_size % slot_size != 0 {
556 instance.clear_tail()
557 }
558}
559
560// rotate circular-shifts the bits by 'offset' positions (move 'offset' bit to 0, 'offset+1' bit to 1, and so on).
561pub fn (instance BitField) rotate(offset int) BitField {
562 /*
563 *
564 * This function "cuts" the bitfield into two and swaps them.
565 * If the offset is positive, the cutting point is counted from the
566 * beginning of the bit array, otherwise from the end.
567 *
568 */
569 size := instance.size
570 // removing extra rotations
571 mut offset_internal := offset % size
572 if offset_internal == 0 {
573 // nothing to shift
574 return instance
575 }
576 if offset_internal < 0 {
577 offset_internal = offset_internal + size
578 }
579 first_chunk := instance.slice(0, offset_internal)
580 second_chunk := instance.slice(offset_internal, size)
581 output := join(second_chunk, first_chunk)
582 return output
583}
584
585// shift_left shift-left the bits by `count` positions.
586pub fn (instance BitField) shift_left(count int) BitField {
587 size := instance.size
588 if count <= 0 {
589 return instance
590 } else if count >= size {
591 // return zeroes
592 return new(size)
593 }
594 zeroes := new(count)
595 return join(instance.slice(count, size), zeroes)
596}
597
598// shift_right shift-right the bits by `count` positions.
599pub fn (instance BitField) shift_right(count int) BitField {
600 size := instance.size
601 if count <= 0 {
602 return instance
603 } else if count >= size {
604 // return zeroes
605 return new(size)
606 }
607 zeroes := new(count)
608 return join(zeroes, instance.slice(0, size - count))
609}
610
611// Internal functions
612// clear_tail clears the extra bits that are not part of the bitfield, but yet are allocated
613@[inline]
614fn (mut instance BitField) clear_tail() {
615 tail := instance.size % slot_size
616 if tail != 0 {
617 // create a mask for the tail
618 mask := u32((1 << tail) - 1)
619 // clear the extra bits
620 instance.field[zbitnslots(instance.size) - 1] = instance.field[zbitnslots(instance.size) - 1] & mask
621 }
622}
623
624// bitmask is the bitmask needed to access a particular bit at offset bitnr
625@[inline]
626fn bitmask(bitnr int) u32 {
627 return u32(u32(1) << u32(bitnr % slot_size))
628}
629
630// bitslot is the slot index (i.e. the integer) where a particular bit is located
631@[inline]
632fn bitslot(size int) int {
633 return size / slot_size
634}
635
636// min returns the minimum of 2 integers; it is here to avoid importing math just for that
637@[inline]
638fn min(input1 int, input2 int) int {
639 if input1 < input2 {
640 return input1
641 } else {
642 return input2
643 }
644}
645
646// zbitnslots returns the minimum number of whole integers, needed to represent a bitfield of size length
647@[inline]
648fn zbitnslots(length int) int {
649 return (length - 1) / slot_size + 1
650}
651