see ya later allocator

This commit is contained in:
IlyaShurupov 2024-03-22 14:05:03 +03:00
parent d7bc7e10ab
commit aa53a4addb
44 changed files with 32 additions and 1693 deletions

View file

@ -1,15 +0,0 @@
project(Allocators)
### ---------------------- Static Library --------------------- ###
file(GLOB SOURCES "./private/*.cpp")
file(GLOB HEADERS "./public/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_link_libraries(${PROJECT_NAME} PUBLIC Callstack)
### -------------------------- Tests -------------------------- ###
enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(Tests${PROJECT_NAME} ${TEST_SOURCES})
target_link_libraries(Tests${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
add_test(NAME Tests${PROJECT_NAME} COMMAND Tests${PROJECT_NAME})

View file

@ -1,36 +0,0 @@
# Profiling
## Memory Leaks
Example program with memory leaks:
```c++
#include "allocators.h"
void test_call22() { new int; }
void test_call21() { new float; }
void test_call11() {
test_call21();
test_call22();
}
int main(char argc, char* argv[]) {
tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleAllocators, NULL };
tp::ModuleManifest TestModule("Test", NULL, NULL, ModuleDependencies);
TestModule.initialize();
test_call11();
TestModule.deinitialize();
}
```
If memory leaks were detected it will be logged in the output console.
![image](https://user-images.githubusercontent.com/63184036/222794298-3f238de4-c0b8-41fa-b7ec-c0c675da8f05.png)
Also debug.memleaks binary will be generated in the working directory that can be viewed with MemLeaks Viewer.
![image](https://user-images.githubusercontent.com/63184036/222793169-a405effe-72be-42fc-b375-bb06dce0a735.png)

View file

@ -1,36 +0,0 @@
#include "Allocators.hpp"
#include "HeapAllocatorGlobal.hpp"
#include <cstdlib>
#include <stdio.h>
static bool init(const tp::ModuleManifest* self) {
tp::HeapAllocGlobal::stopIgnore();
if (tp::HeapAllocGlobal::getNAllocations()) {
printf("Warning : Operator new was called outside module initialization!!\n\n");
}
return true;
}
static void deinit(const tp::ModuleManifest* self) {
tp::HeapAllocGlobal::checkLeaks();
}
static tp::ModuleManifest* sModuleDependencies[] = { nullptr };
tp::ModuleManifest tp::gModuleAllocators = ModuleManifest("Allocators", init, deinit, sModuleDependencies);
void* operator new(size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
void* operator new[](size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
void operator delete(void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
void operator delete[](void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
void* operator new(size_t aSize, tp::HeapAlloc& aAlloc) { return aAlloc.allocate(aSize); }
void* operator new[](size_t aSize, tp::HeapAlloc& aAlloc) { return aAlloc.allocate(aSize); }
void operator delete(void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
void operator delete[](void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
void* operator new(size_t aSize, tp::HeapAllocGlobal& aAlloc) { return tp::HeapAllocGlobal::allocate(aSize); }
void* operator new[](size_t aSize, tp::HeapAllocGlobal& aAlloc) { return tp::HeapAllocGlobal::allocate(aSize); }
void operator delete(void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }
void operator delete[](void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }

View file

@ -1,76 +0,0 @@
#include "HeapAllocator.hpp"
#include "HeapAllocatorGlobal.hpp"
#include "PrivateConfig.hpp"
#include <malloc.h>
using namespace tp;
#if not defined(MEM_DEBUG)
// ----------------------- Release Implementation ---------------------------- //
void* HeapAlloc::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
void HeapAlloc::deallocate(void* aPtr) {
if (!aPtr) return;
free(aPtr);
}
HeapAlloc::~HeapAlloc() {}
#else
namespace tp {
struct MemHeadLocal {
MemHeadLocal* mPrev;
MemHeadLocal* mNext;
};
}
void* HeapAlloc::allocate(ualni aBlockSize) {
auto head = (MemHeadLocal*) HeapAllocGlobal::allocate(aBlockSize + sizeof(MemHeadLocal));
auto out = head + 1;
mNumAllocations++;
if (mEntry) {
DEBUG_ASSERT(!mEntry->mNext)
head->mNext = nullptr;
head->mPrev = mEntry;
mEntry->mNext = head;
} else {
head->mNext = nullptr;
head->mPrev = nullptr;
}
mEntry = head;
return out;
}
void HeapAlloc::deallocate(void* aPtr) {
if (!aPtr) return;
auto head = ((MemHeadLocal*) (aPtr)) - 1;
mNumAllocations--;
DEBUG_ASSERT(!mEntry->mNext)
if (head->mNext) head->mNext->mPrev = head->mPrev;
if (head->mPrev) head->mPrev->mNext = head->mNext;
if (head == mEntry) {
mEntry = head->mPrev;
}
HeapAllocGlobal::deallocate(head);
}
HeapAlloc::~HeapAlloc() {
if (mNumAllocations) {
DEBUG_ASSERT(0 && "Destruction of not freed Allocator")
#ifdef MEM_STACK_TRACE
// TODO : log leaks and free them up
#endif
}
}
#endif

View file

@ -1,232 +0,0 @@
#include "HeapAllocatorGlobal.hpp"
#include "PrivateConfig.hpp"
#include "Callstack.hpp"
#include "Utils.hpp"
#include <cstdio>
#include <cstdlib>
using namespace tp;
#if not defined(MEM_DEBUG)
// ----------------------- Release Implementation ---------------------------- //
void* HeapAllocGlobal::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
void HeapAllocGlobal::deallocate(void* aPtr) {
if (!aPtr) return;
free(aPtr);
}
HeapAllocGlobal::~HeapAllocGlobal() = default;
bool HeapAllocGlobal::checkLeaks() { return false; }
void HeapAllocGlobal::startIgnore() {}
void HeapAllocGlobal::stopIgnore() {}
ualni HeapAllocGlobal::getNAllocations() { return 0; }
#else
tp::MemHead* tp::HeapAllocGlobal::mEntry = nullptr;
tp::ualni tp::HeapAllocGlobal::mNumAllocations = 0;
std::mutex tp::HeapAllocGlobal::mMutex;
bool tp::HeapAllocGlobal::mIgnore = true;
bool tp::HeapAllocGlobal::mEnableCallstack = true;
#ifdef MEM_STACK_TRACE
tp::CallStackCapture tp::HeapAllocGlobal::mCallstack;
#endif
// ----------------------- Debug Implementation ---------------------------- //
// |----------------|
// | MemHead |
// |----------------|
// | wrap top |
// |----------------| - Allocated Block Layout
// | data |
// |----------------|
// | wrap bottom |
// |----------------|
namespace tp {
struct MemHead {
MemHead* mPrev;
MemHead* mNext;
uhalni mBlockSize;
uhalni mIgnored;
#ifdef MEM_STACK_TRACE
const CallStackCapture::CallStack* mCallStack;
#else
void* p;
#endif
};
}
enum : ualni {
ALIGNED_SIZE = ENV_ALNI_SIZE_B,
WRAP_SIZE = MEM_WRAP_SIZE * ALIGNED_SIZE,
WRAP_VAL = MEM_WRAP_FILL_VAL,
HEAD_SIZE = sizeof(MemHead),
CLEAR_ALLOC_VAL = MEM_CLEAR_ON_ALLOC_VAL,
CLEAR_DEALLOC_VAL = MEM_CLEAR_ON_DEALLOC_VAL,
};
void* HeapAllocGlobal::allocate(ualni aBlockSize) {
static_assert(HEAD_SIZE % ALIGNED_SIZE == 0, "Heap Allocator Configuration Error");
if (aBlockSize % ALIGNED_SIZE) {
aBlockSize = (aBlockSize / ALIGNED_SIZE + 1) * ALIGNED_SIZE;
}
// 1) Allocate the block
ALLOCATE:
auto head = (MemHead*) malloc(aBlockSize + WRAP_SIZE * 2 + HEAD_SIZE);
if (!head) {
printf("WARNING : Cant allocate memory. Trying again\n");
goto ALLOCATE; // Just freeze if no memory is available
}
auto wrap_top = (int1*) (head + 1);
auto data = wrap_top + WRAP_SIZE;
auto wrap_bottom = data + aBlockSize;
head->mBlockSize = aBlockSize;
head->mIgnored = mIgnore;
// 2) Link with existing blocks
mMutex.lock();
mNumAllocations++;
if (mEntry) {
DEBUG_ASSERT(mEntry->mNext == nullptr)
head->mNext = nullptr;
head->mPrev = mEntry;
mEntry->mNext = head;
} else {
head->mNext = nullptr;
head->mPrev = nullptr;
}
mEntry = head;
// 3) Trace the stack
#ifdef MEM_STACK_TRACE
// check if somewhat decides to call new within static variable initialization
head->mCallStack = (mEnableCallstack && mCallstack.initialized) ? mCallstack.getSnapshot() : nullptr;
#endif
mMutex.unlock();
// 4) Wrap fill
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
// 5) clear data
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(data, aBlockSize, CLEAR_ALLOC_VAL);
#endif
return data;
}
void HeapAllocGlobal::deallocate(void* aPtr) {
if (!aPtr) return;
// 1) Restore the pointers
auto head = ((MemHead*) ((int1*) aPtr - WRAP_SIZE)) - 1;
auto wrap_top = (int1*) (head + 1);
auto data = wrap_top + WRAP_SIZE;
auto wrap_bottom = data + head->mBlockSize;
// 2) Unlink with blocks
mMutex.lock();
mNumAllocations--;
DEBUG_ASSERT(!mEntry->mNext)
if (head->mNext) head->mNext->mPrev = head->mPrev;
if (head->mPrev) head->mPrev->mNext = head->mNext;
if (head == mEntry) {
mEntry = head->mPrev;
}
if (!head->mIgnored) {
// 3) Check the wrap
if (memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL)) {
#ifdef MEM_STACK_TRACE
if (head->mCallStack) mCallstack.printSnapshot(head->mCallStack);
#endif
ASSERT(!"Allocated Block Wrap Corrupted!")
}
if (memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL)) {
#ifdef MEM_STACK_TRACE
if (head->mCallStack) mCallstack.printSnapshot(head->mCallStack);
#endif
ASSERT(!"Allocated Block Wrap Corrupted!")
}
// 4) clear data
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(data, head->mBlockSize, CLEAR_DEALLOC_VAL);
#endif
}
mMutex.unlock();
// 5) free the block
free(head);
}
bool HeapAllocGlobal::checkLeaks() {
ualni ignoredCount = 0;
for (auto iter = mEntry; iter; iter = iter->mPrev) {
ignoredCount += iter->mIgnored;
}
// 1) Check for not deallocated memory
if (mNumAllocations && ignoredCount < mNumAllocations) {
#ifdef MEM_STACK_TRACE
for (auto iter = mEntry; iter; iter = iter->mPrev) {
if (!iter->mIgnored && iter->mCallStack) mCallstack.printSnapshot(iter->mCallStack);
}
#endif
printf(" Count : %llu", mNumAllocations - ignoredCount);
ASSERT(!"Destruction of not freed Allocator")
return true;
}
return false;
}
void HeapAllocGlobal::startIgnore() {
mMutex.lock();
mIgnore = true;
mMutex.unlock();
}
void HeapAllocGlobal::stopIgnore() {
mMutex.lock();
mIgnore = false;
mMutex.unlock();
}
ualni HeapAllocGlobal::getNAllocations() {
return mNumAllocations;
}
void HeapAllocGlobal::enableCallstack() {
mMutex.lock();
mEnableCallstack = true;
mMutex.unlock();
}
void HeapAllocGlobal::disableCallstack() {
mMutex.lock();
mEnableCallstack = false;
mMutex.unlock();
}
HeapAllocGlobal::~HeapAllocGlobal() = default;
#endif

View file

@ -1,27 +0,0 @@
#pragma once
#include "Utils.hpp"
#include "ChunkAllocator.hpp"
#include "HeapAllocator.hpp"
#include "HeapAllocatorGlobal.hpp"
#include "PoolAllocator.hpp"
namespace tp {
extern ModuleManifest gModuleAllocators;
}
void* operator new(std::size_t aSize);
void* operator new[](std::size_t aSize);
void operator delete(void* aPtr) noexcept;
void operator delete[](void* aPtr) noexcept;
void* operator new(std::size_t aSize, tp::HeapAlloc& aAlloc);
void* operator new[](std::size_t aSize, tp::HeapAlloc& aAlloc);
void operator delete(void* aPtr, tp::HeapAlloc& aAlloc);
void operator delete[](void* aPtr, tp::HeapAlloc& aAlloc);
void* operator new(std::size_t aSize, tp::HeapAllocGlobal& aAlloc);
void* operator new[](std::size_t aSize, tp::HeapAllocGlobal& aAlloc);
void operator delete(void* aPtr, tp::HeapAllocGlobal& aAlloc);
void operator delete[](void* aPtr, tp::HeapAllocGlobal& aAlloc);

View file

@ -1,136 +0,0 @@
#pragma once
/*
* Implementation uses embedded one-directional linked list to track free blocks.
* The embedded part ensures that there is no memory overhead on block specifically.
* Linked list is initialized iteratively on each allocation if it has not been already.
* Allocating:
* 1) updating list entry to stored in the entry itself next free pointer
* 2) returning entry before (1).
*
* Deallocating:
* 1) assigning list entry value to the deleted block
* 2) updating list entry to that block.
*/
#include "Environment.hpp"
#include "HeapAllocatorGlobal.hpp"
#include "PrivateConfig.hpp"
namespace tp {
// Chunk Allocator
// Constant time allocations and de-allocations in any order.
// Memory blocks are fixed in size and number of blocks can not exceed given parameter.
template <typename tType, ualni tNumBlocks>
class ChunkAlloc {
enum : ualni {
ALIGNED_SIZE = ENV_ALNI_SIZE_B,
WRAP_SIZE_ALN = MEM_WRAP_SIZE / 2,
WRAP_SIZE = WRAP_SIZE_ALN * ALIGNED_SIZE,
WRAP_VAL = MEM_WRAP_FILL_VAL,
CLEAR_ALLOC_VAL = MEM_CLEAR_ON_ALLOC_VAL,
CLEAR_DEALLOC_VAL = MEM_CLEAR_ON_DEALLOC_VAL,
};
static constexpr ualni dataSize() {
auto BLOCK_SIZE_BYTES = sizeof(tType);
auto BLOCK_SIZE_ALIGNED = BLOCK_SIZE_BYTES / ALIGNED_SIZE;
return BLOCK_SIZE_ALIGNED;
}
static constexpr ualni blockSize() {
auto BLOCK_SIZE_BYTES = sizeof(tType);
auto BLOCK_SIZE = dataSize() + bool(BLOCK_SIZE_BYTES % ALIGNED_SIZE) + WRAP_SIZE_ALN * 2;
return BLOCK_SIZE;
}
private:
ualni* mNextBlock;
ualni mNumFreeBlocks;
ualni mNumInitBlocks;
ualni mBuff[tNumBlocks * blockSize() * ALIGNED_SIZE];
public:
ChunkAlloc() {
mNumFreeBlocks = tNumBlocks;
mNumInitBlocks = 0;
mNextBlock = mBuff;
}
~ChunkAlloc() = default; // TODO : check for leaks
public:
void* allocate(ualni) {
DEBUG_ASSERT(mNumFreeBlocks && "Out Of Memory")
// 1) PreInitialize blocks
if (mNumInitBlocks < tNumBlocks) {
mBuff[mNumInitBlocks * blockSize()] = (ualni) (mBuff + (mNumInitBlocks + 1) * blockSize());
mNumInitBlocks++;
}
// 2) Find free block and update next free block
auto data = mNextBlock;
mNextBlock = (ualni*) (*data);
mNumFreeBlocks--;
#ifdef MEM_DEBUG
// 3) Fill Wrap and offset data
auto wrap_top = data;
auto wrap_bottom = data + WRAP_SIZE_ALN + dataSize();
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
// 4) Clear data
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(data + WRAP_SIZE_ALN, dataSize() * ALIGNED_SIZE, CLEAR_ALLOC_VAL);
#endif
data += WRAP_SIZE_ALN;
#endif
return data;
}
void deallocate(void* aPtr) {
DEBUG_ASSERT(aPtr >= mBuff && aPtr < mBuff + tNumBlocks * blockSize())
auto block = (ualni*) aPtr;
#ifdef MEM_DEBUG
// 3) Check Wrap and offset data
auto wrap_bottom = block + dataSize();
auto wrap_top = block - WRAP_SIZE_ALN;
block = wrap_top;
// 3) Check the wrap
ASSERT(!memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
ASSERT(!memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
// 4) Clear data
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(block, blockSize() * ALIGNED_SIZE, CLEAR_DEALLOC_VAL);
#endif
#endif
(*block) = (ualni) mNextBlock;
mNextBlock = block;
mNumFreeBlocks++;
}
[[nodiscard]] bool checkWrap() const { return false; }
void checkValid() {}
public:
[[nodiscard]] bool isFull() const { return !mNumFreeBlocks; }
[[nodiscard]] bool isEmpty() const { return mNumFreeBlocks == tNumBlocks; }
[[nodiscard]] const ualni* getBuff() const { return mBuff; }
};
}

View file

@ -1,26 +0,0 @@
#pragma once
#include "Environment.hpp"
namespace tp {
class HeapAlloc {
#ifdef MEM_DEBUG
ualni mNumAllocations = 0;
struct MemHeadLocal* mEntry = nullptr;
#endif
public:
HeapAlloc() = default;
~HeapAlloc();
public:
void* allocate(ualni aBlockSize);
void deallocate(void* aPtr);
public:
[[nodiscard]] bool checkWrap() const { return false; }
void checkValid() {}
};
}

View file

@ -1,41 +0,0 @@
#pragma once
#include "Callstack.hpp"
#include <mutex>
namespace tp {
class HeapAllocGlobal {
#ifdef MEM_DEBUG
static ualni mNumAllocations;
static struct MemHead* mEntry;
static std::mutex mMutex;
static bool mIgnore;
static bool mEnableCallstack;
#ifdef MEM_STACK_TRACE // Save stack on allocation call
static CallStackCapture mCallstack;
#endif
#endif
public:
HeapAllocGlobal() = default;
~HeapAllocGlobal();
public:
static void* allocate(ualni aBlockSize);
static void deallocate(void* aPtr);
static bool checkLeaks();
static void startIgnore();
static void stopIgnore();
static ualni getNAllocations();
static void enableCallstack();
static void disableCallstack();
public:
[[nodiscard]] bool checkWrap() const { return false; }
void checkValid() {}
};
}

View file

@ -1,8 +0,0 @@
#pragma once
#include "Common.hpp"
#ifndef ENV_OS_WINDOWS
inline void* operator new(std::size_t aSize, void* aWhere) noexcept { return aWhere; }
inline void* operator new[](std::size_t aSize, void* aWhere) noexcept { return aWhere; }
#endif

View file

@ -1,161 +0,0 @@
#pragma once
/*
Implementation:
* Adding chunk pointer to each chunk to form one-directional list that keeps track of free chunk
* Storing ordered pointers to chunks in order to find desired chunk from delete pointer on de-allocation in log time
*
* Allocations:
* 1) allocate with chunk stored in list entry
* 2) ...
*
* De-allocations:
* 1) binary-search with delete pointer to find desired chunk
* 2) ...
*
*/
#include "ChunkAllocator.hpp"
namespace tp {
// Pool Allocator
// Overcomes chunk allocator fixed number of max allocations
template <typename tType, ualni tNumBlocks>
class PoolAlloc {
typedef ChunkAlloc<tType, tNumBlocks> Chunk;
struct Chunks {
void add(Chunk* aChunk) {
if (!mBuff) {
mLen = 16;
mBuff = (Chunk**) HeapAllocGlobal::allocate(sizeof(Chunk*) * mLen);
mUsedLen = 1;
mBuff[0] = aChunk;
return;
}
// ensure order
auto smaller_address = findUtil(mBuff, mBuff + mUsedLen, aChunk);
for (auto iter = mBuff + mUsedLen; iter != smaller_address; iter--) {
*iter = *(iter - 1);
}
*(smaller_address) = aChunk;
mUsedLen++;
// check for buff overflow
if (mUsedLen == mLen) {
auto prevBuff = mBuff;
mBuff = (Chunk**) HeapAllocGlobal::allocate(sizeof(Chunk*) * mLen * 2);
memCopy(mBuff, prevBuff, sizeof(Chunk*) * mUsedLen);
mLen *= 2;
HeapAllocGlobal::deallocate(prevBuff);
}
}
void remove(Chunk** del_address) {
if (mUsedLen == 1) {
mLen = 0;
mUsedLen = 0;
HeapAllocGlobal::deallocate(mBuff);
mBuff = nullptr;
return;
}
// ensure order
for (auto iter = del_address; iter != mBuff + mUsedLen - 1; iter++) {
*iter = *(iter + 1);
}
mUsedLen--;
// check for buff low usage
if ((halnf) mUsedLen / (halnf) mLen < 0.25f) {
auto prevBuff = mBuff;
mBuff = (Chunk**) HeapAllocGlobal::allocate(sizeof(Chunk*) * mLen / 2);
memCopy(mBuff, prevBuff, sizeof(Chunk*) * mUsedLen);
mLen /= 2;
HeapAllocGlobal::deallocate(prevBuff);
}
}
[[nodiscard]] Chunk** find(void* aPtr) { return findUtil(mBuff, mBuff + mUsedLen, aPtr) - 1; }
[[nodiscard]] Chunk* findNotFull() const {
for (ualni idx = 0; idx < mUsedLen; idx++) {
if (!mBuff[idx]->isFull()) {
return mBuff[idx];
}
}
return nullptr;
}
Chunk** mBuff = nullptr;
ualni mUsedLen = 0;
ualni mLen = 0;
private:
Chunk** findUtil(Chunk** aLeft, Chunk** aRight, void* aPtr) {
auto range = ualni(aRight - aLeft);
if (range == 1) {
return (aPtr < *aLeft) ? aLeft : aRight;
}
auto middle = aLeft + range / 2;
return (aPtr >= (*middle)) ? findUtil(middle, aRight, aPtr) : findUtil(aLeft, middle, aPtr);
}
};
private:
Chunks mChunks;
Chunk* mFreeChunk = nullptr;
public:
PoolAlloc() = default;
~PoolAlloc() = default;
public:
void* allocate(ualni) {
if (!mFreeChunk || mFreeChunk->isFull()) {
auto new_free_chunk = mChunks.findNotFull();
if (!new_free_chunk) {
new_free_chunk = new (HeapAllocGlobal::allocate(sizeof(Chunk))) Chunk();
DEBUG_ASSERT(new_free_chunk)
mChunks.add(new_free_chunk);
}
mFreeChunk = new_free_chunk;
}
return mFreeChunk->allocate(0);
}
void deallocate(void* aPtr) {
if (!aPtr) return;
auto chunk = mChunks.find(aPtr);
(*chunk)->deallocate(aPtr);
if ((*chunk)->isEmpty()) {
if (mFreeChunk == *chunk) mFreeChunk = nullptr;
HeapAllocGlobal::deallocate(*chunk);
mChunks.remove(chunk);
}
}
public:
[[nodiscard]] bool checkWrap() const { return false; }
void checkValid() {
return;
for (auto i = 0; i < mChunks.mUsedLen; i++) {
for (auto j = 0; j < mChunks.mUsedLen; j++) {
if (i > j) {
ASSERT(mChunks.mBuff[i] > mChunks.mBuff[j])
} else if (i < j) {
ASSERT(mChunks.mBuff[i] < mChunks.mBuff[j])
}
}
}
}
};
}

View file

@ -1,9 +0,0 @@
#pragma once
#define MEM_WRAP_SIZE 8 // Wrapping Size in aligned units
#define MEM_WRAP_FILL_VAL 0xBB // Wrapping Fill Value
#define MEM_CLEAR_ON_ALLOC // Clear data on allocation
#define MEM_CLEAR_ON_DEALLOC // Clear data on free
#define MEM_CLEAR_ON_DEALLOC_VAL 0xAA // Clear data on free
#define MEM_CLEAR_ON_ALLOC_VAL 0xCC // Clear data on free
#define MEM_STACK_TRACE_MAX_DEPTH 32 // Call stack max depth

View file

@ -1,249 +0,0 @@
#include "UnitTest++/UnitTest++.h"
#include "Allocators.hpp"
#include "Utils.hpp"
#include <cmath>
using namespace tp;
struct TestStruct {
alni val = 0;
TestStruct() :
val(0) {}
explicit TestStruct(alni val) :
val(val) {}
TestStruct(const TestStruct& in) :
val(in.val) {}
~TestStruct() { val = -1; }
bool operator==(const TestStruct& in) const { return in.val == val; }
};
template <alni tSize, class tAllocator>
class TestBenches {
tAllocator mAlloc{};
TestStruct mData[tSize]{};
TestStruct* mLoaded[tSize]{};
bool mIsLoaded[tSize]{};
alni mLoadedNum = 0;
public:
TestBenches() {
for (alni i = 0; i < tSize; i++) {
mData[i].val = i;
mIsLoaded[i] = false;
mLoaded[i] = nullptr;
}
}
void runTests() {
try {
test1();
test2();
test3();
test4();
test5();
test6();
} catch (...) {
ASSERT(false)
}
}
private:
alni randomIdx(bool state, Range<alni> range = { 0, tSize }) {
RAND:
auto idx = alni(alnf(range.idxBegin()) + randomFloat() * alnf(range.idxDiff() + 1));
idx = clamp(idx, alni(0), tSize - 1);
if (state == mIsLoaded[idx]) goto RAND;
return idx;
}
void verifyIntegrity() {
mAlloc.checkValid();
ASSERT(!mAlloc.checkWrap())
for (alni i = 0; i < tSize; i++) {
if (mIsLoaded[i]) {
ASSERT(*mLoaded[i] == mData[i])
}
}
}
void loadItem(alni idx) {
if (mIsLoaded[idx]) return;
verifyIntegrity();
mLoaded[idx] = new (mAlloc.allocate(sizeof(TestStruct))) TestStruct(mData[idx]);
ASSERT(mLoaded[idx]);
mIsLoaded[idx] = true;
mLoadedNum++;
verifyIntegrity();
}
void unloadItem(alni idx) {
if (!mIsLoaded[idx]) return;
verifyIntegrity();
mLoaded[idx]->~TestStruct();
mAlloc.deallocate(mLoaded[idx]);
mIsLoaded[idx] = false;
mLoadedNum--;
verifyIntegrity();
}
void changeStates(Range<alni> rg, bool load, bool reversed = false, bool random = false) {
for (auto i : rg) {
alni idx = i;
if (random) {
idx = randomIdx(load, rg);
} else if (reversed) {
idx = rg.idxEnd() - i - 1;
}
(load) ? loadItem(idx) : unloadItem(idx);
}
}
// full down-up load then up-down unload
void test1() {
changeStates({ 0, tSize }, true);
changeStates({ 0, tSize }, false, true);
}
// full down-up load then down-up unload
void test2() {
changeStates({ 0, tSize }, true);
changeStates({ 0, tSize }, false);
}
// full random load then random unload
void test3() {
changeStates({ 0, tSize }, true, false, true);
changeStates({ 0, tSize }, false, false, true);
}
// combo tests 1-3
void test4() {
test1();
test1();
test2();
test2();
test3();
test3();
}
static alnf sineUpFunction(alnf aSize, alnf aX, bool aReverse) {
alnf end = 4 * 3.14159;
alnf a = (2 / 7.f) * aSize;
alnf b = end / aSize;
alni c = ((-1 * aReverse) + (1 * !aReverse));
alnf c1 = (aX - (end * aReverse)) / b;
alnf c2 = (a * sin(aX - (end * aReverse)));
alnf out = c1 + c2;
return (alnf) c * out;
}
// sin load & sin unload with ~1/2 drop factor
void test5() {
alnf end = 4 * 3.14159;
alnf step = end / 4.f;
for (char i = 0; i < 2; i++) {
for (alnf x = 0; x <= end; x += step) {
alni target_alloc_count = (alni) ceil(sineUpFunction(tSize, x, i));
target_alloc_count = clamp(target_alloc_count, alni(0), tSize);
while (mLoadedNum > target_alloc_count) {
unloadItem(randomIdx(0));
}
while (mLoadedNum < target_alloc_count) {
loadItem(randomIdx(1));
}
}
}
}
void checkWrap(ualni offset, bool after) {
offset = clamp(offset, (ualni) 1, (ualni) MEM_WRAP_SIZE);
TestStruct* ts = mLoaded[randomIdx(0)];
ualni shift = (sizeof(TestStruct) * after) + (offset - 1) * after - offset * (!after);
uint1* address = (((uint1*) ts) + shift);
uint1 val = *address;
*address = 5;
ASSERT(!mAlloc.checkWrap());
*address = val;
}
// mem guards test
void test6() {
changeStates({ 0, tSize }, 1);
#ifdef MEM_DEBUG
for (alni after = 0; after < 2; after++) {
for (alni offset = 1; offset <= MEM_WRAP_SIZE; offset++) {
checkWrap(offset, after);
}
}
#endif
changeStates({ 0, tSize }, 0);
}
};
const ualni size = 500;
template <typename Alloc>
void testAlloc() {
try {
TestBenches<size, Alloc> heapTests{};
heapTests.runTests();
} catch (...) {
ASSERT(false);
}
}
SUITE(Allocators) {
TEST(GlobalHeap) { testAlloc<HeapAllocGlobal>(); }
TEST(Heap) { testAlloc<tp::HeapAlloc>(); }
TEST(Chunk) {
testAlloc<ChunkAlloc<TestStruct, size>>();
testAlloc<ChunkAlloc<TestStruct, size * 2>>();
}
TEST(Pool) {
testAlloc<PoolAlloc<TestStruct, 1>>();
testAlloc<PoolAlloc<TestStruct, size / 100>>();
testAlloc<PoolAlloc<TestStruct, size>>();
}
TEST(Simple) {
auto a = new TestStruct(-1);
delete a;
}
}
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, nullptr };
tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
bool res = UnitTest::RunAllTests();
testModule.deinitialize();
return res;
}

View file

@ -11,11 +11,9 @@ project(ModulesRoot)
include(CMakeOptions.txt)
add_subdirectory(Modules)
add_subdirectory(Callstack)
add_subdirectory(Containers)
add_subdirectory(Math)
add_subdirectory(Strings)
add_subdirectory(Allocators)
# add_subdirectory(Language)
add_subdirectory(Externals)
add_subdirectory(Connection)

View file

@ -1,14 +0,0 @@
project(Callstack)
### ---------------------- Static Library --------------------- ###
file(GLOB SOURCES "./private/*.cpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_link_libraries(${PROJECT_NAME} PUBLIC Containers)
### -------------------------- Tests -------------------------- ###
file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(Tests${PROJECT_NAME} ${TEST_SOURCES})
target_link_libraries(Tests${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
add_test(NAME Tests${PROJECT_NAME} COMMAND Tests${PROJECT_NAME})

View file

@ -1,338 +0,0 @@
#include "Callstack.hpp"
#include <iostream>
using namespace tp;
// frame to reference on no sapce left
static void errorNoSpaceLeft() {
// to disable optimization of function
static int dummy;
dummy = 10;
}
ualni CallStackCapture::CallStack::getDepth() const {
ualni len = 0;
for (long long frame : frames) {
if (!frame) {
break;
}
len++;
}
return len++;
}
ualni CallStackCapture::hashCallStack(CallStackKey key) {
auto const cs = key.cs;
ualni out = 0;
for (ualni i = 0; cs->frames[i]; i++) {
out += cs->frames[i];
}
return out;
}
bool CallStackCapture::CallStackKey::operator==(const CallStackCapture::CallStackKey& in) const {
for (ualni i = 0; i < MAX_CALL_DEPTH_CAPTURE; i++) {
if (cs->frames[i] != in.cs->frames[i]) {
return false;
}
if (cs->frames[i] == 0 && in.cs->frames[i] == 0) {
return true;
}
}
DEBUG_ASSERT(0 && "Must Not Happen")
return true;
}
CallStackCapture::CallStackCapture() {
static_assert(MAX_CALL_DEPTH_CAPTURE >= 1);
static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB > 0);
static_assert(MAX_DEBUG_INFO_LEN > sizeof("unresolved"));
static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024 > sizeof(CallStack));
mBuffLoad = 0;
mBuffLen = STACKS_LENGTH;
mBuff = (CallStack*) malloc(mBuffLen * sizeof(CallStack));
mErrorSnapshot.frames[0] = (alni) & errorNoSpaceLeft;
platformInit();
initialized = true;
}
const CallStackCapture::CallStack* CallStackCapture::getSnapshot() {
if (mBuffLoad > mBuffLen) {
return &mErrorSnapshot;
}
CallStack* cs = &mBuff[mBuffLoad];
platformWriteStackTrace(cs);
auto idx = mSnapshots.presents({ cs });
if (idx) {
return mSnapshots.getSlotVal(idx);
}
mSnapshots.put({ cs }, cs);
mBuffLoad++;
return cs;
}
const CallStackCapture::DebugSymbols* CallStackCapture::getSymbols(FramePointer frame) {
auto idx = mSymbols.presents(frame);
if (idx) {
return &mSymbols.getSlotVal(idx);
}
mSymbols.put(frame, {});
auto symbols = &mSymbols.get(frame);
platformWriteDebugSymbols(frame, symbols);
return symbols;
}
void CallStackCapture::clear() {
mBuffLoad = 0;
mSnapshots.removeAll();
mSymbols.removeAll();
}
CallStackCapture::~CallStackCapture() {
free(mBuff);
initialized = false;
}
// ---------------------------------- Platform Depended ---------------------------------- //
#if defined(ENV_OS_LINUX)
#include <cstring>
#include <cxxabi.h>
#include <execinfo.h>
#include <malloc.h>
void CallStackCapture::platformInit() {
}
void CallStackCapture::platformDeinit() {
}
void CallStackCapture::platformWriteStackTrace(CallStack* stack) {
auto depth = backtrace((void**) stack->frames, (int) MAX_CALL_DEPTH_CAPTURE - 1);
stack->frames[depth] = 0;
}
static void getGetSourceFromBinaryAddress(const char* binary, const char* address, char* file, ualni* line) {
static char buff[1024];
snprintf(buff, sizeof(buff), "addr2line -e %s -a %s", binary, address);
FILE* pipe = popen(buff, "r");
if (pipe) {
fgets(buff, sizeof(buff), pipe);
fgets(buff, sizeof(buff), pipe);
pclose(pipe);
char* linePtr = strchr(buff, ':');
printf("%s\n", buff);
if (linePtr != nullptr && buff[0] != '?' && buff[1] != '?' && buff[2] != ':') {
*linePtr = '\0';
auto sourceLen = std::strlen(buff);
std::strcpy(file, buff + ((sourceLen > CallStackCapture::MAX_DEBUG_INFO_LEN) ? (sourceLen - CallStackCapture::MAX_DEBUG_INFO_LEN) : 0));
*line = strtoul(linePtr + 1, nullptr, 10);
return;
}
}
std::strcpy(file, "unresolved");
*line = 0;
}
static void getDemangledName(const char* func, char* out) {
int status;
size_t funcDemangledSize = CallStackCapture::MAX_DEBUG_INFO_LEN;
char* funcDemangled = (char*) malloc(funcDemangledSize);
char* ret = abi::__cxa_demangle(func, funcDemangled, &funcDemangledSize, &status);
if (status == 0) {
funcDemangled = ret;
auto funcLen = std::strlen(funcDemangled);
std::strcpy(out, funcDemangled + ((funcLen > CallStackCapture::MAX_DEBUG_INFO_LEN) ? (funcLen - CallStackCapture::MAX_DEBUG_INFO_LEN) : 0));
free(ret);
return;
}
auto funcLen = std::strlen(func);
std::strcpy(out, func + ((funcLen > CallStackCapture::MAX_DEBUG_INFO_LEN) ? (funcLen - CallStackCapture::MAX_DEBUG_INFO_LEN) : 0));
free(funcDemangled);
}
void CallStackCapture::platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out) {
void* addrList[1] = { (void*) frame };
auto symbolsArray = backtrace_symbols(addrList, 1);
// 'bin(fun+addr)'
char* bin = *symbolsArray;
char* func = nullptr;
char* offset = nullptr;
// 'bin fun+addr'
for (char* p = bin; *p; ++p) {
if (*p == '(') {
*p = 0;
func = p + 1;
} else if (*p == '+') {
offset = p;
} else if (*p == ')' && offset) {
*p = 0;
}
}
if (func && offset) {
getGetSourceFromBinaryAddress(bin, func, out->file, &out->line);
if (offset != func) {
*offset = 0;
getDemangledName(func, out->function);
} else {
std::strcpy(out->function, "unresolved");
}
} else {
std::strcpy(out->file, "unresolved");
std::strcpy(out->function, "unresolved");
}
free(symbolsArray);
}
void CallStackCapture::printSnapshot(const CallStack* snapshot) {
printf("CallStack: \n");
if (snapshot) {
for (auto frame : *snapshot) {
auto symbols = getSymbols(frame.getFrame());
printf(" %s ----- %s:%llu\n", symbols->getFunc(), symbols->getFile(), symbols->getLine());
}
}
printf("\n");
}
void CallStackCapture::logAll() {
for (auto cs : *this) {
printSnapshot(cs.getCallStack());
}
}
#else
#include <windows.h>
#include <dbghelp.h>
#include <stdio.h>
#pragma comment(lib, "dbghelp.lib")
void CallStackCapture::platformInit() {
HANDLE process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
}
void CallStackCapture::platformDeinit() {
HANDLE process = GetCurrentProcess();
SymCleanup(process);
}
void CallStackCapture::platformWriteStackTrace(CallStack* stack) {
DWORD hash;
CONTEXT context;
memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&context);
STACKFRAME64 stackFrame;
memset(&stackFrame, 0, sizeof(STACKFRAME64));
#ifdef _M_IX86
hash = IMAGE_FILE_MACHINE_I386;
stackFrame.AddrPC.Offset = context.Eip;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = context.Ebp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
stackFrame.AddrStack.Offset = context.Esp;
stackFrame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
hash = IMAGE_FILE_MACHINE_AMD64;
stackFrame.AddrPC.Offset = context.Rip;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = context.Rbp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
stackFrame.AddrStack.Offset = context.Rsp;
stackFrame.AddrStack.Mode = AddrModeFlat;
#endif
for (int frameIndex = 0; frameIndex < MAX_CALL_DEPTH_CAPTURE; ++frameIndex) {
if (!StackWalk64(
hash,
GetCurrentProcess(),
GetCurrentThread(),
&stackFrame,
&context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL
)) {
stack->frames[frameIndex] = 0;
break;
}
stack->frames[frameIndex] = (alni) (void*) stackFrame.AddrPC.Offset;
}
stack->frames[MAX_CALL_DEPTH_CAPTURE - 1] = 0;
}
void CallStackCapture::platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out) {
HANDLE process = GetCurrentProcess();
IMAGEHLP_LINE64 lineInfo;
DWORD displacement;
lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymGetLineFromAddr64(process, (DWORD64) frame, &displacement, &lineInfo)) {
strcpy(out->file, lineInfo.FileName);
out->line = lineInfo.LineNumber;
} else {
strcpy(out->file, "unresolved");
out->line = 0;
}
DWORD64 displacementSym = 0;
char symbolBuffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH] = { 0 };
IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*) symbolBuffer;
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
symbol->MaxNameLength = MAX_PATH;
if (SymGetSymFromAddr64(process, (DWORD64) frame, &displacementSym, symbol)) {
strcpy(out->function, symbol->Name);
} else {
strcpy(out->function, "unresolved");
}
}
void CallStackCapture::printSnapshot(const CallStack* snapshot) {
printf("CallStack: \n");
if (snapshot) {
for (int i = 0; i < snapshot->getDepth(); ++i) {
DebugSymbols symbols;
platformWriteDebugSymbols(snapshot->frames[i], &symbols);
printf(" %s ----- %s:%lu\n", symbols.function, symbols.file, symbols.line);
}
}
printf("\n");
}
void CallStackCapture::logAll() {
for (auto cs : *this) {
printSnapshot(cs.getCallStack());
}
}
#endif

View file

@ -1,105 +0,0 @@
#pragma once
#include "Environment.hpp"
#include "Map.hpp"
namespace tp {
class CallStackCapture {
public:
typedef tp::alni FramePointer;
bool initialized = false;
enum {
MAX_CALL_DEPTH_CAPTURE = 16,
MAX_CALL_CAPTURES_MEM_SIZE_MB = 32,
MAX_DEBUG_INFO_LEN = 64,
};
class CallStack {
friend CallStackCapture;
FramePointer frames[MAX_CALL_DEPTH_CAPTURE];
public:
[[nodiscard]] ualni getDepth() const;
class Iterator {
const FramePointer* mFrame;
public:
explicit Iterator(const FramePointer* frame) : mFrame(frame){};
FramePointer getFrame() { return *mFrame; }
bool operator==(const Iterator& in) const { return in.mFrame == mFrame; }
void operator++() { mFrame++; }
const Iterator& operator*() const { return *this; }
};
[[nodiscard]] Iterator begin() const { return Iterator(frames); }
[[nodiscard]] Iterator end() const { return Iterator(frames + getDepth()); }
};
enum { STACKS_LENGTH = (MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024) / sizeof(CallStack) };
class DebugSymbols {
friend CallStackCapture;
char function[MAX_DEBUG_INFO_LEN + 1] = { 0 };
char file[MAX_DEBUG_INFO_LEN + 1] = { 0 };
ualni line = 0;
public:
[[nodiscard]] const char* getFunc() const { return function; }
[[nodiscard]] const char* getFile() const { return file; }
[[nodiscard]] ualni getLine() const { return line; }
};
public:
CallStackCapture();
~CallStackCapture();
[[nodiscard]] const CallStack* getSnapshot();
const DebugSymbols* getSymbols(FramePointer fp);
void printSnapshot(const CallStack* snapshot);
void logAll();
public:
class Iterator {
const CallStack* mSnapshot;
public:
explicit Iterator(const CallStack* start) : mSnapshot(start) {};
const CallStack* getCallStack() { return mSnapshot; }
bool operator==(const Iterator& in) const { return in.mSnapshot == mSnapshot; }
void operator++() { mSnapshot++; }
const Iterator& operator*() const { return *this; }
};
[[nodiscard]] Iterator begin() const { return Iterator(mBuff); }
[[nodiscard]] Iterator end() const { return Iterator(mBuff + mBuffLoad); }
private:
struct CallStackKey {
CallStack* cs;
bool operator==(const CallStackKey& in) const;
};
static void platformWriteStackTrace(CallStack* stack);
static void platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out);
[[nodiscard]] static ualni hashCallStack(CallStackKey key);
void platformInit();
void platformDeinit();
void clear();
private:
CallStack mErrorSnapshot;
ualni mBuffLen;
ualni mBuffLoad;
CallStack* mBuff;
Map<CallStackKey, CallStack*, DefaultAllocator, hashCallStack> mSnapshots;
Map<FramePointer, DebugSymbols> mSymbols;
};
}

View file

@ -1,44 +0,0 @@
#include "UnitTest++/UnitTest++.h"
#include "Callstack.hpp"
#include <cstdio>
using namespace tp;
void common(CallStackCapture& cs) { auto tmp = cs.getSnapshot(); }
void first(CallStackCapture& cs) {
common(cs);
common(cs);
common(cs);
}
void second(CallStackCapture& cs) {
common(cs);
common(cs);
common(cs);
common(cs);
}
void third(CallStackCapture& cs) {
common(cs);
common(cs);
}
void root(CallStackCapture& cs) {
first(cs);
second(cs);
third(cs);
}
SUITE(Utils) {
TEST(CallStackCapture) {
CallStackCapture callstack;
root(callstack);
callstack.logAll();
}
}
int main() { return UnitTest::RunAllTests(); }

View file

@ -11,7 +11,7 @@ file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp" "./applications/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_link_libraries(${PROJECT_NAME} PUBLIC Math Containers Allocators)
target_link_libraries(${PROJECT_NAME} PUBLIC Math Containers)
### -------------------------- Applications -------------------------- ###
add_executable(NumRecTrain applications/NumRecTraining.cpp)

View file

@ -1,9 +0,0 @@
#include "DataAnalysisCommon.hpp"
#include "Allocators.hpp"
#include "ContainersCommon.hpp"
#include "MathCommon.hpp"
namespace tp {
static ModuleManifest* deps[] = { &gModuleAllocators, nullptr };
ModuleManifest gModuleDataAnalysis = ModuleManifest("DataAnalysis", nullptr, nullptr, deps);
}

View file

@ -1,7 +1,6 @@
// #include "NewPlacement.hpp"
#include "FCNN.hpp"
#include "Utils.hpp"
#include <cmath>

View file

@ -1,7 +0,0 @@
#pragma once
#include "Module.hpp"
namespace tp {
extern ModuleManifest gModuleDataAnalysis;
}

View file

@ -1,7 +1,6 @@
#pragma once
#include "Buffer.hpp"
#include "DataAnalysisCommon.hpp"
namespace tp {
// Fully connected neural network

View file

@ -60,16 +60,5 @@ SUITE(FCNN) {
}
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleDataAnalysis, nullptr };
tp::ModuleManifest testModule("DataAnalysisTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
bool res = UnitTest::RunAllTests();
testModule.deinitialize();
return res;
return UnitTest::RunAllTests();
}

View file

@ -10,7 +10,7 @@ file(GLOB HEADERS "./public/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_include_directories(${PROJECT_NAME} PRIVATE ${BINDINGS_INCLUDE})
target_link_libraries(${PROJECT_NAME} PUBLIC Math Allocators)
target_link_libraries(${PROJECT_NAME} PUBLIC Math)
target_link_libraries(${PROJECT_NAME} PRIVATE ${BINDINGS_LIBS})
### -------------------------- Examples -------------------------- ###

View file

@ -21,18 +21,6 @@ public:
};
int main() {
ModuleManifest* deps[] = { &gModuleGraphics, nullptr };
ModuleManifest module("Eample", nullptr, nullptr, deps);
if (!module.initialize()) {
return 1;
}
{
ExampleApplication app;
app.run();
}
module.deinitialize();
ExampleApplication app;
app.run();
}

View file

@ -1,8 +1,6 @@
#include "Window.hpp"
#include "WindowContext.hpp"
#include "Allocators.hpp"
#include "Graphics.hpp"
// -------- Debug UI -------- //
@ -50,13 +48,9 @@ DebugGUI::~DebugGUI() {
}
void DebugGUI::drawBegin() {
tp::HeapAllocGlobal::startIgnore();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
tp::HeapAllocGlobal::stopIgnore();
}
void DebugGUI::drawEnd() {

View file

@ -1,7 +1,6 @@
#include "Window.hpp"
#include "WindowContext.hpp"
#include "Allocators.hpp"
#include "Rect.hpp"
@ -18,11 +17,6 @@
#include <GLFW/glfw3.h>
#include <cstdio>
namespace tp {
static ModuleManifest* deps[] = { &gModuleAllocators, nullptr };
ModuleManifest gModuleGraphics = ModuleManifest("Graphics", nullptr, nullptr, deps);
}
using namespace tp;
static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
@ -62,8 +56,6 @@ Window::~Window() {
}
Window* Window::createWindow(Vec2F size, const char* title) {
HeapAllocGlobal::startIgnore();
static int count = 1;
if (!count) {
printf("Window class is a singleton\n");
@ -82,7 +74,6 @@ Window* Window::createWindow(Vec2F size, const char* title) {
auto out = new Window(size, title);
HeapAllocGlobal::stopIgnore();
return out;
}

View file

@ -4,9 +4,6 @@
#include "EventHandler.hpp"
namespace tp {
extern ModuleManifest gModuleGraphics;
class Window {
class Context;

View file

@ -40,24 +40,10 @@ private:
LibraryWidget<EventHandler, Canvas> gui;
};
void runApp() {
int main() {
tp::GlobalGUIConfig config;
tp::gGlobalGUIConfig = &config;
LibraryViewer lib;
lib.run();
}
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleLibraryViewer, nullptr };
tp::ModuleManifest binModule("LibViewEntry", nullptr, nullptr, deps);
if (!binModule.initialize()) {
return 1;
}
runApp();
binModule.deinitialize();
}

View file

@ -6,11 +6,6 @@
#include "picojson.h"
#include <filesystem>
namespace tp {
static ModuleManifest* deps[] = { &gModuleGraphics, &gModuleStrings, &gModuleAllocators, nullptr };
ModuleManifest gModuleLibraryViewer = ModuleManifest("LibraryViewer", nullptr, nullptr, deps);
}
using namespace tp;
#define AS_STR (int1*) trackProperty.second.to_str().c_str()

View file

@ -10,10 +10,6 @@ tp::String getHome();
tp::String getSongLocalPath(SongId id);
SONG_FORMAT getSongFormat(const tp::String& path);
namespace tp {
extern ModuleManifest gModuleLibraryViewer;
}
class Track {
public:
Track() = default;

View file

@ -26,7 +26,7 @@ private:
int main() {
tp::ModuleManifest* deps[] = { &gModuleObjects, &gModuleGraphics, nullptr };
tp::ModuleManifest* deps[] = { &gModuleObjects, nullptr };
tp::ModuleManifest module("ObjectsTests", nullptr, nullptr, deps);
if (module.initialize()) {

View file

@ -4,8 +4,6 @@
#include "primitives/nullobject.h"
#include "HeapAllocatorGlobal.hpp"
#include <malloc.h>
namespace obj {
@ -26,7 +24,7 @@ namespace obj {
};
Object* ObjectMemAllocate(const ObjectType* type) {
ObjectMemHead* memh = (ObjectMemHead*) tp::HeapAllocGlobal::allocate(type->size + sizeof(ObjectMemHead));
ObjectMemHead* memh = (ObjectMemHead*) malloc(type->size + sizeof(ObjectMemHead));
if (!memh) {
return NULL;
}
@ -62,7 +60,7 @@ namespace obj {
bottom = memh->up;
}
tp::HeapAllocGlobal::deallocate(memh);
free(memh);
count--;
}

View file

@ -1,6 +1,4 @@
#include "HeapAllocatorGlobal.hpp"
#include "core/scriptsection.h"
using namespace obj;
@ -17,7 +15,7 @@ void set_script_head_store_adress(Script* in, tp::alni address) { ((script_data_
tp::alni get_script_head_store_adress(Script* in) { return ((script_data_head*) in - 1)->store_adress; }
Script* ScriptSection::createScript() {
auto sdhead = (script_data_head*) tp::HeapAllocGlobal::allocate(sizeof(script_data_head) + sizeof(Script));
auto sdhead = (script_data_head*) malloc(sizeof(script_data_head) + sizeof(Script));
auto out = (Script*) (sdhead + 1);
if (!sdhead) {
@ -39,7 +37,7 @@ void ScriptSection::delete_script(Script* script) {
script->~Script();
obj::NDO->destroy(script->mReadable);
tp::HeapAllocGlobal::deallocate((((script_data_head*) script) - 1));
free((((script_data_head*) script) - 1));
}
void ScriptSection::reference_script(Script* script) { (((script_data_head*) script) - 1)->refc++; }

View file

@ -27,7 +27,7 @@ obj::Object* ScopeStack::getLocalUtil(Scope& scope, tp::String* id) {
}
ScopeStack::ScopeStack() {
mBuff = (Scope*) tp::HeapAllocGlobal::allocate(sizeof(Scope) * MAX_STACK_SIZE);
mBuff = (Scope*) malloc(sizeof(Scope) * MAX_STACK_SIZE);
mIdx = 0;
mIterIdx = 0;
}
@ -80,4 +80,4 @@ obj::Object* ScopeStack::getLocal(tp::String& str) {
Scope* ScopeStack::getCurrentScope() { return &mBuff[mIdx - 1]; }
ScopeStack::~ScopeStack() { tp::HeapAllocGlobal::deallocate(mBuff); }
ScopeStack::~ScopeStack() { free(mBuff); }

View file

@ -34,7 +34,7 @@ void runApp() {
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleGraphics, &tp::gModuleStrings, &tp::gModuleWidgets, nullptr };
tp::ModuleManifest* deps[] = { &tp::gModuleStrings, nullptr };
tp::ModuleManifest binModule("LibViewEntry", nullptr, nullptr, deps);
if (!binModule.initialize()) {

View file

@ -5,7 +5,7 @@ file(GLOB SOURCES "./private/*.cpp")
file(GLOB HEADERS "./public/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_link_libraries(${PROJECT_NAME} PUBLIC Allocators Containers)
target_link_libraries(${PROJECT_NAME} PUBLIC Containers)
### -------------------------- Tests -------------------------- ###
enable_testing()

View file

@ -1,6 +1,5 @@
#include "Strings.hpp"
#include "Allocators.hpp"
#include "Logging.hpp"
using namespace tp;
@ -12,6 +11,6 @@ bool initialize(const ModuleManifest*) {
void deinitialize(const ModuleManifest*) { Logger::deinitializeGlobal(); }
static tp::ModuleManifest* sModuleDependencies[] = { &tp::gModuleAllocators, nullptr };
static tp::ModuleManifest* sModuleDependencies[] = { nullptr };
ModuleManifest tp::gModuleStrings = ModuleManifest("Strings", initialize, deinitialize, sModuleDependencies);

View file

@ -1,10 +1,10 @@
#pragma once
#include "Allocators.hpp"
#include "Buffer.hpp"
#include "Utils.hpp"
#include <cstdio>
#include <cstdlib>
#include <new>
namespace tp {

View file

@ -1,6 +1,5 @@
#pragma once
#include "Allocators.hpp"
#include "StringLogic.hpp"
namespace tp {
@ -81,7 +80,7 @@ namespace tp {
MAX_BOOL_STRING_LENGTH = 10,
MAX_FLOAT_STRING_LENGTH = 10,
};
static PoolAlloc<StringData<tChar>, STRINGS_POOL_SIZE> sStringPool;
static Data sNullString;
private:
@ -100,16 +99,18 @@ namespace tp {
incReference(mData);
}
void* alloc() { return malloc(sizeof(StringData<tChar>)); }
// Creates new string data from raw data pointer.
// Does not own string buffer - string buffer will not be freed. Initializes as const memory.
StringTemplate(const tChar* raw) {
mData = new (sStringPool.allocate(0)) StringData(raw, true);
mData = new (alloc()) StringData(raw, true);
incReference(mData);
}
// Copies raw data and claims ownership over it
StringTemplate(tChar* raw) {
mData = new (sStringPool.allocate(0)) StringData(raw);
mData = new (alloc()) StringData(raw);
incReference(mData);
}
@ -123,7 +124,7 @@ namespace tp {
dp->mReferenceCount--;
if (!dp->mReferenceCount) {
mData->~StringData();
sStringPool.deallocate(mData);
free(mData);
}
}
@ -150,7 +151,7 @@ namespace tp {
// We have no rights to modify if someone references that memory too
// So we need to create new copy of StringData
if (mData->mReferenceCount > 1) {
mData = new (sStringPool.allocate(0)) StringData(mData->mBuff);
mData = new (alloc()) StringData(mData->mBuff);
incReference(mData);
return;
}
@ -158,7 +159,7 @@ namespace tp {
// Also if initial raw data was marked as const - create copy of raw data
// Note - raw data will be lost at this point if no other record of such is stored
if (mData->mIsConst) {
mData = new (sStringPool.allocate(0)) StringData(mData->mBuff);
mData = new (alloc()) StringData(mData->mBuff);
incReference(mData);
}
}
@ -182,21 +183,21 @@ namespace tp {
explicit StringTemplate(alni val) {
tChar raw[MAX_INT_STRING_LENGTH];
Logic::convertValueToString(val, raw, MAX_INT_STRING_LENGTH);
mData = new (sStringPool.allocate(0)) StringData(raw);
mData = new (alloc()) StringData(raw);
incReference(mData);
}
explicit StringTemplate(alnf val) {
tChar raw[MAX_INT_STRING_LENGTH];
Logic::convertValueToString(val, raw, MAX_FLOAT_STRING_LENGTH);
mData = new (sStringPool.allocate(0)) StringData(raw);
mData = new (alloc()) StringData(raw);
incReference(mData);
}
explicit StringTemplate(bool val) {
tChar raw[MAX_INT_STRING_LENGTH];
Logic::convertValueToString(val, raw, MAX_BOOL_STRING_LENGTH);
mData = new (sStringPool.allocate(0)) StringData(raw);
mData = new (alloc()) StringData(raw);
incReference(mData);
}
@ -260,9 +261,6 @@ namespace tp {
[[nodiscard]] bool getIsConstFlag() const { return mData->mIsConst; }
};
template <typename tChar>
PoolAlloc<StringData<tChar>, StringTemplate<tChar>::STRINGS_POOL_SIZE> StringTemplate<tChar>::sStringPool;
template <typename tChar>
StringData<tChar> StringTemplate<tChar>::sNullString;

View file

@ -23,23 +23,11 @@ private:
};
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleWidgets, nullptr };
tp::ModuleManifest binModule("Chat", nullptr, nullptr, deps);
if (!binModule.initialize()) {
return 1;
}
GlobalGUIConfig mConfig;
gGlobalGUIConfig = &mConfig;
{
GlobalGUIConfig mConfig;
gGlobalGUIConfig = &mConfig;
{
ExampleGUI gui;
gui.run();
}
ExampleGUI gui;
gui.run();
}
binModule.deinitialize();
}

View file

@ -5,7 +5,4 @@
namespace tp {
GlobalGUIConfig* gGlobalGUIConfig = nullptr;
ModuleManifest* deps[] = { &gModuleGraphics, &gModuleStrings, nullptr };
ModuleManifest gModuleWidgets = ModuleManifest("Widgets", nullptr, nullptr, deps);
}

View file

@ -9,8 +9,6 @@
namespace tp {
extern ModuleManifest gModuleWidgets;
struct WidgetConfig {
struct Node {
enum Type { NONE, VAL, COL, REF };