diff --git a/Buffer.cc b/Buffer.cc index 25e6c8a..b799c0f 100644 --- a/Buffer.cc +++ b/Buffer.cc @@ -6,6 +6,35 @@ #include "Buffer.h" namespace kge { + + +constexpr size_t defaultCapacity = 32; +constexpr size_t maxReasonableLine = 8192; + + +Buffer::Buffer() + : contents(nullptr), length(0), capacity(0) +{ + this->Resize(defaultCapacity); +} + + +Buffer::Buffer(size_t initialCapacity) + : contents(nullptr), length(0), capacity(0) +{ + this->Resize(initialCapacity); +} + + +Buffer::Buffer(const char *data) + : contents(nullptr), length(0), capacity(0) +{ + size_t datalen = strnlen(data, maxReasonableLine); + + this->Append(data, datalen); +} + + uint8_t * Buffer::Contents() { @@ -15,25 +44,43 @@ Buffer::Contents() bool Buffer::Append(uint8_t *data, size_t datalen) { - return false; + auto resized = false; + auto newCap = this->mustGrow(datalen); + + if (newCap > 0) { + this->Resize(newCap); + resized = true; + } + + memcpy(this->contents + this->length, data, datalen); + this->length += datalen; + return resized; } bool Buffer::Append(uint8_t c) { - return false; + return this->Append(&c, 1); } bool Buffer::Insert(size_t index, uint8_t *data, size_t datalen) { - return false; + auto resized = this->shift(index, datalen); + + if (newCap > 0) { + this->Resize(newCap); + resized = true; + } + + memcpy(this->contents + index, data, datalen); + return resized; } bool Buffer::Insert(size_t index, uint8_t c) { - return false; + return this->Insert(index, &c, 1); } size_t @@ -51,8 +98,14 @@ Buffer::Resize(size_t newCapacity) uint8_t *newContents = new uint8_t[newCapacity]; - memcpy(newContents, this->contents, this->length); - delete this->contents; + if (this->length > 0) { + memcpy(newContents, this->contents, this->length); + } + + if (this->contents != nullptr) { + delete this->contents; + } + this->contents = newContents; this->capacity = newCapacity; } @@ -82,11 +135,44 @@ Buffer::Reclaim() this->capacity = 0; } -bool -Buffer::mustGrow(size_t newLength) +size_t +Buffer::mustGrow(size_t delta) { - return (newLength + this->length) >= this->capacity; + if ((delta + this->length) < this->capacity) { + return 0; + } + + auto newCapacity = delta + this->length; + newCapacity--; + + newCapacity |= newCapacity >> 1; + newCapacity |= newCapacity >> 2; + newCapacity |= newCapacity >> 4; + newCapacity |= newCapacity >> 8; + newCapacity |= newCapacity >> 16; + newCapacity |= newCapacity >> 32; + return newCapacity; } -} // kge \ No newline at end of file +bool +Buffer:shift(size_t offset, size_t delta) +{ + auto resized = false; + auto newCap = this->mustGrow(delta); + + if (newCap > 0) { + this->Resize(newCap); + resized = true; + } + + + for (size_t i = this->length; i >= offset; i++) { + this->contents[i+delta] = this->contents[i]; + } + + return resized; +} + + +} // kge diff --git a/Buffer.h b/Buffer.h index d904ab2..8e6045c 100644 --- a/Buffer.h +++ b/Buffer.h @@ -10,20 +10,33 @@ namespace kge { + class Buffer { public: - uint8_t *Contents(); + Buffer(); + Buffer(size_t); + Buffer(const char *); + + uint8_t *Contents() { return this->contents; } + size_t Size() { return this->size; }; + size_t Capacity() { return this->capacity; } + bool Append(uint8_t *data, size_t datalen); bool Append(uint8_t c); bool Insert(size_t index, uint8_t *data, size_t datalen); bool Insert(size_t index, uint8_t c); - size_t Size(); + + // bool Remove(size_t index, size_t length); + + /* memory management */ void Resize(size_t newCapacity); size_t Trim(); void Clear(); void Reclaim(); + private: - bool mustGrow(size_t newLength); + bool mustGrow(size_t delta); + bool shift(size_t offset, size_t delta); uint8_t *contents; size_t length; diff --git a/BufferTest.cc b/BufferTest.cc new file mode 100644 index 0000000..37359cf --- /dev/null +++ b/BufferTest.cc @@ -0,0 +1,12 @@ +#include + +#include "Buffer.h" + + +int +main() +{ + Buffer buffer("hlo, world"); + + std::cout << buffer.Contents() << std::endl; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ad1dfb..82c6b17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,9 @@ target_include_directories(imgui PUBLIC include_directories(ext/ ${SDL2_INCLUDE_DIRS}) +add_executable(BufferTest BufferTest.cc Buffer.cc) +add_test(BufferTest COMMAND BufferTest) + add_executable(kge kge.cc Buffer.cc