Browse Source

Split utility into more files

Kajetan Johannes Hammerle 10 months ago
parent
commit
aa67387e3e

+ 2 - 5
data/ArrayList.h

@@ -1,6 +1,7 @@
 #ifndef CORE_ARRAYLIST_H
 #define CORE_ARRAYLIST_H
 
+#include "utils/AlignedData.h"
 #include "utils/ArrayString.h"
 
 namespace Core {
@@ -8,11 +9,7 @@ namespace Core {
     class ArrayList final {
         static_assert(N > 0, "ArrayList size must be positive");
 
-        struct alignas(T) Aligned final {
-            char data[sizeof(T)];
-        };
-
-        Aligned data[static_cast<unsigned int>(N)];
+        AlignedType<T> data[static_cast<unsigned int>(N)];
         int length;
 
     public:

+ 0 - 1
data/BitArray.cpp

@@ -1,7 +1,6 @@
 #include "data/BitArray.h"
 
 #include "math/Math.h"
-#include "utils/Utility.h"
 
 static int roundUpDivide(int a, int b) {
     if(a % b == 0) {

+ 0 - 1
data/HashMap.h

@@ -3,7 +3,6 @@
 
 #include "data/LinkedList.h"
 #include "data/List.h"
-#include "utils/ArrayString.h"
 #include "utils/HashCode.h"
 
 namespace Core {

+ 5 - 6
data/List.h

@@ -1,7 +1,9 @@
 #ifndef CORE_LIST_H
 #define CORE_LIST_H
 
+#include "utils/AlignedData.h"
 #include "utils/ArrayString.h"
+#include "utils/New.hpp"
 
 namespace Core {
     template<typename T>
@@ -22,7 +24,7 @@ namespace Core {
 
         ~List() {
             clear();
-            delete[] reinterpret_cast<Aligned*>(data);
+            delete[] reinterpret_cast<AlignedType<T>*>(data);
         }
 
         List& operator=(const List& other) = delete;
@@ -187,15 +189,12 @@ namespace Core {
         }
 
     private:
-        struct alignas(T) Aligned final {
-            char data[sizeof(T)];
-        };
-
         static Error allocate(T*& t, int n) {
             if(n <= 0) {
                 return Error::NEGATIVE_ARGUMENT;
             }
-            t = reinterpret_cast<T*>(new Aligned[static_cast<size_t>(n)]);
+            t = reinterpret_cast<T*>(
+                new AlignedType<T>[static_cast<size_t>(n)]);
             return t == nullptr ? Error::OUT_OF_MEMORY : Error::NONE;
         }
 

+ 3 - 6
data/ProbingHashMap.h

@@ -2,6 +2,7 @@
 #define CORE_PROBING_HASHMAP_H
 
 #include "data/List.h"
+#include "utils/AlignedData.h"
 #include "utils/ArrayString.h"
 #include "utils/HashCode.h"
 #include "utils/Logger.h"
@@ -119,10 +120,6 @@ namespace Core {
             IteratorAdapter<const ProbingHashMap, ConstKeyIterator>;
 
     private:
-        struct alignas(V) AlignedValue final {
-            char data[sizeof(V)];
-        };
-
         List<K> keys;
         V* values;
         int entries;
@@ -143,7 +140,7 @@ namespace Core {
                     values[i].~V();
                 }
             }
-            delete[] reinterpret_cast<AlignedValue*>(values);
+            delete[] reinterpret_cast<AlignedType<V>*>(values);
         }
 
         ProbingHashMap& operator=(const ProbingHashMap& other) = delete;
@@ -169,7 +166,7 @@ namespace Core {
             ProbingHashMap<K, V> map;
             int l = Core::Math::max(1 << Math::roundUpLog2(minCapacity), 8);
             CORE_RETURN_ERROR(map.keys.resize(l, emptyValue<K>()));
-            map.values = reinterpret_cast<V*>(new AlignedValue[l]);
+            map.values = reinterpret_cast<V*>(new AlignedType<V>[l]);
             if(map.values == nullptr) {
                 return Error::OUT_OF_MEMORY;
             }

+ 2 - 5
data/RingBuffer.h

@@ -1,6 +1,7 @@
 #ifndef CORE_RINGBUFFER_H
 #define CORE_RINGBUFFER_H
 
+#include "utils/AlignedData.h"
 #include "utils/ArrayString.h"
 
 namespace Core {
@@ -8,11 +9,7 @@ namespace Core {
     class RingBuffer final {
         static_assert(N > 0, "RingBuffer size must be positive");
 
-        struct alignas(T) Aligned final {
-            char data[sizeof(T)];
-        };
-
-        Aligned data[static_cast<unsigned int>(N)];
+        AlignedType<T> data[static_cast<unsigned int>(N)];
         int writeIndex;
         int readIndex;
         int values;

+ 1 - 1
math/Math.h

@@ -1,7 +1,7 @@
 #ifndef CORE_MATH_H
 #define CORE_MATH_H
 
-#include "utils/Utility.h"
+#include "utils/Meta.hpp"
 
 namespace Core::Math {
     template<typename T>

+ 2 - 0
meson.build

@@ -3,6 +3,8 @@ project('core', 'cpp', default_options : ['cpp_std=c++2a'])
 src = [
     'utils/Logger.cpp',
     'utils/Utility.cpp',
+    'utils/Error.cpp',
+    'utils/New.cpp',
     'utils/Buffer.cpp',
     'utils/Clock.cpp',
     'utils/Random.cpp',

+ 1 - 1
test/Main.cpp

@@ -29,7 +29,7 @@
 #include "tests/VectorTests.h"
 #include "tests/ViewTests.h"
 #include "utils/ArrayString.h"
-#include "utils/Utility.h"
+#include "utils/Utility.hpp"
 
 static void onExit(int code, void* data) {
     unsigned int i = *static_cast<unsigned int*>(data);

+ 13 - 8
tests/ThreadTests.cpp

@@ -1,7 +1,7 @@
 #include "tests/ThreadTests.h"
 
 #include "test/Test.h"
-#include "thread/Thread.h"
+#include "thread/Thread.hpp"
 
 static int runDone = 0;
 
@@ -16,30 +16,35 @@ static int run(void*) {
 
 static void testStart() {
     runDone = 0;
-    Core::Thread::Id id = Core::Thread::INVALID_ID;
-    CORE_TEST_ERROR(Core::Thread::start(id, run, nullptr));
+    Core::Thread t;
+    CORE_TEST_ERROR(t.start(run, nullptr));
     int returnValue = 0;
-    CORE_TEST_ERROR(Core::Thread::join(id, &returnValue));
+    CORE_TEST_ERROR(t.join(&returnValue));
     CORE_TEST_EQUAL(1, runDone);
     CORE_TEST_EQUAL(7, returnValue);
 }
 
 static void testLambda() {
     IntHolder i(0);
-    Core::Thread::Id id = Core::Thread::INVALID_ID;
-    CORE_TEST_ERROR(Core::Thread::start(
-        id,
+    Core::Thread t;
+    CORE_TEST_ERROR(t.start(
         [](void* p) {
             IntHolder* ip = static_cast<IntHolder*>(p);
             ip->value = 2;
             return 0;
         },
         &i));
-    CORE_TEST_ERROR(Core::Thread::join(id, nullptr));
+    CORE_TEST_ERROR(t.join(nullptr));
     CORE_TEST_EQUAL(2, i.value);
 }
 
+static void testJoinWithoutStart() {
+    Core::Thread t;
+    CORE_TEST_EQUAL(Core::Error::THREAD_ERROR, t.join(nullptr));
+}
+
 void Core::ThreadTests::test() {
     testStart();
     testLambda();
+    testJoinWithoutStart();
 }

+ 0 - 1
tests/UniquePointerTests.cpp

@@ -2,7 +2,6 @@
 
 #include "test/Test.h"
 #include "utils/UniquePointer.h"
-#include "utils/Utility.h"
 
 struct B final {
     static int instances;

+ 1 - 1
tests/UtilityTests.cpp

@@ -1,7 +1,7 @@
 #include "tests/UtilityTests.h"
 
 #include "test/Test.h"
-#include "utils/Utility.h"
+#include "utils/Utility.hpp"
 
 static void testPopCount() {
     CORE_TEST_EQUAL(4, Core::popCount(0xF));

+ 10 - 25
thread/Thread.cpp

@@ -1,31 +1,16 @@
-#include "thread/Thread.h"
+#include "thread/Thread.hpp"
 
 #include <threads.h>
 
-#include "data/HashMap.h"
-
-static Core::HashMap<Core::Thread::Id, thrd_t> threads;
-static Core::Thread::Id idCounter = 0;
-
-Core::Error Core::Thread::start(Id& id, Function f, void* p) {
-    id = idCounter++;
-    thrd_t* t = nullptr;
-    CORE_RETURN_ERROR(threads.tryEmplace(t, id));
-    if(thrd_create(t, f, p) != thrd_success) {
-        (void)threads.remove(id);
-        id = INVALID_ID;
-        return Error::THREAD_ERROR;
-    }
-    return Error::NONE;
+check_return Core::Error Core::Thread::start(Function f, void* p) {
+    ASSERT_ALIGNED_DATA(thread, thrd_t);
+    return thrd_create(thread.as<thrd_t>(), f, p) != thrd_success
+               ? Error::THREAD_ERROR
+               : Error::NONE;
 }
 
-Core::Error Core::Thread::join(Id id, int* returnValue) {
-    thrd_t* t = threads.search(id);
-    if(t == nullptr) {
-        return Error::INVALID_ID;
-    }
-    if(thrd_join(*t, returnValue) != thrd_success) {
-        return Error::THREAD_ERROR;
-    }
-    return threads.remove(id);
+check_return Core::Error Core::Thread::join(int* returnValue) {
+    return thrd_join(*thread.as<thrd_t>(), returnValue) != thrd_success
+               ? Error::THREAD_ERROR
+               : Error::NONE;
 }

+ 0 - 15
thread/Thread.h

@@ -1,15 +0,0 @@
-#ifndef CORE_THREAD_H
-#define CORE_THREAD_H
-
-#include "utils/Utility.h"
-
-namespace Core::Thread {
-    using Id = int;
-    using Function = int (*)(void*);
-    constexpr Id INVALID_ID = -1;
-
-    check_return Error start(Id& id, Function f, void* p);
-    check_return Error join(Id id, int* returnValue = nullptr);
-}
-
-#endif

+ 20 - 0
thread/Thread.hpp

@@ -0,0 +1,20 @@
+#ifndef CORE_THREAD_H
+#define CORE_THREAD_H
+
+#include "utils/AlignedData.h"
+#include "utils/Check.hpp"
+#include "utils/Error.hpp"
+
+namespace Core {
+    class Thread {
+        AlignedData<8, 8> thread;
+
+    public:
+        using Function = int (*)(void*);
+
+        check_return Error start(Function f, void* p);
+        check_return Error join(int* returnValue = nullptr);
+    };
+}
+
+#endif

+ 42 - 0
utils/AlignedData.h

@@ -0,0 +1,42 @@
+#ifndef CORE_ALIGNED_DATA_H
+#define CORE_ALIGNED_DATA_H
+
+#define alignmentof(type) __alignof__(type)
+
+#define ASSERT_ALIGNED_DATA(var, type)                                         \
+    static_assert(sizeof(var) == sizeof(type), "aligned data size missmatch"); \
+    static_assert(var.getSize() >= var.getAlignment(), "size >= alignment");   \
+    static_assert(alignmentof(var) == alignmentof(type),                       \
+                  "aligned data alignment missmatch");
+
+namespace Core {
+    template<int SIZE, int ALIGNMENT>
+    class alignas(ALIGNMENT) AlignedData {
+        static_assert(SIZE > 0, "size must be positive");
+        char buffer[static_cast<unsigned int>(SIZE)] = {};
+
+    public:
+        template<typename T>
+        T* as() {
+            return reinterpret_cast<T*>(this);
+        }
+
+        template<typename T>
+        const T* as() const {
+            return reinterpret_cast<T*>(this);
+        }
+
+        static consteval int getSize() {
+            return SIZE;
+        }
+
+        static consteval int getAlignment() {
+            return ALIGNMENT;
+        }
+    };
+
+    template<typename T>
+    using AlignedType = AlignedData<sizeof(T), alignmentof(T)>;
+}
+
+#endif

+ 3 - 2
utils/ArrayString.h

@@ -2,8 +2,9 @@
 #define CORE_ARRAY_STRING_H
 
 #include "math/Math.h"
-#include "utils/Check.h"
-#include "utils/Utility.h"
+#include "utils/Check.hpp"
+#include "utils/Types.hpp"
+#include "utils/Utility.hpp"
 
 namespace Core {
     template<int N, typename CharType>

+ 1 - 1
utils/Buffer.cpp

@@ -1,7 +1,7 @@
 #include "utils/Buffer.h"
 
 #include "math/Math.h"
-#include "utils/Utility.h"
+#include "utils/Utility.hpp"
 
 Core::Buffer::Buffer(int initialSize)
     : length(0), capacity(initialSize <= 0 ? 1 : initialSize), buffer(nullptr) {

+ 2 - 1
utils/Buffer.h

@@ -1,7 +1,8 @@
 #ifndef CORE_BUFFER_H
 #define CORE_BUFFER_H
 
-#include "utils/Utility.h"
+#include "utils/Check.hpp"
+#include "utils/Error.hpp"
 
 namespace Core {
     class Buffer final {

+ 0 - 0
utils/Check.h → utils/Check.hpp


+ 2 - 1
utils/Clock.h

@@ -2,7 +2,8 @@
 #define CORE_CLOCK_H
 
 #include "data/Array.h"
-#include "utils/Check.h"
+#include "utils/Check.hpp"
+#include "utils/Types.hpp"
 
 namespace Core {
     struct Clock final {

+ 23 - 0
utils/Error.cpp

@@ -0,0 +1,23 @@
+#include "utils/Error.hpp"
+
+const char* Core::getErrorName(Error e) {
+    switch(e) {
+        case Error::NONE: return "NONE";
+        case Error::NEGATIVE_ARGUMENT: return "NEGATIVE_ARGUMENT";
+        case Error::CAPACITY_REACHED: return "CAPACITY_REACHED";
+        case Error::BLOCKED_STDOUT: return "BLOCKED_STDOUT";
+        case Error::OUT_OF_MEMORY: return "OUT_OF_MEMORY";
+        case Error::INVALID_CHAR: return "INVALID_CHAR";
+        case Error::NOT_FOUND: return "NOT_FOUND";
+        case Error::INVALID_STATE: return "INVALID_STATE";
+        case Error::INVALID_INDEX: return "INVALID_INDEX";
+        case Error::INVALID_ARGUMENT: return "INVALID_ARGUMENT";
+        case Error::TIME_NOT_AVAILABLE: return "TIME_NOT_AVAILABLE";
+        case Error::SLEEP_INTERRUPTED: return "SLEEP_INTERRUPTED";
+        case Error::THREAD_ERROR: return "THREAD_ERROR";
+        case Error::EXISTING_KEY: return "EXISTING_KEY";
+        case Error::CANNOT_OPEN_FILE: return "CANNOT_OPEN_FILE";
+        case Error::END_OF_FILE: return "END_OF_FILE";
+    }
+    return "?";
+}

+ 38 - 0
utils/Error.hpp

@@ -0,0 +1,38 @@
+#ifndef CORE_ERROR_H
+#define CORE_ERROR_H
+
+namespace Core {
+    enum class Error {
+        NONE = 0,
+        NEGATIVE_ARGUMENT,
+        CAPACITY_REACHED,
+        BLOCKED_STDOUT,
+        OUT_OF_MEMORY,
+        INVALID_CHAR,
+        NOT_FOUND,
+        INVALID_STATE,
+        INVALID_INDEX,
+        INVALID_ARGUMENT,
+        TIME_NOT_AVAILABLE,
+        SLEEP_INTERRUPTED,
+        THREAD_ERROR,
+        EXISTING_KEY,
+        CANNOT_OPEN_FILE,
+        END_OF_FILE
+    };
+    const char* getErrorName(Error e);
+
+    inline bool checkError(Error& storage, Error e) {
+        return (storage = e) != Error::NONE;
+    }
+
+#define CORE_RETURN_ERROR(checked)                                             \
+    {                                                                          \
+        Core::Error error = Core::Error::NONE;                                 \
+        if(checkError(error, checked)) [[unlikely]] {                          \
+            return error;                                                      \
+        }                                                                      \
+    }
+}
+
+#endif

+ 1 - 1
utils/HashCode.h

@@ -3,7 +3,7 @@
 
 #include <limits.h>
 
-#include "utils/Utility.h"
+#include "utils/Types.hpp"
 
 namespace Core {
     template<typename H>

+ 87 - 0
utils/Meta.hpp

@@ -0,0 +1,87 @@
+#ifndef CORE_META_H
+#define CORE_META_H
+
+namespace Core {
+    namespace Internal {
+        template<typename T>
+        struct BaseRemovePointer final {
+            using Type = T;
+        };
+
+        template<typename T>
+        struct BaseRemovePointer<T*> final {
+            using Type = T;
+        };
+
+        template<typename T>
+        struct BaseRemoveReference final {
+            using Type = T;
+        };
+
+        template<typename T>
+        struct BaseRemoveReference<T&> final {
+            using Type = T;
+        };
+
+        template<typename T>
+        struct BaseRemoveReference<T&&> final {
+            using Type = T;
+        };
+
+        template<typename A, typename B>
+        struct BaseIsSame final {
+            static constexpr bool value = false;
+        };
+
+        template<typename T>
+        struct BaseIsSame<T, T> final {
+            static constexpr bool value = true;
+        };
+
+        template<bool C, typename A, typename B>
+        struct BaseIf final {
+            using Type = A;
+        };
+
+        template<typename A, typename B>
+        struct BaseIf<false, A, B> final {
+            using Type = B;
+        };
+    }
+
+    template<typename T>
+    using RemovePointer = Internal::BaseRemovePointer<T>::Type;
+
+    template<typename T>
+    using RemoveReference = Internal::BaseRemoveReference<T>::Type;
+
+    template<typename T, typename U>
+    constexpr bool IsSame = Internal::BaseIsSame<T, U>::value;
+
+    template<bool C, typename A, typename B>
+    using If = Internal::BaseIf<C, A, B>::Type;
+
+    template<typename T>
+    constexpr RemoveReference<T>&& move(T&& t) {
+        return static_cast<RemoveReference<T>&&>(t);
+    }
+
+    template<typename T>
+    constexpr T&& forward(RemoveReference<T>& t) {
+        return static_cast<T&&>(t);
+    }
+
+    template<typename T>
+    constexpr T&& forward(RemoveReference<T>&& t) {
+        return static_cast<T&&>(t);
+    }
+
+    template<typename T>
+    void swap(T& a, T& b) {
+        T tmp = Core::move(a);
+        a = Core::move(b);
+        b = Core::move(tmp);
+    }
+}
+
+#endif

+ 39 - 0
utils/New.cpp

@@ -0,0 +1,39 @@
+#include "utils/New.hpp"
+
+#include <stdlib.h>
+
+void* operator new(size_t bytes) noexcept {
+    return malloc(bytes);
+}
+
+void* operator new[](size_t bytes) noexcept {
+    return malloc(bytes);
+}
+
+void operator delete(void* p) noexcept {
+    free(p);
+}
+
+void operator delete[](void* p) noexcept {
+    free(p);
+}
+
+void operator delete(void* p, size_t bytes) noexcept {
+    (void)bytes;
+    free(p);
+}
+
+void operator delete[](void* p, size_t bytes) noexcept {
+    (void)bytes;
+    free(p);
+}
+
+void* operator new(size_t bytes, void* p) noexcept {
+    (void)bytes;
+    return p;
+}
+
+/*void* operator new[](size_t bytes, void* p) noexcept {
+    (void)bytes;
+    return p;
+}*/

+ 15 - 0
utils/New.hpp

@@ -0,0 +1,15 @@
+#ifndef CORE_NEW_H
+#define CORE_NEW_H
+
+#include <stddef.h>
+
+void* operator new(size_t bytes) noexcept;
+void* operator new[](size_t bytes) noexcept;
+void operator delete(void* p) noexcept;
+void operator delete[](void* p) noexcept;
+void operator delete(void* p, size_t bytes) noexcept;
+void operator delete[](void* p, size_t bytes) noexcept;
+void* operator new(size_t bytes, void* p) noexcept;
+// void* operator new[](size_t bytes, void* p) noexcept;
+
+#endif

+ 1 - 1
utils/Random.h

@@ -1,7 +1,7 @@
 #ifndef CORE_RANDOM_H
 #define CORE_RANDOM_H
 
-#include "utils/Utility.h"
+#include "utils/Types.hpp"
 
 namespace Core {
     struct Random final {

+ 16 - 0
utils/Types.hpp

@@ -0,0 +1,16 @@
+#ifndef CORE_TYPES_H
+#define CORE_TYPES_H
+
+#include <stdint.h>
+
+using i64 = int64_t;
+using i32 = int32_t;
+using i16 = int16_t;
+using i8 = int8_t;
+using u64 = uint64_t;
+using u32 = uint32_t;
+using u16 = uint16_t;
+using u8 = uint8_t;
+using c32 = char32_t;
+
+#endif

+ 1 - 60
utils/Utility.cpp

@@ -1,4 +1,4 @@
-#include "utils/Utility.h"
+#include "utils/Utility.hpp"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -7,65 +7,6 @@
 static Core::ExitHandler exitHandler = nullptr;
 static void* exitData = nullptr;
 
-const char* Core::getErrorName(Error e) {
-    switch(e) {
-        case Error::NONE: return "NONE";
-        case Error::NEGATIVE_ARGUMENT: return "NEGATIVE_ARGUMENT";
-        case Error::CAPACITY_REACHED: return "CAPACITY_REACHED";
-        case Error::BLOCKED_STDOUT: return "BLOCKED_STDOUT";
-        case Error::OUT_OF_MEMORY: return "OUT_OF_MEMORY";
-        case Error::INVALID_CHAR: return "INVALID_CHAR";
-        case Error::NOT_FOUND: return "NOT_FOUND";
-        case Error::INVALID_STATE: return "INVALID_STATE";
-        case Error::INVALID_INDEX: return "INVALID_INDEX";
-        case Error::INVALID_ARGUMENT: return "INVALID_ARGUMENT";
-        case Error::TIME_NOT_AVAILABLE: return "TIME_NOT_AVAILABLE";
-        case Error::SLEEP_INTERRUPTED: return "SLEEP_INTERRUPTED";
-        case Error::THREAD_ERROR: return "THREAD_ERROR";
-        case Error::INVALID_ID: return "INVALID_ID";
-        case Error::EXISTING_KEY: return "EXISTING_KEY";
-        case Error::CANNOT_OPEN_FILE: return "CANNOT_OPEN_FILE";
-        case Error::END_OF_FILE: return "END_OF_FILE";
-    }
-    return "?";
-}
-
-void* operator new(size_t bytes) noexcept {
-    return malloc(bytes);
-}
-
-void* operator new[](size_t bytes) noexcept {
-    return malloc(bytes);
-}
-
-void operator delete(void* p) noexcept {
-    free(p);
-}
-
-void operator delete[](void* p) noexcept {
-    free(p);
-}
-
-void operator delete(void* p, size_t bytes) noexcept {
-    (void)bytes;
-    free(p);
-}
-
-void operator delete[](void* p, size_t bytes) noexcept {
-    (void)bytes;
-    free(p);
-}
-
-void* operator new(size_t bytes, void* p) noexcept {
-    (void)bytes;
-    return p;
-}
-
-/*void* operator new[](size_t bytes, void* p) noexcept {
-    (void)bytes;
-    return p;
-}*/
-
 void Core::exitWithHandler(const char* file, int line, int value) {
     if(value != 0) {
         printf("\33[1;31mExit from %s:%d with value %d\33[39;49m\n", file, line,

+ 0 - 222
utils/Utility.h

@@ -1,222 +0,0 @@
-#ifndef CORE_UTILITY_H
-#define CORE_UTILITY_H
-
-#include "utils/Check.h"
-
-#define CORE_SIZE(t) static_cast<int>(sizeof(t))
-
-namespace Core {
-    enum class Error {
-        NONE = 0,
-        NEGATIVE_ARGUMENT,
-        CAPACITY_REACHED,
-        BLOCKED_STDOUT,
-        OUT_OF_MEMORY,
-        INVALID_CHAR,
-        NOT_FOUND,
-        INVALID_STATE,
-        INVALID_INDEX,
-        INVALID_ARGUMENT,
-        TIME_NOT_AVAILABLE,
-        SLEEP_INTERRUPTED,
-        THREAD_ERROR,
-        INVALID_ID,
-        EXISTING_KEY,
-        CANNOT_OPEN_FILE,
-        END_OF_FILE
-    };
-    const char* getErrorName(Error e);
-
-    inline bool checkError(Error& storage, Error e) {
-        return (storage = e) != Error::NONE;
-    }
-
-#define CORE_RETURN_ERROR(checked)                                             \
-    {                                                                          \
-        Core::Error error = Core::Error::NONE;                                 \
-        if(checkError(error, checked)) [[unlikely]] {                          \
-            return error;                                                      \
-        }                                                                      \
-    }
-
-    namespace Internal {
-        template<typename T>
-        struct BaseRemovePointer final {
-            using Type = T;
-        };
-
-        template<typename T>
-        struct BaseRemovePointer<T*> final {
-            using Type = T;
-        };
-
-        template<typename T>
-        struct BaseRemoveReference final {
-            using Type = T;
-        };
-
-        template<typename T>
-        struct BaseRemoveReference<T&> final {
-            using Type = T;
-        };
-
-        template<typename T>
-        struct BaseRemoveReference<T&&> final {
-            using Type = T;
-        };
-
-        template<typename A, typename B>
-        struct BaseIsSame final {
-            static constexpr bool value = false;
-        };
-
-        template<typename T>
-        struct BaseIsSame<T, T> final {
-            static constexpr bool value = true;
-        };
-
-        template<bool C, typename A, typename B>
-        struct BaseIf final {
-            using Type = A;
-        };
-
-        template<typename A, typename B>
-        struct BaseIf<false, A, B> final {
-            using Type = B;
-        };
-    }
-
-    template<typename T>
-    using RemovePointer = Internal::BaseRemovePointer<T>::Type;
-
-    template<typename T>
-    using RemoveReference = Internal::BaseRemoveReference<T>::Type;
-
-    template<typename T, typename U>
-    constexpr bool IsSame = Internal::BaseIsSame<T, U>::value;
-
-    template<bool C, typename A, typename B>
-    using If = Internal::BaseIf<C, A, B>::Type;
-
-    namespace Internal {
-        template<int N, typename T1, typename T2, typename T3, typename T4,
-                 typename T5>
-        using SelectType =
-            If<sizeof(T1) == N, T1,
-               If<sizeof(T2) == N, T2,
-                  If<sizeof(T3) == N, T3, If<sizeof(T4) == N, T4, T5>>>>;
-
-        template<int N>
-        using SelectSigned =
-            SelectType<N, signed char, signed short, signed int, signed long,
-                       signed long long>;
-
-        template<int N>
-        using SelectUnsigned =
-            SelectType<N, unsigned char, unsigned short, unsigned int,
-                       unsigned long, unsigned long long>;
-    }
-
-    template<typename T>
-    constexpr RemoveReference<T>&& move(T&& t) {
-        return static_cast<RemoveReference<T>&&>(t);
-    }
-
-    template<typename T>
-    constexpr T&& forward(RemoveReference<T>& t) {
-        return static_cast<T&&>(t);
-    }
-
-    template<typename T>
-    constexpr T&& forward(RemoveReference<T>&& t) {
-        return static_cast<T&&>(t);
-    }
-
-    template<typename T>
-    void swap(T& a, T& b) {
-        T tmp = Core::move(a);
-        a = Core::move(b);
-        b = Core::move(tmp);
-    }
-
-    template<typename T>
-    int popCount(const T& t) {
-        static constexpr int map[16] = {0, 1, 1, 2, 1, 2, 2, 3,
-                                        1, 2, 2, 3, 2, 3, 3, 4};
-        int sum = 0;
-        for(int i = 0; i < CORE_SIZE(T) * 8; i += 4) {
-            sum += map[(t >> i) & 0xF];
-        }
-        return sum;
-    }
-
-    using ExitHandler = void (*)(int, void*);
-    void exitWithHandler(const char* file, int line, int value);
-    void setExitHandler(ExitHandler eh, void* data);
-#define CORE_EXIT(exitValue)                                                   \
-    Core::exitWithHandler(__FILE__, __LINE__, exitValue)
-
-    check_return Error toString(signed short s, char* buffer, int size);
-    check_return Error toString(unsigned short s, char* buffer, int size);
-    check_return Error toString(signed int i, char* buffer, int size);
-    check_return Error toString(unsigned int i, char* buffer, int size);
-    check_return Error toString(signed long l, char* buffer, int size);
-    check_return Error toString(unsigned long l, char* buffer, int size);
-    check_return Error toString(signed long long ll, char* buffer, int size);
-    check_return Error toString(unsigned long long ll, char* buffer, int size);
-    check_return Error toString(float f, char* buffer, int size);
-    check_return Error toString(double d, char* buffer, int size);
-    check_return Error toString(long double ld, char* buffer, int size);
-
-    check_return Error putChar(int c);
-
-    void memorySet(void* p, int c, int n);
-    void memoryCopy(void* dest, const void* src, int n);
-    bool memoryCompare(const void* a, const void* b, int n);
-    check_return Error reallocate(char*& p, int n);
-    void free(void* p);
-
-    const char* getFileName(const char* path);
-
-    template<typename T>
-    constexpr int stringLength(const T* c) {
-        int i = 0;
-        while(*c != '\0') {
-            c++;
-            i++;
-        }
-        return i;
-    }
-}
-
-using i64 = Core::Internal::SelectSigned<8>;
-using i32 = Core::Internal::SelectSigned<4>;
-using i16 = Core::Internal::SelectSigned<2>;
-using i8 = Core::Internal::SelectSigned<1>;
-using u64 = Core::Internal::SelectUnsigned<8>;
-using u32 = Core::Internal::SelectUnsigned<4>;
-using u16 = Core::Internal::SelectUnsigned<2>;
-using u8 = Core::Internal::SelectUnsigned<1>;
-using c32 = char32_t;
-
-static_assert(sizeof(i64) == 8, "invalid size");
-static_assert(sizeof(i32) == 4, "invalid size");
-static_assert(sizeof(i16) == 2, "invalid size");
-static_assert(sizeof(i8) == 1, "invalid size");
-static_assert(sizeof(u64) == 8, "invalid size");
-static_assert(sizeof(u32) == 4, "invalid size");
-static_assert(sizeof(u16) == 2, "invalid size");
-static_assert(sizeof(u8) == 1, "invalid size");
-
-using size_t = u64;
-
-void* operator new(size_t bytes) noexcept;
-void* operator new[](size_t bytes) noexcept;
-void operator delete(void* p) noexcept;
-void operator delete[](void* p) noexcept;
-void operator delete(void* p, size_t bytes) noexcept;
-void operator delete[](void* p, size_t bytes) noexcept;
-void* operator new(size_t bytes, void* p) noexcept;
-// void* operator new[](size_t bytes, void* p) noexcept;
-
-#endif

+ 60 - 0
utils/Utility.hpp

@@ -0,0 +1,60 @@
+#ifndef CORE_UTILITY_H
+#define CORE_UTILITY_H
+
+#include "utils/Check.hpp"
+#include "utils/Error.hpp"
+
+#define CORE_SIZE(t) static_cast<int>(sizeof(t))
+
+namespace Core {
+    template<typename T>
+    int popCount(const T& t) {
+        static constexpr int map[16] = {0, 1, 1, 2, 1, 2, 2, 3,
+                                        1, 2, 2, 3, 2, 3, 3, 4};
+        int sum = 0;
+        for(int i = 0; i < CORE_SIZE(T) * 8; i += 4) {
+            sum += map[(t >> i) & 0xF];
+        }
+        return sum;
+    }
+
+    using ExitHandler = void (*)(int, void*);
+    void exitWithHandler(const char* file, int line, int value);
+    void setExitHandler(ExitHandler eh, void* data);
+#define CORE_EXIT(exitValue)                                                   \
+    Core::exitWithHandler(__FILE__, __LINE__, exitValue)
+
+    check_return Error toString(signed short s, char* buffer, int size);
+    check_return Error toString(unsigned short s, char* buffer, int size);
+    check_return Error toString(signed int i, char* buffer, int size);
+    check_return Error toString(unsigned int i, char* buffer, int size);
+    check_return Error toString(signed long l, char* buffer, int size);
+    check_return Error toString(unsigned long l, char* buffer, int size);
+    check_return Error toString(signed long long ll, char* buffer, int size);
+    check_return Error toString(unsigned long long ll, char* buffer, int size);
+    check_return Error toString(float f, char* buffer, int size);
+    check_return Error toString(double d, char* buffer, int size);
+    check_return Error toString(long double ld, char* buffer, int size);
+
+    check_return Error putChar(int c);
+
+    void memorySet(void* p, int c, int n);
+    void memoryCopy(void* dest, const void* src, int n);
+    bool memoryCompare(const void* a, const void* b, int n);
+    check_return Error reallocate(char*& p, int n);
+    void free(void* p);
+
+    const char* getFileName(const char* path);
+
+    template<typename T>
+    constexpr int stringLength(const T* c) {
+        int i = 0;
+        while(*c != '\0') {
+            c++;
+            i++;
+        }
+        return i;
+    }
+}
+
+#endif