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