From eb0fea1212e90d18957e8a69ac085f79e54f3eeb Mon Sep 17 00:00:00 2001 From: Evan Burkey Date: Mon, 11 Apr 2022 14:33:57 -0700 Subject: [PATCH] write list docs, cleanup bintree and input docs --- .gitignore | 2 + docs/lfbinarytree.md | 15 +-- docs/lfinput.md | 2 +- docs/lflinkedlist.md | 221 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 231 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 1633e14..9b32a43 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ cmake* .cache build compile_commands.json +site/ +web.sh \ No newline at end of file diff --git a/docs/lfbinarytree.md b/docs/lfbinarytree.md index 6fe1cfb..001cf37 100644 --- a/docs/lfbinarytree.md +++ b/docs/lfbinarytree.md @@ -139,7 +139,8 @@ void bintree_init(BinTree *tree, void (*destroy)(void *data)) ### bintree_destroy -Destroys the nodes inside a tree and calls the deallaction function on the data if one was provided. Does not deallocate the tree itself, that is left to the user +Destroys the nodes inside a tree and calls the deallaction function on the data if one was provided. Does not deallocate +the tree itself, that is left to the user. ```c void bintree_destroy(BinTree *tree) @@ -147,7 +148,7 @@ void bintree_destroy(BinTree *tree) ### bintree_ins_left -Creates a new node containing `data` and inserts it as the left child of `node` +Creates a new node containing `data` and inserts it as the left child of `node`. ```c int bintree_ins_left(BinTree *tree, BinTreeNode *node, void *data) @@ -163,7 +164,7 @@ int bintree_ins_right(BinTree *tree, BinTreeNode *node, void *data) ### bintree_rem_left -Removes and deallocates the left child node of `node`. Calls the deallocation function on the data if one was provided +Removes and deallocates the left child node of `node`. Calls the deallocation function on the data if one was provided. ```c void bintree_rem_left(BinTree *tree, BinTreeNode *node) @@ -171,7 +172,7 @@ void bintree_rem_left(BinTree *tree, BinTreeNode *node) ### bintree_rem_right -Removes and deallocates the right child node of `node`. Calls the deallocation function on the data if one was provided +Removes and deallocates the right child node of `node`. Calls the deallocation function on the data if one was provided. ```c void bintree_rem_right(BinTree *tree, BinTreeNode *node) @@ -179,7 +180,7 @@ void bintree_rem_right(BinTree *tree, BinTreeNode *node) ### bintree_debug_print -Prints a representation of the tree to stdout. Gets very messy with large trees +Prints a representation of the tree to stdout. Gets very messy with large trees. ```c void bintree_debug_print(BinTree *tree) @@ -187,7 +188,7 @@ void bintree_debug_print(BinTree *tree) ### bintree_is_eob -Utility macro that checks if the node is the End Of Branch +Utility macro that checks if the node is the End Of Branch. ```c #define bintree_is_eob(node) ((node) == NULL) @@ -195,7 +196,7 @@ Utility macro that checks if the node is the End Of Branch ### bintree_is_leaf -Utility macro that checks if a node has children +Utility macro that checks if a node has children. ```c #define bintree_is_leaf(node) ((node)->left == NULL && (node)->right == NULL) diff --git a/docs/lfinput.md b/docs/lfinput.md index 3400969..4247667 100644 --- a/docs/lfinput.md +++ b/docs/lfinput.md @@ -84,5 +84,5 @@ void del_split(char **sp); /* Usage */ size_t sp_sz = 0; char **sp = split("Delete Me!", &sp_sz, " "); -void del_split(char **sp); +void del_split(sp); ``` diff --git a/docs/lflinkedlist.md b/docs/lflinkedlist.md index ffc7e88..5a8d072 100644 --- a/docs/lflinkedlist.md +++ b/docs/lflinkedlist.md @@ -1,3 +1,222 @@ # lflinkedlist -Coming soon \ No newline at end of file +A dual sided linked list structure. Used as the foundation for many of the structures in `libflint` + +## Usage + +Create the list. The user is responsible for memory management of the `List` struct. + +```c +List *list = malloc(sizeof(List)); +``` + +After the tree is created, init it. The second argument on `bintree_init()` is an optional memory freeing function pointer +with signature `void (*destroy)(void *data)`. Use `free()` from the stdlib if you are creating the data with `malloc()`. +If allocation of your data is more complex, you can pass your own memory deallocation function as long as it fits the +signature. + +In this example, we are passing `NULL` because all memory will be stack allocated. + +```c +ll_init(list, NULL); +int i = 1; +int j = 2; +int k = 4; +``` + +Next, insert data into the list. Data can be inserted from either side of a node. + +```c +ll_ins_next(list, list->head, (void *) &i); +ll_ins_next(list, list->tail, (void *) &j); +ll_ins_next(list, list->tail, (void *) &k); +/* List is now 1 2 4 */ +``` + +Lists can have a node removed by either targeting the node directly or removing a node pointed to by the head or tail of +another node. The user is responsible for the memory management of the data inside the node, which is why a `void*` must +be supplied to hold the data. Since in this example our memory is stack allocated, we don't need to worry about freeing +the `void*` but one must still be supplied for the function to work. + +```c +/* List is 1 2 4 */ +/* node is the 2nd node in the list with value 2 */ +ListNode *node = list->head; +/* void pointer to the data inside of the node */ +void *data; +ll_remove(list, node, &data); +/* List is now 1 4 */ + +printf("Removed: %d\n", *((int *) data)); +/* Prints "2" */ +``` + +Here is an alternative example using `ll_remove_next()` instead of `ll_remove()` +```c +/* node is the 2nd node in the list with value 2 */ +ListNode *node = list->head; +void *data; /* void pointer to the data inside of the node */ +ll_remove_next(list, node, &data); +/* List is now 1 2 */ + +printf("Removed: %d\n", *((int *) data)); +/* Prints "4" */ +``` + +To destroy the list, first call `ll_destroy()` to free the nodes in the list and optionally run the destroy function +against the data stored in the list. Since this example is stack allocated and we passed `NULL` when creating the +list, no destroy function is run against the memory in the nodes. The list itself must be deleted with `free()` + +```c +ll_destroy(list); +free(list); +``` + +Complete example: + +```c +List *list = malloc(sizeof(List)); +ll_init(list, NULL); + +int i = 1; +int j = 2; +int k = 4; + +ll_ins_next(list, list->head, (void *) &i); +ll_ins_next(list, list->tail, (void *) &j); +ll_ins_next(list, list->tail, (void *) &k); + +printf("List: "); +print_ll(list); + +void *data; +ll_remove_next(list, list->head, &data); + +printf("List: "); +print_ll(list); +printf("Removed: %d\n", *((int *) data)); + +ll_destroy(list); +free(list); +``` + +## Structs + +### List + +Double ended linked list struct + +```c +typedef struct { + size_t size; + void (*destroy)(void *data); + int (*match)(const void *a, const void *b); + struct ListNode *head; + struct ListNode *tail; +} List; +``` + +Members: + +- `size`: How many nodes are in the list +- `destroy`: Optional deallocation function for member data. Use `NULL` if data is stack allocated +- `match`: Comparison function between data inside two nodes. This is not used by `List` itself, but is used in structures built on top of `List` +- `head`: Pointer to the `ListNode` at the head of the list +- `tail`: Pointer to the `ListNode` at the tail of the list + +### ListNode + +Node of the list + +```c +typedef struct ListNode { + void *data; + struct ListNode *next; + struct ListNode *prev; +} ListNode; +``` + +Members: + +- `data`: void pointer to the member data in the node +- `next`: Pointer to the `ListNode` before this node in the list +- `prev`: Pointer to the `ListNode` after this node in the list + +## Functions + +### ll_init + +Initalize the list. User is responsible for freeing memory with `ll_destroy()`. + +```c +void ll_init(List *list, void (*destroy)(void *data)); +``` + +### ll_destroy + +Destroys the nodes inside a list and calls the deallocation funciton on the data if one was provided. Does not destroy +the list itself, that is left up to the user. + +```c +void ll_destroy(List *list); +``` + +### ll_ins_next + +Creates a new node containing `data` and inserts it after `node`. + +```c +int ll_ins_next(List *list, ListNode *node, const void *data); +``` + +### ll_ins_prev + +Creates a new node containing `data` and inserts it before `node`. + +```c +int ll_ins_prev(List *list, ListNode *node, const void *data); +``` + +### ll_remove + +Removes and deallocates the node pointed to by `node`. The user is responsible for managing the contained data's memory, +as such the `destroy` function is **not** run by `ll_remove()` + +```c +int ll_remove(List *list, ListNode *node, void **data); +``` + +### ll_remove_next + +Removes and deallocates the node pointed to by `node`'s `tail` pointer. The user is responsible for managing the contained data's memory, +as such the `destroy` function is **not** run by `ll_remove_next()` + +```c +int ll_remove_next(List *list, ListNode *node, void **data); +``` + +### ll_remove_prev + +Removes and deallocates the node pointed to by `node`'s `head` pointer. The user is responsible for managing the contained data's memory, +as such the `destroy` function is **not** run by `ll_remove_prev()` + +```c +int ll_remove_prev(List *list, ListNode *node, void **data); +``` + +## Macros + +### LL_ITER + +A utility macro that helps with iterating over an entire list. A `ListNode` pointer named `node` is created as part of +this macro and can be used to access the current node in the iteration, so be careful your own variable naming if you +intend to use `LL_ITER`. + +```c +#define LL_ITER(list) for(ListNode *node = (list)->head; node != NULL; node = node->next) + +/* Example with list of strings */ +for LL_ITER(list) { + printf("%s\n", (char *)(node->data)); +} +``` \ No newline at end of file