building instructions, remove old docs
This commit is contained in:
parent
34ec1943e1
commit
ba6e929b4f
@ -1,63 +0,0 @@
|
||||
---
|
||||
name: Test and Deploy
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libbsd-dev cmake build-essential netcat
|
||||
|
||||
- name: Build and test
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
./tests
|
||||
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
if: gitea.ref == 'refs/heads/master'
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install SSH client
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y openssh-client
|
||||
|
||||
- name: Setup SSH
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
ssh-keyscan -H burkey.co >> ~/.ssh/known_hosts
|
||||
echo "${{ secrets.BURKEY_CO_KEY}}" >> ~/.ssh/id_rsa
|
||||
chmod -R 700 ~/.ssh
|
||||
eval "$(ssh-agent -s)"
|
||||
ssh-add ~/.ssh/id_rsa
|
||||
|
||||
- name: Install mkdocs
|
||||
run: |
|
||||
pip install mkdocs
|
||||
|
||||
- name: Build documentation
|
||||
run: |
|
||||
mkdocs build
|
||||
|
||||
- name: Deploy documentation
|
||||
run: |
|
||||
ssh debian@burkey.co "rm -rf /var/www/docs/libflint"
|
||||
ssh debian@burkey.co "mkdir -p /var/www/docs/libflint"
|
||||
ssh debian@burkey.co "chmod 755 /var/www/docs/libflint"
|
||||
scp -r ./site/* debian@burkey.co:/var/www/docs/libflint/
|
||||
|
17
README.md
17
README.md
@ -7,10 +7,25 @@ My personal library of common C data structures and algorithms. Supports Linux,
|
||||
Extensive documentation can be found [here](https://wiki.burkey.co/doku.php?id=libflint:start). You can also check out `tests/tests.c` to
|
||||
see example usage from most of the library's API.
|
||||
|
||||
## Building
|
||||
|
||||
`libflint` requires Cmake to be built. It can then be built using either `cmake` or `make` with the provided build files. The `Makefile` is a wrapper around Cmake for Makefile compatibility.
|
||||
|
||||
### Cmake
|
||||
|
||||
```cmake
|
||||
# If libflint is in ./lib/libflint
|
||||
add_subdirectory(lib/libflint)
|
||||
|
||||
# when building target...
|
||||
target_include_directories(${TARGET} PRIVATE lib/libflint/include)
|
||||
target_link_libraries(${TARGET} PRIVATE flint )
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
Building on Linux requires `libbsd`. Building on macOS, OpenBSD, or FreeBSD requires no extra dependencies.
|
||||
|
||||
## Libraries
|
||||
|
||||
`libflint` includes [uthash](https://github.com/troydhanson/uthash) for a hash table implementation. `uthash` is a single header file included in the source code of `libflint`. See the top of `include/uthash.h` for license information
|
||||
`libflint` includes [uthash](https://github.com/troydhanson/uthash) for a hash table implementation. `uthash` is a single header file included in the source code of `libflint`. See the top of `include/uthash.h` for license information
|
||||
|
@ -1,203 +0,0 @@
|
||||
# binarytree
|
||||
|
||||
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)
|
||||
```
|
@ -1,8 +0,0 @@
|
||||
# bool
|
||||
|
||||
Macro representation of truthy values
|
||||
|
||||
```c
|
||||
#define LFTRUE 1
|
||||
#define LFFALSE 0
|
||||
```
|
107
docs/crypto.md
107
docs/crypto.md
@ -1,107 +0,0 @@
|
||||
# crypto
|
||||
|
||||
Cryptographic tools
|
||||
|
||||
Any functions that return string representations of bytes in hexadecimal format will
|
||||
always be formatted with no leading `0x` and lower case letters
|
||||
|
||||
## Functions
|
||||
|
||||
### b64_encode
|
||||
|
||||
Encodes an `unsigned char *` into base64. User is responsible for freeing the
|
||||
`char *` that is returned.
|
||||
|
||||
```c
|
||||
char *b64_encode(const unsigned char *s, size_t sz);
|
||||
```
|
||||
|
||||
### b64_decode
|
||||
|
||||
Decodes a base64 encoded set of bytes into an `unsigned char *`. User is responsible
|
||||
for freeing the `unsigned char *` that is returned. `decode_sz` is an optional argument
|
||||
in case you need to know the size of the decoded data, otherwise you can just pass `NULL`.
|
||||
|
||||
```c
|
||||
unsigned char *b64_decode(const char *s, size_t sz, size_t *decode_sz);
|
||||
```
|
||||
|
||||
### hex_encode
|
||||
|
||||
Encodes an array of bytes into a string in hex representation. For example, converts
|
||||
`[0xDE, 0xAD, 0xBE, 0xEF]` into `"deadbeef"`. User is responsible for freeing the returned string
|
||||
|
||||
```c
|
||||
const char *hex_encode(const unsigned char *hex, size_t sz);
|
||||
|
||||
// Example
|
||||
unsigned char h[4] = {
|
||||
0xde, 0xad, 0xbe, 0xef
|
||||
};
|
||||
const char *s = hex_encode(h, 4);
|
||||
assert(strcmp(s, "deadbeef") == 0);
|
||||
free(s);
|
||||
```
|
||||
|
||||
### hex_decode
|
||||
|
||||
Decodes a string of characters representing hexadecimal bytes into an array of `unsigned char`.
|
||||
Characters can be in upper or lower case, and can start with a leading `0x` or not.
|
||||
For example, converts `"DEADBEEF"` into `[0xde, 0xad, 0xbe, 0xef]`. User is reponsible for the
|
||||
freeing of the returned byte array
|
||||
|
||||
```c
|
||||
unsigned char *hex_decode(const char *orig, size_t *sz);
|
||||
|
||||
// Example
|
||||
unsigned char *s = hex_decode("DEADBEEF", &s_sz);
|
||||
unsigned char h[4] = {
|
||||
0xDE, 0xAD, 0xBE, 0xEF
|
||||
};
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
assert(s[i] == h[i]);
|
||||
}
|
||||
free(s);
|
||||
```
|
||||
|
||||
### hex_to_str
|
||||
|
||||
Converts an array of `unsigned char` into a string based on the ASCII values of each byte. User is
|
||||
responsible for freeing the returned string.
|
||||
|
||||
```c
|
||||
const char *hex_to_str(const unsigned char *hex, size_t sz);
|
||||
```
|
||||
|
||||
### repeating_key_xor
|
||||
|
||||
Performs a repeating-key XOR encryption on an array of bytes. User is responsible for freeing the returned array
|
||||
|
||||
```c
|
||||
const unsigned char* repeating_key_xor(const unsigned char* s, size_t s_sz, const unsigned char* key, size_t k_sz);
|
||||
```
|
||||
|
||||
### repeating_key_xor_s
|
||||
|
||||
Performs a repeating-key XOR encryption on a string. Returns the encrypted string as an array of bytes. User is
|
||||
responsible for freeing the returned array
|
||||
|
||||
```c
|
||||
const unsigned char *repeating_key_xor_s(const char* s, const char* key);
|
||||
```
|
||||
|
||||
### hamming_distance
|
||||
|
||||
Calculates the Hamming Distance (the number of differing bits) between two arrays of unsigned bytes
|
||||
|
||||
```c
|
||||
unsigned int hamming_distance(unsigned char *a, unsigned char *b);
|
||||
```
|
||||
|
||||
### hamming_distance_s
|
||||
|
||||
Calculates the Hamming Distance (the number of differing bits) between two strings
|
||||
|
||||
```c
|
||||
unsigned int hamming_distance_s(const char *a, const char *b);
|
||||
```
|
BIN
docs/flinty.jpg
BIN
docs/flinty.jpg
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
@ -1,25 +0,0 @@
|
||||
# libflint
|
||||
|
||||
`libflint` is a library of common C data structures and algorithms, designed to be as agnostic as possible for its
|
||||
users. Over time, it has become my personal library of reusable C code.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Linux
|
||||
|
||||
Requires `libbsd`. This should be available on all major Linux distros.
|
||||
|
||||
### macOS, OpenBSD, FreeBSD
|
||||
|
||||
Requires no extra dependencies
|
||||
|
||||
## 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 the name 'libflint'?
|
||||
|
||||
`libflint` is named after my dog Flint, who passed away in 2021. I miss you buddy.
|
||||
|
||||

|
120
docs/input.md
120
docs/input.md
@ -1,120 +0,0 @@
|
||||
# input
|
||||
|
||||
I/O module to assist with consuming data from files
|
||||
|
||||
## Functions
|
||||
|
||||
### get_binary
|
||||
|
||||
Reads a file at `path` and returns the contents as a char* buffer. The `fsz` parameter stores the length of the
|
||||
returned array. The buffer is allocated inside the function, so the user is responsible for freeing it when finished.
|
||||
|
||||
```c
|
||||
char *get_binary(const char *path, size_t *fsz);
|
||||
|
||||
/* Usage */
|
||||
size_t fsz = 0;
|
||||
char *buf = get_binary("/home/evan/binfile", &fsz);
|
||||
free(buf);
|
||||
```
|
||||
|
||||
|
||||
### 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
|
||||
unsigned 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(sp);
|
||||
```
|
||||
|
||||
### capture_system
|
||||
|
||||
Runs a command on the system shell and returns stdout as a string. `buffsize` is the size of
|
||||
the returned buffer that holds `stdout`. Passing `0` to `buffsize` will use the default buffer size of `1024`.
|
||||
|
||||
User is responsible for freeing the returned string.
|
||||
|
||||
```c
|
||||
const char *capture_system(const char *cmd, int buffsize);
|
||||
|
||||
/* Usage */
|
||||
const char *cap = capture_system("ls $HOME", 0);
|
||||
printf("%s\n", cap);
|
||||
free(cap);
|
||||
```
|
@ -1,230 +0,0 @@
|
||||
# linkedlist
|
||||
|
||||
A dual sided linked list structure. Used as the foundation for many other modules 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
|
||||
|
||||
Initialize the list. User is responsible for creating the initial `List` structure and freeing memory with `ll_destroy()`. `destroy` is a deallocation function for the members of `List`, pass `NULL` if the memory is stack-allocated
|
||||
|
||||
```c
|
||||
void ll_init(List *list, void (*destroy)(void *data));
|
||||
|
||||
/* Usage */
|
||||
List *list = malloc(sizeof(Stack));
|
||||
|
||||
// Pass NULL for stack-allocated memory
|
||||
ll_init(list, NULL);
|
||||
|
||||
// Pass free or a custom freeing function for heap allocated memory
|
||||
ll_init(list, free);
|
||||
```
|
||||
|
||||
### 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));
|
||||
}
|
||||
```
|
@ -1,63 +0,0 @@
|
||||
# macOS
|
||||
|
||||
Platform-specific code for macOS. Everything in this module, including the headers, is wrapped in the following
|
||||
preprocessor macro
|
||||
|
||||
```c
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
/*
|
||||
... code ...
|
||||
*/
|
||||
#endif /* defined(__APPLE__) || defined(__MACH__) */
|
||||
```
|
||||
|
||||
## Structs
|
||||
|
||||
### ProcessData
|
||||
|
||||
ProcessData is a struct that tracks cpu and memory usage of a process. It needs to be regularly updated with calls to
|
||||
`update_process()` in order to provide accurate information
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
double total_user_time;
|
||||
double total_kernel_time;
|
||||
double last_total_consumed;
|
||||
double percent_cpu;
|
||||
|
||||
uint64_t virtual_memory;
|
||||
uint64_t resident_memory;
|
||||
|
||||
time_t timestamp;
|
||||
time_t last_timestamp;
|
||||
} ProcessData;
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
## new_ProcessData
|
||||
|
||||
Returns a pointer to a `ProcessData` struct.
|
||||
|
||||
```c
|
||||
ProcessData *new_ProcessData();
|
||||
```
|
||||
|
||||
## update_process
|
||||
|
||||
Updates a `ProcessData` struct. This should be called in a loop or at specific intervals to measure proper usage
|
||||
data. An example is below
|
||||
|
||||
```c
|
||||
int update_process(pid_t pid, ProcessData *proc);
|
||||
|
||||
/* Example */
|
||||
pid_t pid = getpid();
|
||||
ProcessData *pd = new_ProcessData();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
update_process(pid, pd);
|
||||
printf("CPU: %.2f\n", pd->percent_cpu);
|
||||
sleep(1);
|
||||
}
|
||||
free(pd);
|
||||
```
|
67
docs/math.md
67
docs/math.md
@ -1,67 +0,0 @@
|
||||
# math
|
||||
|
||||
General math functions
|
||||
|
||||
## Functions
|
||||
|
||||
## max_int
|
||||
|
||||
Return the maximum integer between `int a` and `int b`
|
||||
|
||||
```c
|
||||
int max_int(int a, int b);
|
||||
```
|
||||
|
||||
## min_int
|
||||
|
||||
Return the minimum integer between `int a` and `int b`
|
||||
|
||||
```c
|
||||
int min_int(int a, int b);
|
||||
```
|
||||
|
||||
## clamp_int
|
||||
|
||||
Clamps an integer between a high and low value
|
||||
|
||||
```c
|
||||
int clamp_int(int i, int low, int high);
|
||||
```
|
||||
|
||||
## binstr_to_int
|
||||
|
||||
Converts a string representing a binary number into an integer. Supports underscores as spacing
|
||||
|
||||
```c
|
||||
int binstr_to_int(const char *s);
|
||||
|
||||
/* Usage */
|
||||
int a = binstr_to_int("10011101");
|
||||
int b = binstr_to_int("1001_1101_0010_1011");
|
||||
```
|
||||
|
||||
## bresenham
|
||||
|
||||
Uses bresenham's line algorithim to generate a line in 2D space.
|
||||
Returns a pointer to an array of `Point`.
|
||||
The `sz` parameter holds the size of the array.
|
||||
|
||||
```c
|
||||
Point *bresenham(int x0, int y0, int x1, int y1, size_t *sz);
|
||||
```
|
||||
|
||||
## bresenham_p
|
||||
|
||||
Works the same as `bresenham()` but uses the `Point` struct instead of `int`
|
||||
|
||||
```c
|
||||
Point *bresenham_p(Point p1, Point p2, size_t *sz);
|
||||
```
|
||||
|
||||
## is_power_of_two
|
||||
|
||||
Returns `1` if `i` is a power of two, otherwise returns `1`.
|
||||
|
||||
```c
|
||||
int is_power_of_two(int i);
|
||||
```
|
194
docs/memory.md
194
docs/memory.md
@ -1,194 +0,0 @@
|
||||
# memory
|
||||
|
||||
Custom allocators and memory functions
|
||||
|
||||
## Arena Allocator
|
||||
|
||||
A simple arena-style allocator
|
||||
|
||||
## Structs
|
||||
|
||||
### ArenaAllocator
|
||||
|
||||
Represents an arena allocator. `ArenaAllocator` holds its own buffer, but managing its size is left to the user. Like
|
||||
most structs in `libflint`, it must be malloc'd first before being passed to `arena_init()`.
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
unsigned char* buf;
|
||||
size_t buf_sz;
|
||||
size_t offset_cur;
|
||||
size_t offset_prev;
|
||||
} ArenaAllocator;
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
### arena_init
|
||||
|
||||
Initializes the `ArenaAllocator`. The struct must first be created by the user using `malloc()`, see the example below.
|
||||
`buf_sz` is the size of the underlying buffer in bytes.
|
||||
|
||||
```c
|
||||
void arena_init(ArenaAllocator *allocator, size_t buf_sz);
|
||||
|
||||
/* Usage */
|
||||
ArenaAllocator *a = malloc(sizeof(ArenaAllocator));
|
||||
arena_init(a, 1024);
|
||||
```
|
||||
|
||||
### arena_free
|
||||
Frees `allocator` and its underlying buffer. Users should set `allocator` to `NULL` after calling `arena_free()`.
|
||||
```c
|
||||
void arena_free(ArenaAllocator *allocator);
|
||||
|
||||
/* Usage */
|
||||
arena_free(allocator);
|
||||
allocator = NULL;
|
||||
```
|
||||
|
||||
### arena_clear
|
||||
|
||||
Resets the offset markers of the arena to `0`, but does not wipe the underlying buffer. Technically, any assigned pointers
|
||||
will still work and
|
||||
|
||||
```c
|
||||
void arena_clear(ArenaAllocator *allocator);
|
||||
```
|
||||
|
||||
|
||||
### *arena_malloc
|
||||
|
||||
Request memory of `size` bytes in length from the arena. Returns `NULL` if the assignment failed.
|
||||
|
||||
```c
|
||||
void *arena_malloc(ArenaAllocator* allocator, size_t size);
|
||||
```
|
||||
|
||||
### arena_resize_buf
|
||||
|
||||
Reallocates the underlying buffer in the arena to `new_sz`. You can grow or shrink the arena using this function. Any
|
||||
pointers allocated out of the arena are invalid after using this function.
|
||||
|
||||
```c
|
||||
void arena_resize_buf(ArenaAllocator *allocator, size_t new_sz);
|
||||
```
|
||||
|
||||
### *arena_resize
|
||||
|
||||
Resize an allocated pointer from the arena. See the example below for a simple use case
|
||||
|
||||
```c
|
||||
void *arena_resize(ArenaAllocator *allocator, void *mem, size_t old_sz, size_t new_sz);
|
||||
|
||||
/* Usage */
|
||||
int *i = arena_malloc(a, sizeof(int));
|
||||
*i = 1;
|
||||
long *l = arena_resize(a, i1, sizeof(int), sizeof(long));
|
||||
assert(*l == 1);
|
||||
```
|
||||
|
||||
## Macros
|
||||
|
||||
### arena_sz
|
||||
|
||||
Convenience macro for getting the size of the arena's buffer
|
||||
|
||||
```c
|
||||
#define arena_sz(a) (a)->buf_sz
|
||||
```
|
||||
|
||||
## Pool Allocator
|
||||
|
||||
A pool-based allocator for chunks of the same size. Useful for quickly allocating and using memory of the same size
|
||||
without worrying about order; most operations are `O(1)`
|
||||
|
||||
## Structs
|
||||
|
||||
### PoolAllocator
|
||||
|
||||
Represents a pool allocator. `PoolAllocator` holds its own buffer, but managing its size is left to the user. Like
|
||||
most structs in `libflint`, it must be malloc'd first before being passed to `pool_init()`.
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
unsigned char *buf;
|
||||
size_t buf_sz;
|
||||
size_t chunk_size;
|
||||
|
||||
List *free_list;
|
||||
} PoolAllocator;
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
### pool_init
|
||||
|
||||
Initializes the `PoolAllocator`. The struct must first be created by the user using `malloc()`, see the example below.
|
||||
|
||||
- `buf_sz`: Size of the underlying buffer in bytes
|
||||
- `chunk_sz`: Size of each chunk in bytes
|
||||
- `chunk_align`: The alignment of the chunks. The`LF_DEFAULT_ALIGNMENT` macro is available as a good default for basic types
|
||||
|
||||
```c
|
||||
void pool_init(PoolAllocator *allocator, size_t buf_sz, size_t chunk_sz, size_t chunk_align);
|
||||
|
||||
/* Usage */
|
||||
PoolAllocator *pool = malloc(sizeof(PoolAllocator));
|
||||
pool_init(pool, 64, 16, LF_DEFAULT_ALIGNMENT);
|
||||
```
|
||||
|
||||
### pool_free
|
||||
|
||||
Return a single chunk back to the pool. `ptr` is a pointer to the allocated chunk.
|
||||
|
||||
```c
|
||||
void pool_free(PoolAllocator *allocator, void *ptr);
|
||||
```
|
||||
|
||||
### pool_free_all
|
||||
|
||||
Returns all chunks back to the pool. Any pointers received before this call are now invalid and must be reasigned with
|
||||
`pool_alloc` or set to `NULL`.
|
||||
|
||||
```c
|
||||
void pool_free_all(PoolAllocator *allocator);
|
||||
```
|
||||
|
||||
### pool_alloc
|
||||
|
||||
Allocate a chunk from the pool. Returns `NULL` on failure.
|
||||
|
||||
```c
|
||||
void *pool_alloc(PoolAllocator *allocator);
|
||||
```
|
||||
|
||||
### pool_destroy
|
||||
|
||||
Destroys the underlying buffer and `List` in `allocator`, then frees it. User is responsible for setting `allocator` to
|
||||
`NULL` afterwards.
|
||||
|
||||
```c
|
||||
void pool_destroy(PoolAllocator *allocator);
|
||||
```
|
||||
|
||||
## Macros
|
||||
|
||||
### pool_count_available
|
||||
|
||||
Returns the amount of chunks left available in the pool
|
||||
|
||||
```c
|
||||
#define pool_count_available(x) (x)->free_list->size
|
||||
```
|
||||
|
||||
### LF_DEFAULT_ALIGNMENT
|
||||
|
||||
The default alignment for allocators. Use this as a simple default (defaults to 16 bytes on amd64 systems) when storing
|
||||
basic types
|
||||
|
||||
```c
|
||||
#ifndef DEFAULT_ALIGNMENT
|
||||
#define LF_DEFAULT_ALIGNMENT (2*sizeof(void*))
|
||||
#endif // DEFAULT_ALIGNMENT
|
||||
```
|
106
docs/network.md
106
docs/network.md
@ -1,106 +0,0 @@
|
||||
# network
|
||||
|
||||
This module provides a generic `Server` type that abstracts away the setup and teardown of a socket
|
||||
|
||||
## Enums
|
||||
|
||||
### ServerType
|
||||
|
||||
Types of servers. Currently supports TCP and UDP, will eventually add UNIX sockets.
|
||||
|
||||
```c
|
||||
typedef enum ServerType {
|
||||
SERVERTYPE_TCP,
|
||||
SERVERTYPE_UDP
|
||||
} ServerType;
|
||||
```
|
||||
|
||||
## Structs
|
||||
|
||||
### Server
|
||||
|
||||
Server is a generic abstraction over sockets. The type of the server is defined by `server_type`.
|
||||
|
||||
```c
|
||||
typedef struct Server {
|
||||
ServerType server_type;
|
||||
int fd;
|
||||
int port;
|
||||
void (*handler)(struct Server *s);
|
||||
} Server;
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
### new_server
|
||||
|
||||
Create a `Server*`. User is responsible for freeing the memory.
|
||||
|
||||
```c
|
||||
Server *new_server(ServerType type, const char *port, void(handler)(Server *s));
|
||||
```
|
||||
|
||||
### delete_server
|
||||
|
||||
Frees the memory allocated for `Server*` and sets the pointer to `NULL`.
|
||||
|
||||
```c
|
||||
void delete_server(Server *s);
|
||||
```
|
||||
|
||||
### serve
|
||||
|
||||
Starts up the server. `backlog_size` is the size of the backlog buffer for the underlying socket. Use the macro
|
||||
`DEFAULT_BACKLOG_SIZE` or pass `0` to use a reasonable default.
|
||||
|
||||
```c
|
||||
int serve(Server *s, int backlog_size);
|
||||
```
|
||||
|
||||
### get_in_addr
|
||||
|
||||
Convenience method to get an IP address from a `struct sockaddr_storage` of either IPV4 or IPV6.
|
||||
|
||||
```c
|
||||
void *get_in_addr(struct sockaddr *sa);
|
||||
|
||||
/* Usage */
|
||||
struct sockaddr_storage client_addr;
|
||||
socklen_t client_addr_sz = sizeof(client_addr);
|
||||
char buf[33];
|
||||
|
||||
if (new_fd = accept(s->fd, (struct sockaddr *)&client_addr, &client_addr_sz) == -1) {
|
||||
/* error handling */
|
||||
}
|
||||
inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), buf, 32);
|
||||
printf("Received connection from %s\n", buf);
|
||||
|
||||
```
|
||||
|
||||
### handler_tcp_echo
|
||||
|
||||
An example handler for a multithreaded tcp echo server.
|
||||
|
||||
```c
|
||||
void handler_tcp_echo(Server *s);
|
||||
|
||||
/* Usage */
|
||||
#include "lfnetwork.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Server *server = new_server(SERVERTYPE_TCP, "80", handler_tcp_echo);
|
||||
serve(server, DEFAULT_BACKLOG);
|
||||
delete_server(server);
|
||||
}
|
||||
```
|
||||
|
||||
## Macros
|
||||
|
||||
### DEFAULT_BACKLOG_SIZE
|
||||
|
||||
A default size for the socket's backlog buffer. `5` is a standard default size, providing some backlog but not
|
||||
enough to make huge buffers for each socket
|
||||
|
||||
```c
|
||||
#define DEFAULT_BACKLOG_SIZE 5
|
||||
```
|
@ -1,14 +0,0 @@
|
||||
# parsing
|
||||
|
||||
String parsing tools
|
||||
|
||||
## Functions
|
||||
|
||||
### simple_english_scoring
|
||||
|
||||
Scores a string based on a simple ETAOIN SHRDLU scale. A simple, somewhat accurate way to determine if a string is
|
||||
English.
|
||||
|
||||
```c
|
||||
int simple_english_scoring(const char *s);
|
||||
```
|
@ -1,3 +0,0 @@
|
||||
# set
|
||||
|
||||
Coming soon
|
@ -1,74 +0,0 @@
|
||||
# stack
|
||||
|
||||
LIFO (last in first out) stack structure
|
||||
|
||||
## Structs
|
||||
|
||||
`Stack` is a linked list with stack-based operations available
|
||||
|
||||
```c
|
||||
#define Stack List
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
### stack_init
|
||||
|
||||
Intializes the stack. The user is responsible for creating the initial `Stack` structure and freeing memory with `stack_destroy()`. `destroy` is a deallocation function for the members of `Stack`, pass `NULL` if the memory is stack-allocated
|
||||
|
||||
```c
|
||||
void stack_init(Stack *stack, void (*destroy)(void *data));
|
||||
|
||||
/* Usage */
|
||||
Stack *stack = malloc(sizeof(Stack));
|
||||
|
||||
// Pass NULL for stack-allocated memory
|
||||
stack_init(stack, NULL);
|
||||
|
||||
// Pass free or a custom freeing function for heap allocated memory
|
||||
stack_init(stack, free);
|
||||
```
|
||||
|
||||
### stack_destroy
|
||||
|
||||
Destroys the nodes inside a `Stack` 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 stack_destroy(Stack *stack);
|
||||
```
|
||||
|
||||
### stack_push
|
||||
|
||||
Push a new element onto the top of the stack
|
||||
|
||||
```c
|
||||
int stack_push(Stack *stack, void *data);
|
||||
```
|
||||
|
||||
### stack_peek
|
||||
|
||||
Returns a `void *` to the top element of the stack. Does not remove the element
|
||||
|
||||
```c
|
||||
void *stack_peek(Stack *stack);
|
||||
|
||||
/* Usage */
|
||||
// stack: 1 2 3
|
||||
int *t = (int*)stack_peek(stack);
|
||||
assert(*t == 3);
|
||||
// stack: 1 2 3
|
||||
```
|
||||
|
||||
### stack_pop
|
||||
|
||||
Returns a `void *` to the top element of the stack and removes the element
|
||||
|
||||
```c
|
||||
int stack_pop(Stack *stack, void **data);
|
||||
|
||||
/* Usage */
|
||||
// stack: 1 2 3
|
||||
int *t = (int*)stack_peek(stack);
|
||||
assert(*t == 3);
|
||||
// stack: 1 2
|
||||
```
|
@ -1,46 +0,0 @@
|
||||
# string
|
||||
|
||||
C string helpers
|
||||
|
||||
## Functions
|
||||
|
||||
### find_substrings
|
||||
Finds the indicies of all locations of the given needle in the haystack. `substrings` is an array of `size_t` indicies that
|
||||
the substring is found at. This function allocates the memory for `substrings` and memory cleanup is managed by the user.
|
||||
`num_substrings` is a pointer to a pre-allocated `size_t` that will be modified to contain the number of found substrings
|
||||
and subsequently the size of `substrings`.
|
||||
|
||||
If no substrings are found, `substrings` will not be allocated and left set to `NULL`, `num_substrings` will be `0`, and
|
||||
the function will return `0`.
|
||||
|
||||
Returns 0 if the function is successful. Returns a non-zero value if there is an error.
|
||||
|
||||
```c
|
||||
int find_substrings(const char* haystack, const char* needle, size_t *num_substrings, size_t **substrings);
|
||||
|
||||
/* Usage */
|
||||
const char* haystack = "One two three two";
|
||||
const char* needle = "two";
|
||||
|
||||
size_t subs_sz = 0;
|
||||
size_t *subs = NULL;
|
||||
size_t *subs = find_substrings(haystack, needle, &subs_sz, &subs);
|
||||
// subs: [ 4, 14 ]
|
||||
// subs_sz: 2
|
||||
|
||||
free(subs);
|
||||
```
|
||||
|
||||
### substr
|
||||
|
||||
Extracts a substring at a specific index and length. This function returns a copy of the substring in a heap allocated
|
||||
buffer that the user is responsible for freeing. Returns `NULL` if there is an error.
|
||||
|
||||
```c
|
||||
const char* substr(const char* str, size_t idx, size_t len);
|
||||
|
||||
/* Usage */
|
||||
const char *s = substr("One two three", 4, 3);
|
||||
assert(strcmp(s, "two") == 0);
|
||||
free(s);
|
||||
```
|
@ -1,16 +0,0 @@
|
||||
# utility
|
||||
|
||||
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;
|
||||
```
|
174
docs/vector.md
174
docs/vector.md
@ -1,174 +0,0 @@
|
||||
# vector
|
||||
|
||||
Simple type-agnostic dynamic array
|
||||
|
||||
## Structs
|
||||
|
||||
### Vector
|
||||
|
||||
Vector struct
|
||||
|
||||
```c
|
||||
typedef struct Vector {
|
||||
size_t capacity;
|
||||
size_t length;
|
||||
void **elements;
|
||||
void (*destroy)(void *data);
|
||||
} Vector;
|
||||
```
|
||||
|
||||
Members:
|
||||
|
||||
- `capacity`: The size of `elements` in memory
|
||||
- `length`: The number of real elements stored in the backing `elements` array
|
||||
- `elements`: The dynamic array of `void *` that holds the vector's members
|
||||
- `destroy`: Optional deallocation function for data inside a node. Typical usage is `NULL` for stack allocated data and `free()` for data created with `malloc()`
|
||||
|
||||
## Functions
|
||||
|
||||
### vec_init
|
||||
|
||||
Initialize the vector with a default capacity of 2. User is responsible for freeing elements of the vector with `vec_destroy()`. Returns a non-zero integer if there is an error
|
||||
|
||||
```c
|
||||
int vec_init(Vector *vec, void (*destroy)(void *data));
|
||||
```
|
||||
|
||||
### vec_init_with_capacity
|
||||
|
||||
Initialize the vector with a user-specified capacity. User is responsible for freeing elements of the vector with `vec_destroy()`. Returns a non-zero integer if there is an error
|
||||
|
||||
```c
|
||||
int vec_init_with_capacity(Vector *vec, void (*destroy)(void *data), size_t cap);
|
||||
```
|
||||
|
||||
### vec_destroy
|
||||
|
||||
Frees the underlying array inside a `Vector`. If `destroy` was provided when creating the vector, then it is called against each element in the array before the array is freed. Does not destroy the vector itself, that is left up to the user
|
||||
|
||||
|
||||
```c
|
||||
void vec_destroy(Vector *vec);
|
||||
|
||||
/* Usage */
|
||||
vec_destroy(vec);
|
||||
free(vec);
|
||||
```
|
||||
|
||||
### vec_insert
|
||||
|
||||
Insert `data` into the vector at a specified index. Any elements at that array and beyond will be moved up to make room. Returns a non-zero integer if there is an error
|
||||
|
||||
```c
|
||||
int vec_insert(Vector *vec, void *data, size_t index);
|
||||
|
||||
/* Usage */
|
||||
|
||||
// vec: 1 2 3 4
|
||||
int i = 99;
|
||||
vec_insert(vec, &i, 2);
|
||||
// vec: 1 2 99 3 4
|
||||
```
|
||||
|
||||
### vec_push
|
||||
|
||||
Insert `data` at the end of the vector. Returns a non-zero integer if there is an error
|
||||
|
||||
```c
|
||||
int vec_push(Vector *vec, void *data);
|
||||
|
||||
/* Usage */
|
||||
|
||||
// vec: 1 2 3
|
||||
int *i = malloc(sizeof(int));
|
||||
*i = 4;
|
||||
vec_push(vec, i);
|
||||
// vec: 1 2 3 4
|
||||
```
|
||||
|
||||
### vec_safe_at
|
||||
|
||||
Gets the stored data at a specified index. Uses safety checks to make sure `index` is not out of bounds. Returns `NULL` if there is an error
|
||||
|
||||
```c
|
||||
void *vec_safe_at(Vector *vec, size_t index);
|
||||
```
|
||||
|
||||
### vec_remove
|
||||
|
||||
Removes an element from the array and returns the pointer, then moves elements to shrink the array accordingly. Returns `NULL` if the index is not valid
|
||||
|
||||
```c
|
||||
void *vec_remove(Vector *vec, size_t index);
|
||||
|
||||
/* Usage */
|
||||
// vec: 1 2 3 4
|
||||
int *t = NULL;
|
||||
t = (int*)vec_remove(vec, 2);
|
||||
assert(*t == 3);
|
||||
// vec: 1 2 4
|
||||
```
|
||||
|
||||
### vec_shrink
|
||||
|
||||
Shrinks the capacity of the vector down to the current length. Returns a non-zero integer if there is an error
|
||||
|
||||
```c
|
||||
int vec_shrink(Vector *vec);
|
||||
```
|
||||
|
||||
### vec_max
|
||||
|
||||
Finds the largest value in the vector and returns a void pointer to the underlying data. Requires a
|
||||
comparison function to compare the data in the vector. This function must return `1` if `a > b`, `-1` if
|
||||
`a < b`, or `0` if `a == b`. See the supplied comparison functions below for reference
|
||||
|
||||
```c
|
||||
const void *vec_min(const Vector *vec, int(*cmp)(const void *a, const void *b));
|
||||
```
|
||||
|
||||
### vec_min
|
||||
|
||||
Finds the smallest value in the vector and returns a void pointer to the underlying data. Requires a
|
||||
comparison function to compare the data in the vector. This function must return `1` if `a > b`, `-1` if
|
||||
`a < b`, or `0` if `a == b`. See the supplied comparison functions below for reference
|
||||
|
||||
```c
|
||||
const void *vec_max(const Vector *vec, int(*cmp)(const void *a, const void *b));
|
||||
```
|
||||
|
||||
## Comparison Functions
|
||||
|
||||
Comparison functions to compare data in a vector. These functions must return `1` if `a > b`, `-1` if
|
||||
`a < b`, or `0` if `a == b`.
|
||||
|
||||
```c
|
||||
int vec_cmp_int(const void *a, const void *b);
|
||||
int vec_cmp_char(const void *a, const void *b);
|
||||
```
|
||||
|
||||
## Macros
|
||||
|
||||
### vec_at
|
||||
|
||||
Grabs the element at index `i` without safety checks for better performance. Use with caution
|
||||
|
||||
```c
|
||||
#define vec_at(v, i) (v)->elements[(i)]
|
||||
```
|
||||
|
||||
### vec_len
|
||||
|
||||
Returns the length of the vector
|
||||
|
||||
```c
|
||||
#define vec_len(v) (v)->length
|
||||
```
|
||||
|
||||
### vec_cap
|
||||
|
||||
Returns the capacity of the vector
|
||||
|
||||
```c
|
||||
#define vec_cap(v) (v)->capacity
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user