summaryrefslogtreecommitdiff
path: root/lib/bitmap.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2023-09-18 14:12:22 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2023-10-04 13:07:33 +0200
commite338c4b63c6a9258d858f158049943e1e8f00e6f (patch)
tree2bdf6767e32edbbb12d75760ed8be9f1ed623471 /lib/bitmap.c
parentbcff3ae79acfd938459869ac98db4f83e3d422b6 (diff)
Lib: Extend MPLS label allocator bitmap
Add function lmap_last_one_in_range() for finding the last active label in a label range.
Diffstat (limited to 'lib/bitmap.c')
-rw-r--r--lib/bitmap.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/lib/bitmap.c b/lib/bitmap.c
index 60883cf2..c036f80d 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -398,6 +398,81 @@ lmap_first_zero_in_range(struct lmap *b, uint lo, uint hi)
return hi;
}
+static inline int
+b1024_last_one(u32 *p)
+{
+ for (int i = 31; i >= 0; i--)
+ if (p[i])
+ return 32*i + (31 - u32_clz(p[i]));
+
+ return 1024;
+}
+
+static uint
+b1024_last_one_in_range(u32 *p, uint lo, uint hi)
+{
+ uint lo0 = lo >> 5;
+ uint lo1 = lo & 0x1f;
+ uint hi0 = hi >> 5;
+ uint hi1 = hi & 0x1f;
+ u32 mask = (1u << hi1) - 1;
+ u32 val;
+
+ for (int i = hi0; i > (int) lo0; i--)
+ {
+ val = p[i] & mask;
+ mask = ~0;
+
+ if (val)
+ return 32*i + (31 - u32_clz(val));
+ }
+
+ {
+ mask &= ~((1u << lo1) - 1);
+ val = p[lo0] & mask;
+
+ if (val)
+ return 32*lo0 + (31 - u32_clz(val));
+ }
+
+ return hi;
+}
+
+uint
+lmap_last_one_in_range(struct lmap *b, uint lo, uint hi)
+{
+ uint lo0 = lo >> 10;
+ uint lo1 = lo & 0x3ff;
+ uint hi0 = hi >> 10;
+ uint hi1 = hi & 0x3ff;
+
+ if (hi1 && (hi0 < b->size) && b->data[hi0])
+ {
+ uint min = (lo0 == hi0) ? lo1 : 0;
+ uint n0 = hi0;
+ uint n1 = b1024_last_one_in_range(b->data[n0], min, hi1);
+
+ if (n1 < hi1)
+ return (n0 << 10) + n1;
+ }
+
+ for (int i = (int)MIN(hi0, b->size) - 1; i >= (int) lo0; i--)
+ {
+ if (! b->data[i])
+ continue;
+
+ uint n0 = i;
+ uint n1 = b1024_last_one(b->data[n0]);
+
+ if ((n0 == lo0) && (n1 < lo1))
+ return hi;
+
+ return (n0 << 10) + n1;
+ }
+
+ return hi;
+}
+
void
lmap_check(struct lmap *b)
{