back to topotato report
topotato coverage report
Current view: top level - lib - bitfield.h (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 0 50 0.0 %
Date: 2023-11-16 17:19:14 Functions: 0 6 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /* Bitfields
       3             :  * Copyright (C) 2016 Cumulus Networks, Inc.
       4             :  */
       5             : /**
       6             :  * A simple bit array implementation to allocate and free IDs. An example
       7             :  * of its usage is in allocating link state IDs for OSPFv3 as OSPFv3 has
       8             :  * removed all address semantics from LS ID. Another usage can be in
       9             :  * allocating IDs for BGP neighbors (and dynamic update groups) for
      10             :  * efficient storage of adj-rib-out.
      11             :  *
      12             :  * An example:
      13             :  * #include "bitfield.h"
      14             :  *
      15             :  * bitfield_t bitfield;
      16             :  *
      17             :  * bf_init(bitfield, 32);
      18             :  * ...
      19             :  * bf_assign_index(bitfield, id1);
      20             :  * bf_assign_index(bitfield, id2);
      21             :  * ...
      22             :  * bf_release_index(bitfield, id1);
      23             :  */
      24             : 
      25             : #ifndef _BITFIELD_H
      26             : #define _BITFIELD_H
      27             : 
      28             : #include <stdio.h>
      29             : #include <string.h>
      30             : #include <stdlib.h>
      31             : 
      32             : #ifdef __cplusplus
      33             : extern "C" {
      34             : #endif
      35             : 
      36             : typedef unsigned int word_t;
      37             : #define WORD_MAX 0xFFFFFFFF
      38             : #define WORD_SIZE (sizeof(word_t) * 8)
      39             : 
      40             : /**
      41             :  * The bitfield structure.
      42             :  * @data: the bits to manage.
      43             :  * @n: The current word number that is being used.
      44             :  * @m: total number of words in 'data'
      45             :  */
      46             : typedef struct {word_t *data; size_t n, m; } bitfield_t;
      47             : 
      48             : DECLARE_MTYPE(BITFIELD);
      49             : 
      50             : /**
      51             :  * Initialize the bits.
      52             :  * @v: an instance of bitfield_t struct.
      53             :  * @N: number of bits to start with, which equates to how many
      54             :  *     IDs can be allocated.
      55             :  */
      56             : #define bf_init(v, N)                                                          \
      57             :         do {                                                                   \
      58             :                 (v).n = 0;                                                     \
      59             :                 (v).m = ((N) / WORD_SIZE + 1);                                 \
      60             :                 (v).data = (word_t *)XCALLOC(MTYPE_BITFIELD,                   \
      61             :                                              ((v).m * sizeof(word_t)));        \
      62             :         } while (0)
      63             : 
      64             : /**
      65             :  * allocate and assign an id from bitfield v.
      66             :  */
      67             : #define bf_assign_index(v, id)                                                 \
      68             :         do {                                                                   \
      69             :                 bf_find_bit(v, id);                                            \
      70             :                 bf_set_bit(v, id);                                             \
      71             :         } while (0)
      72             : 
      73             : /*
      74             :  * allocate and assign 0th bit in the bitfiled.
      75             :  */
      76             : #define bf_assign_zero_index(v)                                                \
      77             :         do {                                                                   \
      78             :                 int id = 0;                                                    \
      79             :                 bf_assign_index(v, id);                                        \
      80             :         } while (0)
      81             : 
      82             : /*
      83             :  * return an id to bitfield v
      84             :  */
      85             : #define bf_release_index(v, id)                                                \
      86             :         (v).data[bf_index(id)] &= ~(1 << (bf_offset(id)))
      87             : 
      88             : /* check if an id is in use */
      89             : #define bf_test_index(v, id)                                                \
      90             :         ((v).data[bf_index(id)] & (1 << (bf_offset(id))))
      91             : 
      92             : /* check if the bit field has been setup */
      93             : #define bf_is_inited(v) ((v).data)
      94             : 
      95             : /* compare two bitmaps of the same length */
      96             : #define bf_cmp(v1, v2) (memcmp((v1).data, (v2).data, ((v1).m * sizeof(word_t))))
      97             : 
      98             : /*
      99             :  * return 0th index back to bitfield
     100             :  */
     101             : #define bf_release_zero_index(v) bf_release_index(v, 0)
     102             : 
     103             : #define bf_index(b) ((b) / WORD_SIZE)
     104             : #define bf_offset(b) ((b) % WORD_SIZE)
     105             : 
     106             : /**
     107             :  * Set a bit in the array. If it fills up that word and we are
     108             :  * out of words, extend it by one more word.
     109             :  */
     110             : #define bf_set_bit(v, b)                                                       \
     111             :         do {                                                                   \
     112             :                 size_t w = bf_index(b);                                        \
     113             :                 (v).data[w] |= 1 << (bf_offset(b));                            \
     114             :                 (v).n += ((v).data[w] == WORD_MAX);                            \
     115             :                 if ((v).n == (v).m) {                                          \
     116             :                         (v).m = (v).m + 1;                                     \
     117             :                         (v).data = XREALLOC(MTYPE_BITFIELD, (v).data,          \
     118             :                                             (v).m * sizeof(word_t));           \
     119             :                 }                                                              \
     120             :         } while (0)
     121             : 
     122             : /* Find a clear bit in v and assign it to b. */
     123             : #define bf_find_bit(v, b)                                                      \
     124             :         do {                                                                   \
     125             :                 word_t word = 0;                                               \
     126             :                 unsigned int w, sh;                                            \
     127             :                 for (w = 0; w <= (v).n; w++) {                                 \
     128             :                         if ((word = (v).data[w]) != WORD_MAX)                  \
     129             :                                 break;                                         \
     130             :                 }                                                              \
     131             :                 (b) = ((word & 0xFFFF) == 0xFFFF) << 4;                        \
     132             :                 word >>= (b);                                                  \
     133             :                 sh = ((word & 0xFF) == 0xFF) << 3;                             \
     134             :                 word >>= sh;                                                   \
     135             :                 (b) |= sh;                                                     \
     136             :                 sh = ((word & 0xF) == 0xF) << 2;                               \
     137             :                 word >>= sh;                                                   \
     138             :                 (b) |= sh;                                                     \
     139             :                 sh = ((word & 0x3) == 0x3) << 1;                               \
     140             :                 word >>= sh;                                                   \
     141             :                 (b) |= sh;                                                     \
     142             :                 sh = ((word & 0x1) == 0x1) << 0;                               \
     143             :                 word >>= sh;                                                   \
     144             :                 (b) |= sh;                                                     \
     145             :                 (b) += (w * WORD_SIZE);                                        \
     146             :         } while (0)
     147             : 
     148             : /*
     149             :  * Find a clear bit in v and return it
     150             :  * Start looking in the word containing bit position start_index.
     151             :  * If necessary, wrap around after bit position max_index.
     152             :  */
     153             : static inline unsigned int
     154           0 : bf_find_next_clear_bit_wrap(bitfield_t *v, word_t start_index, word_t max_index)
     155             : {
     156           0 :         int start_bit;
     157           0 :         unsigned long i, offset, scanbits, wordcount_max, index_max;
     158             : 
     159           0 :         if (start_index > max_index)
     160           0 :                 start_index = 0;
     161             : 
     162           0 :         start_bit = start_index & (WORD_SIZE - 1);
     163           0 :         wordcount_max = bf_index(max_index) + 1;
     164             : 
     165           0 :         scanbits = WORD_SIZE;
     166           0 :         for (i = bf_index(start_index); i < v->m; ++i) {
     167           0 :                 if (v->data[i] == WORD_MAX) {
     168             :                         /* if the whole word is full move to the next */
     169           0 :                         start_bit = 0;
     170           0 :                         continue;
     171             :                 }
     172             :                 /* scan one word for clear bits */
     173           0 :                 if ((i == v->m - 1) && (v->m >= wordcount_max))
     174             :                         /* max index could be only part of word */
     175           0 :                         scanbits = (max_index % WORD_SIZE) + 1;
     176           0 :                 for (offset = start_bit; offset < scanbits; ++offset) {
     177           0 :                         if (!((v->data[i] >> offset) & 1))
     178           0 :                                 return ((i * WORD_SIZE) + offset);
     179             :                 }
     180             :                 /* move to the next word */
     181             :                 start_bit = 0;
     182             :         }
     183             : 
     184           0 :         if (v->m < wordcount_max) {
     185             :                 /*
     186             :                  * We can expand bitfield, so no need to wrap.
     187             :                  * Return the index of the first bit of the next word.
     188             :                  * Assumption is that caller will call bf_set_bit which
     189             :                  * will allocate additional space.
     190             :                  */
     191           0 :                 v->m += 1;
     192           0 :                 v->data = (word_t *)XREALLOC(MTYPE_BITFIELD, v->data,
     193             :                                              v->m * sizeof(word_t));
     194           0 :                 v->data[v->m - 1] = 0;
     195           0 :                 return v->m * WORD_SIZE;
     196             :         }
     197             : 
     198             :         /*
     199             :          * start looking for a clear bit at the start of the bitfield and
     200             :          * stop when we reach start_index
     201             :          */
     202           0 :         scanbits = WORD_SIZE;
     203           0 :         index_max = bf_index(start_index - 1);
     204           0 :         for (i = 0; i <= index_max; ++i) {
     205           0 :                 if (i == index_max)
     206           0 :                         scanbits = ((start_index - 1) % WORD_SIZE) + 1;
     207           0 :                 for (offset = start_bit; offset < scanbits; ++offset) {
     208           0 :                         if (!((v->data[i] >> offset) & 1))
     209           0 :                                 return ((i * WORD_SIZE) + offset);
     210             :                 }
     211             :                 /* move to the next word */
     212           0 :                 start_bit = 0;
     213             :         }
     214             : 
     215             :         return WORD_MAX;
     216             : }
     217             : 
     218           0 : static inline unsigned int bf_find_next_set_bit(bitfield_t v,
     219             :                 word_t start_index)
     220             : {
     221           0 :         int start_bit;
     222           0 :         unsigned long i, offset;
     223             : 
     224           0 :         start_bit = start_index & (WORD_SIZE - 1);
     225             : 
     226           0 :         for (i = bf_index(start_index); i < v.m; ++i) {
     227           0 :                 if (v.data[i] == 0) {
     228             :                         /* if the whole word is empty move to the next */
     229           0 :                         start_bit = 0;
     230           0 :                         continue;
     231             :                 }
     232             :                 /* scan one word for set bits */
     233           0 :                 for (offset = start_bit; offset < WORD_SIZE; ++offset) {
     234           0 :                         if ((v.data[i] >> offset) & 1)
     235           0 :                                 return ((i * WORD_SIZE) + offset);
     236             :                 }
     237             :                 /* move to the next word */
     238             :                 start_bit = 0;
     239             :         }
     240             :         return WORD_MAX;
     241             : }
     242             : 
     243             : /* iterate through all the set bits */
     244             : #define bf_for_each_set_bit(v, b, max)                 \
     245             :         for ((b) = bf_find_next_set_bit((v), 0);           \
     246             :                         (b) < max;                                 \
     247             :                         (b) = bf_find_next_set_bit((v), (b) + 1))
     248             : 
     249             : /*
     250             :  * Free the allocated memory for data
     251             :  * @v: an instance of bitfield_t struct.
     252             :  */
     253             : #define bf_free(v)                                                             \
     254             :         do {                                                                   \
     255             :                 XFREE(MTYPE_BITFIELD, (v).data);                               \
     256             :                 (v).data = NULL;                                               \
     257             :         } while (0)
     258             : 
     259           0 : static inline bitfield_t bf_copy(bitfield_t src)
     260             : {
     261           0 :         bitfield_t dst;
     262             : 
     263           0 :         assert(bf_is_inited(src));
     264           0 :         bf_init(dst, WORD_SIZE * (src.m - 1));
     265           0 :         for (size_t i = 0; i < src.m; i++)
     266           0 :                 dst.data[i] = src.data[i];
     267           0 :         dst.n = src.n;
     268           0 :         return dst;
     269             : }
     270             : 
     271             : 
     272             : #ifdef __cplusplus
     273             : }
     274             : #endif
     275             : 
     276             : #endif

Generated by: LCOV version v1.16-topotato