diff --git a/lib/std/collections/bitmap.c3 b/lib/std/collections/bitmap.c3 new file mode 100644 index 000000000..f710cadab --- /dev/null +++ b/lib/std/collections/bitmap.c3 @@ -0,0 +1,73 @@ +/** + * @require Type.kindof == UNSIGNED_INT + **/ +module std::collections::bitmap(); +import std::collections::list; + +def BitmapList = List(); + +struct Bitmap +{ + BitmapList data; +} + +fn void Bitmap.init(&self, usz initial_capacity = 1, Allocator* using = mem::heap()) +{ + self.data.init(initial_capacity, using); +} + +fn void Bitmap.tinit(&self) +{ + self.init(.using = mem::temp()); +} + +fn usz Bitmap.cardinality(&self) +{ + usz n; + foreach (x : self.data) + { + n += x.popcount(); + } + return n; +} + +fn void Bitmap.set(&self, usz i) +{ + usz q = i / Type.sizeof; + usz r = i % Type.sizeof; + if (q >= self.data.len()) + { + self.data.reserve(q + 1); + self.data.size = q + 1; + } + self.data.set(q, self.data[q] | (1 << r)); +} + +fn void Bitmap.unset(&self, usz i) +{ + usz q = i / Type.sizeof; + usz r = i % Type.sizeof; + if (q >= self.data.len()) return; + self.data.set(q, self.data[q] &~ (1 << r)); +} + +fn bool Bitmap.get(&self, usz i) @operator([]) @inline +{ + usz q = i / Type.sizeof; + usz r = i % Type.sizeof; + if (q >= self.data.len()) return false; + return self.data[q] & (1 << r) != 0; +} + +fn usz Bitmap.len(&self) @operator(len) +{ + usz n = self.data.len(); + if (n > 0) n -= self.data[n - 1].ctz(); + return n; +} + +fn void Bitmap.set_bool(&self, usz i, bool value) @operator([]=) @inline +{ + if (value) return self.set(i); + self.unset(i); +} \ No newline at end of file diff --git a/test/unit/stdlib/collections/bitmap.c3 b/test/unit/stdlib/collections/bitmap.c3 new file mode 100644 index 000000000..c4dc76ae4 --- /dev/null +++ b/test/unit/stdlib/collections/bitmap.c3 @@ -0,0 +1,46 @@ +module list_test @test; +import std::collections::bitmap; +import std::collections::list; +import std::io; + +def Bitmap = Bitmap(); +def List = List(); + +fn void! set_get() +{ + Bitmap bm; + bm.tinit(); + assert(bm.len() == 0); + + assert(!bm.get(0)); + bm.set(0); + assert(bm.get(0)); + assert(bm.cardinality() == 1); + + assert(!bm.get(2000)); + bm[2000] = true; + assert(bm.get(2000)); + assert(bm.cardinality() == 2); + + List found; + found.tinit(); + foreach (i, x : bm) + { + switch (i) + { + case 0: + case 2000: + assert(x); + found.push(i); + default: + assert(!x); + } + } + assert(found.array_view() == usz[]{0, 2000}); + + bm.unset(0); + assert(!bm.get(0)); + bm[2000] = false; + assert(!bm.get(2000)); + assert(bm.cardinality() == 0); +} \ No newline at end of file