From 3d5794ed7cdf9fea8c8baaa8a6bb6cf377e5b7e7 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Fri, 25 Sep 2020 16:50:56 -0500 Subject: [PATCH] feat(array): add growable array template --- storm/Array.hpp | 1 + storm/array/TSGrowableArray.hpp | 141 ++++++++++++++++++++++++++++++++ test/Array.cpp | 7 ++ 3 files changed, 149 insertions(+) create mode 100644 storm/array/TSGrowableArray.hpp diff --git a/storm/Array.hpp b/storm/Array.hpp index 12b966c..535de1e 100644 --- a/storm/Array.hpp +++ b/storm/Array.hpp @@ -3,5 +3,6 @@ #include "array/TSBaseArray.hpp" #include "array/TSFixedArray.hpp" +#include "array/TSGrowableArray.hpp" #endif diff --git a/storm/array/TSGrowableArray.hpp b/storm/array/TSGrowableArray.hpp new file mode 100644 index 0000000..196fbcb --- /dev/null +++ b/storm/array/TSGrowableArray.hpp @@ -0,0 +1,141 @@ +#ifndef STORM_ARRAY_TS_GROWABLE_ARRAY_HPP +#define STORM_ARRAY_TS_GROWABLE_ARRAY_HPP + +#include "array/TSFixedArray.hpp" +#include +#include +#include +#include + +template +class TSGrowableArray : public TSFixedArray { + public: + uint32_t m_chunk = 0; + + uint32_t Add(uint32_t count, const T* data); + uint32_t Add(uint32_t count, uint32_t incr, const T* data); + uint32_t CalcChunkSize(uint32_t count); + void GrowToFit(uint32_t index, int32_t zero); + T* New(void); + void Reserve(uint32_t count, int32_t round); + uint32_t RoundToChunk(uint32_t count, uint32_t chunk); + void SetCount(uint32_t count); +}; + +template +uint32_t TSGrowableArray::Add(uint32_t count, const T* data) { + this->Reserve(count, 1); + + for (int32_t i = 0; i < count; i++) { + T* element = &this->m_data[this->m_count + i]; + *element = data[i]; + } + + this->m_count += count; + return this->m_count - count; +} + +template +uint32_t TSGrowableArray::Add(uint32_t count, uint32_t incr, const T* data) { + this->Reserve(count, 1); + + const char* dataptr = reinterpret_cast(data); + + for (int32_t i = 0; i < count; i++) { + T* element = &this->m_data[this->m_count + i]; + *element = *reinterpret_cast(dataptr); + dataptr += incr; + } + + this->m_count += count; + return this->m_count - count; +} + +template +uint32_t TSGrowableArray::CalcChunkSize(uint32_t count) { + uint32_t maxChunk = std::max(static_cast(256 / sizeof(T)), 8); + + if (count >= maxChunk) { + this->m_chunk = maxChunk; + return maxChunk; + } + + uint32_t result = count; + + for (uint32_t i = count & (count - 1); i; i &= i - 1) { + result = i; + } + + if (result < 1) { + result = 1; + } + + return result; +} + +template +void TSGrowableArray::GrowToFit(uint32_t index, int32_t zero) { + uint32_t count = this->m_count; + + if (index >= count) { + this->Reserve(index - count + 1, 1); + + if (zero) { + memset(&this->m_data[count], 0, sizeof(T) * (index - count + 1)); + } + + this->m_count = index + 1; + } +} + +template +T* TSGrowableArray::New() { + this->Reserve(1, 1); + void* element = &this->m_data[this->m_count++]; + return new (element) T(); +} + +template +void TSGrowableArray::Reserve(uint32_t count, int32_t round) { + if (count + this->m_count > this->m_alloc) { + if (round) { + uint32_t chunk = this->m_chunk; + + if (!chunk) { + chunk = this->CalcChunkSize(count + this->m_count); + } + + count = this->RoundToChunk(count, chunk); + } + + this->ReallocData(count + this->m_count); + } +} + +template +uint32_t TSGrowableArray::RoundToChunk(uint32_t count, uint32_t chunk) { + if (count % chunk) { + return chunk - count % chunk + count; + } else { + return count; + } +} + +template +void TSGrowableArray::SetCount(uint32_t count) { + if (count > this->m_count) { + // Expand size + this->Reserve(count - this->m_count, 1); + + T* element; + + for (int32_t i = this->m_count; i < count; ++i) { + element = &this->m_data[i]; + new (element) T(); + } + } + + this->m_count = count; +} + +#endif diff --git a/test/Array.cpp b/test/Array.cpp index 0a65a56..9d3e8f4 100644 --- a/test/Array.cpp +++ b/test/Array.cpp @@ -14,3 +14,10 @@ TEST_CASE("TSFixedArray", "[list]") { REQUIRE(array.Count() == 0); } } + +TEST_CASE("TSGrowableArray", "[list]") { + SECTION("constructs correctly") { + TSGrowableArray array; + REQUIRE(array.Count() == 0); + } +}