1
0

16 Коммитууд 8751750989 ... e076804076

Эзэн SHA1 Мессеж Огноо
  Kajetan Johannes Hammerle e076804076 Merge with C core 3 сар өмнө
  Kajetan Johannes Hammerle 8751750989 WIP 3 сар өмнө
  Kajetan Johannes Hammerle 17d3a13663 WIP 3 сар өмнө
  Kajetan Johannes Hammerle 58381fc6b3 WIP 3 сар өмнө
  Kajetan Johannes Hammerle 4e373fac7e WIP 3 сар өмнө
  Kajetan Johannes Hammerle 4b8e261a11 WIP 3 сар өмнө
  Kajetan Johannes Hammerle 5fd09d85dd WIP 3 сар өмнө
  Kajetan Johannes Hammerle 0c424760e3 WIP 3 сар өмнө
  Kajetan Johannes Hammerle fadee0adc3 WIP 3 сар өмнө
  Kajetan Johannes Hammerle 2faa1bb228 WIP 3 сар өмнө
  Kajetan Johannes Hammerle d575a92e4f WIP 3 сар өмнө
  Kajetan Johannes Hammerle eae5d68d01 WIP 3 сар өмнө
  Kajetan Johannes Hammerle 94b32bf050 WIP 3 сар өмнө
  Kajetan Johannes Hammerle 0a9f3b8879 WIP 3 сар өмнө
  Kajetan Johannes Hammerle c3f8e6fd71 WIP 3 сар өмнө
  Kajetan Johannes Hammerle c24f4165ef Migrate C core 3 сар өмнө
86 өөрчлөгдсөн 2061 нэмэгдсэн , 4370 устгасан
  1. 1 0
      .gitignore
  2. 46 27
      CMakeLists.txt
  3. 30 7
      include/core/ArrayList.hpp
  4. 27 16
      include/core/BitArray.hpp
  5. 29 14
      include/core/Buffer.hpp
  6. 2 2
      include/core/Check.hpp
  7. 27 0
      include/core/Clock.hpp
  8. 9 7
      include/core/Color.hpp
  9. 136 121
      include/core/Components.hpp
  10. 2 2
      include/core/File.hpp
  11. 0 134
      include/core/Generic.hpp
  12. 54 57
      include/core/HashMap.hpp
  13. 5 6
      include/core/HashedString.hpp
  14. 47 41
      include/core/Logger.hpp
  15. 2 2
      include/core/Matrix.hpp
  16. 125 80
      include/core/Queue.hpp
  17. 2 2
      include/core/Random.hpp
  18. 8 6
      include/core/ReadLine.hpp
  19. 0 14
      include/core/SpinLock.hpp
  20. 41 4
      include/core/Thread.hpp
  21. 66 60
      include/core/ToString.hpp
  22. 2 5
      include/core/Utility.hpp
  23. 0 162
      old/BitArray.cpp
  24. 0 44
      old/BitArray.hpp
  25. 0 157
      old/BitArrayTests.cpp
  26. 0 63
      old/Buffer.cpp
  27. 0 38
      old/Buffer.hpp
  28. 0 69
      old/BufferTests.cpp
  29. 0 97
      old/BufferedValue.hpp
  30. 0 95
      old/BufferedValueTests.cpp
  31. 0 48
      old/Clock.cpp
  32. 0 30
      old/Clock.hpp
  33. 0 56
      old/ClockTests.cpp
  34. 0 63
      old/ColorTests.cpp
  35. 0 140
      old/Components.hpp
  36. 0 208
      old/ComponentsTests.cpp
  37. 0 8
      old/ErrorSimulator.cpp
  38. 0 19
      old/ErrorSimulator.hpp
  39. 0 281
      old/HashMap.hpp
  40. 0 72
      old/HashedStringTests.cpp
  41. 0 47
      old/MatrixStack.hpp
  42. 0 120
      old/MatrixStackTests.cpp
  43. 0 23
      old/Mutex.cpp
  44. 0 26
      old/Mutex.hpp
  45. 0 127
      old/RingBuffer.hpp
  46. 0 258
      old/RingBufferTests.cpp
  47. 0 22
      old/SpinLock.cpp
  48. 0 24
      old/SpinLock.hpp
  49. 0 57
      old/Stack.hpp
  50. 0 63
      old/StackTests.cpp
  51. 0 57
      old/Thread.cpp
  52. 0 27
      old/Thread.hpp
  53. 0 168
      old/ThreadTests.cpp
  54. 0 125
      old/performance/Main.cpp
  55. 34 41
      performance/Main.cpp
  56. 98 60
      src/BitArray.cpp
  57. 46 16
      src/Buffer.cpp
  58. 58 0
      src/Clock.cpp
  59. 0 4
      src/Components.cpp
  60. 2 0
      src/File.cpp
  61. 0 24
      src/HashMap.cpp
  62. 5 5
      src/Logger.cpp
  63. 48 77
      src/ReadLine.cpp
  64. 0 22
      src/SpinLock.cpp
  65. 1 0
      src/Terminal.cpp
  66. 74 8
      src/Thread.cpp
  67. 13 9
      src/ToString.cpp
  68. 12 42
      src/Utility.cpp
  69. 13 9
      test/Main.cpp
  70. 3 4
      test/Tests.hpp
  71. 56 37
      test/modules/ArrayListTests.cpp
  72. 102 106
      test/modules/BitArrayTests.cpp
  73. 68 15
      test/modules/BufferTests.cpp
  74. 62 0
      test/modules/ClockTests.cpp
  75. 64 0
      test/modules/ColorTests.cpp
  76. 102 95
      test/modules/ComponentsTests.cpp
  77. 4 4
      test/modules/FileTests.cpp
  78. 73 147
      test/modules/HashMapTests.cpp
  79. 67 0
      test/modules/HashedStringTests.cpp
  80. 223 92
      test/modules/QueueTests.cpp
  81. 17 37
      test/modules/ReadLineTests.cpp
  82. 0 74
      test/modules/SpinLockTests.cpp
  83. 2 2
      test/modules/TerminalTests.cpp
  84. 133 0
      test/modules/ThreadTests.cpp
  85. 20 39
      test/modules/UtilityTests.cpp
  86. BIN
      testData/readLineTest

+ 1 - 0
.gitignore

@@ -1,4 +1,5 @@
 build_debug
+build_profile
 build_release
 install
 profile

+ 46 - 27
CMakeLists.txt

@@ -4,23 +4,21 @@ project(core CXX)
 set(CMAKE_CXX_STANDARD 23)
 
 set(SRC
-    #"src/BitArray.cpp"
+    "src/BitArray.cpp"
     "src/Box.cpp"
-    #"src/Buffer.cpp"
-    #"src/Components.cpp"
+    "src/Buffer.cpp"
+    "src/Clock.cpp"
     "src/File.cpp"
     "src/Frustum.cpp"
-    "src/HashMap.cpp"
     "src/Logger.cpp"
     "src/Matrix.cpp"
     "src/Plane.cpp"
     "src/Quaternion.cpp"
     "src/Random.cpp"
-    #"src/ReadLine.cpp"
-    #"src/SpinLock.cpp"
+    "src/ReadLine.cpp"
     "src/Terminal.cpp"
     "src/Test.cpp"
-    #"src/Thread.cpp"
+    "src/Thread.cpp"
     "src/ToString.cpp"
     "src/Unicode.cpp"
     "src/Utility.cpp"
@@ -30,31 +28,34 @@ set(SRC
 
 set(SRC_TESTS
     "test/Main.cpp"
-    #"test/modules/BitArrayTests.cpp"
+    "test/modules/ArrayListTests.cpp"
+    "test/modules/ArrayTests.cpp"
+    "test/modules/BitArrayTests.cpp"
     "test/modules/BoxTests.cpp"
-    #"test/modules/BufferTests.cpp"
-    #"test/modules/ComponentsTests.cpp"
+    "test/modules/BufferTests.cpp"
+    "test/modules/ClockTests.cpp"
+    "test/modules/ColorTests.cpp"
+    "test/modules/ComponentsTests.cpp"
     "test/modules/FileTests.cpp"
     "test/modules/FrustumTests.cpp"
     "test/modules/HashMapTests.cpp"
-    #"test/modules/ListTests.cpp"
+    "test/modules/HashedStringTests.cpp"
+    "test/modules/ListTests.cpp"
+    "test/modules/MathTests.cpp"
     "test/modules/MatrixTests.cpp"
     "test/modules/PlaneTests.cpp"
     "test/modules/QuaternionTests.cpp"
-    #"test/modules/QueueTests.cpp"
+    "test/modules/QueueTests.cpp"
     "test/modules/RandomTests.cpp"
-    #"test/modules/ReadLineTests.cpp"
-    #"test/modules/SpinLockTests.cpp"
+    "test/modules/ReadLineTests.cpp"
     "test/modules/TerminalTests.cpp"
     "test/modules/TestTests.cpp"
+    "test/modules/ThreadTests.cpp"
     "test/modules/UnicodeTests.cpp"
-    "test/modules/UtilityTests.cpp"
-    "test/modules/ViewTests.cpp"
-    "test/modules/ListTests.cpp"
     "test/modules/UniquePointerTests.cpp"
+    "test/modules/UtilityTests.cpp"
     "test/modules/VectorTests.cpp"
-    "test/modules/MathTests.cpp"
-    "test/modules/ArrayTests.cpp"
+    "test/modules/ViewTests.cpp"
 )
 
 set(SRC_PERFORMANCE
@@ -65,7 +66,12 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
     set(COMPILE_OPTIONS "")
     set(LINK_OPTIONS "")
     set(LOG_LEVEL 2)
-    #set(DEFINITIONS CHECK_MEMORY)
+    set(DEFINITIONS "")
+elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
+    set(COMPILE_OPTIONS "")
+    set(LINK_OPTIONS "")
+    set(LOG_LEVEL 3)
+    set(DEFINITIONS CHECK_MEMORY)
 else()
     set(DEFINITIONS ERROR_SIMULATOR CHECK_MEMORY)
     if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
@@ -92,7 +98,7 @@ target_compile_options(core PUBLIC
     -fdiagnostics-color=always
 )
 target_compile_definitions(core
-    PUBLIC LOG_LEVEL=${LOG_LEVEL}
+    PRIVATE LOG_LEVEL=${LOG_LEVEL}
     PRIVATE ${DEFINITIONS}
 )
 target_link_libraries(core
@@ -102,30 +108,37 @@ target_sources(core PUBLIC
     FILE_SET HEADERS
     BASE_DIRS include
     FILES
+        ./include/core/AlignedData.hpp
+        ./include/core/Array.hpp
+        ./include/core/ArrayList.hpp
         ./include/core/BitArray.hpp
         ./include/core/Box.hpp
         ./include/core/Buffer.hpp
         ./include/core/Check.hpp
+        ./include/core/Clock.hpp
+        ./include/core/Color.hpp
         ./include/core/Components.hpp
         ./include/core/File.hpp
         ./include/core/Frustum.hpp
-        ./include/core/Generic.hpp
         ./include/core/HashMap.hpp
+        ./include/core/HashedString.hpp
         ./include/core/List.hpp
         ./include/core/Logger.hpp
+        ./include/core/Math.hpp
         ./include/core/Matrix.hpp
+        ./include/core/Meta.hpp
         ./include/core/Plane.hpp
         ./include/core/Quaternion.hpp
         ./include/core/Queue.hpp
         ./include/core/Random.hpp
         ./include/core/ReadLine.hpp
-        ./include/core/SpinLock.hpp
         ./include/core/Terminal.hpp
         ./include/core/Test.hpp
         ./include/core/Thread.hpp
         ./include/core/ToString.hpp
         ./include/core/Types.hpp
         ./include/core/Unicode.hpp
+        ./include/core/UniquePointer.hpp
         ./include/core/Utility.hpp
         ./include/core/Vector.hpp
         ./include/core/View.hpp
@@ -135,8 +148,14 @@ install(TARGETS core FILE_SET HEADERS)
 add_executable(test ${SRC_TESTS})
 target_link_libraries(test PRIVATE core)
 target_compile_definitions(test PRIVATE ${DEFINITIONS})
+target_compile_definitions(test
+    PRIVATE LOG_LEVEL=4
+)
 
-#add_executable(performance ${SRC_PERFORMANCE})
-#target_link_libraries(performance PRIVATE core)
-#target_include_directories(performance PRIVATE include)
-#target_compile_definitions(performance PRIVATE ${DEFINITIONS})
+add_executable(performance ${SRC_PERFORMANCE})
+target_link_libraries(performance PRIVATE core)
+target_include_directories(performance PRIVATE include)
+target_compile_definitions(performance PRIVATE ${DEFINITIONS})
+target_compile_definitions(performance
+    PRIVATE LOG_LEVEL=4
+)

+ 30 - 7
old/ArrayList.hpp → include/core/ArrayList.hpp

@@ -1,10 +1,10 @@
 #ifndef CORE_ARRAYLIST_HPP
 #define CORE_ARRAYLIST_HPP
 
-#include <assert.h>
+#include <cassert>
 
-#include "core/utils/AlignedData.hpp"
-#include "core/utils/ArrayString.hpp"
+#include "core/AlignedData.hpp"
+#include "core/Meta.hpp"
 
 namespace Core {
     template<typename T, size_t N>
@@ -84,10 +84,24 @@ namespace Core {
             return begin()[index];
         }
 
+        T& getLast() {
+            assert(length > 0);
+            return begin()[length - 1];
+        }
+
+        const T& getLast() const {
+            assert(length > 0);
+            return begin()[length - 1];
+        }
+
         size_t getLength() const {
             return length;
         }
 
+        consteval size_t getCapacity() const {
+            return N;
+        }
+
         void clear() {
             for(size_t i = 0; i < length; i++) {
                 begin()[i].~T();
@@ -104,12 +118,21 @@ namespace Core {
             begin()[length].~T();
         }
 
-        void removeLast() {
-            removeBySwap(length - 1);
+        void remove(size_t index) {
+            assert(index < length);
+            length--;
+            T* currentT = begin() + index;
+            T* endT = end();
+            while(currentT != endT) {
+                T* nextT = currentT + 1;
+                *currentT = Core::move(*nextT);
+                currentT = nextT;
+            }
+            endT->~T();
         }
 
-        void toString(BufferString& s) const {
-            Core::toString(s, *this);
+        void removeLast() {
+            removeBySwap(length - 1);
         }
 
     private:

+ 27 - 16
include/core/BitArray.hpp

@@ -1,23 +1,34 @@
-#ifndef CORE_BIT_ARRAY_H
-#define CORE_BIT_ARRAY_H
+#ifndef CORE_BIT_ARRAY_HPP
+#define CORE_BIT_ARRAY_HPP
 
 #include "core/Types.hpp"
 
-typedef struct {
-    u64 length : 56;
-    u64 bits : 8;
-    u64* data;
-} BitArray;
+namespace Core {
+    class BitArray final {
+        u64 length : 56;
+        u64 bits : 8;
+        u64* data;
 
-static_assert(sizeof(BitArray) == 16, "invalid bit array size");
+    public:
+        BitArray();
+        BitArray(const BitArray& other);
+        BitArray(BitArray&& other);
+        ~BitArray();
+        BitArray& operator=(BitArray other);
 
-void initBitArray(BitArray* a, size_t length, size_t bits);
-void destroyBitArray(BitArray* a);
-void setBits(BitArray* a, size_t index, u64 value);
-void setAllBits(BitArray* a, u64 value);
-u64 getBits(const BitArray* a, size_t index);
-i64 selectBits(const BitArray* a, size_t index);
-void setBitLength(BitArray* a, size_t newLength, size_t newBits);
-size_t toStringBitArray(const BitArray* a, char* buffer, size_t n);
+        BitArray& set(size_t index, u64 value);
+        u64 get(size_t index) const;
+        size_t getLength() const;
+        size_t getBits() const;
+        size_t getInternalByteSize() const;
+        i64 select(size_t index) const;
+        void resize(size_t newLength, size_t newBits);
+        void fill(u64 value);
+        size_t toString(char* s, size_t n) const;
+        void swap(BitArray& other);
+    };
+
+    static_assert(sizeof(BitArray) == 16, "invalid bit array size");
+}
 
 #endif

+ 29 - 14
include/core/Buffer.hpp

@@ -1,19 +1,34 @@
-#ifndef CORE_BUFFER_H
-#define CORE_BUFFER_H
+#ifndef CORE_BUFFER_HPP
+#define CORE_BUFFER_HPP
 
-#include <stddef.h>
+#include <cstddef>
 
-typedef struct {
-    size_t size;
-    size_t capacity;
-    char* buffer;
-} Buffer;
+namespace Core {
+    class Buffer final {
+        size_t length;
+        size_t capacity;
+        char* buffer;
 
-void initBuffer(Buffer* b);
-void destroyBuffer(Buffer* b);
-void addSizedBufferData(Buffer* b, const void* data, size_t size);
-#define addTypedBufferData(buffer, type, ...)                      \
-    addSizedBufferData(buffer, &(type){__VA_ARGS__}, sizeof(type))
-void clearBuffer(Buffer* b);
+    public:
+        Buffer();
+        Buffer(const Buffer& other);
+        Buffer(Buffer&& other) noexcept;
+        ~Buffer();
+        Buffer& operator=(const Buffer& other);
+        Buffer& operator=(Buffer&& other) noexcept;
+
+        Buffer& add(const void* data, size_t size);
+
+        template<typename T>
+        Buffer& add(const T& t) {
+            return add(&t, sizeof(T));
+        }
+
+        size_t getLength() const;
+        const char* getData() const;
+        void clear();
+        void swap(Buffer& other);
+    };
+}
 
 #endif

+ 2 - 2
include/core/Check.hpp

@@ -1,5 +1,5 @@
-#ifndef CORE_CHECK_H
-#define CORE_CHECK_H
+#ifndef CORE_CHECK_HPP
+#define CORE_CHECK_HPP
 
 #if defined(__GNUC__)
 #define check_format(format_index, arg_start_index)                \

+ 27 - 0
include/core/Clock.hpp

@@ -0,0 +1,27 @@
+#ifndef CORE_CLOCK_HPP
+#define CORE_CLOCK_HPP
+
+#include "core/Array.hpp"
+#include "core/Types.hpp"
+
+namespace Core {
+    struct Clock final {
+        size_t index;
+        i64 last;
+        i64 sum;
+        Array<i64, 1 << 7> time;
+
+    public:
+        Clock();
+
+        // the first invocation will always return 0 nanos
+        i64 update();
+        float getUpdatesPerSecond() const;
+
+        static bool sleepNanos(i64 nanos);
+        static bool sleepMillis(i64 millis);
+        static i64 getNanos();
+    };
+}
+
+#endif

+ 9 - 7
old/Color.hpp → include/core/Color.hpp

@@ -1,10 +1,10 @@
 #ifndef CORE_COLOR_HPP
 #define CORE_COLOR_HPP
 
-#include "core/utils/Types.hpp"
+#include "core/Types.hpp"
 
 namespace Core {
-    using ColorChannel = unsigned char;
+    using ColorChannel = u8;
 
     template<size_t N>
     class Color final {
@@ -15,11 +15,13 @@ namespace Core {
         Color() = default;
 
         template<typename OT, typename... Args>
-        Color(OT a, Args&&... args)
-            : data(static_cast<ColorChannel>(a),
-                   static_cast<ColorChannel>(args)...) {
-            static_assert(sizeof...(args) + 1 == N,
-                          "color channel parameters do not match its size");
+        Color(OT a, Args&&... args) :
+            data(
+                static_cast<ColorChannel>(a),
+                static_cast<ColorChannel>(args)...) {
+            static_assert(
+                sizeof...(args) + 1 == N,
+                "color channel parameters do not match its size");
         }
 
         float asFloat(size_t index) const {

+ 136 - 121
include/core/Components.hpp

@@ -1,127 +1,142 @@
-#ifndef CORE_COMPONENTS_H
-#define CORE_COMPONENTS_H
+#ifndef CORE_COMPONENTS_HPP
+#define CORE_COMPONENTS_HPP
 
 #include "core/HashMap.hpp"
 #include "core/List.hpp"
 
-#define isInvalidKeySize(key) ((key) == 0)
-#define equalSize(a, b) ((a) == (b))
-#define hashSize(key) (key)
-
-LIST(size_t, Size)
-HASHMAP(size_t, size_t, Size)
-
-typedef size_t Entity;
-
-#define COMPONENTS(T, N)                                                       \
-    typedef struct {                                                           \
-        HashMapSize entityToIndex;                                             \
-        ListSize indexToEntity;                                                \
-        List##N components;                                                    \
-    } Components##N;                                                           \
-                                                                               \
-    typedef struct {                                                           \
-        Entity entity;                                                         \
-        T* component;                                                          \
-    } ComponentNode##N;                                                        \
-                                                                               \
-    typedef struct {                                                           \
-        const Entity* indexToEntity;                                           \
-        const Entity* indexToEntityEnd;                                        \
-        T* component;                                                          \
-        T* componentEnd;                                                       \
-        ComponentNode##N node;                                                 \
-    } ComponentIterator##N;                                                    \
-                                                                               \
-    void initComponents##N(Components##N* c);                                  \
-    void destroyComponents##N(Components##N* c);                               \
-    T* getOrAddComponent##N(Components##N* c, Entity e);                       \
-    T* searchComponent##N(Components##N* c, Entity e);                         \
-    bool removeComponent##N(Components##N* c, Entity e);                       \
-    void initComponentIterator##N(ComponentIterator##N* ci, Components##N* c); \
-    bool hasNextComponentNode##N(ComponentIterator##N* ci);                    \
-    ComponentNode##N* nextComponentNode##N(ComponentIterator##N* ci);          \
-    T* getComponentsStart##N(Components##N* c);                                \
-    T* getComponentsEnd##N(Components##N* c);
-
-#define COMPONENTS_SOURCE(T, N)                                         \
-    void initComponents##N(Components##N* c) {                          \
-        initHashMapSize(&c->entityToIndex);                             \
-        initListSize(&c->indexToEntity);                                \
-        initList##N(&c->components);                                    \
-    }                                                                   \
-                                                                        \
-    void destroyComponents##N(Components##N* c) {                       \
-        destroyHashMapSize(&c->entityToIndex);                          \
-        destroyListSize(&c->indexToEntity);                             \
-        destroyList##N(&c->components);                                 \
-    }                                                                   \
-                                                                        \
-    T* getOrAddComponent##N(Components##N* c, Entity e) {               \
-        void* component = searchComponent##N(c, e);                     \
-        if(component != nullptr) {                                      \
-            return component;                                           \
-        }                                                               \
-        size_t index = c->components.length;                            \
-        *putHashMapKeySize(&c->entityToIndex, e) = index;               \
-        addListDataSize(&c->indexToEntity, e);                          \
-        return addEmptyListData##N(&c->components);                     \
-    }                                                                   \
-                                                                        \
-    T* searchComponent##N(Components##N* c, Entity e) {                 \
-        size_t* index = searchHashMapKeySize(&c->entityToIndex, e);     \
-        if(index == nullptr) {                                          \
-            return nullptr;                                             \
-        }                                                               \
-        return getListIndex##N(&c->components, *index);                 \
-    }                                                                   \
-                                                                        \
-    bool removeComponent##N(Components##N* c, Entity e) {               \
-        size_t* indexP = searchHashMapKeySize(&c->entityToIndex, e);    \
-        if(indexP == nullptr) {                                         \
-            return false;                                               \
-        }                                                               \
-        size_t lastIndex = c->components.length - 1;                    \
-        size_t index = *indexP;                                         \
-        removeHashMapKeySize(&c->entityToIndex, e);                     \
-        removeListIndexBySwap##N(&c->components, index);                \
-        if(index == lastIndex) {                                        \
-            removeListIndexBySwapSize(&c->indexToEntity, index);        \
-            return true;                                                \
-        }                                                               \
-        Entity other = *getListIndexSize(&c->indexToEntity, lastIndex); \
-        removeListIndexBySwapSize(&c->indexToEntity, index);            \
-        *putHashMapKeySize(&c->entityToIndex, other) = index;           \
-        return true;                                                    \
-    }                                                                   \
-                                                                        \
-    void initComponentIterator##N(                                      \
-        ComponentIterator##N* ci, Components##N* c) {                   \
-        ci->indexToEntity = getListStartSize(&c->indexToEntity);        \
-        ci->indexToEntityEnd = getListEndSize(&c->indexToEntity);       \
-        ci->component = getListStart##N(&c->components);                \
-        ci->componentEnd = getListEnd##N(&c->components);               \
-        ci->node = (ComponentNode##N){0};                               \
-    }                                                                   \
-                                                                        \
-    bool hasNextComponentNode##N(ComponentIterator##N* ci) {            \
-        return ci->indexToEntity != ci->indexToEntityEnd;               \
-    }                                                                   \
-                                                                        \
-    ComponentNode##N* nextComponentNode##N(ComponentIterator##N* ci) {  \
-        ci->node.component = ci->component;                             \
-        ci->node.entity = *ci->indexToEntity;                           \
-        ci->indexToEntity++;                                            \
-        ci->component++;                                                \
-        return &ci->node;                                               \
-    }                                                                   \
-                                                                        \
-    T* getComponentsStart##N(Components##N* c) {                        \
-        return getListStart##N(&c->components);                         \
-    }                                                                   \
-                                                                        \
-    T* getComponentsEnd##N(Components##N* c) {                          \
-        return getListEnd##N(&c->components);                           \
-    }
+namespace Core {
+    using Entity = size_t;
+
+    template<typename T>
+    class Components final {
+        HashMap<Entity, size_t> entityToIndex{};
+        List<Entity> indexToEntity{};
+        List<T> components{};
+
+    public:
+        template<typename R>
+        struct Node final {
+            Entity entity;
+            R& component;
+        };
+
+        template<typename C>
+        class Iterator final {
+            using EntityIterator = decltype(C().indexToEntity.begin());
+            using ComponentIterator = decltype(C().components.begin());
+            using Component = decltype(*ComponentIterator());
+
+            EntityIterator entityIterator{};
+            ComponentIterator componentIterator{};
+
+        public:
+            Iterator(EntityIterator e, ComponentIterator c) :
+                entityIterator(e), componentIterator(c) {
+            }
+
+            Iterator& operator++() {
+                ++entityIterator;
+                ++componentIterator;
+                return *this;
+            }
+
+            bool operator!=(const Iterator& other) const {
+                return entityIterator != other.entityIterator;
+            }
+
+            Node<Component> operator*() const {
+                return {*entityIterator, *componentIterator};
+            }
+        };
+
+        template<typename C>
+        struct IteratorAdapter final {
+            C& c;
+
+            Iterator<C> begin() {
+                return Iterator<C>(
+                    c.indexToEntity.begin(), c.components.begin());
+            }
+
+            Iterator<C> end() {
+                return Iterator<C>(c.indexToEntity.end(), c.components.end());
+            }
+        };
+
+        template<typename... Args>
+        bool put(T*& t, Entity e, Args&&... args) {
+            size_t index = components.getLength();
+            size_t* indexP = nullptr;
+            if(!entityToIndex.tryEmplace(indexP, e, index)) {
+                return false;
+            }
+            indexToEntity.add(e);
+            t = &components.put(Core::forward<Args>(args)...);
+            return true;
+        }
+
+        template<typename... Args>
+        bool add(Entity e, Args&&... args) {
+            T* t = nullptr;
+            return put(t, e, Core::forward<Args>(args)...);
+        }
+
+        bool remove(Entity e) {
+            size_t* indexP = entityToIndex.search(e);
+            if(indexP == nullptr) {
+                return false;
+            }
+            size_t lastIndex = components.getLength() - 1;
+            size_t index = *indexP;
+            entityToIndex.remove(e);
+            components.removeBySwap(index);
+            if(index == lastIndex) {
+                indexToEntity.removeBySwap(index);
+                return true;
+            }
+            Entity other = indexToEntity[lastIndex];
+            indexToEntity.removeBySwap(index);
+            entityToIndex.add(other, index);
+            return true;
+        }
+
+        T* search(Entity e) {
+            return const_cast<T*>(
+                static_cast<const Components*>(this)->search(e));
+        }
+
+        const T* search(Entity e) const {
+            const size_t* index = entityToIndex.search(e);
+            if(index == nullptr) {
+                return nullptr;
+            }
+            return &(components[*index]);
+        }
+
+        auto begin() {
+            return components.begin();
+        }
+
+        auto begin() const {
+            return components.begin();
+        }
+
+        auto end() {
+            return components.end();
+        }
+
+        auto end() const {
+            return components.end();
+        }
+
+        IteratorAdapter<Components> entities() {
+            return {*this};
+        }
+
+        IteratorAdapter<const Components> entities() const {
+            return {*this};
+        }
+    };
+}
 
 #endif

+ 2 - 2
include/core/File.hpp

@@ -1,5 +1,5 @@
-#ifndef CORE_FILE_H
-#define CORE_FILE_H
+#ifndef CORE_FILE_HPP
+#define CORE_FILE_HPP
 
 #include "core/List.hpp"
 

+ 0 - 134
include/core/Generic.hpp

@@ -1,134 +0,0 @@
-#ifndef CORE_GENERIC_H
-#define CORE_GENERIC_H
-
-#include "core/Matrix.hpp"
-
-// clang-format off
-#define GENERIC_PAIR(type, name) type: name, const type : name
-// clang-format on
-
-#define GENERIC_FLOAT_VECTOR(a, name)     \
-    _Generic(                             \
-        (a),                              \
-        GENERIC_PAIR(Vector2*, name##V2), \
-        GENERIC_PAIR(Vector3*, name##V3), \
-        GENERIC_PAIR(Vector4*, name##V4))
-
-#define GENERIC_VECTOR(a, name)               \
-    _Generic(                                 \
-        (a),                                  \
-        GENERIC_PAIR(Vector2*, name##V2),     \
-        GENERIC_PAIR(Vector3*, name##V3),     \
-        GENERIC_PAIR(Vector4*, name##V4),     \
-        GENERIC_PAIR(IntVector2*, name##IV2), \
-        GENERIC_PAIR(IntVector3*, name##IV3), \
-        GENERIC_PAIR(IntVector4*, name##IV4))
-
-#define ZERO_VECTOR(a)                               \
-    _Generic(                                        \
-        (a),                                         \
-        GENERIC_PAIR(Matrix*, &(Vector3){0}),        \
-        GENERIC_PAIR(Vector2*, &(Vector2){0}),       \
-        GENERIC_PAIR(Vector3*, &(Vector3){0}),       \
-        GENERIC_PAIR(Vector4*, &(Vector4){0}),       \
-        GENERIC_PAIR(IntVector2*, &(IntVector2){0}), \
-        GENERIC_PAIR(IntVector3*, &(IntVector3){0}), \
-        GENERIC_PAIR(IntVector4*, &(IntVector4){0}))
-
-#define GENERIC_FACTOR(b, type, base, factor)                \
-    type:                                                    \
-    _Generic((b), GENERIC_PAIR(type, base), default: factor)
-
-#define SELECT_OP(_1, _2, _3, name, ...) name
-
-#define addSet(a, b) GENERIC_VECTOR(a, addSet)(a, b)
-#define add3(a, b, c) GENERIC_VECTOR(a, add)(a, b, c)
-#define add2(a, b) add3(ZERO_VECTOR(a), a, b)
-#define add(...) SELECT_OP(__VA_ARGS__, add3, add2, 0)(__VA_ARGS__)
-
-#define subSet(a, b) GENERIC_VECTOR(a, subSet)(a, b)
-#define sub3(a, b, c) GENERIC_VECTOR(a, sub)(a, b, c)
-#define sub2(a, b) sub3(ZERO_VECTOR(a), a, b)
-#define sub(...) SELECT_OP(__VA_ARGS__, sub3, sub2, 0)(__VA_ARGS__)
-
-#define mulSet(a, b)                                                 \
-    _Generic(                                                        \
-        (a),                                                         \
-        Matrix *: mulSetMatrix,                                      \
-        Quaternion *: mulSetQ,                                       \
-        GENERIC_FACTOR(b, Vector2*, mulSetV2, mulSetV2F),            \
-        GENERIC_FACTOR(b, Vector3*, mulSetV3, mulSetV3F),            \
-        GENERIC_FACTOR(b, Vector4*, mulSetV4, mulSetV4F),            \
-        GENERIC_FACTOR(b, IntVector2*, mulSetIV2, mulSetIV2F),       \
-        GENERIC_FACTOR(b, IntVector3*, mulSetIV3, mulSetIV3F),       \
-        GENERIC_FACTOR(b, IntVector4*, mulSetIV4, mulSetIV4F))(a, b)
-
-#define mul3(a, b, c)                                             \
-    _Generic(                                                     \
-        (a),                                                      \
-        Matrix *: mulMatrix,                                      \
-        Quaternion *: mulQ,                                       \
-        GENERIC_FACTOR(c, Vector2*, mulV2, mulV2F),               \
-        Vector3 *: _Generic(                                      \
-                     (c),                                         \
-                Vector3 *: _Generic(                              \
-                             (b),                                 \
-                        GENERIC_PAIR(Quaternion*, mulQV3),        \
-                        GENERIC_PAIR(Matrix*, mulMatrixV3),       \
-                        default: mulV3),                          \
-                default: mulV3F),                                 \
-        GENERIC_FACTOR(c, Vector4*, mulV4, mulV4F),               \
-        GENERIC_FACTOR(c, IntVector2*, mulIV2, mulIV2F),          \
-        GENERIC_FACTOR(c, IntVector3*, mulIV3, mulIV3F),          \
-        GENERIC_FACTOR(c, IntVector4*, mulIV4, mulIV4F))(a, b, c)
-#define mul2(a, b) mul3(ZERO_VECTOR(a), a, b)
-#define mul(...) SELECT_OP(__VA_ARGS__, mul3, mul2, 0)(__VA_ARGS__)
-
-#define divSet(a, b)                                                 \
-    _Generic(                                                        \
-        (a),                                                         \
-        GENERIC_FACTOR(b, Vector2*, divSetV2, divSetV2F),            \
-        GENERIC_FACTOR(b, Vector3*, divSetV3, divSetV3F),            \
-        GENERIC_FACTOR(b, Vector4*, divSetV4, divSetV4F),            \
-        GENERIC_FACTOR(b, IntVector2*, divSetIV2, divSetIV2F),       \
-        GENERIC_FACTOR(b, IntVector3*, divSetIV3, divSetIV3F),       \
-        GENERIC_FACTOR(b, IntVector4*, divSetIV4, divSetIV4F))(a, b)
-
-#define div3(a, b, c)                                             \
-    _Generic(                                                     \
-        (a),                                                      \
-        GENERIC_FACTOR(c, Vector2*, divV2, divV2F),               \
-        GENERIC_FACTOR(c, Vector3*, divV3, divV3F),               \
-        GENERIC_FACTOR(c, Vector4*, divV4, divV4F),               \
-        GENERIC_FACTOR(c, IntVector2*, divIV2, divIV2F),          \
-        GENERIC_FACTOR(c, IntVector3*, divIV3, divIV3F),          \
-        GENERIC_FACTOR(c, IntVector4*, divIV4, divIV4F))(a, b, c)
-#define div2(a, b) div3(ZERO_VECTOR(a), a, b)
-#define div(...) SELECT_OP(__VA_ARGS__, div3, div2, 0)(__VA_ARGS__)
-
-#define invertSet(a) GENERIC_VECTOR(a, invertSet)(a)
-#define invert2(a, b) GENERIC_VECTOR(a, invert)(a, b)
-#define invert1(a) invert2(ZERO_VECTOR(a), a)
-#define invert(...) SELECT_OP(0, __VA_ARGS__, invert2, invert1, 0)(__VA_ARGS__)
-#define dot(a, b) GENERIC_FLOAT_VECTOR(a, dot)(a, b)
-#define squareLength(a) GENERIC_FLOAT_VECTOR(a, squareLength)(a)
-#define length(a) GENERIC_FLOAT_VECTOR(a, length)(a)
-#define normalize(a) GENERIC_FLOAT_VECTOR(a, normalize)(a)
-
-#undef cross
-#define SELECT_OP(_1, _2, _3, name, ...) name
-#define cross3(a, b, c) cross(a, b, c)
-#define cross2(a, b) cross(&(Vector3){0}, a, b)
-#define cross(...) SELECT_OP(__VA_ARGS__, cross3, cross2, 0)(__VA_ARGS__)
-
-#define convert(a, b)                  \
-    _Generic(                          \
-        (a),                           \
-        Vector2 *: convertIV2,         \
-        Vector3 *: convertIV3,         \
-        Vector4 *: convertIV4,         \
-        IntVector2 *: convertV2,       \
-        IntVector3 *: convertV3,       \
-        IntVector4 *: convertV4)(a, b)
-
-#endif

+ 54 - 57
include/core/ProbingHashMap.hpp → include/core/HashMap.hpp

@@ -1,9 +1,9 @@
-#ifndef CORE_PROBING_HASHMAP_HPP
-#define CORE_PROBING_HASHMAP_HPP
+#ifndef CORE_HASHMAP_HPP
+#define CORE_HASHMAP_HPP
 
 #include "core/List.hpp"
-#include "core/Logger.hpp"
 #include "core/ToString.hpp"
+#include "core/Types.hpp"
 #include "core/Utility.hpp"
 
 template<typename T>
@@ -23,10 +23,10 @@ namespace Core {
     }
 
     template<typename K, typename V>
-    struct ProbingHashMap final {
+    struct HashMap final {
         template<typename Value>
         class Node final {
-            friend ProbingHashMap;
+            friend HashMap;
             friend List<Node>;
             K key;
 
@@ -51,7 +51,7 @@ namespace Core {
         };
 
     private:
-        static constexpr K INVALID = {};
+        static inline K INVALID = {};
 
         template<typename Value, typename R, R (*A)(const K&, Value&)>
         class Iterator final {
@@ -134,35 +134,34 @@ namespace Core {
             }
         };
 
-        using ValueIteratorAdapter =
-            IteratorAdapter<ProbingHashMap, ValueIterator>;
+        using ValueIteratorAdapter = IteratorAdapter<HashMap, ValueIterator>;
         using ConstValueIteratorAdapter =
-            IteratorAdapter<const ProbingHashMap, ConstValueIterator>;
+            IteratorAdapter<const HashMap, ConstValueIterator>;
 
         using ConstKeyIteratorAdapter =
-            IteratorAdapter<const ProbingHashMap, ConstKeyIterator>;
+            IteratorAdapter<const HashMap, ConstKeyIterator>;
 
     private:
         List<K> keys{};
         V* values = nullptr;
-        List<int> jumps{};
+        List<i8> jumps{};
         size_t entries = 0;
         bool invalidSet = false;
 
     public:
-        ProbingHashMap() = default;
+        HashMap() = default;
 
-        ProbingHashMap(const ProbingHashMap& other) {
+        HashMap(const HashMap& other) {
             for(const auto& e : other) {
                 add(e.getKey(), e.value);
             }
         }
 
-        ProbingHashMap(ProbingHashMap&& other) {
+        HashMap(HashMap&& other) {
             swap(other);
         }
 
-        ~ProbingHashMap() {
+        ~HashMap() {
             size_t length = keys.getLength();
             if(length > 0) {
                 for(size_t i = 1; i < length; i++) {
@@ -174,10 +173,10 @@ namespace Core {
                     values[length].~V();
                 }
             }
-            delete[] reinterpret_cast<AlignedType<V>*>(values);
+            coreDeleteN(reinterpret_cast<AlignedType<V>*>(values));
         }
 
-        ProbingHashMap& operator=(ProbingHashMap other) {
+        HashMap& operator=(HashMap other) {
             swap(other);
             return *this;
         }
@@ -186,11 +185,11 @@ namespace Core {
             if(minCapacity <= keys.getLength()) {
                 return;
             }
-            ProbingHashMap<K, V> map;
+            HashMap<K, V> map;
             size_t l = (1lu << roundUpLog2(max(minCapacity, 8lu))) + 1;
             map.keys.resize(l, INVALID);
             map.values = reinterpret_cast<V*>(coreNewN(AlignedType<V>, l));
-            map.jumps.resize(l, INVALID);
+            map.jumps.resize(l, 0);
             size_t length = keys.getLength();
             if(length > 0) {
                 for(size_t i = 1; i < length; i++) {
@@ -250,7 +249,7 @@ namespace Core {
         }
 
         template<typename VA>
-        ProbingHashMap& add(const K& key, VA&& value) {
+        HashMap& add(const K& key, VA&& value) {
             put(key, Core::forward<VA>(value));
             return *this;
         }
@@ -287,8 +286,8 @@ namespace Core {
             return search(key) != nullptr;
         }
 
-        ProbingHashMap& clear() {
-            ProbingHashMap<K, V> map;
+        HashMap& clear() {
+            HashMap<K, V> map;
             swap(map);
             return *this;
         }
@@ -321,7 +320,7 @@ namespace Core {
             return {keys.end(), keys.end(), nullptr, invalidSet};
         }
 
-        void swap(ProbingHashMap& o) {
+        void swap(HashMap& o) {
             Core::swap(o.keys, keys);
             Core::swap(o.values, values);
             Core::swap(o.jumps, jumps);
@@ -330,47 +329,48 @@ namespace Core {
         }
 
     private:
-        static constexpr size_t MAX_CLUSTER = 5;
+        // clang-format off
+        #define FOR_EACH_HASH_START()                           \
+            do {                                                \
+                size_t baseHash = hashCode(key) * 514'685'581u; \
+                size_t end = keys.getLength() - 2;              \
+                for(size_t i = 0; i <= 5; i++) {                \
+                    size_t hash = 1 + ((baseHash + i) & end)
+        #define FOR_EACH_HASH_STOP() \
+                }                    \
+            } while(false)
+        // clang-format on
 
         size_t searchSlot(const K& key) {
             rehash(1);
             while(true) {
-                size_t baseHash = hashCode(key) * 514'685'581u;
-                size_t end = keys.getLength() - 2;
                 // rehash on bad clustering
-                for(size_t i = 0; i <= MAX_CLUSTER; i++) {
-                    size_t hash = 1 + ((baseHash + i) & end);
-                    if((keys[hash] == INVALID && jumps[hash] == 0) ||
-                       keys[hash] == key) {
-                        return hash;
-                    }
+                FOR_EACH_HASH_START();
+                if((keys[hash] == INVALID && jumps[hash] == 0) ||
+                   keys[hash] == key) {
+                    return hash;
                 }
+                FOR_EACH_HASH_STOP();
                 rehash(keys.getLength() + 1);
             }
         }
 
         void markSlot(const K& key) {
-            size_t baseHash = hashCode(key) * 514'685'581u;
-            size_t end = keys.getLength() - 2;
-            for(size_t i = 0; i <= MAX_CLUSTER; i++) {
-                size_t hash = 1 + ((baseHash + i) & end);
-                if(keys[hash] == key) {
-                    return;
-                }
-                jumps[hash]++;
+            FOR_EACH_HASH_START();
+            if(keys[hash] == key) {
+                return;
             }
+            jumps[hash]++;
+            FOR_EACH_HASH_STOP();
         }
 
         void demarkSlot(const K& key) {
-            size_t baseHash = hashCode(key) * 514'685'581u;
-            size_t end = keys.getLength() - 2;
-            for(size_t i = 0; i <= MAX_CLUSTER; i++) {
-                size_t hash = 1 + ((baseHash + i) & end);
-                if(keys[hash] == key) {
-                    return;
-                }
-                jumps[hash]--;
+            FOR_EACH_HASH_START();
+            if(keys[hash] == key) {
+                return;
             }
+            jumps[hash]--;
+            FOR_EACH_HASH_STOP();
         }
 
         template<typename Value>
@@ -379,16 +379,13 @@ namespace Core {
                 if(key == INVALID) {
                     return invalidSet ? values : nullptr;
                 }
-                size_t baseHash = hashCode(key) * 514'685'581u;
-                size_t end = keys.getLength() - 2;
-                for(size_t i = 0; i <= end; i++) [[unlikely]] {
-                    size_t hash = 1 + ((baseHash + i) & end);
-                    if(keys[hash] == key) [[likely]] {
-                        return values + hash;
-                    } else if(jumps[hash] == 0) {
-                        return nullptr;
-                    }
+                FOR_EACH_HASH_START();
+                if(keys[hash] == key) {
+                    return values + hash;
+                } else if(jumps[hash] == 0) {
+                    return nullptr;
                 }
+                FOR_EACH_HASH_STOP();
             }
             return nullptr;
         }

+ 5 - 6
old/HashedString.hpp → include/core/HashedString.hpp

@@ -1,9 +1,7 @@
 #ifndef CORE_HASHED_STRING_HPP
 #define CORE_HASHED_STRING_HPP
 
-#include <string.h>
-
-#include "core/utils/Types.hpp"
+#include <cstring>
 
 namespace Core {
     struct StringHash {
@@ -15,7 +13,7 @@ namespace Core {
         StringHash h;
         while(*s != '\0') {
             h.length++;
-            h.hash = 2120251889lu * h.hash + static_cast<size_t>(*(s++));
+            h.hash = 2'120'251'889lu * h.hash + static_cast<size_t>(*(s++));
         }
         return h;
     }
@@ -26,11 +24,12 @@ namespace Core {
         char data[N];
 
     public:
-        HashedString() : hash() {
+        HashedString() : hash(), data({}) {
         }
 
         HashedString(const char* s) : hash(hashString(s)) {
-            strncpy(data, s, N);
+            strncpy(data, s, N - 1);
+            data[N - 1] = 0;
         }
 
         bool operator==(const HashedString& other) const {

+ 47 - 41
include/core/Logger.hpp

@@ -6,67 +6,73 @@
 #include "core/Terminal.hpp"
 #include "core/ToString.hpp"
 
-enum class LogLevel { NONE, ERROR, WARNING, INFO, DEBUG };
+namespace Core {
+    enum class LogLevel { NONE, ERROR, WARNING, INFO, DEBUG };
 
-extern LogLevel logLevel;
+    extern LogLevel logLevel;
 
-using ReportHandler = void (*)(
-    LogLevel l, const char* file, int line, void* data, const char* message);
-void callReportHandler(
-    LogLevel l, const char* file, int line, const char* report);
-void setReportHandler(ReportHandler h, void* data);
+    using ReportHandler = void (*)(
+        LogLevel l, const char* file, int line, void* data,
+        const char* message);
+    void callReportHandler(
+        LogLevel l, const char* file, int line, const char* report);
+    void setReportHandler(ReportHandler h, void* data);
 
-template<typename... Args>
-void callReportHandler(
-    LogLevel l, const char* file, int line, const char* format,
-    Args&&... args) {
-    char buffer[512];
-    formatBuffer(buffer, sizeof(buffer), format, Core::forward<Args>(args)...);
-    callReportHandler(l, file, line, buffer);
-}
+    template<typename... Args>
+    void callReportHandler(
+        LogLevel l, const char* file, int line, const char* format,
+        Args&&... args) {
+        char buffer[512];
+        formatBuffer(
+            buffer, sizeof(buffer), format, Core::forward<Args>(args)...);
+        callReportHandler(l, file, line, buffer);
+    }
 
-#define REPORT(l, ...) callReportHandler(l, __FILE__, __LINE__, __VA_ARGS__)
+#define REPORT(l, ...)                                          \
+    Core::callReportHandler(l, __FILE__, __LINE__, __VA_ARGS__)
 
-const char* getShortFileName(const char* s);
+    const char* getShortFileName(const char* s);
 
-template<typename... Args>
-void printLog(
-    LogLevel l, const char* file, int line, const char* prefix,
-    const char* format, Args&&... args) {
-    if(logLevel < l) {
-        return;
+    template<typename... Args>
+    void printLog(
+        LogLevel l, const char* file, int line, const char* prefix,
+        const char* format, Args&&... args) {
+        if(logLevel < l) {
+            return;
+        }
+        file = getShortFileName(file);
+        fputs(prefix, stdout);
+        printf("%s:%d | ", file, line);
+        char buffer[512];
+        formatBuffer(
+            buffer, sizeof(buffer), format, Core::forward<Args>(args)...);
+        fputs(buffer, stdout);
+        puts(TERMINAL_RESET);
     }
-    file = getShortFileName(file);
-    fputs(prefix, stdout);
-    printf("%s:%d | ", file, line);
-    char buffer[512];
-    formatBuffer(buffer, sizeof(buffer), format, Core::forward<Args>(args)...);
-    fputs(buffer, stdout);
-    puts(TERMINAL_RESET);
 }
 
 #if defined(LOG_LEVEL) && LOG_LEVEL >= 1
-#define LOG_ERROR(...)                                                       \
-    printLog(                                                                \
-        LogLevel::ERROR, __FILE__, __LINE__, TERMINAL_BRIGHT_RED "[ERROR] ", \
-        __VA_ARGS__)
+#define LOG_ERROR(...)                               \
+    Core::printLog(                                  \
+        Core::LogLevel::ERROR, __FILE__, __LINE__,   \
+        TERMINAL_BRIGHT_RED "[ERROR] ", __VA_ARGS__)
 #else
 #define LOG_ERROR(...)
 #endif
 
 #if defined(LOG_LEVEL) && LOG_LEVEL >= 2
 #define LOG_WARNING(...)                                  \
-    printLog(                                             \
-        LogLevel::WARNING, __FILE__, __LINE__,            \
+    Core::printLog(                                       \
+        Core::LogLevel::WARNING, __FILE__, __LINE__,      \
         TERMINAL_BRIGHT_YELLOW "[WARNING] ", __VA_ARGS__)
 #else
 #define LOG_WARNING(...)
 #endif
 
 #if defined(LOG_LEVEL) && LOG_LEVEL >= 3
-#define LOG_INFO(...)                                                \
-    printLog(                                                        \
-        LogLevel::INFO, __FILE__, __LINE__, TERMINAL_BOLD "[INFO] ", \
+#define LOG_INFO(...)                                                      \
+    Core::printLog(                                                        \
+        Core::LogLevel::INFO, __FILE__, __LINE__, TERMINAL_BOLD "[INFO] ", \
         __VA_ARGS__)
 #else
 #define LOG_INFO(...)
@@ -74,8 +80,8 @@ void printLog(
 
 #if defined(LOG_LEVEL) && LOG_LEVEL >= 4
 #define LOG_DEBUG(...)                                               \
-    printLog(                                                        \
-        LogLevel::DEBUG, __FILE__, __LINE__,                         \
+    Core::printLog(                                                  \
+        Core::LogLevel::DEBUG, __FILE__, __LINE__,                   \
         TERMINAL_BOLD TERMINAL_BRIGHT_BLACK "[DEBUG] ", __VA_ARGS__)
 #else
 #define LOG_DEBUG(...)

+ 2 - 2
include/core/Matrix.hpp

@@ -1,5 +1,5 @@
-#ifndef CORE_MATRIX_H
-#define CORE_MATRIX_H
+#ifndef CORE_MATRIX_HPP
+#define CORE_MATRIX_HPP
 
 #include "core/Quaternion.hpp"
 

+ 125 - 80
include/core/Queue.hpp

@@ -1,85 +1,130 @@
-#ifndef CORE_QUEUE_H
-#define CORE_QUEUE_H
+#ifndef CORE_QUEUE_HPP
+#define CORE_QUEUE_HPP
 
-#include <assert.h>
+#include <cassert>
 
+#include "core/AlignedData.hpp"
 #include "core/ToString.hpp"
-#include "core/Types.hpp"
-#include "core/Utility.hpp"
-
-#define QUEUE(T, N)                                                       \
-    typedef struct {                                                      \
-        size_t writeIndex;                                                \
-        size_t readIndex;                                                 \
-        size_t length;                                                    \
-        size_t capacity;                                                  \
-        T* data;                                                          \
-    } Queue##N;                                                           \
-                                                                          \
-    void initQueue##N(Queue##N* r, size_t capacity);                      \
-    void destroyQueue##N(Queue##N* r);                                    \
-    void pushQueueData##N(Queue##N* r, T data);                           \
-    T* getQueueIndex##N(const Queue##N* r, size_t index);                 \
-    void clearQueue##N(Queue##N* r);                                      \
-    void popQueueData##N(Queue##N* r);                                    \
-    typedef size_t (*ToString##N)(const T* data, char* buffer, size_t n); \
-    size_t toStringQueue##N(                                              \
-        const Queue##N* r, char* buffer, size_t n, ToString##N c);
-
-#define QUEUE_SOURCE(T, N)                                                  \
-    void initQueue##N(Queue##N* r, size_t capacity) {                       \
-        *r = ((Queue##N){0, 0, 0, capacity, nullptr});                      \
-    }                                                                       \
-                                                                            \
-    void destroyQueue##N(Queue##N* r) {                                     \
-        coreFree(r->data);                                                  \
-        *r = (Queue##N){0};                                                 \
-    }                                                                       \
-                                                                            \
-    void pushQueueData##N(Queue##N* r, T data) {                            \
-        if(r->length >= r->capacity) {                                      \
-            return;                                                         \
-        } else if(r->data == nullptr) {                                     \
-            r->data = coreAllocate(r->capacity * sizeof(T));                \
-        }                                                                   \
-        r->data[r->writeIndex] = data;                                      \
-        r->writeIndex = (r->writeIndex + 1) % r->capacity;                  \
-        r->length++;                                                        \
-    }                                                                       \
-                                                                            \
-    T* getQueueIndex##N(const Queue##N* r, size_t index) {                  \
-        return r->data + ((index + r->readIndex) % r->capacity);            \
-    }                                                                       \
-                                                                            \
-    void clearQueue##N(Queue##N* r) {                                       \
-        r->writeIndex = 0;                                                  \
-        r->readIndex = 0;                                                   \
-        r->length = 0;                                                      \
-    }                                                                       \
-                                                                            \
-    void popQueueData##N(Queue##N* r) {                                     \
-        assert(r->length > 0);                                              \
-        r->length--;                                                        \
-        r->readIndex = (r->readIndex + 1) % r->capacity;                    \
-    }                                                                       \
-                                                                            \
-    size_t toStringQueue##N(                                                \
-        const Queue##N* r, char* buffer, size_t n, ToString##N c) {         \
-        size_t w = 0;                                                       \
-        stringAdd(&w, &buffer, &n, toString(buffer, n, "["));               \
-        size_t end = r->length;                                             \
-        if(end > 0) {                                                       \
-            end--;                                                          \
-            for(size_t i = 0; i < end; i++) {                               \
-                stringAdd(                                                  \
-                    &w, &buffer, &n, c(getQueueIndex##N(r, i), buffer, n)); \
-                stringAdd(&w, &buffer, &n, toString(buffer, n, ", "));      \
-            }                                                               \
-            stringAdd(                                                      \
-                &w, &buffer, &n, c(getQueueIndex##N(r, end), buffer, n));   \
-        }                                                                   \
-        stringAdd(&w, &buffer, &n, toString(buffer, n, "]"));               \
-        return w;                                                           \
-    }
+
+namespace Core {
+    template<typename T, size_t N>
+    class Queue final {
+        AlignedType<T> data[N];
+        size_t writeIndex = 0;
+        size_t readIndex = 0;
+        size_t values = 0;
+
+    public:
+        Queue() = default;
+
+        Queue(const Queue& other) {
+            copy(other);
+        }
+
+        Queue(Queue&& other) noexcept {
+            move(Core::move(other));
+            other.clear();
+        }
+
+        ~Queue() {
+            clear();
+        }
+
+        Queue& operator=(const Queue& other) {
+            if(&other != this) {
+                clear();
+                copy(other);
+            }
+            return *this;
+        }
+
+        Queue& operator=(Queue&& other) noexcept {
+            if(&other != this) {
+                clear();
+                move(Core::move(other));
+                other.clear();
+            }
+            return *this;
+        }
+
+        template<typename... Args>
+        T* put(Args&&... args) {
+            if(getLength() >= N) {
+                return nullptr;
+            }
+            T* t = new(data + writeIndex) T(Core::forward<Args>(args)...);
+            writeIndex = (writeIndex + 1) % N;
+            values++;
+            return t;
+        }
+
+        template<typename... Args>
+        Queue& add(Args&&... args) {
+            put(Core::forward<Args>(args)...);
+            return *this;
+        }
+
+        T& operator[](size_t index) {
+            return reinterpret_cast<T*>(data)[(index + readIndex) % N];
+        }
+
+        const T& operator[](size_t index) const {
+            return reinterpret_cast<const T*>(data)[(index + readIndex) % N];
+        }
+
+        size_t getLength() const {
+            return values;
+        }
+
+        bool canRemove() const {
+            return getLength() > 0;
+        }
+
+        void clear() {
+            for(size_t i = 0; i < getLength(); i++) {
+                (*this)[i].~T();
+            }
+            writeIndex = 0;
+            readIndex = 0;
+            values = 0;
+        }
+
+        void remove() {
+            assert(canRemove());
+            values--;
+            (*this)[0].~T();
+            readIndex = (readIndex + 1) % N;
+        }
+
+        size_t toString(char* s, size_t n) const {
+            size_t total = 0;
+            addString("[", s, n, total);
+            size_t end = getLength();
+            if(end > 0) {
+                end--;
+                for(size_t i = 0; i < end; i++) {
+                    addString((*this)[i], s, n, total);
+                    addString(", ", s, n, total);
+                }
+                addString((*this)[end], s, n, total);
+            }
+            addString("]", s, n, total);
+            return total;
+        }
+
+    private:
+        void copy(const Queue& other) {
+            for(size_t i = 0; i < other.getLength(); i++) {
+                add(other[i]);
+            }
+        }
+
+        void move(Queue&& other) {
+            for(size_t i = 0; i < other.getLength(); i++) {
+                add(Core::move(other[i]));
+            }
+        }
+    };
+}
 
 #endif

+ 2 - 2
include/core/Random.hpp

@@ -1,5 +1,5 @@
-#ifndef CORE_RANDOM_H
-#define CORE_RANDOM_H
+#ifndef CORE_RANDOM_HPP
+#define CORE_RANDOM_HPP
 
 #include "core/Array.hpp"
 #include "core/Types.hpp"

+ 8 - 6
include/core/ReadLine.hpp

@@ -1,10 +1,12 @@
-#ifndef CORE_READ_LINE_H
-#define CORE_READ_LINE_H
+#ifndef CORE_READ_LINE_HPP
+#define CORE_READ_LINE_HPP
 
-#include <stddef.h>
+#include <cstddef>
 
-bool startReadLine(void);
-bool readLine(char* buffer, size_t n);
-void stopReadLine(void);
+namespace Core {
+    bool startReadLine();
+    bool readLine(char* buffer, size_t n);
+    void stopReadLine();
+}
 
 #endif

+ 0 - 14
include/core/SpinLock.hpp

@@ -1,14 +0,0 @@
-#ifndef CORE_SPIN_LOCK_H
-#define CORE_SPIN_LOCK_H
-
-#include <stdatomic.h>
-
-typedef struct {
-    atomic_bool lock;
-} SpinLock;
-
-void initSpinLock(SpinLock* l);
-void lockSpinLock(SpinLock* l);
-void unlockSpinLock(SpinLock* l);
-
-#endif

+ 41 - 4
include/core/Thread.hpp

@@ -1,8 +1,45 @@
-#ifndef CORE_THREAD_H
-#define CORE_THREAD_H
+#ifndef CORE_THREAD_HPP
+#define CORE_THREAD_HPP
 
-#include <threads.h>
+#include <mutex>
+#include <thread>
 
-bool joinThreadSafe(thrd_t* t);
+namespace Core {
+    class Mutex final {
+        std::mutex mutex{};
 
+    public:
+        void lock() noexcept;
+        void unlock() noexcept;
+    };
+
+    class MutexGuard {
+        Mutex& mutex;
+
+    public:
+        MutexGuard(Mutex& m);
+        MutexGuard(const MutexGuard&) = delete;
+        MutexGuard(MutexGuard&&) = delete;
+        ~MutexGuard();
+        MutexGuard& operator=(const MutexGuard&) = delete;
+        MutexGuard& operator=(MutexGuard&&) = delete;
+    };
+
+    class Thread final {
+        std::thread thread;
+
+    public:
+        using Function = void (*)(void*);
+
+        Thread();
+        Thread(const Thread& other) = delete;
+        Thread(Thread&& other);
+        ~Thread();
+        Thread& operator=(const Thread& other) = delete;
+        Thread& operator=(Thread&& other);
+        void swap(Thread& other);
+        bool start(Function f, void* p);
+        bool join();
+    };
+}
 #endif

+ 66 - 60
include/core/ToString.hpp

@@ -7,76 +7,82 @@
 #include "core/Math.hpp"
 #include "core/Meta.hpp"
 
-size_t toString(int v, char* s, size_t n);
-size_t toString(long v, char* s, size_t n);
-size_t toString(long long v, char* s, size_t n);
-size_t toString(unsigned int v, char* s, size_t n);
-size_t toString(unsigned long v, char* s, size_t n);
-size_t toString(unsigned long long v, char* s, size_t n);
-size_t toString(float v, char* s, size_t n);
-size_t toString(double v, char* s, size_t n);
-size_t toString(const char* v, char* s, size_t n);
-size_t toString(char* v, char* s, size_t n);
-size_t toString(const unsigned char* v, char* s, size_t n);
-size_t toString(unsigned char* v, char* s, size_t n);
-size_t toString(bool v, char* s, size_t n);
+namespace Core {
+    size_t toString(char v, char* s, size_t n);
+    size_t toString(short v, char* s, size_t n);
+    size_t toString(int v, char* s, size_t n);
+    size_t toString(long v, char* s, size_t n);
+    size_t toString(long long v, char* s, size_t n);
+    size_t toString(unsigned char v, char* s, size_t n);
+    size_t toString(unsigned short v, char* s, size_t n);
+    size_t toString(unsigned int v, char* s, size_t n);
+    size_t toString(unsigned long v, char* s, size_t n);
+    size_t toString(unsigned long long v, char* s, size_t n);
+    size_t toString(float v, char* s, size_t n);
+    size_t toString(double v, char* s, size_t n);
+    size_t toString(const char* v, char* s, size_t n);
+    size_t toString(char* v, char* s, size_t n);
+    size_t toString(const unsigned char* v, char* s, size_t n);
+    size_t toString(unsigned char* v, char* s, size_t n);
+    size_t toString(bool v, char* s, size_t n);
 
-template<typename T>
-size_t toString(const T& t, char* s, size_t n);
+    template<typename T>
+    size_t toString(const T& t, char* s, size_t n);
 
-template<typename T>
-void addString(const T& t, char*& s, size_t& n, size_t& total) {
-    size_t w = toString(t, s, n);
-    total += w;
-    w = Core::min(n, w);
-    s += w;
-    n -= w;
-}
+    template<typename T>
+    void addString(const T& t, char*& s, size_t& n, size_t& total) {
+        size_t w = toString(t, s, n);
+        total += w;
+        w = Core::min(n, w);
+        s += w;
+        n -= w;
+    }
 
-template<typename T>
-size_t toString(const T& t, char* s, size_t n) {
-    if constexpr(Core::Iterable<T>) {
-        size_t total = 0;
-        addString("[", s, n, total);
-        auto current = t.begin();
-        auto end = t.end();
-        if(current != end) {
-            addString(*current, s, n, total);
-            ++current;
+    template<typename T>
+    size_t toString(const T& t, char* s, size_t n) {
+        if constexpr(Core::Iterable<T>) {
+            size_t total = 0;
+            addString("[", s, n, total);
+            auto current = t.begin();
+            auto end = t.end();
+            if(current != end) {
+                addString(*current, s, n, total);
+                ++current;
+            }
+            while(current != end) {
+                addString(", ", s, n, total);
+                addString(*current, s, n, total);
+                ++current;
+            }
+            addString("]", s, n, total);
+            return total;
+        } else {
+            return t.toString(s, n);
         }
-        while(current != end) {
-            addString(", ", s, n, total);
-            addString(*current, s, n, total);
-            ++current;
-        }
-        addString("]", s, n, total);
-        return total;
-    } else {
-        return t.toString(s, n);
     }
-}
 
-size_t copyFormatUntil(const char*& format, char*& s, size_t& n);
+    size_t copyFormatUntil(const char*& format, char*& s, size_t& n);
 
-template<typename T, typename... Args>
-void formatR(
-    const char*& format, char*& s, size_t& n, size_t& total, const T& t,
-    Args&&... args) {
-    total += copyFormatUntil(format, s, n);
-    addString(t, s, n, total);
-    if constexpr(sizeof...(args) > 0) {
-        formatR(format, s, n, total, Core::forward<Args>(args)...);
+    template<typename T, typename... Args>
+    void formatR(
+        const char*& format, char*& s, size_t& n, size_t& total, const T& t,
+        Args&&... args) {
+        total += copyFormatUntil(format, s, n);
+        addString(t, s, n, total);
+        if constexpr(sizeof...(args) > 0) {
+            formatR(format, s, n, total, Core::forward<Args>(args)...);
+        }
     }
-}
 
-template<typename... Args>
-size_t formatBuffer(char* s, size_t n, const char* format, Args&&... args) {
-    if constexpr(sizeof...(args) > 0) {
-        size_t total = 0;
-        formatR(format, s, n, total, Core::forward<Args>(args)...);
-        return total + toString(format, s, n);
+    template<typename... Args>
+    size_t formatBuffer(char* s, size_t n, const char* format, Args&&... args) {
+        if constexpr(sizeof...(args) > 0) {
+            size_t total = 0;
+            formatR(format, s, n, total, Core::forward<Args>(args)...);
+            return total + toString(format, s, n);
+        }
+        return copyFormatUntil(format, s, n);
     }
-    return copyFormatUntil(format, s, n);
 }
 
 #endif

+ 2 - 5
include/core/Utility.hpp

@@ -1,8 +1,9 @@
 #ifndef CORE_UTILITY_HPP
 #define CORE_UTILITY_HPP
 
+#include <cstddef>
+
 #include "core/Meta.hpp"
-#include "core/Types.hpp"
 
 #ifdef CHECK_MEMORY
 void* operator new(size_t count, const char* file, int line);
@@ -58,10 +59,6 @@ namespace Core {
 #define coreDeleteN(p) delete[](p)
 #endif
 
-    bool sleepMillis(i64 millis);
-    bool sleepNanos(i64 nanos);
-    i64 getNanos(void);
-
     template<typename T>
     void bubbleSort(T* data, size_t n) {
         bool swapped = true;

+ 0 - 162
old/BitArray.cpp

@@ -1,162 +0,0 @@
-#include "core/data/BitArray.hpp"
-
-#include <string.h>
-
-#include "core/math/Math.hpp"
-#include "core/utils/New.hpp"
-
-static u64 roundUpDivide(u64 a, u64 b) {
-    if(a % b == 0) {
-        return a / b;
-    }
-    return a / b + 1;
-}
-
-static constexpr u64 U64_BITS = 64;
-static constexpr u64 DIVIDE_BITS = Core::Math::roundUpLog2(U64_BITS);
-static constexpr u64 LENGTH_MASK = 0x01FF'FFFF'FFFF'FFFF;
-static constexpr u64 LENGTH_BITS = Core::Math::roundUpLog2(LENGTH_MASK);
-static_assert(LENGTH_BITS == 57, "bit array calculation error");
-
-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);
-}
-
-Core::BitArray::BitArray() : lengthBits(0), data(nullptr) {
-}
-
-Core::BitArray::BitArray(const BitArray& other) : BitArray() {
-    (void)resize(other.getLength(), other.getBits());
-    size_t length = getLength();
-    for(size_t i = 0; i < length; i++) {
-        set(i, other.get(i));
-    }
-}
-
-Core::BitArray::BitArray(BitArray&& other) : BitArray() {
-    swap(other);
-}
-
-Core::BitArray::~BitArray() {
-    delete[] data;
-}
-
-Core::BitArray& Core::BitArray::operator=(BitArray other) {
-    swap(other);
-    return *this;
-}
-
-Core::BitArray& Core::BitArray::set(size_t index, u64 value) {
-    if(data == nullptr || index >= getLength()) {
-        return *this;
-    }
-    setBits(data, index, getBits(), value);
-    return *this;
-}
-
-u64 Core::BitArray::get(size_t index) const {
-    if(data == nullptr || index >= getLength()) {
-        return 0;
-    }
-    return readBits(data, index, getBits());
-}
-
-size_t Core::BitArray::getLength() const {
-    return lengthBits & LENGTH_MASK;
-}
-
-size_t Core::BitArray::getBits() const {
-    return (lengthBits & ~LENGTH_MASK) >> LENGTH_BITS;
-}
-
-size_t Core::BitArray::getInternalByteSize() const {
-    if(getLength() <= 0 || getBits() <= 0) {
-        return 0;
-    }
-    return getArrayLength(getLength(), getBits()) * sizeof(u64);
-}
-
-i64 Core::BitArray::select(u64 index) const {
-    if(index <= 0) {
-        return -1;
-    }
-    u64 found = 0;
-    size_t end = getArrayLength(getLength(), getBits());
-    for(size_t i = 0; i < end; i++) {
-        u64 ones = Core::popCount<u64, u64>(data[i]);
-        found += ones;
-        if(found >= index) {
-            found -= ones;
-            u64 a = i * U64_BITS - 1;
-            u64 d = data[i];
-            while(found < index) {
-                found += d & 1;
-                d >>= 1;
-                a++;
-            }
-            return static_cast<i64>(a);
-        }
-    }
-    return -1;
-}
-
-void Core::BitArray::fill(u64 value) {
-    size_t length = getLength();
-    for(size_t i = 0; i < length; i++) {
-        set(i, value);
-    }
-}
-
-CError Core::BitArray::resize(size_t newLength, size_t newBits) {
-    if(newLength == 0 || newBits == 0 || newBits > 64) {
-        return ErrorCode::INVALID_ARGUMENT;
-    }
-    size_t arrayLength = getArrayLength(newLength, newBits);
-    u64* newData = new(noThrow) u64[arrayLength];
-    memset(newData, 0, arrayLength * sizeof(u64));
-
-    size_t end = Math::min(getLength(), newLength);
-    for(size_t i = 0; i < end; i++) {
-        setBits(newData, i, newBits, get(i));
-    }
-    for(size_t i = end; i < newLength; i++) {
-        setBits(newData, i, newBits, 0);
-    }
-    delete[] data;
-    data = newData;
-    lengthBits = newLength | (newBits << LENGTH_BITS);
-    return ErrorCode::NONE;
-}
-
-void Core::BitArray::swap(BitArray& other) {
-    Core::swap(lengthBits, other.lengthBits);
-    Core::swap(data, other.data);
-}

+ 0 - 44
old/BitArray.hpp

@@ -1,44 +0,0 @@
-#ifndef CORE_BIT_ARRAY_HPP
-#define CORE_BIT_ARRAY_HPP
-
-#include "core/utils/ArrayString.hpp"
-
-namespace Core {
-    class BitArray final {
-        u64 lengthBits;
-        u64* data;
-
-    public:
-        BitArray();
-        BitArray(const BitArray& other);
-        BitArray(BitArray&& other);
-        ~BitArray();
-        BitArray& operator=(BitArray other);
-
-        BitArray& set(size_t index, u64 value);
-        u64 get(size_t index) const;
-        size_t getLength() const;
-        size_t getBits() const;
-        size_t getInternalByteSize() const;
-        i64 select(size_t index) const;
-        CError resize(size_t newLength, size_t newBits);
-        void fill(u64 value);
-
-        void toString(BufferString& s) const {
-            s.append("[");
-            size_t length = getLength();
-            if(length > 0) {
-                length--;
-                for(size_t i = 0; i < length; i++) {
-                    s.append(get(i)).append(", ");
-                }
-                s.append(get(length));
-            }
-            s.append("]");
-        }
-
-        void swap(BitArray& other);
-    };
-}
-
-#endif

+ 0 - 157
old/BitArrayTests.cpp

@@ -1,157 +0,0 @@
-#include "../../src/ErrorSimulator.hpp"
-#include "../Tests.hpp"
-#include "core/data/BitArray.hpp"
-
-static void testSetRead() {
-    Core::BitArray bits;
-    CORE_TEST_ERROR(bits.resize(4, 3));
-    bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
-    CORE_TEST_EQUAL(1, bits.get(0));
-    CORE_TEST_EQUAL(2, bits.get(1));
-    CORE_TEST_EQUAL(3, bits.get(2));
-    CORE_TEST_EQUAL(4, bits.get(3));
-}
-
-static void testOutOfBoundsSetRead() {
-    Core::BitArray bits;
-    bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
-    CORE_TEST_EQUAL(0, bits.get(0));
-    CORE_TEST_EQUAL(0, bits.get(1));
-    CORE_TEST_EQUAL(0, bits.get(2));
-    CORE_TEST_EQUAL(0, bits.get(3));
-}
-
-static void testBigSetRead() {
-    Core::BitArray bits;
-    CORE_TEST_ERROR(bits.resize(100, 13));
-    for(size_t i = 0; i < bits.getLength(); i++) {
-        bits.set(i, i);
-    }
-    for(size_t i = 0; i < bits.getLength(); i++) {
-        CORE_TEST_EQUAL(i, bits.get(i));
-    }
-}
-
-static void testRandomSetReadResize() {
-    const int length = 100;
-    u64 data[length];
-    Core::BitArray bits;
-    CORE_TEST_ERROR(bits.resize(100, 13));
-    u64 seed = 534;
-    for(int k = 0; k < 20; k++) {
-        for(u64 i = 0; i < bits.getLength(); i++) {
-            seed = seed * 636455 + 53453;
-            bits.set(i, seed & (0x1FFF));
-            data[i] = seed & (0x1FFF);
-        }
-    }
-    for(size_t i = 0; i < bits.getLength(); i++) {
-        CORE_TEST_EQUAL(data[i], bits.get(i));
-    }
-    CORE_TEST_ERROR(bits.resize(bits.getLength(), bits.getBits() + 1));
-    CORE_TEST_EQUAL(14, bits.getBits());
-    CORE_TEST_EQUAL(100, bits.getLength());
-    for(size_t i = 0; i < bits.getLength(); i++) {
-        CORE_TEST_EQUAL(data[i], bits.get(i));
-    }
-}
-
-static void testReadOnly() {
-    Core::BitArray bits;
-    CORE_TEST_ERROR(bits.resize(4, 3));
-    bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
-    const Core::BitArray copy = bits;
-    CORE_TEST_EQUAL(1, copy.get(0));
-    CORE_TEST_EQUAL(2, copy.get(1));
-    CORE_TEST_EQUAL(3, copy.get(2));
-    CORE_TEST_EQUAL(4, copy.get(3));
-}
-
-static void testSelect() {
-    Core::BitArray bits;
-    CORE_TEST_ERROR(bits.resize(90, 1));
-    bits.fill(0);
-    bits.set(0, 1).set(5, 1).set(20, 1).set(31, 1);
-    bits.set(32, 1).set(33, 1).set(60, 1);
-    CORE_TEST_EQUAL(-1, bits.select(0));
-    CORE_TEST_EQUAL(0, bits.select(1));
-    CORE_TEST_EQUAL(5, bits.select(2));
-    CORE_TEST_EQUAL(20, bits.select(3));
-    CORE_TEST_EQUAL(31, bits.select(4));
-    CORE_TEST_EQUAL(32, bits.select(5));
-    CORE_TEST_EQUAL(33, bits.select(6));
-    CORE_TEST_EQUAL(60, bits.select(7));
-    CORE_TEST_EQUAL(-1, bits.select(8));
-}
-
-static void testToString1() {
-    Core::BitArray bits;
-    CORE_TEST_ERROR(bits.resize(4, 3));
-    bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
-    CORE_TEST_STRING("[1, 2, 3, 4]", bits);
-}
-
-static void testToString2() {
-    Core::BitArray bits;
-    CORE_TEST_ERROR(bits.resize(1, 3));
-    bits.set(0, 1);
-    CORE_TEST_STRING("[1]", bits);
-}
-
-static void testToString3() {
-    Core::BitArray bits;
-    CORE_TEST_STRING("[]", bits);
-}
-
-static void testResizeExact() {
-    Core::BitArray bits;
-    CORE_TEST_EQUAL(0, bits.getInternalByteSize());
-    // the size in bytes matches the internal storage type
-    size_t elements = sizeof(u64);
-    CORE_TEST_ERROR(bits.resize(elements, 8));
-    for(size_t i = 0; i < elements; i++) {
-        bits.set(i, i);
-    }
-    for(size_t i = 0; i < elements; i++) {
-        CORE_TEST_EQUAL(i, bits.get(i));
-    }
-    CORE_TEST_EQUAL(sizeof(u64), bits.getInternalByteSize());
-}
-
-static void testMoveAssignment() {
-    Core::BitArray bits;
-    CORE_TEST_ERROR(bits.resize(8, 8));
-    for(size_t i = 0; i < bits.getLength(); i++) {
-        bits.set(i, i);
-    }
-    Core::BitArray m;
-    m = Core::move(bits);
-    CORE_TEST_EQUAL(8, m.getLength());
-    for(size_t i = 0; i < m.getLength(); i++) {
-        CORE_TEST_EQUAL(i, m.get(i));
-    }
-}
-
-static void testInvalidArgument() {
-    Core::BitArray bits;
-    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(0, 5));
-    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(5, 0));
-    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(0, 0));
-    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(1, 65));
-    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(5, 68));
-}
-
-void Core::testBitArray() {
-    testSetRead();
-    testOutOfBoundsSetRead();
-    testBigSetRead();
-    testRandomSetReadResize();
-    testReadOnly();
-    testSelect();
-    testToString1();
-    testToString2();
-    testToString3();
-    testResizeExact();
-    testMoveAssignment();
-    testInvalidArgument();
-}

+ 0 - 63
old/Buffer.cpp

@@ -1,63 +0,0 @@
-#include "core/utils/Buffer.hpp"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "core/math/Math.hpp"
-#include "core/utils/Utility.hpp"
-
-Core::Buffer::Buffer(size_t initialSize)
-    : length(0), capacity(initialSize <= 0 ? 1 : initialSize), buffer(nullptr) {
-}
-
-Core::Buffer::Buffer(Buffer&& other) : Buffer(1) {
-    swap(other);
-}
-
-Core::Buffer::~Buffer() {
-    free(buffer);
-}
-
-Core::Buffer& Core::Buffer::operator=(Buffer&& other) {
-    swap(other);
-    return *this;
-}
-
-Core::Error Core::Buffer::copyFrom(const Buffer& other) {
-    clear();
-    return add(other.getData(), other.length);
-}
-
-Core::Error Core::Buffer::add(const void* data, size_t size) {
-    if(length + size > capacity || buffer == nullptr) {
-        while(length + size > capacity) {
-            capacity += Math::max<size_t>(4, capacity / 4);
-        }
-        buffer = static_cast<char*>(reallocate(buffer, capacity));
-    }
-    memcpy(buffer + length, data, size);
-    length += size;
-    return ErrorCode::NONE;
-}
-
-size_t Core::Buffer::getLength() const {
-    return length;
-}
-
-Core::Buffer::operator const char*() const {
-    return buffer;
-}
-
-const char* Core::Buffer::getData() const {
-    return buffer;
-}
-
-void Core::Buffer::swap(Buffer& other) {
-    Core::swap(length, other.length);
-    Core::swap(capacity, other.capacity);
-    Core::swap(buffer, other.buffer);
-}
-
-void Core::Buffer::clear() {
-    length = 0;
-}

+ 0 - 38
old/Buffer.hpp

@@ -1,38 +0,0 @@
-#ifndef CORE_BUFFER_HPP
-#define CORE_BUFFER_HPP
-
-#include "core/utils/Check.hpp"
-#include "core/utils/Error.hpp"
-#include "core/utils/Types.hpp"
-
-namespace Core {
-    class Buffer final {
-        size_t length;
-        size_t capacity;
-        char* buffer;
-
-    public:
-        Buffer(size_t initialSize = 32);
-        Buffer(const Buffer& other) = delete;
-        Buffer(Buffer&& other);
-        ~Buffer();
-        Buffer& operator=(const Buffer& other) = delete;
-        Buffer& operator=(Buffer&& other);
-
-        CError copyFrom(const Buffer& other);
-        CError add(const void* data, size_t size);
-
-        template<typename T>
-        check_return Error add(const T& t) {
-            return add(&t, sizeof(T));
-        }
-
-        size_t getLength() const;
-        operator const char*() const;
-        const char* getData() const;
-        void clear();
-        void swap(Buffer& other);
-    };
-}
-
-#endif

+ 0 - 69
old/BufferTests.cpp

@@ -1,69 +0,0 @@
-#include "../Tests.hpp"
-#include "core/utils/Buffer.hpp"
-
-static constexpr size_t SIZE_TYPES =
-    sizeof(int) + sizeof(long) + sizeof(float) + sizeof(double);
-
-static void testAdd(bool light) {
-    Core::Buffer buffer(10);
-    size_t limit = light ? 1000 : 100000;
-    for(size_t i = 0; i < limit; i++) {
-        CORE_TEST_ERROR(buffer.add(5));
-        CORE_TEST_ERROR(buffer.add(5L));
-        CORE_TEST_ERROR(buffer.add(5.0f));
-        CORE_TEST_ERROR(buffer.add(5.0));
-    }
-    CORE_TEST_EQUAL(SIZE_TYPES * limit, buffer.getLength());
-}
-
-static void testCopy() {
-    Core::Buffer buffer(10);
-    for(int i = 0; i < 10; i++) {
-        CORE_TEST_ERROR(buffer.add(5));
-        CORE_TEST_ERROR(buffer.add(5L));
-        CORE_TEST_ERROR(buffer.add(5.0f));
-        CORE_TEST_ERROR(buffer.add(5.0));
-    }
-    Core::Buffer buffer2;
-    CORE_TEST_ERROR(buffer2.copyFrom(buffer));
-    if(CORE_TEST_EQUAL(SIZE_TYPES * 10, buffer.getLength()) &&
-       CORE_TEST_EQUAL(SIZE_TYPES * 10, buffer2.getLength())) {
-        CORE_TEST_TRUE(memcmp(buffer, buffer2, SIZE_TYPES * 10) == 0);
-    }
-}
-
-static void testMoveConstruct() {
-    Core::Buffer buffer(10);
-    for(int i = 0; i < 10; i++) {
-        CORE_TEST_ERROR(buffer.add(5));
-        CORE_TEST_ERROR(buffer.add(5L));
-        CORE_TEST_ERROR(buffer.add(5.0f));
-        CORE_TEST_ERROR(buffer.add(5.0));
-    }
-    Core::Buffer buffer2(Core::move(buffer));
-
-    CORE_TEST_EQUAL(0, buffer.getLength());
-    CORE_TEST_EQUAL(SIZE_TYPES * 10, buffer2.getLength());
-}
-
-static void testMove() {
-    Core::Buffer buffer(10);
-    for(int i = 0; i < 10; i++) {
-        CORE_TEST_ERROR(buffer.add(5));
-        CORE_TEST_ERROR(buffer.add(5L));
-        CORE_TEST_ERROR(buffer.add(5.0f));
-        CORE_TEST_ERROR(buffer.add(5.0));
-    }
-    Core::Buffer buffer2(3);
-    buffer2 = Core::move(buffer);
-
-    CORE_TEST_EQUAL(0, buffer.getLength());
-    CORE_TEST_EQUAL(SIZE_TYPES * 10, buffer2.getLength());
-}
-
-void Core::testBuffer(bool light) {
-    testAdd(light);
-    testCopy();
-    testMoveConstruct();
-    testMove();
-}

+ 0 - 97
old/BufferedValue.hpp

@@ -1,97 +0,0 @@
-#ifndef CORE_BUFFERED_VALUE_HPP
-#define CORE_BUFFERED_VALUE_HPP
-
-#include "core/math/Math.hpp"
-#include "core/utils/Types.hpp"
-
-namespace Core {
-    template<typename T>
-    class BufferedValue final {
-        T last;
-        T current;
-
-    public:
-        BufferedValue(const T& t) : last(t), current(t) {
-        }
-
-        void update() {
-            last = current;
-        }
-
-        T get(float lag) const {
-            return Math::interpolate(last, current, lag);
-        }
-
-        template<typename O>
-        BufferedValue& operator=(const O& o) {
-            current = o;
-            return *this;
-        }
-
-        template<typename O>
-        BufferedValue& operator+=(const O& o) {
-            current += o;
-            return *this;
-        }
-
-        template<typename O>
-        BufferedValue& operator-=(const O& o) {
-            current -= o;
-            return *this;
-        }
-
-        template<typename O>
-        BufferedValue& operator*=(const O& o) {
-            current *= o;
-            return *this;
-        }
-
-        template<typename O>
-        BufferedValue& operator/=(const O& o) {
-            current /= o;
-            return *this;
-        }
-
-        template<typename O>
-        auto operator+(const O& o) const {
-            return current + o;
-        }
-
-        template<typename O>
-        auto operator-(const O& o) const {
-            return current - o;
-        }
-
-        template<typename O>
-        auto operator*(const O& o) const {
-            return current * o;
-        }
-
-        template<typename O>
-        auto operator/(const O& o) const {
-            return current / o;
-        }
-
-        auto operator-() const {
-            return -current;
-        }
-
-        auto& operator[](size_t index) {
-            return current[index];
-        }
-
-        const auto& operator[](size_t index) const {
-            return current[index];
-        }
-
-        operator T&() {
-            return current;
-        }
-
-        operator const T&() const {
-            return current;
-        }
-    };
-}
-
-#endif

+ 0 - 95
old/BufferedValueTests.cpp

@@ -1,95 +0,0 @@
-#include "../Tests.hpp"
-#include "core/math/BufferedValue.hpp"
-#include "core/math/Vector.hpp"
-
-template class Core::BufferedValue<Core::Vector2>;
-
-using BufferedFloat = Core::BufferedValue<float>;
-
-const float eps = 0.0001f;
-
-static void testInit() {
-    BufferedFloat b = 5.0f;
-    CORE_TEST_FLOAT(5.0f, b.get(0.0f), eps);
-    CORE_TEST_FLOAT(5.0f, b.get(0.5f), eps);
-    CORE_TEST_FLOAT(5.0f, b.get(1.0f), eps);
-    CORE_TEST_FLOAT(5.0f, b, eps);
-    CORE_TEST_FLOAT(5.0f, static_cast<const BufferedFloat&>(b), eps);
-}
-
-static void testInterpolate() {
-    BufferedFloat b = 5.0f;
-    b = 7.0f;
-    CORE_TEST_FLOAT(5.0f, b.get(0.0f), eps);
-    CORE_TEST_FLOAT(6.0f, b.get(0.5f), eps);
-    CORE_TEST_FLOAT(7.0f, b.get(1.0f), eps);
-    CORE_TEST_FLOAT(7.0f, b, eps);
-}
-
-static void testUpdate() {
-    BufferedFloat b = 5.0f;
-    b = 7.0f;
-    b.update();
-    CORE_TEST_FLOAT(7.0f, b.get(0.0f), eps);
-    CORE_TEST_FLOAT(7.0f, b.get(0.5f), eps);
-    CORE_TEST_FLOAT(7.0f, b.get(1.0f), eps);
-    CORE_TEST_FLOAT(7.0f, b, eps);
-}
-
-static void testCalculate() {
-    BufferedFloat b = 5.0f;
-    b = 7.0f;
-    b += 3.0f;
-    CORE_TEST_FLOAT(5.0f, b.get(0.0f), eps);
-    CORE_TEST_FLOAT(7.5f, b.get(0.5f), eps);
-    CORE_TEST_FLOAT(10.0f, b.get(1.0f), eps);
-    CORE_TEST_FLOAT(10.0f, b, eps);
-    CORE_TEST_FLOAT(12.0f, b + 2.0f, eps);
-}
-
-static void testVector2() {
-    Core::Vector2 base(5.0f, 6.0f);
-    using BufferedVector2 = Core::BufferedValue<Core::Vector2>;
-    BufferedVector2 b = base;
-
-    CORE_TEST_VECTOR(base, b.get(1.0f));
-    b = Core::Vector2(7.0f, 5.0);
-    CORE_TEST_VECTOR(Core::Vector2(7.0f, 5.0f), b.get(1.0f));
-    b += Core::Vector2(1.0f, 1.0f);
-    CORE_TEST_VECTOR(Core::Vector2(8.0f, 6.0f), b.get(1.0f));
-    b -= Core::Vector2(1.0f, 1.0f);
-    CORE_TEST_VECTOR(Core::Vector2(7.0f, 5.0f), b.get(1.0f));
-    b *= Core::Vector2(2.0f, 2.0f);
-    CORE_TEST_VECTOR(Core::Vector2(14.0f, 10.0f), b.get(1.0f));
-    b /= Core::Vector2(0.5f, 0.5f);
-    CORE_TEST_VECTOR(Core::Vector2(28.0f, 20.0f), b.get(1.0f));
-    b = b + Core::Vector2(1.0f, 1.0f);
-    CORE_TEST_VECTOR(Core::Vector2(29.0f, 21.0f), b.get(1.0f));
-    b = b - Core::Vector2(1.0f, 1.0f);
-    CORE_TEST_VECTOR(Core::Vector2(28.0f, 20.0f), b.get(1.0f));
-    b = b * Core::Vector2(2.0f, 2.0f);
-    CORE_TEST_VECTOR(Core::Vector2(56.0f, 40.0f), b.get(1.0f));
-    b = b / Core::Vector2(0.5f, 0.5f);
-    CORE_TEST_VECTOR(Core::Vector2(112.0f, 80.0f), b.get(1.0f));
-    b = Core::Vector2(1.0f, 1.0f) + b;
-    CORE_TEST_VECTOR(Core::Vector2(113.0f, 81.0f), b.get(1.0f));
-    b = Core::Vector2(1.0f, 1.0f) - b;
-    CORE_TEST_VECTOR(Core::Vector2(-112.0f, -80.0f), b.get(1.0f));
-    b = Core::Vector2(2.0f, 2.0f) * b;
-    CORE_TEST_VECTOR(Core::Vector2(-224.0f, -160.0f), b.get(1.0f));
-    b = Core::Vector2(224.0f, 160.0f) / b;
-    CORE_TEST_VECTOR(Core::Vector2(-1.0f, -1.0f), b.get(1.0f));
-    b = -b;
-    CORE_TEST_VECTOR(Core::Vector2(1.0f, 1.0f), b.get(1.0f));
-    b[0] += 3;
-    CORE_TEST_VECTOR(Core::Vector2(4.0f, 1.0f), b.get(1.0f));
-    CORE_TEST_FLOAT(4.0f, static_cast<const BufferedVector2&>(b)[0], eps);
-}
-
-void Core::testBufferedValue() {
-    testInit();
-    testInterpolate();
-    testUpdate();
-    testCalculate();
-    testVector2();
-}

+ 0 - 48
old/Clock.cpp

@@ -1,48 +0,0 @@
-#include "core/utils/Clock.hpp"
-
-#include <threads.h>
-#include <time.h>
-
-#include "ErrorSimulator.hpp"
-
-Core::Clock::Clock() : index(0), last(0), sum(0), time(0) {
-}
-
-Core::Error Core::Clock::update(Clock::Nanos& n) {
-    Nanos current = 0;
-    CORE_RETURN_ERROR(getNanos(current));
-    if(last == 0) {
-        last = current;
-        n = 0;
-        return ErrorCode::NONE;
-    }
-    index = (index + 1) & (time.getLength() - 1);
-    sum -= time[index];
-    time[index] = current - last;
-    sum += time[index];
-    last = current;
-    n = time[index];
-    return ErrorCode::NONE;
-}
-
-float Core::Clock::getUpdatesPerSecond() const {
-    return (time.getLength() * 1000000000.0f) / static_cast<float>(sum);
-}
-
-Core::Error Core::Clock::getNanos(Clock::Nanos& n) {
-    timespec ts;
-    if(timespec_get(&ts, TIME_UTC) == 0 || CORE_TIME_GET_FAIL) {
-        return ErrorCode::TIME_NOT_AVAILABLE;
-    }
-    n = static_cast<Clock::Nanos>(ts.tv_sec) * 1'000'000'000L +
-        static_cast<Clock::Nanos>(ts.tv_nsec);
-    return ErrorCode::NONE;
-}
-
-Core::Error Core::Clock::wait(Nanos nanos) {
-    timespec t;
-    t.tv_nsec = nanos % 1'000'000'000;
-    t.tv_sec = nanos / 1'000'000'000;
-    return thrd_sleep(&t, nullptr) != 0 ? ErrorCode::SLEEP_INTERRUPTED
-                                        : ErrorCode::NONE;
-}

+ 0 - 30
old/Clock.hpp

@@ -1,30 +0,0 @@
-#ifndef CORE_CLOCK_HPP
-#define CORE_CLOCK_HPP
-
-#include "core/data/Array.hpp"
-#include "core/utils/Check.hpp"
-#include "core/utils/Types.hpp"
-
-namespace Core {
-    struct Clock final {
-        using Nanos = i64;
-
-    private:
-        size_t index;
-        Nanos last;
-        Nanos sum;
-        Array<Nanos, 1 << 7> time;
-
-    public:
-        Clock();
-
-        // the first invocation will always return 0 nanos
-        check_return Error update(Nanos& n);
-        float getUpdatesPerSecond() const;
-
-        check_return static Error wait(Nanos nanos);
-        check_return static Error getNanos(Nanos& n);
-    };
-}
-
-#endif

+ 0 - 56
old/ClockTests.cpp

@@ -1,56 +0,0 @@
-#include "../../src/ErrorSimulator.hpp"
-#include "../Tests.hpp"
-#include "core/utils/Clock.hpp"
-
-static void testUpdate() {
-    Core::Clock c;
-    Core::Clock::Nanos n1 = 0;
-    Core::Clock::Nanos n2 = 0;
-    Core::Clock::Nanos n3 = 0;
-    Core::Clock::Nanos n4 = 0;
-    CORE_TEST_ERROR(c.update(n1));
-    CORE_TEST_ERROR(c.update(n2));
-    CORE_TEST_ERROR(c.update(n3));
-    CORE_TEST_ERROR(c.update(n4));
-    CORE_TEST_TRUE(n1 == 0);
-    CORE_TEST_TRUE(n2 > 0);
-    CORE_TEST_TRUE(n3 > 0);
-    CORE_TEST_TRUE(n4 > 0);
-}
-
-static void testUpdatesPerSecond() {
-    Core::Clock c;
-    for(int i = 0; i < 1000; i++) {
-        Core::Clock::Nanos n = 0;
-        CORE_TEST_ERROR(c.update(n));
-    }
-    CORE_TEST_TRUE(c.getUpdatesPerSecond() > 0.0f);
-}
-
-static void testWait(Core::Clock::Nanos wait) {
-    Core::Clock c;
-    Core::Clock::Nanos n = 0;
-    CORE_TEST_ERROR(c.update(n));
-    CORE_TEST_ERROR(Core::Clock::wait(wait));
-    Core::Clock::Nanos n2 = 0;
-    CORE_TEST_ERROR(c.update(n2));
-    CORE_TEST_TRUE(n2 >= wait && n2 <= wait * 13 / 10);
-}
-
-static void testFail() {
-#ifdef ERROR_SIMULATOR
-    Core::Clock::Nanos n = 0;
-    Core::Fail::timeGet = true;
-    CORE_TEST_EQUAL(Core::ErrorCode::TIME_NOT_AVAILABLE,
-                    Core::Clock::getNanos(n));
-    Core::Fail::timeGet = false;
-#endif
-}
-
-void Core::testClock(bool light) {
-    testUpdate();
-    testUpdatesPerSecond();
-    testWait(light ? 5'000'000 : 50'000'000);
-    testWait(light ? 50'000'000 : 1'300'000'000);
-    testFail();
-}

+ 0 - 63
old/ColorTests.cpp

@@ -1,63 +0,0 @@
-#include "../Tests.hpp"
-#include "core/utils/Color.hpp"
-
-template class Core::Color<1>;
-template class Core::Color<2>;
-template class Core::Color<3>;
-template class Core::Color<4>;
-
-const float eps = 0.0001f;
-
-static void testColor1() {
-    Core::Color1 c(36);
-    CORE_TEST_EQUAL(36, c[0]);
-    CORE_TEST_FLOAT(36.0f / 255.0f, c.asFloat(0), eps);
-}
-
-static void testColor2() {
-    Core::Color2 c(36 + 256, 100.0);
-    CORE_TEST_EQUAL(36, c[0]);
-    CORE_TEST_EQUAL(100, c[1]);
-    CORE_TEST_FLOAT(36.0f / 255.0f, c.asFloat(0), eps);
-    CORE_TEST_FLOAT(100.0f / 255.0f, c.asFloat(1), eps);
-}
-
-static void testColor3() {
-    Core::Color3 c(36, 100.0f, 200);
-    CORE_TEST_EQUAL(36, c[0]);
-    CORE_TEST_EQUAL(100, c[1]);
-    CORE_TEST_EQUAL(200, c[2]);
-    CORE_TEST_FLOAT(36.0f / 255.0f, c.asFloat(0), eps);
-    CORE_TEST_FLOAT(100.0f / 255.0f, c.asFloat(1), eps);
-    CORE_TEST_FLOAT(200.0f / 255.0f, c.asFloat(2), eps);
-}
-
-template<typename T>
-static void testColor4() {
-    T c(36, 100, 200, 142);
-    CORE_TEST_EQUAL(36, c[0]);
-    CORE_TEST_EQUAL(100, c[1]);
-    CORE_TEST_EQUAL(200, c[2]);
-    CORE_TEST_EQUAL(142, c[3]);
-    CORE_TEST_FLOAT(36.0f / 255.0f, c.asFloat(0), eps);
-    CORE_TEST_FLOAT(100.0f / 255.0f, c.asFloat(1), eps);
-    CORE_TEST_FLOAT(200.0f / 255.0f, c.asFloat(2), eps);
-    CORE_TEST_FLOAT(142.0f / 255.0f, c.asFloat(3), eps);
-}
-
-static void testColor4Empty() {
-    Core::Color4 c;
-    CORE_TEST_EQUAL(0, c[0]);
-    CORE_TEST_EQUAL(0, c[1]);
-    CORE_TEST_EQUAL(0, c[2]);
-    CORE_TEST_EQUAL(0, c[3]);
-}
-
-void Core::testColor() {
-    testColor1();
-    testColor2();
-    testColor3();
-    testColor4<Core::Color4>();
-    testColor4<const Core::Color4>();
-    testColor4Empty();
-}

+ 0 - 140
old/Components.hpp

@@ -1,140 +0,0 @@
-#ifndef CORE_COMPONENTS_HPP
-#define CORE_COMPONENTS_HPP
-
-#include "core/data/HashMap.hpp"
-
-namespace Core {
-    using Entity = int;
-
-    template<typename T>
-    class Components final {
-        HashMap<Entity, size_t> entityToIndex{};
-        List<Entity> indexToEntity{};
-        List<T> components{};
-
-    public:
-        template<typename R>
-        struct Node final {
-            const Entity& entity;
-            R& component;
-        };
-
-        template<typename C, typename R>
-        class EntityIterator final {
-            C& components;
-            size_t index;
-
-        public:
-            EntityIterator(C& components_, size_t index_)
-                : components(components_), index(index_) {
-            }
-
-            EntityIterator& operator++() {
-                index++;
-                return *this;
-            }
-
-            bool operator!=(const EntityIterator& other) const {
-                return index != other.index;
-            }
-
-            Node<R> operator*() const {
-                return {components.indexToEntity[index],
-                        components.components[index]};
-            }
-        };
-
-        template<typename C, typename R>
-        struct EntityIteratorAdapter final {
-            C& components;
-
-            EntityIterator<C, R> begin() {
-                return EntityIterator<C, R>(components, 0);
-            }
-
-            EntityIterator<C, R> end() {
-                return EntityIterator<C, R>(components,
-                                            components.components.getLength());
-            }
-        };
-
-        template<typename... Args>
-        bool put(T*& t, Entity ent, Args&&... args) {
-            size_t index = components.getLength();
-            size_t* indexP = nullptr;
-            if(!entityToIndex.tryEmplace(indexP, ent, index)) {
-                return false;
-            }
-            indexToEntity.add(ent);
-            t = &components.put(Core::forward<Args>(args)...);
-            return true;
-        }
-
-        template<typename... Args>
-        bool add(Entity e, Args&&... args) {
-            T* t = nullptr;
-            return put(t, e, Core::forward<Args>(args)...);
-        }
-
-        bool remove(Entity ent) {
-            size_t* indexP = entityToIndex.search(ent);
-            if(indexP == nullptr) {
-                return false;
-            }
-            size_t lastIndex = components.getLength() - 1;
-            size_t index = *indexP;
-            entityToIndex.remove(ent);
-            components.removeBySwap(index);
-            if(index == lastIndex) {
-                indexToEntity.removeBySwap(index);
-                return true;
-            }
-            Entity other = indexToEntity[lastIndex];
-            indexToEntity.removeBySwap(index);
-            entityToIndex.add(other, index);
-            return true;
-        }
-
-        T* search(Entity e) {
-            size_t* index = entityToIndex.search(e);
-            if(index == nullptr) {
-                return nullptr;
-            }
-            return &(components[*index]);
-        }
-
-        const T* search(Entity e) const {
-            const size_t* index = entityToIndex.search(e);
-            if(index == nullptr) {
-                return nullptr;
-            }
-            return &(components[*index]);
-        }
-
-        auto begin() {
-            return components.begin();
-        }
-
-        auto begin() const {
-            return components.begin();
-        }
-
-        auto end() {
-            return components.end();
-        }
-
-        auto end() const {
-            return components.end();
-        }
-
-        EntityIteratorAdapter<Components, T> entities() {
-            return {*this};
-        }
-
-        EntityIteratorAdapter<const Components, const T> entities() const {
-            return {*this};
-        }
-    };
-}
-
-#endif

+ 0 - 208
old/ComponentsTests.cpp

@@ -1,208 +0,0 @@
-#include "../../src/ErrorSimulator.hpp"
-#include "../Tests.hpp"
-#include "core/data/Components.hpp"
-
-template class Core::Components<int>;
-
-using IntComponent = Core::Components<int>;
-
-static void testAddForEach() {
-    IntComponent c;
-    int* i1 = nullptr;
-    int* i2 = nullptr;
-    int* i3 = nullptr;
-    CORE_TEST_TRUE(c.put(i1, 1, 10));
-    CORE_TEST_FALSE(c.put(i1, 1, 20));
-    CORE_TEST_TRUE(c.put(i2, 5, 20));
-    CORE_TEST_TRUE(c.put(i3, 10, 30));
-
-    CORE_TEST_NOT_NULL(i1);
-    CORE_TEST_NOT_NULL(i2);
-    CORE_TEST_NOT_NULL(i3);
-    if(i1 != nullptr && i2 != nullptr && i3 != nullptr) {
-        CORE_TEST_EQUAL(10, *i1);
-        CORE_TEST_EQUAL(20, *i2);
-        CORE_TEST_EQUAL(30, *i3);
-    }
-
-    auto iter = c.entities();
-    auto pos = iter.begin();
-    auto end = iter.end();
-
-    CORE_TEST_EQUAL(1, (*pos).entity);
-    CORE_TEST_EQUAL(10, (*pos).component);
-    CORE_TEST_TRUE(pos != end);
-
-    ++pos;
-
-    CORE_TEST_EQUAL(5, (*pos).entity);
-    CORE_TEST_EQUAL(20, (*pos).component);
-    CORE_TEST_TRUE(pos != end);
-
-    ++pos;
-
-    CORE_TEST_EQUAL(10, (*pos).entity);
-    CORE_TEST_EQUAL(30, (*pos).component);
-    CORE_TEST_TRUE(pos != end);
-
-    ++pos;
-
-    CORE_TEST_FALSE(pos != end);
-}
-
-static void testAddConstForEach() {
-    IntComponent c;
-    int* i1 = nullptr;
-    int* i2 = nullptr;
-    int* i3 = nullptr;
-    CORE_TEST_TRUE(c.put(i1, 1, 10));
-    CORE_TEST_TRUE(c.put(i2, 5, 20));
-    CORE_TEST_TRUE(c.put(i3, 10, 30));
-
-    auto iter = static_cast<const IntComponent&>(c).entities();
-    auto pos = iter.begin();
-    auto end = iter.end();
-
-    CORE_TEST_EQUAL(1, (*pos).entity);
-    CORE_TEST_EQUAL(10, (*pos).component);
-    CORE_TEST_TRUE(pos != end);
-
-    ++pos;
-
-    CORE_TEST_EQUAL(5, (*pos).entity);
-    CORE_TEST_EQUAL(20, (*pos).component);
-    CORE_TEST_TRUE(pos != end);
-
-    ++pos;
-
-    CORE_TEST_EQUAL(10, (*pos).entity);
-    CORE_TEST_EQUAL(30, (*pos).component);
-    CORE_TEST_TRUE(pos != end);
-
-    ++pos;
-
-    CORE_TEST_FALSE(pos != end);
-}
-
-static void testAddComponentForEach() {
-    IntComponent c;
-    int* i1 = nullptr;
-    int* i2 = nullptr;
-    int* i3 = nullptr;
-    CORE_TEST_TRUE(c.put(i1, 1, 10));
-    CORE_TEST_TRUE(c.put(i2, 5, 20));
-    CORE_TEST_TRUE(c.put(i3, 10, 30));
-
-    CORE_TEST_NOT_NULL(i1);
-    CORE_TEST_NOT_NULL(i2);
-    CORE_TEST_NOT_NULL(i3);
-    if(i1 != nullptr && i2 != nullptr && i3 != nullptr) {
-        CORE_TEST_EQUAL(10, *i1);
-        CORE_TEST_EQUAL(20, *i2);
-        CORE_TEST_EQUAL(30, *i3);
-    }
-
-    auto iter = c.begin();
-    CORE_TEST_EQUAL(10, *iter);
-    CORE_TEST_TRUE(iter != c.end());
-
-    ++iter;
-
-    CORE_TEST_EQUAL(20, *iter);
-    CORE_TEST_TRUE(iter != c.end());
-
-    ++iter;
-
-    CORE_TEST_EQUAL(30, *iter);
-    CORE_TEST_TRUE(iter != c.end());
-
-    ++iter;
-
-    CORE_TEST_FALSE(iter != c.end());
-
-    const IntComponent c2 = Core::move(c);
-    auto iter2 = c2.begin();
-    CORE_TEST_EQUAL(10, *iter2);
-    CORE_TEST_TRUE(iter2 != c2.end());
-
-    ++iter2;
-
-    CORE_TEST_EQUAL(20, *iter2);
-    CORE_TEST_TRUE(iter2 != c2.end());
-
-    ++iter2;
-
-    CORE_TEST_EQUAL(30, *iter2);
-    CORE_TEST_TRUE(iter2 != c2.end());
-
-    ++iter2;
-
-    CORE_TEST_FALSE(iter2 != c2.end());
-}
-
-static void testRemove() {
-    IntComponent c;
-    CORE_TEST_TRUE(c.add(1, 10));
-    CORE_TEST_TRUE(c.add(5, 20));
-    CORE_TEST_TRUE(c.add(10, 30));
-
-    CORE_TEST_FALSE(c.remove(20));
-    CORE_TEST_TRUE(c.remove(5));
-    CORE_TEST_FALSE(c.remove(30));
-
-    CORE_TEST_TRUE(c.add(20, 40));
-    CORE_TEST_TRUE(c.remove(20));
-
-    int* i1 = c.search(1);
-    int* i2 = c.search(5);
-    int* i3 = c.search(10);
-
-    CORE_TEST_NOT_NULL(i1);
-    CORE_TEST_NULL(i2);
-    CORE_TEST_NOT_NULL(i3);
-
-    if(i1 != nullptr && i3 != nullptr) {
-        CORE_TEST_EQUAL(10, *i1);
-        CORE_TEST_EQUAL(30, *i3);
-    }
-
-    CORE_TEST_TRUE(c.remove(10));
-
-    i1 = c.search(1);
-    i2 = c.search(5);
-    i3 = c.search(10);
-
-    CORE_TEST_NOT_NULL(i1);
-    CORE_TEST_NULL(i2);
-    CORE_TEST_NULL(i3);
-
-    if(i1 != nullptr) {
-        CORE_TEST_EQUAL(10, *i1);
-    }
-
-    CORE_TEST_TRUE(c.remove(1));
-
-    CORE_TEST_NULL(c.search(1));
-    CORE_TEST_NULL(c.search(5));
-    CORE_TEST_NULL(c.search(10));
-}
-
-static void testConstSearch() {
-    IntComponent c;
-    int* i = nullptr;
-    CORE_TEST_TRUE(c.put(i, 1, 10));
-    const IntComponent& cc = c;
-    const int* component = cc.search(1);
-    if(CORE_TEST_TRUE(component != nullptr)) {
-        CORE_TEST_EQUAL(10, *component);
-    }
-    CORE_TEST_NULL(cc.search(2));
-}
-
-void Core::testComponents() {
-    testAddForEach();
-    testAddConstForEach();
-    testAddComponentForEach();
-    testRemove();
-    testConstSearch();
-}

+ 0 - 8
old/ErrorSimulator.cpp

@@ -1,8 +0,0 @@
-#ifdef ERROR_SIMULATOR
-#include "ErrorSimulator.hpp"
-
-bool Core::Fail::alloc = false;
-bool Core::Fail::fileClose = false;
-bool Core::Fail::timeGet = false;
-
-#endif

+ 0 - 19
old/ErrorSimulator.hpp

@@ -1,19 +0,0 @@
-#ifndef CORE_ERROR_SIMULATOR_HPP
-#define CORE_ERROR_SIMULATOR_HPP
-
-#ifdef ERROR_SIMULATOR
-namespace Core::Fail {
-    extern bool alloc;
-    extern bool fileClose;
-    extern bool timeGet;
-}
-#define CORE_ALLOC_FAIL Core::Fail::alloc
-#define CORE_FILE_CLOSE_FAIL Core::Fail::fileClose
-#define CORE_TIME_GET_FAIL Core::Fail::timeGet
-#else
-#define CORE_ALLOC_FAIL(...) false
-#define CORE_FILE_CLOSE_FAIL false
-#define CORE_TIME_GET_FAIL false
-#endif
-
-#endif

+ 0 - 281
old/HashMap.hpp

@@ -1,281 +0,0 @@
-#ifndef CORE_HASHMAP_HPP
-#define CORE_HASHMAP_HPP
-
-#include "core/data/LinkedList.hpp"
-#include "core/data/List.hpp"
-#include "core/utils/ArrayString.hpp"
-#include "core/utils/HashCode.hpp"
-#include "core/utils/Meta.hpp"
-
-namespace Core {
-    template<typename K, typename V>
-    struct HashMap final {
-        class Node final {
-            friend HashMap;
-            friend List<Node>;
-            friend LinkedList<Node>;
-            K key;
-
-        public:
-            V value;
-
-            const K& getKey() const {
-                return key;
-            }
-
-            void toString(BufferString& s) const {
-                s.append(key).append(" = ").append(value);
-            }
-
-        private:
-            template<typename... Args>
-            Node(const K& key_, Args&&... args)
-                : key(key_), value(Core::forward<Args>(args)...) {
-            }
-        };
-
-    private:
-        using NodePointer = LinkedList<Node>::Node*;
-        using NodePointerList = List<NodePointer>;
-        using NodeIterator = LinkedList<Node>::Iterator;
-        using ConstNodeIterator = LinkedList<Node>::ConstIterator;
-
-        template<typename N, typename I, typename R, R& (*A)(I&)>
-        class Iterator final {
-            N iterator;
-
-        public:
-            Iterator(N iterator_) : iterator(iterator_) {
-            }
-
-            Iterator& operator++() {
-                ++iterator;
-                return *this;
-            }
-
-            bool operator!=(const Iterator& other) const {
-                return iterator != other.iterator;
-            }
-
-            R& operator*() const {
-                return A(*iterator);
-            }
-        };
-
-        template<typename R>
-        static R& access(R& node) {
-            return node;
-        }
-
-        template<typename I, typename R>
-        static R& accessValue(I& node) {
-            return node.value;
-        }
-
-        static const K& accessKey(const Node& node) {
-            return node.getKey();
-        }
-
-        template<typename N, typename R>
-        using BaseEntryIterator = Iterator<N, R, R, access<R>>;
-        using EntryIterator = BaseEntryIterator<NodeIterator, Node>;
-        using ConstEntryIterator =
-            BaseEntryIterator<ConstNodeIterator, const Node>;
-
-        template<typename N, typename I, typename R>
-        using BaseValueIterator = Iterator<N, I, R, accessValue<I, R>>;
-        using ValueIterator = BaseValueIterator<NodeIterator, Node, V>;
-        using ConstValueIterator =
-            BaseValueIterator<ConstNodeIterator, const Node, const V>;
-
-        using ConstKeyIterator =
-            Iterator<ConstNodeIterator, const Node, const K, accessKey>;
-
-        template<typename M, typename I>
-        struct IteratorAdapter final {
-            M& map;
-
-            I begin() const {
-                return I(map.nodes.begin());
-            }
-
-            I end() const {
-                return I(map.nodes.end());
-            }
-        };
-
-        using ValueIteratorAdapter = IteratorAdapter<HashMap, ValueIterator>;
-        using ConstValueIteratorAdapter =
-            IteratorAdapter<const HashMap, ConstValueIterator>;
-
-        using ConstKeyIteratorAdapter =
-            IteratorAdapter<const HashMap, ConstKeyIterator>;
-
-    private:
-        LinkedList<Node> nodes{};
-        List<NodePointerList> nodePointers{};
-
-    public:
-        HashMap() = default;
-
-        HashMap(const HashMap& other) {
-            for(const auto& en : other) {
-                add(en.getKey(), en.value);
-            }
-        }
-
-        HashMap(HashMap&& other) {
-            swap(other);
-        }
-
-        HashMap& operator=(HashMap other) {
-            swap(other);
-            return *this;
-        }
-
-        void rehash(size_t minCapacity) {
-            if(minCapacity <= nodePointers.getLength()) {
-                return;
-            }
-            HashMap<K, V> map;
-            size_t l =
-                1lu << Math::roundUpLog2(Core::Math::max(minCapacity, 8lu));
-            map.nodePointers.resize(l);
-            for(NodePointerList& list : nodePointers) {
-                for(NodePointer& n : list) {
-                    size_t h = map.hashIndex(n->data.key);
-                    map.nodePointers[h].add(n);
-                }
-            }
-            Core::swap(map.nodePointers, nodePointers);
-        }
-
-        template<typename... Args>
-        bool tryEmplace(V*& v, const K& key, Args&&... args) {
-            rehash(nodes.getLength() + 1);
-            size_t h = hashIndex(key);
-            v = searchList(key, h);
-            if(v != nullptr) {
-                return false;
-            }
-            NodePointer np = nodes.put(key, Core::forward<Args>(args)...);
-            nodePointers[h].add(np);
-            v = &(np->data.value);
-            return true;
-        }
-
-        template<typename VA>
-        V& put(const K& key, VA&& value) {
-            rehash(nodes.getLength() + 1);
-            size_t h = hashIndex(key);
-            V* v = searchList(key, h);
-            if(v != nullptr) {
-                *v = Core::forward<VA>(value);
-                return *v;
-            }
-            NodePointer np = nodes.put(key, Core::forward<VA>(value));
-            nodePointers[h].add(np);
-            return np->data.value;
-        }
-
-        template<typename VA>
-        HashMap& add(const K& key, VA&& value) {
-            put(key, Core::forward<VA>(value));
-            return *this;
-        }
-
-        bool remove(const K& key) {
-            NodePointerList& list = nodePointers[hashIndex(key)];
-            for(size_t i = 0; i < list.getLength(); i++) {
-                if(list[i]->data.key == key) {
-                    nodes.remove(list[i]);
-                    list.removeBySwap(i);
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        const V* search(const K& key) const {
-            return searchList(key, hashIndex(key));
-        }
-
-        V* search(const K& key) {
-            return searchList(key, hashIndex(key));
-        }
-
-        bool contains(const K& key) const {
-            return search(key) != nullptr;
-        }
-
-        HashMap& clear() {
-            nodes.clear();
-            for(NodePointerList& n : nodePointers) {
-                n.clear();
-            }
-            return *this;
-        }
-
-        ConstKeyIteratorAdapter getKeys() const {
-            return {*this};
-        }
-
-        ValueIteratorAdapter getValues() {
-            return {*this};
-        }
-
-        ConstValueIteratorAdapter getValues() const {
-            return {*this};
-        }
-
-        EntryIterator begin() {
-            return EntryIterator(nodes.begin());
-        }
-
-        EntryIterator end() {
-            return EntryIterator(nodes.end());
-        }
-
-        ConstEntryIterator begin() const {
-            return ConstEntryIterator(nodes.begin());
-        }
-
-        ConstEntryIterator end() const {
-            return ConstEntryIterator(nodes.end());
-        }
-
-        void swap(HashMap& other) {
-            Core::swap(nodes, other.nodes);
-            Core::swap(nodePointers, other.nodePointers);
-        }
-
-        void toString(BufferString& s) const {
-            Core::toString(s, *this);
-        }
-
-    private:
-        template<typename H>
-        size_t hashIndex(const H& key) const {
-            return hashCode(key) & (nodePointers.getLength() - 1);
-        }
-
-        const V* searchList(const K& key, size_t h) const {
-            if(nodePointers.getLength() == 0) {
-                return nullptr;
-            }
-            for(const NodePointer& n : nodePointers[h]) {
-                if(n->data.key == key) {
-                    return &n->data.value;
-                }
-            }
-            return nullptr;
-        }
-
-        V* searchList(const K& key, size_t h) {
-            return const_cast<V*>(
-                static_cast<const HashMap*>(this)->searchList(key, h));
-        }
-    };
-}
-
-#endif

+ 0 - 72
old/HashedStringTests.cpp

@@ -1,72 +0,0 @@
-#include "../Tests.hpp"
-#include "core/data/HashMap.hpp"
-#include "core/utils/HashedString.hpp"
-
-template class Core::HashedString<32>;
-
-using HString = Core::HashedString<32>;
-
-static void testComparison() {
-    HString a("test");
-    HString b("testA");
-    HString c("");
-    HString d("Btest");
-
-    CORE_TEST_TRUE(a == a);
-    CORE_TEST_TRUE(b == b);
-    CORE_TEST_TRUE(c == c);
-    CORE_TEST_TRUE(d == d);
-    CORE_TEST_TRUE(a != b);
-    CORE_TEST_TRUE(a != c);
-    CORE_TEST_TRUE(a != d);
-    CORE_TEST_TRUE(b != a);
-    CORE_TEST_TRUE(b != c);
-    CORE_TEST_TRUE(b != d);
-    CORE_TEST_TRUE(c != a);
-    CORE_TEST_TRUE(c != b);
-    CORE_TEST_TRUE(c != d);
-    CORE_TEST_TRUE(d != a);
-    CORE_TEST_TRUE(d != b);
-    CORE_TEST_TRUE(d != c);
-}
-
-static void testLength() {
-    HString s("test");
-    CORE_TEST_EQUAL(4, s.getLength());
-    CORE_TEST_EQUAL(31, s.getCapacity());
-}
-
-static void testHashCode() {
-    HString a;
-    HString b("wusi");
-    CORE_TEST_EQUAL(a.hashCode(), 0lu);
-    CORE_TEST_TRUE(b.hashCode() != 0u);
-}
-
-static void testAsHashMapKey() {
-    Core::HashMap<HString, int> map;
-    map.add("wusi", 3).add("hiThere", 7).add("baum123", 5);
-
-    int* a = map.search("wusi");
-    int* b = map.search("hiThere");
-    int* c = map.search("baum123");
-    int* d = map.search("423hifd");
-
-    CORE_TEST_NOT_NULL(a);
-    CORE_TEST_NOT_NULL(b);
-    CORE_TEST_NOT_NULL(c);
-    CORE_TEST_NULL(d);
-
-    if(a != nullptr && b != nullptr && c != nullptr) {
-        CORE_TEST_EQUAL(3, *a);
-        CORE_TEST_EQUAL(7, *b);
-        CORE_TEST_EQUAL(5, *c);
-    }
-}
-
-void Core::testHashedString() {
-    testComparison();
-    testLength();
-    testHashCode();
-    testAsHashMapKey();
-}

+ 0 - 47
old/MatrixStack.hpp

@@ -1,47 +0,0 @@
-#ifndef CORE_MATRIX_STACK_HPP
-#define CORE_MATRIX_STACK_HPP
-
-#include "core/data/ArrayList.hpp"
-#include "core/math/Matrix.hpp"
-
-namespace Core {
-    template<size_t N>
-    class MatrixStack final {
-        ArrayList<Matrix, N> stack;
-
-    public:
-        MatrixStack() : stack() {
-            stack.add(Matrix());
-        }
-
-        void pop() {
-            assert(stack.getLength() > 0);
-            stack.removeLast();
-        }
-
-        void push() {
-            stack.add(peek());
-        }
-
-        Matrix& peek() {
-            assert(stack.getLength() > 0);
-            return stack[stack.getLength() - 1];
-        }
-
-        const Matrix& peek() const {
-            assert(stack.getLength() > 0);
-            return stack[stack.getLength() - 1];
-        }
-
-        void clear() {
-            stack.clear();
-            stack.add(Matrix());
-        }
-
-        void toString(BufferString& s) const {
-            s.append(stack);
-        }
-    };
-}
-
-#endif

+ 0 - 120
old/MatrixStackTests.cpp

@@ -1,120 +0,0 @@
-#include "../Tests.hpp"
-#include "core/math/MatrixStack.hpp"
-
-template class Core::MatrixStack<5>;
-using Matrices = Core::MatrixStack<5>;
-
-static void testInit() {
-    Core::Matrix m;
-    Matrices stack;
-    for(int i = 0; i < 16; i++) {
-        CORE_TEST_FLOAT(m.getValues()[i], stack.peek().getValues()[i], 0.0f);
-    }
-}
-
-static void testPop() {
-    Matrices stack;
-    stack.push();
-    stack.peek().scale(2.0f);
-    stack.pop();
-    Core::Matrix m;
-    for(int i = 0; i < 16; i++) {
-        CORE_TEST_FLOAT(m.getValues()[i], stack.peek().getValues()[i], 0.0f);
-    }
-}
-
-static void testPush(bool light) {
-    Matrices stack;
-    for(int i = 0; i < 4; i++) {
-        stack.push();
-    }
-    int limit = light ? 10000 : 1000000;
-    for(int i = 0; i < limit; i++) {
-        stack.push();
-    }
-}
-
-static void testClear() {
-    Matrices stack;
-    stack.peek().scale(2.0f);
-    stack.push();
-    stack.peek().scale(2.0f);
-    stack.clear();
-    Core::Matrix m;
-    for(int i = 0; i < 16; i++) {
-        CORE_TEST_FLOAT(m.getValues()[i], stack.peek().getValues()[i], 0.0f);
-    }
-}
-
-static void testToString1() {
-    Matrices stack;
-    stack.peek().scale(2.0f);
-    stack.push();
-    stack.peek().scale(3.0f);
-    stack.push();
-    stack.peek().scale(4.0f);
-    CORE_TEST_STRING("["
-                     "[[2.00, 0.00, 0.00, 0.00], "
-                     "[0.00, 2.00, 0.00, 0.00], "
-                     "[0.00, 0.00, 2.00, 0.00], "
-                     "[0.00, 0.00, 0.00, 1.00]], "
-                     "[[6.00, 0.00, 0.00, 0.00], "
-                     "[0.00, 6.00, 0.00, 0.00], "
-                     "[0.00, 0.00, 6.00, 0.00], "
-                     "[0.00, 0.00, 0.00, 1.00]], "
-                     "[[24.00, 0.00, 0.00, 0.00], "
-                     "[0.00, 24.00, 0.00, 0.00], "
-                     "[0.00, 0.00, 24.00, 0.00], "
-                     "[0.00, 0.00, 0.00, 1.00]]"
-                     "]",
-                     stack);
-}
-
-static void testToString2() {
-    Matrices stack;
-    stack.peek().scale(2.0f);
-    stack.push();
-    stack.peek().scale(3.0f);
-    CORE_TEST_STRING("["
-                     "[[2.00, 0.00, 0.00, 0.00], "
-                     "[0.00, 2.00, 0.00, 0.00], "
-                     "[0.00, 0.00, 2.00, 0.00], "
-                     "[0.00, 0.00, 0.00, 1.00]], "
-                     "[[6.00, 0.00, 0.00, 0.00], "
-                     "[0.00, 6.00, 0.00, 0.00], "
-                     "[0.00, 0.00, 6.00, 0.00], "
-                     "[0.00, 0.00, 0.00, 1.00]]"
-                     "]",
-                     stack);
-}
-
-static void testToString3() {
-    Matrices stack;
-    CORE_TEST_STRING("["
-                     "[[1.00, 0.00, 0.00, 0.00], "
-                     "[0.00, 1.00, 0.00, 0.00], "
-                     "[0.00, 0.00, 1.00, 0.00], "
-                     "[0.00, 0.00, 0.00, 1.00]]"
-                     "]",
-                     stack);
-}
-
-static void testConstPeek() {
-    const Matrices stack;
-    CORE_TEST_STRING("[[1.00, 0.00, 0.00, 0.00], "
-                     "[0.00, 1.00, 0.00, 0.00], "
-                     "[0.00, 0.00, 1.00, 0.00], "
-                     "[0.00, 0.00, 0.00, 1.00]]",
-                     stack.peek());
-}
-
-void Core::testMatrixStack(bool light) {
-    testInit();
-    testPop();
-    testPush(light);
-    testClear();
-    testToString1();
-    testToString2();
-    testToString3();
-    testConstPeek();
-}

+ 0 - 23
old/Mutex.cpp

@@ -1,23 +0,0 @@
-#include "core/thread/Mutex.hpp"
-
-#include <string.h>
-
-Core::Mutex::Mutex() : mutex() {
-    memset(&mutex, 0, sizeof(mutex));
-}
-
-Core::Mutex::~Mutex() {
-    mtx_destroy(&mutex);
-}
-
-cbool Core::Mutex::init() {
-    return mtx_init(&mutex, mtx_plain) != thrd_success;
-}
-
-cbool Core::Mutex::lock() {
-    return mtx_lock(&mutex) != thrd_success;
-}
-
-cbool Core::Mutex::unlock() {
-    return mtx_unlock(&mutex) != thrd_success;
-}

+ 0 - 26
old/Mutex.hpp

@@ -1,26 +0,0 @@
-#ifndef CORE_MUTEX_HPP
-#define CORE_MUTEX_HPP
-
-#include <threads.h>
-
-#include "core/utils/Check.hpp"
-#include "core/utils/Error.hpp"
-
-namespace Core {
-    class Mutex final {
-        mtx_t mutex;
-
-    public:
-        Mutex();
-        Mutex(const Mutex& other) = delete;
-        Mutex(Mutex&& other) = delete;
-        ~Mutex();
-        Mutex& operator=(const Mutex& other) = delete;
-        Mutex& operator=(Mutex&& other) = delete;
-        cbool init();
-        cbool lock();
-        cbool unlock();
-    };
-}
-
-#endif

+ 0 - 127
old/RingBuffer.hpp

@@ -1,127 +0,0 @@
-#ifndef CORE_RINGBUFFER_HPP
-#define CORE_RINGBUFFER_HPP
-
-#include <assert.h>
-
-#include "core/utils/AlignedData.hpp"
-#include "core/utils/ArrayString.hpp"
-
-namespace Core {
-    template<typename T, size_t N>
-    class RingBuffer final {
-        AlignedType<T> data[N];
-        size_t writeIndex = 0;
-        size_t readIndex = 0;
-        size_t values = 0;
-
-    public:
-        RingBuffer() = default;
-
-        RingBuffer(const RingBuffer& other) {
-            copy(other);
-        }
-
-        RingBuffer(RingBuffer&& other) {
-            move(Core::move(other));
-            other.clear();
-        }
-
-        ~RingBuffer() {
-            clear();
-        }
-
-        RingBuffer& operator=(const RingBuffer& other) {
-            if(&other != this) {
-                clear();
-                copy(other);
-            }
-            return *this;
-        }
-
-        RingBuffer& operator=(RingBuffer&& other) {
-            if(&other != this) {
-                clear();
-                move(Core::move(other));
-                other.clear();
-            }
-            return *this;
-        }
-
-        template<typename... Args>
-        T* put(Args&&... args) {
-            if(getLength() >= N) {
-                return nullptr;
-            }
-            T* t = new(data + writeIndex) T(Core::forward<Args>(args)...);
-            writeIndex = (writeIndex + 1) % N;
-            values++;
-            return t;
-        }
-
-        template<typename... Args>
-        RingBuffer& add(Args&&... args) {
-            put(Core::forward<Args>(args)...);
-            return *this;
-        }
-
-        T& operator[](size_t index) {
-            return reinterpret_cast<T*>(data)[(index + readIndex) % N];
-        }
-
-        const T& operator[](size_t index) const {
-            return reinterpret_cast<const T*>(data)[(index + readIndex) % N];
-        }
-
-        size_t getLength() const {
-            return values;
-        }
-
-        bool canRemove() const {
-            return getLength() > 0;
-        }
-
-        void clear() {
-            for(size_t i = 0; i < getLength(); i++) {
-                (*this)[i].~T();
-            }
-            writeIndex = 0;
-            readIndex = 0;
-            values = 0;
-        }
-
-        void remove() {
-            assert(canRemove());
-            values--;
-            (*this)[0].~T();
-            readIndex = (readIndex + 1) % N;
-        }
-
-        void toString(BufferString& s) const {
-            s.append("[");
-            size_t end = getLength();
-            if(end > 0) {
-                end--;
-                for(size_t i = 0; i < end; i++) {
-                    s.append((*this)[i]).append(", ");
-                }
-                s.append((*this)[end]);
-            }
-            s.append("]");
-        }
-
-    private:
-        void copy(const RingBuffer& other) {
-            for(size_t i = 0; i < other.getLength(); i++) {
-                add(other[i]);
-            }
-        }
-
-        void move(RingBuffer&& other) {
-            for(size_t i = 0; i < other.getLength(); i++) {
-                add(Core::move(other[i]));
-            }
-        }
-    };
-}
-
-#endif

+ 0 - 258
old/RingBufferTests.cpp

@@ -1,258 +0,0 @@
-#include "../Tests.hpp"
-#include "core/data/RingBuffer.hpp"
-
-template class Core::RingBuffer<int, 5>;
-
-struct Tester final {
-    static int ids;
-    static int sum;
-    int id;
-
-    Tester() : id(++ids) {
-        sum += id;
-    }
-
-    Tester(const Tester&) : id(++ids) {
-        sum += id;
-    }
-
-    Tester(Tester&&) : id(++ids) {
-        sum += id;
-    }
-
-    Tester& operator=(const Tester&) {
-        return *this;
-    }
-
-    Tester& operator=(Tester&&) {
-        return *this;
-    }
-
-    ~Tester() {
-        sum -= id;
-    }
-
-    void toString(Core::BufferString& s) const {
-        s.append(id);
-    }
-};
-
-int Tester::ids = 0;
-int Tester::sum = 0;
-
-static void resetTester() {
-    Tester::ids = 0;
-    Tester::sum = 0;
-}
-
-static void testReadAndWrite() {
-    Core::RingBuffer<int, 5> buffer;
-    CORE_TEST_FALSE(buffer.canRemove());
-    CORE_TEST_EQUAL(0, buffer.getLength());
-    buffer.add(4);
-    CORE_TEST_EQUAL(1, buffer.getLength());
-    CORE_TEST_TRUE(buffer.canRemove());
-    CORE_TEST_EQUAL(4, buffer[0]);
-    buffer.remove();
-    CORE_TEST_FALSE(buffer.canRemove());
-    CORE_TEST_EQUAL(0, buffer.getLength());
-}
-
-static void testOverflow() {
-    Core::RingBuffer<int, 3> buffer;
-    buffer.add(1).add(2).add(3).add(4).add(5);
-    CORE_TEST_EQUAL(3, buffer.getLength());
-    CORE_TEST_EQUAL(1, buffer[0]);
-    buffer.remove();
-    CORE_TEST_EQUAL(2, buffer.getLength());
-    CORE_TEST_EQUAL(2, buffer[0]);
-    buffer.remove();
-    CORE_TEST_EQUAL(1, buffer.getLength());
-    CORE_TEST_EQUAL(3, buffer[0]);
-    buffer.remove();
-    CORE_TEST_FALSE(buffer.canRemove());
-    CORE_TEST_EQUAL(0, buffer.getLength());
-}
-
-static void testRefill() {
-    Core::RingBuffer<int, 3> buffer;
-    buffer.add(1).add(2).add(3).add(4);
-    CORE_TEST_EQUAL(3, buffer.getLength());
-    CORE_TEST_TRUE(buffer.canRemove());
-    CORE_TEST_EQUAL(1, buffer[0]);
-    buffer.remove();
-    CORE_TEST_EQUAL(2, buffer[0]);
-    buffer.remove();
-    CORE_TEST_EQUAL(3, buffer[0]);
-    buffer.remove();
-    CORE_TEST_EQUAL(0, buffer.getLength());
-    CORE_TEST_FALSE(buffer.canRemove());
-    buffer.add(5).add(6);
-    CORE_TEST_EQUAL(2, buffer.getLength());
-    CORE_TEST_TRUE(buffer.canRemove());
-    CORE_TEST_EQUAL(5, buffer[0]);
-    buffer.remove();
-    CORE_TEST_EQUAL(6, buffer[0]);
-    buffer.remove();
-    CORE_TEST_FALSE(buffer.canRemove());
-    CORE_TEST_EQUAL(0, buffer.getLength());
-}
-
-static void testClear() {
-    Core::RingBuffer<int, 3> buffer;
-    buffer.add(1).add(2);
-    CORE_TEST_EQUAL(2, buffer.getLength());
-    buffer.clear();
-    CORE_TEST_FALSE(buffer.canRemove());
-    CORE_TEST_EQUAL(0, buffer.getLength());
-}
-
-static void testConstructDestruct() {
-    resetTester();
-    Core::RingBuffer<Tester, 3> buffer;
-    buffer.add();
-    CORE_TEST_EQUAL(1, Tester::sum);
-    buffer.add();
-    CORE_TEST_EQUAL(3, Tester::sum);
-    buffer.add();
-    CORE_TEST_EQUAL(6, Tester::sum);
-
-    buffer.remove();
-    CORE_TEST_EQUAL(5, Tester::sum);
-    buffer.remove();
-    CORE_TEST_EQUAL(3, Tester::sum);
-    buffer.remove();
-    CORE_TEST_EQUAL(0, Tester::sum);
-}
-
-static void testCopyDestruct() {
-    resetTester();
-    {
-        Core::RingBuffer<Tester, 3> buffer;
-        buffer.add();
-        CORE_TEST_EQUAL(1, Tester::sum);
-        buffer.add();
-        CORE_TEST_EQUAL(3, Tester::sum);
-        buffer.add();
-        CORE_TEST_EQUAL(6, Tester::sum);
-        {
-            Core::RingBuffer<Tester, 3> copy = buffer;
-            CORE_TEST_EQUAL(6 + 4 + 5 + 6, Tester::sum);
-        }
-        CORE_TEST_EQUAL(6, Tester::sum);
-    }
-    CORE_TEST_EQUAL(0, Tester::sum);
-}
-
-static void testCopyAssignmentDestruct() {
-    resetTester();
-    {
-        Core::RingBuffer<Tester, 3> buffer;
-        buffer.add();
-        CORE_TEST_EQUAL(1, Tester::sum);
-        buffer.add();
-        CORE_TEST_EQUAL(3, Tester::sum);
-        buffer.add();
-        CORE_TEST_EQUAL(6, Tester::sum);
-        {
-            Core::RingBuffer<Tester, 3> copy;
-            copy = buffer;
-            CORE_TEST_EQUAL(6 + 4 + 5 + 6, Tester::sum);
-        }
-        CORE_TEST_EQUAL(6, Tester::sum);
-    }
-    CORE_TEST_EQUAL(0, Tester::sum);
-}
-
-static void testMoveDestruct() {
-    resetTester();
-    {
-        Core::RingBuffer<Tester, 3> buffer;
-        buffer.add();
-        CORE_TEST_EQUAL(1, Tester::sum);
-        buffer.add();
-        CORE_TEST_EQUAL(3, Tester::sum);
-        buffer.add();
-        CORE_TEST_EQUAL(6, Tester::sum);
-        {
-            Core::RingBuffer<Tester, 3> move = Core::move(buffer);
-            CORE_TEST_EQUAL(4 + 5 + 6, Tester::sum);
-            CORE_TEST_EQUAL(0, buffer.getLength());
-        }
-        CORE_TEST_EQUAL(0, Tester::sum);
-    }
-    CORE_TEST_EQUAL(0, Tester::sum);
-}
-
-static void testMoveAssignmentDestruct() {
-    resetTester();
-    {
-        Core::RingBuffer<Tester, 3> buffer;
-        buffer.add();
-        CORE_TEST_EQUAL(1, Tester::sum);
-        buffer.add();
-        CORE_TEST_EQUAL(3, Tester::sum);
-        buffer.add();
-        CORE_TEST_EQUAL(6, Tester::sum);
-        {
-            Core::RingBuffer<Tester, 3> move;
-            move = Core::move(buffer);
-            CORE_TEST_EQUAL(4 + 5 + 6, Tester::sum);
-            CORE_TEST_EQUAL(0, buffer.getLength());
-        }
-        CORE_TEST_EQUAL(0, Tester::sum);
-    }
-    CORE_TEST_EQUAL(0, Tester::sum);
-}
-
-static void testOverall() {
-    resetTester();
-    Core::RingBuffer<Tester, 3> buffer;
-    buffer.add().add().add();
-    CORE_TEST_STRING("[1, 2, 3]", buffer);
-    CORE_TEST_EQUAL(3, buffer.getLength());
-    CORE_TEST_EQUAL(6, Tester::sum);
-
-    buffer.remove();
-    CORE_TEST_STRING("[2, 3]", buffer);
-    CORE_TEST_EQUAL(2, buffer.getLength());
-    CORE_TEST_EQUAL(5, Tester::sum);
-
-    buffer.add();
-    CORE_TEST_STRING("[2, 3, 4]", buffer);
-    CORE_TEST_EQUAL(3, buffer.getLength());
-    CORE_TEST_EQUAL(9, Tester::sum);
-
-    buffer.remove();
-    CORE_TEST_STRING("[3, 4]", buffer);
-    CORE_TEST_EQUAL(2, buffer.getLength());
-    CORE_TEST_EQUAL(7, Tester::sum);
-
-    buffer.add();
-    CORE_TEST_STRING("[3, 4, 5]", buffer);
-    CORE_TEST_EQUAL(3, buffer.getLength());
-    CORE_TEST_EQUAL(12, Tester::sum);
-
-    buffer.remove();
-    CORE_TEST_STRING("[4, 5]", buffer);
-    CORE_TEST_EQUAL(2, buffer.getLength());
-    CORE_TEST_EQUAL(9, Tester::sum);
-
-    buffer.clear();
-    CORE_TEST_STRING("[]", buffer);
-    CORE_TEST_EQUAL(0, buffer.getLength());
-    CORE_TEST_EQUAL(0, Tester::sum);
-}
-
-void Core::testRingBuffer() {
-    testReadAndWrite();
-    testOverflow();
-    testRefill();
-    testClear();
-    testConstructDestruct();
-    testCopyDestruct();
-    testCopyAssignmentDestruct();
-    testMoveDestruct();
-    testMoveAssignmentDestruct();
-    testOverall();
-}

+ 0 - 22
old/SpinLock.cpp

@@ -1,22 +0,0 @@
-#include "core/thread/SpinLock.hpp"
-
-#include <threads.h>
-
-Core::SpinLock::SpinLock() : locked() {
-    atomic_init(&locked, false);
-}
-
-void Core::SpinLock::lock() {
-    while(true) {
-        bool expected = false;
-        if(atomic_compare_exchange_weak(&locked, &expected, true)) {
-            break;
-        }
-        timespec s{0, 0};
-        thrd_sleep(&s, nullptr);
-    }
-}
-
-void Core::SpinLock::unlock() {
-    atomic_store(&locked, false);
-}

+ 0 - 24
old/SpinLock.hpp

@@ -1,24 +0,0 @@
-#ifndef CORE_SPIN_LOCK_HPP
-#define CORE_SPIN_LOCK_HPP
-
-// stdatomic.h is not compatible with C++
-// all calls are noexcept
-#include <atomic>
-using atomic_bool = std::atomic_bool;
-
-namespace Core {
-    class SpinLock final {
-        atomic_bool locked;
-
-    public:
-        SpinLock();
-        SpinLock(const SpinLock& other) = delete;
-        SpinLock(SpinLock&& other) = delete;
-        SpinLock& operator=(const SpinLock& other) = delete;
-        SpinLock& operator=(SpinLock&& other) = delete;
-        void lock();
-        void unlock();
-    };
-}
-
-#endif

+ 0 - 57
old/Stack.hpp

@@ -1,57 +0,0 @@
-#ifndef CORE_STACK_HPP
-#define CORE_STACK_HPP
-
-#include "core/data/ArrayList.hpp"
-#include "core/data/List.hpp"
-#include "core/utils/Error.hpp"
-
-namespace Core {
-    namespace Internal {
-        template<typename T, typename S>
-        class BaseStack final {
-            S data{};
-
-        public:
-            template<typename... Args>
-            BaseStack& push(Args&&... args) {
-                data.add(Core::forward<Args>(args)...);
-                return *this;
-            }
-
-            void clear() {
-                data.clear();
-            }
-
-            void pop() {
-                assert(data.getLength() > 0);
-                data.removeBySwap(data.getLength() - 1);
-            }
-
-            bool isEmpty() const {
-                return data.getLength() == 0;
-            }
-
-            T& peek() {
-                assert(data.getLength() > 0);
-                return data[data.getLength() - 1];
-            }
-
-            const T& peek() const {
-                assert(data.getLength() > 0);
-                return data[data.getLength() - 1];
-            }
-
-            void toString(BufferString& s) const {
-                s.append(data);
-            }
-        };
-    }
-
-    template<typename T>
-    using ListStack = Internal::BaseStack<T, List<T>>;
-
-    template<typename T, size_t N>
-    using ArrayStack = Internal::BaseStack<T, ArrayList<T, N>>;
-}
-
-#endif

+ 0 - 63
old/StackTests.cpp

@@ -1,63 +0,0 @@
-#include "../Tests.hpp"
-#include "core/data/Stack.hpp"
-
-template class Core::Internal::BaseStack<int, Core::List<int>>;
-template class Core::Internal::BaseStack<int, Core::ArrayList<int, 100>>;
-
-template<typename T>
-static void testPushPopPeek() {
-    T stack;
-    stack.push(1).push(2).push(3);
-    CORE_TEST_EQUAL(3, stack.peek());
-    CORE_TEST_EQUAL(3, static_cast<const T&>(stack).peek());
-    stack.pop();
-    CORE_TEST_EQUAL(2, stack.peek());
-    CORE_TEST_EQUAL(2, static_cast<const T&>(stack).peek());
-    stack.pop();
-    CORE_TEST_EQUAL(1, stack.peek());
-    CORE_TEST_EQUAL(1, static_cast<const T&>(stack).peek());
-    stack.pop();
-    CORE_TEST_TRUE(stack.isEmpty());
-}
-
-template<typename T>
-static void testBigPushPop(int amount) {
-    T stack;
-    for(int i = 0; i < amount; i++) {
-        stack.push(i);
-    }
-    for(int i = 0; i < amount; i++) {
-        stack.pop();
-    }
-    CORE_TEST_TRUE(stack.isEmpty());
-}
-
-template<typename T>
-static void testToString() {
-    T stack;
-    stack.push(1).push(243).push(-423);
-    CORE_TEST_STRING("[1, 243, -423]", stack);
-    CORE_TEST_STRING("[1]", T().push(1));
-    CORE_TEST_STRING("[]", T());
-}
-
-template<typename T>
-static void testClear() {
-    T stack;
-    stack.push(1).push(2).push(3);
-    stack.clear();
-    CORE_TEST_TRUE(stack.isEmpty());
-}
-
-template<typename T>
-static void testType(int amount) {
-    testPushPopPeek<T>();
-    testBigPushPop<T>(amount);
-    testToString<T>();
-    testClear<T>();
-}
-
-void Core::testStack(bool light) {
-    testType<Core::ListStack<int>>(light ? 10000 : 100000);
-    testType<Core::ArrayStack<int, 100>>(100);
-}

+ 0 - 57
old/Thread.cpp

@@ -1,57 +0,0 @@
-#include "core/thread/Thread.hpp"
-
-#include <string.h>
-
-static void reset(thrd_t& t) {
-    memset(&t, 0, sizeof(thrd_t));
-}
-
-Core::Thread::Thread() : thread() {
-    reset(thread);
-}
-
-Core::Thread::Thread(Thread&& other) : thread() {
-    swap(other);
-}
-
-static bool doesExist(thrd_t& t) {
-    thrd_t zero{};
-    return memcmp(&zero, &t, sizeof(thrd_t)) != 0;
-}
-
-Core::Thread::~Thread() {
-    if(doesExist(thread)) {
-        (void)join(nullptr);
-    }
-}
-
-Core::Thread& Core::Thread::operator=(Thread&& other) {
-    if(this != &other) {
-        if(doesExist(thread)) {
-            (void)join(nullptr);
-        }
-        reset(thread);
-        swap(other);
-    }
-    return *this;
-}
-
-cbool Core::Thread::start(Function f, void* p) {
-    if(doesExist(thread)) {
-        return true;
-    }
-    return thrd_create(&thread, f, p) != thrd_success;
-}
-
-cbool Core::Thread::join(int* returnValue) {
-    int e = thrd_join(thread, returnValue);
-    reset(thread);
-    return e != thrd_success;
-}
-
-void Core::Thread::swap(Thread& other) {
-    thrd_t tmp;
-    memcpy(&tmp, &thread, sizeof(thrd_t));
-    memcpy(&thread, &other.thread, sizeof(thrd_t));
-    memcpy(&other.thread, &tmp, sizeof(thrd_t));
-}

+ 0 - 27
old/Thread.hpp

@@ -1,27 +0,0 @@
-#ifndef CORE_THREAD_HPP
-#define CORE_THREAD_HPP
-
-#include <threads.h>
-
-#include "core/utils/Check.hpp"
-
-namespace Core {
-    class Thread final {
-        thrd_t thread;
-
-    public:
-        using Function = int (*)(void*);
-
-        Thread();
-        Thread(const Thread& other) = delete;
-        Thread(Thread&& other);
-        ~Thread();
-        Thread& operator=(const Thread& other) = delete;
-        Thread& operator=(Thread&& other);
-        void swap(Thread& other);
-        cbool start(Function f, void* p);
-        cbool join(int* returnValue = nullptr);
-    };
-}
-
-#endif

+ 0 - 168
old/ThreadTests.cpp

@@ -1,168 +0,0 @@
-#include <threads.h>
-
-#include "../Tests.hpp"
-#include "core/thread/Mutex.hpp"
-#include "core/thread/SpinLock.hpp"
-#include "core/thread/Thread.hpp"
-#include "core/utils/Clock.hpp"
-
-static int runDone = 0;
-
-struct IntHolder {
-    int value;
-};
-
-static int run(void*) {
-    runDone = 1;
-    return 7;
-}
-
-static void testStart() {
-    runDone = 0;
-    Core::Thread t;
-    CORE_TEST_FALSE(t.start(run, nullptr));
-    int returnValue = 0;
-    CORE_TEST_FALSE(t.join(&returnValue));
-    CORE_TEST_EQUAL(1, runDone);
-    CORE_TEST_EQUAL(7, returnValue);
-}
-
-static void testLambda() {
-    IntHolder i(0);
-    Core::Thread t;
-    CORE_TEST_FALSE(t.start(
-        [](void* p) {
-            IntHolder* ip = static_cast<IntHolder*>(p);
-            ip->value = 2;
-            return 0;
-        },
-        &i));
-    CORE_TEST_FALSE(t.join(nullptr));
-    CORE_TEST_EQUAL(2, i.value);
-}
-
-static void testJoinWithoutStart() {
-    Core::Thread t;
-    CORE_TEST_TRUE(t.join(nullptr));
-}
-
-static void testAutoJoin() {
-    Core::Thread t;
-    CORE_TEST_FALSE(t.start([](void*) { return 0; }, nullptr));
-}
-
-static void testMove() {
-    Core::Thread t;
-    CORE_TEST_FALSE(t.start([](void*) { return 0; }, nullptr));
-    Core::Thread m = Core::move(t);
-    CORE_TEST_FALSE(m.join());
-}
-
-static void testMoveAssignment() {
-    Core::Thread t;
-    CORE_TEST_FALSE(t.start([](void*) { return 0; }, nullptr));
-    Core::Thread m;
-    m = Core::move(t);
-    CORE_TEST_FALSE(m.join());
-}
-
-static void testMoveIntoActive() {
-    Core::Thread t;
-    CORE_TEST_FALSE(t.start([](void*) { return 0; }, nullptr));
-    Core::Thread m;
-    t = Core::move(m);
-}
-
-static void testDoubleJoin() {
-    Core::Thread t;
-    CORE_TEST_FALSE(t.start([](void*) { return 0; }, nullptr));
-    CORE_TEST_FALSE(t.join(nullptr));
-    CORE_TEST_TRUE(t.join(nullptr));
-}
-
-struct MutexCounter {
-    Core::Mutex m{};
-    int counter = 0;
-};
-
-static int incrementMutexCounter(void* p) {
-    MutexCounter* mcp = static_cast<MutexCounter*>(p);
-    for(int i = 0; i < 10000; i++) {
-        (void)mcp->m.lock();
-        mcp->counter++;
-        (void)mcp->m.unlock();
-    }
-    return 0;
-}
-
-static void testMutex() {
-    Core::Clock::Nanos n;
-    CORE_TEST_ERROR(Core::Clock::getNanos(n));
-
-    MutexCounter mc;
-    CORE_TEST_FALSE(mc.m.init());
-    Core::Thread t[2];
-    CORE_TEST_FALSE(t[0].start(incrementMutexCounter, &mc));
-    CORE_TEST_FALSE(t[1].start(incrementMutexCounter, &mc));
-    CORE_TEST_FALSE(t[0].join(nullptr));
-    CORE_TEST_FALSE(t[1].join(nullptr));
-    CORE_TEST_EQUAL(20000, mc.counter);
-
-    Core::Clock::Nanos n2;
-    CORE_TEST_ERROR(Core::Clock::getNanos(n2));
-    Core::ArrayString<64> s;
-    s.append(n2 - n).append("ns Mutex").printLine();
-}
-
-struct SpinLockCounter {
-    Core::SpinLock s{};
-    int counter = 0;
-};
-
-static int incrementSpinLockCounter(void* p) {
-    SpinLockCounter* mcp = static_cast<SpinLockCounter*>(p);
-    for(int i = 0; i < 10000; i++) {
-        mcp->s.lock();
-        mcp->counter++;
-        mcp->s.unlock();
-    }
-    return 0;
-}
-
-static void testSpinLock() {
-    Core::Clock::Nanos n;
-    CORE_TEST_ERROR(Core::Clock::getNanos(n));
-
-    SpinLockCounter sc;
-    Core::Thread t[2];
-    CORE_TEST_FALSE(t[0].start(incrementSpinLockCounter, &sc));
-    CORE_TEST_FALSE(t[1].start(incrementSpinLockCounter, &sc));
-    CORE_TEST_FALSE(t[0].join(nullptr));
-    CORE_TEST_FALSE(t[1].join(nullptr));
-    CORE_TEST_EQUAL(20000, sc.counter);
-
-    Core::Clock::Nanos n2;
-    CORE_TEST_ERROR(Core::Clock::getNanos(n2));
-    Core::ArrayString<64> s;
-    s.append(n2 - n).append("ns SpinLock").printLine();
-}
-
-static void testDoubleStart() {
-    Core::Thread t;
-    CORE_TEST_FALSE(t.start([](void*) { return 0; }, nullptr));
-    CORE_TEST_TRUE(t.start([](void*) { return 0; }, nullptr));
-}
-
-void Core::testThread() {
-    testStart();
-    testLambda();
-    testJoinWithoutStart();
-    testAutoJoin();
-    testMove();
-    testMoveAssignment();
-    testMoveIntoActive();
-    testDoubleJoin();
-    testMutex();
-    testSpinLock();
-    testDoubleStart();
-}

+ 0 - 125
old/performance/Main.cpp

@@ -1,125 +0,0 @@
-#include "../test/Test.hpp"
-#include "core/data/HashMap.hpp"
-#include "core/data/ProbingHashMap.hpp"
-#include "core/utils/Clock.hpp"
-#include "core/utils/Random.hpp"
-
-using Nanos = Core::Clock::Nanos;
-namespace Logger = Core::Logger;
-
-struct Timer {
-    Nanos nanos;
-
-    Timer() : nanos(0) {
-        CORE_TEST_ERROR(Core::Clock::getNanos(nanos));
-    }
-
-    Nanos get() const {
-        Nanos nanos2 = 0;
-        CORE_TEST_ERROR(Core::Clock::getNanos(nanos2));
-        return nanos2 - nanos;
-    }
-};
-
-template<typename Map>
-static Nanos testSearch(const Map& m) {
-    Timer t;
-    volatile int sum = 0;
-    for(int i = 0; i < 10000; i++) {
-        for(int k = -5000; k < 5000; k++) {
-            const int* s = m.search(i + k);
-            if(s != nullptr) {
-                sum = sum + *s;
-            }
-        }
-    }
-    return t.get();
-}
-
-template<typename Map>
-static Nanos testEmptySearch(const Map& m) {
-    Timer t;
-    volatile int sum = 0;
-    for(int i = 0; i < 100'000'000; i++) {
-        const int* s = m.search(-i);
-        if(s != nullptr) {
-            sum = sum + *s;
-        }
-    }
-    return t.get();
-}
-
-template<typename Map>
-static void fillOrder(Map& m) {
-    for(int i = 0; i < 10000; i++) {
-        m.add(i, i * i);
-    }
-}
-
-template<typename Map>
-static void fillChaos(Map& m) {
-    Core::Random random(0);
-    for(int i = 0; i < 10000; i++) {
-        int r = random.nextI32(0, 9999);
-        m.add(r, r * r);
-    }
-}
-
-template<typename Map>
-static int average(Map& m, Nanos (*f)(const Map&), int n) {
-    Nanos sum = 0;
-    for(int i = 0; i < n; i++) {
-        sum += f(m);
-    }
-    return static_cast<int>(sum / (n * 1'000'000));
-}
-
-static void order(int n) {
-    Core::HashMap<int, int> m;
-    Core::ProbingHashMap<int, int> m2;
-    fillOrder(m);
-    fillOrder(m2);
-    Logger::log(Logger::COLOR_GRAY, "Order Chaining | Order Probing");
-    Logger::log(Logger::COLOR_GRAY, "Search | # ms | # ms",
-                average(m, testSearch, n), average(m2, testSearch, n));
-    Logger::log(Logger::COLOR_GRAY, "EmptySearch | # ms | # ms",
-                average(m, testEmptySearch, n),
-                average(m2, testEmptySearch, n));
-}
-
-static void chaos(int n) {
-    Core::HashMap<int, int> m;
-    Core::ProbingHashMap<int, int> m2;
-    fillChaos(m);
-    fillChaos(m2);
-    Logger::log(Logger::COLOR_GRAY, "Chaos Chaining | Chaos Probing");
-    Logger::log(Logger::COLOR_GRAY, "Search | # ms | # ms",
-                average(m, testSearch, n), average(m2, testSearch, n));
-    Logger::log(Logger::COLOR_GRAY, "EmptySearch | # ms | # ms",
-                average(m, testEmptySearch, n),
-                average(m2, testEmptySearch, n));
-}
-
-static void testProbing(int n) {
-    Core::ProbingHashMap<int, int> m;
-    Core::ProbingHashMap<int, int> m2;
-    fillOrder(m);
-    fillChaos(m2);
-    Logger::log(Logger::COLOR_GRAY, "Order | Chaos");
-    Logger::log(Logger::COLOR_GRAY, "Search | # ms | # ms",
-                average(m, testSearch, n), average(m2, testSearch, n));
-    Logger::log(Logger::COLOR_GRAY, "EmptySearch | # ms | # ms",
-                average(m, testEmptySearch, n),
-                average(m2, testEmptySearch, n));
-}
-
-int main() {
-    (void)order;
-    (void)chaos;
-    (void)testProbing;
-    order(3);
-    chaos(3);
-    // testProbing(3);
-    Core::Test::finalize();
-    return 0;
-}

+ 34 - 41
performance/Main.cpp

@@ -1,84 +1,77 @@
-#include <inttypes.h>
-#include <stdio.h>
+#include "core/Clock.hpp"
+#include "core/HashMap.hpp"
+#include "core/Logger.hpp"
+#include "core/Random.hpp"
 
-#include "core/HashMap.h"
-#include "core/Random.h"
-#include "core/Utility.h"
+using HashMapInt = Core::HashMap<int, int>;
+using Core::Clock;
 
-HASHMAP(int, int, Int)
-HASHMAP_SOURCE(int, int, Int)
-
-static i64 testSearch(const HashMapInt* m) {
-    i64 nanos = getNanos();
+static i64 testSearch(const HashMapInt& m) {
+    i64 nanos = Clock::getNanos();
     volatile int sum = 0;
     for(int i = 0; i < 10'000; i++) {
         for(int k = -5000; k < 5000; k++) {
-            const int* s = searchHashMapKeyInt(m, i + k);
+            const int* s = m.search(i + k);
             if(s != nullptr) {
                 sum = sum + *s;
             }
         }
     }
-    return getNanos() - nanos;
+    return Clock::getNanos() - nanos;
 }
 
-static i64 testEmptySearch(const HashMapInt* m) {
-    i64 nanos = getNanos();
+static i64 testEmptySearch(const HashMapInt& m) {
+    i64 nanos = Clock::getNanos();
     volatile int sum = 0;
     for(int i = 0; i < 100'000'000; i++) {
-        const int* s = searchHashMapKeyInt(m, -i);
+        const int* s = m.search(-i);
         if(s != nullptr) {
             sum = sum + *s;
         }
     }
-    return getNanos() - nanos;
+    return Clock::getNanos() - nanos;
 }
 
-static void fillOrder(HashMapInt* m) {
-    i64 nanos = getNanos();
+static void fillOrder(HashMapInt& m) {
+    i64 nanos = Clock::getNanos();
     for(int i = 0; i < 10'000; i++) {
-        *putHashMapKeyInt(m, i) = i * i;
+        m.put(i, i * i);
     }
-    printf("Fill Order: %" PRId64 "ns\n", getNanos() - nanos);
+    LOG_INFO("Fill Order: #ns", Clock::getNanos() - nanos);
 }
 
-static void fillChaos(HashMapInt* m) {
-    i64 nanos = getNanos();
-    Random random;
-    initRandom(&random, 0);
+static void fillChaos(HashMapInt& m) {
+    i64 nanos = Clock::getNanos();
+    Core::Random random(0);
     for(int i = 0; i < 10'000; i++) {
-        int r = randomI32(&random, 0, 10'000);
-        *putHashMapKeyInt(m, r) = r * r;
+        int r = random.nextI32(0, 10'000);
+        m.put(r, r * r);
     }
-    printf("Fill Chaos: %" PRId64 "ns\n", getNanos() - nanos);
+    LOG_INFO("Fill Chaos: #ns", Clock::getNanos() - nanos);
 }
 
-static i64 average(HashMapInt* m, i64 (*f)(const HashMapInt* m), int n) {
+static i64 average(HashMapInt& m, i64 (*f)(const HashMapInt& m), int n) {
     i64 sum = 0;
     for(int i = 0; i < n; i++) {
         sum += f(m);
     }
-    return (i64)(sum / (n * 1'000'000));
+    return static_cast<i64>(sum / (n * 1'000'000));
 }
 
 static void order(int n) {
     HashMapInt m;
-    initHashMapInt(&m);
-    fillOrder(&m);
-    puts("Order Probing");
-    printf("Search | %" PRId64 " ms\n", average(&m, testSearch, n));
-    printf("EmptySearch | %" PRId64 " ms\n", average(&m, testEmptySearch, n));
-    destroyHashMapInt(&m);
+    fillOrder(m);
+    LOG_INFO("Order Probing");
+    LOG_INFO("Search | #ms", average(m, testSearch, n));
+    LOG_INFO("EmptySearch | #ms", average(m, testEmptySearch, n));
 }
 
 static void chaos(int n) {
     HashMapInt m;
-    initHashMapInt(&m);
-    fillChaos(&m);
-    puts("Chaos Probing");
-    printf("Search | %" PRId64 " ms\n", average(&m, testSearch, n));
-    printf("EmptySearch | %" PRId64 " ms\n", average(&m, testEmptySearch, n));
-    destroyHashMapInt(&m);
+    fillChaos(m);
+    LOG_INFO("Chaos Probing");
+    LOG_INFO("Search | #ms", average(m, testSearch, n));
+    LOG_INFO("EmptySearch | #ms", average(m, testEmptySearch, n));
 }
 
 int main() {

+ 98 - 60
src/BitArray.cpp

@@ -1,19 +1,17 @@
 #include "core/BitArray.hpp"
 
-#include <assert.h>
-#include <inttypes.h>
-#include <string.h>
+#include <cassert>
+#include <cstring>
 
+#include "core/BitArray.hpp"
 #include "core/ToString.hpp"
 #include "core/Utility.hpp"
 
+using Core::BitArray;
+
 static constexpr size_t U64_BITS = 64;
 static constexpr size_t DIVIDE_BITS = 6;
 
-static u64 roundUpDivide(u64 a, u64 b) {
-    return a / b + ((a % b) != 0);
-}
-
 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;
@@ -27,7 +25,7 @@ static u64 readBits(const u64* data, size_t index, u64 bits) {
     return r;
 }
 
-static void writeBits(u64* data, size_t index, size_t bits, u64 value) {
+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;
@@ -42,102 +40,142 @@ static void writeBits(u64* data, size_t index, size_t bits, u64 value) {
     }
 }
 
+static u64 roundUpDivide(u64 a, u64 b) {
+    return a / b + ((a % b) != 0);
+}
+
 static size_t getArrayLength(size_t length, size_t bits) {
     return roundUpDivide(length * bits, U64_BITS);
 }
 
-void initBitArray(BitArray* a, size_t length, size_t bits) {
-    *a = (BitArray){0};
-    if(length > 0 && bits > 0) {
-        setBitLength(a, length, bits);
+BitArray::BitArray() : length(0), bits(0), data(nullptr) {
+}
+
+BitArray::BitArray(const BitArray& other) : BitArray() {
+    resize(other.getLength(), other.getBits());
+    size_t l = getLength();
+    for(size_t i = 0; i < l; i++) {
+        set(i, other.get(i));
     }
 }
 
-void destroyBitArray(BitArray* a) {
-    coreFree(a->data);
-    *a = (BitArray){0};
+BitArray::BitArray(BitArray&& other) : BitArray() {
+    swap(other);
 }
 
-void setBits(BitArray* a, size_t index, u64 value) {
-    assert(a->data != nullptr);
-    assert(index < a->length);
-    writeBits(a->data, index, a->bits, value);
+BitArray::~BitArray() {
+    coreDeleteN(data);
 }
 
-void setAllBits(BitArray* a, u64 value) {
-    size_t length = a->length;
-    for(size_t i = 0; i < length; i++) {
-        setBits(a, i, value);
-    }
+BitArray& BitArray::operator=(BitArray other) {
+    swap(other);
+    return *this;
+}
+
+BitArray& BitArray::set(size_t index, u64 value) {
+    assert(data != nullptr);
+    assert(index < length);
+    setBits(data, index, bits, value);
+    return *this;
 }
 
-u64 getBits(const BitArray* a, size_t index) {
-    assert(a->data != nullptr);
-    assert(index < a->length);
-    return readBits(a->data, index, a->bits);
+u64 BitArray::get(size_t index) const {
+    assert(data != nullptr);
+    assert(index < length);
+    return readBits(data, index, bits);
 }
 
-i64 selectBits(const BitArray* a, size_t index) {
+size_t BitArray::getLength() const {
+    return length;
+}
+
+size_t BitArray::getBits() const {
+    return bits;
+}
+
+size_t Core::BitArray::getInternalByteSize() const {
+    if(getLength() <= 0 || getBits() <= 0) {
+        return 0;
+    }
+    return getArrayLength(getLength(), getBits()) * sizeof(u64);
+}
+
+i64 BitArray::select(u64 index) const {
     if(index <= 0) {
         return -1;
     }
     u64 found = 0;
-    size_t end = getArrayLength(a->length, a->bits);
+    size_t end = getArrayLength(length, bits);
     for(size_t i = 0; i < end; i++) {
-        u64 ones = popCount(a->data[i]);
+        u64 ones = Core::popCount<u64, u64>(data[i]);
         found += ones;
         if(found >= index) {
             found -= ones;
-            u64 c = i * U64_BITS - 1;
-            u64 d = a->data[i];
+            u64 a = i * U64_BITS - 1;
+            u64 d = data[i];
             while(found < index) {
                 found += d & 1;
                 d >>= 1;
-                c++;
+                a++;
             }
-            return (i64)c;
+            return static_cast<i64>(a);
         }
     }
     return -1;
 }
 
-void setBitLength(BitArray* a, size_t newLength, size_t newBits) {
+void BitArray::fill(u64 value) {
+    size_t l = getLength();
+    for(size_t i = 0; i < l; i++) {
+        set(i, value);
+    }
+}
+
+void BitArray::resize(size_t newLength, size_t newBits) {
     if(newLength == 0 || newBits == 0) {
-        destroyBitArray(a);
         return;
     } else if(newBits > 64) {
         newBits = 64;
     }
     size_t arrayLength = getArrayLength(newLength, newBits);
-    u64* newData = coreAllocate(sizeof(u64) * arrayLength);
+    u64* newData = coreNewN(u64, arrayLength);
     memset(newData, 0, arrayLength * sizeof(u64));
 
-    size_t end = minSize(a->length, newLength);
+    size_t end = Core::min(length, newLength);
     for(size_t i = 0; i < end; i++) {
-        writeBits(newData, i, newBits, getBits(a, i));
+        setBits(newData, i, newBits, get(i));
     }
     for(size_t i = end; i < newLength; i++) {
-        writeBits(newData, i, newBits, 0);
+        setBits(newData, i, newBits, 0);
     }
-    coreFree(a->data);
-    a->data = newData;
-    a->length = newLength & 0xFF'FFFF'FFFF'FFFF;
-    a->bits = newBits & 0xFF;
-}
-
-size_t toStringBitArray(const BitArray* a, char* buffer, size_t n) {
-    size_t w = 0;
-    stringAdd(&w, &buffer, &n, toString(buffer, n, "["));
-    size_t length = a->length;
-    if(length > 0) {
-        length--;
-        for(size_t i = 0; i < length; i++) {
-            u64 v = getBits(a, i);
-            stringAdd(&w, &buffer, &n, toString(buffer, n, "%" PRIu64 ", ", v));
+    delete[] data;
+    data = newData;
+    length = newLength & 0x00FF'FFFF;
+    bits = newBits & 0xFF;
+}
+
+size_t BitArray::toString(char* s, size_t n) const {
+    size_t total = 0;
+    addString("[", s, n, total);
+    size_t l = length;
+    if(l > 0) {
+        l--;
+        for(size_t i = 0; i < l; i++) {
+            addString(get(i), s, n, total);
+            addString(", ", s, n, total);
         }
-        u64 v = getBits(a, length);
-        stringAdd(&w, &buffer, &n, toString(buffer, n, "%" PRIu64, v));
+        addString(get(l), s, n, total);
     }
-    stringAdd(&w, &buffer, &n, toString(buffer, n, "]"));
-    return w;
+    addString("]", s, n, total);
+    return total;
+}
+
+void BitArray::swap(BitArray& other) {
+    u64 l = length;
+    u64 b = bits;
+    length = other.length;
+    bits = other.bits;
+    other.length = l & 0x00FF'FFFF;
+    other.bits = b & 0xFF;
+    Core::swap(data, other.data);
 }

+ 46 - 16
src/Buffer.cpp

@@ -1,29 +1,59 @@
 #include "core/Buffer.hpp"
 
-#include <string.h>
+#include <cstring>
 
+#include "core/Buffer.hpp"
+#include "core/Math.hpp"
 #include "core/Utility.hpp"
 
-void initBuffer(Buffer* b) {
-    b->buffer = nullptr;
-    b->capacity = 0;
-    b->size = 0;
+Core::Buffer::Buffer() : length(0), capacity(0), buffer(nullptr) {
+}
+
+Core::Buffer::Buffer(const Buffer& other) : Buffer() {
+    add(other.getData(), other.getLength());
+}
+
+Core::Buffer::Buffer(Buffer&& other) noexcept : Buffer() {
+    swap(other);
+}
+
+Core::Buffer::~Buffer() {
+    deallocateRaw(buffer);
 }
 
-void destroyBuffer(Buffer* b) {
-    coreFree(b->buffer);
-    initBuffer(b);
+Core::Buffer& Core::Buffer::operator=(Buffer&& other) noexcept {
+    swap(other);
+    return *this;
 }
 
-void addSizedBufferData(Buffer* b, const void* data, size_t size) {
-    while(b->size + size >= b->capacity) {
-        b->capacity = b->capacity == 0 ? 8 : (b->capacity * 5) / 4;
-        b->buffer = coreReallocate(b->buffer, b->capacity);
+Core::Buffer& Core::Buffer::operator=(const Buffer& other) {
+    return add(other.getData(), other.length);
+}
+
+Core::Buffer& Core::Buffer::add(const void* data, size_t size) {
+    while(length + size > capacity) {
+        capacity += Core::max<size_t>(8, capacity / 4);
+        buffer = static_cast<char*>(reallocateRaw(buffer, capacity));
     }
-    memcpy(b->buffer + b->size, data, size);
-    b->size += size;
+    memcpy(buffer + length, data, size);
+    length += size;
+    return *this;
+}
+
+size_t Core::Buffer::getLength() const {
+    return length;
+}
+
+const char* Core::Buffer::getData() const {
+    return buffer;
+}
+
+void Core::Buffer::swap(Buffer& other) {
+    Core::swap(length, other.length);
+    Core::swap(capacity, other.capacity);
+    Core::swap(buffer, other.buffer);
 }
 
-void clearBuffer(Buffer* b) {
-    b->size = 0;
+void Core::Buffer::clear() {
+    length = 0;
 }

+ 58 - 0
src/Clock.cpp

@@ -0,0 +1,58 @@
+#include "core/Clock.hpp"
+
+#include <chrono>
+#include <thread>
+
+#include "ErrorSimulator.hpp"
+
+using Core::Clock;
+
+Clock::Clock() : index(0), last(0), sum(0), time({}) {
+}
+
+i64 Clock::update() {
+    i64 current = getNanos();
+    if(current < 0) {
+        return current;
+    }
+    if(last == 0) {
+        last = current;
+        return 0;
+    }
+    index = (index + 1) & (time.getLength() - 1);
+    sum -= time[index];
+    time[index] = current - last;
+    sum += time[index];
+    last = current;
+    return time[index];
+}
+
+float Core::Clock::getUpdatesPerSecond() const {
+    return (time.getLength() * 1000000000.0f) / static_cast<float>(sum);
+}
+
+bool Clock::sleepNanos(i64 nanos) {
+    try {
+        FAIL_STEP_THROW();
+        std::this_thread::sleep_for(std::chrono::nanoseconds(nanos));
+    } catch(...) {
+        return true;
+    }
+    return false;
+}
+
+bool Clock::sleepMillis(i64 millis) {
+    return sleepNanos(millis * 1'000'000l);
+}
+
+i64 Clock::getNanos(void) {
+    try {
+        FAIL_STEP_THROW();
+        using namespace std::chrono;
+        return duration_cast<nanoseconds>(
+                   high_resolution_clock::now().time_since_epoch())
+            .count();
+    } catch(std::exception& e) {
+        return -1;
+    }
+}

+ 0 - 4
src/Components.cpp

@@ -1,4 +0,0 @@
-#include "core/Components.hpp"
-
-LIST_SOURCE(size_t, Size)
-HASHMAP_SOURCE(size_t, size_t, Size)

+ 2 - 0
src/File.cpp

@@ -5,6 +5,8 @@
 #include "ErrorSimulator.hpp"
 #include "core/Logger.hpp"
 
+using Core::LogLevel;
+
 static bool readOpenFile(FILE* file, Core::List<char>& f, const char* path) {
     if(FAIL_STEP || fseek(file, 0, SEEK_END)) {
         REPORT(LogLevel::ERROR, "cannot seek file end of '#'", path);

+ 0 - 24
src/HashMap.cpp

@@ -1,24 +0,0 @@
-#include "core/ProbingHashMap.hpp"
-
-/*size_t hashString(const char* key) {
-    size_t h = 0;
-    while(*key != '\0') {
-        h = 2'120'251'889lu * h + (size_t)(*(key++));
-    }
-    return h;
-}
-
-size_t roundUp2(size_t n) {
-    n -= n != 0;
-    n |= n >> 1;
-    n |= n >> 2;
-    n |= n >> 4;
-    n |= n >> 8;
-    if(sizeof(n) >= 4) {
-        n |= n >> 16;
-    }
-    if(sizeof(n) >= 8) {
-        n |= n >> 32;
-    }
-    return n + 1;
-}*/

+ 5 - 5
src/Logger.cpp

@@ -1,22 +1,22 @@
 #include "core/Logger.hpp"
 
-LogLevel logLevel = LogLevel::DEBUG;
-static ReportHandler reportHandler = nullptr;
+Core::LogLevel Core::logLevel = Core::LogLevel::DEBUG;
+static Core::ReportHandler reportHandler = nullptr;
 static void* reportData = nullptr;
 
-void setReportHandler(ReportHandler h, void* data) {
+void Core::setReportHandler(ReportHandler h, void* data) {
     reportHandler = h;
     reportData = data;
 }
 
-void callReportHandler(
+void Core::callReportHandler(
     LogLevel l, const char* file, int line, const char* report) {
     if(reportHandler != nullptr) {
         reportHandler(l, file, line, reportData, report);
     }
 }
 
-const char* getShortFileName(const char* s) {
+const char* Core::getShortFileName(const char* s) {
     const char* r = s;
     while(*s != '\0') {
         if(*(s++) == '/') {

+ 48 - 77
src/ReadLine.cpp

@@ -1,12 +1,9 @@
 #include "core/ReadLine.hpp"
 
-#include <ctype.h>
-#include <stdatomic.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
+#include <atomic>
 
-#include "ErrorSimulator.hpp"
+#include "core/Array.hpp"
+#include "core/Clock.hpp"
 #include "core/Logger.hpp"
 #include "core/Queue.hpp"
 #include "core/Thread.hpp"
@@ -15,22 +12,19 @@
 static constexpr size_t HISTORY_LENGTH = 10;
 static constexpr size_t CONSOLE_BUFFER_SIZE = 256;
 
-typedef struct ConsoleLine {
-    char data[CONSOLE_BUFFER_SIZE];
-    size_t length;
-} ConsoleLine;
+struct ConsoleLine {
+    Core::Array<char, 256> data{};
+    size_t length = 0;
+};
 
-QUEUE(ConsoleLine, CL)
-QUEUE_SOURCE(ConsoleLine, CL)
+static std::atomic_bool running = true;
+static Core::Thread readThread;
 
-static atomic_bool running = true;
-static thrd_t readThread = {0};
-
-static QueueCL buffer = {0};
-static ConsoleLine currentBuffer = {0};
+static Core::Queue<ConsoleLine, 10> buffer;
+static ConsoleLine currentBuffer;
 static size_t move = 0;
 static size_t cursorMove = 0;
-static mtx_t bufferMutex = {0};
+static Core::Mutex bufferMutex;
 
 static ConsoleLine history[HISTORY_LENGTH];
 static size_t historyOffset = 0;
@@ -38,7 +32,7 @@ static size_t historyIndex = 0;
 static size_t historyLength = 0;
 
 static void addChar(u64 c) {
-    UTF8 u = convertUnicodeToUTF8((u32)c);
+    Core::UTF8 u = Core::convertUnicodeToUTF8(static_cast<u32>(c));
     for(u32 k = 0; k < u.length; k++) {
         if(currentBuffer.length >= CONSOLE_BUFFER_SIZE - 1) {
             return;
@@ -48,7 +42,8 @@ static void addChar(u64 c) {
                 currentBuffer.data[currentBuffer.length - i - 1];
         }
         currentBuffer.length++;
-        currentBuffer.data[currentBuffer.length - move - 1] = (char)u.data[k];
+        currentBuffer.data[currentBuffer.length - move - 1] =
+            static_cast<char>(u.data[k]);
         currentBuffer.data[currentBuffer.length] = '\0';
     }
 }
@@ -59,12 +54,12 @@ static void print(const char* s) {
 
 static void refreshLine(const char* prefix) {
     print(prefix);
-    print(currentBuffer.data);
+    print(currentBuffer.data.begin());
     if(cursorMove > 0) {
-        moveCursorLeft((int)cursorMove);
+        Core::moveCursorLeft(static_cast<int>(cursorMove));
     }
     fflush(stdout);
-    clearTerminalLine();
+    Core::clearTerminalLine();
 }
 
 static bool clear() {
@@ -84,23 +79,10 @@ static void addToHistory() {
     historyIndex = (historyIndex + 1) % HISTORY_LENGTH;
 }
 
-static void lock() {
-    if(mtx_lock(&bufferMutex) != thrd_success || MUTEX_LOCK_FAIL) {
-        REPORT(LOG_WARNING, "could not lock buffer mutex");
-    }
-}
-
-static void unlock() {
-    if(mtx_unlock(&bufferMutex) != thrd_success || MUTEX_UNLOCK_FAIL) {
-        REPORT(LOG_WARNING, "could not unlock buffer mutex");
-    }
-}
-
 static void addLine() {
     addToHistory();
-    lock();
-    pushQueueDataCL(&buffer, currentBuffer);
-    unlock();
+    Core::MutexGuard mg(bufferMutex);
+    buffer.add(currentBuffer);
     clear();
 }
 
@@ -108,8 +90,9 @@ static bool removeChar() {
     size_t pos = currentBuffer.length - move;
     if(pos > 0) {
         size_t l = 1;
-        while(pos - l >= 0) {
-            if(!isUTF8Remainder((u8)currentBuffer.data[pos - l])) {
+        while(pos >= l) {
+            if(!Core::isUTF8Remainder(
+                   static_cast<u8>(currentBuffer.data[pos - l]))) {
                 break;
             }
             l++;
@@ -162,7 +145,8 @@ static char getMoved() {
 static void handleLeftArrow() {
     if(move < currentBuffer.length) {
         move++;
-        while(move < currentBuffer.length && isUTF8Remainder((u8)getMoved())) {
+        while(move < currentBuffer.length &&
+              Core::isUTF8Remainder(static_cast<u8>(getMoved()))) {
             move++;
         }
         cursorMove++;
@@ -172,7 +156,7 @@ static void handleLeftArrow() {
 static void handleRightArrow() {
     if(move > 0) {
         move--;
-        while(move > 0 && isUTF8Remainder((u8)getMoved())) {
+        while(move > 0 && Core::isUTF8Remainder(static_cast<u8>(getMoved()))) {
             move--;
         }
         cursorMove--;
@@ -181,7 +165,7 @@ static void handleRightArrow() {
 
 static void handleChars() {
     while(true) {
-        u64 c = getRawChar();
+        u64 c = Core::getRawChar();
         if(c == 0) {
             break;
         } else if(c == TERMINAL_KEY_ARROW_UP) {
@@ -197,66 +181,53 @@ static void handleChars() {
                 handleRightArrow();
                 removeChar();
             }
-        } else if(iscntrl(c)) {
+        } else if(iscntrl(c & 0x7FFF'FFFF)) {
             if(handleControlKey(c)) {
                 addLine();
                 return;
             }
-        } else {
+        } else if(!Core::isSpecialChar(c)) {
             addChar(c);
         }
     }
 }
 
-static int loop(void* data) {
-    (void)data;
+static void loop(void*) {
     while(running) {
         handleChars();
-        refreshLine("wusi> ");
-        struct timespec t = {.tv_nsec = 1'000'000};
-        thrd_sleep(&t, nullptr);
+        refreshLine("> ");
+        Core::Clock::sleepMillis(1);
     }
-    return 0;
 }
 
-bool startReadLine(void) {
+bool Core::startReadLine(void) {
     if(enterRawTerminal()) {
-        REPORT(LOG_WARNING, "cannot set terminal attributes");
+        REPORT(LogLevel::WARNING, "cannot set terminal attributes");
     }
-    initQueueCL(&buffer, 10);
-    atomic_store(&running, true);
-    if(MUTEX_INIT_FAIL || mtx_init(&bufferMutex, mtx_plain) != thrd_success) {
-        REPORT(LOG_ERROR, "cannot init buffer mutex");
-        stopReadLine();
-        return true;
-    } else if(
-        THREAD_INIT_FAIL ||
-        thrd_create(&readThread, loop, nullptr) != thrd_success) {
-        REPORT(LOG_ERROR, "cannot start read thread");
+    running = true;
+    if(readThread.start(loop, nullptr)) {
+        REPORT(LogLevel::ERROR, "cannot start read thread");
         stopReadLine();
         return true;
     }
     return false;
 }
 
-bool readLine(char* buffer_, size_t n) {
-    if(buffer.length == 0) {
+bool Core::readLine(char* buffer_, size_t n) {
+    if(buffer.getLength() == 0) {
         return false;
     }
-    lock();
-    ConsoleLine* line = getQueueIndexCL(&buffer, 0);
-    snprintf(buffer_, n, "%s", line->data);
-    popQueueDataCL(&buffer);
-    unlock();
+    Core::MutexGuard mg(bufferMutex);
+    snprintf(buffer_, n, "%s", buffer[0].data.begin());
+    buffer.remove();
     return true;
 }
 
-void stopReadLine() {
-    atomic_store(&running, false);
-    joinThreadSafe(&readThread);
-    if(leaveRawTerminal()) {
-        REPORT(LOG_WARNING, "cannot restore terminal attributes");
+void Core::stopReadLine() {
+    running = false;
+    readThread.join();
+    if(Core::leaveRawTerminal()) {
+        REPORT(LogLevel::WARNING, "cannot restore terminal attributes");
     }
-    destroyQueueCL(&buffer);
-    mtx_destroy(&bufferMutex);
+    buffer.clear();
 }

+ 0 - 22
src/SpinLock.cpp

@@ -1,22 +0,0 @@
-#include "core/SpinLock.hpp"
-
-#include <threads.h>
-
-void initSpinLock(SpinLock* l) {
-    atomic_init(&l->lock, false);
-}
-
-void lockSpinLock(SpinLock* l) {
-    while(true) {
-        bool expected = false;
-        if(atomic_compare_exchange_weak(&l->lock, &expected, true)) {
-            break;
-        }
-        struct timespec s = {.tv_nsec = 0, .tv_sec = 0};
-        thrd_sleep(&s, nullptr);
-    }
-}
-
-void unlockSpinLock(SpinLock* l) {
-    atomic_store(&l->lock, false);
-}

+ 1 - 0
src/Terminal.cpp

@@ -13,6 +13,7 @@
 #define ESC "\33["
 #define esc(s) fputs(ESC s, stdout)
 
+using Core::LogLevel;
 static termios originalTerminal;
 
 struct EscapeSequence {

+ 74 - 8
src/Thread.cpp

@@ -1,18 +1,84 @@
 #include "core/Thread.hpp"
 
-#include <string.h>
-
 #include "ErrorSimulator.hpp"
 #include "core/Logger.hpp"
 
-bool joinThreadSafe(thrd_t* t) {
-    static thrd_t nullThread = {0};
-    if(memcmp(t, &nullThread, sizeof(thrd_t)) != 0) {
-        if(THREAD_JOIN_FAIL || thrd_join(*t, nullptr) != thrd_success) {
-            REPORT(LOG_ERROR, "cannot join thread");
+using Core::Mutex;
+using Core::MutexGuard;
+using Core::Thread;
+
+void Mutex::lock() noexcept {
+    try {
+        FAIL_STEP_THROW();
+        mutex.lock();
+    } catch(std::exception& e) {
+        REPORT(LogLevel::ERROR, "Could not lock mutex: #", e.what());
+    }
+}
+
+void Mutex::unlock() noexcept {
+    try {
+        FAIL_STEP_THROW();
+        mutex.unlock();
+    } catch(std::exception& e) {
+        REPORT(LogLevel::ERROR, "Could not unlock mutex: #", e.what());
+    }
+}
+
+MutexGuard::MutexGuard(Mutex& m) : mutex(m) {
+    mutex.lock();
+}
+
+MutexGuard::~MutexGuard() {
+    mutex.unlock();
+}
+
+Thread::Thread() : thread() {
+}
+
+Thread::Thread(Thread&& other) : thread() {
+    swap(other);
+}
+
+Thread::~Thread() {
+    join();
+}
+
+Thread& Thread::operator=(Thread&& other) {
+    if(this != &other) {
+        join();
+        thread = Core::move(other.thread);
+    }
+    return *this;
+}
+
+void Core::Thread::swap(Thread& other) {
+    Core::swap(thread, other.thread);
+}
+
+bool Thread::start(Function f, void* p) {
+    if(thread.joinable()) {
+        return true;
+    }
+    try {
+        FAIL_STEP_THROW();
+        thread = std::thread([f, p]() { f(p); });
+    } catch(std::exception& e) {
+        REPORT(LogLevel::ERROR, "Could not start thread: #", e.what());
+        return true;
+    }
+    return false;
+}
+
+bool Thread::join() {
+    if(thread.joinable()) {
+        try {
+            FAIL_STEP_THROW();
+            thread.join();
+        } catch(std::exception& e) {
+            REPORT(LogLevel::ERROR, "Could not join thread: #", e.what());
             return true;
         }
-        *t = (thrd_t){0};
     }
     return false;
 }

+ 13 - 9
src/ToString.cpp

@@ -3,15 +3,19 @@
 #include <cstdarg>
 #include <cstdio>
 
-#define TO_STRING(type, format)                    \
-    size_t toString(type v, char* s, size_t n) {   \
-        int e = snprintf(s, n, format, v);         \
-        return e < 0 ? 0 : static_cast<size_t>(e); \
+#define TO_STRING(type, format)                        \
+    size_t Core::toString(type v, char* s, size_t n) { \
+        int e = snprintf(s, n, format, v);             \
+        return e < 0 ? 0 : static_cast<size_t>(e);     \
     }
 
+TO_STRING(char, "%c")
+TO_STRING(short, "%hd")
 TO_STRING(int, "%d")
 TO_STRING(long, "%ld")
 TO_STRING(long long, "%lld")
+TO_STRING(unsigned char, "%c")
+TO_STRING(unsigned short, "%hu")
 TO_STRING(unsigned int, "%u")
 TO_STRING(unsigned long, "%lu")
 TO_STRING(unsigned long long, "%llu")
@@ -19,25 +23,25 @@ TO_STRING(double, "%.2f")
 TO_STRING(const char*, "%s")
 TO_STRING(const unsigned char*, "%s")
 
-size_t toString(float v, char* s, size_t n) {
+size_t Core::toString(float v, char* s, size_t n) {
     int e = snprintf(s, n, "%.2f", static_cast<double>(v));
     return e < 0 ? 0 : static_cast<size_t>(e);
 }
 
-size_t toString(char* v, char* s, size_t n) {
+size_t Core::toString(char* v, char* s, size_t n) {
     return toString(static_cast<const char*>(v), s, n);
 }
 
-size_t toString(unsigned char* v, char* s, size_t n) {
+size_t Core::toString(unsigned char* v, char* s, size_t n) {
     return toString(static_cast<const unsigned char*>(v), s, n);
 }
 
-size_t toString(bool v, char* s, size_t n) {
+size_t Core::toString(bool v, char* s, size_t n) {
     int e = snprintf(s, n, "%s", v ? "true" : "false");
     return e < 0 ? 0 : static_cast<size_t>(e);
 }
 
-size_t copyFormatUntil(const char*& format, char*& s, size_t& n) {
+size_t Core::copyFormatUntil(const char*& format, char*& s, size_t& n) {
     size_t w = 0;
     while(*format != '\0') {
         char u = *(format++);

+ 12 - 42
src/Utility.cpp

@@ -1,13 +1,10 @@
 #include "core/Utility.hpp"
 
-#include <chrono>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 #include <ctime>
-#include <thread>
 
-#include "ErrorSimulator.hpp"
 #include "core/Logger.hpp"
 
 static Core::ExitHandler exitHandler = nullptr;
@@ -88,23 +85,22 @@ struct MemoryInfo {
 static_assert(sizeof(MemoryInfo) == 80, "memory info has invalid size");
 static MemoryInfo* headMemoryInfo = nullptr;
 
-static void addMemoryInfo(
-    MemoryInfo* info, const char* file, int line, size_t n) {
-    info->next = nullptr;
-    info->previous = nullptr;
-    info->size = n;
-    info->line = line;
-    snprintf(info->buffer, sizeof(info->buffer), "%s", getShortFileName(file));
-    memcpy(info->canary, CANARY, sizeof(CANARY));
+static void addMemoryInfo(MemoryInfo* i, const char* file, int line, size_t n) {
+    i->next = nullptr;
+    i->previous = nullptr;
+    i->size = n;
+    i->line = line;
+    snprintf(i->buffer, sizeof(i->buffer), "%s", Core::getShortFileName(file));
+    memcpy(i->canary, CANARY, sizeof(CANARY));
     memcpy(
-        reinterpret_cast<char*>(info) + n - sizeof(CANARY), CANARY,
+        reinterpret_cast<char*>(i) + n - sizeof(CANARY), CANARY,
         sizeof(CANARY));
     if(headMemoryInfo == nullptr) {
-        headMemoryInfo = info;
+        headMemoryInfo = i;
     } else {
-        headMemoryInfo->previous = info;
-        info->next = headMemoryInfo;
-        headMemoryInfo = info;
+        headMemoryInfo->previous = i;
+        i->next = headMemoryInfo;
+        headMemoryInfo = i;
     }
 }
 
@@ -238,29 +234,3 @@ void Core::deallocateRaw(void* p) {
 }
 
 #endif
-
-bool Core::sleepNanos(i64 nanos) {
-    try {
-        FAIL_STEP_THROW();
-        std::this_thread::sleep_for(std::chrono::nanoseconds(nanos));
-    } catch(...) {
-        return true;
-    }
-    return false;
-}
-
-bool Core::sleepMillis(i64 millis) {
-    return sleepNanos(millis * 1'000'000l);
-}
-
-i64 Core::getNanos(void) {
-    try {
-        FAIL_STEP_THROW();
-        using namespace std::chrono;
-        return duration_cast<nanoseconds>(
-                   high_resolution_clock::now().time_since_epoch())
-            .count();
-    } catch(std::exception& e) {
-        return -1;
-    }
-}

+ 13 - 9
test/Main.cpp

@@ -65,31 +65,35 @@ int main(int argAmount, const char** args) {
     testUniquePointer();
     testVector();
     testMath();
+    testClock(light);
     testArray();
-    // testBitArray();
+    testBitArray();
     testBox();
-    // testBuffer(light);
-    // testComponents();
+    testBuffer(light);
+    testComponents();
     testFile();
     testFrustum();
+    testArrayList(light);
     testHashMap(light);
     testMatrix();
+    testColor();
+    testHashedString();
     testPlane();
     testQuaternion();
-    // testQueue();
+    testThread();
+    testQueue();
     testRandom(light);
     if(light) {
-        // testReadLine();
+        testReadLine();
     }
-    // testSpinLock();
     testTerminal(!light);
     testUnicode();
-    testUtility(light);
+    testUtility();
     testView();
 
-    logLevel = LogLevel::WARNING;
+    Core::logLevel = Core::LogLevel::WARNING;
     LOG_DEBUG("You won't see this!");
-    logLevel = LogLevel::DEBUG;
+    Core::logLevel = Core::LogLevel::DEBUG;
 
     unsigned int data = 123'456'789;
     Core::setExitHandler(onExit, &data);

+ 3 - 4
test/Tests.hpp

@@ -1,5 +1,5 @@
-#ifndef CORE_TESTS_H
-#define CORE_TESTS_H
+#ifndef CORE_TESTS_HPP
+#define CORE_TESTS_HPP
 
 [[noreturn]] void testInvalidAllocate();
 [[noreturn]] void testInvalidReallocate();
@@ -36,14 +36,13 @@ void testQueue();
 void testRandom(bool light);
 void testReadLine();
 void testRingBuffer();
-void testSpinLock();
 void testStack(bool light);
 void testTerminal(bool tty);
 void testTest();
 void testThread();
 void testUnicode();
 void testUniquePointer();
-void testUtility(bool light);
+void testUtility();
 void testVector();
 void testView();
 

+ 56 - 37
old/ArrayListTests.cpp → test/modules/ArrayListTests.cpp

@@ -1,5 +1,6 @@
 #include "../Tests.hpp"
-#include "core/data/ArrayList.hpp"
+#include "core/ArrayList.hpp"
+#include "core/Test.hpp"
 
 template class Core::ArrayList<size_t, 20>;
 using IntList = Core::ArrayList<size_t, 20>;
@@ -7,31 +8,34 @@ using IntList = Core::ArrayList<size_t, 20>;
 static void testAdd() {
     IntList list;
     list.add(5u);
-    CORE_TEST_EQUAL(5, list[0]);
-    CORE_TEST_EQUAL(1, list.getLength());
+    TEST(5, list[0]);
+    TEST(5, list.getLast());
+    const IntList& cList = list;
+    TEST(5, cList.getLast());
+    TEST(1, list.getLength());
 }
 
 static void testMultipleAdd() {
     IntList list;
     list.add(4u).add(3u).add(2u);
-    CORE_TEST_EQUAL(4, list[0]);
-    CORE_TEST_EQUAL(3, list[1]);
-    CORE_TEST_EQUAL(2, list[2]);
-    CORE_TEST_EQUAL(3, list.getLength());
+    TEST(4, list[0]);
+    TEST(3, list[1]);
+    TEST(2, list[2]);
+    TEST(3, list.getLength());
 }
 
 static void testAddReplace() {
     IntList list;
     list.add(5u);
     list[0] = 3;
-    CORE_TEST_EQUAL(3, list[0]);
+    TEST(3, list[0]);
 }
 
 static void testClear() {
     IntList list;
     list.add(5u).add(4u);
     list.clear();
-    CORE_TEST_EQUAL(0, list.getLength());
+    TEST(0, list.getLength());
 }
 
 static void testOverflow(bool light) {
@@ -39,12 +43,12 @@ static void testOverflow(bool light) {
     for(size_t i = 0; i < 20; i++) {
         list.add(i);
     }
-    size_t limit = light ? 1000 : 100000;
+    size_t limit = light ? 1000 : 100'000;
     for(size_t i = 0; i < limit; i++) {
         list.add(i);
     }
     for(size_t i = 0; i < list.getLength(); i++) {
-        CORE_TEST_EQUAL(i, list[i]);
+        TEST(i, list[i]);
     }
 }
 
@@ -52,9 +56,9 @@ static void testCopy() {
     IntList list;
     list.add(1u).add(2u).add(3u);
     IntList copy(list);
-    CORE_TEST_EQUAL(list.getLength(), copy.getLength());
+    TEST(list.getLength(), copy.getLength());
     for(size_t i = 0; i < copy.getLength() && i < list.getLength(); i++) {
-        CORE_TEST_EQUAL(list[i], copy[i]);
+        TEST(list[i], copy[i]);
     }
 }
 
@@ -63,9 +67,9 @@ static void testCopyAssignment() {
     list.add(1u).add(2u).add(3u);
     IntList copy;
     copy = list;
-    CORE_TEST_EQUAL(list.getLength(), copy.getLength());
+    TEST(list.getLength(), copy.getLength());
     for(size_t i = 0; i < copy.getLength() && i < list.getLength(); i++) {
-        CORE_TEST_EQUAL(list[i], copy[i]);
+        TEST(list[i], copy[i]);
     }
 }
 
@@ -73,11 +77,11 @@ static void testMove() {
     IntList list;
     list.add(1u).add(2u).add(3u);
     IntList move(Core::move(list));
-    CORE_TEST_EQUAL(0, list.getLength());
-    CORE_TEST_EQUAL(3, move.getLength());
-    CORE_TEST_EQUAL(1, move[0]);
-    CORE_TEST_EQUAL(2, move[1]);
-    CORE_TEST_EQUAL(3, move[2]);
+    TEST(0, list.getLength());
+    TEST(3, move.getLength());
+    TEST(1, move[0]);
+    TEST(2, move[1]);
+    TEST(3, move[2]);
 }
 
 static void testMoveAssignment() {
@@ -85,33 +89,47 @@ static void testMoveAssignment() {
     list.add(1u).add(2u).add(3u);
     IntList move;
     move = Core::move(list);
-    CORE_TEST_EQUAL(0, list.getLength());
-    CORE_TEST_EQUAL(3, move.getLength());
-    CORE_TEST_EQUAL(1, move[0]);
-    CORE_TEST_EQUAL(2, move[1]);
-    CORE_TEST_EQUAL(3, move[2]);
+    TEST(0, list.getLength());
+    TEST(3, move.getLength());
+    TEST(1, move[0]);
+    TEST(2, move[1]);
+    TEST(3, move[2]);
 }
 
 static void testToString() {
     IntList list;
     list.add(1u).add(243u).add(423u);
-    CORE_TEST_STRING("[1, 243, 423]", list);
-    CORE_TEST_STRING("[1]", IntList().add(1u));
-    CORE_TEST_STRING("[]", IntList());
+    TEST_STRING("[1, 243, 423]", list);
+    TEST_STRING("[1]", IntList().add(1u));
+    TEST_STRING("[]", IntList());
 }
 
-static void testRemove() {
+static void testRemoveBySwap() {
     IntList list;
     list.add(4u).add(3u).add(2u);
     list.removeBySwap(0);
-    CORE_TEST_EQUAL(2, list[0]);
-    CORE_TEST_EQUAL(3, list[1]);
-    CORE_TEST_EQUAL(2, list.getLength());
+    TEST(2, list[0]);
+    TEST(3, list[1]);
+    TEST(2, list.getLength());
     list.removeBySwap(1);
-    CORE_TEST_EQUAL(2, list[0]);
-    CORE_TEST_EQUAL(1, list.getLength());
+    TEST(2, list[0]);
+    TEST(1, list.getLength());
     list.removeBySwap(0);
-    CORE_TEST_EQUAL(0, list.getLength());
+    TEST(0, list.getLength());
+}
+
+static void testRemove() {
+    IntList list;
+    list.add(4u).add(3u).add(2u);
+    list.remove(0);
+    TEST(3, list[0]);
+    TEST(2, list[1]);
+    TEST(2, list.getLength());
+    list.remove(1);
+    TEST(3, list[0]);
+    TEST(1, list.getLength());
+    list.removeLast();
+    TEST(0, list.getLength());
 }
 
 static void testForRange() {
@@ -121,11 +139,11 @@ static void testForRange() {
         i++;
     }
     for(size_t i = 0; i < list.getLength(); i++) {
-        CORE_TEST_EQUAL(i + 2, list[i]);
+        TEST(i + 2, list[i]);
     }
 }
 
-void Core::testArrayList(bool light) {
+void testArrayList(bool light) {
     testAdd();
     testMultipleAdd();
     testAddReplace();
@@ -136,6 +154,7 @@ void Core::testArrayList(bool light) {
     testMove();
     testMoveAssignment();
     testToString();
+    testRemoveBySwap();
     testRemove();
     testForRange();
 }

+ 102 - 106
test/modules/BitArrayTests.cpp

@@ -1,157 +1,153 @@
-#include "../Tests.h"
-#include "core/BitArray.h"
+#include "../Tests.hpp"
+#include "core/BitArray.hpp"
+#include "core/Test.hpp"
 
 static void testSetRead() {
-    BitArray bits;
-    initBitArray(&bits, 4, 3);
-    setBits(&bits, 0, 1);
-    setBits(&bits, 1, 2);
-    setBits(&bits, 2, 3);
-    setBits(&bits, 3, 4);
-    TEST_U64(1, getBits(&bits, 0));
-    TEST_U64(2, getBits(&bits, 1));
-    TEST_U64(3, getBits(&bits, 2));
-    TEST_U64(4, getBits(&bits, 3));
-    destroyBitArray(&bits);
+    Core::BitArray bits;
+    bits.resize(4, 3);
+    bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
+    TEST(1, bits.get(0));
+    TEST(2, bits.get(1));
+    TEST(3, bits.get(2));
+    TEST(4, bits.get(3));
+    Core::BitArray copy;
+    copy = bits;
+    TEST(1, copy.get(0));
+    TEST(2, copy.get(1));
+    TEST(3, copy.get(2));
+    TEST(4, copy.get(3));
+    Core::BitArray move = Core::move(copy);
+    TEST(1, move.get(0));
+    TEST(2, move.get(1));
+    TEST(3, move.get(2));
+    TEST(4, move.get(3));
 }
 
 static void testBigSetRead() {
-    BitArray bits;
-    initBitArray(&bits, 100, 13);
-    for(size_t i = 0; i < bits.length; i++) {
-        setBits(&bits, i, i);
+    Core::BitArray bits;
+    bits.resize(100, 13);
+    for(size_t i = 0; i < bits.getLength(); i++) {
+        bits.set(i, i);
     }
-    for(size_t i = 0; i < bits.length; i++) {
-        TEST_U64(i, getBits(&bits, i));
+    for(size_t i = 0; i < bits.getLength(); i++) {
+        TEST(i, bits.get(i));
     }
-    destroyBitArray(&bits);
 }
 
 static void testRandomSetReadResize() {
-    u64 data[100];
-    BitArray bits;
-    initBitArray(&bits, 100, 13);
+    constexpr int length = 100;
+    u64 data[length];
+    Core::BitArray bits;
+    bits.resize(100, 13);
     u64 seed = 534;
     for(int k = 0; k < 20; k++) {
-        for(u64 i = 0; i < bits.length; i++) {
+        for(u64 i = 0; i < bits.getLength(); i++) {
             seed = seed * 636'455 + 53'453;
-            setBits(&bits, i, seed);
-            data[i] = seed & 0x1FFF;
+            bits.set(i, seed);
+            data[i] = seed & (0x1FFF);
         }
     }
-    for(size_t i = 0; i < bits.length; i++) {
-        TEST_U64(data[i], getBits(&bits, i));
+    for(size_t i = 0; i < bits.getLength(); i++) {
+        TEST(data[i], bits.get(i));
     }
-    setBitLength(&bits, bits.length, bits.bits + 1u);
-    TEST_U64(14, bits.bits);
-    TEST_U64(100, bits.length);
-    for(size_t i = 0; i < bits.length; i++) {
-        TEST_U64(data[i], getBits(&bits, i));
+    bits.resize(bits.getLength(), bits.getBits() + 1);
+    TEST(14, bits.getBits());
+    TEST(100, bits.getLength());
+    for(size_t i = 0; i < bits.getLength(); i++) {
+        TEST(data[i], bits.get(i));
     }
-    destroyBitArray(&bits);
+}
+
+static void testReadOnly() {
+    Core::BitArray bits;
+    bits.resize(4, 3);
+    bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
+    const Core::BitArray copy = bits;
+    TEST(1, copy.get(0));
+    TEST(2, copy.get(1));
+    TEST(3, copy.get(2));
+    TEST(4, copy.get(3));
 }
 
 static void testSelect() {
-    BitArray bits;
-    initBitArray(&bits, 90, 1);
-    setAllBits(&bits, 0);
-    setBits(&bits, 0, 1);
-    setBits(&bits, 5, 1);
-    setBits(&bits, 20, 1);
-    setBits(&bits, 31, 1);
-    setBits(&bits, 32, 1);
-    setBits(&bits, 33, 1);
-    setBits(&bits, 60, 1);
-    TEST_I64(-1, selectBits(&bits, 0));
-    TEST_I64(0, selectBits(&bits, 1));
-    TEST_I64(5, selectBits(&bits, 2));
-    TEST_I64(20, selectBits(&bits, 3));
-    TEST_I64(31, selectBits(&bits, 4));
-    TEST_I64(32, selectBits(&bits, 5));
-    TEST_I64(33, selectBits(&bits, 6));
-    TEST_I64(60, selectBits(&bits, 7));
-    TEST_I64(-1, selectBits(&bits, 8));
-    destroyBitArray(&bits);
+    Core::BitArray bits;
+    bits.resize(90, 1);
+    bits.fill(0);
+    bits.set(0, 1).set(5, 1).set(20, 1).set(31, 1);
+    bits.set(32, 1).set(33, 1).set(60, 1);
+    TEST(-1, bits.select(0));
+    TEST(0, bits.select(1));
+    TEST(5, bits.select(2));
+    TEST(20, bits.select(3));
+    TEST(31, bits.select(4));
+    TEST(32, bits.select(5));
+    TEST(33, bits.select(6));
+    TEST(60, bits.select(7));
+    TEST(-1, bits.select(8));
 }
 
 static void testToString1() {
-    BitArray bits;
-    initBitArray(&bits, 4, 3);
-    setBits(&bits, 0, 1);
-    setBits(&bits, 1, 2);
-    setBits(&bits, 2, 3);
-    setBits(&bits, 3, 4);
-    char buffer[128];
-    size_t n = toStringBitArray(&bits, buffer, sizeof(buffer));
-    TEST_SIZE(12, n);
-    TEST_STRING("[1, 2, 3, 4]", buffer);
-    destroyBitArray(&bits);
+    Core::BitArray bits;
+    bits.resize(4, 3);
+    bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
+    TEST_STRING("[1, 2, 3, 4]", bits);
 }
 
 static void testToString2() {
-    BitArray bits;
-    initBitArray(&bits, 1, 3);
-    setBits(&bits, 0, 1);
-    char buffer[128];
-    size_t n = toStringBitArray(&bits, buffer, sizeof(buffer));
-    TEST_SIZE(3, n);
-    TEST_STRING("[1]", buffer);
-    destroyBitArray(&bits);
+    Core::BitArray bits;
+    bits.resize(1, 3);
+    bits.set(0, 1);
+    TEST_STRING("[1]", bits);
 }
 
 static void testToString3() {
-    BitArray bits;
-    initBitArray(&bits, 0, 0);
-    char buffer[128];
-    size_t n = toStringBitArray(&bits, buffer, sizeof(buffer));
-    TEST_SIZE(2, n);
-    TEST_STRING("[]", buffer);
-    destroyBitArray(&bits);
+    Core::BitArray bits;
+    TEST_STRING("[]", bits);
 }
 
 static void testResizeExact() {
-    BitArray bits;
+    Core::BitArray bits;
+    TEST(0, bits.getInternalByteSize());
     // the size in bytes matches the internal storage type
     size_t elements = sizeof(u64);
-    initBitArray(&bits, elements, 8);
+    bits.resize(elements, 8);
     for(size_t i = 0; i < elements; i++) {
-        setBits(&bits, i, i);
+        bits.set(i, i);
     }
     for(size_t i = 0; i < elements; i++) {
-        TEST_U64(i, getBits(&bits, i));
+        TEST(i, bits.get(i));
     }
-    destroyBitArray(&bits);
+    TEST(sizeof(u64), bits.getInternalByteSize());
 }
 
 static void testInvalidArgument() {
-    BitArray bits;
-    initBitArray(&bits, 0, 0);
-    setBitLength(&bits, 0, 5);
-    TEST_SIZE(0, bits.length);
-    TEST_SIZE(0, bits.bits);
-    setBitLength(&bits, 5, 0);
-    TEST_SIZE(0, bits.length);
-    TEST_SIZE(0, bits.bits);
-    setBitLength(&bits, 0, 0);
-    TEST_SIZE(0, bits.length);
-    TEST_SIZE(0, bits.bits);
-    setBitLength(&bits, 1, 65);
-    TEST_SIZE(1, bits.length);
-    TEST_SIZE(64, bits.bits);
-    setBitLength(&bits, 5, 68);
-    TEST_SIZE(5, bits.length);
-    TEST_SIZE(64, bits.bits);
-    destroyBitArray(&bits);
+    Core::BitArray bits;
+    bits.resize(0, 5);
+    TEST(0, bits.getLength());
+    TEST(0, bits.getBits());
+    bits.resize(5, 0);
+    TEST(0, bits.getLength());
+    TEST(0, bits.getBits());
+    bits.resize(0, 0);
+    TEST(0, bits.getLength());
+    TEST(0, bits.getBits());
+    bits.resize(1, 65);
+    TEST(1, bits.getLength());
+    TEST(64, bits.getBits());
+    bits.resize(5, 68);
+    TEST(5, bits.getLength());
+    TEST(64, bits.getBits());
 }
 
 void testBitArray() {
-    testSetRead();
     testBigSetRead();
+    testInvalidArgument();
     testRandomSetReadResize();
+    testReadOnly();
+    testResizeExact();
     testSelect();
+    testSetRead();
     testToString1();
     testToString2();
     testToString3();
-    testResizeExact();
-    testInvalidArgument();
 }

+ 68 - 15
test/modules/BufferTests.cpp

@@ -1,24 +1,77 @@
-#include "../Tests.h"
-#include "core/Buffer.h"
+#include "../Tests.hpp"
+#include "core/Buffer.hpp"
+#include "core/Test.hpp"
 
-static const size_t SIZE_TYPES =
+static constexpr size_t SIZE_TYPES =
     sizeof(int) + sizeof(long) + sizeof(float) + sizeof(double);
 
-void testBuffer(bool light) {
-    Buffer buffer;
-    initBuffer(&buffer);
+static void testAdd(bool light) {
+    Core::Buffer buffer;
     size_t limit = light ? 1000 : 100'000;
     for(size_t i = 0; i < limit; i++) {
-        addTypedBufferData(&buffer, int, 5);
-        addTypedBufferData(&buffer, long, 51);
-        addTypedBufferData(&buffer, float, 5.0f);
-        addTypedBufferData(&buffer, double, 5.0);
+        buffer.add(5);
+        buffer.add(5L);
+        buffer.add(5.0f);
+        buffer.add(5.0);
+    }
+    TEST(SIZE_TYPES * limit, buffer.getLength());
+    buffer.clear();
+    TEST(0, buffer.getLength());
+    buffer.add(20l);
+    TEST(sizeof(long), buffer.getLength());
+}
+
+static void testCopy() {
+    Core::Buffer buffer;
+    for(int i = 0; i < 10; i++) {
+        buffer.add(5);
+        buffer.add(5L);
+        buffer.add(5.0f);
+        buffer.add(5.0);
+    }
+    Core::Buffer buffer2 = buffer;
+    Core::Buffer buffer3;
+    buffer3 = buffer;
+    if(TEST(SIZE_TYPES * 10, buffer.getLength()) &&
+       TEST(SIZE_TYPES * 10, buffer2.getLength()) &&
+       TEST(SIZE_TYPES * 10, buffer3.getLength())) {
+        TEST_TRUE(
+            memcmp(buffer.getData(), buffer2.getData(), SIZE_TYPES * 10) == 0);
+        TEST_TRUE(
+            memcmp(buffer.getData(), buffer3.getData(), SIZE_TYPES * 10) == 0);
+    }
+}
+
+static void testMoveConstruct() {
+    Core::Buffer buffer;
+    for(int i = 0; i < 10; i++) {
+        buffer.add(5);
+        buffer.add(5L);
+        buffer.add(5.0f);
+        buffer.add(5.0);
     }
-    TEST_SIZE(SIZE_TYPES * limit, buffer.size);
+    Core::Buffer buffer2(Core::move(buffer));
+    TEST(0, buffer.getLength());
+    TEST(SIZE_TYPES * 10, buffer2.getLength());
+}
 
-    clearBuffer(&buffer);
-    addTypedBufferData(&buffer, long, 20);
-    TEST_SIZE(sizeof(long), buffer.size);
+static void testMove() {
+    Core::Buffer buffer;
+    for(int i = 0; i < 10; i++) {
+        buffer.add(5);
+        buffer.add(5L);
+        buffer.add(5.0f);
+        buffer.add(5.0);
+    }
+    Core::Buffer buffer2;
+    buffer2 = Core::move(buffer);
+    TEST(0, buffer.getLength());
+    TEST(SIZE_TYPES * 10, buffer2.getLength());
+}
 
-    destroyBuffer(&buffer);
+void testBuffer(bool light) {
+    testAdd(light);
+    testCopy();
+    testMoveConstruct();
+    testMove();
 }

+ 62 - 0
test/modules/ClockTests.cpp

@@ -0,0 +1,62 @@
+#include "../../src/ErrorSimulator.hpp"
+#include "../Tests.hpp"
+#include "core/Clock.hpp"
+#include "core/Test.hpp"
+
+using Core::Clock;
+
+static void testUpdate() {
+    Clock c;
+    TEST_TRUE(c.update() == 0);
+    TEST_TRUE(c.update() >= 0);
+    TEST_TRUE(c.update() >= 0);
+    TEST_TRUE(c.update() >= 0);
+}
+
+static void testUpdatesPerSecond() {
+    Clock c;
+    for(int i = 0; i < 1000; i++) {
+        TEST_TRUE(c.update() >= 0);
+    }
+    TEST_TRUE(c.getUpdatesPerSecond() > 0.0f);
+}
+
+static void testSleep(i64 nanos) {
+    Clock c;
+    TEST_TRUE(c.update() >= 0);
+    TEST_FALSE(Clock::sleepNanos(nanos));
+    i64 n = c.update();
+    TEST_TRUE(n >= nanos && n <= nanos * 13 / 10);
+}
+
+static void testSleepMillis(i64 millis) {
+    Clock c;
+    TEST_TRUE(c.update() >= 0);
+    TEST_FALSE(Clock::sleepMillis(millis));
+    i64 n = c.update();
+    i64 nanos = millis * 1'000'000;
+    TEST_TRUE(n >= nanos && n <= nanos * 13 / 10);
+}
+
+static void testFail() {
+    Clock c;
+#ifdef ERROR_SIMULATOR
+    failStepThrow = 1;
+    TEST(-1l, c.update());
+    failStepThrow = 1;
+    TEST(-1l, Clock::getNanos());
+    failStepThrow = 1;
+    TEST_TRUE(Clock::sleepMillis(5));
+    failStepThrow = 0;
+#endif
+}
+
+void testClock(bool light) {
+    testUpdate();
+    testUpdatesPerSecond();
+    testSleep(light ? 5'000'000 : 50'000'000);
+    testSleep(light ? 50'000'000 : 1'300'000'000);
+    testSleepMillis(light ? 5 : 50);
+    testSleepMillis(light ? 50 : 1300);
+    testFail();
+}

+ 64 - 0
test/modules/ColorTests.cpp

@@ -0,0 +1,64 @@
+#include "../Tests.hpp"
+#include "core/Color.hpp"
+#include "core/Test.hpp"
+
+template class Core::Color<1>;
+template class Core::Color<2>;
+template class Core::Color<3>;
+template class Core::Color<4>;
+
+const float eps = 0.0001f;
+
+static void testColor1() {
+    Core::Color1 c(36);
+    TEST(36, c[0]);
+    TEST_FLOAT(36.0f / 255.0f, c.asFloat(0), eps);
+}
+
+static void testColor2() {
+    Core::Color2 c(36 + 256, 100.0);
+    TEST(36, c[0]);
+    TEST(100, c[1]);
+    TEST_FLOAT(36.0f / 255.0f, c.asFloat(0), eps);
+    TEST_FLOAT(100.0f / 255.0f, c.asFloat(1), eps);
+}
+
+static void testColor3() {
+    Core::Color3 c(36, 100.0f, 200);
+    TEST(36, c[0]);
+    TEST(100, c[1]);
+    TEST(200, c[2]);
+    TEST_FLOAT(36.0f / 255.0f, c.asFloat(0), eps);
+    TEST_FLOAT(100.0f / 255.0f, c.asFloat(1), eps);
+    TEST_FLOAT(200.0f / 255.0f, c.asFloat(2), eps);
+}
+
+template<typename T>
+static void testColor4() {
+    T c(36, 100, 200, 142);
+    TEST(36, c[0]);
+    TEST(100, c[1]);
+    TEST(200, c[2]);
+    TEST(142, c[3]);
+    TEST_FLOAT(36.0f / 255.0f, c.asFloat(0), eps);
+    TEST_FLOAT(100.0f / 255.0f, c.asFloat(1), eps);
+    TEST_FLOAT(200.0f / 255.0f, c.asFloat(2), eps);
+    TEST_FLOAT(142.0f / 255.0f, c.asFloat(3), eps);
+}
+
+static void testColor4Empty() {
+    Core::Color4 c;
+    TEST(0, c[0]);
+    TEST(0, c[1]);
+    TEST(0, c[2]);
+    TEST(0, c[3]);
+}
+
+void testColor() {
+    testColor1();
+    testColor2();
+    testColor3();
+    testColor4<Core::Color4>();
+    testColor4<const Core::Color4>();
+    testColor4Empty();
+}

+ 102 - 95
test/modules/ComponentsTests.cpp

@@ -1,125 +1,132 @@
-#include "../Tests.h"
-#include "core/Components.h"
+#include "../Tests.hpp"
+#include "core/Components.hpp"
+#include "core/Test.hpp"
 
-LIST(int, Int)
-LIST_SOURCE(int, Int)
-COMPONENTS(int, Int)
-COMPONENTS_SOURCE(int, Int)
+template class Core::Components<int>;
+using IntComponent = Core::Components<int>;
 
-static void testAddForEach() {
-    ComponentsInt c;
-    initComponentsInt(&c);
-
-    int* i1 = getOrAddComponentInt(&c, 1);
-    if(TEST_NOT_NULL(i1)) {
-        *i1 = 10;
-    }
-    int* i2 = getOrAddComponentInt(&c, 1);
-    if(TEST_NOT_NULL(i2)) {
-        *i2 = 15;
+template<typename T>
+static void testEntityIterator(T c) {
+    auto iter = c.entities();
+    auto pos = iter.begin();
+    auto end = iter.end();
+    if(TEST_TRUE(pos != end)) {
+        TEST(1, (*pos).entity);
+        TEST(10, (*pos).component);
+        TEST_TRUE(pos != end);
+        ++pos;
     }
-    int* i3 = getOrAddComponentInt(&c, 5);
-    if(TEST_NOT_NULL(i3)) {
-        *i3 = 20;
-    }
-    int* i4 = getOrAddComponentInt(&c, 10);
-    if(TEST_NOT_NULL(i4)) {
-        *i4 = 30;
-    }
-    TEST_TRUE(i1 == i2);
-
-    ComponentIteratorInt iter;
-    initComponentIteratorInt(&iter, &c);
-    if(TEST_TRUE(hasNextComponentNodeInt(&iter))) {
-        ComponentNodeInt* n = nextComponentNodeInt(&iter);
-        TEST_SIZE(1, n->entity);
-        TEST_INT(15, *n->component);
+    if(TEST_TRUE(pos != end)) {
+        TEST(5, (*pos).entity);
+        TEST(20, (*pos).component);
+        TEST_TRUE(pos != end);
+        ++pos;
     }
-    if(TEST_TRUE(hasNextComponentNodeInt(&iter))) {
-        ComponentNodeInt* n = nextComponentNodeInt(&iter);
-        TEST_SIZE(5, n->entity);
-        TEST_INT(20, *n->component);
+    if(TEST_TRUE(pos != end)) {
+        TEST(10, (*pos).entity);
+        TEST(30, (*pos).component);
+        TEST_TRUE(pos != end);
+        ++pos;
     }
-    if(TEST_TRUE(hasNextComponentNodeInt(&iter))) {
-        ComponentNodeInt* n = nextComponentNodeInt(&iter);
-        TEST_SIZE(10, n->entity);
-        TEST_INT(30, *n->component);
-    }
-    TEST_FALSE(hasNextComponentNodeInt(&iter));
-    destroyComponentsInt(&c);
+    TEST_FALSE(pos != end);
 }
 
-static void testAddComponentForEach() {
-    ComponentsInt c;
-    initComponentsInt(&c);
-    int* i1 = getOrAddComponentInt(&c, 1);
-    if(TEST_NOT_NULL(i1)) {
-        *i1 = 10;
-    }
-    int* i2 = getOrAddComponentInt(&c, 5);
-    if(TEST_NOT_NULL(i2)) {
-        *i2 = 20;
-    }
-    int* i3 = getOrAddComponentInt(&c, 10);
-    if(TEST_NOT_NULL(i3)) {
-        *i3 = 30;
+static void testAddForEach() {
+    IntComponent c;
+    int* i1 = nullptr;
+    int* i2 = nullptr;
+    int* i3 = nullptr;
+    TEST_TRUE(c.put(i1, 1, 10));
+    TEST_FALSE(c.put(i1, 1, 20));
+    TEST_TRUE(c.put(i2, 5, 20));
+    TEST_TRUE(c.put(i3, 10, 30));
+    if(TEST_NOT_NULL(i1) && TEST_NOT_NULL(i2) && TEST_NOT_NULL(i3)) {
+        TEST(10, *i1);
+        TEST(20, *i2);
+        TEST(30, *i3);
     }
+    testEntityIterator<IntComponent&>(c);
+    testEntityIterator<const IntComponent&>(c);
+}
 
-    int* iter = getComponentsStartInt(&c);
-    int* end = getComponentsEndInt(&c);
+template<typename T>
+static void testComponentIterator(T c) {
+    auto iter = c.begin();
+    auto end = c.end();
     if(TEST_TRUE(iter != end)) {
-        TEST_INT(10, *(iter++));
+        TEST(10, *(iter++));
     }
     if(TEST_TRUE(iter != end)) {
-        TEST_INT(20, *(iter++));
+        TEST(20, *(iter++));
     }
     if(TEST_TRUE(iter != end)) {
-        TEST_INT(30, *(iter++));
+        TEST(30, *(iter++));
     }
-    TEST_TRUE(iter == end);
-    destroyComponentsInt(&c);
+    TEST_FALSE(iter != c.end());
 }
 
-static void testRemove() {
-    ComponentsInt c;
-    initComponentsInt(&c);
-    *getOrAddComponentInt(&c, 1) = 10;
-    *getOrAddComponentInt(&c, 5) = 20;
-    *getOrAddComponentInt(&c, 10) = 30;
-
-    TEST_FALSE(removeComponentInt(&c, 20));
-    TEST_TRUE(removeComponentInt(&c, 5));
-    TEST_FALSE(removeComponentInt(&c, 30));
-
-    *getOrAddComponentInt(&c, 20) = 40;
-    TEST_TRUE(removeComponentInt(&c, 20));
+static void testAddComponentForEach() {
+    IntComponent c;
+    int* i1 = nullptr;
+    int* i2 = nullptr;
+    int* i3 = nullptr;
+    TEST_TRUE(c.put(i1, 1, 10));
+    TEST_TRUE(c.put(i2, 5, 20));
+    TEST_TRUE(c.put(i3, 10, 30));
+    if(TEST_NOT_NULL(i1) && TEST_NOT_NULL(i2) && TEST_NOT_NULL(i3)) {
+        TEST(10, *i1);
+        TEST(20, *i2);
+        TEST(30, *i3);
+    }
+    testComponentIterator<IntComponent&>(c);
+    testComponentIterator<const IntComponent&>(c);
+}
 
-    int* i1 = searchComponentInt(&c, 1);
-    int* i3 = searchComponentInt(&c, 10);
-    TEST_NULL(searchComponentInt(&c, 5));
+static void testRemove() {
+    IntComponent c;
+    TEST_TRUE(c.add(1, 10));
+    TEST_TRUE(c.add(5, 20));
+    TEST_TRUE(c.add(10, 30));
+    TEST_FALSE(c.remove(20));
+    TEST_TRUE(c.remove(5));
+    TEST_FALSE(c.remove(30));
+    TEST_TRUE(c.add(20, 40));
+    TEST_TRUE(c.remove(20));
+    int* i1 = c.search(1);
+    TEST_NULL(c.search(5));
+    int* i3 = c.search(10);
     if(TEST_NOT_NULL(i1) && TEST_NOT_NULL(i3)) {
-        TEST_INT(10, *i1);
-        TEST_INT(30, *i3);
+        TEST(10, *i1);
+        TEST(30, *i3);
     }
-
-    TEST_TRUE(removeComponentInt(&c, 10));
-    i1 = searchComponentInt(&c, 1);
-    TEST_NULL(searchComponentInt(&c, 5));
-    TEST_NULL(searchComponentInt(&c, 10));
+    TEST_TRUE(c.remove(10));
+    i1 = c.search(1);
+    TEST_NULL(c.search(5));
+    TEST_NULL(c.search(10));
     if(TEST_NOT_NULL(i1)) {
-        TEST_INT(10, *i1);
+        TEST(10, *i1);
     }
+    TEST_TRUE(c.remove(1));
+    TEST_NULL(c.search(1));
+    TEST_NULL(c.search(5));
+    TEST_NULL(c.search(10));
+}
 
-    TEST_TRUE(removeComponentInt(&c, 1));
-    TEST_NULL(searchComponentInt(&c, 1));
-    TEST_NULL(searchComponentInt(&c, 5));
-    TEST_NULL(searchComponentInt(&c, 10));
-
-    destroyComponentsInt(&c);
+static void testConstSearch() {
+    IntComponent c;
+    int* i = nullptr;
+    TEST_TRUE(c.put(i, 1, 10));
+    const IntComponent& cc = c;
+    const int* component = cc.search(1);
+    if(TEST_TRUE(component != nullptr)) {
+        TEST(10, *component);
+    }
+    TEST_NULL(cc.search(2));
 }
 
 void testComponents() {
     testAddForEach();
     testAddComponentForEach();
     testRemove();
+    testConstSearch();
 }

+ 4 - 4
test/modules/FileTests.cpp

@@ -16,8 +16,8 @@ static const char* fails[] = {
     "cannot close file 'testData/someFile'"};
 
 static void printReport(
-    LogLevel l, const char*, int, void*, const char* message) {
-    TEST(static_cast<int>(LogLevel::ERROR), static_cast<int>(l));
+    Core::LogLevel l, const char*, int, void*, const char* message) {
+    TEST(static_cast<int>(Core::LogLevel::ERROR), static_cast<int>(l));
     if(!TEST_TRUE(strstr(message, fails[failIndex]) != nullptr)) {
         LOG_ERROR("'#' does not contain '#'", message, fails[failIndex]);
     }
@@ -49,11 +49,11 @@ static void testFails(int steps) {
 }
 
 void testFile() {
-    setReportHandler(printReport, nullptr);
+    Core::setReportHandler(printReport, nullptr);
     testExistingFile();
     testNotExistingFile();
     for(int i = 1; i < 6; i++) {
         testFails(i);
     }
-    setReportHandler(nullptr, nullptr);
+    Core::setReportHandler(nullptr, nullptr);
 }

+ 73 - 147
test/modules/HashMapTests.cpp

@@ -1,28 +1,18 @@
 #include "../Tests.hpp"
-#include "core/ProbingHashMap.hpp"
+#include "core/HashMap.hpp"
 #include "core/Random.hpp"
 #include "core/Test.hpp"
 
-template struct Core::ProbingHashMap<int, int>;
-using ProbingIntMap = Core::ProbingHashMap<int, int>;
+template struct Core::HashMap<int, int>;
+using IntMap = Core::HashMap<int, int>;
 
-// template struct Core::HashMap<int, int>;
-// using IntMap = Core::HashMap<int, int>;
-
-// static void testHash() {
-//     const char* s = "wusi";
-//     TEST_TRUE(hashString(s) != 0);
-// }
-
-template<typename T>
-static T getTestIntMap() {
-    T map;
+static IntMap getTestIntMap() {
+    IntMap map;
     map.add(1, 3).add(2, 4).add(3, 5).add(0, 20);
     return map;
 }
 
-template<typename T>
-static void checkIntMap(T& map) {
+static void checkIntMap(IntMap& map) {
     int* a = map.search(1);
     int* b = map.search(2);
     int* c = map.search(3);
@@ -36,9 +26,8 @@ static void checkIntMap(T& map) {
     }
 }
 
-template<typename T>
 static void testAdd() {
-    T map;
+    IntMap map;
     map.add(5, 4);
     int* value = map.search(5);
     if(TEST_NOT_NULL(value)) {
@@ -46,9 +35,8 @@ static void testAdd() {
     }
 }
 
-template<typename T>
 static void testMultipleAdd() {
-    T map = getTestIntMap<T>();
+    IntMap map = getTestIntMap();
     TEST_TRUE(map.contains(0));
     TEST_TRUE(map.contains(1));
     TEST_TRUE(map.contains(2));
@@ -56,17 +44,15 @@ static void testMultipleAdd() {
     checkIntMap(map);
 }
 
-template<typename T>
 static void testSearch() {
-    T map;
+    IntMap map;
     TEST_NULL(map.search(6));
     map.add(5, 4).add(10, 3).add(15, 2);
     TEST_NULL(map.search(6));
 }
 
-template<typename T>
 static void testAddReplace() {
-    T map;
+    IntMap map;
     map.add(5, 4).add(5, 10);
     TEST_TRUE(map.contains(5));
     int* a = map.search(5);
@@ -75,9 +61,8 @@ static void testAddReplace() {
     }
 }
 
-template<typename T>
 static void testClear() {
-    T map;
+    IntMap map;
     map.clear();
     map.add(5, 4).add(4, 10);
     map.clear();
@@ -85,10 +70,9 @@ static void testClear() {
     TEST_FALSE(map.contains(4));
 }
 
-template<typename T>
 static void testOverflow(bool light) {
     int limit = light ? 10'000 : 100'000;
-    T map;
+    IntMap map;
     for(int i = 0; i < limit; i++) {
         map.add(i, i);
     }
@@ -99,44 +83,19 @@ static void testOverflow(bool light) {
 
 static int aInstances = 0;
 
-struct HashMapTest {
+struct ProbingTest final {
     int a;
     int b;
 
-    HashMapTest(int a_, int b_) : a(a_), b(b_) {
-    }
-
-    // none of these should be needed for the hashmap
-    HashMapTest(const HashMapTest&) = delete;
-    HashMapTest(HashMapTest&&) = delete;
-    HashMapTest& operator=(const HashMapTest&) = delete;
-    HashMapTest& operator=(HashMapTest&&) = delete;
-
-    bool operator==(const HashMapTest& other) const {
-        return a == other.a && b == other.b;
-    }
-
-    size_t toString(char* s, size_t n) const {
-        size_t total = 0;
-        addString("A(", s, n, total);
-        addString(a, s, n, total);
-        addString(", ", s, n, total);
-        addString(b, s, n, total);
-        addString(")", s, n, total);
-        return total;
-    }
-};
-
-struct ProbingTest final : public HashMapTest {
-    ProbingTest(int a_, int b_) : HashMapTest(a_, b_) {
+    ProbingTest(int a_, int b_) : a(a_), b(b_) {
         aInstances++;
     }
 
-    ProbingTest(const ProbingTest& o) : HashMapTest(o.a, o.b) {
+    ProbingTest(const ProbingTest& o) : ProbingTest(o.a, o.b) {
         aInstances++;
     }
 
-    ProbingTest(ProbingTest&& o) : HashMapTest(o.a, o.b) {
+    ProbingTest(ProbingTest&& o) : ProbingTest(o.a, o.b) {
         aInstances++;
     }
 
@@ -149,11 +108,25 @@ struct ProbingTest final : public HashMapTest {
         b = o.b;
         return *this;
     }
+
+    bool operator==(const ProbingTest& other) const {
+        return a == other.a && b == other.b;
+    }
+
+    size_t toString(char* s, size_t n) const {
+        size_t total = 0;
+        Core::addString("A(", s, n, total);
+        Core::addString(a, s, n, total);
+        Core::addString(", ", s, n, total);
+        Core::addString(b, s, n, total);
+        Core::addString(")", s, n, total);
+        return total;
+    }
 };
 
 static void testEmplaceProbing() {
     {
-        Core::ProbingHashMap<int, ProbingTest> map;
+        Core::HashMap<int, ProbingTest> map;
 
         ProbingTest* ar = nullptr;
         TEST_TRUE(map.tryEmplace(ar, 0, 3, 4));
@@ -175,23 +148,16 @@ static void testEmplaceProbing() {
     TEST(0, aInstances);
 }
 
-template<typename T>
 static void testToString() {
-    if constexpr(Core::IsSame<T, int>) {
-        TEST_STRING(
-            "[1 = 3, 2 = 4, 3 = 5, 2147483647 = 20]", getTestIntMap<T>());
-    } else {
-        TEST_STRING("[0 = 20, 2 = 4, 1 = 3, 3 = 5]", getTestIntMap<T>());
-    }
-    TEST_STRING("[1 = 3]", T().add(1, 3));
-    TEST_STRING("[]", T());
+    TEST_STRING("[0 = 20, 2 = 4, 1 = 3, 3 = 5]", getTestIntMap());
+    TEST_STRING("[1 = 3]", IntMap().add(1, 3));
+    TEST_STRING("[]", IntMap());
 }
 
-template<typename T>
 static void testCopy() {
-    T map = getTestIntMap<T>();
-    T copy = map;
-    T copyA;
+    IntMap map = getTestIntMap();
+    IntMap copy = map;
+    IntMap copyA;
     copyA = map;
     checkIntMap(map);
     checkIntMap(copy);
@@ -201,24 +167,21 @@ static void testCopy() {
     checkIntMap(copyA);
 }
 
-template<typename T>
 static void testMove() {
-    T map = getTestIntMap<T>();
-    T move(Core::move(map));
+    IntMap map = getTestIntMap();
+    IntMap move(Core::move(map));
     checkIntMap(move);
 }
 
-template<typename T>
 static void testMoveAssignment() {
-    T map = getTestIntMap<T>();
-    T move;
+    IntMap map = getTestIntMap();
+    IntMap move;
     move = Core::move(map);
     checkIntMap(move);
 }
 
-template<typename T>
 static void testEntryForEach() {
-    T map;
+    IntMap map;
     map.add(0, 1).add(5, 4).add(10, 3).add(15, 2);
 
     int counter = 0;
@@ -227,7 +190,7 @@ static void testEntryForEach() {
     }
     TEST(40, counter);
 
-    const T& cmap = map;
+    const IntMap& cmap = map;
     counter = 0;
     for(auto entry : cmap) {
         counter += entry.getKey() + entry.value;
@@ -235,9 +198,8 @@ static void testEntryForEach() {
     TEST(40, counter);
 }
 
-template<typename T>
 static void testKeyForEach() {
-    T map;
+    IntMap map;
     map.add(5, 4).add(10, 3).add(15, 2);
 
     int counter = 0;
@@ -246,7 +208,7 @@ static void testKeyForEach() {
     }
     TEST(30, counter);
 
-    const T& cmap = map;
+    const IntMap& cmap = map;
     counter = 0;
     for(const int& key : cmap.getKeys()) {
         counter += key;
@@ -254,9 +216,8 @@ static void testKeyForEach() {
     TEST(30, counter);
 }
 
-template<typename T>
 static void testValueForEach() {
-    T map;
+    IntMap map;
     map.add(5, 4).add(10, 3).add(15, 2);
 
     int counter = 0;
@@ -265,7 +226,7 @@ static void testValueForEach() {
     }
     TEST(9, counter);
 
-    const T& cmap = map;
+    const IntMap& cmap = map;
     counter = 0;
     for(const int& value : cmap.getValues()) {
         counter += value;
@@ -275,11 +236,10 @@ static void testValueForEach() {
 
 template<typename T>
 static void testType() {
-    Core::ProbingHashMap<T, int> m;
+    Core::HashMap<T, int> m;
     m.add(1, 3);
 }
 
-template<typename T>
 static void testTypes() {
     testType<char>();
     testType<signed char>();
@@ -294,10 +254,9 @@ static void testTypes() {
     testType<unsigned long long>();
 }
 
-template<typename T>
 static void testInvalid() {
-    T map;
-    int* v;
+    IntMap map;
+    int* v = nullptr;
     TEST_TRUE(map.tryEmplace(v, 0, 2));
     if(TEST_NOT_NULL(v)) {
         TEST(2, *v);
@@ -315,9 +274,8 @@ static void testInvalid() {
     TEST_NULL(map.search(0));
 }
 
-template<typename T>
 static void testInvalidPut() {
-    T map;
+    IntMap map;
     TEST_STRING("[]", map);
     TEST(3, map.put(0, 3));
     TEST_STRING("[0 = 3]", map);
@@ -330,17 +288,15 @@ static void testInvalidPut() {
     TEST_STRING("[]", map);
 }
 
-template<typename T>
 static void testAddCollisions() {
-    T map;
+    IntMap map;
     for(int i = 0; i < 16; i++) {
         map.add(i * 64, i);
     }
 }
 
-template<typename T>
 static void testRemove() {
-    T map;
+    IntMap map;
     map.add(1, 3).add(2, 4).add(3, 5);
 
     TEST_TRUE(map.remove(2));
@@ -357,9 +313,8 @@ static void testRemove() {
     }
 }
 
-template<typename T>
 static void testRemoveLong() {
-    T map;
+    IntMap map;
     Core::Random r(5);
     constexpr size_t LIMIT = 75;
     Core::Array<i32, LIMIT> a;
@@ -387,54 +342,25 @@ static void testRemoveLong() {
     }
 }
 
-template<typename T>
-static void testMap(bool light) {
-    testAdd<T>();
-    testMultipleAdd<T>();
-    testSearch<T>();
-    testAddReplace<T>();
-    testClear<T>();
-    testOverflow<T>(light);
-    testToString<T>();
-    testCopy<T>();
-    testMove<T>();
-    testMoveAssignment<T>();
-    testEntryForEach<T>();
-    testKeyForEach<T>();
-    testValueForEach<T>();
-    testTypes<T>();
-    testInvalid<T>();
-    testInvalidPut<T>();
-    testAddCollisions<T>();
-    testRemove<T>();
-    testRemoveLong<T>();
-}
-
-// static void testEmplace() {
-//     Core::ProbingHashMap<int, HashMapTest> map;
-//
-//     HashMapTest* ar = nullptr;
-//     TEST_TRUE(map.tryEmplace(ar, 0, 3, 4));
-//     TEST_TRUE(map.tryEmplace(ar, 3, 4, 5));
-//     TEST_TRUE(map.tryEmplace(ar, 20, 5, 6));
-//     TEST_FALSE(map.tryEmplace(ar, 3, 6, 7));
-//     TEST_FALSE(map.tryEmplace(ar, 20, 7, 8));
-//
-//     HashMapTest* a = map.search(0);
-//     HashMapTest* b = map.search(3);
-//     HashMapTest* c = map.search(20);
-//
-//     if(TEST_NOT_NULL(a) && TEST_NOT_NULL(b) && TEST_NOT_NULL(c)) {
-//         TEST(HashMapTest(3, 4), *a);
-//         TEST(HashMapTest(4, 5), *b);
-//         TEST(HashMapTest(5, 6), *c);
-//     }
-// }
-
 void testHashMap(bool light) {
-    // testHash();
-    testMap<ProbingIntMap>(light);
-    // testMap<IntMap>(light);
-    // testEmplace();
+    testAdd();
+    testMultipleAdd();
+    testSearch();
+    testAddReplace();
+    testClear();
+    testOverflow(light);
+    testToString();
+    testCopy();
+    testMove();
+    testMoveAssignment();
+    testEntryForEach();
+    testKeyForEach();
+    testValueForEach();
+    testTypes();
+    testInvalid();
+    testInvalidPut();
+    testAddCollisions();
+    testRemove();
+    testRemoveLong();
     testEmplaceProbing();
 }

+ 67 - 0
test/modules/HashedStringTests.cpp

@@ -0,0 +1,67 @@
+#include "../Tests.hpp"
+#include "core/HashMap.hpp"
+#include "core/HashedString.hpp"
+#include "core/Test.hpp"
+
+template class Core::HashedString<32>;
+using HString = Core::HashedString<32>;
+
+static void testComparison() {
+    HString a("test");
+    TEST_STRING("test", static_cast<const char*>(a));
+    HString b("testA");
+    HString c("");
+    HString d("Btest");
+
+    TEST_TRUE(a == a);
+    TEST_TRUE(b == b);
+    TEST_TRUE(c == c);
+    TEST_TRUE(d == d);
+    TEST_TRUE(a != b);
+    TEST_TRUE(a != c);
+    TEST_TRUE(a != d);
+    TEST_TRUE(b != a);
+    TEST_TRUE(b != c);
+    TEST_TRUE(b != d);
+    TEST_TRUE(c != a);
+    TEST_TRUE(c != b);
+    TEST_TRUE(c != d);
+    TEST_TRUE(d != a);
+    TEST_TRUE(d != b);
+    TEST_TRUE(d != c);
+}
+
+static void testLength() {
+    HString s("test");
+    TEST(4, s.getLength());
+    TEST(31, s.getCapacity());
+}
+
+static void testHashCode() {
+    HString a;
+    HString b("wusi");
+    TEST(a.hashCode(), 0lu);
+    TEST_TRUE(b.hashCode() != 0u);
+}
+
+static void testAsHashMapKey() {
+    Core::HashMap<HString, int> map;
+    map.add("wusi", 3).add("hiThere", 7).add("baum123", 5);
+    int* a = map.search("wusi");
+    int* b = map.search("hiThere");
+    int* c = map.search("baum123");
+    TEST_NULL(map.search("423hifd"));
+
+    if(TEST_NOT_NULL(a) && TEST_NOT_NULL(b) && TEST_NOT_NULL(c)) {
+        TEST(3, *a);
+        TEST(7, *b);
+        TEST(5, *c);
+    }
+}
+
+void testHashedString() {
+    testComparison();
+    testLength();
+    testHashCode();
+    testAsHashMapKey();
+}

+ 223 - 92
test/modules/QueueTests.cpp

@@ -1,123 +1,249 @@
-#include "../Tests.h"
-#include "core/Queue.h"
-#include "core/ToString.h"
+#include "../Tests.hpp"
+#include "core/Queue.hpp"
+#include "core/Test.hpp"
 
-QUEUE(size_t, Size)
-QUEUE_SOURCE(size_t, Size)
+template class Core::Queue<int, 5>;
+
+struct Tester final {
+    static int ids;
+    static int sum;
+    int id;
+
+    Tester() : id(++ids) {
+        sum += id;
+    }
+
+    Tester(const Tester&) : id(++ids) {
+        sum += id;
+    }
+
+    Tester(Tester&&) : id(++ids) {
+        sum += id;
+    }
+
+    Tester& operator=(const Tester&) {
+        return *this;
+    }
+
+    Tester& operator=(Tester&&) {
+        return *this;
+    }
+
+    ~Tester() {
+        sum -= id;
+    }
+
+    size_t toString(char* s, size_t n) const {
+        int w = snprintf(s, n, "%d", id);
+        return w >= 0 ? static_cast<size_t>(w) : 0;
+    }
+};
+
+int Tester::ids = 0;
+int Tester::sum = 0;
+
+static void resetTester() {
+    Tester::ids = 0;
+    Tester::sum = 0;
+}
 
 static void testReadAndWrite() {
-    QueueSize r;
-    initQueueSize(&r, 5);
-    TEST_SIZE(0, r.length);
-    pushQueueDataSize(&r, 4);
-    TEST_SIZE(1, r.length);
-    TEST_SIZE(4, *getQueueIndexSize(&r, 0));
-    popQueueDataSize(&r);
-    TEST_SIZE(0, r.length);
-    destroyQueueSize(&r);
+    Core::Queue<int, 5> buffer;
+    TEST_FALSE(buffer.canRemove());
+    TEST(0, buffer.getLength());
+    buffer.add(4);
+    TEST(1, buffer.getLength());
+    TEST_TRUE(buffer.canRemove());
+    TEST(4, buffer[0]);
+    buffer.remove();
+    TEST_FALSE(buffer.canRemove());
+    TEST(0, buffer.getLength());
 }
 
 static void testOverflow() {
-    QueueSize r;
-    initQueueSize(&r, 3);
-    pushQueueDataSize(&r, 1);
-    pushQueueDataSize(&r, 2);
-    pushQueueDataSize(&r, 3);
-    pushQueueDataSize(&r, 4);
-    pushQueueDataSize(&r, 5);
-    TEST_SIZE(3, r.length);
-    TEST_SIZE(1, *getQueueIndexSize(&r, 0));
-    popQueueDataSize(&r);
-    TEST_SIZE(2, r.length);
-    TEST_SIZE(2, *getQueueIndexSize(&r, 0));
-    popQueueDataSize(&r);
-    TEST_SIZE(1, r.length);
-    TEST_SIZE(3, *getQueueIndexSize(&r, 0));
-    popQueueDataSize(&r);
-    TEST_SIZE(0, r.length);
-    destroyQueueSize(&r);
+    Core::Queue<int, 3> buffer;
+    buffer.add(1).add(2).add(3).add(4).add(5);
+    TEST(3, buffer.getLength());
+    TEST(1, buffer[0]);
+    buffer.remove();
+    TEST(2, buffer.getLength());
+    TEST(2, buffer[0]);
+    buffer.remove();
+    TEST(1, buffer.getLength());
+    TEST(3, buffer[0]);
+    buffer.remove();
+    TEST_FALSE(buffer.canRemove());
+    TEST(0, buffer.getLength());
 }
 
 static void testRefill() {
-    QueueSize r;
-    initQueueSize(&r, 3);
-    pushQueueDataSize(&r, 1);
-    pushQueueDataSize(&r, 2);
-    pushQueueDataSize(&r, 3);
-    pushQueueDataSize(&r, 4);
-    TEST_SIZE(3, r.length);
-    TEST_SIZE(1, *getQueueIndexSize(&r, 0));
-    popQueueDataSize(&r);
-    TEST_SIZE(2, *getQueueIndexSize(&r, 0));
-    popQueueDataSize(&r);
-    TEST_SIZE(3, *getQueueIndexSize(&r, 0));
-    popQueueDataSize(&r);
-    TEST_SIZE(0, r.length);
-    pushQueueDataSize(&r, 5);
-    pushQueueDataSize(&r, 6);
-    TEST_SIZE(2, r.length);
-    TEST_SIZE(5, *getQueueIndexSize(&r, 0));
-    popQueueDataSize(&r);
-    TEST_SIZE(6, *getQueueIndexSize(&r, 0));
-    popQueueDataSize(&r);
-    TEST_SIZE(0, r.length);
-    destroyQueueSize(&r);
+    Core::Queue<int, 3> buffer;
+    buffer.add(1).add(2).add(3).add(4);
+    TEST(3, buffer.getLength());
+    TEST_TRUE(buffer.canRemove());
+    TEST(1, buffer[0]);
+    buffer.remove();
+    TEST(2, buffer[0]);
+    buffer.remove();
+    TEST(3, buffer[0]);
+    buffer.remove();
+    TEST(0, buffer.getLength());
+    TEST_FALSE(buffer.canRemove());
+    buffer.add(5).add(6);
+    TEST(2, buffer.getLength());
+    TEST_TRUE(buffer.canRemove());
+    TEST(5, buffer[0]);
+    buffer.remove();
+    TEST(6, buffer[0]);
+    buffer.remove();
+    TEST_FALSE(buffer.canRemove());
+    TEST(0, buffer.getLength());
 }
 
 static void testClear() {
-    QueueSize r;
-    initQueueSize(&r, 3);
-    pushQueueDataSize(&r, 1);
-    pushQueueDataSize(&r, 2);
-    TEST_SIZE(2, r.length);
-    clearQueueSize(&r);
-    TEST_SIZE(0, r.length);
-    destroyQueueSize(&r);
+    Core::Queue<int, 3> buffer;
+    buffer.add(1).add(2);
+    TEST(2, buffer.getLength());
+    buffer.clear();
+    TEST_FALSE(buffer.canRemove());
+    TEST(0, buffer.getLength());
+}
+
+static void testConstructDestruct() {
+    resetTester();
+    Core::Queue<Tester, 3> buffer;
+    buffer.add();
+    TEST(1, Tester::sum);
+    buffer.add();
+    TEST(3, Tester::sum);
+    buffer.add();
+    TEST(6, Tester::sum);
+
+    buffer.remove();
+    TEST(5, Tester::sum);
+    buffer.remove();
+    TEST(3, Tester::sum);
+    buffer.remove();
+    TEST(0, Tester::sum);
+}
+
+static void testCopyDestruct() {
+    resetTester();
+    {
+        Core::Queue<Tester, 3> buffer;
+        buffer.add();
+        TEST(1, Tester::sum);
+        buffer.add();
+        TEST(3, Tester::sum);
+        buffer.add();
+        TEST(6, Tester::sum);
+        {
+            Core::Queue<Tester, 3> copy = buffer;
+            TEST(6 + 4 + 5 + 6, Tester::sum);
+        }
+        TEST(6, Tester::sum);
+    }
+    TEST(0, Tester::sum);
+}
+
+static void testCopyAssignmentDestruct() {
+    resetTester();
+    {
+        Core::Queue<Tester, 3> buffer;
+        buffer.add();
+        TEST(1, Tester::sum);
+        buffer.add();
+        TEST(3, Tester::sum);
+        buffer.add();
+        TEST(6, Tester::sum);
+        {
+            Core::Queue<Tester, 3> copy;
+            copy = buffer;
+            TEST(6 + 4 + 5 + 6, Tester::sum);
+        }
+        TEST(6, Tester::sum);
+    }
+    TEST(0, Tester::sum);
+}
+
+static void testMoveDestruct() {
+    resetTester();
+    {
+        Core::Queue<Tester, 3> buffer;
+        buffer.add();
+        TEST(1, Tester::sum);
+        buffer.add();
+        TEST(3, Tester::sum);
+        buffer.add();
+        TEST(6, Tester::sum);
+        {
+            Core::Queue<Tester, 3> move = Core::move(buffer);
+            TEST(4 + 5 + 6, Tester::sum);
+            TEST(0, buffer.getLength());
+        }
+        TEST(0, Tester::sum);
+    }
+    TEST(0, Tester::sum);
+}
+
+static void testMoveAssignmentDestruct() {
+    resetTester();
+    {
+        Core::Queue<Tester, 3> buffer;
+        buffer.add();
+        TEST(1, Tester::sum);
+        buffer.add();
+        TEST(3, Tester::sum);
+        buffer.add();
+        TEST(6, Tester::sum);
+        {
+            Core::Queue<Tester, 3> move;
+            move = Core::move(buffer);
+            TEST(4 + 5 + 6, Tester::sum);
+            TEST(0, buffer.getLength());
+        }
+        TEST(0, Tester::sum);
+    }
+    TEST(0, Tester::sum);
 }
 
 static void testOverall() {
-    QueueSize r;
-    initQueueSize(&r, 3);
-    pushQueueDataSize(&r, 1);
-    pushQueueDataSize(&r, 2);
-    pushQueueDataSize(&r, 3);
-
-    char buffer[128];
-    toStringQueueSize(&r, buffer, sizeof(buffer), toStringSize);
+    resetTester();
+    Core::Queue<Tester, 3> buffer;
+    buffer.add().add().add();
     TEST_STRING("[1, 2, 3]", buffer);
-    TEST_SIZE(3, r.length);
+    TEST(3, buffer.getLength());
+    TEST(6, Tester::sum);
 
-    popQueueDataSize(&r);
-    toStringQueueSize(&r, buffer, sizeof(buffer), toStringSize);
+    buffer.remove();
     TEST_STRING("[2, 3]", buffer);
-    TEST_SIZE(2, r.length);
+    TEST(2, buffer.getLength());
+    TEST(5, Tester::sum);
 
-    pushQueueDataSize(&r, 4);
-    toStringQueueSize(&r, buffer, sizeof(buffer), toStringSize);
+    buffer.add();
     TEST_STRING("[2, 3, 4]", buffer);
-    TEST_SIZE(3, r.length);
+    TEST(3, buffer.getLength());
+    TEST(9, Tester::sum);
 
-    popQueueDataSize(&r);
-    toStringQueueSize(&r, buffer, sizeof(buffer), toStringSize);
+    buffer.remove();
     TEST_STRING("[3, 4]", buffer);
-    TEST_SIZE(2, r.length);
+    TEST(2, buffer.getLength());
+    TEST(7, Tester::sum);
 
-    pushQueueDataSize(&r, 5);
-    toStringQueueSize(&r, buffer, sizeof(buffer), toStringSize);
+    buffer.add();
     TEST_STRING("[3, 4, 5]", buffer);
-    TEST_SIZE(3, r.length);
+    TEST(3, buffer.getLength());
+    TEST(12, Tester::sum);
 
-    popQueueDataSize(&r);
-    toStringQueueSize(&r, buffer, sizeof(buffer), toStringSize);
+    buffer.remove();
     TEST_STRING("[4, 5]", buffer);
-    TEST_SIZE(2, r.length);
+    TEST(2, buffer.getLength());
+    TEST(9, Tester::sum);
 
-    clearQueueSize(&r);
-    toStringQueueSize(&r, buffer, sizeof(buffer), toStringSize);
+    buffer.clear();
     TEST_STRING("[]", buffer);
-    TEST_SIZE(0, r.length);
-
-    destroyQueueSize(&r);
+    TEST(0, buffer.getLength());
+    TEST(0, Tester::sum);
 }
 
 void testQueue() {
@@ -125,5 +251,10 @@ void testQueue() {
     testOverflow();
     testRefill();
     testClear();
+    testConstructDestruct();
+    testCopyDestruct();
+    testCopyAssignmentDestruct();
+    testMoveDestruct();
+    testMoveAssignmentDestruct();
     testOverall();
 }

+ 17 - 37
test/modules/ReadLineTests.cpp

@@ -1,64 +1,49 @@
-#include <stdio.h>
-#include <threads.h>
+#include <cstdio>
 
-#include "../Tests.h"
-#include "../src/ErrorSimulator.h"
-#include "core/ReadLine.h"
-
-static void sleepMillis(int millis) {
-    struct timespec t = {.tv_nsec = millis * 1'000'000};
-    thrd_sleep(&t, nullptr);
-}
+#include "../Tests.hpp"
+#include "../src/ErrorSimulator.hpp"
+#include "core/Clock.hpp"
+#include "core/ReadLine.hpp"
+#include "core/Test.hpp"
 
 static void testStringError(int line, const char* s) {
     char buffer[256];
     for(int i = 0; i < 200; i++) {
-        if(readLine(buffer, sizeof(buffer))) {
+        if(Core::readLine(buffer, sizeof(buffer))) {
             break;
         }
-        sleepMillis(10);
+        Core::Clock::sleepMillis(10);
     }
-    if(!testString(__FILE__, line, s, buffer)) {
+    if(!Core::testString(__FILE__, line, s, buffer)) {
         const char* p = buffer;
         printf("Invalid sequence: ");
         while(*p != 0) {
-            printf("%u ", (unsigned int)*p & 0xFF);
+            printf("%u ", static_cast<unsigned int>(*p & 0xFF));
             p++;
         }
         putchar('\n');
         p = s;
         printf("Correct sequence: ");
         while(*p != 0) {
-            printf("%u ", (unsigned int)*p & 0xFF);
+            printf("%u ", static_cast<unsigned int>(*p & 0xFF));
             p++;
         }
         putchar('\n');
     }
 }
 
-void testReadLine(void) {
+void testReadLine() {
 #ifdef ERROR_SIMULATOR
-    failMutexInit = true;
-    if(!TEST_TRUE(startReadLine())) {
-        return;
-    }
-    failMutexInit = false;
-    failThreadInit = true;
-    if(!TEST_TRUE(startReadLine())) {
+    failStepThrow = 1;
+    if(!TEST_TRUE(Core::startReadLine())) {
         return;
     }
-    failThreadInit = false;
-    failMutexLock = true;
-    failMutexUnlock = true;
+    failStepThrow = 0;
 #endif
-    if(!TEST_FALSE(startReadLine())) {
+    if(!TEST_FALSE(Core::startReadLine())) {
         return;
     }
     testStringError(__LINE__, "wusi");
-#ifdef ERROR_SIMULATOR
-    failMutexLock = false;
-    failMutexUnlock = false;
-#endif
     testStringError(__LINE__, "gusi");
     testStringError(__LINE__, "abc");
     testStringError(__LINE__, "abc");
@@ -77,10 +62,5 @@ void testReadLine(void) {
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb");
     testStringError(__LINE__, "abäo");
     testStringError(__LINE__, "bäöo");
-#ifdef ERROR_SIMULATOR
-    failThreadJoin = true;
-    stopReadLine();
-    failThreadJoin = false;
-#endif
-    stopReadLine();
+    Core::stopReadLine();
 }

+ 0 - 74
test/modules/SpinLockTests.cpp

@@ -1,74 +0,0 @@
-#include <inttypes.h>
-#include <stdio.h>
-#include <threads.h>
-
-#include "../Tests.h"
-#include "core/SpinLock.h"
-#include "core/Utility.h"
-
-typedef struct {
-    mtx_t m;
-    int counter;
-} MutexCounter;
-
-static int incrementMutexCounter(void* p) {
-    MutexCounter* mcp = (MutexCounter*)p;
-    for(int i = 0; i < 20'000; i++) {
-        mtx_lock(&mcp->m);
-        mcp->counter++;
-        mtx_unlock(&mcp->m);
-    }
-    return 0;
-}
-
-static void testMutex() {
-    i64 n = -getNanos();
-
-    MutexCounter mc = {.counter = 0};
-    mtx_init(&mc.m, mtx_plain);
-    thrd_t t[2];
-    thrd_create(t + 0, incrementMutexCounter, &mc);
-    thrd_create(t + 1, incrementMutexCounter, &mc);
-    thrd_join(t[0], nullptr);
-    thrd_join(t[1], nullptr);
-    TEST_INT(40'000, mc.counter);
-
-    n += getNanos();
-    printf("%" PRId64 "ns Mutex\n", n);
-}
-
-typedef struct {
-    SpinLock s;
-    int counter;
-} SpinLockCounter;
-
-static int incrementSpinLockCounter(void* p) {
-    SpinLockCounter* mcp = (SpinLockCounter*)p;
-    for(int i = 0; i < 20'000; i++) {
-        lockSpinLock(&mcp->s);
-        mcp->counter++;
-        unlockSpinLock(&mcp->s);
-    }
-    return 0;
-}
-
-static void testSpinLockLoop() {
-    i64 n = -getNanos();
-
-    SpinLockCounter sc = {.counter = 0};
-    initSpinLock(&sc.s);
-    thrd_t t[2];
-    thrd_create(t + 0, incrementSpinLockCounter, &sc);
-    thrd_create(t + 1, incrementSpinLockCounter, &sc);
-    thrd_join(t[0], nullptr);
-    thrd_join(t[1], nullptr);
-    TEST_INT(40'000, sc.counter);
-
-    n += getNanos();
-    printf("%" PRId64 "ns SpinLock\n", n);
-}
-
-void testSpinLock() {
-    testMutex();
-    testSpinLockLoop();
-}

+ 2 - 2
test/modules/TerminalTests.cpp

@@ -1,10 +1,10 @@
 #include <stdio.h>
 
 #include "../Tests.hpp"
+#include "core/Clock.hpp"
 #include "core/Logger.hpp"
 #include "core/Terminal.hpp"
 #include "core/Test.hpp"
-#include "core/Utility.hpp"
 
 #define KEY_CASE(key)           \
     case key: puts(#key); break
@@ -59,7 +59,7 @@ void testInteractiveTerminal(void) {
     Core::resetCursor();
     Core::showCursor();
     puts("the final!!!");
-    Core::sleepMillis(500);
+    Core::Clock::sleepMillis(500);
 
     Core::enterRawTerminal();
 

+ 133 - 0
test/modules/ThreadTests.cpp

@@ -0,0 +1,133 @@
+#include "../../src/ErrorSimulator.hpp"
+#include "../Tests.hpp"
+#include "core/Test.hpp"
+#include "core/Thread.hpp"
+
+static int runDone = 0;
+
+struct IntHolder {
+    int value;
+};
+
+static void run(void*) {
+    runDone = 1;
+}
+
+static void testStart() {
+    runDone = 0;
+    {
+        Core::Thread t;
+        TEST_FALSE(t.start(run, nullptr));
+    }
+    TEST(1, runDone);
+}
+
+static void testLambda() {
+    IntHolder i(0);
+    Core::Thread t;
+    TEST_FALSE(t.start([](void* p) {
+        IntHolder* ip = static_cast<IntHolder*>(p);
+        ip->value = 2;
+    }, &i));
+    TEST_FALSE(t.join());
+    TEST(2, i.value);
+}
+
+static void testJoinWithoutStart() {
+    Core::Thread t;
+    TEST_FALSE(t.join());
+}
+
+static void testAutoJoin() {
+    Core::Thread t;
+    TEST_FALSE(t.start([](void*) {}, nullptr));
+}
+
+static void testMove() {
+    Core::Thread t;
+    TEST_FALSE(t.start([](void*) {}, nullptr));
+    Core::Thread m = Core::move(t);
+    TEST_FALSE(m.join());
+}
+
+static void testMoveAssignment() {
+    Core::Thread t;
+    TEST_FALSE(t.start([](void*) {}, nullptr));
+    Core::Thread m;
+    m = Core::move(t);
+    TEST_FALSE(m.join());
+}
+
+static void testMoveIntoActive() {
+    Core::Thread t;
+    TEST_FALSE(t.start([](void*) {}, nullptr));
+    Core::Thread m;
+    t = Core::move(m);
+}
+
+static void testDoubleJoin() {
+    Core::Thread t;
+    TEST_FALSE(t.start([](void*) {}, nullptr));
+    TEST_FALSE(t.join());
+    TEST_FALSE(t.join());
+}
+
+struct MutexCounter {
+    Core::Mutex m{};
+    int counter = 0;
+};
+
+static void incrementMutexCounter(void* p) {
+    MutexCounter* mcp = static_cast<MutexCounter*>(p);
+    for(int i = 0; i < 100'000; i++) {
+        Core::MutexGuard mg(mcp->m);
+        mcp->counter++;
+    }
+}
+
+static void testMutex() {
+    MutexCounter mc;
+    Core::Thread t[2];
+    TEST_FALSE(t[0].start(incrementMutexCounter, &mc));
+    TEST_FALSE(t[1].start(incrementMutexCounter, &mc));
+    TEST_FALSE(t[0].join());
+    TEST_FALSE(t[1].join());
+    TEST(200'000, mc.counter);
+}
+
+static void testDoubleStart() {
+    Core::Thread t;
+    TEST_FALSE(t.start([](void*) {}, nullptr));
+    TEST_TRUE(t.start([](void*) {}, nullptr));
+}
+
+static void testFail() {
+#ifdef ERROR_SIMULATOR
+    Core::Mutex m;
+    failStepThrow = 1;
+    m.lock();
+    failStepThrow = 1;
+    m.unlock();
+
+    Core::Thread t;
+    failStepThrow = 1;
+    TEST_TRUE(t.start([](void*) {}, nullptr));
+    TEST_FALSE(t.start([](void*) {}, nullptr));
+    failStepThrow = 1;
+    TEST_TRUE(t.join());
+#endif
+}
+
+void testThread() {
+    testStart();
+    testLambda();
+    testJoinWithoutStart();
+    testAutoJoin();
+    testMove();
+    testMoveAssignment();
+    testMoveIntoActive();
+    testDoubleJoin();
+    testMutex();
+    testDoubleStart();
+    testFail();
+}

+ 20 - 39
test/modules/UtilityTests.cpp

@@ -1,6 +1,5 @@
 #include <cstring>
 
-#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/Test.hpp"
 #include "core/ToString.hpp"
@@ -51,21 +50,6 @@ static void testZeroAllocate() {
     Core::deallocateRaw(b);
 }
 
-static void testSleep(i64 nanos) {
-    i64 time = -Core::getNanos();
-    TEST_FALSE(Core::sleepNanos(nanos));
-    time += Core::getNanos();
-    TEST_TRUE(time >= nanos && time <= (nanos * 13) / 10);
-}
-
-static void testSleepMillis(i64 millis) {
-    i64 time = -Core::getNanos();
-    TEST_FALSE(Core::sleepMillis(millis));
-    time += Core::getNanos();
-    i64 nanos = millis * 1'000'000;
-    TEST_TRUE(time >= nanos && time <= (nanos * 13) / 10);
-}
-
 typedef struct {
     int i;
     i64 d;
@@ -81,16 +65,6 @@ static void testSwap() {
     TEST(20l, b.d);
 }
 
-static void testFail() {
-#ifdef ERROR_SIMULATOR
-    failStepThrow = 1;
-    TEST(-1l, Core::getNanos());
-    failStepThrow = 1;
-    TEST_TRUE(Core::sleepMillis(5));
-    failStepThrow = 0;
-#endif
-}
-
 static void testSort() {
     size_t data[] = {9, 0, 3, 1, 8, 4, 6, 2, 5, 7};
     size_t n = 10;
@@ -104,33 +78,40 @@ static void testSort() {
 
 static void testToString() {
     char buffer[512];
-    TEST(10, formatBuffer(buffer, sizeof(buffer), "a#a##a", 1.0, 2, 3));
+    TEST(10, Core::formatBuffer(buffer, sizeof(buffer), "a#a##a", 1.0, 2, 3));
     TEST_STRING("a1.00a#a23", buffer);
-    TEST(5, formatBuffer(buffer, sizeof(buffer), "aa##ab"));
+    TEST(5, Core::formatBuffer(buffer, sizeof(buffer), "aa##ab"));
     TEST_STRING("aa#ab", buffer);
-    TEST(6, formatBuffer(buffer, 3, "aaaaaa"));
+    TEST(6, Core::formatBuffer(buffer, 3, "aaaaaa"));
     TEST_STRING("aa", buffer);
-    TEST(4, formatBuffer(buffer, 4, "a#", 456));
+    TEST(4, Core::formatBuffer(buffer, 4, "a#", 456));
     TEST_STRING("a45", buffer);
-    TEST(10, formatBuffer(buffer, 4, "# # #", 456, 567, 78));
+    TEST(10, Core::formatBuffer(buffer, 4, "# # #", 456, 567, 78));
     TEST_STRING("456", buffer);
-    TEST(10, formatBuffer(buffer, 1, "# # #", 456, 567, 78));
+    TEST(10, Core::formatBuffer(buffer, 1, "# # #", 456, 567, 78));
     TEST_STRING("", buffer);
-    TEST(10, formatBuffer(nullptr, 0, "# # #", 456ll, 567l, 78ull));
+    TEST(10, Core::formatBuffer(nullptr, 0, "# # #", 456ll, 567l, 78ull));
+
+    char c = 'a';
+    short s = 4;
+    unsigned char cu = 'h';
+    unsigned short su = 67;
+    TEST(
+        8, Core::formatBuffer(buffer, sizeof(buffer), "# # # #", c, s, cu, su));
+    TEST_STRING("a 4 h 67", buffer);
+
+    unsigned char text[] = "fgsdf";
+    TEST(5, Core::toString(text, buffer, sizeof(buffer)));
+    TEST_STRING("fgsdf", buffer);
 }
 
-void testUtility(bool light) {
+void testUtility() {
     testPopCount();
     testIf();
     testZeroRellocate();
     testMemoryInfoList();
     testZeroAllocate();
-    testSleep(light ? 5'000'000 : 50'000'000);
-    testSleep(light ? 50'000'000 : 1'300'000'000);
-    testSleepMillis(light ? 5 : 50);
-    testSleepMillis(light ? 50 : 1300);
     testSwap();
-    testFail();
     testSort();
     testToString();
 }

BIN
testData/readLineTest