From 3d141195362dc7557d09deab5b25c3647ee4764e Mon Sep 17 00:00:00 2001 From: fallenoak Date: Mon, 27 Mar 2023 17:28:51 -0500 Subject: [PATCH] feat(hash): add synchronized export table template --- storm/Hash.hpp | 1 + storm/hash/TSExportTableSyncReuse.hpp | 87 +++++++++++++++++++++++++++ test/Hash.cpp | 44 ++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 storm/hash/TSExportTableSyncReuse.hpp diff --git a/storm/Hash.hpp b/storm/Hash.hpp index 4bc513b..e0b966f 100644 --- a/storm/Hash.hpp +++ b/storm/Hash.hpp @@ -3,6 +3,7 @@ #include "storm/hash/Hashkey.hpp" #include "storm/hash/TSExportTableSimpleReuse.hpp" +#include "storm/hash/TSExportTableSyncReuse.hpp" #include "storm/hash/TSHashObject.hpp" #include "storm/hash/TSHashTable.hpp" #include "storm/hash/TSHashTableReuse.hpp" diff --git a/storm/hash/TSExportTableSyncReuse.hpp b/storm/hash/TSExportTableSyncReuse.hpp new file mode 100644 index 0000000..21fdb64 --- /dev/null +++ b/storm/hash/TSExportTableSyncReuse.hpp @@ -0,0 +1,87 @@ +#ifndef STORM_HASH_TS_EXPORT_TABLE_SYNC_REUSE_HPP +#define STORM_HASH_TS_EXPORT_TABLE_SYNC_REUSE_HPP + +#include "storm/hash/Hashkey.hpp" +#include "storm/hash/TSExportTableSimpleReuse.hpp" + +template +class TSExportTableSyncReuse : public TSExportTableSimpleReuse { + public: + // Virtual member functions + virtual ~TSExportTableSyncReuse() = default; + + // Member functions + void Delete(THandle handle); + void DeleteUnlock(T* ptr, TLockedHandle lockedHandle); + T* Lock(THandle handle, TLockedHandle* lockedHandlePtr, int32_t forWriting); + T* NewLock(THandle* handlePtr, TLockedHandle* lockedHandlePtr); + void Unlock(TLockedHandle lockedHandle); + + private: + // Member variables + TSync m_sync; + + // Member functions + int32_t IsForWriting(TLockedHandle lockedHandle); + void SyncEnterLock(TLockedHandle* lockedHandlePtr, int32_t forWriting); + void SyncLeaveLock(TLockedHandle lockedHandle); +}; + +template +void TSExportTableSyncReuse::Delete(THandle handle) { + TLockedHandle lockedHandle; + auto ptr = this->Lock(handle, &lockedHandle, 1); + this->DeleteUnlock(ptr, lockedHandle); +} + +template +void TSExportTableSyncReuse::DeleteUnlock(T* ptr, TLockedHandle lockedHandle) { + this->TSExportTableSimpleReuse::Delete(ptr); + this->Unlock(lockedHandle); +} + +template +int32_t TSExportTableSyncReuse::IsForWriting(TLockedHandle lockedHandle) { + return reinterpret_cast(lockedHandle) == 1; +} + +template +T* TSExportTableSyncReuse::Lock(THandle handle, TLockedHandle* lockedHandlePtr, int32_t forWriting) { + this->SyncEnterLock(lockedHandlePtr, forWriting); + + auto ptr = this->Ptr(handle); + + if (!ptr) { + this->SyncLeaveLock(*lockedHandlePtr); + *lockedHandlePtr = nullptr; + return nullptr; + } + + return ptr; +} + +template +T* TSExportTableSyncReuse::NewLock(THandle* handlePtr, TLockedHandle* lockedHandlePtr) { + this->SyncEnterLock(lockedHandlePtr, 1); + return this->New(handlePtr); +} + +template +void TSExportTableSyncReuse::SyncEnterLock(TLockedHandle* lockedHandlePtr, int32_t forWriting) { + this->m_sync.Enter(forWriting); + *lockedHandlePtr = reinterpret_cast(forWriting ? 1 : -1); +} + +template +void TSExportTableSyncReuse::SyncLeaveLock(TLockedHandle lockedHandle) { + if (lockedHandle) { + this->m_sync.Leave(this->IsForWriting(lockedHandle)); + } +} + +template +void TSExportTableSyncReuse::Unlock(TLockedHandle lockedHandle) { + this->SyncLeaveLock(lockedHandle); +} + +#endif diff --git a/test/Hash.cpp b/test/Hash.cpp index 76b4ab3..155cb7c 100644 --- a/test/Hash.cpp +++ b/test/Hash.cpp @@ -1,4 +1,5 @@ #include "storm/Hash.hpp" +#include "storm/Thread.hpp" #include "test/Test.hpp" struct TestHashObject : TSHashObject { @@ -11,6 +12,8 @@ struct TestExportObject : TSHashObject { typedef void* TestExportObjectHandle; +typedef void* TestExportLockedHandle; + TEST_CASE("TSHashTable", "[hash]") { SECTION("constructs correctly") { TSHashTable hashTable; @@ -117,3 +120,44 @@ TEST_CASE("TSExportTableSimpleReuse::Delete", "[hash]") { REQUIRE(exportTable.Ptr(handle) == nullptr); } } + +TEST_CASE("TSExportTableSyncReuse", "[hash]") { + SECTION("constructs correctly") { + TSExportTableSyncReuse exportTable; + REQUIRE(exportTable.Head() == nullptr); + } +} + +TEST_CASE("TSExportTableSyncReuse::NewLock", "[hash]") { + SECTION("returns a new object, handle, and locked handle") { + TSExportTableSyncReuse exportTable; + TestExportObjectHandle handle; + TestExportLockedHandle lockedHandle; + auto object = exportTable.NewLock(&handle, &lockedHandle); + exportTable.Unlock(lockedHandle); + + REQUIRE(handle != nullptr); + REQUIRE(lockedHandle != nullptr); + REQUIRE(object != nullptr); + REQUIRE(object != handle); + REQUIRE(exportTable.Head() == object); + REQUIRE(exportTable.Ptr(handle) == object); + } +} + +TEST_CASE("TSExportTableSyncReuse::Delete", "[hash]") { + SECTION("deletes object from export table") { + TSExportTableSyncReuse exportTable; + TestExportObjectHandle handle; + TestExportLockedHandle lockedHandle; + auto object = exportTable.NewLock(&handle, &lockedHandle); + exportTable.Unlock(lockedHandle); + exportTable.Delete(handle); + + REQUIRE(handle != nullptr); + REQUIRE(object != nullptr); + REQUIRE(object != handle); + REQUIRE(exportTable.Head() == nullptr); + REQUIRE(exportTable.Ptr(handle) == nullptr); + } +}