From e01b2451c6b8c8a49279025ed392138b48e52c39 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Wed, 18 Jan 2023 16:58:33 +0100 Subject: [PATCH 1/6] chore: add some more config files --- .clangd | 2 ++ Makefile | 1 + 2 files changed, 3 insertions(+) create mode 100644 .clangd diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..ef516ad --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Add: -ferror-limit=0 diff --git a/Makefile b/Makefile index 238d4d3..4907163 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,7 @@ $(BUILD_DIR)/$(TEST_DIR)/%.c.o: $(TEST_DIR)/%.c mkdir -p $(dir $@) $(CC) $(CFLAGS) -I$(TEST_DIR) -c $< -o $@ + # =====MAINTENANCE===== .PHONY: lint lint: -- 2.40.1 From ad8c37c9eaafb469076583803ebc49bef8f1364d Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Wed, 18 Jan 2023 17:04:45 +0100 Subject: [PATCH 2/6] chore: added woodpecker config --- .woodpecker.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .woodpecker.yml diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..a7e8fe3 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,36 @@ +variables: + &image 'git.rustybever.be/chewing_bever/c-devop:alpine3.17' + +matrix: + PLATFORM: + - 'linux/amd64' + - 'linux/arm64' + +branches: + exclude: [ main ] +platform: ${PLATFORM} + +pipeline: + lint: + image: *image + pull: true + commands: + - make lint + when: + event: [push, pull_request] + + build: + image: *image + commands: + - make + - make clean + - CFLAGS='-O3' make + when: + event: [push, pull_request] + + test: + image: *image + commands: + - make test + when: + event: [push, pull_request] -- 2.40.1 From 050e99b413314e680cfc50787889f901905d3a57 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sat, 21 Jan 2023 16:31:22 +0100 Subject: [PATCH 3/6] feat(heap): code skeleton --- Makefile | 2 +- include/vieter_heap.h | 26 ++++++++++++++++++++++++++ src/heap/heap.c | 28 ++++++++++++++++++++++++++++ test/heap/test_heap.c | 18 ++++++++++++++++++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 include/vieter_heap.h create mode 100644 src/heap/heap.c create mode 100644 test/heap/test_heap.c diff --git a/Makefile b/Makefile index 4907163..edca96b 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ INC_FLAGS := $(addprefix -I,$(INC_DIRS)) # object file is also recompiled if only a header is changed. # -MP: generate a dummy target for every header file (according to the docs it # prevents some errors when removing header files) -CFLAGS ?= -MMD -MP -Wall -Werror -Wextra +CFLAGS ?= -MMD -MP -Wall -Wextra CFLAGS += $(INC_FLAGS) .PHONY: all diff --git a/include/vieter_heap.h b/include/vieter_heap.h new file mode 100644 index 0000000..ffb7da2 --- /dev/null +++ b/include/vieter_heap.h @@ -0,0 +1,26 @@ +#ifndef VIETER_HEAP +#define VIETER_HEAP + +#include +#include + +typedef struct vieter_heap vieter_heap; + +typedef enum vieter_heap_error { + vieter_heap_ok = 0, + vieter_heap_empty = 1 +} vieter_heap_error; + +vieter_heap *vieter_heap_init(); + +void vieter_heap_free(vieter_heap *heap); + +uint64_t vieter_heap_size(vieter_heap *heap); + +vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, void *data); + +vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap); + +vieter_heap_error vieter_heap_peek(void **out, vieter_heap *heap); + +#endif diff --git a/src/heap/heap.c b/src/heap/heap.c new file mode 100644 index 0000000..7e3669a --- /dev/null +++ b/src/heap/heap.c @@ -0,0 +1,28 @@ +#include "vieter_heap.h" + +struct vieter_heap { + uint64_t size; +}; + +vieter_heap *vieter_heap_init() { + return NULL; +} + +uint64_t vieter_heap_size(vieter_heap *heap) { + return heap->size; +} + +void vieter_heap_free(vieter_heap *heap) {} + + +vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, void *data) { + return vieter_heap_ok; +} + +vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap) { + return vieter_heap_ok; +} + +vieter_heap_error vieter_heap_peek(void **out, vieter_heap *heap) { + return vieter_heap_ok; +} diff --git a/test/heap/test_heap.c b/test/heap/test_heap.c new file mode 100644 index 0000000..4079569 --- /dev/null +++ b/test/heap/test_heap.c @@ -0,0 +1,18 @@ +#include "acutest.h" +#include "vieter_heap.h" + +#define TEST_SIZE(heap, size) \ + TEST_CHECK(vieter_heap_size(heap) == size); \ + TEST_MSG("Size: %zu", vieter_heap_size(heap)) + +void test_init() { + vieter_heap *heap = vieter_heap_init(); + TEST_CHECK(heap != NULL); + TEST_SIZE(heap, 0); + vieter_heap_free(heap); +} + +TEST_LIST = { + {"test_init", test_init}, + {NULL, NULL} +}; -- 2.40.1 From 6823050c2fecf6246366f61a4d42051d01a2c4a6 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sun, 22 Jan 2023 09:40:35 +0100 Subject: [PATCH 4/6] refactor(heap): properly organised code --- include/vieter_heap.h | 9 +++++---- src/heap/heap.c | 28 --------------------------- src/heap/vieter_heap.c | 38 +++++++++++++++++++++++++++++++++++++ src/heap/vieter_heap_tree.c | 38 +++++++++++++++++++++++++++++++++++++ src/heap/vieter_heap_tree.h | 30 +++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 32 deletions(-) delete mode 100644 src/heap/heap.c create mode 100644 src/heap/vieter_heap.c create mode 100644 src/heap/vieter_heap_tree.c create mode 100644 src/heap/vieter_heap_tree.h diff --git a/include/vieter_heap.h b/include/vieter_heap.h index ffb7da2..c7a9706 100644 --- a/include/vieter_heap.h +++ b/include/vieter_heap.h @@ -1,14 +1,14 @@ #ifndef VIETER_HEAP #define VIETER_HEAP -#include #include +#include typedef struct vieter_heap vieter_heap; typedef enum vieter_heap_error { - vieter_heap_ok = 0, - vieter_heap_empty = 1 + vieter_heap_ok = 0, + vieter_heap_empty = 1 } vieter_heap_error; vieter_heap *vieter_heap_init(); @@ -17,7 +17,8 @@ void vieter_heap_free(vieter_heap *heap); uint64_t vieter_heap_size(vieter_heap *heap); -vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, void *data); +vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, + void *data); vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap); diff --git a/src/heap/heap.c b/src/heap/heap.c deleted file mode 100644 index 7e3669a..0000000 --- a/src/heap/heap.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "vieter_heap.h" - -struct vieter_heap { - uint64_t size; -}; - -vieter_heap *vieter_heap_init() { - return NULL; -} - -uint64_t vieter_heap_size(vieter_heap *heap) { - return heap->size; -} - -void vieter_heap_free(vieter_heap *heap) {} - - -vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, void *data) { - return vieter_heap_ok; -} - -vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap) { - return vieter_heap_ok; -} - -vieter_heap_error vieter_heap_peek(void **out, vieter_heap *heap) { - return vieter_heap_ok; -} diff --git a/src/heap/vieter_heap.c b/src/heap/vieter_heap.c new file mode 100644 index 0000000..6d543df --- /dev/null +++ b/src/heap/vieter_heap.c @@ -0,0 +1,38 @@ +#include "vieter_heap.h" +#include "vieter_heap_tree.h" + +#include + +struct vieter_heap { + vieter_heap_tree *tree; +}; + +vieter_heap *vieter_heap_init() { return calloc(1, sizeof(vieter_heap)); } + +uint64_t vieter_heap_size(vieter_heap *heap) { return 0; } + +void vieter_heap_free(vieter_heap *heap) {} + +vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, + void *data) { + vieter_heap_node *new_node = vieter_heap_node_init(); + new_node->key = key; + new_node->data = data; + vieter_heap_tree *new_tree = vieter_heap_tree_init(new_node, NULL, 1); + + if (heap->tree == NULL) { + heap->tree = new_tree; + } else { + heap->tree = vieter_heap_tree_merge(heap->tree, new_tree); + } + + return vieter_heap_ok; +} + +vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap) { + return vieter_heap_ok; +} + +vieter_heap_error vieter_heap_peek(void **out, vieter_heap *heap) { + return vieter_heap_ok; +} diff --git a/src/heap/vieter_heap_tree.c b/src/heap/vieter_heap_tree.c new file mode 100644 index 0000000..e65fb56 --- /dev/null +++ b/src/heap/vieter_heap_tree.c @@ -0,0 +1,38 @@ +#include "vieter_heap_tree.h" + +vieter_heap_node *vieter_heap_node_init() { + return calloc(1, sizeof(vieter_heap_node)); +} + +vieter_heap_node *vieter_heap_node_merge_same_order(vieter_heap_node *root_a, + vieter_heap_node *root_b) { + vieter_heap_node *new_root, *new_child; + + if (root_a->key <= root_b->key) { + new_root = root_a; + new_child = root_b; + } else { + new_root = root_b; + new_child = root_a; + } + + new_root->next_largest_order = new_root->largest_order; + new_root->largest_order = new_child; + + return new_root; +} + +vieter_heap_tree *vieter_heap_tree_init(vieter_heap_node *root, + vieter_heap_tree *next, + uint64_t order) { + vieter_heap_tree *tree = malloc(sizeof(vieter_heap_tree)); + + tree->root = root; + tree->next = next; + tree->order = order; + + return tree; +} + +vieter_heap_tree *vieter_heap_tree_merge(vieter_heap_tree *tree_a, + vieter_heap_tree *tree_b) {} diff --git a/src/heap/vieter_heap_tree.h b/src/heap/vieter_heap_tree.h new file mode 100644 index 0000000..73e1611 --- /dev/null +++ b/src/heap/vieter_heap_tree.h @@ -0,0 +1,30 @@ +#ifndef VIETER_HEAP_TREE +#define VIETER_HEAP_TREE + +#include +#include + +typedef struct vieter_heap_node { + uint64_t key; + void *data; + struct vieter_heap_node *largest_order; + struct vieter_heap_node *next_largest_order; +} vieter_heap_node; + +vieter_heap_node *vieter_heap_node_init(); + +void vieter_heap_node_free(vieter_heap_node *node); + +vieter_heap_node *vieter_heap_node_merge_same_order(vieter_heap_node *root_a, vieter_heap_node *root_b); + +typedef struct vieter_heap_tree { + uint64_t order; + vieter_heap_node *root; + struct vieter_heap_tree *next; +} vieter_heap_tree; + +vieter_heap_tree *vieter_heap_tree_init(vieter_heap_node *root, vieter_heap_tree *next, uint64_t order); + +vieter_heap_tree *vieter_heap_tree_merge(vieter_heap_tree *tree_a, vieter_heap_tree *tree_b); + +#endif -- 2.40.1 From ef625ed14e18e654c0f21b357ea509e551267da5 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sun, 22 Jan 2023 10:08:15 +0100 Subject: [PATCH 5/6] chore: allow tests to access internal methods --- Makefile | 10 +++++++--- test/heap/test_heap.c | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index edca96b..30b6a31 100644 --- a/Makefile +++ b/Makefile @@ -56,11 +56,15 @@ build-test: $(BINS_TEST) $(BINS_TEST): %: %.c.o $(OBJS) $(CC) $^ -o $@ -# Each test includes the test directory, which contains the acutest header file +# Allow with the include directory, each test includes $(TEST_DIR) (which +# contains the acutest.h header file), and the src directory of the module it's +# testing. This allows tests to access internal methods, which aren't publicly +# exposed. $(BUILD_DIR)/$(TEST_DIR)/%.c.o: $(TEST_DIR)/%.c mkdir -p $(dir $@) - $(CC) $(CFLAGS) -I$(TEST_DIR) -c $< -o $@ - + $(CC) $(CFLAGS) -I$(TEST_DIR) \ + -I$(dir $(@:$(BUILD_DIR)/$(TEST_DIR)/%=$(SRC_DIR)/%)) \ + -c $< -o $@ # =====MAINTENANCE===== .PHONY: lint diff --git a/test/heap/test_heap.c b/test/heap/test_heap.c index 4079569..832404d 100644 --- a/test/heap/test_heap.c +++ b/test/heap/test_heap.c @@ -1,5 +1,6 @@ #include "acutest.h" #include "vieter_heap.h" +#include "vieter_heap_tree.h" #define TEST_SIZE(heap, size) \ TEST_CHECK(vieter_heap_size(heap) == size); \ -- 2.40.1 From 2cc974accc6ff049c4bacbb28ab18ed4bbe7f9de Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sun, 22 Jan 2023 11:56:11 +0100 Subject: [PATCH 6/6] chore: updated readme --- README.md | 36 +++++++++++++++---- ...{expression.c => vieter_cron_expression.c} | 0 src/cron/{parse.c => vieter_cron_parse.c} | 0 src/heap/vieter_heap_tree.h | 2 +- 4 files changed, 30 insertions(+), 8 deletions(-) rename src/cron/{expression.c => vieter_cron_expression.c} (100%) rename src/cron/{parse.c => vieter_cron_parse.c} (100%) diff --git a/README.md b/README.md index 724ba54..9381fb1 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,12 @@ # libvieter -This library powers part of Vieter, most noteably the sections that can easily +This library powers part of Vieter, most notably the sections that can easily be implemented in C (or just parts I want to implement in C because it's fun). -The goal of this library is to be completely self-contained, meaning any -required data structures have to be implemented as well. It can only depend on -the C standard libraries. +The goal of this library is to be as self-contained as possible; data +structures should be implemented manually if possible. -Currently it contains the following: - -* Cron expression parser & next time calculator +See the [source code](/src) for the list of modules. ## Development @@ -18,6 +15,27 @@ Currently it contains the following: Everything is handled by the provided Makefile. To compile the static library, simply run `make`. +### Project structure + +Each module has its own subdirectory inside `src`, e.g. `src/cron`. This +directory contains the actual implementation of a module, along with any +internally used header files. Each internal function should be defined in a +header file, as to make testing these possible. + +Each module should also have its own header file inside the `include` +directory. This header file defines the public API that the library exposes for +this specific module. + +Any code in a module may only import internal headers from that module, along +with any of the public API header files. Modules should not depend on each +other's internal implementationns. + +Each module should contain a README describing its contents. + +All file names, function names... (even internals) should follow snake case +convention and have a prefix unique to that module, starting with `vieter_`. +For example, the `cron` modules uses the `vieter_cron_` prefix for everything. + ### Testing This library uses [Acutest](https://github.com/mity/acutest) for its tests. @@ -25,6 +43,10 @@ Tests should be placed in the `test` subdirectory, further divided into directories that correspond those in `src`. Test files should begin with `test_`, and their format should follow the expected format for Acutest. +Each `test_` is compiled separately into a binary, linked with libvieter. A +test file can import any of the public API header files, along with any header +files defined in its respective module. This allows testing internal functions. + To run the tests, simply run `make test`. If you wish to only run a specific test binary, you can find them in `build/test`. diff --git a/src/cron/expression.c b/src/cron/vieter_cron_expression.c similarity index 100% rename from src/cron/expression.c rename to src/cron/vieter_cron_expression.c diff --git a/src/cron/parse.c b/src/cron/vieter_cron_parse.c similarity index 100% rename from src/cron/parse.c rename to src/cron/vieter_cron_parse.c diff --git a/src/heap/vieter_heap_tree.h b/src/heap/vieter_heap_tree.h index 73e1611..18808e1 100644 --- a/src/heap/vieter_heap_tree.h +++ b/src/heap/vieter_heap_tree.h @@ -15,7 +15,7 @@ vieter_heap_node *vieter_heap_node_init(); void vieter_heap_node_free(vieter_heap_node *node); -vieter_heap_node *vieter_heap_node_merge_same_order(vieter_heap_node *root_a, vieter_heap_node *root_b); +vieter_heap_node *vieter_heap_tree_merge_same_order(vieter_heap_node *root_a, vieter_heap_node *root_b); typedef struct vieter_heap_tree { uint64_t order; -- 2.40.1