mirror of
https://github.com/thunderbrewhq/squall.git
synced 2025-12-12 10:32:29 +00:00
feat(hash): add memory recycling hash table
This commit is contained in:
parent
06dbb7d1c8
commit
8a232d34f2
5 changed files with 158 additions and 5 deletions
|
|
@ -4,5 +4,6 @@
|
|||
#include "storm/hash/Hashkey.hpp"
|
||||
#include "storm/hash/TSHashObject.hpp"
|
||||
#include "storm/hash/TSHashTable.hpp"
|
||||
#include "storm/hash/TSHashTableReuse.hpp"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
15
storm/hash/TSHashObjectChunk.hpp
Normal file
15
storm/hash/TSHashObjectChunk.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef STORM_HASH_TS_OBJECT_CHUNK_HPP
|
||||
#define STORM_HASH_TS_OBJECT_CHUNK_HPP
|
||||
|
||||
#include "storm/Array.hpp"
|
||||
#include "storm/List.hpp"
|
||||
|
||||
template <class T, class TKey>
|
||||
class TSHashObjectChunk {
|
||||
public:
|
||||
// Member variables
|
||||
TSGrowableArray<T> m_array;
|
||||
TSLink<TSHashObjectChunk<T, TKey>> m_link;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -14,20 +14,22 @@ class TSHashTable {
|
|||
TSGrowableArray<STORM_EXPLICIT_LIST(T, m_linktoslot)> m_slotlistarray;
|
||||
uint32_t m_slotmask = -1;
|
||||
|
||||
// Virtual member functions
|
||||
virtual void InternalDelete(T* ptr);
|
||||
virtual T* InternalNew(STORM_EXPLICIT_LIST(T, m_linktoslot)* listptr, size_t extrabytes, uint32_t flags);
|
||||
virtual ~TSHashTable();
|
||||
virtual void Destroy();
|
||||
|
||||
// Member functions
|
||||
~TSHashTable();
|
||||
void Clear();
|
||||
uint32_t ComputeSlot(uint32_t hashval);
|
||||
void Destroy();
|
||||
int32_t GetLinkOffset();
|
||||
T* Head();
|
||||
void Initialize();
|
||||
bool Initialized();
|
||||
void Insert(T* ptr, uint32_t hashval, const TKey& key);
|
||||
void InternalClear(int32_t warn);
|
||||
void InternalDelete(T* ptr);
|
||||
void InternalLinkNode(T* ptr, uint32_t hashval);
|
||||
T* InternalNew(STORM_EXPLICIT_LIST(T, m_linktoslot)* listptr, size_t extrabytes, uint32_t flags);
|
||||
T* InternalNewNode(uint32_t, size_t extrabytes, uint32_t flags);
|
||||
int32_t MonitorFullness(uint32_t slot);
|
||||
T* New(const char* str, size_t extrabytes, uint32_t flags);
|
||||
|
|
@ -49,6 +51,14 @@ void TSHashTable<T, TKey>::Clear() {
|
|||
this->InternalClear(0);
|
||||
}
|
||||
|
||||
template <class T, class TKey>
|
||||
void TSHashTable<T, TKey>::Destroy() {
|
||||
this->InternalClear(1);
|
||||
this->m_fullnessIndicator = 0;
|
||||
this->m_slotmask = -1;
|
||||
this->m_slotlistarray.Clear();
|
||||
}
|
||||
|
||||
template <class T, class TKey>
|
||||
uint32_t TSHashTable<T, TKey>::ComputeSlot(uint32_t hashval) {
|
||||
return hashval & this->m_slotmask;
|
||||
|
|
|
|||
86
storm/hash/TSHashTableReuse.hpp
Normal file
86
storm/hash/TSHashTableReuse.hpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#ifndef STORM_HASH_TS_HASH_TABLE_REUSE_HPP
|
||||
#define STORM_HASH_TS_HASH_TABLE_REUSE_HPP
|
||||
|
||||
#include "storm/hash/TSHashObjectChunk.hpp"
|
||||
#include "storm/hash/TSHashTable.hpp"
|
||||
#include "storm/Error.hpp"
|
||||
#include "storm/List.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
template <class T, class TKey>
|
||||
class TSHashTableReuse : public TSHashTable<T, TKey> {
|
||||
public:
|
||||
// Virtual member functions
|
||||
virtual ~TSHashTableReuse();
|
||||
virtual void Destroy();
|
||||
|
||||
private:
|
||||
using object_chunk_t = TSHashObjectChunk<T, TKey>;
|
||||
|
||||
// Member variables
|
||||
STORM_EXPLICIT_LIST(T, m_linktoslot) m_reuseList;
|
||||
uint32_t m_chunkSize = 16;
|
||||
STORM_EXPLICIT_LIST(object_chunk_t, m_link) m_chunkList;
|
||||
|
||||
// Virtual member functions
|
||||
virtual void InternalDelete(T* ptr);
|
||||
virtual T* InternalNew(STORM_EXPLICIT_LIST(T, m_linktoslot)* listptr, size_t extrabytes, uint32_t flags);
|
||||
|
||||
// Member functions
|
||||
void Destructor();
|
||||
};
|
||||
|
||||
template <class T, class TKey>
|
||||
TSHashTableReuse<T, TKey>::~TSHashTableReuse() {
|
||||
this->Destructor();
|
||||
}
|
||||
|
||||
template <class T, class TKey>
|
||||
void TSHashTableReuse<T, TKey>::Destroy() {
|
||||
this->Clear();
|
||||
this->Destructor();
|
||||
}
|
||||
|
||||
template <class T, class TKey>
|
||||
void TSHashTableReuse<T, TKey>::Destructor() {
|
||||
this->m_chunkList.Clear();
|
||||
this->m_reuseList.Clear();
|
||||
this->m_chunkSize = 16;
|
||||
}
|
||||
|
||||
template <class T, class TKey>
|
||||
void TSHashTableReuse<T, TKey>::InternalDelete(T* ptr) {
|
||||
this->m_fulllist.UnlinkNode(ptr);
|
||||
this->m_reuseList.LinkNode(ptr, 1, nullptr);
|
||||
}
|
||||
|
||||
template <class T, class TKey>
|
||||
T* TSHashTableReuse<T, TKey>::InternalNew(STORM_EXPLICIT_LIST(T, m_linktoslot)* listptr, size_t extrabytes, uint32_t flags) {
|
||||
STORM_ASSERT(!extrabytes);
|
||||
|
||||
auto node = this->m_reuseList.Head();
|
||||
|
||||
if (!node) {
|
||||
object_chunk_t* chunk;
|
||||
|
||||
while (true) {
|
||||
chunk = this->m_chunkList.Head();
|
||||
|
||||
if (chunk && chunk->m_array.Reserved()) {
|
||||
break;
|
||||
}
|
||||
|
||||
chunk = this->m_chunkList.NewNode(1, 0, 0x0);
|
||||
chunk->m_array.Reserve(this->m_chunkSize, 0);
|
||||
}
|
||||
|
||||
node = chunk->m_array.New();
|
||||
}
|
||||
|
||||
listptr->LinkNode(node, 1, nullptr);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#include "test/Test.hpp"
|
||||
|
||||
struct TestHashObject : TSHashObject<TestHashObject, HASHKEY_STRI> {
|
||||
uint32_t index = 0;
|
||||
uint32_t index = 255;
|
||||
};
|
||||
|
||||
TEST_CASE("TSHashTable", "[hash]") {
|
||||
|
|
@ -34,3 +34,44 @@ TEST_CASE("TSHashTable::Clear", "[hash]") {
|
|||
REQUIRE(hashTable.Head() == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("TSHashTableReuse", "[hash]") {
|
||||
SECTION("constructs correctly") {
|
||||
TSHashTableReuse<TestHashObject, HASHKEY_STRI> hashTable;
|
||||
REQUIRE(hashTable.Head() == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("TSHashTableReuse::New", "[hash]") {
|
||||
SECTION("allocates new object correctly") {
|
||||
TSHashTableReuse<TestHashObject, HASHKEY_STRI> hashTable;
|
||||
auto object = hashTable.New("testKey1", 0, 0x0);
|
||||
|
||||
REQUIRE(object != nullptr);
|
||||
REQUIRE(object->index == 255);
|
||||
}
|
||||
|
||||
SECTION("recycles memory correctly") {
|
||||
TSHashTableReuse<TestHashObject, HASHKEY_STRI> hashTable;
|
||||
|
||||
auto object1 = hashTable.New("testKey1", 0, 0x0);
|
||||
auto object1Ptr = reinterpret_cast<uintptr_t>(object1);
|
||||
|
||||
hashTable.Clear();
|
||||
|
||||
auto object2 = hashTable.New("testKey2", 0, 0x0);
|
||||
auto object2Ptr = reinterpret_cast<uintptr_t>(object2);
|
||||
|
||||
hashTable.Clear();
|
||||
|
||||
auto object3 = hashTable.New("testKey3", 0, 0x0);
|
||||
auto object3Ptr = reinterpret_cast<uintptr_t>(object3);
|
||||
|
||||
REQUIRE(object1Ptr == object2Ptr);
|
||||
REQUIRE(object1Ptr == object3Ptr);
|
||||
REQUIRE(hashTable.Ptr("testKey1") == nullptr);
|
||||
REQUIRE(hashTable.Ptr("testKey2") == nullptr);
|
||||
REQUIRE(hashTable.Ptr("testKey3") != nullptr);
|
||||
REQUIRE(hashTable.Ptr("testKey3")->index == 255);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue