aboutsummaryrefslogtreecommitdiff
path: root/src/NonStupidBitfield.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/NonStupidBitfield.h')
-rw-r--r--src/NonStupidBitfield.h149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/NonStupidBitfield.h b/src/NonStupidBitfield.h
new file mode 100644
index 0000000..124ba76
--- /dev/null
+++ b/src/NonStupidBitfield.h
@@ -0,0 +1,149 @@
+#ifndef NONSTUPIDBITFIELD_H
+#define NONSTUPIDBITFIELD_H
+
+#include "types.h"
+
+#include <memory.h>
+
+#include <initializer_list>
+#include <algorithm>
+
+// like std::bitset but less stupid and optimised for
+// our use case (keeping track of memory invalidations)
+
+template <u32 Size>
+struct NonStupidBitField
+{
+ static_assert((Size % 8) == 0, "bitfield size must be a multiple of 8");
+ static const u32 DataLength = Size / 8;
+ u8 Data[DataLength];
+
+ struct Ref
+ {
+ NonStupidBitField<Size>& BitField;
+ u32 Idx;
+
+ operator bool()
+ {
+ return BitField.Data[Idx >> 3] & (1 << (Idx & 0x7));
+ }
+
+ Ref& operator=(bool set)
+ {
+ BitField.Data[Idx >> 3] &= ~(1 << (Idx & 0x7));
+ BitField.Data[Idx >> 3] |= ((u8)set << (Idx & 0x7));
+ return *this;
+ }
+ };
+
+ struct Iterator
+ {
+ NonStupidBitField<Size>& BitField;
+ u32 DataIdx;
+ u32 BitIdx;
+ u64 RemainingBits;
+
+ u32 operator*() { return DataIdx * 8 + BitIdx; }
+
+ bool operator==(const Iterator& other) { return other.DataIdx == DataIdx; }
+ bool operator!=(const Iterator& other) { return other.DataIdx != DataIdx; }
+
+ template <typename T>
+ void Next()
+ {
+ while (RemainingBits == 0 && DataIdx < DataLength)
+ {
+ DataIdx += sizeof(T);
+ RemainingBits = *(T*)&BitField.Data[DataIdx];
+ }
+
+ BitIdx = __builtin_ctzll(RemainingBits);
+ RemainingBits &= ~(1ULL << BitIdx);
+ }
+
+ Iterator operator++(int)
+ {
+ Iterator prev(*this);
+ ++*this;
+ return prev;
+ }
+
+ Iterator& operator++()
+ {
+ if ((DataLength % 8) == 0)
+ Next<u64>();
+ else if ((DataLength % 4) == 0)
+ Next<u32>();
+ else if ((DataLength % 2) == 0)
+ Next<u16>();
+ else
+ Next<u8>();
+
+ return *this;
+ }
+ };
+
+ NonStupidBitField(u32 start, u32 size)
+ {
+ memset(Data, 0, sizeof(Data));
+
+ if (size == 0)
+ return;
+
+ u32 roundedStartBit = (start + 7) & ~7;
+ u32 roundedEndBit = (start + size) & ~7;
+ if (roundedStartBit != roundedEndBit)
+ memset(Data + roundedStartBit / 8, 0xFF, (roundedEndBit - roundedStartBit) / 8);
+
+ if (start & 0x7)
+ Data[start >> 3] = 0xFF << (start & 0x7);
+ if ((start + size) & 0x7)
+ Data[(start + size) >> 3] = 0xFF >> ((start + size) & 0x7);
+ }
+
+ NonStupidBitField()
+ {
+ memset(Data, 0, sizeof(Data));
+ }
+
+ Iterator End()
+ {
+ return Iterator{*this, DataLength, 0, 0};
+ }
+ Iterator Begin()
+ {
+ if ((DataLength % 8) == 0)
+ return ++Iterator{*this, 0, 0, *(u64*)Data};
+ else if ((DataLength % 4) == 0)
+ return ++Iterator{*this, 0, 0, *(u32*)Data};
+ else if ((DataLength % 2) == 0)
+ return ++Iterator{*this, 0, 0, *(u16*)Data};
+ else
+ return ++Iterator{*this, 0, 0, *Data};
+ }
+
+ Ref operator[](u32 idx)
+ {
+ return Ref{*this, idx};
+ }
+
+ NonStupidBitField& operator|=(const NonStupidBitField<Size>& other)
+ {
+ for (u32 i = 0; i < DataLength; i++)
+ {
+ Data[i] |= other.Data[i];
+ }
+ return *this;
+ }
+ NonStupidBitField& operator&=(const NonStupidBitField<Size>& other)
+ {
+ for (u32 i = 0; i < DataLength; i++)
+ {
+ Data[i] &= other.Data[i];
+ }
+ return *this;
+ }
+};
+
+
+#endif \ No newline at end of file