Parcourir la source

buffer uses malloc / realloc as it can prevent many expensive copies and
only primitive bytes are supported

Kajetan Johannes Hammerle il y a 3 ans
Parent
commit
188cc8dab2
3 fichiers modifiés avec 110 ajouts et 18 suppressions
  1. 54 2
      tests/BufferTests.cpp
  2. 42 2
      utils/Buffer.cpp
  3. 14 14
      utils/Buffer.h

+ 54 - 2
tests/BufferTests.cpp

@@ -2,6 +2,9 @@
 #include "tests/Test.h"
 #include "utils/Buffer.h"
 
+static constexpr int SIZE_TYPES =
+    sizeof(int) + sizeof(long) + sizeof(float) + sizeof(double);
+
 static void testAdd(Test& test) {
     Buffer buffer(10);
     for(int i = 0; i < 100000; i++) {
@@ -10,12 +13,61 @@ static void testAdd(Test& test) {
         buffer.add(5.0f);
         buffer.add(5.0);
     }
-    test.checkEqual(static_cast<int> ((sizeof (int) + sizeof (long) + sizeof (float) + sizeof (double)) * 100000),
-            buffer.getLength(), "add increments length");
+    test.checkEqual(SIZE_TYPES * 100000, buffer.getLength(),
+                    "add increments length");
+}
+
+static void testCopy(Test& test) {
+    Buffer buffer(10);
+    for(int i = 0; i < 10; i++) {
+        buffer.add(5);
+        buffer.add(5L);
+        buffer.add(5.0f);
+        buffer.add(5.0);
+    }
+    Buffer buffer2(buffer);
+    Buffer buffer3(2);
+    buffer3 = buffer;
+
+    test.checkEqual(SIZE_TYPES * 10, buffer.getLength(), "copy");
+    test.checkEqual(SIZE_TYPES * 10, buffer2.getLength(), "copy");
+    test.checkEqual(SIZE_TYPES * 10, buffer3.getLength(), "copy");
+}
+
+static void testMoveConstruct(Test& test) {
+    Buffer buffer(10);
+    for(int i = 0; i < 10; i++) {
+        buffer.add(5);
+        buffer.add(5L);
+        buffer.add(5.0f);
+        buffer.add(5.0);
+    }
+    Buffer buffer2(std::move(buffer));
+
+    test.checkEqual(0, buffer.getLength(), "move");
+    test.checkEqual(SIZE_TYPES * 10, buffer2.getLength(), "move");
+}
+
+static void testMove(Test& test) {
+    Buffer buffer(10);
+    for(int i = 0; i < 10; i++) {
+        buffer.add(5);
+        buffer.add(5L);
+        buffer.add(5.0f);
+        buffer.add(5.0);
+    }
+    Buffer buffer2(3);
+    buffer2 = std::move(buffer);
+
+    test.checkEqual(0, buffer.getLength(), "move");
+    test.checkEqual(SIZE_TYPES * 10, buffer2.getLength(), "move");
 }
 
 void BufferTests::test() {
     Test test("Buffer");
     testAdd(test);
+    testCopy(test);
+    testMoveConstruct(test);
+    testMove(test);
     test.finalize();
 }

+ 42 - 2
utils/Buffer.cpp

@@ -1,6 +1,40 @@
+#include <cstdlib>
+#include <cstring>
+
 #include "utils/Buffer.h"
 
-Buffer::Buffer(int n) : data(n) {
+Buffer::Buffer(int initialSize)
+    : length(0), capacity(initialSize),
+      buffer(static_cast<char*>(malloc(initialSize))) {
+}
+
+Buffer::Buffer(const Buffer& other)
+    : length(other.length), capacity(other.capacity),
+      buffer(static_cast<char*>(malloc(capacity))) {
+    memcpy(buffer, other.buffer, length);
+}
+
+Buffer::Buffer(Buffer&& other) : length(0), capacity(0), buffer(nullptr) {
+    swap(other);
+}
+
+Buffer::~Buffer() {
+    free(buffer);
+}
+
+Buffer& Buffer::operator=(Buffer other) {
+    swap(other);
+    return *this;
+}
+
+Buffer& Buffer::add(const void* data, int size) {
+    while(length + size > capacity) {
+        capacity *= 2;
+        buffer = static_cast<char*>(realloc(buffer, capacity));
+    }
+    memcpy(buffer + length, data, size);
+    length += size;
+    return *this;
 }
 
 int Buffer::getLength() const {
@@ -8,5 +42,11 @@ int Buffer::getLength() const {
 }
 
 Buffer::operator const char*() const {
-    return &(data[0]);
+    return buffer;
+}
+
+void Buffer::swap(Buffer& other) {
+    std::swap(length, other.length);
+    std::swap(capacity, other.capacity);
+    std::swap(buffer, other.buffer);
 }

+ 14 - 14
utils/Buffer.h

@@ -1,33 +1,33 @@
 #ifndef BUFFER_H
 #define BUFFER_H
 
-#include <cstring>
-
 #include "memory/StackAllocator.h"
 
 class Buffer {
-    StackAllocator::Array<char> data;
-    int length = 0;
+    int length;
+    int capacity;
+    char* buffer;
 
 public:
-    Buffer(int n);
+    Buffer(int initialSize);
+    Buffer(const Buffer& other);
+    Buffer(Buffer&& other);
+    ~Buffer();
+    Buffer& operator=(Buffer other);
+
+    Buffer& add(const void* data, int size);
 
     template<typename T>
     Buffer& add(const T& t) {
-        int bytes = data.getLength() - length;
-        if(bytes > static_cast<int>(sizeof(T))) {
-            bytes = sizeof(T);
-        } else if(data.grow(data.getLength()) > 0) {
-            return add(t);
-        }
-        memcpy(data + length, &t, bytes);
-        length += bytes;
+        add(&t, sizeof(T));
         return *this;
     }
 
     int getLength() const;
-
     operator const char*() const;
+
+private:
+    void swap(Buffer& other);
 };
 
 #endif