feat(memory): add assertion mode check to CDataAllocator

This commit is contained in:
VDm 2025-08-17 16:30:57 +04:00
parent 739adccafd
commit d4ee19c6af
4 changed files with 76 additions and 4 deletions

6
.gitignore vendored
View file

@ -1,6 +1,10 @@
.DS_Store .DS_Store
.idea .vs
.vscode .vscode
.idea
/build /build
/cmake-build-* /cmake-build-*
/out
/CMakeSettings.json

View file

@ -11,9 +11,13 @@ CDataAllocator::CDataAllocator(uint32_t bytesPerData, uint32_t dataPerBlock) {
} }
CDataAllocator::~CDataAllocator() { CDataAllocator::~CDataAllocator() {
if (this->m_blockList) {
Clear(__FILE__, __LINE__);
}
} }
void CDataAllocator::Clear(const char* fileName, int32_t lineNumber) { void CDataAllocator::Clear(const char* fileName, int32_t lineNumber) {
#if defined(WHOA_BUILD_ASSERTIONS)
if (this->m_dataUsed) { if (this->m_dataUsed) {
if (!fileName) { if (!fileName) {
fileName == __FILE__; fileName == __FILE__;
@ -21,7 +25,7 @@ void CDataAllocator::Clear(const char* fileName, int32_t lineNumber) {
} }
SErrDisplayErrorFmt( SErrDisplayErrorFmt(
0x8510007E, STORM_ERROR(0x7E),
fileName, fileName,
lineNumber, lineNumber,
1, 1,
@ -34,6 +38,7 @@ void CDataAllocator::Clear(const char* fileName, int32_t lineNumber) {
this->m_dataPerBlock, this->m_dataPerBlock,
this->m_bytesPerData); this->m_bytesPerData);
} }
#endif
while (this->m_blockList) { while (this->m_blockList) {
auto block = this->m_blockList; auto block = this->m_blockList;
@ -63,7 +68,7 @@ CDataAllocator::Data* CDataAllocator::GetData(int32_t zero, const char* fileName
lineNumber, lineNumber,
0)); 0));
Block* block = reinterpret_cast<Block*>(memory); Block* block = reinterpret_cast<Block*>(memory);
Data* data = reinterpret_cast<Data*>(memory + sizeof(Block*)); Data* data = reinterpret_cast<Data*>(memory + sizeof(Block));
this->m_dataList = data; this->m_dataList = data;
for (uint32_t i = 0; i < this->m_dataPerBlock - 1; ++i) { for (uint32_t i = 0; i < this->m_dataPerBlock - 1; ++i) {
@ -71,7 +76,7 @@ CDataAllocator::Data* CDataAllocator::GetData(int32_t zero, const char* fileName
data->m_next = reinterpret_cast<Data*>(next); data->m_next = reinterpret_cast<Data*>(next);
data = data->m_next; data = data->m_next;
} }
data->m_next = 0; data->m_next = nullptr;
block->m_next = this->m_blockList; block->m_next = this->m_blockList;
this->m_blockList = block; this->m_blockList = block;
} }

View file

@ -2,6 +2,25 @@
#define COMMON_MEMORY_C_DATA_ALLOCATOR_HPP #define COMMON_MEMORY_C_DATA_ALLOCATOR_HPP
#include <cstdint> #include <cstdint>
#include <cstdlib>
#include <new>
#include <type_traits>
#define ALLOCATOR_GET(allocator) allocator.GetData(0, __FILE__, __LINE__)
#define ALLOCATOR_GET_ZERO(allocator) allocator.GetData(1, __FILE__, __LINE__)
#define ALLOCATOR_NEW(allocator, T, ...) (new (allocator.GetData(0, __FILE__, __LINE__)) T(__VA_ARGS__))
#define ALLOCATOR_NEW_ZERO(allocator, T, ...) (new (allocator.GetData(1, __FILE__, __LINE__)) T(__VA_ARGS__))
#define ALLOCATOR_PUT(allocator, ptr) allocator.PutData(ptr, __FILE__, __LINE__)
#define ALLOCATOR_PUT(allocator, ptr) \
do { \
if (ptr) { \
using __data_object = std::remove_pointer<std::decay<decltype(ptr)>::type>::type; \
(ptr)->~__data_object(); \
allocator.PutData(ptr, __FILE__, __LINE__); \
} \
} while (0)
class CDataAllocator { class CDataAllocator {
public: public:
@ -21,6 +40,11 @@ class CDataAllocator {
Data* GetData(int32_t zero, const char* fileName, int32_t lineNumber); Data* GetData(int32_t zero, const char* fileName, int32_t lineNumber);
void PutData(void* data, const char* fileName, int32_t lineNumber); void PutData(void* data, const char* fileName, int32_t lineNumber);
inline uint32_t BytesPerData() const { return this->m_bytesPerData; }
inline uint32_t DataPerBlock() const { return this->m_dataPerBlock; }
inline uint32_t DataUsed() const { return this->m_dataUsed; }
private:
// Member variables // Member variables
uint32_t m_bytesPerData = sizeof(Data); uint32_t m_bytesPerData = sizeof(Data);
uint32_t m_dataPerBlock = 1; uint32_t m_dataPerBlock = 1;

39
test/DataAllocator.cpp Normal file
View file

@ -0,0 +1,39 @@
#include "common/DataAllocator.hpp"
#include "test/Test.hpp"
struct TestContainer
{
uint32_t value[10];
};
TEST_CASE("CDataAllocator::CDataAllocator", "[dataallocator]") {
SECTION("constructs new data allocator") {
CDataAllocator allocator(sizeof(TestContainer), 2);
SUCCEED();
}
}
TEST_CASE("CDataAllocator::GetData", "[dataallocator]") {
SECTION("get allocated objects") {
CDataAllocator allocator(sizeof(TestContainer), 2);
auto container = (TestContainer*)allocator.GetData(0, __FILE__, __LINE__);
auto container2 = (TestContainer*)allocator.GetData(0, __FILE__, __LINE__);
auto container3 = (TestContainer*)allocator.GetData(0, __FILE__, __LINE__);
REQUIRE(container);
REQUIRE(container2);
REQUIRE(container3);
REQUIRE(allocator.DataUsed() == 3);
}
}
TEST_CASE("CDataAllocator::PutData", "[dataallocator]") {
SECTION("return allocated objects") {
CDataAllocator allocator(sizeof(TestContainer), 2);
auto container = (TestContainer*)allocator.GetData(0, __FILE__, __LINE__);
auto container2 = (TestContainer*)allocator.GetData(0, __FILE__, __LINE__);
auto container3 = (TestContainer*)allocator.GetData(0, __FILE__, __LINE__);
allocator.PutData(container, __FILE__, __LINE__);
allocator.PutData(container3, __FILE__, __LINE__);
REQUIRE(allocator.DataUsed() == 1);
}
}