squall/storm/array/TSGrowableArray.hpp

142 lines
3.3 KiB
C++
Raw Normal View History

#ifndef STORM_ARRAY_TS_GROWABLE_ARRAY_HPP
#define STORM_ARRAY_TS_GROWABLE_ARRAY_HPP
2020-11-01 17:45:45 -06:00
#include "storm/array/TSFixedArray.hpp"
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <new>
template <class T>
class TSGrowableArray : public TSFixedArray<T> {
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 <class T>
uint32_t TSGrowableArray<T>::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 <class T>
uint32_t TSGrowableArray<T>::Add(uint32_t count, uint32_t incr, const T* data) {
this->Reserve(count, 1);
const char* dataptr = reinterpret_cast<const char*>(data);
for (int32_t i = 0; i < count; i++) {
T* element = &this->m_data[this->m_count + i];
*element = *reinterpret_cast<const T*>(dataptr);
dataptr += incr;
}
this->m_count += count;
return this->m_count - count;
}
template <class T>
uint32_t TSGrowableArray<T>::CalcChunkSize(uint32_t count) {
uint32_t maxChunk = std::max(static_cast<int32_t>(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 <class T>
void TSGrowableArray<T>::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 <class T>
T* TSGrowableArray<T>::New() {
this->Reserve(1, 1);
void* element = &this->m_data[this->m_count++];
return new (element) T();
}
template <class T>
void TSGrowableArray<T>::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 <class T>
uint32_t TSGrowableArray<T>::RoundToChunk(uint32_t count, uint32_t chunk) {
if (count % chunk) {
return chunk - count % chunk + count;
} else {
return count;
}
}
template <class T>
void TSGrowableArray<T>::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