mirror of
https://github.com/thunderbrewhq/squall.git
synced 2025-12-12 02:22:30 +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/Hashkey.hpp"
|
||||||
#include "storm/hash/TSHashObject.hpp"
|
#include "storm/hash/TSHashObject.hpp"
|
||||||
#include "storm/hash/TSHashTable.hpp"
|
#include "storm/hash/TSHashTable.hpp"
|
||||||
|
#include "storm/hash/TSHashTableReuse.hpp"
|
||||||
|
|
||||||
#endif
|
#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;
|
TSGrowableArray<STORM_EXPLICIT_LIST(T, m_linktoslot)> m_slotlistarray;
|
||||||
uint32_t m_slotmask = -1;
|
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
|
// Member functions
|
||||||
~TSHashTable();
|
|
||||||
void Clear();
|
void Clear();
|
||||||
uint32_t ComputeSlot(uint32_t hashval);
|
uint32_t ComputeSlot(uint32_t hashval);
|
||||||
void Destroy();
|
|
||||||
int32_t GetLinkOffset();
|
int32_t GetLinkOffset();
|
||||||
T* Head();
|
T* Head();
|
||||||
void Initialize();
|
void Initialize();
|
||||||
bool Initialized();
|
bool Initialized();
|
||||||
void Insert(T* ptr, uint32_t hashval, const TKey& key);
|
void Insert(T* ptr, uint32_t hashval, const TKey& key);
|
||||||
void InternalClear(int32_t warn);
|
void InternalClear(int32_t warn);
|
||||||
void InternalDelete(T* ptr);
|
|
||||||
void InternalLinkNode(T* ptr, uint32_t hashval);
|
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);
|
T* InternalNewNode(uint32_t, size_t extrabytes, uint32_t flags);
|
||||||
int32_t MonitorFullness(uint32_t slot);
|
int32_t MonitorFullness(uint32_t slot);
|
||||||
T* New(const char* str, size_t extrabytes, uint32_t flags);
|
T* New(const char* str, size_t extrabytes, uint32_t flags);
|
||||||
|
|
@ -49,6 +51,14 @@ void TSHashTable<T, TKey>::Clear() {
|
||||||
this->InternalClear(0);
|
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>
|
template <class T, class TKey>
|
||||||
uint32_t TSHashTable<T, TKey>::ComputeSlot(uint32_t hashval) {
|
uint32_t TSHashTable<T, TKey>::ComputeSlot(uint32_t hashval) {
|
||||||
return hashval & this->m_slotmask;
|
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"
|
#include "test/Test.hpp"
|
||||||
|
|
||||||
struct TestHashObject : TSHashObject<TestHashObject, HASHKEY_STRI> {
|
struct TestHashObject : TSHashObject<TestHashObject, HASHKEY_STRI> {
|
||||||
uint32_t index = 0;
|
uint32_t index = 255;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE("TSHashTable", "[hash]") {
|
TEST_CASE("TSHashTable", "[hash]") {
|
||||||
|
|
@ -34,3 +34,44 @@ TEST_CASE("TSHashTable::Clear", "[hash]") {
|
||||||
REQUIRE(hashTable.Head() == nullptr);
|
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