Formatting code

This commit is contained in:
Ilusha 2023-06-30 14:02:55 +00:00
parent 6dc64ce76b
commit 13a8f07e32
37 changed files with 2242 additions and 2281 deletions

View file

@ -107,7 +107,7 @@ bool ChunkAlloc::isFull() const { return !mNFreeBlocks; }
bool ChunkAlloc::isEmpty() const { return mNFreeBlocks == mNBlocks; } bool ChunkAlloc::isEmpty() const { return mNFreeBlocks == mNBlocks; }
ChunkAlloc::~ChunkAlloc() { ChunkAlloc::~ChunkAlloc() {
// TODO : check for leaks // TODO : check for leaks
if (mOwnBuff) { if (mOwnBuff) {
HeapAllocGlobal::deallocate(mBuff); HeapAllocGlobal::deallocate(mBuff);
} }

View file

@ -61,7 +61,7 @@ void HeapAlloc::deallocate(void* aPtr) {
} }
} }
HeapAllocGlobal::deallocate(head); HeapAllocGlobal::deallocate(head);
} }
HeapAlloc::~HeapAlloc() { HeapAlloc::~HeapAlloc() {
@ -69,7 +69,7 @@ HeapAlloc::~HeapAlloc() {
DEBUG_BREAK("Destruction of not freed Allocator"); DEBUG_BREAK("Destruction of not freed Allocator");
#ifdef MEM_STACK_TRACE #ifdef MEM_STACK_TRACE
// TODO : log leaks and free them up // TODO : log leaks and free them up
#endif #endif
} }
} }

View file

@ -140,7 +140,7 @@ HeapAllocGlobal::~HeapAllocGlobal() {
DEBUG_BREAK("Destruction of not freed Allocator"); DEBUG_BREAK("Destruction of not freed Allocator");
#ifdef MEM_STACK_TRACE #ifdef MEM_STACK_TRACE
// TODO: log leaks // TODO: log leaks
#endif #endif
} }
} }

View file

@ -15,7 +15,7 @@ namespace tp {
void* allocate(); void* allocate();
void deallocate(void* aPtr); void deallocate(void* aPtr);
[[nodiscard]] bool isFull() const; [[nodiscard]] bool isFull() const;
[[nodiscard]] bool isEmpty() const; [[nodiscard]] bool isEmpty() const;
~ChunkAlloc(); ~ChunkAlloc();

View file

@ -12,7 +12,7 @@ namespace tp {
#endif #endif
static void* allocate(ualni aBlockSize); static void* allocate(ualni aBlockSize);
static void deallocate(void* aPtr); static void deallocate(void* aPtr);
~HeapAllocGlobal(); ~HeapAllocGlobal();
}; };
}; };

View file

@ -19,287 +19,284 @@ int main() {
} }
struct test_struct { struct test_struct {
tp::alni val = 0; tp::alni val = 0;
test_struct() { val = 1; } test_struct() { val = 1; }
~test_struct() { val = -1; } ~test_struct() { val = -1; }
bool operator==(const test_struct& in) { return in.val == val; } bool operator==(const test_struct& in) { return in.val == val; }
}; };
template <tp::alni size> template <tp::alni size>
struct allocator_test { struct allocator_test {
test_struct data[size]; test_struct data[size];
bool is_allocated[size]; bool is_allocated[size];
tp::alni n_loaded = 0; tp::alni n_loaded = 0;
test_struct* allocations[size]; test_struct* allocations[size];
tp::AbstractAllocator* alloc; tp::AbstractAllocator* alloc;
tp::AbstractAllocator* parent_alloc; tp::AbstractAllocator* parent_alloc;
const char* allocator_name = NULL; const char* allocator_name = NULL;
tp::alni rand_idx(bool state) { tp::alni rand_idx(bool state) {
RAND: RAND:
tp::alni idx = (tp::alni)(tp::randf() * (size + 1)); tp::alni idx = (tp::alni)(tp::randf() * (size + 1));
CLAMP(idx, 0, size - 1); CLAMP(idx, 0, size - 1);
if (state == is_allocated[idx]) { if (state == is_allocated[idx]) {
goto RAND; goto RAND;
} }
return idx; return idx;
} }
allocator_test(tp::AbstractAllocator* palloc, const char* pallocator_name, allocator_test(tp::AbstractAllocator* palloc, const char* pallocator_name, tp::AbstractAllocator* p_parent_alloc) {
tp::AbstractAllocator* p_parent_alloc) { allocator_name = pallocator_name;
allocator_name = pallocator_name; parent_alloc = p_parent_alloc;
parent_alloc = p_parent_alloc; alloc = palloc;
alloc = palloc; for (tp::alni i = 0; i < size; i++) {
for (tp::alni i = 0; i < size; i++) { RAND:
RAND: tp::alni val = tp::alni(tp::randf() * (size + 100.f));
tp::alni val = tp::alni(tp::randf() * (size + 100.f)); for (tp::alni check_idx = 0; check_idx < size; check_idx++) {
for (tp::alni check_idx = 0; check_idx < size; check_idx++) { if (data[check_idx].val == val) {
if (data[check_idx].val == val) { goto RAND;
goto RAND; }
} }
}
data[i].val = val; data[i].val = val;
is_allocated[i] = false; is_allocated[i] = false;
allocations[i] = 0; allocations[i] = 0;
} }
} }
void verify_integrity() { void verify_integrity() {
// verify data integrity // verify data integrity
for (tp::alni i = 0; i < size; i++) { for (tp::alni i = 0; i < size; i++) {
if (is_allocated[i]) { if (is_allocated[i]) {
assert(*allocations[i] == data[i] && "data is currupted\n"); assert(*allocations[i] == data[i] && "data is currupted\n");
} }
} }
if (alloc->isWrapSupport()) assert(!alloc->isWrapCorrupted()); if (alloc->isWrapSupport()) assert(!alloc->isWrapCorrupted());
if (parent_alloc && parent_alloc->isWrapSupport()) if (parent_alloc && parent_alloc->isWrapSupport())
assert(!parent_alloc->isWrapCorrupted()); assert(!parent_alloc->isWrapCorrupted());
verify_sizes(); verify_sizes();
} }
void verify_sizes() { void verify_sizes() {
return; return;
#ifdef MEM_TRACE #ifdef MEM_TRACE
assert(alloc->sizeInuse() == n_loaded * sizeof(test_struct) && assert(alloc->sizeInuse() == n_loaded * sizeof(test_struct) &&
"invalid inuse size\n"); "invalid inuse size\n");
assert(alloc->sizeReserved() >= n_loaded * (tp::alni)sizeof(test_struct) && assert(alloc->sizeReserved() >= n_loaded * (tp::alni)sizeof(test_struct) &&
"invalid reserved size\n"); "invalid reserved size\n");
#endif #endif
} }
void load_item(tp::alni idx) { void load_item(tp::alni idx) {
if (!is_allocated[idx]) { if (!is_allocated[idx]) {
allocations[idx] = new (alloc) test_struct(); allocations[idx] = new (alloc) test_struct();
assert(allocations[idx] && "allocator returned NULL"); assert(allocations[idx] && "allocator returned NULL");
allocations[idx]->val = data[idx].val; allocations[idx]->val = data[idx].val;
is_allocated[idx] = true; is_allocated[idx] = true;
n_loaded++; n_loaded++;
verify_integrity(); verify_integrity();
} }
} }
void unload_item(tp::alni idx) { void unload_item(tp::alni idx) {
if (is_allocated[idx]) { if (is_allocated[idx]) {
verify_integrity(); verify_integrity();
delete allocations[idx]; delete allocations[idx];
is_allocated[idx] = false; is_allocated[idx] = false;
n_loaded--; n_loaded--;
verify_integrity(); verify_integrity();
} }
} }
void change_states(tp::Range<tp::alni> rg, bool state, bool reversed = false, void change_states(tp::Range<tp::alni> rg, bool state, bool reversed = false, bool random = false) {
bool random = false) { for (auto i : rg) {
for (auto i : rg) { tp::alni idx = i;
tp::alni idx = i;
if (random) { if (random) {
idx = rand_idx(state); idx = rand_idx(state);
} }
else if (reversed) { else if (reversed) {
idx = size - i - 1; idx = size - i - 1;
} }
(state) ? load_item(idx) : unload_item(idx); (state) ? load_item(idx) : unload_item(idx);
} }
} }
// full down-up load then up-down unload // full down-up load then up-down unload
void test1() { void test1() {
change_states({ 0, size }, 1); change_states({ 0, size }, 1);
change_states({ 0, size }, 0, true); change_states({ 0, size }, 0, true);
} }
// full down-up load then down-up unload // full down-up load then down-up unload
void test2() { void test2() {
change_states({ 0, size }, 1); change_states({ 0, size }, 1);
change_states({ 0, size }, 0); change_states({ 0, size }, 0);
} }
// full random load then random unload // full random load then random unload
void test3() { void test3() {
change_states({ 0, size }, 1, 0, 1); change_states({ 0, size }, 1, 0, 1);
change_states({ 0, size }, 0, 0, 1); change_states({ 0, size }, 0, 0, 1);
} }
// multipul tests 1-3 // multipul tests 1-3
void test4() { void test4() {
test1(); test1();
test1(); test1();
test2(); test2();
test2(); test2();
test3(); test3();
test3(); test3();
} }
static tp::alnf sineupf(tp::alnf asize, tp::alnf x, bool reverse) { static tp::alnf sineupf(tp::alnf asize, tp::alnf x, bool reverse) {
tp::alnf end = 4 * PI; tp::alnf end = 4 * PI;
tp::alnf a = (2 / 7.f) * asize; tp::alnf a = (2 / 7.f) * asize;
tp::alnf b = end / asize; tp::alnf b = end / asize;
tp::alni c = ((-1 * reverse) + (1 * !reverse)); tp::alni c = ((-1 * reverse) + (1 * !reverse));
tp::alnf c1 = (x - (end * reverse)) / b; tp::alnf c1 = (x - (end * reverse)) / b;
tp::alnf c2 = (a * sin(x - (end * reverse))); tp::alnf c2 = (a * sin(x - (end * reverse)));
tp::alnf out = c1 + c2; tp::alnf out = c1 + c2;
return c * out; return c * out;
} }
// sin load & sin unload with ~1/2 drop factor // sin load & sin unload with ~1/2 drop factor
void test5() { void test5() {
tp::alnf end = 4 * PI; tp::alnf end = 4 * PI;
tp::alnf step = end / 4.f; tp::alnf step = end / 4.f;
for (char i = 0; i < 2; i++) { for (char i = 0; i < 2; i++) {
for (tp::alnf x = 0; x <= end; x += step) { for (tp::alnf x = 0; x <= end; x += step) {
tp::alni target_alloc_count = (tp::alni)ceil(sineupf(size, x, i)); tp::alni target_alloc_count = (tp::alni)ceil(sineupf(size, x, i));
CLAMP(target_alloc_count, 0, size); CLAMP(target_alloc_count, 0, size);
while (n_loaded > target_alloc_count) { while (n_loaded > target_alloc_count) {
unload_item(rand_idx(0)); unload_item(rand_idx(0));
} }
while (n_loaded < target_alloc_count) { while (n_loaded < target_alloc_count) {
load_item(rand_idx(1)); load_item(rand_idx(1));
} }
} }
} }
} }
#ifdef MEM_WRAP #ifdef MEM_WRAP
void check_wrap(tp::alni offset, bool after) { void check_wrap(tp::alni offset, bool after) {
CLAMP(offset, 1, WRAP_LEN); CLAMP(offset, 1, WRAP_LEN);
test_struct* ts = allocations[rand_idx(0)]; test_struct* ts = allocations[rand_idx(0)];
tp::alni shift = (sizeof(test_struct) * after) + (offset - 1) * after - tp::alni shift = (sizeof(test_struct) * after) + (offset - 1) * after -
offset * (!after); offset * (!after);
tp::uint1* address = (((tp::uint1*)ts) + shift); tp::uint1* address = (((tp::uint1*)ts) + shift);
tp::uint1 val = *address; tp::uint1 val = *address;
*address = 5; *address = 5;
assert(alloc->isWrapCorrupted()); assert(alloc->isWrapCorrupted());
*address = val; *address = val;
}
#endif
// mem guards test
void test6() {
change_states({ 0, size }, 1);
#ifdef MEM_WRAP
for (tp::alni after = 0; after < 2; after++) {
for (tp::alni offset = 1; offset <= WRAP_LEN; offset++) {
check_wrap(offset, after);
}
} }
#endif #endif
// mem guards test change_states({ 0, size }, 0);
void test6() { }
change_states({ 0, size }, 1);
#ifdef MEM_WRAP void run_tests() {
for (tp::alni after = 0; after < 2; after++) { try {
for (tp::alni offset = 1; offset <= WRAP_LEN; offset++) { test1();
check_wrap(offset, after); test2();
test3();
test4();
test5();
if (alloc->isWrapSupport()) {
test6();
}
printf("%s - passed\n", allocator_name);
if (!alloc->isWrapSupport()) {
printf(" WARNING: %s has no wrap support!! \n", allocator_name);
} }
} }
#endif catch (...) {
printf("%s - failed\n", allocator_name);
change_states({ 0, size }, 0); }
} }
void run_tests() {
try {
test1();
test2();
test3();
test4();
test5();
if (alloc->isWrapSupport()) {
test6();
}
printf("%s - passed\n", allocator_name);
if (!alloc->isWrapSupport()) {
printf(" WARNING: %s has no wrap support!! \n", allocator_name);
}
}
catch (...) {
printf("%s - failed\n", allocator_name);
}
}
}; };
void heap_alloc_test() { void heap_alloc_test() {
tp::alloc_init(); { tp::alloc_init(); {
try { try {
allocator_test<150> hatest(tp::heapalloc, "heap allocator", NULL); allocator_test<150> hatest(tp::heapalloc, "heap allocator", NULL);
hatest.run_tests(); hatest.run_tests();
} }
catch (...) { catch (...) {
printf("heap alloc failed\n"); printf("heap alloc failed\n");
} }
} tp::alloc_uninit(); } tp::alloc_uninit();
} }
void chunk_alloc_test() { void chunk_alloc_test() {
tp::alloc_init(); { tp::alloc_init(); {
try { try {
tp::ChunkAlloc calloc(sizeof(test_struct), 50); tp::ChunkAlloc calloc(sizeof(test_struct), 50);
allocator_test<50> ca_test(&calloc, "chunk allocator", tp::heapalloc); allocator_test<50> ca_test(&calloc, "chunk allocator", tp::heapalloc);
ca_test.run_tests(); ca_test.run_tests();
} }
catch (...) { catch (...) {
printf("chunk alloc failed\n"); printf("chunk alloc failed\n");
} }
} tp::alloc_uninit(); } tp::alloc_uninit();
} }
void pool_alloc_test() { void pool_alloc_test() {
tp::alloc_init(); { tp::alloc_init(); {
try { try {
tp::PoolAlloc palloc(sizeof(test_struct), 50); tp::PoolAlloc palloc(sizeof(test_struct), 50);
allocator_test<150> pa_test(&palloc, "pool allocator", tp::heapalloc); allocator_test<150> pa_test(&palloc, "pool allocator", tp::heapalloc);
pa_test.run_tests(); pa_test.run_tests();
} }
catch (...) { catch (...) {
printf("chunk alloc failed\n"); printf("chunk alloc failed\n");
} }
} tp::alloc_uninit(); } tp::alloc_uninit();
} }
void allocators_test() { void allocators_test() {
printf("running tests on alocators:\n");
printf("running tests on alocators:\n"); heap_alloc_test();
chunk_alloc_test();
heap_alloc_test(); pool_alloc_test();
chunk_alloc_test();
pool_alloc_test();
} }
CROSSPLATFORM_MAIN; CROSSPLATFORM_MAIN;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
tp::print_env_info(); tp::print_env_info();
allocators_test(); allocators_test();
} }

View file

@ -5,14 +5,14 @@
namespace tp { namespace tp {
static ModuleManifest* sModuleDependencies[] = { &gModuleBase,nullptr }; static ModuleManifest* sModuleDependencies[] = { &gModuleBase,nullptr };
ModuleManifest gModuleContainers = ModuleManifest("Containers", nullptr, nullptr, sModuleDependencies); ModuleManifest gModuleContainers = ModuleManifest("Containers", nullptr, nullptr, sModuleDependencies);
void* DefaultAllocator::allocate(ualni size) { void* DefaultAllocator::allocate(ualni size) {
return malloc(size); return malloc(size);
} }
void DefaultAllocator::deallocate(void* p) { void DefaultAllocator::deallocate(void* p) {
free(p); free(p);
} }
} }

View file

@ -9,88 +9,88 @@ namespace tp {
NumericType val; NumericType val;
AvlNumericKey() = default; AvlNumericKey() = default;
AvlNumericKey(NumericType val) : val(val) {} AvlNumericKey(NumericType val) : val(val) {}
inline bool descentRight(AvlNumericKey in) const { return in.val > val; } inline bool descentRight(AvlNumericKey in) const { return in.val > val; }
inline bool descentLeft(AvlNumericKey in) const { return in.val < val; } inline bool descentLeft(AvlNumericKey in) const { return in.val < val; }
inline bool exactNode(AvlNumericKey in) const { return in.val == val; } inline bool exactNode(AvlNumericKey in) const { return in.val == val; }
inline AvlNumericKey getFindKey(/**/) const { return *this; } inline AvlNumericKey getFindKey(/**/) const { return *this; }
inline AvlNumericKey keyInRightSubtree(AvlNumericKey in) const { return in; } inline AvlNumericKey keyInRightSubtree(AvlNumericKey in) const { return in; }
inline AvlNumericKey keyInLeftSubtree(AvlNumericKey in) const { return in; } inline AvlNumericKey keyInLeftSubtree(AvlNumericKey in) const { return in; }
inline void updateTreeCacheCallBack() {} inline void updateTreeCacheCallBack() {}
}; };
template <typename Key, typename Data, class Allocator = DefaultAllocator> template <typename Key, typename Data, class Allocator = DefaultAllocator>
class AvlTree { class AvlTree {
typedef SelCopyArg<Key> KeyArg; typedef SelCopyArg<Key> KeyArg;
typedef SelCopyArg<Data> DataArg; typedef SelCopyArg<Data> DataArg;
public: public:
class Node { class Node {
friend AvlTree; friend AvlTree;
private: private:
Node(KeyArg aKey, DataArg aData) : key(aKey), data(aData) {} Node(KeyArg aKey, DataArg aData) : key(aKey), data(aData) {}
public: public:
Data data; Data data;
Key key; Key key;
private: private:
Node* mLeft = nullptr; Node* mLeft = nullptr;
Node* mRight = nullptr; Node* mRight = nullptr;
Node* mParent = nullptr; Node* mParent = nullptr;
ualni mHeight = 0; ualni mHeight = 0;
private: private:
inline bool descentRight(KeyArg aKey) const { return key.descentRight(aKey); } inline bool descentRight(KeyArg aKey) const { return key.descentRight(aKey); }
inline bool descentLeft(KeyArg aKey) const { return key.descentLeft(aKey); } inline bool descentLeft(KeyArg aKey) const { return key.descentLeft(aKey); }
inline bool exactNode(KeyArg aKey) const { return key.exactNode(aKey); } inline bool exactNode(KeyArg aKey) const { return key.exactNode(aKey); }
inline KeyArg getFindKey(const Node* node = nullptr) const { return key.getFindKey(/*node*/); } inline KeyArg getFindKey(const Node* node = nullptr) const { return key.getFindKey(/*node*/); }
inline KeyArg keyInRightSubtree(KeyArg aKey) const { return key.keyInRightSubtree(aKey); } inline KeyArg keyInRightSubtree(KeyArg aKey) const { return key.keyInRightSubtree(aKey); }
inline KeyArg keyInLeftSubtree(KeyArg aKey) const { return key.keyInLeftSubtree(aKey); } inline KeyArg keyInLeftSubtree(KeyArg aKey) const { return key.keyInLeftSubtree(aKey); }
inline void updateTreeCacheCallBack() { key.updateTreeCacheCallBack(); } inline void updateTreeCacheCallBack() { key.updateTreeCacheCallBack(); }
}; };
private: private:
Node* mRoot = nullptr; Node* mRoot = nullptr;
ualni mSize = 0; ualni mSize = 0;
Allocator mAlloc; Allocator mAlloc;
private: private:
inline void deleteNode(Node* node) { inline void deleteNode(Node* node) {
node->~Node(); node->~Node();
mAlloc.deallocate(node); mAlloc.deallocate(node);
} }
inline Node* newNode(KeyArg key, DataArg data) { inline Node* newNode(KeyArg key, DataArg data) {
return new (mAlloc.allocate(sizeof(Node))) Node(key, data); return new (mAlloc.allocate(sizeof(Node))) Node(key, data);
} }
inline void injectNodeInstead(Node* place, Node* inject) { inline void injectNodeInstead(Node* place, Node* inject) {
// TODO : swap instead of copy // TODO : swap instead of copy
place->data = inject->data; place->data = inject->data;
place->key = inject->key; place->key = inject->key;
} }
inline alni getNodeHeight(const Node* node) const { inline alni getNodeHeight(const Node* node) const {
return node ? node->mHeight : -1; return node ? node->mHeight : -1;
} }
// returns new head // returns new head
Node* rotateLeft(Node* pivot) { Node* rotateLeft(Node* pivot) {
DEBUG_ASSERT(pivot); DEBUG_ASSERT(pivot);
Node* const head = pivot; Node* const head = pivot;
Node* const right = pivot->mRight; Node* const right = pivot->mRight;
Node* const right_left = right->mLeft; Node* const right_left = right->mLeft;
Node* const parent = pivot->mParent; Node* const parent = pivot->mParent;
// parents // parents
if (right_left) right_left->mParent = head; if (right_left) right_left->mParent = head;
@ -112,13 +112,13 @@ namespace tp {
return right; return right;
} }
Node* rotateRight(Node* pivot) { Node* rotateRight(Node* pivot) {
DEBUG_ASSERT(pivot); DEBUG_ASSERT(pivot);
Node* const head = pivot; Node* const head = pivot;
Node* const left = pivot->mLeft; Node* const left = pivot->mLeft;
Node* const left_right = left->mRight; Node* const left_right = left->mRight;
Node* const parent = pivot->mParent; Node* const parent = pivot->mParent;
// parents // parents
if (left_right) left_right->mParent = head; if (left_right) left_right->mParent = head;
@ -141,12 +141,12 @@ namespace tp {
} }
// recursively returns valid left or right child or root // recursively returns valid left or right child or root
Node* insertUtil(Node* head, KeyArg key, DataArg data) { Node* insertUtil(Node* head, KeyArg key, DataArg data) {
Node* insertedNode; Node* insertedNode;
if (head == nullptr) { if (head == nullptr) {
mSize++; mSize++;
Node* out = newNode(key, data); Node* out = newNode(key, data);
out->updateTreeCacheCallBack(); out->updateTreeCacheCallBack();
return out; return out;
@ -155,14 +155,14 @@ namespace tp {
return head; return head;
} }
else if (head->descentRight(key)) { else if (head->descentRight(key)) {
insertedNode = insertUtil(head->mRight, head->keyInRightSubtree(key), data); insertedNode = insertUtil(head->mRight, head->keyInRightSubtree(key), data);
head->mRight = insertedNode; head->mRight = insertedNode;
insertedNode->mParent = head; insertedNode->mParent = head;
} }
else { else {
insertedNode = insertUtil(head->mLeft, head->keyInLeftSubtree(key), data); insertedNode = insertUtil(head->mLeft, head->keyInLeftSubtree(key), data);
head->mLeft = insertedNode; head->mLeft = insertedNode;
insertedNode->mParent = head; insertedNode->mParent = head;
} }
// update height // update height
@ -194,31 +194,31 @@ namespace tp {
return head; return head;
} }
Node* removeUtil(Node* head, KeyArg key) { Node* removeUtil(Node* head, KeyArg key) {
if (head == nullptr) return head; if (head == nullptr) return head;
if (head->exactNode(key)) { if (head->exactNode(key)) {
if (head->mRight && head->mLeft) { if (head->mRight && head->mLeft) {
Node* min = minNode(head->mRight); Node* min = minNode(head->mRight);
auto const& newKey = min->getFindKey(head->mRight); auto const& newKey = min->getFindKey(head->mRight);
injectNodeInstead(head, min); injectNodeInstead(head, min);
head->mRight = removeUtil(head->mRight, newKey); head->mRight = removeUtil(head->mRight, newKey);
} }
else if (head->mRight) { else if (head->mRight) {
injectNodeInstead(head, head->mRight); injectNodeInstead(head, head->mRight);
deleteNode(head->mRight); deleteNode(head->mRight);
head->mRight = nullptr; head->mRight = nullptr;
mSize--; mSize--;
} }
else if (head->mLeft) { else if (head->mLeft) {
injectNodeInstead(head, head->mLeft); injectNodeInstead(head, head->mLeft);
deleteNode(head->mLeft); deleteNode(head->mLeft);
head->mLeft = nullptr; head->mLeft = nullptr;
mSize--; mSize--;
} }
else { else {
deleteNode(head); deleteNode(head);
mSize--; mSize--;
head = nullptr; head = nullptr;
} }
} }
@ -229,7 +229,7 @@ namespace tp {
head->mLeft = removeUtil(head->mLeft, head->keyInLeftSubtree(key)); head->mLeft = removeUtil(head->mLeft, head->keyInLeftSubtree(key));
} }
if (head == nullptr) return head; if (head == nullptr) return head;
head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft)); head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft));
alni balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft); alni balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
@ -268,7 +268,7 @@ namespace tp {
return mSize; return mSize;
} }
Node* head() const { Node* head() const {
return this->mRoot; return this->mRoot;
} }
@ -282,24 +282,24 @@ namespace tp {
if (mRoot) mRoot->mParent = nullptr; if (mRoot) mRoot->mParent = nullptr;
} }
Node* maxNode(Node* head) const { Node* maxNode(Node* head) const {
if (!head) return nullptr;
while (head->mRight != nullptr) {
head = head->mRight;
}
return head;
}
Node* minNode(Node* head) const {
if (!head) return nullptr; if (!head) return nullptr;
while (head->mLeft != nullptr) { while (head->mRight != nullptr) {
head = head->mLeft; head = head->mRight;
} }
return head; return head;
} }
Node* find(KeyArg key) const { Node* minNode(Node* head) const {
Node* iter = mRoot; if (!head) return nullptr;
while (head->mLeft != nullptr) {
head = head->mLeft;
}
return head;
}
Node* find(KeyArg key) const {
Node* iter = mRoot;
while (true) { while (true) {
if (!iter) return nullptr; if (!iter) return nullptr;
if (iter->exactNode(key)) return iter; if (iter->exactNode(key)) return iter;
@ -313,61 +313,61 @@ namespace tp {
} }
} }
Node* findLessOrEq(KeyArg key) const { Node* findLessOrEq(KeyArg key) const {
Node* iter = mRoot; Node* iter = mRoot;
while (true) { while (true) {
if (!iter) return nullptr; if (!iter) return nullptr;
if (iter->exactNode(key)) return iter; if (iter->exactNode(key)) return iter;
if (iter->descentLeft(key)) { if (iter->descentLeft(key)) {
if (iter->mLeft) { if (iter->mLeft) {
key = iter->keyInLeftSubtree(key); key = iter->keyInLeftSubtree(key);
iter = iter->mLeft; iter = iter->mLeft;
} else { } else {
return iter; return iter;
} }
} else { } else {
if (iter->mRight) { if (iter->mRight) {
key = iter->keyInRightSubtree(key); key = iter->keyInRightSubtree(key);
iter = iter->mRight; iter = iter->mRight;
} else { } else {
return iter; return iter;
} }
} }
} }
} }
// returns first invalid node // returns first invalid node
const Node* findInvalidNode(const Node* head) const { const Node* findInvalidNode(const Node* head) const {
if (head == nullptr) return nullptr; if (head == nullptr) return nullptr;
if (head->mLeft) { if (head->mLeft) {
// TODO: incomplete test // TODO: incomplete test
if (!head->descentLeft(head->mLeft->getFindKey(head))) return head; if (!head->descentLeft(head->mLeft->getFindKey(head))) return head;
if (head->mLeft->mParent != head) return head; if (head->mLeft->mParent != head) return head;
if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) return head; if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) return head;
} }
if (head->mRight) { if (head->mRight) {
if (!head->descentRight(head->mRight->getFindKey(head))) return head; if (!head->descentRight(head->mRight->getFindKey(head))) return head;
if (head->mRight->mParent != head) return head; if (head->mRight->mParent != head) return head;
if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) return head; if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) return head;
} }
if (head->mLeft && head->mRight) { if (head->mLeft && head->mRight) {
if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) return head; if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) return head;
} }
int balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft); int balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
if (balance > 1 || balance < -1) return head; if (balance > 1 || balance < -1) return head;
const Node* ret = findInvalidNode(head->mRight); const Node* ret = findInvalidNode(head->mRight);
if (ret) return ret; if (ret) return ret;
return findInvalidNode(head->mLeft); return findInvalidNode(head->mLeft);
} }
bool isValid() { return findInvalidNode(head()) == nullptr; } bool isValid() { return findInvalidNode(head()) == nullptr; }
}; };
} }

View file

@ -4,23 +4,23 @@
#include "Module.hpp" #include "Module.hpp"
namespace tp { namespace tp {
extern ModuleManifest gModuleContainers; extern ModuleManifest gModuleContainers;
class DefaultAllocator { class DefaultAllocator {
public: public:
DefaultAllocator() = default; DefaultAllocator() = default;
static void *allocate(ualni); static void *allocate(ualni);
static void deallocate(void *); static void deallocate(void *);
}; };
class DefaultSaverLoader { class DefaultSaverLoader {
public: public:
DefaultSaverLoader() = default; DefaultSaverLoader() = default;
template<typename Type> template<typename Type>
static void write(const Type&) {} static void write(const Type&) {}
template<typename Type> template<typename Type>
static void read(Type&) {} static void read(Type&) {}
}; };
} }

View file

@ -7,92 +7,92 @@
namespace tp { namespace tp {
template <typename Type, class Allocator = DefaultAllocator> template <typename Type, class Allocator = DefaultAllocator>
class List { class List {
typedef SelCopyArg<Type> TypeArg; typedef SelCopyArg<Type> TypeArg;
typedef ualni Index; typedef ualni Index;
public: public:
struct Node { struct Node {
Type data; Type data;
Node* next = nullptr; Node* next = nullptr;
Node* prev = nullptr; Node* prev = nullptr;
Node() = default; Node() = default;
explicit Node(TypeArg p_data) : data(p_data) {} explicit Node(TypeArg p_data) : data(p_data) {}
Type& operator->() { return data; } Type& operator->() { return data; }
}; };
class IteratorPointer { class IteratorPointer {
protected: protected:
Node* mIter; Node* mIter;
public: public:
IteratorPointer() = default; IteratorPointer() = default;
Type& operator->() { return (mIter->data); } Type& operator->() { return (mIter->data); }
const Type& operator->() const { return (mIter->data); } const Type& operator->() const { return (mIter->data); }
}; };
class IteratorReference { class IteratorReference {
protected: protected:
Node* mIter; Node* mIter;
public: public:
IteratorReference() = default; IteratorReference() = default;
Type* operator->() { return &(mIter->data); } Type* operator->() { return &(mIter->data); }
const Type* operator->() const { return &(mIter->data); } const Type* operator->() const { return &(mIter->data); }
}; };
class Iterator : public TypeSelect<TypeTraits<Type>::isPointer, IteratorPointer, IteratorReference>::Result { class Iterator : public TypeSelect<TypeTraits<Type>::isPointer, IteratorPointer, IteratorReference>::Result {
public: public:
explicit Iterator(Node* iter) { this->mIter = iter; } explicit Iterator(Node* iter) { this->mIter = iter; }
Node* node() { return this->mIter; } Node* node() { return this->mIter; }
Type& data() { return this->mIter->data; } Type& data() { return this->mIter->data; }
const Node* node() const { return this->mIter; } const Node* node() const { return this->mIter; }
const Type& data() const { return this->mIter->data; } const Type& data() const { return this->mIter->data; }
const Iterator& operator*() const { return *this; } const Iterator& operator*() const { return *this; }
Iterator& operator++() { Iterator& operator++() {
this->mIter = this->mIter->next; this->mIter = this->mIter->next;
return *this; return *this;
} }
bool operator==(const Iterator& left) const { return left.mIter == this->mIter; } bool operator==(const Iterator& left) const { return left.mIter == this->mIter; }
bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; } bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; }
}; };
private: private:
Node* mFirst = nullptr; Node* mFirst = nullptr;
Node* mLast = nullptr; Node* mLast = nullptr;
Index mLength = 0; Index mLength = 0;
Allocator mAlloc; Allocator mAlloc;
public: public:
List() = default; List() = default;
List(const init_list<Type>& list) { operator=(list); } List(const init_list<Type>& list) { operator=(list); }
[[nodiscard]] inline Node* first() const { return mFirst; } [[nodiscard]] inline Node* first() const { return mFirst; }
[[nodiscard]] inline Node* last() const { return mLast; } [[nodiscard]] inline Node* last() const { return mLast; }
[[nodiscard]] inline Index length() const { return mLength; } [[nodiscard]] inline Index length() const { return mLength; }
[[nodiscard]] Node* newNode() { return new (mAlloc.allocate(sizeof(Node))) Node(); } [[nodiscard]] Node* newNode() { return new (mAlloc.allocate(sizeof(Node))) Node(); }
[[nodiscard]] Node* newNode(TypeArg arg) { return new (mAlloc.allocate(sizeof(Node))) Node(arg); } [[nodiscard]] Node* newNode(TypeArg arg) { return new (mAlloc.allocate(sizeof(Node))) Node(arg); }
[[nodiscard]] Node* newNodeNotConstructed() { [[nodiscard]] Node* newNodeNotConstructed() {
auto node = (Node*) mAlloc.allocate(sizeof(Node)); auto node = (Node*) mAlloc.allocate(sizeof(Node));
node->next = node->prev = nullptr; node->next = node->prev = nullptr;
return node; return node;
} }
[[nodiscard]] const Allocator& getAllocator() const { return mAlloc; } [[nodiscard]] const Allocator& getAllocator() const { return mAlloc; }
void deleteNode(Node* node) { void deleteNode(Node* node) {
node->~Node(); node->~Node();
mAlloc.deallocate(node); mAlloc.deallocate(node);
} }
Node* addNodeBack() { Node* addNodeBack() {
auto const out = newNode(); auto const out = newNode();
@ -145,7 +145,7 @@ namespace tp {
mLength--; mLength--;
} }
[[nodiscard]] Node* findIdx(Index idx) const { [[nodiscard]] Node* findIdx(Index idx) const {
DEBUG_ASSERT(!mFirst || idx > mLength - 1) DEBUG_ASSERT(!mFirst || idx > mLength - 1)
Node* found = mFirst; Node* found = mFirst;
for (int i = 0; i != idx; i++) { for (int i = 0; i != idx; i++) {
@ -154,7 +154,7 @@ namespace tp {
return found; return found;
} }
[[nodiscard]] Node* find(const TypeArg data) const { [[nodiscard]] Node* find(const TypeArg data) const {
Node* found = mFirst; Node* found = mFirst;
for (alni i = 0; data != found->data; i++) { for (alni i = 0; data != found->data; i++) {
if (!found->next) { if (!found->next) {
@ -165,33 +165,33 @@ namespace tp {
return found; return found;
} }
[[nodiscard]] inline const Type& operator[](Index idx) const { [[nodiscard]] inline const Type& operator[](Index idx) const {
DEBUG_ASSERT(idx < mLength) DEBUG_ASSERT(idx < mLength)
return find(idx)->data; return find(idx)->data;
} }
void pushBack(Node* new_node) { attach(new_node, mLast); } void pushBack(Node* new_node) { attach(new_node, mLast); }
void pushFront(Node* new_node) { attach(new_node, nullptr); } void pushFront(Node* new_node) { attach(new_node, nullptr); }
void pushBack(TypeArg data) { pushBack(newNode(data)); } void pushBack(TypeArg data) { pushBack(newNode(data)); }
void pushFront(TypeArg data) { pushFront(newNode(data)); } void pushFront(TypeArg data) { pushFront(newNode(data)); }
void popBack() { void popBack() {
DEBUG_ASSERT(mLast) DEBUG_ASSERT(mLast)
detach(mLast); detach(mLast);
deleteNode(mLast); deleteNode(mLast);
} }
void popFront() { void popFront() {
DEBUG_ASSERT(mFirst) DEBUG_ASSERT(mFirst)
auto temp = mFirst; auto temp = mFirst;
detach(mFirst); detach(mFirst);
deleteNode(temp); deleteNode(temp);
} }
void insert(Node* node, Index idx) { void insert(Node* node, Index idx) {
if (!mLength) { if (!mLength) {
attach(node, mLast); attach(node, mLast);
} else if (idx >= mLength) { } else if (idx >= mLength) {
attach(node, nullptr); attach(node, nullptr);
} else { } else {
attach(node, find(idx)->prev); attach(node, find(idx)->prev);
@ -209,11 +209,11 @@ namespace tp {
void removeAll() { void removeAll() {
while (mFirst) { while (mFirst) {
popFront(); popFront();
} }
} }
// copies data // copies data
List& operator+=(const List& in) { List& operator+=(const List& in) {
for (auto node : in) { for (auto node : in) {
pushBack(node.data()); pushBack(node.data());
@ -229,38 +229,38 @@ namespace tp {
} }
List& operator=(const List& in) { List& operator=(const List& in) {
if (this == &in) { return *this; } if (this == &in) { return *this; }
removeAll(); removeAll();
(*this) += in; (*this) += in;
return *this; return *this;
} }
List& operator=(const init_list<Type>& list) { List& operator=(const init_list<Type>& list) {
removeAll(); removeAll();
*this += list; *this += list;
return *this; return *this;
} }
[[nodiscard]] bool operator==(const List& in) const { [[nodiscard]] bool operator==(const List& in) const {
if (in == *this) { return true; } if (in == *this) { return true; }
if (in.length() != length()) { if (in.length() != length()) {
return false; return false;
} }
Node* left = in.first(); Node* left = in.first();
Node* right = first(); Node* right = first();
while (left && right) { while (left && right) {
if (left->data != right->data) { if (left->data != right->data) {
return false; return false;
} }
} }
if (left != right) { if (left != right) {
return false; return false;
} }
return true; return true;
} }
template <typename compare_val> template <typename compare_val>
[[nodiscard]] Node* find(bool (*found)(Node* node, compare_val val), compare_val value) const { [[nodiscard]] Node* find(bool (*found)(Node* node, compare_val val), compare_val value) const {
for (Node* node = mFirst; node; node = node->next) { for (Node* node = mFirst; node; node = node->next) {
if (found(node, value)) { if (found(node, value)) {
return node; return node;
@ -269,12 +269,12 @@ namespace tp {
return nullptr; return nullptr;
} }
[[nodiscard]] Iterator begin() const { [[nodiscard]] Iterator begin() const {
Iterator out(mFirst); Iterator out(mFirst);
return out; return out;
} }
[[nodiscard]] Iterator end() const { [[nodiscard]] Iterator end() const {
return Iterator(nullptr); return Iterator(nullptr);
} }
@ -290,33 +290,33 @@ namespace tp {
} }
void detachAll() { void detachAll() {
while (mFirst) { while (mFirst) {
detach(mFirst); detach(mFirst);
} }
} }
template<class Saver> template<class Saver>
void write(Saver& file) const { void write(Saver& file) const {
file.write(mLength); file.write(mLength);
for (auto item : *this) { for (auto item : *this) {
file.write(item.data()); file.write(item.data());
} }
} }
template<class Loader> template<class Loader>
void read(Loader& file) { void read(Loader& file) {
removeAll(); removeAll();
ualni len; ualni len;
file.read(len); file.read(len);
for (auto i = len; i; i--) { for (auto i = len; i; i--) {
auto node = newNodeNotConstructed(); auto node = newNodeNotConstructed();
file.read(node->data); file.read(node->data);
pushBack(node); pushBack(node);
} }
} }
~List() { ~List() {
removeAll(); removeAll();
} }
}; };
} }

View file

@ -11,12 +11,7 @@ namespace tp {
return hash(key); return hash(key);
} }
template< template<typename tKey, typename tVal, class tAllocator = DefaultAllocator, ualni(*tHashFunc)(SelCopyArg<tKey>) = DefaultHashFunc<tKey>, int tTableInitialSize = 4>
typename tKey, typename tVal,
class tAllocator = DefaultAllocator,
ualni(*tHashFunc)(SelCopyArg<tKey>) = DefaultHashFunc<tKey>,
int tTableInitialSize = 4
>
class Map { class Map {
enum { enum {
@ -25,23 +20,23 @@ namespace tp {
MAP_MAX_LOAD_PERCENTAGE = 66, MAP_MAX_LOAD_PERCENTAGE = 66,
}; };
typedef SelCopyArg<tKey> KeyArg; typedef SelCopyArg<tKey> KeyArg;
typedef SelCopyArg<tVal> ValArg; typedef SelCopyArg<tVal> ValArg;
public: public:
class Node { class Node {
friend Map; friend Map;
Node(KeyArg aKey, ValArg aVal) : key(aKey), val(aVal) {} Node(KeyArg aKey, ValArg aVal) : key(aKey), val(aVal) {}
public: public:
tKey key; tKey key;
tVal val; tVal val;
}; };
struct Idx { struct Idx {
alni idx = -1; alni idx = -1;
operator bool() { return idx != -1; } operator bool() { return idx != -1; }
}; };
private: private:
tAllocator mAlloc; tAllocator mAlloc;
@ -49,160 +44,160 @@ namespace tp {
ualni mNSlots = 0; ualni mNSlots = 0;
ualni mNEntries = 0; ualni mNEntries = 0;
private: private:
constexpr halnf maxLoadFactor() { return halnf(MAP_MAX_LOAD_PERCENTAGE) / 100.f; } constexpr halnf maxLoadFactor() { return halnf(MAP_MAX_LOAD_PERCENTAGE) / 100.f; }
inline Node** newTable(const ualni len) { inline Node** newTable(const ualni len) {
return new(mAlloc.allocate(sizeof(Node*) * len)) Node*[len](); return new(mAlloc.allocate(sizeof(Node*) * len)) Node*[len]();
} }
inline Node* newNode(KeyArg key, ValArg val) { inline Node* newNode(KeyArg key, ValArg val) {
return new(mAlloc.allocate(sizeof(Node))) Node(key, val); return new(mAlloc.allocate(sizeof(Node))) Node(key, val);
} }
inline Node* newNodeNotConstructed() { inline Node* newNodeNotConstructed() {
return (Node*) mAlloc.allocate(sizeof(Node)); return (Node*) mAlloc.allocate(sizeof(Node));
} }
inline void deleteTable(Node** table) { inline void deleteTable(Node** table) {
mAlloc.deallocate(table); mAlloc.deallocate(table);
} }
inline void deleteNode(Node* p) { inline void deleteNode(Node* p) {
p->~Node(); p->~Node();
mAlloc.deallocate(p); mAlloc.deallocate(p);
} }
void markDeletedSlot(ualni idx) const { void markDeletedSlot(ualni idx) const {
mTable[idx] = (Node*)-1; mTable[idx] = (Node*)-1;
} }
static bool isDeletedNode(Node* node) { static bool isDeletedNode(Node* node) {
return node == (Node*)-1; return node == (Node*)-1;
} }
void rehash() { void rehash() {
alni nSlotsOld = mNSlots; alni nSlotsOld = mNSlots;
Node** tableOld = mTable; Node** tableOld = mTable;
mNSlots = next2pow((uhalni)((1.f / (maxLoadFactor())) * mNEntries + 1)); mNSlots = next2pow((uhalni)((1.f / (maxLoadFactor())) * mNEntries + 1));
mTable = newTable(mNSlots); mTable = newTable(mNSlots);
mNEntries = 0; mNEntries = 0;
for (alni i = 0; i < nSlotsOld; i++) { for (alni i = 0; i < nSlotsOld; i++) {
if (!tableOld[i] || isDeletedNode(tableOld[i])) { if (!tableOld[i] || isDeletedNode(tableOld[i])) {
continue; continue;
} }
alni idx = findSlotWrite(tableOld[i]->key); alni idx = findSlotWrite(tableOld[i]->key);
mTable[idx] = tableOld[i]; mTable[idx] = tableOld[i];
mNEntries++; mNEntries++;
} }
deleteTable(tableOld); deleteTable(tableOld);
} }
alni findSlotRead(KeyArg key) const { alni findSlotRead(KeyArg key) const {
ualni const hashed_key = tHashFunc(key); ualni const hashed_key = tHashFunc(key);
ualni const mask = mNSlots - 1; ualni const mask = mNSlots - 1;
ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1; ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1;
alni idx = hashed_key & mask; alni idx = hashed_key & mask;
NEXT: NEXT:
if (isDeletedNode(mTable[idx])) { if (isDeletedNode(mTable[idx])) {
goto SKIP; goto SKIP;
} }
if (!mTable[idx]) { if (!mTable[idx]) {
return -1; return -1;
} }
if (mTable[idx]->key == key) { if (mTable[idx]->key == key) {
return idx; return idx;
} }
SKIP: SKIP:
idx = ((5 * idx) + 1 + shift) & mask; idx = ((5 * idx) + 1 + shift) & mask;
goto NEXT; goto NEXT;
} }
// compares keys only when collisions occur // compares keys only when collisions occur
alni findSlotReadExisting(KeyArg key) const { alni findSlotReadExisting(KeyArg key) const {
ualni const hashed_key = tHashFunc(key); ualni const hashed_key = tHashFunc(key);
ualni const mask = mNSlots - 1; ualni const mask = mNSlots - 1;
ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1; ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1;
alni idx = hashed_key & mask; alni idx = hashed_key & mask;
NEXT: NEXT:
if (isDeletedNode(mTable[idx])) { if (isDeletedNode(mTable[idx])) {
goto SKIP; goto SKIP;
} }
if (!mTable[idx]) { if (!mTable[idx]) {
return -1; return -1;
} }
if (mTable[((5 * idx) + 1 + shift) & mask] == nullptr) { if (mTable[((5 * idx) + 1 + shift) & mask] == nullptr) {
return idx; return idx;
} }
if (mTable[idx]->key == key) { if (mTable[idx]->key == key) {
return idx; return idx;
} }
SKIP: SKIP:
idx = ((5 * idx) + 1 + shift) & mask; idx = ((5 * idx) + 1 + shift) & mask;
goto NEXT; goto NEXT;
} }
ualni findSlotWrite(KeyArg key) const { ualni findSlotWrite(KeyArg key) const {
ualni const hashed_key = tHashFunc(key); ualni const hashed_key = tHashFunc(key);
ualni const mask = mNSlots - 1; ualni const mask = mNSlots - 1;
ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1; ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1;
ualni idx = hashed_key & mask; ualni idx = hashed_key & mask;
NEXT: NEXT:
if (isDeletedNode(mTable[idx]) || !mTable[idx]) { if (isDeletedNode(mTable[idx]) || !mTable[idx]) {
return idx; return idx;
} }
if (mTable[idx]->key == key) { if (mTable[idx]->key == key) {
return idx; return idx;
} }
idx = ((5 * idx) + 1 + shift) & mask; idx = ((5 * idx) + 1 + shift) & mask;
goto NEXT; goto NEXT;
} }
void put(Node* node) { void put(Node* node) {
const ualni idx = findSlotWrite(node->key); const ualni idx = findSlotWrite(node->key);
if (!mTable[idx] || isDeletedNode(mTable[idx])) { if (!mTable[idx] || isDeletedNode(mTable[idx])) {
mNEntries++; mNEntries++;
} }
mTable[idx] = node; mTable[idx] = node;
if ((halnf)mNEntries / mNSlots > maxLoadFactor()) { if ((halnf)mNEntries / mNSlots > maxLoadFactor()) {
rehash(); rehash();
} }
} }
public: public:
Map() { Map() {
MODULE_SANITY_CHECK(gModuleContainers) MODULE_SANITY_CHECK(gModuleContainers)
mNSlots = next2pow(uhalni(tTableInitialSize - 1)); mNSlots = next2pow(uhalni(tTableInitialSize - 1));
mTable = newTable(mNSlots); mTable = newTable(mNSlots);
} }
Node** buff() const { Node** buff() const {
return mTable; return mTable;
} }
[[nodiscard]] ualni size() const { [[nodiscard]] ualni size() const {
return mNEntries; return mNEntries;
} }
[[nodiscard]] ualni slotsSize() const { [[nodiscard]] ualni slotsSize() const {
return mNEntries; return mNEntries;
} }
[[nodiscard]] const tAllocator& getAllocator() const { [[nodiscard]] const tAllocator& getAllocator() const {
return mAlloc; return mAlloc;
} }
void put(KeyArg key, ValArg val) { void put(KeyArg key, ValArg val) {
const ualni idx = findSlotWrite(key); const ualni idx = findSlotWrite(key);
if (!mTable[idx] || isDeletedNode(mTable[idx])) { if (!mTable[idx] || isDeletedNode(mTable[idx])) {
mTable[idx] = newNode(key, val); mTable[idx] = newNode(key, val);
mNEntries++; mNEntries++;
@ -215,22 +210,22 @@ namespace tp {
// undefined behavior if item is not presents // undefined behavior if item is not presents
tVal& get(KeyArg key) { tVal& get(KeyArg key) {
DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error") DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error")
return mTable[findSlotReadExisting(key)]->val; return mTable[findSlotReadExisting(key)]->val;
} }
const tVal& get(KeyArg key) const { const tVal& get(KeyArg key) const {
DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error") DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error")
return mTable[findSlotReadExisting(key)]->val; return mTable[findSlotReadExisting(key)]->val;
} }
[[nodiscard]] Idx presents(KeyArg key) const { return { findSlotRead(key) }; } [[nodiscard]] Idx presents(KeyArg key) const { return { findSlotRead(key) }; }
void remove(KeyArg key) { void remove(KeyArg key) {
DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error") DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error")
auto idx = findSlotReadExisting(key); auto idx = findSlotReadExisting(key);
deleteNode(mTable[idx]); deleteNode(mTable[idx]);
markDeletedSlot(idx); markDeletedSlot(idx);
@ -241,30 +236,30 @@ namespace tp {
} }
const tVal& getSlotVal(ualni slot) const { const tVal& getSlotVal(ualni slot) const {
DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error") DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error")
return mTable[slot]->val; return mTable[slot]->val;
} }
tVal& getSlotVal(ualni slot) { tVal& getSlotVal(ualni slot) {
DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error") DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error")
return mTable[slot]->val; return mTable[slot]->val;
} }
const tVal& getSlotVal(Idx slot) const { const tVal& getSlotVal(Idx slot) const {
DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error") DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error")
return mTable[slot]->val; return mTable[slot]->val;
} }
tVal& getSlotVal(Idx slot) { tVal& getSlotVal(Idx slot) {
DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error") DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error")
return mTable[slot.idx]->val; return mTable[slot.idx]->val;
} }
Map& operator=(const Map& in) { Map& operator=(const Map& in) {
if (this == &in) { if (this == &in) {
return *this; return *this;
} }
removeAll(); removeAll();
mNSlots = in.mNSlots; mNSlots = in.mNSlots;
mTable = newTable(mNSlots); mTable = newTable(mNSlots);
for (alni i = 0; i < mNSlots; i++) { for (alni i = 0; i < mNSlots; i++) {
@ -272,31 +267,31 @@ namespace tp {
put(in.mTable[i]->key, in.mTable[i]->val); put(in.mTable[i]->key, in.mTable[i]->val);
} }
} }
return *this; return *this;
} }
[[nodiscard]] bool operator==(const Map& in) const { [[nodiscard]] bool operator==(const Map& in) const {
if (this == &in) { if (this == &in) {
return true; return true;
} }
if (in.mNEntries != mNEntries) { if (in.mNEntries != mNEntries) {
return false; return false;
} }
for (auto i : in) { for (auto i : in) {
if (!presents(i->key) || get(i->key) != i->val) { if (!presents(i->key) || get(i->key) != i->val) {
return false; return false;
} }
} }
return true; return true;
} }
void removeAll() { void removeAll() {
for (ualni i = 0; i < mNSlots; i++) { for (ualni i = 0; i < mNSlots; i++) {
if (mTable[i] && !isDeletedNode(mTable[i])) { if (mTable[i] && !isDeletedNode(mTable[i])) {
deleteNode(mTable[i]); deleteNode(mTable[i]);
} }
} }
deleteTable(mTable); deleteTable(mTable);
mTable = newTable(tTableInitialSize); mTable = newTable(tTableInitialSize);
mNSlots = tTableInitialSize; mNSlots = tTableInitialSize;
mNEntries = 0; mNEntries = 0;
@ -323,74 +318,74 @@ namespace tp {
const Node* GetEntry(ualni idx) const { const Node* GetEntry(ualni idx) const {
auto slot = slotIdx(idx); auto slot = slotIdx(idx);
DEBUG_ASSERT(slot != -1 && "Key error") DEBUG_ASSERT(slot != -1 && "Key error")
return mTable[slot]; return mTable[slot];
} }
public: public:
class Iterator { class Iterator {
const Map* map; const Map* map;
Node* mIter; Node* mIter;
alni mSlot; alni mSlot;
alni mEntry; alni mEntry;
friend Map; friend Map;
explicit Iterator(const Map* _map) { explicit Iterator(const Map* _map) {
mSlot = -1; mSlot = -1;
mEntry = -1; mEntry = -1;
map = _map; map = _map;
this->operator++(); this->operator++();
} }
public: public:
Node* operator->() { return mIter; } Node* operator->() { return mIter; }
const Node* operator->() const { return mIter; } const Node* operator->() const { return mIter; }
const Iterator& operator*() const { return *this; } const Iterator& operator*() const { return *this; }
bool operator!=(ualni idx) const { return mSlot != idx; } bool operator!=(ualni idx) const { return mSlot != idx; }
void operator++() { void operator++() {
mSlot++; mSlot++;
while ((map->isDeletedNode(map->mTable[mSlot]) || !map->mTable[mSlot]) && (mSlot != map->mNSlots)) { while ((map->isDeletedNode(map->mTable[mSlot]) || !map->mTable[mSlot]) && (mSlot != map->mNSlots)) {
mSlot++; mSlot++;
} }
if (mSlot != map->mNSlots) { if (mSlot != map->mNSlots) {
mIter = map->mTable[mSlot]; mIter = map->mTable[mSlot];
mEntry++; mEntry++;
} }
} }
}; };
[[nodiscard]] Iterator begin() const { [[nodiscard]] Iterator begin() const {
return Iterator(this); return Iterator(this);
} }
[[nodiscard]] ualni end() const { [[nodiscard]] ualni end() const {
return mNSlots; return mNSlots;
} }
template<class Saver> template<class Saver>
void write(Saver& file) { void write(Saver& file) {
file.write(mNEntries); file.write(mNEntries);
for (auto item : *this) { for (auto item : *this) {
file.write(item->val); file.write(item->val);
file.write(item->key); file.write(item->key);
} }
} }
template<class Loader> template<class Loader>
void read(Loader& file) { void read(Loader& file) {
removeAll(); removeAll();
ualni len; ualni len;
file.read(len); file.read(len);
for (auto i = len; i; i--) { for (auto i = len; i; i--) {
auto node = newNodeNotConstructed(); auto node = newNodeNotConstructed();
file.read(node->val); file.read(node->val);
file.read(node->key); file.read(node->key);
put(node); put(node);
} }
} }
~Map() { removeAll(); } ~Map() { removeAll(); }
}; };

View file

@ -10,122 +10,122 @@
using namespace tp; using namespace tp;
TEST_DEF_STATIC(Simple) { TEST_DEF_STATIC(Simple) {
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree; AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
TEST(tree.size() == 0); TEST(tree.size() == 0);
TEST(tree.head() == nullptr); TEST(tree.head() == nullptr);
tree.insert(6, TestClass(6)); tree.insert(6, TestClass(6));
TEST(tree.isValid()); TEST(tree.isValid());
TEST(tree.size() == 1); TEST(tree.size() == 1);
TEST(tree.head()->data == TestClass(6)); TEST(tree.head()->data == TestClass(6));
tree.remove(6); tree.remove(6);
TEST(tree.isValid()); TEST(tree.isValid());
TEST(tree.size() == 0); TEST(tree.size() == 0);
TEST(tree.head() == nullptr); TEST(tree.head() == nullptr);
} }
TEST_DEF_STATIC(Persistance) { TEST_DEF_STATIC(Persistance) {
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree; AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
const auto size = 1000; const auto size = 1000;
struct Item { struct Item {
Item() : data(0) {} Item() : data(0) {}
bool presents = false; bool presents = false;
TestClass data; TestClass data;
}; };
Item buff[size]; Item buff[size];
for (auto i : Range(size)) { for (auto i : Range(size)) {
buff[i].data.setVal(i); buff[i].data.setVal(i);
} }
// random load // random load
ualni loadSize = 0; ualni loadSize = 0;
while (loadSize < size / 2) { while (loadSize < size / 2) {
ualni idx = rand() % (size - 1); ualni idx = rand() % (size - 1);
DEBUG_ASSERT(idx < size) DEBUG_ASSERT(idx < size)
if (!buff[idx].presents) { if (!buff[idx].presents) {
tree.insert((alni) buff[idx].data.getVal(), buff[idx].data); tree.insert((alni) buff[idx].data.getVal(), buff[idx].data);
loadSize++; loadSize++;
buff[idx].presents = true; buff[idx].presents = true;
TEST(tree.isValid()); TEST(tree.isValid());
TEST(tree.size() == loadSize); TEST(tree.size() == loadSize);
} }
} }
for (auto& item : buff) { for (auto& item : buff) {
if (item.presents) continue; if (item.presents) continue;
tree.insert((alni) item.data.getVal(), item.data); tree.insert((alni) item.data.getVal(), item.data);
loadSize++; loadSize++;
item.presents = true; item.presents = true;
TEST(tree.isValid()); TEST(tree.isValid());
TEST(tree.size() == loadSize); TEST(tree.size() == loadSize);
} }
TEST(tree.size() == size); TEST(tree.size() == size);
TEST(tree.maxNode(tree.head())->data.getVal() == size - 1); TEST(tree.maxNode(tree.head())->data.getVal() == size - 1);
TEST(tree.minNode(tree.head())->data.getVal() == 0); TEST(tree.minNode(tree.head())->data.getVal() == 0);
// find // find
for (auto item : buff) { for (auto item : buff) {
auto node = tree.find((alni) item.data.getVal()); auto node = tree.find((alni) item.data.getVal());
TEST(node); TEST(node);
if (!node) continue; if (!node) continue;
TEST(node->data.getVal() == item.data.getVal()); TEST(node->data.getVal() == item.data.getVal());
} }
TEST(!tree.find(size + 1)); TEST(!tree.find(size + 1));
TEST(!tree.find(-1)); TEST(!tree.find(-1));
// random unload // random unload
ualni unloadSize = 0; ualni unloadSize = 0;
while (unloadSize < size / 2) { while (unloadSize < size / 2) {
ualni idx = rand() % (size - 1); ualni idx = rand() % (size - 1);
if (buff[idx].presents) { if (buff[idx].presents) {
tree.remove((alni) buff[idx].data.getVal()); tree.remove((alni) buff[idx].data.getVal());
unloadSize++; unloadSize++;
buff[idx].presents = false; buff[idx].presents = false;
// find // find
for (auto item : buff) { for (auto item : buff) {
if (!item.presents) continue; if (!item.presents) continue;
auto node = tree.find((alni) item.data.getVal()); auto node = tree.find((alni) item.data.getVal());
TEST(node); TEST(node);
if (!node) continue; if (!node) continue;
TEST(node->data.getVal() == item.data.getVal()); TEST(node->data.getVal() == item.data.getVal());
} }
TEST(tree.isValid()); TEST(tree.isValid());
TEST(tree.size() == size - unloadSize); TEST(tree.size() == size - unloadSize);
} }
} }
for (auto& item : buff) { for (auto& item : buff) {
if (item.presents) { if (item.presents) {
tree.remove((alni) item.data.getVal()); tree.remove((alni) item.data.getVal());
unloadSize++; unloadSize++;
item.presents = false; item.presents = false;
TEST(tree.isValid()); TEST(tree.isValid());
TEST(tree.size() == size - unloadSize); TEST(tree.size() == size - unloadSize);
} }
} }
TEST(tree.size() == 0); TEST(tree.size() == 0);
TEST(tree.head() == nullptr); TEST(tree.head() == nullptr);
TEST(tree.maxNode(tree.head()) == nullptr); TEST(tree.maxNode(tree.head()) == nullptr);
TEST(tree.minNode(tree.head()) == nullptr); TEST(tree.minNode(tree.head()) == nullptr);
} }
TEST_DEF(Avl) { TEST_DEF(Avl) {
testSimple(); testSimple();
testPersistance(); testPersistance();
} }

View file

@ -7,82 +7,82 @@
using namespace tp; using namespace tp;
TEST_DEF_STATIC(SimpleReference) { TEST_DEF_STATIC(SimpleReference) {
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) }; tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
list.pushBack(TestClass(5)); list.pushBack(TestClass(5));
list.pushFront(TestClass(0)); list.pushFront(TestClass(0));
ualni i = -1; ualni i = -1;
for (auto iter : list) { for (auto iter : list) {
i++; i++;
TEST_EQUAL(iter->getVal(), i); TEST_EQUAL(iter->getVal(), i);
} }
TEST(i == 5); TEST(i == 5);
list.removeAll(); list.removeAll();
TEST(list.getAllocator().getAllocationsCount() == 0); TEST(list.getAllocator().getAllocationsCount() == 0);
} }
TEST_DEF_STATIC(SimplePointer) { TEST_DEF_STATIC(SimplePointer) {
tp::List<TestClass*, TestAllocator> list = { new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4) }; tp::List<TestClass*, TestAllocator> list = { new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4) };
list.pushBack(new TestClass(5)); list.pushBack(new TestClass(5));
list.pushFront(new TestClass(0)); list.pushFront(new TestClass(0));
ualni i = -1; ualni i = -1;
for (auto iter : list) { for (auto iter : list) {
i++; i++;
TEST_EQUAL(iter->getVal(), i); TEST_EQUAL(iter->getVal(), i);
} }
TEST(i == 5); TEST(i == 5);
list.removeAll(); list.removeAll();
TEST(list.getAllocator().getAllocationsCount() == 0); TEST(list.getAllocator().getAllocationsCount() == 0);
} }
TEST_DEF_STATIC(Copy) { TEST_DEF_STATIC(Copy) {
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) }; tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
tp::List<TestClass, TestAllocator> list2 = list; tp::List<TestClass, TestAllocator> list2 = list;
TEST_EQUAL(list, list2); TEST_EQUAL(list, list2);
list.removeAll(); list.removeAll();
list2.removeAll(); list2.removeAll();
TEST(list.getAllocator().getAllocationsCount() == 0); TEST(list.getAllocator().getAllocationsCount() == 0);
TEST(list2.getAllocator().getAllocationsCount() == 0); TEST(list2.getAllocator().getAllocationsCount() == 0);
} }
TEST_DEF_STATIC(SaveLoad) { TEST_DEF_STATIC(SaveLoad) {
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) }; tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
TestFile file; TestFile file;
list.write(file); list.write(file);
list.removeAll(); list.removeAll();
file.setAddress(0); file.setAddress(0);
list.read(file); list.read(file);
ualni i = 0; ualni i = 0;
for (auto iter : list) { for (auto iter : list) {
i++; i++;
TEST_EQUAL(iter->getVal(), i); TEST_EQUAL(iter->getVal(), i);
} }
TEST(i == 4); TEST(i == 4);
list.removeAll(); list.removeAll();
TEST(list.getAllocator().getAllocationsCount() == 0); TEST(list.getAllocator().getAllocationsCount() == 0);
} }
TEST_DEF(List) { TEST_DEF(List) {
testSimplePointer(); testSimplePointer();
testSimpleReference(); testSimpleReference();
testSaveLoad(); testSaveLoad();
} }

View file

@ -9,129 +9,129 @@
using namespace tp; using namespace tp;
TEST_DEF_STATIC(SimpleReference) { TEST_DEF_STATIC(SimpleReference) {
tp::Map<tp::ualni, TestClass, TestAllocator> map; tp::Map<tp::ualni, TestClass, TestAllocator> map;
for (auto i : Range(1000, 100000)) { for (auto i : Range(1000, 100000)) {
map.put(i, TestClass(i)); map.put(i, TestClass(i));
} }
for (auto i : Range(1000, 100000)) { for (auto i : Range(1000, 100000)) {
TEST(map.presents(i)); TEST(map.presents(i));
TEST_EQUAL(map.get(i).getVal(), i); TEST_EQUAL(map.get(i).getVal(), i);
} }
for (auto i : Range(1000, 100000)) { for (auto i : Range(1000, 100000)) {
map.put(i, TestClass(i)); map.put(i, TestClass(i));
} }
for (auto i : Range(1000, 2000)) { for (auto i : Range(1000, 2000)) {
TEST(map.presents(i)); TEST(map.presents(i));
map.remove(i); map.remove(i);
TEST(!map.presents(i)); TEST(!map.presents(i));
} }
for (auto i : Range(2000, 100000)) { for (auto i : Range(2000, 100000)) {
TEST(map.presents(i)); TEST(map.presents(i));
TEST_EQUAL(map.get(i).getVal(), i); TEST_EQUAL(map.get(i).getVal(), i);
} }
for (auto i : map) { for (auto i : map) {
i->val.setVal(3); i->val.setVal(3);
} }
map.removeAll(); map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1); TEST(map.getAllocator().getAllocationsCount() == 1);
} }
TEST_DEF_STATIC(SimplePointer) { TEST_DEF_STATIC(SimplePointer) {
tp::Map<tp::ualni, TestClass*, TestAllocator> map; tp::Map<tp::ualni, TestClass*, TestAllocator> map;
for (auto i : Range(1000)) { for (auto i : Range(1000)) {
map.put(i, new TestClass(i)); map.put(i, new TestClass(i));
} }
for (auto i : Range(1000)) { for (auto i : Range(1000)) {
TEST(map.presents(i)); TEST(map.presents(i));
TEST_EQUAL(map.get(i)->getVal(), i); TEST_EQUAL(map.get(i)->getVal(), i);
} }
for (auto i : Range(1000)) { for (auto i : Range(1000)) {
map.put(i, new TestClass(i)); map.put(i, new TestClass(i));
} }
for (auto i : Range(900, 1000)) { for (auto i : Range(900, 1000)) {
TEST(map.presents(i)); TEST(map.presents(i));
map.remove(i); map.remove(i);
TEST(!map.presents(i)); TEST(!map.presents(i));
} }
for (auto i : Range(900)) { for (auto i : Range(900)) {
TEST(map.presents(i)); TEST(map.presents(i));
TEST_EQUAL(map.get(i)->getVal(), i); TEST_EQUAL(map.get(i)->getVal(), i);
} }
for (auto i : map) { for (auto i : map) {
i->val->setVal(3); i->val->setVal(3);
delete i->val; delete i->val;
} }
map.removeAll(); map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1); TEST(map.getAllocator().getAllocationsCount() == 1);
} }
TEST_DEF_STATIC(Copy) { TEST_DEF_STATIC(Copy) {
tp::Map<tp::ualni, TestClass, TestAllocator> map; tp::Map<tp::ualni, TestClass, TestAllocator> map;
for (auto i : Range(10)) { for (auto i : Range(10)) {
map.put(i, TestClass(i)); map.put(i, TestClass(i));
} }
tp::Map<tp::ualni, TestClass, TestAllocator> map2 = map; tp::Map<tp::ualni, TestClass, TestAllocator> map2 = map;
TEST_EQUAL(map, map2); TEST_EQUAL(map, map2);
map.removeAll(); map.removeAll();
map2.removeAll(); map2.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1); TEST(map.getAllocator().getAllocationsCount() == 1);
TEST(map2.getAllocator().getAllocationsCount() == 1); TEST(map2.getAllocator().getAllocationsCount() == 1);
} }
TEST_DEF_STATIC(SaveLoad) { TEST_DEF_STATIC(SaveLoad) {
tp::Map<tp::ualni, TestClass, TestAllocator> map; tp::Map<tp::ualni, TestClass, TestAllocator> map;
for (auto i : Range(10)) { for (auto i : Range(10)) {
map.put(i, TestClass(i)); map.put(i, TestClass(i));
} }
TestFile file; TestFile file;
map.write(file); map.write(file);
map.removeAll(); map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1); TEST(map.getAllocator().getAllocationsCount() == 1);
file.setAddress(0); file.setAddress(0);
map.read(file); map.read(file);
TEST(map.getAllocator().getAllocationsCount() == 11); TEST(map.getAllocator().getAllocationsCount() == 11);
for (auto i : Range(10)) { for (auto i : Range(10)) {
TEST(map.presents(i)); TEST(map.presents(i));
TEST_EQUAL(map.get(i).getVal(), i); TEST_EQUAL(map.get(i).getVal(), i);
} }
map.removeAll(); map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1); TEST(map.getAllocator().getAllocationsCount() == 1);
} }
TEST_DEF(Map) { TEST_DEF(Map) {
testSimplePointer(); testSimplePointer();
testSimpleReference(); testSimpleReference();
testSaveLoad(); testSaveLoad();
} }

View file

@ -6,36 +6,36 @@
#include <cstdlib> #include <cstdlib>
static bool init(const tp::ModuleManifest* self) { static bool init(const tp::ModuleManifest* self) {
tp::gTesting.setRootName(self->getName()); tp::gTesting.setRootName(self->getName());
return true; return true;
} }
void* TestAllocator::allocate(tp::ualni size) { void* TestAllocator::allocate(tp::ualni size) {
nAllocations++; nAllocations++;
return malloc(size); return malloc(size);
} }
void TestAllocator::deallocate(void* p) { void TestAllocator::deallocate(void* p) {
nAllocations--; nAllocations--;
free(p); free(p);
} }
tp::ualni TestAllocator::getAllocationsCount() const { tp::ualni TestAllocator::getAllocationsCount() const {
return nAllocations; return nAllocations;
} }
int main() { int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr }; tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("ContainersTest", init, nullptr, deps); tp::ModuleManifest testModule("ContainersTest", init, nullptr, deps);
if (!testModule.initialize()) { if (!testModule.initialize()) {
return 1; return 1;
} }
testList(); testList();
testMap(); testMap();
testAvl(); testAvl();
testModule.deinitialize(); testModule.deinitialize();
} }

View file

@ -3,69 +3,69 @@
#include "Utils.hpp" #include "Utils.hpp"
class TestClass { class TestClass {
tp::ualni val2 = 0; tp::ualni val2 = 0;
tp::ualni val1; tp::ualni val1;
public: public:
explicit TestClass(tp::ualni val) : val1(val) {} explicit TestClass(tp::ualni val) : val1(val) {}
template<class Saver> template<class Saver>
void write(Saver& file) const { void write(Saver& file) const {
file.write(val1); file.write(val1);
} }
template<class Loader> template<class Loader>
void read(Loader& file) { void read(Loader& file) {
file.read(val1); file.read(val1);
} }
[[nodiscard]] bool operator==(const TestClass& in) const { [[nodiscard]] bool operator==(const TestClass& in) const {
return in.val1 == val1; return in.val1 == val1;
} }
[[nodiscard]] tp::ualni getVal() const { return val1; } [[nodiscard]] tp::ualni getVal() const { return val1; }
void setVal(tp::ualni val) { val1 = val; } void setVal(tp::ualni val) { val1 = val; }
}; };
class TestAllocator { class TestAllocator {
tp::ualni nAllocations = 0; tp::ualni nAllocations = 0;
public: public:
TestAllocator() = default; TestAllocator() = default;
void* allocate(tp::ualni size); void* allocate(tp::ualni size);
void deallocate(void* p); void deallocate(void* p);
[[nodiscard]] tp::ualni getAllocationsCount() const; [[nodiscard]] tp::ualni getAllocationsCount() const;
}; };
class TestFile { class TestFile {
tp::ualni mem[1024] = { 0 }; tp::ualni mem[1024] = { 0 };
tp::ualni address = 0; tp::ualni address = 0;
public: public:
TestFile() = default; TestFile() = default;
template<typename Type> template<typename Type>
void write(const Type& val) { void write(const Type& val) {
val.write(*this); val.write(*this);
} }
template<> template<>
void write<tp::ualni>(const tp::ualni& val) { void write<tp::ualni>(const tp::ualni& val) {
mem[address] = val; mem[address] = val;
address++; address++;
} }
void setAddress(tp::ualni addr) { address = addr; } void setAddress(tp::ualni addr) { address = addr; }
template<typename Type> template<typename Type>
void read(Type& val) { void read(Type& val) {
val.read(*this); val.read(*this);
} }
template<> template<>
void read<tp::ualni>(tp::ualni& val) { void read<tp::ualni>(tp::ualni& val) {
val = mem[address]; val = mem[address];
address++; address++;
} }
}; };
void testList(); void testList();

View file

@ -7,20 +7,20 @@
using namespace tp; using namespace tp;
void tp::_assert_(const char* exp, const char* file, int line) { void tp::_assert_(const char* exp, const char* file, int line) {
if (!exp) { if (!exp) {
exp = "no info"; exp = "no info";
} }
printf("\nERROR: Assertion Failure - %s -- %s:%i\n", exp, file, line); printf("\nERROR: Assertion Failure - %s -- %s:%i\n", exp, file, line);
#ifdef ENV_BUILD_DEBUG #ifdef ENV_BUILD_DEBUG
DEBUG_BREAK(true); DEBUG_BREAK(true);
#else #else
exit(1); exit(1);
#endif #endif
} }
void tp::terminate(tp::alni code) { void tp::terminate(tp::alni code) {
exit((int)code); exit((int)code);
} }

View file

@ -2,45 +2,45 @@
#include "Common.hpp" #include "Common.hpp"
namespace tp { namespace tp {
ualni next2pow(ualni v) { ualni next2pow(ualni v) {
v |= v >> 1; v |= v >> 1;
v |= v >> 2; v |= v >> 2;
v |= v >> 4; v |= v >> 4;
v |= v >> 8; v |= v >> 8;
v |= v >> 16; v |= v >> 16;
v |= v >> 32; v |= v >> 32;
return v + 1; return v + 1;
} }
uhalni next2pow(uhalni v) { uhalni next2pow(uhalni v) {
v |= v >> 1; v |= v >> 1;
v |= v >> 2; v |= v >> 2;
v |= v >> 4; v |= v >> 4;
v |= v >> 8; v |= v >> 8;
v |= v >> 16; v |= v >> 16;
return v + 1; return v + 1;
} }
ufalni next2pow(ufalni v) { ufalni next2pow(ufalni v) {
v |= v >> 1; v |= v >> 1;
v |= v >> 2; v |= v >> 2;
v |= v >> 4; v |= v >> 4;
v |= v >> 8; v |= v >> 8;
return v + 1; return v + 1;
} }
ualni hash(const char* bytes) { ualni hash(const char* bytes) {
unsigned long hash = 5381; unsigned long hash = 5381;
int c; int c;
while ((c = *bytes++)) { while ((c = *bytes++)) {
hash = ((hash << 5) + hash) + c; hash = ((hash << 5) + hash) + c;
} }
return hash; return hash;
} }
ualni hash(alni bytes) { return abs(bytes); } ualni hash(alni bytes) { return abs(bytes); }
ualni hash(alnf bytes) { return (alni)(abs(bytes)); } ualni hash(alnf bytes) { return (alni)(abs(bytes)); }
ualni hash(halni bytes) { return hash(alni(bytes)); } ualni hash(halni bytes) { return hash(alni(bytes)); }
ualni hash(uhalni bytes) { return hash(alni(bytes)); } ualni hash(uhalni bytes) { return hash(alni(bytes)); }
ualni hash(ualni bytes) { return hash(alni(bytes)); } ualni hash(ualni bytes) { return hash(alni(bytes)); }
} }

View file

@ -13,9 +13,9 @@ const char* ArchWidthString[] = { "UNDEF", "X64", "X32" };
const tp::Environment tp::gEnvironment; const tp::Environment tp::gEnvironment;
void tp::Environment::log() const { void tp::Environment::log() const {
std::cout << "ARCH : " << ArchString[(int)mArch] << "\n"; std::cout << "ARCH : " << ArchString[(int)mArch] << "\n";
std::cout << "WIDTH : " << ArchWidthString[(int)mWidth] << "\n"; std::cout << "WIDTH : " << ArchWidthString[(int)mWidth] << "\n";
std::cout << "CURRENT OS : " << OSString[(int)mOS] << "\n"; std::cout << "CURRENT OS : " << OSString[(int)mOS] << "\n";
std::cout << "TOOLCHAIN : " << ToolchainString[(int)mToolchain] << "\n"; std::cout << "TOOLCHAIN : " << ToolchainString[(int)mToolchain] << "\n";
std::cout << "BUILD TYPE : " << BuildTypeString[(int)mBuildType] << "\n"; std::cout << "BUILD TYPE : " << BuildTypeString[(int)mBuildType] << "\n";
} }

View file

@ -6,76 +6,76 @@
using namespace tp; using namespace tp;
static bool init(const ModuleManifest* self) { static bool init(const ModuleManifest* self) {
gEnvironment.log(); gEnvironment.log();
return true; return true;
} }
static ModuleManifest* deps[] = { nullptr }; static ModuleManifest* deps[] = { nullptr };
ModuleManifest tp::gModuleBase = ModuleManifest("Common", init, nullptr, deps); ModuleManifest tp::gModuleBase = ModuleManifest("Common", init, nullptr, deps);
ModuleManifest::ModuleManifest(const char* aModuleName, ModuleInit aInit, ModuleDeinit aDeinit, ModuleManifest** aDependencies) { ModuleManifest::ModuleManifest(const char* aModuleName, ModuleInit aInit, ModuleDeinit aDeinit, ModuleManifest** aDependencies) {
mInit = aInit; mInit = aInit;
mDeinit = aDeinit; mDeinit = aDeinit;
mDependencies = aDependencies; mDependencies = aDependencies;
mModuleName = aModuleName; mModuleName = aModuleName;
} }
bool ModuleManifest::isInitialized() const { bool ModuleManifest::isInitialized() const {
return mInitialized; return mInitialized;
} }
bool ModuleManifest::initialize() { bool ModuleManifest::initialize() {
mInitCount++; mInitCount++;
if (isInitialized()) { if (isInitialized()) {
return true; return true;
} }
mInitialized = true; mInitialized = true;
for (auto module = mDependencies; module && *module; module++) { for (auto module = mDependencies; module && *module; module++) {
mInitialized &= (*module)->initialize(); mInitialized &= (*module)->initialize();
} }
std::cout << "====== Initializing \"" << mModuleName << "\"\n"; std::cout << "====== Initializing \"" << mModuleName << "\"\n";
if (mInit) mInitialized &= mInit(this); if (mInit) mInitialized &= mInit(this);
if (!mInitialized) { if (!mInitialized) {
std::cout << "Failed to Initialize.\n"; std::cout << "Failed to Initialize.\n";
} }
return mInitialized; return mInitialized;
} }
void ModuleManifest::deinitialize() { void ModuleManifest::deinitialize() {
mInitCount--; mInitCount--;
if (mInitCount > 0) { if (mInitCount > 0) {
return; return;
} }
if (!isInitialized()) { if (!isInitialized()) {
return; return;
} }
if (mDeinit) mDeinit(this); if (mDeinit) mDeinit(this);
mInitialized = false; mInitialized = false;
auto len = 0; auto len = 0;
for (auto module = mDependencies; module && *module; module++) { for (auto module = mDependencies; module && *module; module++) {
len++; len++;
} }
for (auto i = 0; i < len; i++) { for (auto i = 0; i < len; i++) {
auto module = mDependencies + (len - i - 1); auto module = mDependencies + (len - i - 1);
if ((*module)->isInitialized()) { if ((*module)->isInitialized()) {
(*module)->deinitialize(); (*module)->deinitialize();
} }
} }
} }
const char *ModuleManifest::getName() const { const char *ModuleManifest::getName() const {
return mModuleName; return mModuleName;
} }

View file

@ -5,7 +5,7 @@
namespace tp { namespace tp {
void _assert_(const char* exp, const char* file, int line); void _assert_(const char* exp, const char* file, int line);
void terminate(tp::alni code = 0); void terminate(tp::alni code = 0);
}; };
#define FAIL(exp) tp::_assert_(#exp, __FILE__, __LINE__); #define FAIL(exp) tp::_assert_(#exp, __FILE__, __LINE__);

View file

@ -6,54 +6,54 @@
#include <initializer_list> #include <initializer_list>
namespace tp { namespace tp {
template<typename Type> template<typename Type>
using init_list = std::initializer_list<Type>; using init_list = std::initializer_list<Type>;
// Selects whether to pass by constant reference or by value // Selects whether to pass by constant reference or by value
template <typename tType> template <typename tType>
using SelCopyArg = typename TypeSelect<(sizeof(tType) > sizeof(tp::alni)), const tType&, tType>::Result; using SelCopyArg = typename TypeSelect<(sizeof(tType) > sizeof(tp::alni)), const tType&, tType>::Result;
ualni next2pow(ualni v); ualni next2pow(ualni v);
uhalni next2pow(uhalni v); uhalni next2pow(uhalni v);
ufalni next2pow(ufalni v); ufalni next2pow(ufalni v);
ualni hash(const char* bytes); ualni hash(const char* bytes);
ualni hash(alni bytes); ualni hash(alni bytes);
ualni hash(halni bytes); ualni hash(halni bytes);
ualni hash(uhalni bytes); ualni hash(uhalni bytes);
ualni hash(ualni bytes); ualni hash(ualni bytes);
ualni hash(alnf bytes); ualni hash(alnf bytes);
template <typename T> template <typename T>
[[nodiscard]] T clamp(T v, T l, T u) { if (v < l) { v = l; } else if (v > u) { v = u; } return v; } [[nodiscard]] T clamp(T v, T l, T u) { if (v < l) { v = l; } else if (v > u) { v = u; } return v; }
template <typename T> template <typename T>
[[nodiscard]] T max(T a, T b) { return (a > b) ? a : b; } [[nodiscard]] T max(T a, T b) { return (a > b) ? a : b; }
template <typename T> template <typename T>
[[nodiscard]] T min(T a, T b) { return (a < b) ? a : b; } [[nodiscard]] T min(T a, T b) { return (a < b) ? a : b; }
template <typename T> template <typename T>
[[nodiscard]] T abs(T v) { if (v < 0) { return -v; } return v; } [[nodiscard]] T abs(T v) { if (v < 0) { return -v; } return v; }
template <typename T> template <typename T>
inline void swap(T& t1, T& t2) { const T tmp = t1; t1 = t2; t2 = tmp; } inline void swap(T& t1, T& t2) { const T tmp = t1; t1 = t2; t2 = tmp; }
// only for x > 0 and y > 0 // only for x > 0 and y > 0
template <typename T> template <typename T>
[[nodiscard]] T ceil_positive(T x, T y) { return T( 1 + ((x - 1) / (tp::alnf)y) ); } [[nodiscard]] T ceil_positive(T x, T y) { return T( 1 + ((x - 1) / (tp::alnf)y) ); }
// power // power
template <typename T> template <typename T>
[[nodiscard]] T pow(T x, uhalni n) { [[nodiscard]] T pow(T x, uhalni n) {
T out = x; for (uhalni i = 0; i < n - 1; i++) { out = out * x; } T out = x; for (uhalni i = 0; i < n - 1; i++) { out = out * x; }
return out; return out;
} }
template<typename Type> template<typename Type>
halni nDig10(Type val) { halni nDig10(Type val) {
val = abs(val); halni out = 0; val = abs(val); halni out = 0;
while (val != 0) { val = halni(val / 10); out++; } while (val != 0) { val = halni(val / 10); out++; }
return out; return out;
} }
} }

View file

@ -6,138 +6,138 @@
namespace tp { namespace tp {
class Environment { class Environment {
public: public:
enum class Arch { UNDEF, INTEL, ARM } mArch = Arch::UNDEF; enum class Arch { UNDEF, INTEL, ARM } mArch = Arch::UNDEF;
// Build Type // Build Type
#if defined(__DEBUG__) || defined(_DEBUG) || defined(DEBUG) || !defined(NDEBUG) #if defined(__DEBUG__) || defined(_DEBUG) || defined(DEBUG) || !defined(NDEBUG)
#define ENV_BUILD_DEBUG #define ENV_BUILD_DEBUG
enum class BuildType { UNDEF, DEBUG, RELEASE } mBuildType = BuildType::DEBUG; enum class BuildType { UNDEF, DEBUG, RELEASE } mBuildType = BuildType::DEBUG;
#else #else
#define ENV_BUILD_RELEASE #define ENV_BUILD_RELEASE
enum class BuildType { UNDEF, DEBUG, RELEASE } mBuildType = BuildType::RELEASE; enum class BuildType { UNDEF, DEBUG, RELEASE } mBuildType = BuildType::RELEASE;
#endif #endif
// MCVS // MCVS
#ifdef _MSC_VER #ifdef _MSC_VER
#define ENV_COMPILER_MSVC #define ENV_COMPILER_MSVC
enum class Toolchain { UNDEF, GNU, LLVM, MSVC } mToolchain = Toolchain::MSVC; enum class Toolchain { UNDEF, GNU, LLVM, MSVC } mToolchain = Toolchain::MSVC;
// VERSION // VERSION
// TODO // TODO
// TARGET OS // TARGET OS
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#define ENV_OS_WINDOWS #define ENV_OS_WINDOWS
enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::WINDOWS; enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::WINDOWS;
#else #else
enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::UNDEF; enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::UNDEF;
#error "unexplored compilation to os target" #error "unexplored compilation to os target"
#endif #endif
// TARGET ALIGNED SIZE // TARGET ALIGNED SIZE
#ifdef _WIN64 #ifdef _WIN64
enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X64; enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X64;
#define ENV_BITS_64 #define ENV_BITS_64
#else #else
enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X32; enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X32;
#define ENV_BITS_32 #define ENV_BITS_32
#endif #endif
#endif #endif
// GCC // GCC
#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) #if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
#define ENV_COMPILER_GCC #define ENV_COMPILER_GCC
enum class Toolchain { UNDEF, GNU, LLVM, MSVC } mToolchain = Toolchain::GNU; enum class Toolchain { UNDEF, GNU, LLVM, MSVC } mToolchain = Toolchain::GNU;
// VERSION // VERSION
#if (__GNUC___ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) #if (__GNUC___ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1))
// TODO // TODO
#endif #endif
// TARGET OS // TARGET OS
#if defined(__linux__) && !defined(__ANDROID__) #if defined(__linux__) && !defined(__ANDROID__)
#define ENV_OS_LINUX #define ENV_OS_LINUX
enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::LINUX; enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::LINUX;
#else #else
#error "unexplored compilation to os target" #error "unexplored compilation to os target"
#endif #endif
// TARGET ALIGNED SIZE // TARGET ALIGNED SIZE
#if defined(__aarch64__) || defined(__x86_64__) || defined(__ARM_64BIT_STATE) #if defined(__aarch64__) || defined(__x86_64__) || defined(__ARM_64BIT_STATE)
#define ENV_BITS_64 #define ENV_BITS_64
enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X64; enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X64;
#elif defined(__x86_64__) || defined(i386) #elif defined(__x86_64__) || defined(i386)
#define ENV_BITS_32 #define ENV_BITS_32
enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X32; enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X32;
#endif #endif
#endif #endif
// CLANG // CLANG
#if defined(__clang__) && !defined(ENV_COMPILER_GCC) #if defined(__clang__) && !defined(ENV_COMPILER_GCC)
#define ENV_COMPILER_CLANG #define ENV_COMPILER_CLANG
enum class Toolchain { UNDEF, GNU, LLVM, MSVC } mToolchain = Toolchain::LLVM; enum class Toolchain { UNDEF, GNU, LLVM, MSVC } mToolchain = Toolchain::LLVM;
// VERSION // VERSION
#if (__clang_major__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) #if (__clang_major__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1))
// TODO // TODO
#endif #endif
// TARGET OS // TARGET OS
#if defined(__linux__) && !defined(__ANDROID__) #if defined(__linux__) && !defined(__ANDROID__)
#define ENV_OS_LINUX #define ENV_OS_LINUX
enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::LINUX; enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::LINUX;
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::ANDOID; enum class OS { UNDEF, LINUX, WINDOWS, ANDROID, IOS } mOS = OS::ANDOID;
#define ENV_OS_ANDROID #define ENV_OS_ANDROID
#else #else
#error "unexplored compilation to target os" #error "unexplored compilation to target os"
#endif #endif
// TARGET ALIGNED SIZE // TARGET ALIGNED SIZE
#if defined(__aarch64__) || defined(__x86_64__) || defined(__ARM_64BIT_STATE) #if defined(__aarch64__) || defined(__x86_64__) || defined(__ARM_64BIT_STATE)
#define ENV_BITS_64 #define ENV_BITS_64
enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X64; enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X64;
#elif defined(__x86_64__) || defined(i386) #elif defined(__x86_64__) || defined(i386)
#define ENV_BITS_32 #define ENV_BITS_32
enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X32; enum class ArchWidth { UNDEF, X64, X32 } mWidth = ArchWidth::X32;
#endif #endif
#endif #endif
#if defined(__EMSCRIPTEN__) || defined(__MINGW32__) || defined(__MINGW32__) || defined(__MINGW64__) #if defined(__EMSCRIPTEN__) || defined(__MINGW32__) || defined(__MINGW32__) || defined(__MINGW64__)
#error "compiler is not supported" #error "compiler is not supported"
#else #else
#if !(defined(ENV_COMPILER_MSVC) || defined(ENV_COMPILER_CLANG) || defined(ENV_COMPILER_GCC)) #if !(defined(ENV_COMPILER_MSVC) || defined(ENV_COMPILER_CLANG) || defined(ENV_COMPILER_GCC))
// Linux and Linux - derived __linux__ // Linux and Linux - derived __linux__
// Darwin(Mac OS X and iOS) __APPLE__ // Darwin(Mac OS X and iOS) __APPLE__
// Akaros __ros__ // Akaros __ros__
// NaCL __native_client__ // NaCL __native_client__
// AsmJS __asmjs__ // AsmJS __asmjs__
// Fuschia __Fuchsia__ // Fuschia __Fuchsia__
#error "unknown compiler" #error "unknown compiler"
#endif #endif
#endif #endif
void log() const; void log() const;
}; };
#ifndef ENV_BITS_64 #ifndef ENV_BITS_64
#error "ERROR - not 64 bit archytectures are out of support" #error "ERROR - not 64 bit archytectures are out of support"
#endif #endif
const extern Environment gEnvironment; const extern Environment gEnvironment;
typedef char int1; typedef char int1;
typedef unsigned char uint1; typedef unsigned char uint1;
typedef short int2; typedef short int2;
typedef unsigned short uint2; typedef unsigned short uint2;
typedef unsigned int uint4; typedef unsigned int uint4;
typedef uint2 ufalni; typedef uint2 ufalni;
typedef uint4 uhalni; typedef uint4 uhalni;
typedef int int4; typedef int int4;
typedef int4 halni; typedef int4 halni;

View file

@ -8,24 +8,24 @@
namespace tp { namespace tp {
class ModuleManifest { class ModuleManifest {
public: public:
typedef bool (*ModuleInit)(const ModuleManifest*); typedef bool (*ModuleInit)(const ModuleManifest*);
typedef void (*ModuleDeinit)(const ModuleManifest*); typedef void (*ModuleDeinit)(const ModuleManifest*);
ModuleManifest(const char* aModuleName, ModuleInit aInit, ModuleDeinit aDeinit, ModuleManifest** aDependencies); ModuleManifest(const char* aModuleName, ModuleInit aInit, ModuleDeinit aDeinit, ModuleManifest** aDependencies);
[[nodiscard]] bool isInitialized() const; [[nodiscard]] bool isInitialized() const;
bool initialize(); bool initialize();
void deinitialize(); void deinitialize();
[[nodiscard]] const char* getName() const; [[nodiscard]] const char* getName() const;
private: private:
const char* mModuleName = nullptr; const char* mModuleName = nullptr;
ModuleManifest** mDependencies; // NULL terminated ModuleManifest** mDependencies; // NULL terminated
bool mInitialized = false; bool mInitialized = false;
ModuleInit mInit = nullptr; ModuleInit mInit = nullptr;
ModuleDeinit mDeinit = nullptr; ModuleDeinit mDeinit = nullptr;
uhalni mInitCount = 0; uhalni mInitCount = 0;
}; };
extern ModuleManifest gModuleBase; extern ModuleManifest gModuleBase;
}; };

File diff suppressed because it is too large Load diff

View file

@ -4,19 +4,19 @@
#include "Common.hpp" #include "Common.hpp"
int main() { int main() {
tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleBase, nullptr }; tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleBase, nullptr };
tp::ModuleManifest TestModule("Test", nullptr, nullptr, ModuleDependencies); tp::ModuleManifest TestModule("Test", nullptr, nullptr, ModuleDependencies);
if (!TestModule.initialize()) { if (!TestModule.initialize()) {
return 1; return 1;
} }
ASSERT(tp::gEnvironment.mWidth == tp::Environment::ArchWidth::X64); ASSERT(tp::gEnvironment.mWidth == tp::Environment::ArchWidth::X64);
ASSERT(tp::max(2, 1) == 2); ASSERT(tp::max(2, 1) == 2);
ASSERT(tp::max(-1, 0) == 0); ASSERT(tp::max(-1, 0) == 0);
ASSERT(tp::max(0, -1) == 0); ASSERT(tp::max(0, -1) == 0);
ASSERT(tp::min(0, -1) == -1); ASSERT(tp::min(0, -1) == -1);
TestModule.deinitialize(); TestModule.deinitialize();
} }

2
TODO
View file

@ -1,5 +1,3 @@
Convert tabs to spaces
Containers: Containers:
Avl read write ! Avl read write !
Add check copy times ! Add check copy times !

View file

@ -9,103 +9,103 @@ using namespace tp;
CallStackCapture* tp::gCSCapture = nullptr; CallStackCapture* tp::gCSCapture = nullptr;
void initializeCallStackCapture() { void initializeCallStackCapture() {
gCSCapture = new CallStackCapture(); gCSCapture = new CallStackCapture();
} }
void deinitializeCallStackCapture() { void deinitializeCallStackCapture() {
delete gCSCapture; delete gCSCapture;
} }
ualni CallStackCapture::CallStack::getDepth() const { ualni CallStackCapture::CallStack::getDepth() const {
ualni len = 0; ualni len = 0;
for (long long frame : frames) { for (long long frame : frames) {
if (!frame) { break; } if (!frame) { break; }
len++; len++;
} }
ualni stripedLen = 0; ualni stripedLen = 0;
for (auto i = FRAMES_TO_SKIP_START; i < len - FRAMES_TO_SKIP_END; i++) { for (auto i = FRAMES_TO_SKIP_START; i < len - FRAMES_TO_SKIP_END; i++) {
if (!frames[i]) { break; } if (!frames[i]) { break; }
stripedLen++; stripedLen++;
} }
return stripedLen; return stripedLen;
} }
ualni CallStackCapture::hashCallStack(CallStackKey key) { ualni CallStackCapture::hashCallStack(CallStackKey key) {
auto const cs = key.cs; auto const cs = key.cs;
ualni out = 0; ualni out = 0;
for (ualni i = 0; cs->frames[i]; i++) { out += cs->frames[i]; } for (ualni i = 0; cs->frames[i]; i++) { out += cs->frames[i]; }
return out; return out;
} }
bool CallStackCapture::CallStackKey::operator==(const CallStackCapture::CallStackKey &in) const { bool CallStackCapture::CallStackKey::operator==(const CallStackCapture::CallStackKey &in) const {
for (auto i : Range(MAX_CALL_DEPTH_CAPTURE)) { for (auto i : Range(MAX_CALL_DEPTH_CAPTURE)) {
if (cs->frames[i] != in.cs->frames[i]) { if (cs->frames[i] != in.cs->frames[i]) {
return false; return false;
} }
if (cs->frames[i] == 0 && in.cs->frames[i] == 0) { if (cs->frames[i] == 0 && in.cs->frames[i] == 0) {
return true; return true;
} }
} }
DEBUG_ASSERT(0 && "Must Not Happen") DEBUG_ASSERT(0 && "Must Not Happen")
return true; return true;
} }
CallStackCapture::CallStackCapture() { CallStackCapture::CallStackCapture() {
static_assert(MAX_CALL_DEPTH_CAPTURE >= 1); static_assert(MAX_CALL_DEPTH_CAPTURE >= 1);
static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB > 0); static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB > 0);
static_assert(MAX_DEBUG_INFO_LEN > sizeof("unresolved")); static_assert(MAX_DEBUG_INFO_LEN > sizeof("unresolved"));
static_assert(FRAMES_TO_SKIP_END >= 0 && FRAMES_TO_SKIP_START >= 0); static_assert(FRAMES_TO_SKIP_END >= 0 && FRAMES_TO_SKIP_START >= 0);
static_assert(MAX_CALL_DEPTH_CAPTURE > FRAMES_TO_SKIP_START + FRAMES_TO_SKIP_END); static_assert(MAX_CALL_DEPTH_CAPTURE > FRAMES_TO_SKIP_START + FRAMES_TO_SKIP_END);
static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024 > sizeof(CallStack)); static_assert(MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024 > sizeof(CallStack));
MODULE_SANITY_CHECK(gModuleUtils) MODULE_SANITY_CHECK(gModuleUtils)
mBuffLoad = 0; mBuffLoad = 0;
mBuffLen = (MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024) / sizeof(CallStack); mBuffLen = (MAX_CALL_CAPTURES_MEM_SIZE_MB * 1024 * 1024) / sizeof(CallStack);
mBuff = (CallStack*) malloc(mBuffLen * sizeof(CallStack)); mBuff = (CallStack*) malloc(mBuffLen * sizeof(CallStack));
} }
const CallStackCapture::CallStack* CallStackCapture::getSnapshot() { const CallStackCapture::CallStack* CallStackCapture::getSnapshot() {
if (mBuffLoad > mBuffLen) { if (mBuffLoad > mBuffLen) {
static CallStack cs; static CallStack cs;
cs.frames[0] = 0; cs.frames[0] = 0;
return &cs; return &cs;
} }
CallStack* cs = &mBuff[mBuffLoad]; CallStack* cs = &mBuff[mBuffLoad];
platformWriteStackTrace(cs); platformWriteStackTrace(cs);
auto idx = mSnapshots.presents({ cs }); auto idx = mSnapshots.presents({ cs });
if (idx) { if (idx) {
return mSnapshots.getSlotVal(idx); return mSnapshots.getSlotVal(idx);
} }
mSnapshots.put({ cs }, cs); mSnapshots.put({ cs }, cs);
mBuffLoad++; mBuffLoad++;
return cs; return cs;
} }
const CallStackCapture::DebugSymbols* CallStackCapture::getSymbols(FramePointer frame) { const CallStackCapture::DebugSymbols* CallStackCapture::getSymbols(FramePointer frame) {
auto idx = mSymbols.presents(frame); auto idx = mSymbols.presents(frame);
if (idx) { if (idx) {
return &mSymbols.getSlotVal(idx); return &mSymbols.getSlotVal(idx);
} }
mSymbols.put(frame, {}); mSymbols.put(frame, {});
auto symbols = &mSymbols.get(frame); auto symbols = &mSymbols.get(frame);
platformWriteDebugSymbols(frame, symbols); platformWriteDebugSymbols(frame, symbols);
return symbols; return symbols;
} }
void CallStackCapture::clear() { void CallStackCapture::clear() {
mBuffLoad = 0; mBuffLoad = 0;
mSnapshots.removeAll(); mSnapshots.removeAll();
mSymbols.removeAll(); mSymbols.removeAll();
} }
CallStackCapture::~CallStackCapture() { CallStackCapture::~CallStackCapture() {
free(mBuff); free(mBuff);
} }
// ---------------------------------- Platform Depended ---------------------------------- // // ---------------------------------- Platform Depended ---------------------------------- //
@ -118,90 +118,90 @@ CallStackCapture::~CallStackCapture() {
#include <cxxabi.h> #include <cxxabi.h>
void CallStackCapture::platformWriteStackTrace(CallStack* stack) { void CallStackCapture::platformWriteStackTrace(CallStack* stack) {
auto depth = backtrace((void**)stack->frames, (int) MAX_CALL_DEPTH_CAPTURE - 1); auto depth = backtrace((void**)stack->frames, (int) MAX_CALL_DEPTH_CAPTURE - 1);
stack->frames[depth] = 0; stack->frames[depth] = 0;
} }
static void getGetSourceFromBinaryAddress(const char* binary, const char* address, char* file, ualni* line) { static void getGetSourceFromBinaryAddress(const char* binary, const char* address, char* file, ualni* line) {
static char buff[1024]; static char buff[1024];
snprintf(buff, sizeof(buff), "addr2line -e %s -a %s", binary, address); snprintf(buff, sizeof(buff), "addr2line -e %s -a %s", binary, address);
FILE* pipe = popen(buff, "r"); FILE* pipe = popen(buff, "r");
if (pipe) { if (pipe) {
fgets(buff, sizeof(buff), pipe); fgets(buff, sizeof(buff), pipe);
fgets(buff, sizeof(buff), pipe); fgets(buff, sizeof(buff), pipe);
pclose(pipe); pclose(pipe);
char* linePtr = strchr(buff, ':'); char* linePtr = strchr(buff, ':');
printf("%s\n", buff); printf("%s\n", buff);
if (linePtr != nullptr && buff[0] != '?' && buff[1] != '?' && buff[2] != ':') { if (linePtr != nullptr && buff[0] != '?' && buff[1] != '?' && buff[2] != ':') {
*linePtr = '\0'; *linePtr = '\0';
auto sourceLen = std::strlen(buff); auto sourceLen = std::strlen(buff);
std::strcpy(file, buff + ((sourceLen > MAX_DEBUG_INFO_LEN) ? (sourceLen - MAX_DEBUG_INFO_LEN) : 0)); std::strcpy(file, buff + ((sourceLen > MAX_DEBUG_INFO_LEN) ? (sourceLen - MAX_DEBUG_INFO_LEN) : 0));
*line = strtoul(linePtr + 1, nullptr, 10); *line = strtoul(linePtr + 1, nullptr, 10);
return; return;
} }
} }
std::strcpy(file, "unresolved"); std::strcpy(file, "unresolved");
*line = 0; *line = 0;
} }
static void getDemangledName(const char* func, char* out) { static void getDemangledName(const char* func, char* out) {
int status; int status;
size_t funcDemangledSize = MAX_DEBUG_INFO_LEN; size_t funcDemangledSize = MAX_DEBUG_INFO_LEN;
char* funcDemangled = (char*)malloc(funcDemangledSize); char* funcDemangled = (char*)malloc(funcDemangledSize);
char* ret = abi::__cxa_demangle(func, funcDemangled, &funcDemangledSize, &status); char* ret = abi::__cxa_demangle(func, funcDemangled, &funcDemangledSize, &status);
if (status == 0) { if (status == 0) {
funcDemangled = ret; funcDemangled = ret;
auto funcLen = std::strlen(funcDemangled); auto funcLen = std::strlen(funcDemangled);
std::strcpy(out, funcDemangled + ((funcLen > MAX_DEBUG_INFO_LEN) ? (funcLen - MAX_DEBUG_INFO_LEN) : 0)); std::strcpy(out, funcDemangled + ((funcLen > MAX_DEBUG_INFO_LEN) ? (funcLen - MAX_DEBUG_INFO_LEN) : 0));
free(ret); free(ret);
return; return;
} }
auto funcLen = std::strlen(func); auto funcLen = std::strlen(func);
std::strcpy(out, func + ((funcLen > MAX_DEBUG_INFO_LEN) ? (funcLen - MAX_DEBUG_INFO_LEN) : 0)); std::strcpy(out, func + ((funcLen > MAX_DEBUG_INFO_LEN) ? (funcLen - MAX_DEBUG_INFO_LEN) : 0));
free(funcDemangled); free(funcDemangled);
} }
void CallStackCapture::platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out) { void CallStackCapture::platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out) {
void* addrList[1] = { (void*) frame }; void* addrList[1] = { (void*) frame };
auto symbolsArray = backtrace_symbols(addrList, 1); auto symbolsArray = backtrace_symbols(addrList, 1);
// 'bin(fun+addr)' // 'bin(fun+addr)'
char* bin = *symbolsArray; char* bin = *symbolsArray;
char* func = nullptr; char* func = nullptr;
char* offset = nullptr; char* offset = nullptr;
// 'bin fun+addr' // 'bin fun+addr'
for (char *p = bin; *p; ++p) { for (char *p = bin; *p; ++p) {
if (*p == '(') { *p = 0; func = p + 1; } if (*p == '(') { *p = 0; func = p + 1; }
else if (*p == '+') { offset = p; } else if (*p == '+') { offset = p; }
else if (*p == ')' && offset) { *p = 0; } else if (*p == ')' && offset) { *p = 0; }
} }
if (func && offset) { if (func && offset) {
getGetSourceFromBinaryAddress(bin, func, out->file, &out->line); getGetSourceFromBinaryAddress(bin, func, out->file, &out->line);
if (offset != func) { if (offset != func) {
*offset = 0; *offset = 0;
getDemangledName(func, out->function); getDemangledName(func, out->function);
} else { } else {
std::strcpy(out->function, "unresolved"); std::strcpy(out->function, "unresolved");
} }
} else { } else {
std::strcpy(out->file, "unresolved"); std::strcpy(out->file, "unresolved");
std::strcpy(out->function, "unresolved"); std::strcpy(out->function, "unresolved");
} }
free(symbolsArray); free(symbolsArray);
} }
#else #else
void CallStackCapture::platformWriteStackTrace(CallStack* stack) { stack->frames[0] = 0; } void CallStackCapture::platformWriteStackTrace(CallStack* stack) { stack->frames[0] = 0; }
void CallStackCapture::platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out) { void CallStackCapture::platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out) {
std::strcpy(out->file, "unresolved"); std::strcpy(out->file, "unresolved");
std::strcpy(out->function, "unresolved"); std::strcpy(out->function, "unresolved");
} }
#endif #endif

View file

@ -10,72 +10,72 @@ using namespace tp;
Testing tp::gTesting; Testing tp::gTesting;
void Testing::startTest(const char* name) { void Testing::startTest(const char* name) {
MODULE_SANITY_CHECK(gModuleUtils) MODULE_SANITY_CHECK(gModuleUtils)
mCurrent->mSubTests.pushBack(new TestingNode{ {}, {}, name, mCurrent }); mCurrent->mSubTests.pushBack(new TestingNode{ {}, {}, name, mCurrent });
mCurrent = mCurrent->mSubTests.last()->data; mCurrent = mCurrent->mSubTests.last()->data;
} }
void Testing::endTest() { void Testing::endTest() {
if (mCurrent->mParent) { if (mCurrent->mParent) {
mCurrent = mCurrent->mParent; mCurrent = mCurrent->mParent;
} }
} }
void Testing::addFailedCheck(const FailedCheck& info) { void Testing::addFailedCheck(const FailedCheck& info) {
DEBUG_BREAK(0 && info.expression); DEBUG_BREAK(0 && info.expression);
auto lastRecord = &mCurrent->mFailedChecks.last()->data; auto lastRecord = &mCurrent->mFailedChecks.last()->data;
if (lastRecord && lastRecord->failedCheck.file == info.file && lastRecord->failedCheck.line == info.line) { if (lastRecord && lastRecord->failedCheck.file == info.file && lastRecord->failedCheck.line == info.line) {
lastRecord->times++; lastRecord->times++;
return; return;
} }
mCurrent->mFailedChecks.pushBack({ info, 1 }); mCurrent->mFailedChecks.pushBack({ info, 1 });
} }
void Testing::reportState() { void Testing::reportState() {
mRootTest.updateState(); mRootTest.updateState();
printf("\n"); printf("\n");
mRootTest.report(); mRootTest.report();
} }
bool Testing::hasFailed() { bool Testing::hasFailed() {
mRootTest.updateState(); mRootTest.updateState();
return mRootTest.mHasFailed; return mRootTest.mHasFailed;
} }
void Testing::setRootName(const char* name) { void Testing::setRootName(const char* name) {
mRootTest.mName = name; mRootTest.mName = name;
} }
void Testing::TestingNode::updateState() { void Testing::TestingNode::updateState() {
for (auto child : mSubTests) { for (auto child : mSubTests) {
child->updateState(); child->updateState();
mHasFailed = child->mHasFailed; mHasFailed = child->mHasFailed;
if (mHasFailed) return; if (mHasFailed) return;
} }
mHasFailed = mFailedChecks.length(); mHasFailed = mFailedChecks.length();
} }
void Testing::TestingNode::report(const char* path) const { void Testing::TestingNode::report(const char* path) const {
if (!mHasFailed) { if (!mHasFailed) {
return; return;
} }
auto newPath = path ? std::string(path) + "/" + mName : std::string(mName); auto newPath = path ? std::string(path) + "/" + mName : std::string(mName);
for (auto check : mFailedChecks) { for (auto check : mFailedChecks) {
auto failedCheck = &check.data().failedCheck; auto failedCheck = &check.data().failedCheck;
auto times = check.data().times; auto times = check.data().times;
printf("%s Failed - (%s) %s:%llu x%i\n", newPath.c_str(), failedCheck->expression, failedCheck->file, failedCheck->line, (halni) times); printf("%s Failed - (%s) %s:%llu x%i\n", newPath.c_str(), failedCheck->expression, failedCheck->file, failedCheck->line, (halni) times);
} }
for (const auto& child : mSubTests) { for (const auto& child : mSubTests) {
child->report(newPath.c_str()); child->report(newPath.c_str());
} }
} }
Testing::TestingNode::~TestingNode() { Testing::TestingNode::~TestingNode() {
for (const auto& child : mSubTests) { for (const auto& child : mSubTests) {
delete child.data(); delete child.data();
} }
} }

View file

@ -5,77 +5,73 @@
#include "Timing.hpp" #include "Timing.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#define GETTIMEMSC() \ #define GETTIMEMSC() (time_ms)\
(time_ms)( \ (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch()).count())
std::chrono::duration_cast<std::chrono::milliseconds>( \
std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()) \
.time_since_epoch()) \
.count())
#define THREAD_SLEEP(time_ms) std::this_thread::sleep_for(std::chrono::milliseconds(time_ms)) #define THREAD_SLEEP(time_ms) std::this_thread::sleep_for(std::chrono::milliseconds(time_ms))
tp::time_ms tp::gCurrentTime = tp::get_time(); tp::time_ms tp::gCurrentTime = tp::get_time();
namespace tp { namespace tp {
time_ms get_time() { time_ms get_time() {
gCurrentTime = GETTIMEMSC(); gCurrentTime = GETTIMEMSC();
return gCurrentTime; return gCurrentTime;
} }
void sleep(time_ms mDuration) { void sleep(time_ms mDuration) {
THREAD_SLEEP(mDuration); THREAD_SLEEP(mDuration);
} }
Timer::Timer() { Timer::Timer() {
mDuration = 0; mDuration = 0;
mStart = GETTIMEMSC(); mStart = GETTIMEMSC();
} }
Timer::Timer(time_ms mDuration) { Timer::Timer(time_ms mDuration) {
mStart = GETTIMEMSC(); mStart = GETTIMEMSC();
this->mDuration = mDuration; this->mDuration = mDuration;
} }
bool Timer::isTimeout() { bool Timer::isTimeout() {
return mDuration < GETTIMEMSC() - mStart; return mDuration < GETTIMEMSC() - mStart;
} }
void Timer::reset() { void Timer::reset() {
mStart = GETTIMEMSC(); mStart = GETTIMEMSC();
} }
time_ms Timer::timePassed() { time_ms Timer::timePassed() {
return GETTIMEMSC() - mStart; return GETTIMEMSC() - mStart;
} }
time_ms Timer::remainder() { time_ms Timer::remainder() {
return mDuration - (GETTIMEMSC() - mStart); return mDuration - (GETTIMEMSC() - mStart);
} }
time_ms Timer::start() { return mStart; } time_ms Timer::start() { return mStart; }
time_ms Timer::duration() { return mDuration; } time_ms Timer::duration() { return mDuration; }
void Timer::setDuration(time_ms dur) { mDuration = dur; } void Timer::setDuration(time_ms dur) { mDuration = dur; }
void Timer::wait() { void Timer::wait() {
if (!isTimeout()) { if (!isTimeout()) {
sleep(remainder()); sleep(remainder());
} }
} }
float Timer::easeIn(time_ms pDuration) { float Timer::easeIn(time_ms pDuration) {
if (!pDuration) { if (!pDuration) {
pDuration = mDuration; pDuration = mDuration;
} }
float x = (1.f / pDuration) * timePassed(); float x = (1.f / pDuration) * timePassed();
return clamp((1.1f * x) / (x + 0.1f), 0.f, 1.f); return clamp((1.1f * x) / (x + 0.1f), 0.f, 1.f);
} }
float Timer::easeOut(time_ms pDuration) { float Timer::easeOut(time_ms pDuration) {
if (!pDuration) { if (!pDuration) {
pDuration = mDuration; pDuration = mDuration;
} }
float x = (1.f / pDuration) * timePassed(); float x = (1.f / pDuration) * timePassed();
return clamp((0.1f * (1 - x)) / (x + 0.1f), 0.f, 1.f); return clamp((0.1f * (1 - x)) / (x + 0.1f), 0.f, 1.f);
} }
} }

View file

@ -11,84 +11,84 @@ void initializeCallStackCapture();
void deinitializeCallStackCapture(); void deinitializeCallStackCapture();
static bool initialize(const tp::ModuleManifest* self) { static bool initialize(const tp::ModuleManifest* self) {
initializeCallStackCapture(); initializeCallStackCapture();
return true; return true;
} }
static void deinitialize(const tp::ModuleManifest* self) { static void deinitialize(const tp::ModuleManifest* self) {
deinitializeCallStackCapture(); deinitializeCallStackCapture();
tp::gTesting.reportState(); tp::gTesting.reportState();
if (tp::gTesting.hasFailed()) { exit(1); } if (tp::gTesting.hasFailed()) { exit(1); }
} }
namespace tp { namespace tp {
static ModuleManifest* sModuleUtilsDeps[] = { &gModuleContainers, nullptr }; static ModuleManifest* sModuleUtilsDeps[] = { &gModuleContainers, nullptr };
ModuleManifest gModuleUtils = ModuleManifest("Utils", initialize, deinitialize, sModuleUtilsDeps); ModuleManifest gModuleUtils = ModuleManifest("Utils", initialize, deinitialize, sModuleUtilsDeps);
void memsetv(void* p, uhalni bytesize, uint1 val) { void memsetv(void* p, uhalni bytesize, uint1 val) {
MODULE_SANITY_CHECK(gModuleBase) MODULE_SANITY_CHECK(gModuleBase)
alni alignedval = 0; alni alignedval = 0;
for (ualni idx = 0; idx < sizeof(alni); idx++) { for (ualni idx = 0; idx < sizeof(alni); idx++) {
((uint1*) &alignedval)[idx] = val; ((uint1*) &alignedval)[idx] = val;
} }
ualni alignedlen = bytesize / sizeof(alni); ualni alignedlen = bytesize / sizeof(alni);
for (ualni idx = 0; idx < alignedlen; idx++) { for (ualni idx = 0; idx < alignedlen; idx++) {
((alni*) p)[idx] = alignedval; ((alni*) p)[idx] = alignedval;
} }
ualni unalignedlen = bytesize - (alignedlen * sizeof(alni)); ualni unalignedlen = bytesize - (alignedlen * sizeof(alni));
for (ualni idx = 0; idx < unalignedlen; idx++) { for (ualni idx = 0; idx < unalignedlen; idx++) {
((uint1*) p)[bytesize - idx - 1] = val; ((uint1*) p)[bytesize - idx - 1] = val;
} }
} }
void memcp(void* left, const void* right, uhalni len) { void memcp(void* left, const void* right, uhalni len) {
MODULE_SANITY_CHECK(gModuleBase) MODULE_SANITY_CHECK(gModuleBase)
ualni alignedlen = len / sizeof(alni); ualni alignedlen = len / sizeof(alni);
for (ualni idx = 0; idx < alignedlen; idx++) { for (ualni idx = 0; idx < alignedlen; idx++) {
((alni*) left)[idx] = ((alni*) right)[idx]; ((alni*) left)[idx] = ((alni*) right)[idx];
} }
ualni unalignedlen = len - (alignedlen * sizeof(alni)); ualni unalignedlen = len - (alignedlen * sizeof(alni));
for (ualni idx = 0; idx < unalignedlen; idx++) { for (ualni idx = 0; idx < unalignedlen; idx++) {
((uint1*) left)[len - idx - 1] = ((uint1*) right)[len - idx - 1]; ((uint1*) left)[len - idx - 1] = ((uint1*) right)[len - idx - 1];
} }
} }
int1 memecomp(const void* left, const void* right, uhalni len) { int1 memecomp(const void* left, const void* right, uhalni len) {
MODULE_SANITY_CHECK(gModuleBase) MODULE_SANITY_CHECK(gModuleBase)
if (!len) return 0; if (!len) return 0;
ualni alignedLength = len / sizeof(alni); ualni alignedLength = len / sizeof(alni);
for (ualni idx = 0; idx < alignedLength; idx++) { for (ualni idx = 0; idx < alignedLength; idx++) {
if (((alni*) left)[idx] == ((alni*) right)[idx]) { if (((alni*) left)[idx] == ((alni*) right)[idx]) {
continue; continue;
} }
if (((alni*) left)[idx] > ((alni*) right)[idx]) { if (((alni*) left)[idx] > ((alni*) right)[idx]) {
return 1; return 1;
} }
return -1; return -1;
} }
ualni unalignedLength = len - (alignedLength * sizeof(alni)); ualni unalignedLength = len - (alignedLength * sizeof(alni));
for (ualni idx = 0; idx < unalignedLength; idx++) { for (ualni idx = 0; idx < unalignedLength; idx++) {
if (((uint1*) left)[len - idx - 1] == ((uint1*) right)[len - idx - 1]) { if (((uint1*) left)[len - idx - 1] == ((uint1*) right)[len - idx - 1]) {
continue; continue;
} }
if (((uint1*) left)[len - idx - 1] > ((uint1*) right)[len - idx - 1]) { if (((uint1*) left)[len - idx - 1] > ((uint1*) right)[len - idx - 1]) {
return 1; return 1;
} }
return -1; return -1;
} }
return 0; return 0;
} }
alnf randf() { alnf randf() {
alnf r = static_cast<alnf>(std::rand()) / static_cast<alnf>(RAND_MAX); alnf r = static_cast<alnf>(std::rand()) / static_cast<alnf>(RAND_MAX);
return r; return r;
} }
} }

View file

@ -12,110 +12,110 @@
namespace tp { namespace tp {
class CallStackCapture { class CallStackCapture {
public: public:
typedef tp::alni FramePointer; typedef tp::alni FramePointer;
class CallStack { class CallStack {
friend CallStackCapture; friend CallStackCapture;
FramePointer frames[MAX_CALL_DEPTH_CAPTURE]; FramePointer frames[MAX_CALL_DEPTH_CAPTURE];
public: public:
[[nodiscard]] ualni getDepth() const; [[nodiscard]] ualni getDepth() const;
class Iterator { class Iterator {
const FramePointer* mFrame; const FramePointer* mFrame;
public: public:
explicit Iterator(const FramePointer* frame) : mFrame(frame) {}; explicit Iterator(const FramePointer* frame) : mFrame(frame) {};
FramePointer getFrame() { return *mFrame; } FramePointer getFrame() { return *mFrame; }
bool operator==(const Iterator& in) const { return in.mFrame == mFrame; } bool operator==(const Iterator& in) const { return in.mFrame == mFrame; }
void operator++() { mFrame++; } void operator++() { mFrame++; }
const Iterator& operator*() const { return *this; } const Iterator& operator*() const { return *this; }
}; };
[[nodiscard]] Iterator begin() const { return Iterator(frames + FRAMES_TO_SKIP_START); } [[nodiscard]] Iterator begin() const { return Iterator(frames + FRAMES_TO_SKIP_START); }
[[nodiscard]] Iterator end() const { return Iterator(frames + FRAMES_TO_SKIP_START + getDepth()); } [[nodiscard]] Iterator end() const { return Iterator(frames + FRAMES_TO_SKIP_START + getDepth()); }
}; };
class DebugSymbols { class DebugSymbols {
friend CallStackCapture; friend CallStackCapture;
char function[MAX_DEBUG_INFO_LEN + 1] = { 0 }; char function[MAX_DEBUG_INFO_LEN + 1] = { 0 };
char file[MAX_DEBUG_INFO_LEN + 1] = { 0 }; char file[MAX_DEBUG_INFO_LEN + 1] = { 0 };
ualni line = 0; ualni line = 0;
public: public:
[[nodiscard]] const char* getFunc() const { return function; } [[nodiscard]] const char* getFunc() const { return function; }
[[nodiscard]] const char* getFile() const { return file; } [[nodiscard]] const char* getFile() const { return file; }
[[nodiscard]] ualni getLine() const { return line; } [[nodiscard]] ualni getLine() const { return line; }
}; };
public: public:
CallStackCapture(); CallStackCapture();
~CallStackCapture(); ~CallStackCapture();
[[nodiscard]] const CallStack* getSnapshot(); [[nodiscard]] const CallStack* getSnapshot();
const DebugSymbols* getSymbols(FramePointer fp); const DebugSymbols* getSymbols(FramePointer fp);
public: public:
template<class Saver> template<class Saver>
void write(Saver& file) { void write(Saver& file) {
file.write(mBuffLoad); file.write(mBuffLoad);
for (auto cs : *this) { for (auto cs : *this) {
file.write(cs.getCallStack()->getDepth()); file.write(cs.getCallStack()->getDepth());
for (auto frame : *cs.getCallStack()) { for (auto frame : *cs.getCallStack()) {
file.write((ualni) frame.getFrame()); file.write((ualni) frame.getFrame());
} }
} }
file.write(mSymbols); file.write(mSymbols);
} }
// independent of the configuration // independent of the configuration
template<class Loader> template<class Loader>
void read(Loader& file) { void read(Loader& file) {
clear(); clear();
ualni loadLen; ualni loadLen;
file.read(loadLen); file.read(loadLen);
for (auto cs = loadLen; cs; cs--) { for (auto cs = loadLen; cs; cs--) {
ualni callStackLen; ualni callStackLen;
file.read(callStackLen); file.read(callStackLen);
for (auto fp = callStackLen; fp; fp--) { for (auto fp = callStackLen; fp; fp--) {
// -- // --
} }
} }
} }
public: public:
class Iterator { class Iterator {
const CallStack* mSnapshot; const CallStack* mSnapshot;
public: public:
explicit Iterator(const CallStack* start) : mSnapshot(start) {}; explicit Iterator(const CallStack* start) : mSnapshot(start) {};
const CallStack* getCallStack() { return mSnapshot; } const CallStack* getCallStack() { return mSnapshot; }
bool operator==(const Iterator& in) const { return in.mSnapshot == mSnapshot; } bool operator==(const Iterator& in) const { return in.mSnapshot == mSnapshot; }
void operator++() { mSnapshot++; } void operator++() { mSnapshot++; }
const Iterator& operator*() const { return *this; } const Iterator& operator*() const { return *this; }
}; };
[[nodiscard]] Iterator begin() const { return Iterator(mBuff); } [[nodiscard]] Iterator begin() const { return Iterator(mBuff); }
[[nodiscard]] Iterator end() const { return Iterator(mBuff + mBuffLoad); } [[nodiscard]] Iterator end() const { return Iterator(mBuff + mBuffLoad); }
private: private:
struct CallStackKey { struct CallStackKey {
CallStack* cs; CallStack* cs;
bool operator==(const CallStackKey& in) const; bool operator==(const CallStackKey& in) const;
}; };
static void platformWriteStackTrace(CallStack* stack); static void platformWriteStackTrace(CallStack* stack);
static void platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out); static void platformWriteDebugSymbols(FramePointer frame, DebugSymbols* out);
[[nodiscard]] static ualni hashCallStack(CallStackKey key); [[nodiscard]] static ualni hashCallStack(CallStackKey key);
void clear(); void clear();
private: private:
ualni mBuffLen; ualni mBuffLen;
ualni mBuffLoad; ualni mBuffLoad;
CallStack* mBuff; CallStack* mBuff;
Map<CallStackKey, CallStack*, DefaultAllocator, hashCallStack> mSnapshots; Map<CallStackKey, CallStack*, DefaultAllocator, hashCallStack> mSnapshots;
Map<FramePointer, DebugSymbols> mSymbols; Map<FramePointer, DebugSymbols> mSymbols;
}; };
extern CallStackCapture* gCSCapture; extern CallStackCapture* gCSCapture;

View file

@ -41,23 +41,23 @@ namespace tp {
while (i < n1 && j < n2) { while (i < n1 && j < n2) {
if (!(grater(Left[i], Right[j]))) { if (!(grater(Left[i], Right[j]))) {
buff[k] = Left[i]; buff[k] = Left[i];
i++; i++;
} else { } else {
buff[k] = Right[j]; buff[k] = Right[j];
j++; j++;
} }
k++; k++;
} }
while (i < n1) { while (i < n1) {
buff[k] = Left[i]; buff[k] = Left[i];
i++; i++;
k++; k++;
} }
while (j < n2) { while (j < n2) {
buff[k] = Right[j]; buff[k] = Right[j];
j++; j++;
k++; k++;
} }

View file

@ -4,61 +4,61 @@
#include "List.hpp" #include "List.hpp"
namespace tp { namespace tp {
class Testing { class Testing {
public: public:
struct FailedCheck { struct FailedCheck {
const char* expression = nullptr; const char* expression = nullptr;
const char* file = nullptr; const char* file = nullptr;
ualni line = 0; ualni line = 0;
}; };
Testing() = default; Testing() = default;
void startTest(const char* name); void startTest(const char* name);
void endTest(); void endTest();
void addFailedCheck(const FailedCheck& info); void addFailedCheck(const FailedCheck& info);
void reportState(); void reportState();
void setRootName(const char* name); void setRootName(const char* name);
[[nodiscard]] bool hasFailed(); [[nodiscard]] bool hasFailed();
private: private:
struct TestingNode { struct TestingNode {
struct FailedCheckRecord { FailedCheck failedCheck; ualni times; }; struct FailedCheckRecord { FailedCheck failedCheck; ualni times; };
List<FailedCheckRecord> mFailedChecks; List<FailedCheckRecord> mFailedChecks;
List<TestingNode*> mSubTests; List<TestingNode*> mSubTests;
const char* mName = "Unnamed"; const char* mName = "Unnamed";
TestingNode* mParent = nullptr; TestingNode* mParent = nullptr;
bool mHasFailed = false; bool mHasFailed = false;
void report(const char* path = nullptr) const; void report(const char* path = nullptr) const;
void updateState(); void updateState();
~TestingNode(); ~TestingNode();
}; };
TestingNode mRootTest; TestingNode mRootTest;
TestingNode* mCurrent = &mRootTest; TestingNode* mCurrent = &mRootTest;
}; };
extern Testing gTesting; extern Testing gTesting;
} }
#define TEST_DEF(Name)\ #define TEST_DEF(Name)\
static void Name##FunctorBody();\ static void Name##FunctorBody();\
void test##Name() { \ void test##Name() { \
tp::gTesting.startTest(#Name);\ tp::gTesting.startTest(#Name);\
Name##FunctorBody();\ Name##FunctorBody();\
tp::gTesting.endTest();\ tp::gTesting.endTest();\
} \ } \
void Name##FunctorBody() void Name##FunctorBody()
#define TEST_DEF_STATIC(Name)\ #define TEST_DEF_STATIC(Name)\
static void Name##FunctorBody();\ static void Name##FunctorBody();\
static void test##Name() { \ static void test##Name() { \
tp::gTesting.startTest(#Name);\ tp::gTesting.startTest(#Name);\
Name##FunctorBody();\ Name##FunctorBody();\
tp::gTesting.endTest();\ tp::gTesting.endTest();\
} \ } \
void Name##FunctorBody() void Name##FunctorBody()
#define TEST(expr) if (!(expr)) tp::gTesting.addFailedCheck({ #expr, __FILE__, __LINE__ }) #define TEST(expr) if (!(expr)) tp::gTesting.addFailedCheck({ #expr, __FILE__, __LINE__ })
#define TEST_EQUAL(l, r) if (!((l) == (r))) tp::gTesting.addFailedCheck({ #l" == "#r, __FILE__, __LINE__ }) #define TEST_EQUAL(l, r) if (!((l) == (r))) tp::gTesting.addFailedCheck({ #l" == "#r, __FILE__, __LINE__ })

View file

@ -4,55 +4,55 @@
namespace tp { namespace tp {
typedef alni time_ms; typedef alni time_ms;
typedef alni time_ns; typedef alni time_ns;
extern time_ms gCurrentTime; extern time_ms gCurrentTime;
class Timer { class Timer {
time_ms mStart; time_ms mStart;
time_ms mDuration; time_ms mDuration;
public: public:
Timer(); Timer();
explicit Timer(time_ms time); explicit Timer(time_ms time);
time_ms start(); time_ms start();
time_ms duration(); time_ms duration();
void setDuration(time_ms dur); void setDuration(time_ms dur);
bool isTimeout(); bool isTimeout();
void reset(); void reset();
time_ms timePassed(); time_ms timePassed();
time_ms remainder(); time_ms remainder();
void wait(); void wait();
float easeIn(time_ms duration = 0); float easeIn(time_ms duration = 0);
float easeOut(time_ms duration = 0); float easeOut(time_ms duration = 0);
}; };
void sleep(time_ms duration); void sleep(time_ms duration);
time_ms get_time(); time_ms get_time();
struct FpsCounter { struct FpsCounter {
halni frames = 0; halni frames = 0;
Timer time; Timer time;
halni fps = 0; halni fps = 0;
FpsCounter() : time(1000) {} FpsCounter() : time(1000) {}
void update(bool log = true) { void update(bool log = true) {
frames++; frames++;
if (time.isTimeout()) { if (time.isTimeout()) {
fps = frames; fps = frames;
if (log) { if (log) {
// printf("fps %i \n", fps); // printf("fps %i \n", fps);
} }
frames = 0; frames = 0;
time.reset(); time.reset();
} }
} }
}; };
} }

View file

@ -7,73 +7,73 @@
namespace tp { namespace tp {
extern ModuleManifest gModuleUtils; extern ModuleManifest gModuleUtils;
void memsetv(void* p, uhalni bytesize, uint1 val); void memsetv(void* p, uhalni bytesize, uint1 val);
void memcp(void* left, const void* right, uhalni len); void memcp(void* left, const void* right, uhalni len);
int1 memequal(const void* left, const void* right, uhalni len); int1 memequal(const void* left, const void* right, uhalni len);
} }
namespace tp { namespace tp {
[[nodiscard]] alnf randf(); [[nodiscard]] alnf randf();
} }
namespace tp { namespace tp {
template <typename T1, typename T2> template <typename T1, typename T2>
class Pair { class Pair {
public: public:
Pair() {} Pair() {}
Pair(T1 t1, T2 t2) : head(t1), tail(t2) {} Pair(T1 t1, T2 t2) : head(t1), tail(t2) {}
union { T1 t1; T1 head; T1 x; }; union { T1 t1; T1 head; T1 x; };
union { T2 t2; T2 tail; T2 y; }; union { T2 t2; T2 tail; T2 y; };
}; };
template <typename Type = alni> template <typename Type = alni>
class Bits { class Bits {
Type mFlags = 0; Type mFlags = 0;
public: public:
Bits() = default; Bits() = default;
explicit Bits(Type val) { mFlags = val; } explicit Bits(Type val) { mFlags = val; }
explicit Bits(bool val) { for (int bit = 0; bit < sizeof(Type); bit++) { set(bit, val); } } explicit Bits(bool val) { for (int bit = 0; bit < sizeof(Type); bit++) { set(bit, val); } }
bool get(int1 idx) { return mFlags & (1l << idx); } bool get(int1 idx) { return mFlags & (1l << idx); }
void set(int1 idx, bool val) { void set(int1 idx, bool val) {
if (val) { if (val) {
mFlags |= (1l << idx); mFlags |= (1l << idx);
} else { } else {
mFlags &= ~(1l << idx); mFlags &= ~(1l << idx);
} }
} }
}; };
template<typename tType = ualni> template<typename tType = ualni>
class Range { class Range {
public: public:
class Iterator { class Iterator {
public: public:
tType mIndex; tType mIndex;
explicit Iterator(tType pStartIndex) : mIndex(pStartIndex) {} explicit Iterator(tType pStartIndex) : mIndex(pStartIndex) {}
tType index() const { return mIndex; } tType index() const { return mIndex; }
inline void operator++() { mIndex++; } inline void operator++() { mIndex++; }
inline operator tType() const { return mIndex; } inline operator tType() const { return mIndex; }
inline bool operator==(Iterator pIndex) { return mIndex == pIndex.mIndex; } inline bool operator==(Iterator pIndex) { return mIndex == pIndex.mIndex; }
inline bool operator!=(Iterator pIndex) { return mIndex != pIndex.mIndex; } inline bool operator!=(Iterator pIndex) { return mIndex != pIndex.mIndex; }
inline const Iterator& operator*() { return *this; } inline const Iterator& operator*() { return *this; }
}; };
tType mBegin = 0; tType mBegin = 0;
tType mEnd = 0; tType mEnd = 0;
Range() = default; Range() = default;
explicit Range(tType pEndIndex) : mBegin(0), mEnd(pEndIndex) {} explicit Range(tType pEndIndex) : mBegin(0), mEnd(pEndIndex) {}
Range(tType pStartIndex, tType pEndIndex) : mBegin(pStartIndex), mEnd(pEndIndex) {} Range(tType pStartIndex, tType pEndIndex) : mBegin(pStartIndex), mEnd(pEndIndex) {}
bool valid() { return mBegin < mEnd; } bool valid() { return mBegin < mEnd; }
tType idxBegin() const { return mBegin; } tType idxBegin() const { return mBegin; }
tType idxEnd() const { return mEnd; } tType idxEnd() const { return mEnd; }
Iterator begin() { return Iterator(mBegin); } Iterator begin() { return Iterator(mBegin); }
Iterator end() { return Iterator(mEnd); } Iterator end() { return Iterator(mEnd); }
}; };
} }

View file

@ -8,60 +8,60 @@
using namespace tp; using namespace tp;
void printSnapshot(const tp::CallStackCapture::CallStack* snapshot) { void printSnapshot(const tp::CallStackCapture::CallStack* snapshot) {
printf("CallStack: \n"); printf("CallStack: \n");
for (auto frame : *snapshot) { for (auto frame : *snapshot) {
auto symbols = gCSCapture->getSymbols(frame.getFrame()); auto symbols = gCSCapture->getSymbols(frame.getFrame());
printf(" %s ----- %s:%llu\n", symbols->getFunc(), symbols->getFile(), symbols->getLine()); printf(" %s ----- %s:%llu\n", symbols->getFunc(), symbols->getFile(), symbols->getLine());
} }
printf("\n"); printf("\n");
} }
void common() { void common() {
gCSCapture->getSnapshot(); gCSCapture->getSnapshot();
} }
void first() { void first() {
common(); common();
common(); common();
common(); common();
} }
void second() { void second() {
common(); common();
common(); common();
common(); common();
common(); common();
} }
void third() { void third() {
common(); common();
common(); common();
} }
void root() { void root() {
first(); first();
second(); second();
third(); third();
} }
TEST_DEF(Debugging) { TEST_DEF(Debugging) {
root(); root();
for (auto cs : *gCSCapture) { for (auto cs : *gCSCapture) {
printSnapshot(cs.getCallStack()); printSnapshot(cs.getCallStack());
} }
} }
int main() { int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr }; tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("UtilsTest", nullptr, nullptr, deps); tp::ModuleManifest testModule("UtilsTest", nullptr, nullptr, deps);
if (!testModule.initialize()) { if (!testModule.initialize()) {
return 1; return 1;
} }
testDebugging(); testDebugging();
testModule.deinitialize(); testModule.deinitialize();
} }