diff --git a/README.md b/README.md index 336c5d7..ddafddd 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ # libflint -My personal library of common C data structures and algorithms. +My personal library of common C data structures and algorithms. Supports Linux, OpenBSD, and FreeBSD. + +## Documentation + +Extensive documentation can be found [here](https://docs.fputs.com/libflint/index.html) + +## Requirements + +Building on Linux requires `libbsd`. \ No newline at end of file diff --git a/build.sh b/build.sh index 18423d2..c860355 100755 --- a/build.sh +++ b/build.sh @@ -1,8 +1,10 @@ #!/bin/sh -e +# For building outside of CLion + mkdir -p build cd build cmake .. make cp compile_commands.json .. -cd +cd diff --git a/docs/flinty.jpg b/docs/flinty.jpg new file mode 100644 index 0000000..24336ae Binary files /dev/null and b/docs/flinty.jpg differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..8436a95 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,19 @@ +# libflint + +`libflint` is a library of common C data structures and algorithms, designed to be as agnostic as possible for its +users. + +## Requirements + +The only requirement is `libbsd`. This should be available on all major Linux distros. If building on a bsd, then + +## Memory Management + +The parts of this library that create data structures pass all responsibility of memory management to the user. This +is clearly documented in the individual module's documentation. + +## Why 'libflint'? + +`libflint` is named after my dog Flint, who passed away in 2021. I miss you, buddy. + +![flint](flinty.jpg) \ No newline at end of file diff --git a/docs/lfbinarytree.md b/docs/lfbinarytree.md new file mode 100644 index 0000000..6fe1cfb --- /dev/null +++ b/docs/lfbinarytree.md @@ -0,0 +1,202 @@ +# lfbinarytree + +Binary tree with standard leaf operations + +## Usage + +Create the tree. The user is responsible for memory management of the `BinTree` struct. + +```c +BinTree *tree = malloc(sizeof(BinTree)); +``` + +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 +bintree_init(tree, NULL); +int root = 0; +int l1 = 1; +int l2 = 2; +int r1 = 12; +int r2 = 200; +``` + +Next lets insert our data into the tree. The insert functions signature is `bintree_ins_...(tree, parent, data)`. If you +are inserting data at the root of the tree, you may use either `bintree_ins_left()` or `bintree_ins_right()` as long as +`NULL` is passed as the parent argument. + +```c +bintree_ins_left(tree, NULL, &root); +bintree_ins_left(tree, tree->root, &l1); +bintree_ins_left(tree, tree->root->left, &l2); +bintree_ins_right(tree, tree->root->left, &r2); +bintree_ins_right(tree, tree->root, &r1); +bintree_ins_right(tree, tree->root->right, &r2); +bintree_ins_left(tree, tree->root->right, &l1); +``` + +We can use `bintree_debug_print(tree)` to print a graphical representation of the tree to `stdout` +```plaintext +└──0 + ├──1 + │ ├──2 + │ └──200 + └──12 + ├──1 + └──200 +``` + +To cleanup the tree, first destroy the nodes. If you passed a deallocation function, it will be called on +the data member of each node before the node itself is freed. `bintree_destroy()` does not free the tree itself, just the +nodes inside of it, hence we must also call `free()` on the tree. + +```c +bintree_destroy(tree); +free(tree); +tree = NULL; +``` + +Here is the entire example: + +```c +BinTree *tree = malloc(sizeof(BinTree)); +bintree_init(tree, NULL); + +int root = 0; +int l1 = 1; +int l2 = 2; +int r1 = 12; +int r2 = 200; + +bintree_ins_left(tree, NULL, &root); +bintree_ins_left(tree, tree->root, &l1); +bintree_ins_left(tree, tree->root->left, &l2); +bintree_ins_right(tree, tree->root->left, &r2); +bintree_ins_right(tree, tree->root, &r1); +bintree_ins_right(tree, tree->root->right, &r2); +bintree_ins_left(tree, tree->root->right, &l1); + +bintree_debug_print(tree); + +bintree_destroy(tree); +free(tree); +tree = NULL; +``` + +## Structs + +### BinTree + +Binary tree struct + +```c +typedef struct { + int size; + int (*compare)(const void *a, const void *b); + void (*destroy)(void *data); + struct BinTreeNode *root; +} BinTree; +``` + +Members: + +- `size`: How many nodes the tree contains +- `compare`: Comparison function between data in two nodes. Currently not used for anything +- `destroy`: Optional deallocation function for data inside a node. Typical usage is `NULL` for stack allocated data and `free()` for data created with `malloc()` +- `root`: The root node of the tree + +### BinTreeNode + +Node of the tree + +```c +typedef struct BinTreeNode { + void *data; + struct BinTreeNode *left; + struct BinTreeNode *right; +} BinTreeNode; +``` + +Members: +- `data`: void pointer to data the node contains +- `left`: left facing leaf of the node +- `right`: right facing leaf of the node + +## Functions + +### bintree_init + +Initialize the binary tree. User is responsible for freeing memory with `bintree_destroy()`. + +```c +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 + +```c +void bintree_destroy(BinTree *tree) +``` + +### bintree_ins_left + +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) +``` + +### bintree_ins_right + +Creates a new node containing `data` and inserts it as the right child of `node`. + +```c +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 + +```c +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 + +```c +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 + +```c +void bintree_debug_print(BinTree *tree) +``` + +### bintree_is_eob + +Utility macro that checks if the node is the End Of Branch + +```c +#define bintree_is_eob(node) ((node) == NULL) +``` + +### bintree_is_leaf + +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/lfbool.md b/docs/lfbool.md new file mode 100644 index 0000000..8a8dd61 --- /dev/null +++ b/docs/lfbool.md @@ -0,0 +1,8 @@ +# lfbool + +Macro representation of truthy values + +```c +#define LFTRUE 1 +#define LFFALSE 0 +``` diff --git a/docs/lfinput.md b/docs/lfinput.md new file mode 100644 index 0000000..3400969 --- /dev/null +++ b/docs/lfinput.md @@ -0,0 +1,88 @@ +# lfinput + +I/O module to assist with consuming data from files + +## Functions + +### get_input + +Reads a file at `path` and returns the contents as a single string. The string is allocated inside the function and +the user is responsible for freeing it when finished. + +```c +char *get_input(const char *path); + +/* Usage */ +char *str = get_input("/home/evan/textfile"); +free(str); +``` + +### get_lines + +Reads a file at `path` and returns the contents as an array of strings. The newline character `\n` is used as the +delimiter to determine where the file is split. The user is responsible for cleaning up the memory using `del_lines()`. +`lsz` is set to the number of lines in the array. + +```c +char **get_lines(const char *path, size_t *lsz); + +/* Usage */ +size_t sz = 0; +char **lines = get_lines("/home/evan/textfile", &sz); +for (size_t i = 0; i < sz; i++) { + printf("%s\n", lines[i]); +} +del_lines(lines); +``` + +### del_lines + +Frees all memory used by `get_lines()` + +```c +void del_lines(char **lines); +``` + +### get_ints +Reads a file at `path` and returns the contents as an array of integers. The file is assumed to be a newline seperated +list of integers and nothing else. + +The newline character `\n` is used as the delimiter to determine where the file is split. The user is responsible for +cleaning up the memory using `free()`. `lsz` is set to the number of lines in the array. + +```c +int *get_ints(const char *path, size_t *lsz); + +/* Usage */ +int *nums = get_ints("/home/evan/intfile"); +for (size_t i = 0; i < sz; i++) { + printf("%d\n", nums[i]); +} +free(nums); +``` + +### split + +Takes a string `s` and splits it into an array of strings based on the delimiter. `s` is left unchanged. The user is +responsible for cleaning up the memory of the split using `del_split()`. `sp_sz` is set to the size of the split. + +```c +char **split(char *s, size_t *lsz, const char *delim) + +/* Usage */ +size_t sp_sz = 0; +char **sp = split("Split on whitespace", &sp_sz, " "); +printf("%s\n", sp[0]); // Prints "Split" +``` + +### del_split + +Frees all memory used by `split()`. Just like `split`, it does not touch the original string +```c +void del_split(char **sp); + +/* Usage */ +size_t sp_sz = 0; +char **sp = split("Delete Me!", &sp_sz, " "); +void del_split(char **sp); +``` diff --git a/docs/lflinkedlist.md b/docs/lflinkedlist.md new file mode 100644 index 0000000..ffc7e88 --- /dev/null +++ b/docs/lflinkedlist.md @@ -0,0 +1,3 @@ +# lflinkedlist + +Coming soon \ No newline at end of file diff --git a/docs/lfmath.md b/docs/lfmath.md new file mode 100644 index 0000000..f816e20 --- /dev/null +++ b/docs/lfmath.md @@ -0,0 +1,3 @@ +# lfmath + +Coming soon \ No newline at end of file diff --git a/docs/lfset.md b/docs/lfset.md new file mode 100644 index 0000000..8d68b40 --- /dev/null +++ b/docs/lfset.md @@ -0,0 +1,3 @@ +# lfset + +Coming soon \ No newline at end of file diff --git a/docs/lfstack.md b/docs/lfstack.md new file mode 100644 index 0000000..ccb61d1 --- /dev/null +++ b/docs/lfstack.md @@ -0,0 +1,3 @@ +# lfstack + +Coming soon \ No newline at end of file diff --git a/docs/lfutility.md b/docs/lfutility.md new file mode 100644 index 0000000..1dc0fef --- /dev/null +++ b/docs/lfutility.md @@ -0,0 +1,16 @@ +# lfutility + +Utility code that does not fit anywhere else + +## Structs + +### Point + +Representation of a point on a two dimensional grid + +```c +typedef struct { + int x; + int y; +} Point; +``` diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..503cf1d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,16 @@ +site_name: libflint +site_url: https://example.com +theme: + name: readthedocs +nav: + - 'index.md' + - 'Modules': + - 'Boolean': 'lfbool.md' + - 'Input': 'lfinput.md' + - 'Math': 'lfmath.md' + - 'Utility': 'lfutility.md' + - 'Data Structures': + - 'Binary Tree': 'lfbinarytree.md' + - 'Linked List': 'lflinkedlist.md' + - 'Set': 'lfset.md' + - 'Stack': 'lfstack.md'