From 865e16955ba84c2c913d7777a2f77584fecdf4cc Mon Sep 17 00:00:00 2001 From: Prathamesh Deshpande <94743121+prathameshd30@users.noreply.github.com> Date: Tue, 7 Jan 2025 23:14:29 +0530 Subject: [PATCH] recovery recommit --- .github/ISSUE_TEMPLATE/add-tests.md | 12 + .../workflows/cmake-multi-platform-val.yml | 110 ++++++++ .gitignore | 29 +++ CMakeLists.txt | 19 ++ CTestCustom.cmake | 2 + LICENSE | 24 ++ README.md | 109 ++++++++ include/algorithms/search/binary_search_arr.h | 31 +++ include/algorithms/search/linear_search_arr.h | 18 ++ include/algorithms/sort/bubble_sort.h | 48 ++++ include/algorithms/sort/insertion_sort.h | 26 ++ include/algorithms/sort/selection_sort.h | 27 ++ .../linked_list/doubly_linked_list.h | 128 ++++++++++ .../linked_list/singly_linked_list.h | 241 ++++++++++++++++++ include/data_structures/queue/queue_SLL.h | 37 +++ include/data_structures/queue/queue_vector.h | 23 ++ include/data_structures/stack/stack_SLL.h | 74 ++++++ include/data_structures/stack/stack_vector.h | 106 ++++++++ .../data_structures/tree/binary_search_tree.h | 68 +++++ include/data_structures/tree/binary_tree.h | 132 ++++++++++ .../data_structures/tree/binary_tree_addon.h | 98 +++++++ include/data_structures/vector/vector.h | 209 +++++++++++++++ .../search/binary_search_arr_example.c | 42 +++ .../sort/bubble_sort_primitive_example.c | 24 ++ .../sort/insertion_sort_primitive_example.c | 25 ++ .../sort/selection_sort_primitive_example.c | 25 ++ .../linked_list/singly_linked_list_example.c | 29 +++ .../queue/deque_DLL_primitive_example.c | 19 ++ .../queue/queue_vector_primitive_example.c | 20 ++ .../stack/stack_SLL_primitive_example.c | 18 ++ .../stack/stack_SLL_struct_example.c | 45 ++++ .../stack/stack_vector_primitive_example.c | 31 +++ .../stack/stack_vector_struct_example.c | 39 +++ .../tree/binary_search_tree_primitive.c | 24 ++ .../tree/binary_tree_primitive_addon.c | 50 ++++ .../tree/binary_tree_primitive_example.c | 42 +++ tests/data_structures/vector/CMakeLists.txt | 5 + .../vector/vector_primitive_test.c | 124 +++++++++ .../vector/vector_struct_test.c | 66 +++++ util/testing_macro.h | 17 ++ 40 files changed, 2216 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/add-tests.md create mode 100644 .github/workflows/cmake-multi-platform-val.yml create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 CTestCustom.cmake create mode 100644 LICENSE create mode 100644 README.md create mode 100644 include/algorithms/search/binary_search_arr.h create mode 100644 include/algorithms/search/linear_search_arr.h create mode 100644 include/algorithms/sort/bubble_sort.h create mode 100644 include/algorithms/sort/insertion_sort.h create mode 100644 include/algorithms/sort/selection_sort.h create mode 100644 include/data_structures/linked_list/doubly_linked_list.h create mode 100644 include/data_structures/linked_list/singly_linked_list.h create mode 100644 include/data_structures/queue/queue_SLL.h create mode 100644 include/data_structures/queue/queue_vector.h create mode 100644 include/data_structures/stack/stack_SLL.h create mode 100644 include/data_structures/stack/stack_vector.h create mode 100644 include/data_structures/tree/binary_search_tree.h create mode 100644 include/data_structures/tree/binary_tree.h create mode 100644 include/data_structures/tree/binary_tree_addon.h create mode 100644 include/data_structures/vector/vector.h create mode 100644 tests/algorithms/search/binary_search_arr_example.c create mode 100644 tests/algorithms/sort/bubble_sort_primitive_example.c create mode 100644 tests/algorithms/sort/insertion_sort_primitive_example.c create mode 100644 tests/algorithms/sort/selection_sort_primitive_example.c create mode 100644 tests/data_structures/linked_list/singly_linked_list_example.c create mode 100644 tests/data_structures/queue/deque_DLL_primitive_example.c create mode 100644 tests/data_structures/queue/queue_vector_primitive_example.c create mode 100644 tests/data_structures/stack/stack_SLL_primitive_example.c create mode 100644 tests/data_structures/stack/stack_SLL_struct_example.c create mode 100644 tests/data_structures/stack/stack_vector_primitive_example.c create mode 100644 tests/data_structures/stack/stack_vector_struct_example.c create mode 100644 tests/data_structures/tree/binary_search_tree_primitive.c create mode 100644 tests/data_structures/tree/binary_tree_primitive_addon.c create mode 100644 tests/data_structures/tree/binary_tree_primitive_example.c create mode 100644 tests/data_structures/vector/CMakeLists.txt create mode 100644 tests/data_structures/vector/vector_primitive_test.c create mode 100644 tests/data_structures/vector/vector_struct_test.c create mode 100644 util/testing_macro.h diff --git a/.github/ISSUE_TEMPLATE/add-tests.md b/.github/ISSUE_TEMPLATE/add-tests.md new file mode 100644 index 0000000..9577046 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/add-tests.md @@ -0,0 +1,12 @@ +--- +name: Add tests +about: Add tests for a particular data structure or algorithm +title: Add tests +labels: add-tests +assignees: '' + +--- + +Name of data structure or algorithm to which testing is to be added - +Is test already present - [YES,NO] +If test is already present, what is not covered and needs to be added? - \ No newline at end of file diff --git a/.github/workflows/cmake-multi-platform-val.yml b/.github/workflows/cmake-multi-platform-val.yml new file mode 100644 index 0000000..ec653da --- /dev/null +++ b/.github/workflows/cmake-multi-platform-val.yml @@ -0,0 +1,110 @@ +name: Multiplatform CMake Build, CTest, Valgrind Profiling + +on: + push: + branches: + - main + paths-ignore: + - '**/*.md' + - '.github/**' + pull_request: + branches: + - main + paths-ignore: + - '**/README.md' + - '.github/**' + workflow_dispatch: + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + #For testing all configs, true for report first failure and stop + fail-fast: false + # 1. + # 2. + # 3. + matrix: + os: [ubuntu-latest, windows-latest] + build_type: [Release] + c_compiler: [gcc, clang, cl] + include: + - os: windows-latest + c_compiler: cl + cpp_compiler: cl + - os: ubuntu-latest + c_compiler: gcc + cpp_compiler: g++ + - os: ubuntu-latest + c_compiler: clang + cpp_compiler: clang++ + exclude: + - os: windows-latest + c_compiler: gcc + - os: windows-latest + c_compiler: clang + - os: ubuntu-latest + c_compiler: cl + + steps: + - uses: actions/checkout@v4 + + - name: Set reusable strings + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + - name: Install Valgrind if not present + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get -y install valgrind + + + - name: Configure CMake + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -S ${{ github.workspace }} + + - name: Build + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + + - name: Test + working-directory: ${{ steps.strings.outputs.build-output-dir }} + run: ctest --build-config ${{ matrix.build_type }} + + - name: CTest-Memcheck-Valgrind + if: matrix.os == 'ubuntu-latest' + run: | + ctest -T memcheck -C Debug --test-dir build + ctest_output_code=$? + + - name: CTest Memcheck (Valgrind) Upload Results + if: matrix.os == 'ubuntu-latest' + uses: actions/upload-artifact@v4 + with: + name: memcheck-results-${{matrix.c_compiler}} + path: /home/runner/work/prime-headers/prime-headers/build/Testing/Temporary/MemoryChecker.* + if-no-files-found: ignore + + - name: Check if valgrind failed + if: matrix.os == 'ubuntu-latest' + run: | + pattern=".*LastTestsFailed.*.log" + files=$(find /home/runner/work/prime-headers/prime-headers/build/Testing/Temporary/ -regex "$pattern") + if [ -n "$files" ]; then + echo "Valgrind Failed, LastTestFailed files exist and are uploaded to Artifacts" + exit 1 + else + echo "Valgrind Passed" + fi + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..752b6fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +*.gch +*.exe +*.out +*.exe +.vscode/ +.vs/ +out/ + +list.txt + +#CMake +build/ +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles/ +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +CMakeUserPresets.json +DartConfiguration.tcl + +#Misc +string/ +local-test.bash \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..59107ee --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.28) # Needed to reduce version for compatibility with MS VS 2022 + +project(prime-headers C) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_BUILD_TYPE Debug) +##set(CMAKE_BUILD_TYPE Release) + +# deliberately not including these subdirectories by glob regex as precaution + +include_directories(include/algorithms/sort) +include_directories(include/data_structures/vector) +include_directories(util) + +enable_testing() +include(CTest) + +add_subdirectory(tests/data_structures/vector) diff --git a/CTestCustom.cmake b/CTestCustom.cmake new file mode 100644 index 0000000..e84e077 --- /dev/null +++ b/CTestCustom.cmake @@ -0,0 +1,2 @@ +set(MEMORYCHECK_COMMAND valgrind) +set(MEMORYCHECK_COMMAND_OPTIONS "--leak-check=full") \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4c115b --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +# Prime Headers +## Header-only, type-safe, generic data structures and algorithms for C. + +[![Multiplatform CMake Build, CTest, Valgrind Profiling](https://github.com/prathameshd30/prime-headers/actions/workflows/cmake-multi-platform-val.yml/badge.svg)](https://github.com/prathameshd30/prime-headers/actions/workflows/cmake-multi-platform-val.yml) + +Prime Headers is (aiming to be) a headers-only, easy to use, type-safe way to use generic data structures and algorithms in C Projects. + +It aims to have each data structure and algorithm thoroughly tested with primitive and pointer-to-structs examples. + +It works primarily by ~~ab~~using the C preprocessor to a scale hitherto undreamt of (I have later realised that this scale was indeed dreamt to). + +It uses macros with arguments to generate the appropriate structs and functions at the preprocessing stage, leading to no runtime overhead. However, this approach has definite drawbacks, which are clarified further. + +It uses CMake as the build system, Valgrind for checking memory safety (which needs to be migrated to AddressSanitizer as Valgrind is too slow) and GitHub Actions for checking cross-platform compatibility. + +### Features +- [x] Header-only, generic, type-safe data structures and algorithms. +- [x] Build tested on multiple platforms and compilers using CMake and GitHub actions. +- [x] Unit tested using CTest. +- [x] Memory profiled using Valgrind. +- [x] Supports primitive data structures as well as pointer-to-structs. + +### Currently Tested Platforms +- Ubuntu + - gcc + - clang +- Windows + - cl (MSVC) + +### To Do +- [x] Use GitHub Actions for testing +- [x] Use Valgrind for testing +- [x] Setup CMake, CTest and GitHub actions +- [ ] Migrate memory profiler to AddressSanitizer from Valgrind +- [ ] Write primitive as well as pointer-to-structs examples for each data structure and algorithm + +### Checklist +- Each function, with pointer parameters, should check for NULL for each pointer parameter. +- Have a thorough deletion mechanism for each data structure. +- Library functions in snake_case_##DATA_STRUCTURE().. +- All reallocs need to be first assigned to temp variables, so as to not lose access to data. + +### To build and test locally +After ensuring you have the prerequisite dependencies (CMake and Valgrind), run these commands in the root directory of the repository. +```bash +$ pwd # Make sure you are in the root directory of the repository +$ mkdir build +$ cd build +$ cmake .. +$ cmake --build . +$ ctest # Just run the tests without memory profiling +$ ctest -T memcheck -C Debug --test-dir ../build # Valgrind memcheck and test +``` + +### Data structures and algorithms implemented + +> The project is a work in progress, with an emphasis on getting things working first. Apologies for the ugly/(currently wrong) code. + +- [x] Vector +- [x] Stack using Vector +- [x] Stack using Linked List +- [x] Queue using Vector +- [x] Queue using Linked List +- [x] Deque (Double Ended Queue) using Vector +- [x] Deque (Double Ended Queue) using Doubly Linked List +- [x] Singly Linked List +- [ ] Set +- [ ] Unordered Set +- [ ] Map +- [ ] Unordered Map (Hashmap) +- [ ] Circular Singly Linked List +- [x] Doubly Linked List +- [ ] Circular Doubly Linked List +- [ ] Generalized Linked List +- [ ] Heap +- [x] Binary Tree (Generation using 2 traversals left) +- [x] Binary Search Tree (Done recursively, TODO delete for all 3 cases) +- [ ] AVL Tree +- [ ] RB Tree + +### Algorithms implemented + +- [x] Linear Search in Vector +- [x] Linear Search in SLL +- [ ] Binary Search +- [x] Bubble Sort +- [x] Selection Sort +- [x] Insertion Sort +- [ ] Merge Sort +- [ ] Quick sort + +### Pros + +1. Relatively easy use of generic data structures and algorithms while being type-safe. +2. Is cool, I mean what is cooler than preprocessor hijinks. + +### Cons + +1. This method is optimised for ease of use (probably for beginners/learners because it primarily works with pointers to structs), however, defining multiple data structures in the same file may (read WILL) lead to **slower compilation times** due to large compilation units because of the coupling of interfaces (headers & prototypes) and the actual functionality (function definitions) itself. +2. **Poor support** (slow) for Intellisense and similar code intelligence and autocompletion tools. +3. As all the functions are defined in the macro, with everything being in C, there is no way to apply **access modifiers** to helper functions for a cleaner interface and hacks like using double underscores seem inelegant. + +> This project is a side-effect of trying to develop a command-line tool for easier use of generic data structures for C, which splits the interface and the function definitions, leading to better compilation times. + +## Some helpful projects which helped me develop this + +1. Thought this was an original idea, but this repository I found later implemented this already - https://github.com/mystborn/GenericDataStructures + +2. I got the idea for the need of type-safe data structures by seeing this repository, otherwise it is perfect, especially the error handling is **chef's kiss** - https://github.com/MostafaTwfiq/C-DataStructures-And-Algorithms \ No newline at end of file diff --git a/include/algorithms/search/binary_search_arr.h b/include/algorithms/search/binary_search_arr.h new file mode 100644 index 0000000..425f0ab --- /dev/null +++ b/include/algorithms/search/binary_search_arr.h @@ -0,0 +1,31 @@ +#ifndef BINARY_SEARCH_ARR_H +#define BINARY_SEARCH_ARR_H + +#include + +#define DEFINE_BINARY_SEARCH_ARR(NAME, TYPE)\ +TYPE* recursive_binary_helper_##NAME(TYPE* arr, uint64_t low, uint64_t high, TYPE val, int16_t (*comparator)(TYPE, TYPE)){\ + if(high >= low){\ + uint64_t mid = (low+high)/2;\ + int16_t res = comparator(val ,arr[mid]);\ + if(res == 0){\ + return &(arr[mid]);\ + }\ + else if(res < 0){\ + return recursive_binary_helper_##NAME(arr, low, mid, val, comparator);\ + }\ + else if(res > 0){\ + return recursive_binary_helper_##NAME(arr, mid+1, high, val, comparator);\ + }\ + }\ + return NULL;\ +}\ +TYPE* recursive_binary_search_##NAME(TYPE* arr, size_t size, TYPE val ,int16_t (*comparator)(TYPE,TYPE)){\ + uint64_t low = 0;\ + uint64_t high = size - 1;\ + return recursive_binary_helper_##NAME(arr, low, high, val, comparator);\ +}\ + + + +#endif \ No newline at end of file diff --git a/include/algorithms/search/linear_search_arr.h b/include/algorithms/search/linear_search_arr.h new file mode 100644 index 0000000..cd46df9 --- /dev/null +++ b/include/algorithms/search/linear_search_arr.h @@ -0,0 +1,18 @@ +#ifndef LINEAR_SEARCH +#define LINEAR_SEARCH + +#include +#include + +#define DEFINE_LINEAR_SEARCH_ARR(NAME, TYPE)\ +bool linear_search_##NAME(TYPE* arr, uint64_t arrSize, bool(*comparator)(TYPE,TYPE), TYPE ref ,uint64_t* index){\ + for (uint64_t i = 0; i < count; ++i){\ + if(comparator(ref,arr[i])){\ + *index = i;\ + return true;\ + }\ + }\ + return false;\ +} + +#endif \ No newline at end of file diff --git a/include/algorithms/sort/bubble_sort.h b/include/algorithms/sort/bubble_sort.h new file mode 100644 index 0000000..ab9063b --- /dev/null +++ b/include/algorithms/sort/bubble_sort.h @@ -0,0 +1,48 @@ +#ifndef BUBBLE_SORT_H +#define BUBBLE_SORT_H + +#include +#include +#define DEFINE_BUBBLE_SORT_ARR(NAME,TYPE)\ +bool bubble_sort_##NAME(TYPE* data, uint64_t size, bool (*comparator)(TYPE, TYPE)){\ + if(!data || size == 0 || !comparator){\ + return false;\ + }\ + TYPE temp;\ + for(uint64_t i = 0; i +#include + +#define DEFINE_INSERTION_SORT(NAME,TYPE)\ +bool insertion_sort_##NAME(TYPE* data, int64_t size, bool (*comparator)(TYPE, TYPE), bool (*swap)(TYPE*, TYPE*)){\ + if(!data || size == 0 || !comparator || !swap){\ + return false;\ + }\ + int64_t j;\ + TYPE key;\ + for(int64_t i = 1; i= 0){\ + swap(&data[j+1],&data[j]);\ + --j;\ + }\ + data[j+1] = key;\ + }\ + return true;\ +} + +#endif \ No newline at end of file diff --git a/include/algorithms/sort/selection_sort.h b/include/algorithms/sort/selection_sort.h new file mode 100644 index 0000000..795c9cd --- /dev/null +++ b/include/algorithms/sort/selection_sort.h @@ -0,0 +1,27 @@ +#ifndef SELECTION_SORT_H +#define SELECTION_SORT_H + +#include +#include + +#define DEFINE_SELECTION_SORT(NAME, TYPE)\ +bool selection_sort_##NAME(TYPE* data, uint64_t size, bool (*comparator)(TYPE, TYPE), bool (*swap)(TYPE*, TYPE*)){\ + if(!data || size == 0 || !comparator || !swap){\ + return false;\ + }\ + uint64_t key_index;\ + for (uint64_t i = 0; i < size; ++i){\ + key_index = i;\ + for(uint64_t j = i+1; j +#include + +#define DEFINE_DLL_NODE(NAME,TYPE)\ +struct NAME{\ + TYPE val;\ + struct NAME* next;\ + struct NAME* prev;\ +};\ +typedef struct NAME NAME;\ +NAME* new_##NAME(TYPE val, NAME* next, NAME* prev){\ + NAME* obj = malloc(sizeof(NAME));\ + if(!obj){\ + return NULL;\ + }\ + obj->val = val;\ + obj->next = next;\ + obj->prev = prev;\ + return obj;\ +}\ +bool insert_at_head_DLL_##NAME(NAME** head, TYPE val){\ + if(!head || !*head){\ + return false;\ + }\ + NAME* obj = new_##NAME(val, *head,NULL);\ + if(!obj){\ + return false;\ + }\ + *head = obj;\ + return true;\ +}\ +bool insert_after_node_DLL_##NAME(NAME* node, TYPE val){\ + if(!node){\ + return false;\ + }\ + NAME* obj = new_##NAME(val,node->next,node);\ + if(!obj){\ + return false;\ + }\ + if(node->next){\ + node->next->prev = obj;\ + }\ + node->next = obj;\ + return true;\ +}\ +bool insert_at_end_DLL_##NAME(NAME* head, TYPE val){\ + if(!head){\ + return false;\ + }\ + while(head->next){\ + head = head->next;\ + }\ + if(!insert_after_node_DLL_##NAME(head,val)){\ + return false;\ + }\ + return true;\ +}\ +bool remove_node_DLL_##NAME(NAME* node, TYPE* val, bool (*delete_element)(TYPE)){\ + if(!node){\ + return false;\ + }\ + if(node->prev){\ + node->prev->next = node->next;\ + }\ + if(node->next){\ + node->next->prev = node->prev;\ + }\ + if(val){\ + *val = node->val;\ + }\ + else if(delete_element){\ + delete_element(node->val); /*should there be error checking for delete_element?, if so how? */\ + }\ + free(node);\ + return true;\ +}\ +bool remove_from_end_DLL_##NAME(NAME* head, TYPE* val, bool (*delete_element)(TYPE)){\ + if(!head){\ + return false;\ + }\ + while(head->next){\ + head = head->next;\ + }\ + if(!remove_node_DLL_##NAME(head,val,delete_element)){\ + return false;\ + }\ + return true;\ +}\ +bool remove_from_beginning_##NAME(NAME** head, TYPE* val, bool (*delete_element)(TYPE)){\ + if(!head || !(*head)){\ + return false;\ + }\ + NAME* node = *head;\ + *head = node->next;\ + if(val){\ + *val = node->val;\ + }\ + else if(delete_element){\ + delete_element(node->val);\ + }\ + free(node);\ + return true;\ +}\ +bool delete_DLL_##NAME(NAME* head, bool (*delete_element)(TYPE)){\ + NAME* tempNext;\ + while(head){\ + tempNext = head->next;\ + if(delete_element){\ + delete_element(head->val);/*Error checking? if so how?*/\ + }\ + free(head);\ + head = tempNext;\ + }\ + return true;\ +}\ +void print_DLL_##NAME(NAME* head, void(*print_element)(TYPE)){\ + while(head){\ + print_element(head->val);\ + head = head->next;\ + }\ + return;\ +}\ + + +#endif \ No newline at end of file diff --git a/include/data_structures/linked_list/singly_linked_list.h b/include/data_structures/linked_list/singly_linked_list.h new file mode 100644 index 0000000..bbf9220 --- /dev/null +++ b/include/data_structures/linked_list/singly_linked_list.h @@ -0,0 +1,241 @@ +#ifndef SLL_H +#define SLL_H + +#include +#include +#include + +/*Should there be insertAtIndex? No, use indexing to traverse through list and use insert_after using the pointer, as insert at index would use some integer size, and I don't like to choose*/ + +#define DEFINE_SINGLY_LINKED_LIST_NODE(NAME, TYPE) \ + typedef struct NAME NAME; \ + struct NAME \ + { \ + TYPE val; \ + NAME *next; \ + }; \ + NAME *new_##NAME(TYPE element, NAME *next) \ + { \ + NAME *new_obj = malloc(sizeof(NAME)); \ + if (!new_obj) \ + { \ + return NULL; \ + } \ + new_obj->val = element; \ + new_obj->next = next; \ + return new_obj; \ + } \ + bool insert_at_head_SLL_##NAME(NAME **head, TYPE element) \ + { \ + if (!head || !(*head)) \ + { \ + return false; \ + } \ + NAME *new_obj = new_##NAME(element, *head); \ + if (!new_obj) \ + { \ + return false; \ + } \ + *head = new_obj; \ + return true; \ + } \ + bool insert_after_SLL_##NAME(NAME *node, TYPE element) \ + { \ + if (!node) \ + { \ + return false; \ + } \ + NAME *new_obj = new_##NAME(element, node->next); \ + if (!new_obj) \ + { \ + return false; \ + } \ + node->next = new_obj; \ + return true; \ + } \ + bool insert_at_end_SLL_##NAME(NAME *head, TYPE element) \ + { \ + if (!head) \ + { \ + return false; \ + } \ + NAME *new_obj = new_##NAME(element, NULL); \ + if (!new_obj || !head) \ + { \ + return false; \ + } \ + while (head->next) \ + { \ + head = head->next; \ + } \ + head->next = new_obj; \ + return true; \ + } \ + void print_SLL_##NAME(const NAME *head, void (*print_node)(TYPE)) \ + { \ + if (!head) \ + { \ + return; \ + } \ + while (head) \ + { \ + print_node(head->val); \ + head = head->next; \ + } \ + } \ + bool remove_head_SLL_##NAME(NAME **head, bool (*delete_val)(TYPE)) \ + { \ + if (!head || !(*head)) \ + { \ + return false; \ + } \ + NAME *temp = *head; \ + *head = (*head)->next; \ + if (delete_val) \ + { \ + delete_val(temp->val); \ + } \ + free(temp); \ + return true; \ + } \ + bool remove_tail_SLL_##NAME(NAME **head, bool (*delete_val)(TYPE)) \ + { \ + if (!head || !(*head)) \ + { \ + return false; \ + } \ + if ((*head)->next == NULL) \ + { \ + free(*head); \ + *head = NULL; \ + return true; \ + } \ + NAME *temp = (*head)->next; \ + NAME *tempPrev = *head; \ + while (temp->next) \ + { \ + tempPrev = temp; \ + temp = temp->next; \ + } \ + tempPrev->next = temp->next; \ + if (delete_val) \ + { \ + delete_val(temp->val); \ + } \ + free(temp); \ + return true; \ + } \ + bool remove_value_SLL_##NAME(NAME **head, TYPE val, bool (*delete_val)(TYPE)) \ + { \ + if (!head || !(*head)) \ + { \ + return false; \ + } \ + if ((*head)->val == val) \ + { \ + NAME *temp = *head; \ + *head = (*head)->next; \ + free(temp); \ + return true; \ + } \ + NAME *temp = (*head)->next; \ + NAME *tempPrev = (*head); \ + while (temp) \ + { \ + if (temp->val == val) \ + { \ + tempPrev->next = temp->next; \ + if (delete_val) \ + { \ + delete_val(temp->val); \ + } \ + free(temp); \ + return true; \ + } \ + tempPrev = temp; \ + temp = temp->next; \ + } \ + return false; \ + } \ + bool remove_node_SLL_##NAME(NAME **head, NAME *node, bool delete_val(TYPE)) \ + { \ + if (!head || !(*head)) \ + { \ + return false; \ + } \ + if (*head == node) \ + { \ + return remove_head_SLL_##NAME(head, delete_val); \ + } \ + NAME *temp = (*head)->next; \ + NAME *tempPrev = *head; \ + while (temp != node && temp != NULL) \ + { \ + tempPrev = temp; \ + temp = temp->next; \ + } \ + if (temp == NULL) \ + { \ + return false; \ + } \ + tempPrev->next = temp->next; \ + if (delete_val) \ + { \ + delete_val(temp->val); \ + } \ + free(temp); \ + return true; \ + } \ + NAME *find_val_SLL_##NAME(NAME *head, TYPE val) /*To find index of result, traverse manually*/ \ + { \ + if (!head) \ + { \ + return NULL; \ + } \ + while (head) \ + { \ + if (head->val == val) \ + { \ + return head; \ + } \ + head = head->next; \ + } \ + \ return NULL; \ + } \ + bool is_empty_SLL_##NAME(NAME *head) \ + { \ + return (head == NULL); \ + } \ + bool delete_SLL_##NAME(NAME **head, bool (*delete_val)(TYPE)) \ + { \ + if (!head || !(*head)) \ + { \ + return false; \ + } \ + while (!remove_head_SLL_##NAME(head, delete_val)) \ + ; \ + if (*head == NULL) \ + { \ + return true; \ + } \ + return false; /*head double pointer null, to be honest I don;t even know what it means*/ \ + } \ + bool linear_search_##NAME(NAME *head, bool (*comparator)(TYPE, TYPE), TYPE ref, NAME **foundNode) \ + { \ + while (head) \ + { \ + if (comparator(ref, head->val)) \ + { \ + if (foundNode) \ + { \ + *foundNode = head; \ + } \ + return true; \ + } \ + head = head->next; \ + } \ + *foundNode = NULL; \ + return false; \ + } + +#endif \ No newline at end of file diff --git a/include/data_structures/queue/queue_SLL.h b/include/data_structures/queue/queue_SLL.h new file mode 100644 index 0000000..a52e8f3 --- /dev/null +++ b/include/data_structures/queue/queue_SLL.h @@ -0,0 +1,37 @@ +#include +#include "../linked_list/singly_linked_list.h" + +#define DEFINE_QUEUE_SLL(NAME,NODE_NAME,TYPE)\ +DEFINE_SINGLY_LINKED_LIST_NODE(NODE_NAME,TYPE)\ +struct NAME{\ + NODE_NAME* front;\ + NODE_NAME* rear;\ +};\ +typedef struct NAME NAME;\ +NAME* new_##NAME(void){\ + NAME* obj = malloc(sizeof(NAME));\ + obj->front = NULL;\ + obj->rear = NULL;\ + return obj;\ +}\ +bool enqueue_##NAME(NAME* obj, TYPE val){\ + if(!obj){\ + return false;\ + }\ + return insert_at_head_SLL_##NODE_NAME(&obj->front, val);\ +}\ +bool dequeue_##NAME(NAME* obj, TYPE* return_param, bool (*delete_element)(TYPE)){\ + if(!obj){\ + return false;\ + }\ + NODE_NAME* temp = obj->rear;\ + if(return_param){\ + *return_param = obj->rear->val;\ + }\ + else if(delete_element){\ + delete_element(temp->val);\ + }\ + obj->rear = obj->rear->next;\ + free(temp);\ + return true;\ +} \ No newline at end of file diff --git a/include/data_structures/queue/queue_vector.h b/include/data_structures/queue/queue_vector.h new file mode 100644 index 0000000..7b15e0b --- /dev/null +++ b/include/data_structures/queue/queue_vector.h @@ -0,0 +1,23 @@ +#ifndef QUEUE_VECTOR_H +#define QUEUE_VECTOR_H +#include "../vector/vector.h" + +#define DEFINE_QUEUE_VECTOR(NAME, VEC_NAME, TYPE)\ +DEFINE_VECTOR(VEC_NAME,TYPE)\ +struct NAME{\ + VEC_NAME* vec;\ +};\ +typedef struct NAME NAME;\ +NAME* new_##NAME(TYPE val){\ + NAME* obj = malloc(sizeof(NAME));\ + obj->vec = new_##VEC_NAME(0,val);\ + return obj;\ +}\ +bool enqueue_##NAME(NAME* obj, TYPE val){\ + return add_at_end_##VEC_NAME(obj->vec,val);\ +}\ +bool dequeue_##NAME(NAME* obj, TYPE* val){\ + return remove_from_beginning_##VEC_NAME(obj->vec, val, NULL);\ +} + +#endif \ No newline at end of file diff --git a/include/data_structures/stack/stack_SLL.h b/include/data_structures/stack/stack_SLL.h new file mode 100644 index 0000000..df98941 --- /dev/null +++ b/include/data_structures/stack/stack_SLL.h @@ -0,0 +1,74 @@ +#ifndef STACK_SLL_H +#define STACK_SLL_H + +#include "../linked_list/singly_linked_list.h" + +#define DEFINE_STACK_SLL(NAME, NODE_NAME,TYPE)\ +DEFINE_SINGLY_LINKED_LIST_NODE(NODE_NAME, TYPE)\ +struct NAME{\ + NODE_NAME* top;\ +};\ +typedef struct NAME NAME;\ +NAME* new_##NAME(void){\ + NAME* obj = malloc(sizeof(NAME));\ + obj->top = NULL;\ + return obj;\ +}\ +bool isEmpty_##NAME(NAME* obj){\ + if(!obj){\ + return false;\ + }\ + if(!obj->top){\ + return true;\ + }\ + return false;\ +}\ +bool push_##NAME(NAME* obj, TYPE val){\ + if(!obj){\ + return false;\ + }\ + NODE_NAME* newNode = new_##NODE_NAME(val, obj->top);\ + if(!newNode){\ + return false;\ + }\ + obj->top = newNode;\ + return true;\ +}\ +bool top_##NAME(NAME* obj, TYPE* return_param){\ + if(!obj || isEmpty_##NAME(obj)){\ + return false;\ + }\ + *return_param = obj->top->val;\ + return true;\ +}\ +bool pop_##NAME(NAME* obj, bool (*delete_type)(TYPE)){\ + if(!obj || isEmpty_##NAME(obj)){\ + return false;\ + }\ + NODE_NAME* temp = obj->top;\ + obj->top = obj->top->next;\ + if(delete_type){\ + delete_type(temp->val);\ + }\ + free(temp);\ + return true;\ +}\ +bool delete_##NAME(NAME* obj, bool (*delete_element)(TYPE)){\ + if(!obj){\ + return false;\ + }\ + delete_SLL_##NODE_NAME(&obj->top,delete_element);\ + return true;\ +}\ +void print_##NAME(NAME* obj, void (*print_element)(TYPE)){\ + if(obj->top == NULL){\ + return;\ + }\ + NODE_NAME* temp = obj->top;\ + while(temp!=NULL){\ + print_element(temp->val);\ + temp = temp->next;\ + }\ +}\ + +#endif \ No newline at end of file diff --git a/include/data_structures/stack/stack_vector.h b/include/data_structures/stack/stack_vector.h new file mode 100644 index 0000000..a2531de --- /dev/null +++ b/include/data_structures/stack/stack_vector.h @@ -0,0 +1,106 @@ +#ifndef STACK_VECTOR_H +#define STACK_VECTOR_H + +#include +#include +#include +#include "../vector/vector.h" + +#define DEFINE_STACK_VECTOR(NAME, VEC_NAME,TYPE)\ +DEFINE_VECTOR(VEC_NAME,TYPE)\ +typedef struct NAME NAME;\ +struct NAME{\ + VEC_NAME* vec;\ + uint64_t top;\ + bool isEmpty;\ +};\ +NAME* new_##NAME(void){\ + NAME* new_obj = malloc(sizeof(NAME));\ + if(!new_obj){\ + return NULL;\ + }\ + new_obj->vec = new_##VEC_NAME(0);\ + if(!new_obj->vec){\ + free(new_obj);\ + return NULL;\ + }\ + new_obj->top = 0;\ + new_obj->isEmpty = true;\ + return new_obj;\ +}\ +bool isEmpty_##NAME(NAME* obj){\ + if(!obj || !obj->vec){\ + return false;\ + }\ + else if(obj->isEmpty|| !obj->vec->data || obj->vec->size == 0){\ + return true;\ + }\ + return false;\ +}\ +bool push_##NAME(NAME* obj, TYPE val){\ + if(!obj || !obj->vec){\ + return false;\ + }\ + if(!add_at_end_##VEC_NAME(obj->vec,val)){\ + return false;\ + }\ + else{\ + if(isEmpty_##NAME(obj)){\ + obj->isEmpty = false;\ + }\ + obj->top = obj->vec->size - 1;\ + return true;\ + }\ +}\ +bool top_##NAME(NAME* obj, TYPE* return_param){\ + if(!obj || !obj->vec){\ + return false;\ + }\ + if(isEmpty_##NAME(obj)){\ + return false;\ + }\ + *return_param = obj->vec->data[obj->top];\ + return true;\ +}\ +bool pop_##NAME(NAME* obj, bool (*delete_element)(TYPE)){\ + if(!obj || !obj->vec){\ + return false;\ + }\ + if(isEmpty_##NAME(obj)){\ + return false;\ + }\ + if(!remove_from_end_##VEC_NAME(obj->vec,NULL, delete_element)){\ + return false;\ + }\ + if(obj->top == 0){\ + obj->isEmpty = true;\ + }\ + else{\ + obj->top = obj->vec->size - 1;\ + }\ + return true;\ +}\ +bool delete_##NAME(NAME* obj, bool (*delete_element)(TYPE)){\ + if(!obj || !obj->vec){\ + return false;\ + }\ + if(delete_element){\ + delete_##VEC_NAME(obj->vec,delete_element);\ + }\ + free(obj);\ + return true;\ +}\ +void print_##NAME(NAME* obj, void (*print_type)(TYPE)){\ + if(isEmpty_##NAME(obj)){\ + return;\ + }\ + for(uint64_t i = obj->top; ; --i){\ + print_type(obj->vec->data[i]);\ + if(i==0){\ + return;\ + }\ + }\ +} + + +#endif \ No newline at end of file diff --git a/include/data_structures/tree/binary_search_tree.h b/include/data_structures/tree/binary_search_tree.h new file mode 100644 index 0000000..cd33aa6 --- /dev/null +++ b/include/data_structures/tree/binary_search_tree.h @@ -0,0 +1,68 @@ +/** + * TO DO + * Delete Node (All 3 Cases, Leaf Node, 1 Child, 2 Children) + */ +#ifndef BST_H +#define BST_H + +#include +#include "binary_tree.h" + +#define DEFINE_BINARY_SEARCH_TREE(TREE_NAME, NODE_NAME,TYPE)\ +DEFINE_BINARY_TREE(TREE_NAME,NODE_NAME, TYPE)\ +bool recursive_insert_BST_helper_##TREE_NAME(NODE_NAME* root, TYPE val, int16_t (*comparator)(TYPE, TYPE)){\ + if(!root){\ + return false;\ + }\ + int16_t result = comparator(val, root->val);\ + if(result == 0){\ + return false;\ + }\ + else if(result > 0){\ + if(root->right){\ + recursive_insert_BST_helper_##TREE_NAME(root->right,val, comparator);\ + }\ + else{\ + return insert_at_right_##NODE_NAME(root,val,NULL,NULL);\ + }\ + }\ + else if(result < 0){\ + if(root->left){\ + recursive_insert_BST_helper_##TREE_NAME(root->left,val, comparator);\ + }\ + else{\ + insert_at_left_##NODE_NAME(root,val,NULL,NULL);\ + }\ + }\ + return root;\ +}\ +bool recursive_insert_BST_##TREE_NAME(TREE_NAME* tree, TYPE val, int16_t (*comparator)(TYPE, TYPE)){\ + if(!(tree->root)){\ + return false;\ + }\ + if(recursive_insert_BST_helper_##TREE_NAME(tree->root,val,comparator)){\ + return true;\ + }\ + return false;\ +}\ +NODE_NAME* recursive_search_BST_helper_##TREE_NAME(NODE_NAME* root, TYPE val, int16_t (*comparator)(TYPE,TYPE)){\ + if(!root){\ + return NULL;\ + }\ + int16_t result = comparator(val, root->val);\ + if(result == 0){\ + return root;\ + }\ + else if(result > 0){\ + return recursive_search_BST_helper_##TREE_NAME(root->right, val, comparator);\ + }\ + else if(result < 0){\ + return recursive_search_BST_helper_##TREE_NAME(root->left, val, comparator);\ + }\ + return NULL; /*Should be impossible to reach*/\ +}\ +NODE_NAME* recursive_search_BST_##TREE_NAME(TREE_NAME* tree, TYPE val, int16_t(*comparator)(TYPE, TYPE)){\ + return recursive_search_BST_helper_##TREE_NAME(tree->root,val,comparator);\ +} + +#endif \ No newline at end of file diff --git a/include/data_structures/tree/binary_tree.h b/include/data_structures/tree/binary_tree.h new file mode 100644 index 0000000..bdbec22 --- /dev/null +++ b/include/data_structures/tree/binary_tree.h @@ -0,0 +1,132 @@ +#ifndef BINARY_TREE_H +#define BINARY_TREE_H + +#include +#include + +#define DEFINE_BINARY_TREE(NAME, NODE_NAME, TYPE)\ +struct NODE_NAME{\ + TYPE val;\ + struct NODE_NAME* left;\ + struct NODE_NAME* right;\ +};\ +typedef struct NODE_NAME NODE_NAME;\ +struct NAME{\ + NODE_NAME* root;\ +};\ +typedef struct NAME NAME;\ +NODE_NAME* new_##NODE_NAME(TYPE val, NODE_NAME* left, NODE_NAME* right){\ + NODE_NAME* obj = malloc(sizeof(NODE_NAME));\ + if(!obj){\ + return NULL;\ + }\ + obj->val = val;\ + obj->left = left;\ + obj->right = right;\ + return obj;\ +}\ +bool insert_at_left_##NODE_NAME(NODE_NAME* obj, TYPE val, NODE_NAME* left, NODE_NAME* right){\ + if(!obj){\ + return false;\ + }\ + if(obj->left){\ + return false;\ + }\ + NODE_NAME* new_node = new_##NODE_NAME(val,left,right);\ + if(!new_node){\ + return false;\ + }\ + obj->left = new_node;\ + return true;\ +}\ +bool insert_at_right_##NODE_NAME(NODE_NAME* obj, TYPE val, NODE_NAME* left, NODE_NAME* right){\ + if(!obj){\ + return false;\ + }\ + if(obj->right){\ + return false;\ + }\ + NODE_NAME* new_node = new_##NODE_NAME(val, left, right);\ + if(!new_node){\ + return false;\ + }\ + obj->right = new_node;\ + return true;\ +}\ +NAME* new_##NAME(TYPE val){\ + NAME* obj = malloc(sizeof(NAME));\ + if(!obj){\ + return NULL;\ + }\ + obj->root = new_##NODE_NAME(val,NULL,NULL);\ + if(!obj->root){\ + free(obj);\ + return NULL;\ + }\ + return obj;\ +}\ +void print_recursive_inorder_helper_##NODE_NAME(NODE_NAME* node, void (*print_val)(TYPE)){\ + if(!node){\ + return;\ + }\ + if(node->left){\ + print_recursive_inorder_helper_##NODE_NAME(node->left,print_val);\ + }\ + print_val(node->val);\ + if(node->right){\ + print_recursive_inorder_helper_##NODE_NAME(node->right,print_val);\ + }\ + return;\ +}\ +bool print_recursive_inorder_##NAME(NAME* obj, void (*print_val)(TYPE)){\ + if(!obj){\ + return false;\ + }\ + print_recursive_inorder_helper_##NODE_NAME(obj->root,print_val);\ + return true;\ +}\ +void print_recursive_preorder_helper_##NODE_NAME(NODE_NAME* obj, void(*print_val)(TYPE)){\ + if(!obj){\ + return;\ + }\ + print_val(obj->val);\ + if(obj->left){\ + print_recursive_preorder_helper_##NODE_NAME(obj->left, print_val);\ + }\ + if(obj->right){\ + print_recursive_preorder_helper_##NODE_NAME(obj->right, print_val);\ + }\ + return;\ +}\ +bool print_recursive_preorder_##NAME(NAME* obj, void(*print_val)(TYPE)){\ + if(!obj){\ + return false;\ + }\ + print_recursive_preorder_helper_##NODE_NAME(obj->root,print_val);\ + return true;\ +}\ +void print_recursive_postorder_helper_##NODE_NAME(NODE_NAME* obj, void(*print_val)(TYPE)){\ + if(!obj){\ + return;\ + }\ + if(obj->left){\ + print_recursive_postorder_helper_##NODE_NAME(obj->left, print_val);\ + }\ + if(obj->right){\ + print_recursive_postorder_helper_##NODE_NAME(obj->right, print_val);\ + }\ + print_val(obj->val);\ + return;\ +}\ +bool print_recursive_postorder_##NAME(NAME* obj, void(*print_val)(TYPE)){\ + if(!obj){\ + return false;\ + }\ + print_recursive_postorder_helper_##NODE_NAME(obj->root, print_val);\ + return true;\ +} + + + + +#endif \ No newline at end of file diff --git a/include/data_structures/tree/binary_tree_addon.h b/include/data_structures/tree/binary_tree_addon.h new file mode 100644 index 0000000..229b219 --- /dev/null +++ b/include/data_structures/tree/binary_tree_addon.h @@ -0,0 +1,98 @@ +#ifdef BINARY_TREE_H +#ifndef BINARY_TREE_ALG_H +#define BINARY_TREE_ALG_H + +#include "../../../include/data_structures/vector/vector.h" +#include "../../../include/data_structures/stack/stack_vector.h" +#include "binary_tree.h" + +#define DEFINE_BINARY_TREE_ALGOS(NAME, NODE_NAME, TYPE, VECTOR_NAME, STACK_NAME, STACK_VECTOR_NAME)\ +DEFINE_BINARY_TREE(NAME, NODE_NAME, TYPE)\ +DEFINE_VECTOR(VECTOR_NAME, TYPE)\ +DEFINE_STACK_VECTOR(STACK_NAME,STACK_VECTOR_NAME, NODE_NAME*)\ +void recursive_inorder_vec_helper_##NODE_NAME(NODE_NAME* node, VECTOR_NAME* vec){\ + if(!node){\ + return;\ + }\ + if(node->left){\ + recursive_inorder_vec_helper_##NODE_NAME(node->left,vec);\ + }\ + add_at_end_##VECTOR_NAME(vec, node->val);\ + if(node->right){\ + recursive_inorder_vec_helper_##NODE_NAME(node->right,vec);\ + }\ +}\ +VECTOR_NAME* recursive_inorder_vec_##NAME(NAME* obj){\ + VECTOR_NAME* new_vec = new_##VECTOR_NAME(0);\ + recursive_inorder_vec_helper_##NODE_NAME(obj->root, new_vec);\ + return new_vec;\ +}\ +void recursive_preorder_vec_helper_##NODE_NAME(NODE_NAME* node, VECTOR_NAME* vec){\ + if(!node){\ + return;\ + }\ + add_at_end_##VECTOR_NAME(vec, node->val);\ + if(node->left){\ + recursive_preorder_vec_helper_##NODE_NAME(node->left,vec);\ + }\ + if(node->right){\ + recursive_preorder_vec_helper_##NODE_NAME(node->right,vec);\ + }\ +}\ +VECTOR_NAME* recursive_preorder_vec_##NAME(NAME* obj){\ + VECTOR_NAME* new_vec = new_##VECTOR_NAME(0);\ + recursive_preorder_vec_helper_##NODE_NAME(obj->root, new_vec);\ + return new_vec;\ +}\ +void recursive_postorder_vec_helper_##NODE_NAME(NODE_NAME* node, VECTOR_NAME* vec){\ + if(!node){\ + return;\ + }\ + if(node->left){\ + recursive_postorder_vec_helper_##NODE_NAME(node->left,vec);\ + }\ + if(node->right){\ + recursive_postorder_vec_helper_##NODE_NAME(node->right,vec);\ + }\ + add_at_end_##VECTOR_NAME(vec, node->val);\ +}\ +VECTOR_NAME* recursive_postorder_vec_##NAME(NAME* obj){\ + VECTOR_NAME* new_vec = new_##VECTOR_NAME(0);\ + recursive_postorder_vec_helper_##NODE_NAME(obj->root, new_vec);\ + return new_vec;\ +}\ +bool print_preorder_##NAME(NAME* obj, void(*print_val)(TYPE), bool(*delete_element)(NODE_NAME*)){\ + STACK_NAME* st = new_##STACK_NAME();\ + push_##STACK_NAME(st, obj->root);\ + NODE_NAME* tempNode;\ + while(!(st->isEmpty)){\ + top_##STACK_NAME(st,&tempNode);\ + pop_##STACK_NAME(st,delete_element);\ + print_val(tempNode->val);\ + if(tempNode->right){\ + push_##STACK_NAME(st,tempNode->right);\ + }\ + if(tempNode->left){\ + push_##STACK_NAME(st,tempNode->left);\ + }\ + }\ + return true;\ +}\ +bool print_inorder_##NAME(NAME* obj, void(*print_val)(TYPE), bool(*delete_element)(NODE_NAME*)){\ + STACK_NAME* st = new_##STACK_NAME();\ + NODE_NAME* tempNode = obj->root;\ + while(tempNode!=NULL || !(st->isEmpty)){\ + while(tempNode){\ + push_##STACK_NAME(st,tempNode);\ + tempNode = tempNode->left;\ + }\ + top_##STACK_NAME(st,&tempNode);\ + print_val(tempNode->val);\ + pop_##STACK_NAME(st,delete_element);\ + tempNode = tempNode->right;\ + }\ + return true;\ +}\ + +#endif +#endif \ No newline at end of file diff --git a/include/data_structures/vector/vector.h b/include/data_structures/vector/vector.h new file mode 100644 index 0000000..f0a1972 --- /dev/null +++ b/include/data_structures/vector/vector.h @@ -0,0 +1,209 @@ +/* This implementation of vector does not preallocate memory to save time, as I intend for this to be a simple-to-understand implementation rather than the 'best' one*/ +#ifndef VECTOR_H +#define VECTOR_H + +#include +#include +#include + +#define DEFINE_VECTOR(NAME, TYPE)\ +typedef struct NAME NAME;\ +struct NAME{\ + TYPE* data;\ + uint64_t size;\ +};\ +NAME* new_##NAME(uint64_t size){ /*Size is set only after allocation of vector->data memory, need someone to clarify if this is advised*/ \ + NAME* new_obj = malloc(sizeof(NAME));\ + if(!new_obj){\ + return NULL;\ + }\ + if(size == 0){\ + new_obj->data = NULL;\ + new_obj->size = 0;\ + return new_obj;\ + }\ + new_obj->data = calloc(size,sizeof(TYPE));\ + if(!(new_obj->data)){\ + free(new_obj);\ + return NULL;\ + }\ + new_obj->size = size;\ + return new_obj;\ +}\ +NAME* construct_from_arr_##NAME(TYPE* const arr, uint64_t size){\ + if(!arr){\ + return NULL;\ + }\ + NAME* new_obj = new_##NAME(size);\ + if(!new_obj){\ + return NULL;\ + }\ + if(size == 0){\ + return new_obj;\ + }\ + for(uint64_t index = 0; index < new_obj->size; ++index){\ + new_obj->data[index] = arr[index];\ + }\ + return new_obj;\ +}\ +bool is_empty_##NAME(const NAME* const obj){\ + if(!obj){\ + return false;\ + }\ + if(obj->size == 0 || obj->data == NULL){\ + return true;\ + }\ + return false;\ +}\ +bool at_##NAME(const NAME* const obj, uint64_t index, TYPE* const val){\ + if(!obj || !val){\ + return false;\ + }\ + if(index > obj->size - 1){\ + return false;\ + }\ + *val = obj->data[index];\ + return true;\ +}\ +bool set_at_##NAME(const NAME* const obj, uint64_t index, TYPE val){\ + if(!obj){\ + return false;\ + }\ + if(obj->size == 0){\ + return false;\ + }\ + if(index > obj->size - 1){\ + return false;\ + }\ + obj->data[index] = val;\ + return true;\ +}\ +bool set_whole_##NAME(const NAME* const obj, TYPE val){\ + if(!obj || !(obj->data) || (obj->size == 0)){\ + return false;\ + }\ + for(uint64_t index = 0; index < obj->size; ++index){\ + obj->data[index] = val;\ + }\ + return true;\ +}\ +bool add_at_end_##NAME(NAME* const obj, TYPE val){\ + if(!obj){\ + return false;\ + }\ + TYPE* temp = realloc(obj->data, (obj->size + 1)* sizeof(TYPE));\ + if(!temp){\ + return false;\ + }\ + obj->data = temp;\ + ++obj->size;\ + obj->data[obj->size - 1] = val;\ + return true;\ +}\ +bool add_at_beginning_##NAME(NAME* const obj, TYPE val){\ + if(!obj){\ + return false;\ + }\ + TYPE* temp = realloc(obj->data, (obj->size + 1) * sizeof(TYPE));\ + if(!temp){\ + return false;\ + }\ + obj->data = temp;\ + ++obj->size;\ + for(uint64_t i = obj->size - 1; i>0; --i){\ + obj->data[i] = obj->data[i-1];\ + }\ + obj->data[0] = val;\ + return true;\ +}\ +bool remove_from_beginning_##NAME(NAME* const obj, TYPE* const val, bool (*delete_element)(TYPE)){\ + if(!obj || !obj->data || obj->size == 0){\ + return false;\ + }\ + if(val){\ + *val = obj->data[0];\ + }\ + else if(delete_element){\ + delete_element(obj->data[0]);\ + }\ + for(uint64_t i = 1; isize; ++i){\ + obj->data[i-1] = obj->data[i];\ + }\ + TYPE* temp = realloc(obj->data, (obj->size-1) * sizeof(TYPE));\ + if(!temp){\ + return false;\ + }\ + obj->data = temp;\ + --(obj->size);\ + return true;\ +}\ +bool remove_from_end_##NAME(NAME* const obj, TYPE* const val, bool (*delete_type)(TYPE)){\ + if(!obj || !obj->data || obj->size == 0){\ + return false;\ + }\ + if(val){\ + *val = obj->data[obj->size-1];\ + }\ + else if(delete_type){\ + delete_type(obj->data[obj->size-1]);\ + }\ + TYPE* temp = realloc(obj->data, (obj->size-1)*sizeof(TYPE));\ + if(!temp){\ + return false;\ + }\ + obj->data = temp;\ + --(obj->size);\ + return true;\ +}\ +void print_##NAME(const NAME* const obj, void (*print_element)(TYPE)){\ + if(!obj || !print_element || !(obj->data)){\ + return;\ + }\ + for(uint64_t i = 0; i < obj->size; ++i){\ + print_element(obj->data[i]);\ + }\ +}\ +bool linear_search_##NAME(const NAME* const obj, TYPE ref ,bool (*comparator)(TYPE, TYPE), uint64_t* const index){\ + if(!obj || !obj->data || obj->size == 0 || !(comparator)){\ + return false;\ + }\ + for(uint64_t i = 0; isize; ++i){\ + if(comparator(obj->data[i], ref)){\ + *index = i;\ + return true;\ + }\ + }\ + return false;\ +}\ +bool delete_##NAME(NAME** const obj, bool (*delete_type)(TYPE)){\ + if(!obj || !*obj){\ + return false;\ + }\ + if((*obj)->data){\ + if(delete_type){\ + for(uint64_t i = 0; i<(*obj)->size; ++i){\ + delete_type((*obj)->data[i]);\ + }\ + }\ + free((*obj)->data);\ + }\ + free(*(obj));\ + *obj = NULL;\ + return true;\ +}\ +bool clear_##NAME(NAME* const obj, bool (*delete_type)(TYPE)){\ + if(!obj){\ + return false;\ + }\ + if(obj->data && delete_type){\ + for(uint64_t i = 0; isize; ++i){\ + delete_type(obj->data[i]);\ + }\ + free(obj->data);\ + }\ + obj->data = NULL;\ + obj->size = 0;\ + return true;\ +} + +#endif \ No newline at end of file diff --git a/tests/algorithms/search/binary_search_arr_example.c b/tests/algorithms/search/binary_search_arr_example.c new file mode 100644 index 0000000..148ecab --- /dev/null +++ b/tests/algorithms/search/binary_search_arr_example.c @@ -0,0 +1,42 @@ +#include + +#include "../../../include/algorithms/searching/binary_search_arr.h" +#include "../../../include/algorithms/sorting/bubble_sort.h" +DEFINE_BUBBLE_SORT_ARR(intArr,int) + +DEFINE_BINARY_SEARCH_ARR(intArr,int) + +bool intGreater(int a, int b){ + return a>b; +} + +bool swap(int* a, int* b){ + int temp = *a; + *a = *b; + *b = temp; + return true; +} + +int16_t binInt(int a, int b){ + if(a==b){ + return 0; + } + else if(a < b){ + return -1; + } + return 1; +} + +int main(void){ + int arr[] = {0,2,5,4,1}; + bubble_sort_int(arr,sizeof(arr)/sizeof(arr[0]),intGreater,swap); + for(int i = 0; i +#include "../../../include/algorithms/sorting/bubble_sort.h" +DEFINE_BUBBLE_SORT_ARR(intSort,int); + +#define SIZE 10 + +bool int_greater_than(int a, int b){ + return (a>b); +} + +bool int_swap(int* a, int* b){ + int temp = *a; + *a = *b; + *b = temp; + return true; +} + +int main(void){ + int a[SIZE] = {0,1,3,4,5,2,9,8,6,7}; + bubble_sort_intSort(a,sizeof(a)/sizeof(a[0]),int_greater_than,int_swap); + for(int i = 0; i +#include "../../../include/algorithms/sorting/insertion_sort.h" + +DEFINE_INSERTION_SORT(intSort,int) + +#define SIZE 10 + +bool greater_than(int a, int b){ + return a>b; +} + +bool swap(int* a, int *b){ + int temp = *a; + *a = *b; + *b = temp; + return true; +} + +int main(void){ + int a[SIZE] = {0,3,5,4,1,2,8,6,7,9}; + insertion_sort_intSort(a,sizeof(a)/sizeof(a[0]),greater_than,swap); + for(int i = 0; i +#include "../../../include/algorithms/sorting/selection_sort.h" + +DEFINE_SELECTION_SORT(intSort,int) + +#define SIZE 10 + +bool greater_than(int a, int b){ + return a>b; +} + +bool swap(int* a, int* b){ + int temp = *a; + *a = *b; + *b = temp; + return true; +} + +int main(void){ + int a[SIZE] = {1,2,4,7,9,8,6,5,3,0}; + selection_sort_intSort(a,sizeof(a)/sizeof(a[0]),greater_than,swap); + for(int i = 0; i +#include "../../../include/data_structures/linked_list/singly_linked_list.h" + +DEFINE_SINGLY_LINKED_LIST_NODE(intNode, int) + +void printInt(int a){ + printf("%d ",a); +} + +bool intIsEqual(int a, int b){ + return a==b; +} + +int main(int argc, char const *argv[]) +{ + intNode* in = new_intNode(0,NULL); + print_SLL_intNode(in,printInt); + putchar('\n'); + insert_after_SLL_intNode(in,1); + print_SLL_intNode(in,printInt); + putchar('\n'); + insert_at_end_SLL_intNode(in,2); + print_SLL_intNode(in,printInt); + putchar('\n'); + intNode* tempNode=NULL; + printf("%d\n",linear_search_intNode(in,intIsEqual,1,&tempNode)); + printf("%d\n",tempNode->val); + return 0; +} diff --git a/tests/data_structures/queue/deque_DLL_primitive_example.c b/tests/data_structures/queue/deque_DLL_primitive_example.c new file mode 100644 index 0000000..b0d9c55 --- /dev/null +++ b/tests/data_structures/queue/deque_DLL_primitive_example.c @@ -0,0 +1,19 @@ +#include +#include "../../../include/data_structures/linked_list/doubly_linked_list.h" + +DEFINE_DLL_NODE(intNode, int) + +void print_int(int a){ + printf("%d ",a); +} + +int main(void){ + intNode* head = new_intNode(0,NULL,NULL); + print_DLL_intNode(head,print_int); + putchar('\n'); + insert_at_head_DLL_intNode(&head,-1); + print_DLL_intNode(head,print_int); + insert_at_end_DLL_intNode(head,1); + putchar('\n'); + print_DLL_intNode(head,print_int); +} \ No newline at end of file diff --git a/tests/data_structures/queue/queue_vector_primitive_example.c b/tests/data_structures/queue/queue_vector_primitive_example.c new file mode 100644 index 0000000..5a27d62 --- /dev/null +++ b/tests/data_structures/queue/queue_vector_primitive_example.c @@ -0,0 +1,20 @@ +#include +#include "../../../include/data_structures/queue/queue_vector.h" + +DEFINE_QUEUE_VECTOR(intQ, intVec, int) + +void print_int(int a){ + printf("%d ",a); +} + +int main(void){ + intQ* newQ = new_intQ(0); + enqueue_intQ(newQ,0); + enqueue_intQ(newQ,1); + print_intVec(newQ->vec,print_int); + int a; + dequeue_intQ(newQ,&a); + printf("\n%d\n",a); + print_intVec(newQ->vec,print_int); + +} \ No newline at end of file diff --git a/tests/data_structures/stack/stack_SLL_primitive_example.c b/tests/data_structures/stack/stack_SLL_primitive_example.c new file mode 100644 index 0000000..3c24bb7 --- /dev/null +++ b/tests/data_structures/stack/stack_SLL_primitive_example.c @@ -0,0 +1,18 @@ +#include +#include "../../../include/data_structures/stack/stack_SLL.h" + +DEFINE_STACK_SLL(intStack,intNode, int) + +void print_int(int a){ + printf("%d ",a); +} + +int main(void){ + intStack* is = new_intStack(); + push_intStack(is,0); + push_intStack(is,1); + pop_intStack(is,NULL); + pop_intStack(is,NULL); + print_intStack(is,print_int); + return 0; +} diff --git a/tests/data_structures/stack/stack_SLL_struct_example.c b/tests/data_structures/stack/stack_SLL_struct_example.c new file mode 100644 index 0000000..ef47ff0 --- /dev/null +++ b/tests/data_structures/stack/stack_SLL_struct_example.c @@ -0,0 +1,45 @@ +#include +#include +#include "../../../include/data_structures/stack/stack_SLL.h" + +struct Card{ + char* name; + uint64_t name_len; + char suit; + char val; +}; + +typedef struct Card Card; + +Card* new_Card(char* name, uint64_t name_len, char suit, char val){ + Card* card = malloc(sizeof(Card)); + card->name = calloc(name_len,sizeof(char)); + strncpy(card->name,name,name_len); + card->suit = suit; + card->val = val; + return card; +} + +bool delete_Card(Card* card){ + free(card->name); + free(card); + return true; +} + +DEFINE_STACK_SLL(cardStack, cardNode, Card*) + +void print_card(Card* card){ + printf("%c\t%c\t%s\n",card->suit,card->val,card->name); +} + +int main(void){ + cardStack* cs = new_cardStack(); + Card* newCard = new_Card("Ace of Spades",strlen("Ace of Spades"),'S','A'); + push_cardStack(cs,newCard); + newCard = new_Card("King of Hearts",strlen("King of Hearts"),'H','K'); + push_cardStack(cs,newCard); + print_cardStack(cs,print_card); + pop_cardStack(cs,delete_Card); + putchar('\n'); + print_cardStack(cs,print_card); +} diff --git a/tests/data_structures/stack/stack_vector_primitive_example.c b/tests/data_structures/stack/stack_vector_primitive_example.c new file mode 100644 index 0000000..6d74a8d --- /dev/null +++ b/tests/data_structures/stack/stack_vector_primitive_example.c @@ -0,0 +1,31 @@ +#include +#include "../../../include/data_structures/stack/stack_vector.h" + +DEFINE_STACK_VECTOR(charStack,charVec,char) + +void print_char(char c){ + printf("%c ",c); +} + +int main(void){ + char s[] = "()(())"; + charStack* cs = new_charStack(); + for(int i = 0; i +#include "../../../include/data_structures/stack/stack_vector.h" + +struct Card{ + char suit; + char val; +}; +typedef struct Card Card; + +void print_card(Card* a){ + printf("%c %c\n",a->suit,a->val); +} + +bool delete_card(Card* c){ + free(c); + return true; +} + +DEFINE_STACK_VECTOR(cardStack, cardVec,Card*) + +int main(void){ + cardStack* cs = new_cardStack(); + Card* newCard = malloc(sizeof(Card)); + newCard->suit = 'S'; //Spades + newCard->val = 'A'; //Ace + push_cardStack(cs,newCard); + newCard = malloc(sizeof(Card)); + newCard->suit = 'H'; //Hearts + newCard->val = 'K'; //King + push_cardStack(cs,newCard); + print_cardStack(cs,print_card); + pop_cardStack(cs,delete_card); + pop_cardStack(cs,delete_card); + putchar('\n'); + print_cardStack(cs,print_card); + if(!pop_cardStack(cs,delete_card)){ + printf("Empty stack, cannot remove\n"); + } +} \ No newline at end of file diff --git a/tests/data_structures/tree/binary_search_tree_primitive.c b/tests/data_structures/tree/binary_search_tree_primitive.c new file mode 100644 index 0000000..c7827cc --- /dev/null +++ b/tests/data_structures/tree/binary_search_tree_primitive.c @@ -0,0 +1,24 @@ +#include +#include "../../../include/data_structures/tree/binary_search_tree.h" + +DEFINE_BINARY_SEARCH_TREE(intBST, intBSTNode, int) + +void print_int(int a){ + printf("%d ",a); +} + +int16_t comparator(int a, int b){ + return a-b; +} + +int main(void){ + intBST* bst = new_intBST(0); + print_recursive_inorder_intBST(bst,print_int); + putchar('\n'); + recursive_insert_BST_intBST(bst,-1,comparator); + print_recursive_inorder_intBST(bst,print_int); + putchar('\n'); + recursive_insert_BST_intBST(bst,1,comparator); + print_recursive_inorder_intBST(bst,print_int); + putchar('\n'); +} \ No newline at end of file diff --git a/tests/data_structures/tree/binary_tree_primitive_addon.c b/tests/data_structures/tree/binary_tree_primitive_addon.c new file mode 100644 index 0000000..0017de7 --- /dev/null +++ b/tests/data_structures/tree/binary_tree_primitive_addon.c @@ -0,0 +1,50 @@ +#include + +#include "../../../include/data_structures/tree/binary_tree.h" +#include "../../../include/data_structures/tree/binary_tree_addon.h" + +DEFINE_BINARY_TREE_ALGOS(intBinTree, intNode, int, intVec, intStack, intStackVec) + +void print_int(int a){ + printf("%d ",a); +} + +void print_all_traversals(intBinTree* obj){ + intVec* vec; + vec = recursive_preorder_vec_intBinTree(obj); + printf("Preorder traversal - ");print_intVec(vec,print_int); + putchar('\n'); + delete_intVec(vec,NULL); + vec = recursive_inorder_vec_intBinTree(obj); + printf("Inorder traversal - ");print_intVec(vec,print_int); + putchar('\n'); + delete_intVec(vec,NULL); + vec = recursive_postorder_vec_intBinTree(obj); + printf("Postorder traversal - ");print_intVec(vec,print_int); + putchar('\n'); + delete_intVec(vec,NULL); +} + +int main(void){ + intBinTree* binTree = new_intBinTree(0); + if(binTree==NULL){ + puts("Tree creation failed"); + return -1; + } + print_all_traversals(binTree); + putchar('\n'); + if(!insert_at_left_intNode(binTree->root,1,NULL,NULL)){ + puts("Insertion failed"); + return -1; + } + print_all_traversals(binTree); + putchar('\n'); + if(!insert_at_right_intNode(binTree->root,2,NULL,NULL)){ + puts("Insertion failed"); + return -1; + } + print_all_traversals(binTree); + putchar('\n'); + printf("Stack preorder - ");print_preorder_intBinTree(binTree,print_int,NULL);putchar('\n'); + printf("Stack inorder - ");print_inorder_intBinTree(binTree,print_int,NULL);putchar('\n'); +} \ No newline at end of file diff --git a/tests/data_structures/tree/binary_tree_primitive_example.c b/tests/data_structures/tree/binary_tree_primitive_example.c new file mode 100644 index 0000000..e0fca26 --- /dev/null +++ b/tests/data_structures/tree/binary_tree_primitive_example.c @@ -0,0 +1,42 @@ +#include +#include "../../../include/data_structures/tree/binary_tree.h" + +DEFINE_BINARY_TREE(intBinTree,intNode,int) + +void print_int(int a){ + printf("%d ",a); +} + +void printAllTraversals(intBinTree* obj){ + printf("Preorder traversal - "); + print_recursive_preorder_intBinTree(obj,print_int); + putchar('\n'); + printf("Inorder traversal - "); + print_recursive_inorder_intBinTree(obj,print_int); + putchar('\n'); + printf("Postorder traversal - "); + print_recursive_postorder_intBinTree(obj,print_int); + putchar('\n'); +} + +int main(void){ + intBinTree* binTree = new_intBinTree(1); + if(binTree==NULL){ + puts("Tree creation failed"); + return -1; + } + printAllTraversals(binTree); + putchar('\n'); + if(!insert_at_left_intNode(binTree->root,0,NULL,NULL)){ + puts("Insertion failed"); + return -1; + } + printAllTraversals(binTree); + putchar('\n'); + if(!insert_at_right_intNode(binTree->root,2,NULL,NULL)){ + puts("Insertion failed"); + return -1; + } + printAllTraversals(binTree); + putchar('\n'); +} \ No newline at end of file diff --git a/tests/data_structures/vector/CMakeLists.txt b/tests/data_structures/vector/CMakeLists.txt new file mode 100644 index 0000000..6b2c448 --- /dev/null +++ b/tests/data_structures/vector/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(vector_primitive_test vector_primitive_test.c) +add_test(vector_primitive_test vector_primitive_test) + +add_executable(vector_struct_test vector_struct_test.c) +add_test(vector_struct_test vector_struct_test) \ No newline at end of file diff --git a/tests/data_structures/vector/vector_primitive_test.c b/tests/data_structures/vector/vector_primitive_test.c new file mode 100644 index 0000000..1e17e44 --- /dev/null +++ b/tests/data_structures/vector/vector_primitive_test.c @@ -0,0 +1,124 @@ +#include + +//For manual valgrind testing +// #include "../../../include/data_structures/vector/vector.h" +// #include "../../../include/algorithms/sort/bubble_sort.h" +// #include "../../../util/testing_macro.h" + +#include "vector.h" +#include "bubble_sort.h" +#include "testing_macro.h" + +#define ARRAY_SIZE 10 // Is not a const global variable due to it being used for vanilla array size + +DEFINE_VECTOR(intVec,int) +DEFINE_BUBBLE_SORT_ARR(intArr,int) + +/* To print the vector, we must pass in a function (pointer) which +prints a single instance of the type stored in vector. */ +void print_int(int a){ + printf("%d ",a); +} + +// Comparator for swapping when sorting the array +bool less_than(int a, int b){ + return adata == NULL, "Empty vector data not NULLed."); + delete_intVec(&iv,NULL); + test(iv==NULL, "Deleted integer vector still points to memory."); + + // Testing of +ve sized constructor + const uint64_t size = 10; + iv = new_intVec(size); + test(iv->size == size, "Vector size incorrectly set."); + test(iv->data != NULL, "Integer vector data is NULLed."); + delete_intVec(&iv, NULL); + test(iv==NULL,"Deleted integer vector still points to memory") + + /*Negative size parameter not possible due to use of uint64, transfers + responsibility of checking size to the programmer */ + + // Construct from raw array. + int arr[ARRAY_SIZE] = {0}; + for(uint64_t i = 0; isize == sizeof(arr)/sizeof(arr[0]), "Size of vector object incorrectly set."); + print_intVec(iv,print_int); + putchar('\n'); + delete_intVec(&iv, NULL); + test(iv==NULL, "Deleted integer vector still points to memory."); + + // Test construction from array when NULL ptr + int* test_array = NULL; + iv = construct_from_arr_intVec(test_array,ARRAY_SIZE); + test(iv==NULL, "Construct vector from array returns non NULL when NULL array.") + + // Test is_empty with size and set_whole + iv = new_intVec(size); + test(!is_empty_intVec(iv), "Non-empty vector triggers is empty.") + + //Test set_whole and at_vec + const int element = 10; + set_whole_intVec(iv,element); + int got_element; + print_intVec(iv,print_int); + putchar('\n'); + for (uint64_t i = 0; i < iv->size; ++i) + { + if(at_intVec(iv,i,&got_element)){ + test(got_element==element,"Set whole vector not setting to element correctly."); + } + else{ + test(false,"at_vec failing") + } + } + + //Test that access at out of bounds is invalid + test(!at_intVec(iv,size,&got_element),"Out of bounds is valid.") + for(uint64_t i = 0; isize; ++i){ + test(set_at_intVec(iv,i,i),"set_at failing") + test(at_intVec(iv,i,&got_element) && got_element == iv->data[i], "at_failing or wrong value") + } + print_intVec(iv,print_int); + putchar('\n'); + + + //Test set at out of bounds + test(!set_at_intVec(iv,iv->size,0),"set_at out of bounds accepted") + + //Test set whole + if(!set_whole_intVec(iv,0)){ + puts("set_at_whole failed with non-empty vector"); + return -1; + } + print_intVec(iv,print_int); + putchar('\n'); + + if(!add_at_end_intVec(iv,1)){ + puts("add_at_end failed"); + return -1; + } + + if(!add_at_beginning_intVec(iv,-1)){ + puts("add_at_beginning failed"); + return -1; + } + + // More tests required! + delete_intVec(&iv,NULL); + return 0; +} \ No newline at end of file diff --git a/tests/data_structures/vector/vector_struct_test.c b/tests/data_structures/vector/vector_struct_test.c new file mode 100644 index 0000000..b039dbd --- /dev/null +++ b/tests/data_structures/vector/vector_struct_test.c @@ -0,0 +1,66 @@ +#include +#include + +//For manual valgrind testing +// #include "../../../include/data_structures/vector/vector.h" + +#include "vector.h" +#include + +//Type for struct +struct Card{ + char* name; + uint16_t name_length; + char suite; + unsigned short value; +}; +typedef struct Card Card; + +Card* new_Card(char* name, uint16_t name_length, char suite, unsigned short value){ + Card* new_obj = calloc(1,sizeof(Card)); + new_obj->name = calloc(name_length+1, sizeof(char)); // accounting for null character (thanks valgrind!) (Unsafe if buffer overflow, just for basic testing) + strncpy(new_obj->name,name,name_length); + new_obj->name_length = name_length; + new_obj->suite = suite; + new_obj->value = value; + return new_obj; +} + +void print_Card(Card* card){ + if(!card){ + return; + } + if(!card->name){ + printf("Name null"); + } + printf("Name - %s\nValue - %d\nSuite - %c\n",card->name,card->value,card->suite); +} + +bool delete_Card(Card* card){ + if(!card){ + return false; + } + if(card->name){ + free(card->name); + } + free(card); + return true; +} + +DEFINE_VECTOR(CardVector, Card*) + +int main(void){ + CardVector* cv = new_CardVector(0); + if(!is_empty_CardVector(cv)){ + puts("Empty Card Vector does not fulfill is_empty"); + return -1; + } + if(!add_at_beginning_CardVector(cv, new_Card("Ace of Spades", strlen("Ace of Spades"), 'S', 1))){ + puts("Could not add at beginning"); + return -1; + } + // More tests needed + print_CardVector(cv,print_Card); + delete_CardVector(&cv,delete_Card); + return 0; +} \ No newline at end of file diff --git a/util/testing_macro.h b/util/testing_macro.h new file mode 100644 index 0000000..86be83e --- /dev/null +++ b/util/testing_macro.h @@ -0,0 +1,17 @@ +#ifndef TEST_MACRO +#define TEST_MACRO + +// If not condition, then failure, hence message +// Didnt want assert, failed tests needn't call abort() + +#include +#include + +// Can double stringize for better memory safety but tbh do not understand it completely. Hence used printf instead of puts. +#define test(EXPECTED_CONDITION, FAILURE_MESSAGE)\ +if(!(EXPECTED_CONDITION)){\ + printf("File:"__FILE__ " Line:%d " #EXPECTED_CONDITION " : " FAILURE_MESSAGE "\n", __LINE__);\ + exit(-1);\ +} + +#endif \ No newline at end of file