1
0

2 Commits dd9cc95647 ... bfa9d55bc1

Autor SHA1 Mensagem Data
  Kajetan Johannes Hammerle bfa9d55bc1 Simpler list swap há 2 semanas atrás
  Kajetan Johannes Hammerle 142a564630 BitArray and tests há 2 semanas atrás
6 ficheiros alterados com 394 adições e 44 exclusões
  1. 3 3
      CMakeLists.txt
  2. 27 0
      include/core/BitArray.h
  3. 168 0
      src/BitArray.c
  4. 3 40
      src/List.c
  5. 1 1
      test/Main.c
  6. 192 0
      test/modules/BitArrayTests.c

+ 3 - 3
CMakeLists.txt

@@ -4,6 +4,7 @@ project(core)
 set(CMAKE_C_STANDARD 23)
 
 set(SRC
+    "src/BitArray.c"
     "src/Box.c"
     "src/Buffer.c"
     "src/Frustum.c"
@@ -17,12 +18,12 @@ set(SRC
     "src/Utility.c"
     "src/Vector.c"
     "src/View.c"
-    #"src/BitArray.cpp"
 )
 
 set(SRC_TESTS
     "test/Main.c"
     "test/Test.c"
+    "test/modules/BitArrayTests.c"
     "test/modules/BoxTests.c"
     "test/modules/BufferTests.c"
     "test/modules/FrustumTests.c"
@@ -35,7 +36,6 @@ set(SRC_TESTS
     "test/modules/UtilityTests.c"
     "test/modules/VectorTests.c"
     "test/modules/ViewTests.c"
-    #"test/modules/BitArrayTests.cpp"
     #"test/modules/ComponentsTests.cpp"
     #"test/modules/HashMapTests.cpp"
     #"test/modules/LinkedListTests.cpp"
@@ -97,6 +97,7 @@ target_sources(core PUBLIC
     FILE_SET HEADERS
     BASE_DIRS include
     FILES 
+        ./include/core/BitArray.h
         ./include/core/Box.h
         ./include/core/Buffer.h
         ./include/core/Check.h
@@ -111,7 +112,6 @@ target_sources(core PUBLIC
         ./include/core/Types.h
         ./include/core/Utility.h
         ./include/core/View.h
-#        ./include/core/BitArray.hpp
 #        ./include/core/Components.hpp
 #        ./include/core/HashMap.hpp
 #        ./include/core/LinkedList.hpp

+ 27 - 0
include/core/BitArray.h

@@ -0,0 +1,27 @@
+#ifndef CORE_BIT_ARRAY_H
+#define CORE_BIT_ARRAY_H
+
+#include "core/Types.h"
+
+typedef struct {
+    u64 length : 56;
+    u64 bits : 8;
+    u64* data;
+} CoreBitArray;
+
+static_assert(sizeof(CoreBitArray) == 16, "wusi");
+
+#define CORE_BIT_ARRAY ((CoreBitArray){0, 0, nullptr})
+void coreCopyBitArray(CoreBitArray* a, const CoreBitArray* other);
+void coreMoveBitArray(CoreBitArray* a, CoreBitArray* other);
+void coreDestroyBitArray(CoreBitArray* a);
+CoreBitArray* coreBitArraySet(CoreBitArray* a, size_t index, u64 value);
+u64 coreBitArrayGet(const CoreBitArray* a, size_t index);
+size_t coreBitArrayBytes(const CoreBitArray* a);
+i64 coreBitArraySelect(const CoreBitArray* a, size_t index);
+void coreResizeBitArray(CoreBitArray* a, size_t newLength, size_t newBits);
+void coreFillBitArray(CoreBitArray* a, u64 value);
+size_t coreToStringBitArray(const CoreBitArray* a, char* buffer, size_t n);
+void coreSwapBitArray(CoreBitArray* a, CoreBitArray* b);
+
+#endif

+ 168 - 0
src/BitArray.c

@@ -0,0 +1,168 @@
+#include "core/BitArray.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "core/Utility.h"
+
+static u64 roundUpDivide(u64 a, u64 b) {
+    return a / b + ((a % b) != 0);
+}
+
+#define U64_BITS 64
+#define DIVIDE_BITS 6
+
+static u64 readBits(const u64* data, size_t index, u64 bits) {
+    u64 dataIndexA = (index * bits) >> DIVIDE_BITS;
+    u64 dataIndexB = ((index * bits) + (bits - 1lu)) >> DIVIDE_BITS;
+    u64 shifts = (index * bits) & (U64_BITS - 1lu);
+    if(dataIndexA == dataIndexB) {
+        return (data[dataIndexA] >> shifts) & ((1lu << bits) - 1lu);
+    }
+    u64 bitsInA = U64_BITS - shifts;
+    u64 r = (data[dataIndexA] >> shifts) & ((1lu << bitsInA) - 1lu);
+    r |= (data[dataIndexB] & ((1lu << (bits - bitsInA)) - 1lu)) << bitsInA;
+    return r;
+}
+
+static void setBits(u64* data, size_t index, size_t bits, u64 value) {
+    u64 mask = (1lu << bits) - 1lu;
+    value &= mask;
+    u64 dataIndexA = (index * bits) >> DIVIDE_BITS;
+    u64 dataIndexB = ((index * bits) + (bits - 1lu)) >> DIVIDE_BITS;
+    u64 shifts = (index * bits) & (U64_BITS - 1lu);
+    data[dataIndexA] &= ~(mask << shifts);
+    data[dataIndexA] |= (value << shifts);
+    if(dataIndexA != dataIndexB) {
+        u64 leftBits = bits - (U64_BITS - shifts);
+        data[dataIndexB] &= ~((1lu << leftBits) - 1lu);
+        data[dataIndexB] |= (value >> (U64_BITS - shifts));
+    }
+}
+
+static size_t getArrayLength(size_t length, size_t bits) {
+    return roundUpDivide(length * bits, U64_BITS);
+}
+
+void coreCopyBitArray(CoreBitArray* a, const CoreBitArray* other) {
+    if(a == other) {
+        return;
+    }
+    coreResizeBitArray(a, other->length, other->bits);
+    size_t length = a->length;
+    for(size_t i = 0; i < length; i++) {
+        coreBitArraySet(a, i, coreBitArrayGet(other, i));
+    }
+}
+
+void coreMoveBitArray(CoreBitArray* a, CoreBitArray* other) {
+    if(a == other) {
+        return;
+    }
+    coreSwapBitArray(a, other);
+    coreDestroyBitArray(other);
+}
+
+void coreDestroyBitArray(CoreBitArray* a) {
+    coreFree(a->data);
+    *a = CORE_BIT_ARRAY;
+}
+
+CoreBitArray* coreBitArraySet(CoreBitArray* a, size_t index, u64 value) {
+    assert(a->data != nullptr);
+    assert(index < a->length);
+    setBits(a->data, index, a->bits, value);
+    return a;
+}
+
+u64 coreBitArrayGet(const CoreBitArray* a, size_t index) {
+    assert(a->data != nullptr);
+    assert(index < a->length);
+    return readBits(a->data, index, a->bits);
+}
+
+size_t coreBitArrayBytes(const CoreBitArray* a) {
+    if(a->length <= 0 || a->bits <= 0) {
+        return 0;
+    }
+    return getArrayLength(a->length, a->bits) * sizeof(u64);
+}
+
+i64 coreBitArraySelect(const CoreBitArray* a, size_t index) {
+    if(index <= 0) {
+        return -1;
+    }
+    u64 found = 0;
+    size_t end = getArrayLength(a->length, a->bits);
+    for(size_t i = 0; i < end; i++) {
+        u64 ones = corePopCount(a->data[i]);
+        found += ones;
+        if(found >= index) {
+            found -= ones;
+            u64 c = i * U64_BITS - 1;
+            u64 d = a->data[i];
+            while(found < index) {
+                found += d & 1;
+                d >>= 1;
+                c++;
+            }
+            return (i64)c;
+        }
+    }
+    return -1;
+}
+
+void coreResizeBitArray(CoreBitArray* a, size_t newLength, size_t newBits) {
+    if(newLength == 0 || newBits == 0) {
+        coreDestroyBitArray(a);
+        return;
+    } else if(newBits > 64) {
+        newBits = 64;
+    }
+    size_t arrayLength = getArrayLength(newLength, newBits);
+    u64* newData = coreAllocate(sizeof(u64) * arrayLength);
+    memset(newData, 0, arrayLength * sizeof(u64));
+
+    size_t end = coreMinSize(a->length, newLength);
+    for(size_t i = 0; i < end; i++) {
+        setBits(newData, i, newBits, coreBitArrayGet(a, i));
+    }
+    for(size_t i = end; i < newLength; i++) {
+        setBits(newData, i, newBits, 0);
+    }
+    coreFree(a->data);
+    a->data = newData;
+    a->length = newLength;
+    a->bits = newBits;
+}
+
+void coreFillBitArray(CoreBitArray* a, u64 value) {
+    size_t length = a->length;
+    for(size_t i = 0; i < length; i++) {
+        coreBitArraySet(a, i, value);
+    }
+}
+
+size_t coreToStringBitArray(const CoreBitArray* a, char* buffer, size_t n) {
+    size_t w = 0;
+    coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, "["));
+    size_t length = a->length;
+    if(length > 0) {
+        length--;
+        for(size_t i = 0; i < length; i++) {
+            coreStringAddI(&w, &buffer, &n,
+                           snprintf(buffer, n, "%lu, ", coreBitArrayGet(a, i)));
+        }
+        coreStringAddI(&w, &buffer, &n,
+                       snprintf(buffer, n, "%lu", coreBitArrayGet(a, length)));
+    }
+    coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, "]"));
+    return w;
+}
+
+void coreSwapBitArray(CoreBitArray* a, CoreBitArray* b) {
+    CoreBitArray tmp = *a;
+    *a = *b;
+    *b = tmp;
+}

+ 3 - 40
src/List.c

@@ -142,44 +142,7 @@ size_t coreToStringList(CoreList* l, char* buffer, size_t n, CoreToString c) {
 }
 
 void coreSwapList(CoreList* a, CoreList* b) {
-    coreSwapSize(&a->length, &b->length);
-    coreSwapSize(&a->capacity, &b->capacity);
-    coreSwapSize(&a->dataSize, &b->dataSize);
-    coreSwapPointer(&a->data, &b->data);
+    CoreList tmp = *a;
+    *a = *b;
+    *b = tmp;
 }
-
-/*
-    T* begin() {
-        return data;
-    }
-
-    T* end() {
-        return data + length;
-    }
-
-    const T* begin() const {
-        return data;
-    }
-
-    const T* end() const {
-        return data + length;
-    }
-
-    void resize(size_t n) {
-        if(length < n) {
-            reserve(n);
-            for(size_t i = n - length; i != 0; i--) {
-                unsafeAdd(T());
-            }
-        } else if(length > n) {
-            for(size_t i = n; i < length; i++) {
-                data[i].~T();
-            }
-            length = n;
-        }
-    }
-
-    void toString(BufferString& s) const {
-        Core::toString(s, *this);
-    }
-};*/

+ 1 - 1
test/Main.c

@@ -31,7 +31,7 @@ int main(int argAmount, const char** args) {
         }
     }
 
-    // coreTestBitArray();
+    coreTestBitArray();
     // coreTestComponents();
     // coreTestHashMap(light);
     // coreTestLinkedList(light);

+ 192 - 0
test/modules/BitArrayTests.c

@@ -0,0 +1,192 @@
+#include "../Tests.h"
+#include "core/BitArray.h"
+
+static void testSetRead() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    coreResizeBitArray(&bits, 4, 3);
+    coreBitArraySet(&bits, 0, 1);
+    coreBitArraySet(&bits, 1, 2);
+    coreBitArraySet(&bits, 2, 3);
+    coreBitArraySet(&bits, 3, 4);
+    CORE_TEST_U64(1, coreBitArrayGet(&bits, 0));
+    CORE_TEST_U64(2, coreBitArrayGet(&bits, 1));
+    CORE_TEST_U64(3, coreBitArrayGet(&bits, 2));
+    CORE_TEST_U64(4, coreBitArrayGet(&bits, 3));
+    coreDestroyBitArray(&bits);
+}
+
+static void testBigSetRead() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    coreResizeBitArray(&bits, 100, 13);
+    for(size_t i = 0; i < bits.length; i++) {
+        coreBitArraySet(&bits, i, i);
+    }
+    for(size_t i = 0; i < bits.length; i++) {
+        CORE_TEST_U64(i, coreBitArrayGet(&bits, i));
+    }
+    coreDestroyBitArray(&bits);
+}
+
+static void testRandomSetReadResize() {
+    u64 data[100];
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    coreResizeBitArray(&bits, 100, 13);
+    u64 seed = 534;
+    for(int k = 0; k < 20; k++) {
+        for(u64 i = 0; i < bits.length; i++) {
+            seed = seed * 636455 + 53453;
+            coreBitArraySet(&bits, i, seed);
+            data[i] = seed & 0x1FFF;
+        }
+    }
+    for(size_t i = 0; i < bits.length; i++) {
+        CORE_TEST_U64(data[i], coreBitArrayGet(&bits, i));
+    }
+    coreResizeBitArray(&bits, bits.length, bits.bits + 1);
+    CORE_TEST_U64(14, bits.bits);
+    CORE_TEST_U64(100, bits.length);
+    for(size_t i = 0; i < bits.length; i++) {
+        CORE_TEST_U64(data[i], coreBitArrayGet(&bits, i));
+    }
+    coreDestroyBitArray(&bits);
+}
+
+static void testCopy() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    coreResizeBitArray(&bits, 4, 3);
+    coreBitArraySet(&bits, 0, 1);
+    coreBitArraySet(&bits, 1, 2);
+    coreBitArraySet(&bits, 2, 3);
+    coreBitArraySet(&bits, 3, 4);
+    CoreBitArray copy = CORE_BIT_ARRAY;
+    coreCopyBitArray(&copy, &bits);
+    CORE_TEST_U64(1, coreBitArrayGet(&copy, 0));
+    CORE_TEST_U64(2, coreBitArrayGet(&copy, 1));
+    CORE_TEST_U64(3, coreBitArrayGet(&copy, 2));
+    CORE_TEST_U64(4, coreBitArrayGet(&copy, 3));
+    coreDestroyBitArray(&copy);
+    coreDestroyBitArray(&bits);
+}
+
+static void testSelect() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    coreResizeBitArray(&bits, 90, 1);
+    coreFillBitArray(&bits, 0);
+    coreBitArraySet(&bits, 0, 1);
+    coreBitArraySet(&bits, 5, 1);
+    coreBitArraySet(&bits, 20, 1);
+    coreBitArraySet(&bits, 31, 1);
+    coreBitArraySet(&bits, 32, 1);
+    coreBitArraySet(&bits, 33, 1);
+    coreBitArraySet(&bits, 60, 1);
+    CORE_TEST_I64(-1, coreBitArraySelect(&bits, 0));
+    CORE_TEST_I64(0, coreBitArraySelect(&bits, 1));
+    CORE_TEST_I64(5, coreBitArraySelect(&bits, 2));
+    CORE_TEST_I64(20, coreBitArraySelect(&bits, 3));
+    CORE_TEST_I64(31, coreBitArraySelect(&bits, 4));
+    CORE_TEST_I64(32, coreBitArraySelect(&bits, 5));
+    CORE_TEST_I64(33, coreBitArraySelect(&bits, 6));
+    CORE_TEST_I64(60, coreBitArraySelect(&bits, 7));
+    CORE_TEST_I64(-1, coreBitArraySelect(&bits, 8));
+    coreDestroyBitArray(&bits);
+}
+
+static void testToString1() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    coreResizeBitArray(&bits, 4, 3);
+    coreBitArraySet(&bits, 0, 1);
+    coreBitArraySet(&bits, 1, 2);
+    coreBitArraySet(&bits, 2, 3);
+    coreBitArraySet(&bits, 3, 4);
+    char buffer[128];
+    size_t n = coreToStringBitArray(&bits, buffer, sizeof(buffer));
+    CORE_TEST_SIZE(12, n);
+    CORE_TEST_STRING("[1, 2, 3, 4]", buffer);
+    coreDestroyBitArray(&bits);
+}
+
+static void testToString2() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    coreResizeBitArray(&bits, 1, 3);
+    coreBitArraySet(&bits, 0, 1);
+    char buffer[128];
+    size_t n = coreToStringBitArray(&bits, buffer, sizeof(buffer));
+    CORE_TEST_SIZE(3, n);
+    CORE_TEST_STRING("[1]", buffer);
+    coreDestroyBitArray(&bits);
+}
+
+static void testToString3() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    char buffer[128];
+    size_t n = coreToStringBitArray(&bits, buffer, sizeof(buffer));
+    CORE_TEST_SIZE(2, n);
+    CORE_TEST_STRING("[]", buffer);
+    coreDestroyBitArray(&bits);
+}
+
+static void testResizeExact() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    CORE_TEST_U64(0, coreBitArrayBytes(&bits));
+    // the size in bytes matches the internal storage type
+    size_t elements = sizeof(u64);
+    coreResizeBitArray(&bits, elements, 8);
+    for(size_t i = 0; i < elements; i++) {
+        coreBitArraySet(&bits, i, i);
+    }
+    for(size_t i = 0; i < elements; i++) {
+        CORE_TEST_U64(i, coreBitArrayGet(&bits, i));
+    }
+    CORE_TEST_U64(sizeof(u64), coreBitArrayBytes(&bits));
+    coreDestroyBitArray(&bits);
+}
+
+static void testMove() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    coreResizeBitArray(&bits, 8, 8);
+    for(size_t i = 0; i < bits.length; i++) {
+        coreBitArraySet(&bits, i, i);
+    }
+    CoreBitArray m = CORE_BIT_ARRAY;
+    coreMoveBitArray(&m, &bits);
+    CORE_TEST_U64(8, m.length);
+    for(size_t i = 0; i < m.length; i++) {
+        CORE_TEST_U64(i, coreBitArrayGet(&m, i));
+    }
+    coreDestroyBitArray(&m);
+    coreDestroyBitArray(&bits);
+}
+
+static void testInvalidArgument() {
+    CoreBitArray bits = CORE_BIT_ARRAY;
+    coreResizeBitArray(&bits, 0, 5);
+    CORE_TEST_SIZE(0, bits.length);
+    CORE_TEST_SIZE(0, bits.bits);
+    coreResizeBitArray(&bits, 5, 0);
+    CORE_TEST_SIZE(0, bits.length);
+    CORE_TEST_SIZE(0, bits.bits);
+    coreResizeBitArray(&bits, 0, 0);
+    CORE_TEST_SIZE(0, bits.length);
+    CORE_TEST_SIZE(0, bits.bits);
+    coreResizeBitArray(&bits, 1, 65);
+    CORE_TEST_SIZE(1, bits.length);
+    CORE_TEST_SIZE(64, bits.bits);
+    coreResizeBitArray(&bits, 5, 68);
+    CORE_TEST_SIZE(5, bits.length);
+    CORE_TEST_SIZE(64, bits.bits);
+    coreDestroyBitArray(&bits);
+}
+
+void coreTestBitArray() {
+    testSetRead();
+    testBigSetRead();
+    testRandomSetReadResize();
+    testCopy();
+    testSelect();
+    testToString1();
+    testToString2();
+    testToString3();
+    testResizeExact();
+    testMove();
+    testInvalidArgument();
+}