| @@ -2,3 +2,4 @@ | |||||
| *.report | *.report | ||||
| /ftb | /ftb | ||||
| vgcore.* | vgcore.* | ||||
| tests/ftb | |||||
| @@ -1,9 +1,82 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <initializer_list> | #include <initializer_list> | ||||
| #ifdef FTB_INTERNAL_DEBUG | |||||
| # include <stdio.h> | |||||
| #endif | |||||
| #include "types.hpp" | #include "types.hpp" | ||||
| #include "macros.hpp" | #include "macros.hpp" | ||||
| template <typename type> | |||||
| struct Stack_Array_List { | |||||
| type* data; | |||||
| u32 length; | |||||
| u32 count; | |||||
| Stack_Array_List(u32 length) { | |||||
| data = (type*)alloca(length); | |||||
| #ifdef FTB_INTERNAL_DEBUG | |||||
| if (data == nullptr) { | |||||
| fprintf(stderr, "ERROR: alloca did return nullptr \n"); | |||||
| } | |||||
| #endif | |||||
| this->length = length; | |||||
| this->count = 0; | |||||
| } | |||||
| static Stack_Array_List<type> create_from(std::initializer_list<type> l) { | |||||
| Stack_Array_List<type> ret(l.size()); | |||||
| for (type t : l) { | |||||
| ret.data[ret.count++] = t; | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| void extend(std::initializer_list<type> l) { | |||||
| for (type e : l) { | |||||
| append(e); | |||||
| } | |||||
| } | |||||
| void clear() { | |||||
| count = 0; | |||||
| } | |||||
| type* begin() { | |||||
| return data; | |||||
| } | |||||
| type* end() { | |||||
| return data+(count); | |||||
| } | |||||
| void remove_index(u32 index) { | |||||
| #ifdef FTB_INTERNAL_DEBUG | |||||
| if (index >= count) | |||||
| fprintf(stderr, "ERROR: removing index that is not in use\n"); | |||||
| #endif | |||||
| data[index] = data[--count]; | |||||
| } | |||||
| void append(type element) { | |||||
| #ifdef FTB_INTERNAL_DEBUG | |||||
| if (count == length) { | |||||
| fprintf(stderr, "ERROR: Stack_Array_List is full!\n"); | |||||
| } | |||||
| #endif | |||||
| data[count] = element; | |||||
| count++; | |||||
| } | |||||
| type& operator[](u32 index) { | |||||
| return data[index]; | |||||
| } | |||||
| }; | |||||
| template <typename type> | template <typename type> | ||||
| struct Array_List { | struct Array_List { | ||||
| type* data; | type* data; | ||||
| @@ -180,24 +253,64 @@ struct Array_List { | |||||
| template <typename type> | template <typename type> | ||||
| struct Auto_Array_List : public Array_List<type> { | struct Auto_Array_List : public Array_List<type> { | ||||
| Auto_Array_List(u32 length) { | |||||
| this->alloc(length); | |||||
| } | |||||
| Auto_Array_List(u32 length) { | |||||
| this->alloc(length); | |||||
| } | |||||
| Auto_Array_List() { | |||||
| this->alloc(16); | |||||
| } | |||||
| Auto_Array_List() { | |||||
| this->alloc(16); | |||||
| Auto_Array_List(std::initializer_list<type> l) { | |||||
| this->alloc(l.size()); | |||||
| for (type e : l) { | |||||
| this->append(e); | |||||
| } | } | ||||
| } | |||||
| Auto_Array_List(std::initializer_list<type> l) { | |||||
| this->alloc(l.size()); | |||||
| for (type e : l) { | |||||
| this->append(e); | |||||
| } | |||||
| } | |||||
| ~Auto_Array_List() { | |||||
| free(this->data); | |||||
| this->data = nullptr; | |||||
| } | |||||
| }; | |||||
| template <typename type> | |||||
| struct Queue { | |||||
| Array_List<type> arr_list; | |||||
| u32 next_index; | |||||
| void alloc(u32 initial_capacity = 16) { | |||||
| next_index = 0; | |||||
| arr_list.alloc(initial_capacity); | |||||
| } | |||||
| ~Auto_Array_List() { | |||||
| free(this->data); | |||||
| this->data = nullptr; | |||||
| void dealloc() { | |||||
| arr_list.dealloc(); | |||||
| } | |||||
| void push_back(type e) { | |||||
| arr_list.append(e); | |||||
| } | |||||
| type get_next() { | |||||
| #ifdef FTB_INTERNAL_DEBUG | |||||
| if (next_index >= arr_list.length) { | |||||
| fprintf(stderr, "ERROR: Out of bounds access in queue\n"); | |||||
| } | } | ||||
| #endif | |||||
| return arr_list.data[next_index++]; | |||||
| } | |||||
| bool is_empty() { | |||||
| return next_index == arr_list.count; | |||||
| } | |||||
| int get_count() { | |||||
| return arr_list.count - next_index; | |||||
| } | |||||
| void clear() { | |||||
| next_index = 0; | |||||
| arr_list.clear(); | |||||
| } | |||||
| }; | }; | ||||
| @@ -5,12 +5,12 @@ pushd $SCRIPTPATH > /dev/null | |||||
| # _DEBUG | # _DEBUG | ||||
| # time g++ -fpermissive src/main.cpp -g -o ./bin/slime --std=c++17 || exit 1 | # time g++ -fpermissive src/main.cpp -g -o ./bin/slime --std=c++17 || exit 1 | ||||
| time clang++ -D_DEBUG -D_PROFILING -fpermissive main.cpp -g -o ./ftb --std=c++17 || exit 1 | time clang++ -D_DEBUG -D_PROFILING -fpermissive main.cpp -g -o ./ftb --std=c++17 || exit 1 | ||||
| time clang++ -D_DEBUG -D_PROFILING -fpermissive cpu_info.cpp -g -o ./cpu_info --std=c++17 || exit 1 | |||||
| # time clang++ -D_DEBUG -D_PROFILING -fpermissive cpu_info.cpp -g -o ./cpu_info --std=c++17 || exit 1 | |||||
| echo "" | echo "" | ||||
| # time valgrind --leak-check=full ./ftb | # time valgrind --leak-check=full ./ftb | ||||
| time ./ftb | time ./ftb | ||||
| time ./cpu_info | |||||
| # time ./cpu_info | |||||
| popd > /dev/null | popd > /dev/null | ||||
| unset TIMEFORMAT | unset TIMEFORMAT | ||||
| @@ -146,6 +146,128 @@ auto test_hm() -> void { | |||||
| }); | }); | ||||
| } | } | ||||
| proc test_stack_array_lists() -> testresult { | |||||
| Stack_Array_List<int> list(20); | |||||
| assert_equal_int(list.count, 0); | |||||
| assert_equal_int(list.length, 20); | |||||
| assert(list.data != NULL, "list should have some data allocated"); | |||||
| // test sum of empty list | |||||
| int sum = 0; | |||||
| int iter = 0; | |||||
| for (auto e : list) { | |||||
| sum += e; | |||||
| iter++; | |||||
| } | |||||
| assert_equal_int(sum, 0); | |||||
| assert_equal_int(iter, 0); | |||||
| // append some elements | |||||
| list.append(1); | |||||
| list.append(2); | |||||
| list.append(3); | |||||
| list.append(4); | |||||
| assert_equal_int(list.count, 4); | |||||
| assert_equal_int(list.length, 20); | |||||
| // test sum again | |||||
| sum = 0; | |||||
| iter = 0; | |||||
| for (auto e : list) { | |||||
| sum += e; | |||||
| iter++; | |||||
| } | |||||
| assert_equal_int(sum, 10); | |||||
| assert_equal_int(iter, 4); | |||||
| // bracketed access | |||||
| list[0] = 11; | |||||
| list[1] = 3; | |||||
| list[2] = 2; | |||||
| list.append(5); | |||||
| // test sum again | |||||
| sum = 0; | |||||
| iter = 0; | |||||
| for (auto e : list) { | |||||
| sum += e; | |||||
| ++iter; | |||||
| } | |||||
| assert_equal_int(sum, 25); | |||||
| assert_equal_int(iter, 5); | |||||
| // assert memory correct | |||||
| assert_equal_int(list.data[0], 11); | |||||
| assert_equal_int(list.data[1], 3); | |||||
| assert_equal_int(list.data[2], 2); | |||||
| assert_equal_int(list.data[3], 4); | |||||
| assert_equal_int(list.data[4], 5); | |||||
| // removing some indices | |||||
| list.remove_index(4); | |||||
| // test sum again | |||||
| sum = 0; | |||||
| iter = 0; | |||||
| for (auto e : list) { | |||||
| sum += e; | |||||
| ++iter; | |||||
| } | |||||
| assert_equal_int(sum, 20); | |||||
| assert_equal_int(iter, 4); | |||||
| // removing some indices | |||||
| list.remove_index(1); | |||||
| list.remove_index(0); | |||||
| // test sum again | |||||
| sum = 0; | |||||
| iter = 0; | |||||
| for (auto e : list) { | |||||
| sum += e; | |||||
| ++iter; | |||||
| } | |||||
| assert_equal_int(sum, 6); | |||||
| assert_equal_int(iter, 2); | |||||
| return pass; | |||||
| } | |||||
| proc test_queue() -> testresult { | |||||
| Queue<int> q; | |||||
| q.alloc(4); | |||||
| assert(q.is_empty(), "queue should start empty"); | |||||
| assert_equal_int(q.get_count(), 0); | |||||
| q.push_back(1); | |||||
| q.push_back(2); | |||||
| q.push_back(3); | |||||
| assert_equal_int(q.get_count(), 3); | |||||
| assert_equal_int(q.get_next(), 1); | |||||
| assert_equal_int(q.get_count(), 2); | |||||
| assert(!q.is_empty(), "should not be empty"); | |||||
| assert_equal_int(q.get_next(), 2); | |||||
| assert_equal_int(q.get_count(), 1); | |||||
| q.push_back(4); | |||||
| assert_equal_int(q.get_count(), 2); | |||||
| assert_equal_int(q.get_next(), 3); | |||||
| assert_equal_int(q.get_count(), 1); | |||||
| assert(!q.is_empty(), "should not be empty"); | |||||
| assert_equal_int(q.get_next(), 4); | |||||
| assert(q.is_empty(), "should be empty"); | |||||
| assert_equal_int(q.get_count(), 0); | |||||
| return pass; | |||||
| } | |||||
| proc test_array_lists_adding_and_removing() -> testresult { | proc test_array_lists_adding_and_removing() -> testresult { | ||||
| // test adding and removing | // test adding and removing | ||||
| @@ -446,7 +568,9 @@ s32 main(s32, char**) { | |||||
| invoke_test(test_array_lists_sorting); | invoke_test(test_array_lists_sorting); | ||||
| invoke_test(test_array_lists_searching); | invoke_test(test_array_lists_searching); | ||||
| invoke_test(test_array_list_sort_many); | invoke_test(test_array_list_sort_many); | ||||
| invoke_test(test_stack_array_lists); | |||||
| invoke_test(test_bucket_allocator); | invoke_test(test_bucket_allocator); | ||||
| invoke_test(test_queue); | |||||
| return 0; | return 0; | ||||
| } | } | ||||