This commit is contained in:
Evan Burkey 2021-02-01 14:06:37 -08:00
commit 86be1e8de5
18 changed files with 750 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
cmake*

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

2
.idea/libfputs.iml Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

4
.idea/misc.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/libfputs.iml" filepath="$PROJECT_DIR$/.idea/libfputs.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

21
CMakeLists.txt Normal file
View File

@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.17)
project(flint C)
set(CMAKE_C_STANDARD 99)
include_directories(include)
set(SOURCES
src/linkedlist.c
src/set.c
src/stack.c
src/binarytree.c
)
add_library(flint ${SOURCES})
if(${CMAKE_PROJECT_NAME} STREQUAL flint)
add_executable(tests tests/tests.c)
target_include_directories(tests PRIVATE include)
target_link_libraries(tests flint)
endif()

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
Copyright 2021 Evan Burkey <evan@burkey.co>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# flint
My personal library of common C data structures and algorithms.

31
include/binarytree.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef LIBFLINT_BINARY_TREE_H
#define LIBFLINT_BINARY_TREE_H
struct BinTreeNode {
void *data;
struct BinTreeNode *left;
struct BinTreeNode *right;
};
struct BinTree {
int size;
int (*compare)(const void *a, const void *b);
void (*destroy)(void *data);
struct BinTreeNode *root;
};
void bintree_init(struct BinTree *tree, void (*destroy)(void *data));
void bintree_destroy(struct BinTree *tree);
int bintree_ins_left(struct BinTree *tree, struct BinTreeNode *node, void *data);
int bintree_ins_right(struct BinTree *tree, struct BinTreeNode *node, void *data);
void bintree_rem_left(struct BinTree *tree, struct BinTreeNode *node);
void bintree_rem_right(struct BinTree *tree, struct BinTreeNode *node);
int bintree_merge(struct BinTree *merge, struct BinTree *left, struct BinTree *right, void *data);
void bintree_debug_print(struct BinTree *tree);
#define bintree_is_eob(node) ((node) == NULL)
#define bintree_is_leaf(node) ((node)->left == NULL && (node)->right == NULL)
#endif

30
include/linkedlist.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef LIBFLINT_LL_H
#define LIBFLINT_LL_H
#include <stddef.h>
struct ListNode {
void* data;
struct ListNode* next;
struct ListNode* prev;
};
struct List {
size_t size;
void (*destroy)(void* data);
int (*match)(const void* a, const void* b);
struct ListNode* head;
struct ListNode* tail;
};
void ll_init(struct List* list, void (*destroy)(void *data));
void ll_destroy(struct List* list);
int ll_ins_next(struct List* list, struct ListNode* node, const void* data);
int ll_ins_prev(struct List* list, struct ListNode* node, const void* data);
int ll_remove(struct List* list, struct ListNode* node, void** data);
int ll_remove_next(struct List* list, struct ListNode* node, void** data);
int ll_remove_prev(struct List* list, struct ListNode* node, void** data);
#endif

20
include/set.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef LIBFLINT_SET_H
#define LIBFLINT_SET_H
#include "linkedlist.h"
#define Set List
void set_init(struct Set* set, int (*match)(const void* a, const void* b),
void (*destroy)(void* data));
void set_destroy(struct Set* set);
int set_insert(struct Set* set, const void* data);
int set_remove(struct Set* set, void** data);
int set_union(struct Set* setu, const struct Set* a, const struct Set* b);
int set_intersection(struct Set* seti, const struct Set* a, const struct Set* b);
int set_difference(struct Set* setd, const struct Set* a, const struct Set* b);
int set_is_member(const struct Set* set, const void* data);
int set_is_subset(const struct Set* a, const struct Set* b);
int set_is_equal(const struct Set* a, const struct Set* b);
#endif

14
include/stack.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef LIBFLINT_STACK_H
#define LIBFLINT_STACK_H
#include "linkedlist.h"
#define Stack List
void stack_init(struct Stack* stack, void (*destroy)(void* data));
void stack_destroy(struct Stack* stack);
int stack_push(struct Stack* stack, void *data);
void *stack_peek(struct Stack *stack);
int stack_pop(struct Stack *stack, void **data);
#endif

163
src/binarytree.c Normal file
View File

@ -0,0 +1,163 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "binarytree.h"
void bintree_init(struct BinTree *tree, void (*destroy)(void *data)) {
tree->size = 0;
tree->destroy = destroy;
tree->compare = NULL;
tree->root = NULL;
}
void bintree_destroy(struct BinTree *tree) {
bintree_rem_left(tree, NULL);
memset(tree, 0, sizeof(struct BinTree));
}
int bintree_ins_left(struct BinTree *tree, struct BinTreeNode *node, void *data) {
struct BinTreeNode *new_node;
struct BinTreeNode **pos;
if (node == NULL) {
if (tree->size > 0) {
return 1;
}
pos = &tree->root;
} else {
if (node->left != NULL) {
return -1;
}
pos = &node->left;
}
if ((new_node = malloc(sizeof(struct BinTreeNode))) == NULL) {
return 2;
}
new_node->data = data;
new_node->left = NULL;
new_node->right = NULL;
*pos = new_node;
tree->size += 1;
return 0;
}
int bintree_ins_right(struct BinTree *tree, struct BinTreeNode *node, void *data) {
struct BinTreeNode *new_node;
struct BinTreeNode **pos;
if (node == NULL) {
if (tree->size > 0) {
return 1;
}
pos = &tree->root;
} else {
if (node->right != NULL) {
return -1;
}
pos = &node->right;
}
if ((new_node = malloc(sizeof(struct BinTreeNode))) == NULL) {
return 2;
}
new_node->data = data;
new_node->left = NULL;
new_node->right = NULL;
*pos = new_node;
tree->size += 1;
return 0;
}
void bintree_rem_left(struct BinTree *tree, struct BinTreeNode *node) {
if (tree->size == 0) {
return;
}
struct BinTreeNode **pos;
if (node == NULL) {
pos = &tree->root;
} else {
pos = &node->left;
}
if (*pos != NULL) {
bintree_rem_left(tree, *pos);
bintree_rem_right(tree, *pos);
if (tree->destroy != NULL) {
tree->destroy((*pos)->data);
}
free(*pos);
*pos = NULL;
tree->size -= 1;
}
}
void bintree_rem_right(struct BinTree *tree, struct BinTreeNode *node) {
if (tree->size == 0) {
return;
}
struct BinTreeNode **pos;
if (node == NULL) {
pos = &tree->root;
} else {
pos = &node->right;
}
if (*pos != NULL) {
bintree_rem_left(tree, *pos);
bintree_rem_right(tree, *pos);
if (tree->destroy != NULL) {
tree->destroy((*pos)->data);
}
free(*pos);
*pos = NULL;
tree->size -= 1;
}
}
int bintree_merge(struct BinTree *merge, struct BinTree *left, struct BinTree *right, void *data) {
bintree_init(merge, left->destroy);
if (bintree_ins_left(merge, NULL, data) != 0) {
bintree_destroy(merge);
return -1;
}
merge->root->left = left->root;
merge->root->right = right->root;
left->root = NULL;
left->size = 0;
right->root = NULL;
right->size = 0;
return 0;
}
void print_node(char* prefix, struct BinTreeNode *node, int is_left, void (*pfunc)(void* data)) {
if (node != NULL) {
printf("%s%s", prefix, (is_left ? "├──" : "└──" ));
pfunc(node->data);
char new_prefix[64];
memset(new_prefix, 0, 64);
strcat(new_prefix, prefix);
strcat(new_prefix, (is_left == 1 ? "" : " "));
print_node(new_prefix, node->left, 1, pfunc);
print_node(new_prefix, node->right, 0, pfunc);
}
}
void bintree_debug_pfunc_int(void* data) {
int i = *((int*)data);
printf("%d\n", i);
}
void bintree_debug_print(struct BinTree *tree) {
print_node("", tree->root, 0, bintree_debug_pfunc_int);
}

122
src/linkedlist.c Normal file
View File

@ -0,0 +1,122 @@
#include <string.h>
#include <stdlib.h>
#include "linkedlist.h"
void ll_init(struct List* list, void (*destroy)(void *data)) {
list->size = 0;
list->destroy = destroy;
list->head = NULL;
list->tail = NULL;
}
void ll_destroy(struct List* list) {
void* data;
while (list->size > 0) {
if (ll_remove(list, list->tail, (void**)&data) == 0 && list->destroy != NULL) {
list->destroy(data);
}
}
memset(list, 0, sizeof(struct List));
}
int ll_ins_next(struct List* list, struct ListNode* node, const void* data) {
struct ListNode* new_node;
if (node == NULL && list->size != 0) {
return -1;
}
if ((new_node = malloc(sizeof(struct ListNode))) == NULL) {
return -1;
}
new_node->data = (void*)data;
if (list->size == 0) {
list->head = new_node;
list->head->prev = NULL;
list->head->next = NULL;
list->tail = new_node;
} else {
new_node->next = node->next;
new_node->prev = node;
if (node->next == NULL) {
list->tail = new_node;
} else {
node->next->prev = new_node;
}
node->next = new_node;
}
list->size++;
return 0;
}
int ll_ins_prev(struct List* list, struct ListNode* node, const void* data) {
struct ListNode* new_node;
if (node == NULL && list->size != 0) {
return -1;
}
if ((new_node = malloc(sizeof(struct ListNode))) == NULL) {
return -1;
}
new_node->data = (void*)data;
if (list->size == 0) {
list->head = new_node;
list->head->prev = NULL;
list->head->next = NULL;
list->tail = new_node;
} else {
new_node->next = node;
new_node->prev = node->prev;
if (node->prev == NULL) {
list->head = new_node;
} else {
node->prev->next = new_node;
}
node->prev = new_node;
}
list->size++;
return 0;
}
int ll_remove(struct List* list, struct ListNode* node, void** data) {
if (node == NULL || list->size == 0) {
return -1;
}
*data = node->data;
if (node == list->head) {
list->head = node->next;
if (list->head == NULL) {
list->tail = NULL;
} else {
node->next->prev = NULL;
}
} else {
node->prev->next = node->next;
if (node->next == NULL) {
list->tail = node->prev;
} else {
node->next->prev = node->prev;
}
}
free(node);
list->size--;
return 0;
}
int ll_remove_next(struct List* list, struct ListNode* node, void** data) {
if (node->next == NULL) {
return -1;
}
return ll_remove(list, node->next, data);
}
int ll_remove_prev(struct List* list, struct ListNode* node, void** data) {
if (node->prev == NULL) {
return -1;
}
return ll_remove(list, node->prev, data);
}

124
src/set.c Normal file
View File

@ -0,0 +1,124 @@
#include "set.h"
void set_init(struct Set* set, int (*match)(const void* a, const void* b),
void (*destroy)(void* data)) {
ll_init(set, destroy);
set->match = match;
}
void set_destroy(struct Set* set) {
ll_destroy(set);
}
int set_insert(struct Set* set, const void* data) {
if (set_is_member(set, data)) {
return 1;
}
return ll_ins_next(set, set->tail, data);
}
int set_remove(struct Set* set, void** data) {
struct ListNode* node = NULL;
for (node = set->head; node != NULL; node = node->next) {
if (set->match(*data, node->data)) {
break;
}
}
if (node == NULL) {
return -1;
}
return ll_remove_next(set, node, data);
}
int set_union(struct Set* setu, const struct Set* a, const struct Set* b) {
struct ListNode* node;
void* data;
set_init(setu, a->match, NULL);
for (node = a->head; node != NULL; node = node->next) {
data = node->data;
if (ll_ins_next(setu, setu->tail, data) != 0) {
set_destroy(setu);
return -1;
}
}
for (node = b->head; node != NULL; node = node->next) {
if (set_is_member(a, node->data)) {
continue;
}
data = node->data;
if (ll_ins_next(setu, setu->tail, data) != 0) {
set_destroy(setu);
return -1;
}
}
return 0;
}
int set_intersection(struct Set* seti, const struct Set* a, const struct Set* b) {
struct ListNode* node;
void* data;
set_init(seti, a->match, NULL);
for (node = a->head; node != NULL; node = node->next) {
data = node->data;
if (set_is_member(b, data)) {
if (ll_ins_next(seti, seti->tail, data)) {
set_destroy(seti);
return -1;
}
}
}
return 0;
}
int set_difference(struct Set* setd, const struct Set* a, const struct Set* b) {
struct ListNode* node;
void* data;
set_init(setd, a->match, NULL);
for (node = a->head; node != NULL; node = node->next) {
data = node->data;
if (!set_is_member(b, data)) {
if (ll_ins_next(setd, setd->tail, data)) {
set_destroy(setd);
return -1;
}
}
}
return 0;
}
int set_is_member(const struct Set* set, const void* data) {
for (struct ListNode* node = set->head; node != NULL; node = node->next) {
if (set->match(data, node->data)) {
return 1;
}
}
return 0;
}
int set_is_subset(const struct Set* a, const struct Set* b) {
if (a->size > b->size) {
return 0;
}
for (struct ListNode* node = a->head; node != NULL; node = node->next) {
if (!set_is_member(b, node->data)) {
return 0;
}
}
return 1;
}
int set_is_equal(const struct Set* a, const struct Set* b) {
if (a->size == b->size) {
return 0;
}
return set_is_subset(a, b);
}

25
src/stack.c Normal file
View File

@ -0,0 +1,25 @@
#include "stack.h"
void stack_init(struct Stack* stack, void (*destroy)(void* data)) {
ll_init(stack, destroy);
}
void stack_destroy(struct Stack* stack) {
ll_destroy(stack);
}
int stack_push(struct Stack* stack, void *data) {
if (stack->size == 0) {
return ll_ins_next(stack, NULL, data);
} else {
return ll_ins_next(stack, stack->tail, data);
}
}
void *stack_peek(struct Stack *stack) {
return stack->tail == NULL ? NULL : stack->tail->data;
}
int stack_pop(struct Stack *stack, void **data) {
return ll_remove(stack, stack->tail, data);
}

155
tests/tests.c Normal file
View File

@ -0,0 +1,155 @@
#include <stdio.h>
#include <stdlib.h>
#include "linkedlist.h"
#include "set.h"
#include "stack.h"
#include "binarytree.h"
void print_ll(struct List* list) {
for (struct ListNode* node = list->head; node != NULL; node = node->next) {
printf(" %d", *((int*)node->data));
}
printf("\n");
}
void test_ll() {
printf("\n--- LIST TEST ---\n");
struct List* list = malloc(sizeof(struct 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("struct List: ");
print_ll(list);
void* data;
ll_remove_next(list, list->head, &data);
printf("struct List: ");
print_ll(list);
printf("Removed: %d\n", *((int*)data));
ll_destroy(list);
free(list);
}
int int_match(const void* a, const void* b) {
return *((int*)a) == *((int*)b);
}
void test_set() {
printf("\n--- SET TEST ---\n");
struct Set* set = malloc(sizeof(struct Set));
set_init(set, int_match, NULL);
int i = 1;
int j = 2;
int k = 2;
set_insert(set, (void*)&i);
set_insert(set, (void*)&j);
set_insert(set, (void*)&k);
int i2 = 1;
int j2 = 4;
struct Set* set2 = malloc(sizeof(struct Set));
set_init(set2, int_match, NULL);
set_insert(set2, (void*)&i2);
set_insert(set2, (void*)&j2);
printf("struct Set 1:");
print_ll(set);
printf("struct Set 2:");
print_ll(set2);
printf("\n");
struct Set* set_u = malloc(sizeof(struct Set));
struct Set* set_i = malloc(sizeof(struct Set));
struct Set* set_d = malloc(sizeof(struct Set));
set_union(set_u, set, set2);
printf("Union:");
print_ll(set_u);
set_difference(set_d, set, set2);
printf("Difference:");
print_ll(set_d);
set_intersection(set_i, set, set2);
printf("Intersection:");
print_ll(set_i);
set_destroy(set);
set_destroy(set2);
set_destroy(set_u);
set_destroy(set_i);
set_destroy(set_d);
free(set);
free(set2);
free(set_u);
free(set_i);
free(set_d);
}
void test_stack() {
printf("\n--- STACK TEST ---\n");
struct Stack *stack = malloc(sizeof(struct Stack));
stack_init(stack, NULL);
int a = 1, b = 2;
stack_push(stack, &a);
stack_push(stack, &b);
printf("struct Stack size: %lu\n", stack->size);
int *p = NULL;
stack_pop(stack, (void **)&p);
printf("b = %d\n", *p);
stack_pop(stack, (void **)&p);
printf("a = %d\n", *p);
printf("struct Stack size: %lu\n", stack->size);
stack_destroy(stack);
}
void test_bintree() {
printf("\n--- BINARY TREE TEST ---\n");
struct BinTree *tree = malloc(sizeof(struct 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);
}
int main() {
test_ll();
test_set();
test_stack();
test_bintree();
return 0;
}