Browse Source

bit array

Kajetan Johannes Hammerle 3 years ago
parent
commit
9f04c008ff
5 changed files with 208 additions and 1 deletions
  1. 13 0
      Main.cpp
  2. 1 1
      meson.build
  3. 75 0
      tests/BitArrayTests.cpp
  4. 8 0
      tests/BitArrayTests.h
  5. 111 0
      utils/BitArray.h

+ 13 - 0
Main.cpp

@@ -1,8 +1,21 @@
 #include "tests/HashMapTests.h"
 #include "tests/ListTests.h"
+#include "tests/BitArrayTests.h"
+#include "utils/BitArray.h"
+
+#include <iostream>
+
+void test(int i) {
+    for(int k = 0; k < 32; k++) {
+        std::cout << static_cast<char> ((i & 1) + '0');
+        i >>= 1;
+    }
+    std::cout << "\n";
+}
 
 int main() {
     HashMapTests::test();
     ListTests::test();
+    BitArrayTests::test();
     return 0;
 }

+ 1 - 1
meson.build

@@ -1,6 +1,6 @@
 project('gaming core tests', 'cpp')
 
-sources = ['Main.cpp', 'tests/Test.cpp', 'tests/HashMapTests.cpp', 'tests/ListTests.cpp']
+sources = ['Main.cpp', 'tests/Test.cpp', 'tests/HashMapTests.cpp', 'tests/ListTests.cpp', 'tests/BitArrayTests.cpp']
 
 executable('tests', 
     sources: sources,

+ 75 - 0
tests/BitArrayTests.cpp

@@ -0,0 +1,75 @@
+#include "tests/BitArrayTests.h"
+#include "tests/Test.h"
+#include "utils/BitArray.h"
+
+static void testSetRead(Test& test) {
+    BitArray<4, 3> bits;
+    bits[0] = 1;
+    bits[1] = 2;
+    bits[2] = 3;
+    bits[3] = 4;
+    test.checkEqual(1, static_cast<int> (bits[0]), "set and read correct value");
+    test.checkEqual(2, static_cast<int> (bits[1]), "set and read correct value");
+    test.checkEqual(3, static_cast<int> (bits[2]), "set and read correct value");
+    test.checkEqual(4, static_cast<int> (bits[3]), "set and read correct value");
+}
+
+static void testBigSetRead(Test& test) {
+    BitArray<100, 13> bits;
+    for(int i = 0; i < bits.getLength(); i++) {
+        bits[i] = i;
+    }
+    for(int i = 0; i < bits.getLength(); i++) {
+        test.checkEqual(i, static_cast<int> (bits[i]), "set and read correct value over long array");
+    }
+}
+
+static void testRandomSetRead(Test& test) {
+    const int length = 100;
+    int data[length];
+    BitArray<100, 13> bits;
+    int seed = 534;
+    for(int k = 0; k < 20; k++) {
+        for(int i = 0; i < bits.getLength(); i++) {
+            seed = seed * 636455 + 53453;
+            bits[i] = seed & (0x1FFF);
+            data[i] = seed & (0x1FFF);
+        }
+    }
+    for(int i = 0; i < bits.getLength(); i++) {
+        test.checkEqual(data[i], static_cast<int> (bits[i]), "set and read correct value with random input");
+    }
+}
+
+static void testReadOnly(Test& test) {
+    BitArray<4, 3> bits;
+    bits[0] = 1;
+    bits[1] = 2;
+    bits[2] = 3;
+    bits[3] = 4;
+    const BitArray<4, 3> bits2 = bits;
+    test.checkEqual(1, bits2[0], "can read from const");
+    test.checkEqual(2, bits2[1], "can read from const");
+    test.checkEqual(3, bits2[2], "can read from const");
+    test.checkEqual(4, bits2[3], "can read from const");
+}
+
+static void testChainedSet(Test& test) {
+    BitArray<4, 3> bits;
+    bits[0] = bits[2] = bits[3] = 2;
+    bits[3] = bits[1] = 7;
+    test.checkEqual(2, static_cast<int>(bits[0]), "chained set sets correct value");
+    test.checkEqual(7, static_cast<int>(bits[1]), "chained set sets correct value");
+    test.checkEqual(2, static_cast<int>(bits[2]), "chained set sets correct value");
+    test.checkEqual(7, static_cast<int>(bits[3]), "chained set sets correct value");
+}
+
+void BitArrayTests::test() {
+    Test test("BitArray");
+    testSetRead(test);
+    testBigSetRead(test);
+    testRandomSetRead(test);
+    testReadOnly(test);
+    testChainedSet(test);
+    test.finalize();
+}

+ 8 - 0
tests/BitArrayTests.h

@@ -0,0 +1,8 @@
+#ifndef BITARRAYTESTS_H
+#define BITARRAYTESTS_H
+
+namespace BitArrayTests {
+    void test();
+}
+
+#endif

+ 111 - 0
utils/BitArray.h

@@ -0,0 +1,111 @@
+#ifndef BITARRAY_H
+#define BITARRAY_H
+
+#include <iostream>
+
+template<int N, int BITS>
+class BitArray final {
+    static constexpr int INT_BITS = sizeof (int) * 8;
+
+    static_assert(BITS >= 1, "each bit array element must have at least one bit");
+    static_assert(BITS <= INT_BITS, "each bit array element can have at most as much bits as an int");
+
+    static constexpr int MASK = (1 << BITS) - 1;
+    static constexpr int LENGTH = (N * BITS) / INT_BITS + (((N * BITS) % INT_BITS) > 0);
+
+    constexpr static int getDivideBits() {
+        int c = 0;
+        int i = INT_BITS - 1;
+        while(i > 0) {
+            i >>= 1;
+            c++;
+        }
+        return c;
+    }
+
+    static constexpr int DIVIDE_BITS = getDivideBits();
+
+    int data[LENGTH];
+
+    static int readBits(const int* data, int index) {
+        int dataIndexA = (index * BITS) >> DIVIDE_BITS;
+        int dataIndexB = ((index + 1) * BITS) >> DIVIDE_BITS;
+        int shifts = (index * BITS) & (INT_BITS - 1);
+        if(dataIndexA == dataIndexB) {
+            return (data[dataIndexA] >> shifts) & MASK;
+        }
+        int bitsInA = INT_BITS - shifts;
+        int r = (data[dataIndexA] >> shifts) & ((1 << bitsInA) - 1);
+        r |= (data[dataIndexB] & ((1 << (BITS - bitsInA)) - 1)) << bitsInA;
+        return r;
+    }
+
+public:
+
+    class BitInt {
+        friend BitArray;
+
+        int* data;
+        int index;
+
+        BitInt(int* data, int index) : data(data), index(index) {
+        }
+
+        BitInt(const BitInt& other) = default;
+        BitInt(BitInt&& other) = default;
+
+    public:
+
+        BitInt& operator=(const BitInt& other) {
+            return (*this) = static_cast<int> (other);
+        }
+
+        BitInt& operator=(BitInt&& other) {
+            return (*this) = static_cast<int> (other);
+        }
+
+        BitInt& operator=(int i) {
+            i &= MASK;
+            int dataIndexA = (index * BITS) >> DIVIDE_BITS;
+            int dataIndexB = ((index + 1) * BITS) >> DIVIDE_BITS;
+            int shifts = (index * BITS) & (INT_BITS - 1);
+            data[dataIndexA] &= ~(MASK << shifts);
+            data[dataIndexA] |= (i << shifts);
+            if(dataIndexA != dataIndexB) {
+                int leftBits = BITS - (INT_BITS - shifts);
+                int mask = (1 << leftBits) - 1;
+                data[dataIndexB] &= ~mask;
+                data[dataIndexB] |= (i >> (INT_BITS - shifts));
+            }
+            return *this;
+        }
+
+        operator int() const {
+            return readBits(data, index);
+        }
+    };
+
+    BitArray(int bits = 0) {
+        fill(bits);
+    }
+
+    void fill(int bits) {
+        for(int i = 0; i < N; i++) {
+            (*this)[i] = bits;
+        }
+    }
+
+    BitInt operator[](int index) {
+        return BitInt(data, index);
+    }
+
+    int operator[](int index) const {
+        return readBits(data, index);
+    }
+
+    constexpr int getLength() const {
+        return N;
+    }
+};
+
+#endif