Kajetan Johannes Hammerle hace 3 años
padre
commit
c6cd373bae
Se han modificado 5 ficheros con 146 adiciones y 0 borrados
  1. 2 0
      Main.cpp
  2. 60 0
      memory/ObjectPool.h
  3. 1 0
      meson.build
  4. 75 0
      tests/ObjectPoolTests.cpp
  5. 8 0
      tests/ObjectPoolTests.h

+ 2 - 0
Main.cpp

@@ -22,6 +22,7 @@
 #include "tests/BufferTests.h"
 #include "tests/StackAllocatorTests.h"
 #include "tests/TypedBufferTests.h"
+#include "tests/ObjectPoolTests.h"
 #include "wrapper/Framebuffer.h"
 #include "rendering/FileTexture.h"
 
@@ -52,5 +53,6 @@ int main(int argAmount, char** args) {
     BufferTests::test();
     StackAllocatorTests::test();
     TypedBufferTests::test();
+    ObjectPoolTests::test();
     return 0;
 }

+ 60 - 0
memory/ObjectPool.h

@@ -0,0 +1,60 @@
+#ifndef OBJECTPOOL_H
+#define OBJECTPOOL_H
+
+#include "utils/UninitializedArray.h"
+
+template<typename T, int N>
+class ObjectPool {
+    int freeIndex;
+
+    union Node {
+        int next;
+        T t;
+
+        template<typename... Args>
+        Node(Args&&... args) : t(std::forward<Args>(args)...) {
+        }
+
+        ~Node() {
+            t.~T();
+        }
+    };
+
+    UninitializedArray<Node, N> data;
+
+public:
+
+    ObjectPool() : freeIndex(0) {
+        for(int i = 0; i < N - 1; i++) {
+            data[i].next = i + 1;
+        }
+        data[N - 1].next = -1;
+    }
+
+    template<typename... Args>
+    int allocate(Args&&... args) {
+        if(freeIndex == -1) {
+            return -1;
+        }
+        int index = freeIndex;
+        freeIndex = data[index].next;
+        data.init(index, std::forward<Args>(args)...);
+        return index;
+    }
+
+    void free(int p) {
+        data.destroy(p);
+        data[p].next = freeIndex;
+        freeIndex = p;
+    }
+
+    T& operator[](int index) {
+        return data[index].t;
+    }
+
+    const T& operator[](int index) const {
+        return data[index].t;
+    }
+};
+
+#endif

+ 1 - 0
meson.build

@@ -47,6 +47,7 @@ sources = ['Main.cpp',
     'rendering/FileTexture.cpp',
     'memory/StackAllocator.cpp',
     'tests/StackAllocatorTests.cpp',
+    'tests/ObjectPoolTests.cpp',
     'utils/Buffer.cpp']
 
 glewDep = dependency('glew')

+ 75 - 0
tests/ObjectPoolTests.cpp

@@ -0,0 +1,75 @@
+#include "tests/ObjectPoolTests.h"
+#include "tests/Test.h"
+#include "memory/ObjectPool.h"
+
+struct A {
+    static int instances;
+    int a;
+
+    A(int a) : a(a) {
+        instances += a;
+    }
+
+    ~A() {
+        instances -= a;
+    }
+};
+
+int A::instances = 0;
+
+static void testAllocateAndFree(Test& test) {
+    ObjectPool<A, 3> pool;
+    int a = pool.allocate(1);
+    int b = pool.allocate(2);
+    int c = pool.allocate(3);
+    int d = pool.allocate(4);
+    int e = pool.allocate(5);
+    test.checkEqual(0, a, "int pointer allocate 1");
+    test.checkEqual(1, b, "int pointer allocate 2");
+    test.checkEqual(2, c, "int pointer allocate 3");
+    test.checkEqual(-1, d, "int pointer allocate 4");
+    test.checkEqual(-1, e, "int pointer allocate 5");
+    pool.free(a);
+    pool.free(b);
+    pool.free(c);
+    test.checkEqual(0, A::instances, "all destructors are called 1");
+}
+
+static void testAllocateAfterFree(Test& test) {
+    ObjectPool<A, 3> pool;
+    int a = pool.allocate(1);
+    int b = pool.allocate(2);
+    int c = pool.allocate(3);
+    
+    pool.free(b);
+    b = pool.allocate(7);
+    test.checkEqual(1, b, "int pointer allocate after free 1");
+    
+    pool.free(c);
+    c = pool.allocate(9);
+    test.checkEqual(2, c, "int pointer allocate after free 2");
+    
+    pool.free(a);
+    a = pool.allocate(11);
+    test.checkEqual(0, a, "int pointer allocate after free 3");
+    
+    pool.free(a);
+    pool.free(b);
+    b = pool.allocate(23);
+    a = pool.allocate(17);
+    test.checkEqual(0, a, "int pointer allocate after free 4");
+    test.checkEqual(1, b, "int pointer allocate after free 5");
+    test.checkEqual(-1, pool.allocate(50), "int pointer allocate after free 6");
+
+    pool.free(a);
+    pool.free(b);
+    pool.free(c);
+    test.checkEqual(0, A::instances, "all destructors are called 2");
+}
+
+void ObjectPoolTests::test() {
+    Test test("ObjectPool");
+    testAllocateAndFree(test);
+    testAllocateAfterFree(test);
+    test.finalize();
+}

+ 8 - 0
tests/ObjectPoolTests.h

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