blob: 592bfc245c73ebf393085a72c334f1a910ac6bd7 [file] [log] [blame]
Harald Welteec8b4502010-02-20 20:34:29 +01001/* bit vector utility routines */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
Maxa15f05f2016-01-26 10:43:15 +01004 * (C) 2012 Ivan Klyuchnikov
Jacob Erlbeck5f349be2015-12-21 16:04:03 +01005 * (C) 2015 by Sysmocom s.f.m.c. GmbH
Harald Welteec8b4502010-02-20 20:34:29 +01006 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
Harald Welteba6988b2011-08-17 12:46:48 +020025/*! \addtogroup bitvec
26 * @{
27 */
28
29/*! \file bitvec.c
30 * \brief Osmocom bit vector abstraction
31 */
Harald Welteec8b4502010-02-20 20:34:29 +010032
33#include <errno.h>
34#include <stdint.h>
Jacob Erlbeck5f349be2015-12-21 16:04:03 +010035#include <string.h>
Maxa15f05f2016-01-26 10:43:15 +010036#include <stdio.h>
Max0a59e982016-02-05 13:55:37 +010037#include <stdbool.h>
Harald Welteec8b4502010-02-20 20:34:29 +010038
Max0a59e982016-02-05 13:55:37 +010039#include <osmocom/core/bits.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010040#include <osmocom/core/bitvec.h>
Harald Welteec8b4502010-02-20 20:34:29 +010041
42#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
43
44static inline unsigned int bytenum_from_bitnum(unsigned int bitnum)
45{
46 unsigned int bytenum = bitnum / 8;
47
48 return bytenum;
49}
50
51/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */
52static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum)
53{
54 int bitval;
55
56 switch (bit) {
57 case ZERO:
58 bitval = (0 << bitnum);
59 break;
60 case ONE:
61 bitval = (1 << bitnum);
62 break;
63 case L:
64 bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum));
65 break;
66 case H:
67 bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum));
68 break;
69 default:
70 return 0;
71 }
72 return bitval;
73}
74
Harald Welteba6988b2011-08-17 12:46:48 +020075/*! \brief check if the bit is 0 or 1 for a given position inside a bitvec
76 * \param[in] bv the bit vector on which to check
77 * \param[in] bitnr the bit number inside the bit vector to check
78 * \returns
79 */
Harald Welted9abf012010-03-06 11:28:49 +010080enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr)
Harald Welteec8b4502010-02-20 20:34:29 +010081{
82 unsigned int bytenum = bytenum_from_bitnum(bitnr);
83 unsigned int bitnum = 7 - (bitnr % 8);
84 uint8_t bitval;
85
86 if (bytenum >= bv->data_len)
87 return -EINVAL;
88
89 bitval = bitval2mask(ONE, bitnum);
90
91 if (bv->data[bytenum] & bitval)
92 return ONE;
93
94 return ZERO;
95}
96
Harald Welteba6988b2011-08-17 12:46:48 +020097/*! \brief check if the bit is L or H for a given position inside a bitvec
98 * \param[in] bv the bit vector on which to check
99 * \param[in] bitnr the bit number inside the bit vector to check
100 */
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +0000101enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
102 unsigned int bitnr)
103{
104 unsigned int bytenum = bytenum_from_bitnum(bitnr);
105 unsigned int bitnum = 7 - (bitnr % 8);
106 uint8_t bitval;
107
108 if (bytenum >= bv->data_len)
109 return -EINVAL;
110
111 bitval = bitval2mask(H, bitnum);
112
Andreas.Eversbergdc0ebdf2010-10-24 11:59:33 +0200113 if ((bv->data[bytenum] & (1 << bitnum)) == bitval)
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +0000114 return H;
115
116 return L;
117}
118
Harald Welteba6988b2011-08-17 12:46:48 +0200119/*! \brief get the Nth set bit inside the bit vector
120 * \param[in] bv the bit vector to use
121 * \param[in] n the bit number to get
122 * \returns the bit number (offset) of the Nth set bit in \a bv
123 */
Harald Welted9abf012010-03-06 11:28:49 +0100124unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n)
Harald Welteec8b4502010-02-20 20:34:29 +0100125{
126 unsigned int i, k = 0;
127
128 for (i = 0; i < bv->data_len*8; i++) {
129 if (bitvec_get_bit_pos(bv, i) == ONE) {
130 k++;
131 if (k == n)
132 return i;
133 }
134 }
135
136 return 0;
137}
138
Harald Welteba6988b2011-08-17 12:46:48 +0200139/*! \brief set a bit at given position in a bit vector
140 * \param[in] bv bit vector on which to operate
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100141 * \param[in] bitnr number of bit to be set
Harald Welteba6988b2011-08-17 12:46:48 +0200142 * \param[in] bit value to which the bit is to be set
Max912bc6f2016-01-28 12:07:12 +0100143 * \returns 0 on success, negative value on error
Harald Welteba6988b2011-08-17 12:46:48 +0200144 */
Harald Welteec8b4502010-02-20 20:34:29 +0100145int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
146 enum bit_value bit)
147{
148 unsigned int bytenum = bytenum_from_bitnum(bitnr);
149 unsigned int bitnum = 7 - (bitnr % 8);
150 uint8_t bitval;
151
152 if (bytenum >= bv->data_len)
153 return -EINVAL;
154
155 /* first clear the bit */
156 bitval = bitval2mask(ONE, bitnum);
157 bv->data[bytenum] &= ~bitval;
158
159 /* then set it to desired value */
160 bitval = bitval2mask(bit, bitnum);
161 bv->data[bytenum] |= bitval;
162
163 return 0;
164}
165
Harald Welteba6988b2011-08-17 12:46:48 +0200166/*! \brief set the next bit inside a bitvec
167 * \param[in] bv bit vector to be used
168 * \param[in] bit value of the bit to be set
Max912bc6f2016-01-28 12:07:12 +0100169 * \returns 0 on success, negative value on error
Harald Welteba6988b2011-08-17 12:46:48 +0200170 */
Harald Welteec8b4502010-02-20 20:34:29 +0100171int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
172{
173 int rc;
174
175 rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
176 if (!rc)
177 bv->cur_bit++;
178
179 return rc;
180}
181
Harald Welteba6988b2011-08-17 12:46:48 +0200182/*! \brief get the next bit (low/high) inside a bitvec */
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +0000183int bitvec_get_bit_high(struct bitvec *bv)
184{
185 int rc;
186
187 rc = bitvec_get_bit_pos_high(bv, bv->cur_bit);
188 if (rc >= 0)
189 bv->cur_bit++;
190
191 return rc;
192}
193
Harald Welteba6988b2011-08-17 12:46:48 +0200194/*! \brief set multiple bits (based on array of bitvals) at current pos
195 * \param[in] bv bit vector
196 * \param[in] bits array of \ref bit_value
197 * \param[in] count number of bits to set
198 */
Maxe49af082016-01-22 16:46:56 +0100199int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, unsigned int count)
Harald Welteec8b4502010-02-20 20:34:29 +0100200{
201 int i, rc;
202
203 for (i = 0; i < count; i++) {
204 rc = bitvec_set_bit(bv, bits[i]);
205 if (rc)
206 return rc;
207 }
208
209 return 0;
210}
211
Harald Welteba6988b2011-08-17 12:46:48 +0200212/*! \brief set multiple bits (based on numeric value) at current pos */
Maxe49af082016-01-22 16:46:56 +0100213int bitvec_set_uint(struct bitvec *bv, unsigned int ui, unsigned int num_bits)
Harald Welteec8b4502010-02-20 20:34:29 +0100214{
Maxe49af082016-01-22 16:46:56 +0100215 int rc;
216 unsigned i;
Harald Welteec8b4502010-02-20 20:34:29 +0100217 for (i = 0; i < num_bits; i++) {
218 int bit = 0;
219 if (ui & (1 << (num_bits - i - 1)))
220 bit = 1;
221 rc = bitvec_set_bit(bv, bit);
222 if (rc)
223 return rc;
224 }
225
226 return 0;
227}
228
Max0a59e982016-02-05 13:55:37 +0100229/*! \brief get multiple bits (num_bits) from beginning of vector (MSB side) */
230int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits)
231{
232 if (num_bits > 15 || bv->cur_bit < num_bits)
233 return -EINVAL;
234
235 if (num_bits < 9)
236 return bv->data[0] >> (8 - num_bits);
237
238 return osmo_load16be(bv->data) >> (16 - num_bits);
239}
240
Harald Welteba6988b2011-08-17 12:46:48 +0200241/*! \brief get multiple bits (based on numeric value) from current pos */
Maxe49af082016-01-22 16:46:56 +0100242int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits)
Andreas.Eversberg0ebd6882010-05-09 09:36:54 +0000243{
244 int i;
245 unsigned int ui = 0;
246
247 for (i = 0; i < num_bits; i++) {
248 int bit = bitvec_get_bit_pos(bv, bv->cur_bit);
249 if (bit < 0)
250 return bit;
251 if (bit)
252 ui |= (1 << (num_bits - i - 1));
253 bv->cur_bit++;
254 }
255
256 return ui;
257}
258
Max0a59e982016-02-05 13:55:37 +0100259/*! \brief fill num_bits with \fill starting from the current position
260 * returns 0 on success, negative otherwise (out of vector boundary)
261 */
262int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill)
263{
264 unsigned i, stop = bv->cur_bit + num_bits;
265 for (i = bv->cur_bit; i < stop; i++)
266 if (bitvec_set_bit(bv, fill) < 0)
267 return -EINVAL;
268
269 return 0;
270}
271
Harald Welteba6988b2011-08-17 12:46:48 +0200272/*! \brief pad all remaining bits up to num_bits */
Harald Welteec8b4502010-02-20 20:34:29 +0100273int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
274{
Max0a59e982016-02-05 13:55:37 +0100275 int n = up_to_bit - bv->cur_bit + 1;
276 if (n < 1)
277 return 0;
Harald Welteec8b4502010-02-20 20:34:29 +0100278
Max0a59e982016-02-05 13:55:37 +0100279 return bitvec_fill(bv, n, L);
Harald Welteec8b4502010-02-20 20:34:29 +0100280}
Pablo Neira Ayuso36bdf2c2011-03-28 19:24:19 +0200281
Harald Welteba6988b2011-08-17 12:46:48 +0200282/*! \brief find first bit set in bit vector */
Pablo Neira Ayuso36bdf2c2011-03-28 19:24:19 +0200283int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n,
284 enum bit_value val)
285{
286 unsigned int i;
287
288 for (i = n; i < bv->data_len*8; i++) {
289 if (bitvec_get_bit_pos(bv, i) == val)
290 return i;
291 }
292
293 return -1;
294}
Harald Welteba6988b2011-08-17 12:46:48 +0200295
Jacob Erlbeck5f349be2015-12-21 16:04:03 +0100296/*! \brief get multiple bytes from current pos
297 * Assumes MSB first encoding.
298 * \param[in] bv bit vector
299 * \param[in] bytes array
300 * \param[in] count number of bytes to copy
301 */
Maxe49af082016-01-22 16:46:56 +0100302int bitvec_get_bytes(struct bitvec *bv, uint8_t *bytes, unsigned int count)
Jacob Erlbeck5f349be2015-12-21 16:04:03 +0100303{
304 int byte_offs = bytenum_from_bitnum(bv->cur_bit);
305 int bit_offs = bv->cur_bit % 8;
306 uint8_t c, last_c;
307 int i;
308 uint8_t *src;
309
310 if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
311 return -EINVAL;
312
313 if (bit_offs == 0) {
314 memcpy(bytes, bv->data + byte_offs, count);
315 } else {
316 src = bv->data + byte_offs;
317 last_c = *(src++);
318 for (i = count; i > 0; i--) {
319 c = *(src++);
320 *(bytes++) =
321 (last_c << bit_offs) |
322 (c >> (8 - bit_offs));
323 last_c = c;
324 }
325 }
326
327 bv->cur_bit += count * 8;
328 return 0;
329}
330
331/*! \brief set multiple bytes at current pos
332 * Assumes MSB first encoding.
333 * \param[in] bv bit vector
334 * \param[in] bytes array
335 * \param[in] count number of bytes to copy
336 */
Maxe49af082016-01-22 16:46:56 +0100337int bitvec_set_bytes(struct bitvec *bv, const uint8_t *bytes, unsigned int count)
Jacob Erlbeck5f349be2015-12-21 16:04:03 +0100338{
339 int byte_offs = bytenum_from_bitnum(bv->cur_bit);
340 int bit_offs = bv->cur_bit % 8;
341 uint8_t c, last_c;
342 int i;
343 uint8_t *dst;
344
345 if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
346 return -EINVAL;
347
348 if (bit_offs == 0) {
349 memcpy(bv->data + byte_offs, bytes, count);
350 } else if (count > 0) {
351 dst = bv->data + byte_offs;
352 /* Get lower bits of first dst byte */
353 last_c = *dst >> (8 - bit_offs);
354 for (i = count; i > 0; i--) {
355 c = *(bytes++);
356 *(dst++) =
357 (last_c << (8 - bit_offs)) |
358 (c >> bit_offs);
359 last_c = c;
360 }
361 /* Overwrite lower bits of N+1 dst byte */
362 *dst = (*dst & ((1 << (8 - bit_offs)) - 1)) |
363 (last_c << (8 - bit_offs));
364 }
365
366 bv->cur_bit += count * 8;
367 return 0;
368}
Maxa15f05f2016-01-26 10:43:15 +0100369
370struct bitvec *bitvec_alloc(unsigned int size, TALLOC_CTX *ctx)
371{
372 struct bitvec *bv = talloc_zero(ctx, struct bitvec);
373 if (!bv)
374 return NULL;
375
376 bv->data = talloc_zero_array(bv, uint8_t, size);
377 if (!(bv->data)) {
378 talloc_free(bv);
379 return NULL;
380 }
381
382 bv->data_len = size;
383 bv->cur_bit = 0;
384 return bv;
385}
386
387void bitvec_free(struct bitvec *bv)
388{
389 talloc_free(bv->data);
390 talloc_free(bv);
391}
392
393unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer)
394{
395 unsigned int i = 0;
396 for (i = 0; i < bv->data_len; i++)
397 buffer[i] = bv->data[i];
398
399 return i;
400}
401
402unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer)
403{
404 unsigned int i = 0;
405 for (i = 0; i < bv->data_len; i++)
406 bv->data[i] = buffer[i];
407
408 return i;
409}
410
411
412int bitvec_unhex(struct bitvec *bv, const char *src)
413{
Holger Hans Peter Freyther2745b482016-01-27 17:08:02 +0100414 unsigned i;
Maxa15f05f2016-01-26 10:43:15 +0100415 unsigned val;
416 unsigned write_index = 0;
417 unsigned digits = bv->data_len * 2;
Holger Hans Peter Freyther2745b482016-01-27 17:08:02 +0100418
419 for (i = 0; i < digits; i++) {
Maxa15f05f2016-01-26 10:43:15 +0100420 if (sscanf(src + i, "%1x", &val) < 1) {
421 return 1;
422 }
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100423 bitvec_write_field(bv, &write_index, val, 4);
Maxa15f05f2016-01-26 10:43:15 +0100424 }
425 return 0;
426}
427
Max912bc6f2016-01-28 12:07:12 +0100428/*! \brief read part of the vector
429 * \param[in] bv The boolean vector to work on
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100430 * \param[in,out] read_index Where reading supposed to start in the vector
Max912bc6f2016-01-28 12:07:12 +0100431 * \param[in] len How many bits to read from vector
432 * \returns read bits or negative value on error
433 */
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100434uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len)
Maxa15f05f2016-01-26 10:43:15 +0100435{
436 unsigned int i;
437 uint64_t ui = 0;
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100438 bv->cur_bit = *read_index;
Maxa15f05f2016-01-26 10:43:15 +0100439
440 for (i = 0; i < len; i++) {
441 int bit = bitvec_get_bit_pos((const struct bitvec *)bv, bv->cur_bit);
442 if (bit < 0)
443 return bit;
444 if (bit)
445 ui |= ((uint64_t)1 << (len - i - 1));
446 bv->cur_bit++;
447 }
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100448 *read_index += len;
Maxa15f05f2016-01-26 10:43:15 +0100449 return ui;
450}
451
Max912bc6f2016-01-28 12:07:12 +0100452/*! \brief write into the vector
453 * \param[in] bv The boolean vector to work on
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100454 * \param[in,out] write_index Where writing supposed to start in the vector
Max912bc6f2016-01-28 12:07:12 +0100455 * \param[in] len How many bits to write
456 * \returns next write index or negative value on error
457 */
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100458int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len)
Maxa15f05f2016-01-26 10:43:15 +0100459{
460 unsigned int i;
461 int rc;
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100462 bv->cur_bit = *write_index;
Maxa15f05f2016-01-26 10:43:15 +0100463 for (i = 0; i < len; i++) {
464 int bit = 0;
465 if (val & ((uint64_t)1 << (len - i - 1)))
466 bit = 1;
467 rc = bitvec_set_bit(bv, bit);
468 if (rc)
469 return rc;
470 }
Holger Hans Peter Freythera9301a12016-01-30 10:54:43 +0100471 *write_index += len;
Maxa15f05f2016-01-26 10:43:15 +0100472 return 0;
473}
474
Max0a59e982016-02-05 13:55:37 +0100475/*! \brief convert enum to corresponding character */
476char bit_value_to_char(enum bit_value v)
477{
478 switch (v) {
479 case ZERO: return '0';
480 case ONE: return '1';
481 case L: return 'L';
482 case H: return 'H';
483 default: abort();
484 }
485}
486
487/*! \brief prints bit vector to provided string
488 * It's caller's responsibility to ensure that we won't shoot him in the foot:
489 * the provided buffer should be at lest cur_bit + 1 bytes long
490 */
491void bitvec_to_string_r(const struct bitvec *bv, char *str)
492{
493 unsigned i, pos = 0;
494 char *cur = str;
495 for (i = 0; i < bv->cur_bit; i++) {
496 if (0 == i % 8)
497 *cur++ = ' ';
498 *cur++ = bit_value_to_char(bitvec_get_bit_pos(bv, i));
499 pos++;
500 }
501 *cur = 0;
502}
503
504/* we assume that x have at least 1 non-b bit */
505static inline unsigned leading_bits(uint8_t x, bool b)
506{
507 if (b) {
508 if (x < 0x80) return 0;
509 if (x < 0xC0) return 1;
510 if (x < 0xE0) return 2;
511 if (x < 0xF0) return 3;
512 if (x < 0xF8) return 4;
513 if (x < 0xFC) return 5;
514 if (x < 0xFE) return 6;
515 } else {
516 if (x > 0x7F) return 0;
517 if (x > 0x3F) return 1;
518 if (x > 0x1F) return 2;
519 if (x > 0xF) return 3;
520 if (x > 7) return 4;
521 if (x > 3) return 5;
522 if (x > 1) return 6;
523 }
524 return 7;
525}
526/*! \brief force bit vector to all 0 and current bit to the beginnig of the vector */
527void bitvec_zero(struct bitvec *bv)
528{
529 bv->cur_bit = 0;
530 memset(bv->data, 0, bv->data_len);
531}
532
533/*! \brief Return number (bits) of uninterrupted bit run in vector starting from the MSB
534 * \param[in] bv The boolean vector to work on
535 * \param[in] b The boolean, sequence of which is looked at from the vector start
536 * \returns Number of consecutive bits of \p b in \p bv
537 */
538unsigned bitvec_rl(const struct bitvec *bv, bool b)
539{
540 unsigned i;
541 for (i = 0; i < (bv->cur_bit % 8 ? bv->cur_bit / 8 + 1 : bv->cur_bit / 8); i++) {
542 if ( (b ? 0xFF : 0) != bv->data[i])
543 return i * 8 + leading_bits(bv->data[i], b);
544 }
545
546 return bv->cur_bit;
547}
548
549/*! \brief Shifts bitvec to the left, n MSB bits lost */
550void bitvec_shiftl(struct bitvec *bv, unsigned n)
551{
552 if (0 == n)
553 return;
554 if (n >= bv->cur_bit) {
555 bitvec_zero(bv);
556 return;
557 }
558
559 memmove(bv->data, bv->data + n / 8, bv->data_len - n / 8);
560
561 uint8_t tmp[2];
562 unsigned i;
563 for (i = 0; i < bv->data_len - 2; i++) {
564 uint16_t t = osmo_load16be(bv->data + i);
565 osmo_store16be(t << (n % 8), &tmp);
566 bv->data[i] = tmp[0];
567 }
568
569 bv->data[bv->data_len - 1] <<= (n % 8);
570 bv->cur_bit -= n;
571}
572
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200573/*! @} */