Formatting code
This commit is contained in:
parent
6dc64ce76b
commit
13a8f07e32
37 changed files with 2242 additions and 2281 deletions
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -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&) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -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(); }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
@ -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)); }
|
||||||
}
|
}
|
||||||
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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__);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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
2
TODO
|
|
@ -1,5 +1,3 @@
|
||||||
Convert tabs to spaces
|
|
||||||
|
|
||||||
Containers:
|
Containers:
|
||||||
Avl read write !
|
Avl read write !
|
||||||
Add check copy times !
|
Add check copy times !
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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__ })
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -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); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue