Browse Source

No more C++ dependencies

Kajetan Johannes Hammerle 1 year ago
parent
commit
87883a6254

+ 6 - 8
data/ArrayList.h

@@ -1,10 +1,8 @@
 #ifndef ARRAYLIST_H
 #define ARRAYLIST_H
 
-#include <new>
-#include <utility>
-
 #include "utils/StringBuffer.h"
+#include "utils/Utility.h"
 
 template<typename T, int N>
 class ArrayList final {
@@ -26,7 +24,7 @@ public:
     }
 
     ArrayList(ArrayList&& other) : ArrayList() {
-        move(std::move(other));
+        move(Core::move(other));
         other.clear();
     }
 
@@ -45,7 +43,7 @@ public:
     ArrayList& operator=(ArrayList&& other) {
         if(&other != this) {
             clear();
-            move(std::move(other));
+            move(Core::move(other));
             other.clear();
         }
         return *this;
@@ -72,7 +70,7 @@ public:
         if(length >= N) {
             return true;
         }
-        new(begin() + length++) T(std::forward<Args>(args)...);
+        new(begin() + length++) T(Core::forward<Args>(args)...);
         return false;
     }
 
@@ -98,7 +96,7 @@ public:
     void remove(int index) {
         length--;
         if(index != length) {
-            begin()[index] = std::move(begin()[length]);
+            begin()[index] = Core::move(begin()[length]);
         }
         begin()[length].~T();
     }
@@ -125,7 +123,7 @@ private:
 
     void move(ArrayList&& other) {
         for(int i = 0; i < other.length; i++) {
-            add(std::move(other[i]));
+            add(Core::move(other[i]));
         }
     }
 };

+ 5 - 4
data/BitArray.cpp

@@ -1,6 +1,7 @@
 #include "data/BitArray.h"
 
 #include "math/Math.h"
+#include "utils/Utility.h"
 
 static int roundUpDivide(int a, int b) {
     if(a % b == 0) {
@@ -111,7 +112,7 @@ int BitArray::select(int index) const {
     int found = 0;
     int end = getArrayLength(length, bits);
     for(int i = 0; i < end; i++) {
-        int ones = __builtin_popcount(static_cast<unsigned int>(data[i]));
+        int ones = Core::popcount(data[i]);
         found += ones;
         if(found >= index) {
             found -= ones;
@@ -150,7 +151,7 @@ void BitArray::resize(int newLength, int newBits) {
 }
 
 void BitArray::swap(BitArray& other) {
-    std::swap(length, other.length);
-    std::swap(bits, other.bits);
-    std::swap(data, other.data);
+    Core::swap(length, other.length);
+    Core::swap(bits, other.bits);
+    Core::swap(data, other.data);
 }

+ 1 - 1
data/Components.h

@@ -64,7 +64,7 @@ public:
         if(entityToIndex.tryEmplace(e, index)) {
             return;
         }
-        components.add(std::forward<Args>(args)...);
+        components.add(Core::forward<Args>(args)...);
         indexToEntity.add(e);
     }
 

+ 6 - 6
data/HashMap.h

@@ -23,7 +23,7 @@ struct HashMap final {
     private:
         template<typename... Args>
         Node(const K& key_, Args&&... args)
-            : key(key_), value(std::forward<Args>(args)...) {
+            : key(key_), value(Core::forward<Args>(args)...) {
         }
     };
     using Nodes = List<List<Node>>;
@@ -131,7 +131,7 @@ public:
         Hash h = hash(key);
         V* v = searchList(key, h);
         if(v == nullptr) {
-            nodes[static_cast<int>(h)].add(key, std::forward<Args>(args)...);
+            nodes[static_cast<int>(h)].add(key, Core::forward<Args>(args)...);
             elements++;
             return false;
         }
@@ -144,10 +144,10 @@ public:
         Hash h = hash(key);
         V* v = searchList(key, h);
         if(v == nullptr) {
-            nodes[static_cast<int>(h)].add(key, std::forward<VA>(value));
+            nodes[static_cast<int>(h)].add(key, Core::forward<VA>(value));
             elements++;
         } else {
-            *v = std::forward<VA>(value);
+            *v = Core::forward<VA>(value);
         }
         return *this;
     }
@@ -265,10 +265,10 @@ private:
         HashMap<K, V> map(nodes.getLength() * 2);
         for(List<Node>& list : nodes) {
             for(Node& n : list) {
-                map.tryEmplace(n.key, std::move(n.value));
+                map.tryEmplace(n.key, Core::move(n.value));
             }
         }
-        *this = std::move(map);
+        *this = Core::move(map);
     }
 
     const V* searchList(const K& key, Hash h) const {

+ 9 - 11
data/List.h

@@ -1,10 +1,8 @@
 #ifndef LIST_H
 #define LIST_H
 
-#include <new>
-#include <utility>
-
 #include "utils/StringBuffer.h"
+#include "utils/Utility.h"
 
 template<typename T>
 class List final {
@@ -61,7 +59,7 @@ public:
         copy.capacity = n;
         copy.data = allocate(n);
         for(int i = 0; i < length; i++) {
-            copy.add(std::move(data[i]));
+            copy.add(Core::move(data[i]));
         }
         swap(copy);
     }
@@ -74,7 +72,7 @@ public:
         copy.capacity = length;
         copy.data = allocate(length);
         for(int i = 0; i < length; i++) {
-            copy.add(std::move(data[i]));
+            copy.add(Core::move(data[i]));
         }
         swap(copy);
     }
@@ -110,7 +108,7 @@ public:
     template<typename... Args>
     List& add(Args&&... args) {
         ensureCapacity();
-        new(data + length++) T(std::forward<Args>(args)...);
+        new(data + length++) T(Core::forward<Args>(args)...);
         return *this;
     }
 
@@ -140,7 +138,7 @@ public:
     void removeBySwap(int index) {
         length--;
         if(index != length) {
-            data[index] = std::move(data[length]);
+            data[index] = Core::move(data[length]);
         }
         data[length].~T();
     }
@@ -148,7 +146,7 @@ public:
     void remove(int index) {
         length--;
         for(int i = index; i < length; i++) {
-            data[i] = std::move(data[i + 1]);
+            data[i] = Core::move(data[i + 1]);
         }
         data[length].~T();
     }
@@ -179,9 +177,9 @@ private:
     }
 
     void swap(List& other) {
-        std::swap(length, other.length);
-        std::swap(capacity, other.capacity);
-        std::swap(data, other.data);
+        Core::swap(length, other.length);
+        Core::swap(capacity, other.capacity);
+        Core::swap(data, other.data);
     }
 
     void ensureCapacity() {

+ 1 - 1
data/Stack.h

@@ -10,7 +10,7 @@ class Stack final {
 public:
     template<typename... Args>
     Stack& push(Args&&... args) {
-        data.add(std::forward<Args>(args)...);
+        data.add(Core::forward<Args>(args)...);
         return *this;
     }
 

+ 6 - 1
io/ImageReader.cpp

@@ -1,12 +1,17 @@
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wmissing-declarations"
-#pragma GCC diagnostic ignored "-Wpadded"
 #include "libs/lodepng/lodepng.h"
 #pragma GCC diagnostic pop
 
+#include <stdlib.h>
+
 #include "io/ImageReader.h"
 #include "utils/Cleaner.h"
 
+void ImageReader::Image::clean(ColorChannel*& c) {
+    free(c);
+}
+
 static void cleanRawData(ColorChannel*& c) {
     free(c);
 }

+ 1 - 3
io/ImageReader.h

@@ -7,9 +7,7 @@
 
 namespace ImageReader {
     class Image final {
-        static void clean(ColorChannel*& c) {
-            free(c);
-        }
+        static void clean(ColorChannel*& c);
 
     public:
         Image();

+ 1 - 1
math/Math.h

@@ -1,7 +1,7 @@
 #ifndef COREMATH_H
 #define COREMATH_H
 
-#include <cmath>
+#include <math.h>
 
 #ifndef M_PI
 #define M_PI 3.14159265358979323846

+ 20 - 5
meson.build

@@ -25,6 +25,7 @@ src = [
     'utils/Error.cpp',
     'utils/Logger.cpp',
     'utils/Random.cpp',
+    'utils/Utility.cpp',
 ]
 
 src_tests = [
@@ -61,7 +62,7 @@ src_tests = [
 ]
 
 compiler = meson.get_compiler('cpp')
-args = compiler.get_supported_arguments([
+error_args = compiler.get_supported_arguments([
     '-Wcast-align=strict', '-pedantic', '-Wmissing-declarations', '-Wdate-time', 
     '-Winit-self', '-Woverlength-strings', '-Wsign-promo', '-Wnon-virtual-dtor', 
     '-Wconversion', '-Woverloaded-virtual', '-Wdeprecated-enum-enum-conversion', 
@@ -75,9 +76,17 @@ args = compiler.get_supported_arguments([
     '-Wredundant-decls', '-Werror', '-Wsign-conversion', '-Walloca', '-Wshadow',
     '-Winvalid-pch', '-Wdeprecated-copy-dtor', '-Wundef', '-Wdouble-promotion',
     '-Warith-conversion', '-Wextra', '-Wtrivial-auto-var-init', '-Wlogical-op', 
-    '-Wall', '-Wenum-conversion',
+    '-Wall', '-Wenum-conversion'
+])
+compile_args = compiler.get_supported_arguments([
+    '-nostdinc++', '-fno-exceptions', '-fno-rtti', '-fno-threadsafe-statics'
+])
+link_args = compiler.get_supported_arguments([
+    '-nodefaultlibs', '-lc', '-lm'
 ])
 
+add_global_arguments('-DLODEPNG_NO_COMPILE_CPP', language : 'cpp')
+
 cmake = import('cmake')
 glfw_proj = cmake.subproject('glfw')
 glfw_includes = glfw_proj.include_directories('glfw')
@@ -97,14 +106,19 @@ dl_dep = compiler.find_library('dl', required: false)
 
 gamingcore_include = [include_directories('.'), glfw_includes, glew_includes]
 
-lodepng = static_library('lodepng', sources: 'libs/lodepng/lodepng.cpp')
+lodepng = static_library('lodepng', 
+    sources: 'libs/lodepng/lodepng.cpp',
+    cpp_args: compile_args,
+    link_args: link_args)
 lodepng_dep = declare_dependency(link_with: lodepng)
 
 gamingcore = static_library('gamingcore', 
     sources: src,
     include_directories: gamingcore_include,
     dependencies: [thread_dep, glfw_dep, glew_dep, gl_dep, ws2_32_dep, winmm_dep, glu_dep, dl_dep, glu_dep, lodepng_dep],
-    cpp_args: args)
+    cpp_args: error_args + compile_args,
+    link_args: link_args)
+
 gamingcore_dep = declare_dependency(
     include_directories: gamingcore_include,
     link_with: gamingcore)
@@ -112,4 +126,5 @@ gamingcore_dep = declare_dependency(
 executable('tests', 
     sources: src_tests,
     dependencies: gamingcore_dep,
-    cpp_args: args + ['-DLOG_LEVEL=4'])
+    cpp_args: error_args + compile_args + ['-DLOG_LEVEL=4'],
+    link_args: link_args)

+ 12 - 16
rendering/GL.cpp

@@ -1,27 +1,23 @@
 #include "rendering/GL.h"
 
-#include <type_traits>
-
 #include "GL/glew.h"
 #include "data/Array.h"
 #include "utils/Logger.h"
-
-static_assert(std::is_same<GL::Shader, GLuint>::value,
-              "shader has invalid type");
-static_assert(std::is_same<GL::Program, GLuint>::value, "p has invalid type");
-static_assert(std::is_same<char, GLchar>::value, "char has invalid type");
-static_assert(std::is_same<int, GLint>::value, "int has invalid type");
-static_assert(std::is_same<float, GLfloat>::value, "float has invalid type");
-static_assert(std::is_same<GL::Texture, GLuint>::value,
-              "texture has invalid type");
-static_assert(std::is_same<GL::Framebuffer, GLuint>::value,
+#include "utils/Utility.h"
+
+static_assert(Core::IsSame<GL::Shader, GLuint>, "shader has invalid type");
+static_assert(Core::IsSame<GL::Program, GLuint>, "p has invalid type");
+static_assert(Core::IsSame<char, GLchar>, "char has invalid type");
+static_assert(Core::IsSame<int, GLint>, "int has invalid type");
+static_assert(Core::IsSame<float, GLfloat>, "float has invalid type");
+static_assert(Core::IsSame<GL::Texture, GLuint>, "texture has invalid type");
+static_assert(Core::IsSame<GL::Framebuffer, GLuint>,
               "framebuffer has invalid type");
-static_assert(std::is_same<GL::ColorAttachment, GLenum>::value,
+static_assert(Core::IsSame<GL::ColorAttachment, GLenum>,
               "color attachment has invalid type");
-static_assert(std::is_same<GL::VertexArray, GLuint>::value,
+static_assert(Core::IsSame<GL::VertexArray, GLuint>,
               "vertex array has invalid type");
-static_assert(std::is_same<GL::Buffer, GLuint>::value,
-              "buffer has invalid type");
+static_assert(Core::IsSame<GL::Buffer, GLuint>, "buffer has invalid type");
 
 GL::Attribute::Attribute(int count_, int size_, int type_, bool normalized_)
     : count(count_), size(size_), type(type_), normalized(normalized_) {

+ 12 - 6
rendering/Shader.cpp

@@ -1,6 +1,6 @@
 #include "rendering/Shader.h"
 
-#include <fstream>
+#include <stdio.h>
 
 #include "utils/Logger.h"
 
@@ -49,19 +49,25 @@ Error Shader::readAndCompile(const char* path, GL::Shader& s,
 }
 
 Error Shader::readFile(List<char>& code, const char* path) const {
-    std::ifstream in;
-    in.open(path);
-    if(!in.good()) {
-        return {"cannot read file"};
+    FILE* in = fopen(path, "r");
+    if(in == nullptr) {
+        Error e = {"cannot read file: "};
+        e.message.append(path);
+        return e;
     }
     while(true) {
-        int c = in.get();
+        int c = fgetc(in);
         if(c == EOF) {
             break;
         }
         code.add(static_cast<char>(c));
     }
     code.add('\0');
+    if(fclose(in) != 0) {
+        Error e = {"cannot close file: "};
+        e.message.append(path);
+        return e;
+    }
     return {};
 }
 

+ 11 - 7
rendering/Window.cpp

@@ -1,11 +1,10 @@
 #include "rendering/Window.h"
 
-#include <utility>
-
 #include "GL/glew.h"
 #include "GLFW/glfw3.h"
 #include "data/Array.h"
 #include "data/HashMap.h"
+#include "utils/Utility.h"
 
 static GLFWwindow* window = nullptr;
 static Clock fps;
@@ -125,7 +124,7 @@ static void addUnicode(uint32 codepoint) {
     }
     input.add(codepoint);
     for(int i = input.getLength() - 1; i > inputCursor; i--) {
-        std::swap(input[i], input[i - 1]);
+        Core::swap(input[i], input[i - 1]);
     }
     inputCursor++;
 }
@@ -244,8 +243,8 @@ bool Window::shouldClose() {
     return glfwWindowShouldClose(window);
 }
 
-Clock::Nanos Window::startFrame() {
-    return fps.update();
+Error Window::startFrame(Clock::Nanos& n) {
+    return fps.update(n);
 }
 
 static bool searchForGamepad() {
@@ -294,11 +293,16 @@ void Window::endFrame() {
     }
 }
 
-void Window::tick() {
-    tps.update();
+Error Window::tick() {
+    Clock::Nanos n = 0;
+    Error e = tps.update(n);
+    if(e.has()) {
+        return e;
+    }
     for(Button& b : buttons) {
         b.tick();
     }
+    return Error();
 }
 
 void Window::postTick() {

+ 14 - 5
rendering/Window.h

@@ -41,25 +41,34 @@ namespace Window {
     void show();
     bool shouldClose();
 
-    Clock::Nanos startFrame();
+    Error startFrame(Clock::Nanos& n);
     void endFrame();
-    void tick();
+    Error tick();
     void postTick();
 
     template<ShouldRun SR, Tick T, Render R>
-    void run(Clock::Nanos nanosPerTick) {
+    Error run(Clock::Nanos nanosPerTick) {
         Clock::Nanos lag = 0;
         while(SR()) {
-            lag += startFrame();
+            Clock::Nanos passedTime = 0;
+            Error e = startFrame(passedTime);
+            if(e.has()) {
+                return e;
+            }
+            lag += passedTime;
             while(lag >= nanosPerTick) {
                 lag -= nanosPerTick;
-                tick();
+                e = tick();
+                if(e.has()) {
+                    return e;
+                }
                 T();
                 postTick();
             }
             R(static_cast<float>(lag) / static_cast<float>(nanosPerTick));
             endFrame();
         }
+        return Error();
     }
 
     namespace Input {

+ 3 - 2
tests/ArrayListTests.cpp

@@ -1,4 +1,5 @@
 #include "tests/ArrayListTests.h"
+
 #include "data/ArrayList.h"
 #include "tests/Test.h"
 #include "utils/StringBuffer.h"
@@ -89,7 +90,7 @@ static void testMove(Test& test) {
     list.add(2);
     list.add(3);
 
-    IntList move(std::move(list));
+    IntList move(Core::move(list));
     test.checkEqual(0, list.getLength(), "moved has length 0");
     test.checkEqual(3, move.getLength(), "moved passes length");
     test.checkEqual(1, move[0], "moved passes values");
@@ -104,7 +105,7 @@ static void testMoveAssignment(Test& test) {
     list.add(3);
 
     IntList move;
-    move = std::move(list);
+    move = Core::move(list);
     test.checkEqual(0, list.getLength(), "assignment moved has length 0");
     test.checkEqual(3, move.getLength(), "assignment moved passes length");
     test.checkEqual(1, move[0], "assignment moved passes values");

+ 4 - 2
tests/BufferTests.cpp

@@ -1,6 +1,8 @@
 #include "tests/BufferTests.h"
+
 #include "tests/Test.h"
 #include "utils/Buffer.h"
+#include "utils/Utility.h"
 
 static constexpr int SIZE_TYPES =
     sizeof(int) + sizeof(long) + sizeof(float) + sizeof(double);
@@ -42,7 +44,7 @@ static void testMoveConstruct(Test& test) {
         buffer.add(5.0f);
         buffer.add(5.0);
     }
-    Buffer buffer2(std::move(buffer));
+    Buffer buffer2(Core::move(buffer));
 
     test.checkEqual(0, buffer.getLength(), "move");
     test.checkEqual(SIZE_TYPES * 10, buffer2.getLength(), "move");
@@ -57,7 +59,7 @@ static void testMove(Test& test) {
         buffer.add(5.0);
     }
     Buffer buffer2(3);
-    buffer2 = std::move(buffer);
+    buffer2 = Core::move(buffer);
 
     test.checkEqual(0, buffer.getLength(), "move");
     test.checkEqual(SIZE_TYPES * 10, buffer2.getLength(), "move");

+ 34 - 17
tests/ClockTests.cpp

@@ -1,40 +1,57 @@
 #include "tests/ClockTests.h"
+
 #include "tests/Test.h"
 #include "utils/Clock.h"
 
 static void testUpdate(Test& test) {
     Clock c;
-    Clock::Nanos n1 = c.update();
-    Clock::Nanos n2 = c.update();
-    Clock::Nanos n3 = c.update();
-    Clock::Nanos n4 = c.update();
-    test.checkEqual(true, n1 > 0, "time measurement is positive 1");
-    test.checkEqual(true, n2 > 0, "time measurement is positive 2");
-    test.checkEqual(true, n3 > 0, "time measurement is positive 3");
-    test.checkEqual(true, n4 > 0, "time measurement is positive 4");
+    Clock::Nanos n1 = 0;
+    Clock::Nanos n2 = 0;
+    Clock::Nanos n3 = 0;
+    Clock::Nanos n4 = 0;
+    Error e1 = c.update(n1);
+    Error e2 = c.update(n2);
+    Error e3 = c.update(n3);
+    Error e4 = c.update(n4);
+    test.checkFalse(e1.has(), "time measurement worked 1");
+    test.checkFalse(e2.has(), "time measurement worked 2");
+    test.checkFalse(e3.has(), "time measurement worked 3");
+    test.checkFalse(e4.has(), "time measurement worked 4");
+    test.checkTrue(n1 == 0, "time measurement is 0 the first time");
+    test.checkTrue(n2 > 0, "time measurement is positive 2");
+    test.checkTrue(n3 > 0, "time measurement is positive 3");
+    test.checkTrue(n4 > 0, "time measurement is positive 4");
 }
 
 static void testUpdatesPerSecond(Test& test) {
     Clock c;
     for(int i = 0; i < 1000; i++) {
-        c.update();
+        Clock::Nanos n = 0;
+        Error e = c.update(n);
+        test.checkFalse(e.has(), "time measurement worked per second");
     }
-    test.checkEqual(true, c.getUpdatesPerSecond() > 0.0f, "updates per second are a positive");
+    test.checkTrue(c.getUpdatesPerSecond() > 0.0f,
+                   "updates per second are a positive");
 }
 
-static void testWait(Test& test) {
-    const Clock::Nanos wait = 50'000'000;
+static void testWait(Test& test, Clock::Nanos wait) {
     Clock c;
-    c.update();
-    c.wait(wait);
-    Clock::Nanos n2 = c.update();
-    test.checkEqual(true, n2 >= wait, "wait passes time");
+    Clock::Nanos n = 0;
+    Error e = c.update(n);
+    test.checkFalse(e.has(), "time measurement worked for wait 1");
+    test.checkFalse(c.wait(wait).has(), "wait worked");
+    Clock::Nanos n2 = 0;
+    e = c.update(n2);
+    test.checkFalse(e.has(), "time measurement worked for wait 2");
+    test.checkEqual(true, n2 >= wait && n2 <= wait * 11 / 10,
+                    "wait passes time but not too much");
 }
 
 void ClockTests::test() {
     Test test("Clock");
     testUpdate(test);
     testUpdatesPerSecond(test);
-    testWait(test);
+    testWait(test, 50'000'000);
+    testWait(test, 1'300'000'000);
     test.finalize();
 }

+ 3 - 2
tests/HashMapTests.cpp

@@ -3,6 +3,7 @@
 #include "data/HashMap.h"
 #include "tests/Test.h"
 #include "utils/StringBuffer.h"
+#include "utils/Utility.h"
 
 typedef HashMap<int, int> IntMap;
 typedef StringBuffer<50> String;
@@ -176,7 +177,7 @@ static void testCopyAssignment(Test& test) {
 static void testMove(Test& test) {
     IntMap map;
     map.add(1, 3).add(2, 4).add(3, 5);
-    IntMap move(std::move(map));
+    IntMap move(Core::move(map));
 
     int* a = move.search(1);
     int* b = move.search(2);
@@ -198,7 +199,7 @@ static void testMoveAssignment(Test& test) {
     map.add(1, 3).add(2, 4).add(3, 5);
 
     IntMap move;
-    move = std::move(map);
+    move = Core::move(map);
 
     int* a = move.search(1);
     int* b = move.search(2);

+ 4 - 2
tests/ListTests.cpp

@@ -1,7 +1,9 @@
 #include "tests/ListTests.h"
+
 #include "data/List.h"
 #include "tests/Test.h"
 #include "utils/StringBuffer.h"
+#include "utils/Utility.h"
 
 typedef List<int> IntList;
 typedef StringBuffer<50> String;
@@ -88,7 +90,7 @@ static void testMove(Test& test) {
     IntList list;
     list.add(1).add(2).add(3);
 
-    IntList move(std::move(list));
+    IntList move(Core::move(list));
     test.checkEqual(0, list.getLength(), "moved has length 0");
     test.checkEqual(3, move.getLength(), "moved passes length");
     test.checkEqual(1, move[0], "moved passes values");
@@ -101,7 +103,7 @@ static void testMoveAssignment(Test& test) {
     list.add(1).add(2).add(3);
 
     IntList move;
-    move = std::move(list);
+    move = Core::move(list);
     test.checkEqual(0, list.getLength(), "assignment moved has length 0");
     test.checkEqual(3, move.getLength(), "assignment moved passes length");
     test.checkEqual(1, move[0], "assignment moved passes values");

+ 0 - 3
tests/NetworkTests.cpp

@@ -1,7 +1,5 @@
 #include "tests/NetworkTests.h"
 
-#include <iostream>
-
 #include "network/Client.h"
 #include "network/Server.h"
 #include "tests/Test.h"
@@ -9,7 +7,6 @@
 static bool checkError(Test& test, const Error e, const char* msg) {
     if(e.has()) {
         test.checkFalse(true, msg);
-        std::cout << "Error: " << e.message << "\n";
         return true;
     }
     return false;

+ 3 - 1
tests/UniquePointerTests.cpp

@@ -1,6 +1,8 @@
 #include "tests/UniquePointerTests.h"
+
 #include "tests/Test.h"
 #include "utils/UniquePointer.h"
+#include "utils/Utility.h"
 
 struct B {
     static int instances;
@@ -29,7 +31,7 @@ static void testMoveDestroys(Test& test) {
         UniquePointer<B> p1(new B());
         UniquePointer<B> p2(new B());
         test.checkEqual(2, B::instances, "two instances");
-        p1 = std::move(p2);
+        p1 = Core::move(p2);
         test.checkEqual(1, B::instances, "one after move");
     }
     test.checkEqual(0, B::instances,

+ 7 - 6
utils/Buffer.cpp

@@ -1,8 +1,9 @@
 #include "utils/Buffer.h"
 
-#include <cstdlib>
-#include <cstring>
-#include <utility>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils/Utility.h"
 
 Buffer::Buffer(int initialSize)
     : length(0), capacity(initialSize <= 0 ? 1 : initialSize),
@@ -48,9 +49,9 @@ Buffer::operator const char*() const {
 }
 
 void Buffer::swap(Buffer& other) {
-    std::swap(length, other.length);
-    std::swap(capacity, other.capacity);
-    std::swap(buffer, other.buffer);
+    Core::swap(length, other.length);
+    Core::swap(capacity, other.capacity);
+    Core::swap(buffer, other.buffer);
 }
 
 void Buffer::clear() {

+ 3 - 1
utils/Check.h

@@ -1,7 +1,9 @@
 #ifndef CHECK_H
 #define CHECK_H
 
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 202300L
+#if defined(__cplusplus) && __cplusplus > 201700L
+#define check_return [[nodiscard]]
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 202300L
 #define check_return [[nodiscard]]
 #elif defined(__GNUC__)
 #define check_return __attribute__((warn_unused_result))

+ 31 - 12
utils/Clock.cpp

@@ -1,31 +1,50 @@
 #include "utils/Clock.h"
 
-#include <chrono>
-#include <thread>
+#include <threads.h>
+#include <time.h>
 
-Clock::Clock() : index(0), last(getNanos()), sum(0), time(0) {
+Clock::Clock() : index(0), last(0), sum(0), time(0) {
 }
 
-Clock::Nanos Clock::update() {
+Error Clock::update(Clock::Nanos& n) {
+    Nanos current = 0;
+    Error e = getNanos(current);
+    if(e.has()) {
+        return e;
+    } else if(last == 0) {
+        last = current;
+        n = 0;
+        return Error();
+    }
     index = (index + 1) & (LENGTH - 1);
-    Nanos current = getNanos();
     sum -= time[index];
     time[index] = current - last;
     sum += time[index];
     last = current;
-    return time[index];
+    n = time[index];
+    return Error();
 }
 
 float Clock::getUpdatesPerSecond() const {
     return (LENGTH * 1000000000.0f) / static_cast<float>(sum);
 }
 
-Clock::Nanos Clock::getNanos() const {
-    return std::chrono::duration_cast<std::chrono::nanoseconds>(
-               std::chrono::high_resolution_clock::now().time_since_epoch())
-        .count();
+Error Clock::getNanos(Clock::Nanos& n) {
+    struct timespec ts;
+    if(timespec_get(&ts, TIME_UTC) == 0) {
+        return {"Could not get time"};
+    }
+    n = static_cast<Clock::Nanos>(ts.tv_sec) * 1'000'000'000L +
+        static_cast<Clock::Nanos>(ts.tv_nsec);
+    return Error();
 }
 
-void Clock::wait(Nanos nanos) const {
-    std::this_thread::sleep_for(std::chrono::nanoseconds(nanos));
+Error Clock::wait(Nanos nanos) const {
+    struct timespec t;
+    t.tv_nsec = nanos % 1'000'000'000;
+    t.tv_sec = nanos / 1'000'000'000;
+    if(thrd_sleep(&t, nullptr) == 0) {
+        return Error();
+    }
+    return {"Sleep was interrupted"};
 }

+ 7 - 6
utils/Clock.h

@@ -2,6 +2,8 @@
 #define CLOCK_H
 
 #include "data/Array.h"
+#include "utils/Check.h"
+#include "utils/Error.h"
 #include "utils/Types.h"
 
 struct Clock final {
@@ -17,12 +19,11 @@ private:
 
 public:
     Clock();
-    Nanos update();
-    float getUpdatesPerSecond() const;
-    void wait(Nanos nanos) const;
-
-private:
-    Nanos getNanos() const;
+    // the first invocation will always return 0 nanos
+    check_return Error update(Nanos& n);
+    check_return float getUpdatesPerSecond() const;
+    check_return Error wait(Nanos nanos) const;
+    check_return static Error getNanos(Nanos& n);
 };
 
 #endif

+ 17 - 5
utils/Logger.h

@@ -1,7 +1,7 @@
 #ifndef LOGGER_H
 #define LOGGER_H
 
-#include <iostream>
+#include <stdio.h>
 
 namespace Logger {
     enum Level { L_NONE, L_ERROR, L_WARNING, L_INFO, L_DEBUG };
@@ -11,7 +11,10 @@ namespace Logger {
 #if defined(LOG_LEVEL) && LOG_LEVEL >= 1
 #define LOG_ERROR(text)                                                        \
     if(Logger::level >= Logger::Level::L_ERROR) {                              \
-        std::cout << "\33[1;31m[ERROR] " << (text) << "\33[39;49m\n";          \
+        StringBuffer<512> s("\33[1;31m[ERROR] ");                              \
+        s.append(text);                                                        \
+        s.append("\33[39;49m");                                                \
+        s.printLine();                                                         \
     }
 #else
 #define LOG_ERROR(text)
@@ -20,7 +23,10 @@ namespace Logger {
 #if defined(LOG_LEVEL) && LOG_LEVEL >= 2
 #define LOG_WARNING(text)                                                      \
     if(Logger::level >= Logger::Level::L_WARNING) {                            \
-        std::cout << "\33[1;33m[WARNING] " << (text) << "\33[39;49m\n";        \
+        StringBuffer<512> s("\33[1;33m[WARNING] ");                            \
+        s.append(text);                                                        \
+        s.append("\33[39;49m");                                                \
+        s.printLine();                                                         \
     }
 #else
 #define LOG_WARNING(text)
@@ -29,7 +35,10 @@ namespace Logger {
 #if defined(LOG_LEVEL) && LOG_LEVEL >= 3
 #define LOG_INFO(text)                                                         \
     if(Logger::level >= Logger::Level::L_INFO) {                               \
-        std::cout << "\33[1;37m[INFO] " << (text) << "\33[39;49m\n";           \
+        StringBuffer<512> s("\33[1;37m[INFO] ");                               \
+        s.append(text);                                                        \
+        s.append("\33[39;49m");                                                \
+        s.printLine();                                                         \
     }
 #else
 #define LOG_INFO(text)
@@ -38,7 +47,10 @@ namespace Logger {
 #if defined(LOG_LEVEL) && LOG_LEVEL >= 4
 #define LOG_DEBUG(text)                                                        \
     if(Logger::level >= Logger::Level::L_DEBUG) {                              \
-        std::cout << "\33[1;32m[DEBUG] " << (text) << "\33[39;49m\n";          \
+        StringBuffer<512> s("\33[1;32m[DEBUG] ");                              \
+        s.append(text);                                                        \
+        s.append("\33[39;49m");                                                \
+        s.printLine();                                                         \
     }
 #else
 #define LOG_DEBUG(text)

+ 0 - 7
utils/Random.cpp

@@ -1,7 +1,5 @@
 #include "utils/Random.h"
 
-#include <chrono>
-
 Random::Random(Seed seed) : index(0) {
     for(int i = 0; i < N; i++) {
         data[i] = seed;
@@ -9,11 +7,6 @@ Random::Random(Seed seed) : index(0) {
     }
 }
 
-Random::Random()
-    : Random(static_cast<Seed>(
-          std::chrono::steady_clock::now().time_since_epoch().count())) {
-}
-
 void Random::update() {
     static const Seed map[2] = {0, 0x8EBFD028};
     for(int i = 0; i < N - M; i++) {

+ 0 - 1
utils/Random.h

@@ -17,7 +17,6 @@ private:
 
 public:
     Random(Seed seed);
-    Random();
 
     int next();
     int next(int min, int inclusiveMax);

+ 5 - 5
utils/StringBuffer.h

@@ -1,9 +1,9 @@
 #ifndef STRINGBUFFER_H
 #define STRINGBUFFER_H
 
-#include <cstdarg>
-#include <cstring>
-#include <iostream>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
 
 #include "utils/Check.h"
 #include "utils/Types.h"
@@ -185,11 +185,11 @@ public:
     }
 
     void print() const {
-        std::cout << data;
+        fputs(data, stdout);
     }
 
     void printLine() const {
-        std::cout << data << '\n';
+        puts(data);
     }
 
 private:

+ 0 - 2
utils/TypedBuffer.h

@@ -1,8 +1,6 @@
 #ifndef TYPEBUFFER_H
 #define TYPEBUFFER_H
 
-#include <iostream>
-
 #include "data/List.h"
 
 template<typename T>

+ 1 - 1
utils/Types.h

@@ -1,7 +1,7 @@
 #ifndef TYPES_H
 #define TYPES_H
 
-#include <cinttypes>
+#include <inttypes.h>
 
 typedef int64_t int64;
 typedef int32_t int32;

+ 63 - 0
utils/Utility.cpp

@@ -0,0 +1,63 @@
+#include "utils/Utility.h"
+
+int Core::popcount(int i) {
+    int count = 0;
+    static constexpr int map[16] = {
+        0, // 0000
+        1, // 0001
+        1, // 0010
+        2, // 0011
+        1, // 0100
+        2, // 0101
+        2, // 0110
+        3, // 0111
+        1, // 1000
+        2, // 1001
+        2, // 1010
+        3, // 1011
+        2, // 1100
+        3, // 1101
+        3, // 1110
+        4, // 1111
+    };
+    for(int k = 0; k < static_cast<int>(sizeof(int) * 8); k += 4) {
+        count += map[(i >> k) & 0xF];
+    }
+    return count;
+}
+
+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;
+}

+ 74 - 0
utils/Utility.h

@@ -0,0 +1,74 @@
+#ifndef UTILITY_H
+#define UTILITY_H
+
+#include <stdlib.h>
+
+namespace Core {
+    namespace Internal {
+        template<typename T>
+        struct RemoveReferenceBase {
+            typedef T t;
+        };
+
+        template<typename T>
+        struct RemoveReferenceBase<T&> {
+            typedef T t;
+        };
+
+        template<typename T>
+        struct RemoveReferenceBase<T&&> {
+            typedef T t;
+        };
+
+        template<typename A, typename B>
+        struct IsSameBase {
+            static constexpr bool value = false;
+        };
+
+        template<typename T>
+        struct IsSameBase<T, T> {
+            static constexpr bool value = true;
+        };
+    }
+
+    template<typename T>
+    using RemoveReference = typename Internal::RemoveReferenceBase<T>::t;
+
+    template<typename T, typename U>
+    constexpr bool IsSame = Internal::IsSameBase<T, U>::value;
+
+    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);
+    }
+
+    int popcount(int i);
+}
+
+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