From 1bc5bc0b106f658a64519607dc11b03cf04e93eb Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Mon, 9 Oct 2023 10:24:40 -0700 Subject: [PATCH] Move Buffer from kge. --- Buffer.cc | 180 +++++++++++++++++++++++++++++++++++++++++++++++++ Buffer.h | 48 +++++++++++++ CMakeLists.txt | 4 ++ bufferTest.cc | 16 +++++ 4 files changed, 248 insertions(+) create mode 100644 Buffer.cc create mode 100644 Buffer.h create mode 100644 bufferTest.cc diff --git a/Buffer.cc b/Buffer.cc new file mode 100644 index 0000000..37d43cd --- /dev/null +++ b/Buffer.cc @@ -0,0 +1,180 @@ +// +// Created by kyle on 2023-10-09. +// + +#include +#include +#include "Buffer.h" + +namespace klib { + + +constexpr size_t defaultCapacity = 32; +constexpr size_t maxReasonableLine = 8192; + + +static size_t +nearestPower(size_t x) +{ + if (x == 0) { + return 0; + } + + x--; + + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x |= x >> 32; + + return x; +} + + +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((uint8_t *)data, datalen); +} + + +bool +Buffer::Append(uint8_t *data, size_t datalen) +{ + 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 this->Append(&c, 1); +} + +bool +Buffer::Insert(size_t index, uint8_t *data, size_t datalen) +{ + auto resized = this->shift(index, datalen); + + memcpy(this->contents + index, data, datalen); + return resized; +} + +bool +Buffer::Insert(size_t index, uint8_t c) +{ + return this->Insert(index, &c, 1); +} + + +void +Buffer::Resize(size_t newCapacity) +{ + if (newCapacity < this->length) { + return; + } + + uint8_t *newContents = new uint8_t[newCapacity]; + + if (this->length > 0) { + memcpy(newContents, this->contents, this->length); + } + + if (this->contents != nullptr) { + delete this->contents; + } + + this->contents = newContents; + this->capacity = newCapacity; +} + +size_t +Buffer::Trim() +{ + size_t projectedCapacity = nearestPower(this->length); + + assert(projectedCapacity >= length); + + if (projectedCapacity < this->capacity) { + this->Resize(projectedCapacity); + return this->Capacity(); + } + + return 0; +} + +void +Buffer::Clear() +{ + memset(this->contents, 0, this->length); + this->length = 0; +} + +void +Buffer::Reclaim() +{ + delete this->contents; + this->length = 0; + this->capacity = 0; +} + +size_t +Buffer::mustGrow(size_t delta) +{ + if ((delta + this->length) < this->capacity) { + return 0; + } + + auto newCapacity = delta + this->length; + return nearestPower(newCapacity); +} + + +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; +} + + +} // namespace klib diff --git a/Buffer.h b/Buffer.h new file mode 100644 index 0000000..df379f9 --- /dev/null +++ b/Buffer.h @@ -0,0 +1,48 @@ +// +// Created by kyle on 2023-10-09. +// + +#ifndef KGE_BUFFER_H +#define KGE_BUFFER_H + +#include + + +namespace klib { + + +class Buffer { +public: + Buffer(); + Buffer(size_t); + Buffer(const char *); + + uint8_t *Contents() { return this->contents; } + size_t Size() { return this->length; }; + 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); + + // bool Remove(size_t index, size_t length); + + /* memory management */ + void Resize(size_t newCapacity); + size_t Trim(); + void Clear(); + void Reclaim(); + +private: + size_t mustGrow(size_t delta); + bool shift(size_t offset, size_t delta); + + uint8_t *contents; + size_t length; + size_t capacity; +}; + +} // namespace klib + +#endif //KGE_BUFFER_H diff --git a/CMakeLists.txt b/CMakeLists.txt index 412b972..aea49dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ add_compile_options("-DDESKTOP_BUILD") add_library(klib STATIC Arena.cc + Buffer.cc TLV.cc Dictionary.cc) @@ -25,3 +26,6 @@ target_link_libraries(tlv_test klib) add_executable(dictionary_test dictionaryTest.cc) target_link_libraries(dictionary_test klib) +add_executable(buffer_test bufferTest.cc) +target_link_libraries(buffer_test klib) + diff --git a/bufferTest.cc b/bufferTest.cc new file mode 100644 index 0000000..e075b94 --- /dev/null +++ b/bufferTest.cc @@ -0,0 +1,16 @@ +#include + +#include "Buffer.h" + + +int +main() +{ + klib::Buffer buffer("hlo, world"); + + std::cout << buffer.Contents() << std::endl; + + buffer.Insert(1, (uint8_t *)"el", 2); + + std::cout << buffer.Contents() << std::endl; +}