From 2f946a8a762734b9e799e8def33bdfa52d11b72c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 4 Sep 2023 13:23:18 +1000 Subject: [PATCH] remove submodule, add source files (#134) * remove submodule * add alex-c-collections, remove submodule --- .cppcheck.supp | 1 + .github/workflows/ci.yml | 2 - .gitmodules | 4 - CONTRIBUTING.md | 6 - GNUmakefile | 15 +-- config.mk | 2 +- lib/alex-c-collections | 1 - lib/col/.source | 1 + lib/col/inc/itable.h | 67 ++++++++++ lib/col/inc/oset.h | 65 ++++++++++ lib/col/inc/ptable.h | 59 +++++++++ lib/col/inc/slist.h | 84 +++++++++++++ lib/col/inc/stable.h | 66 ++++++++++ lib/col/src/itable.c | 240 +++++++++++++++++++++++++++++++++++ lib/col/src/oset.c | 210 +++++++++++++++++++++++++++++++ lib/col/src/ptable.c | 48 +++++++ lib/col/src/slist.c | 265 +++++++++++++++++++++++++++++++++++++++ lib/col/src/stable.c | 246 ++++++++++++++++++++++++++++++++++++ tst/GNUmakefile | 5 +- 19 files changed, 1360 insertions(+), 27 deletions(-) delete mode 100644 .gitmodules delete mode 160000 lib/alex-c-collections create mode 100644 lib/col/.source create mode 100644 lib/col/inc/itable.h create mode 100644 lib/col/inc/oset.h create mode 100644 lib/col/inc/ptable.h create mode 100644 lib/col/inc/slist.h create mode 100644 lib/col/inc/stable.h create mode 100644 lib/col/src/itable.c create mode 100644 lib/col/src/oset.c create mode 100644 lib/col/src/ptable.c create mode 100644 lib/col/src/slist.c create mode 100644 lib/col/src/stable.c diff --git a/.cppcheck.supp b/.cppcheck.supp index 0cd64b94..6075d6c0 100644 --- a/.cppcheck.supp +++ b/.cppcheck.supp @@ -1,2 +1,3 @@ +unusedFunction:lib/col/*c unusedFunction:tst/wrap-log.c unusedFunction:tst/util.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ecfbcca..8d89ad25 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - with: - submodules: true - name: deps run: | sudo add-apt-repository universe diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 4b151bbc..00000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "lib/alex-c-collections"] - path = lib/alex-c-collections - url = https://github.com/alex-courtis/alex-c-collections.git - branch = 1.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cb0f959f..33dff9c3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,12 +20,6 @@ Most will be available if you are running a wlroots based compositor like sway. yaml-cpp will need to be installed via your distribution's package manager. -## Library Submodules - -Following clone the libraries must be fetched. - -`git submodule update --init` - ## Development gcc is the default for packaging reasons, however clang is preferred. diff --git a/GNUmakefile b/GNUmakefile index 31e89b74..29d157f7 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,15 +1,11 @@ include config.mk -INC_H = $(wildcard inc/*.h) +INC_H = $(wildcard inc/*.h) $(wildcard lib/col/inc/*.h) -SRC_C = $(wildcard src/*.c) +SRC_C = $(wildcard src/*.c) $(wildcard lib/col/src/*.c) SRC_CXX = $(wildcard src/*.cpp) SRC_O = $(SRC_C:.c=.o) $(SRC_CXX:.cpp=.o) -LIB_H = $(wildcard lib/alex-c-collections/inc/*.h) -LIB_C = $(wildcard lib/alex-c-collections/src/*.c) -LIB_O = $(LIB_C:.c=.o) - EXAMPLE_C = $(wildcard examples/*.c) EXAMPLE_O = $(EXAMPLE_C:.c=.o) EXAMPLE_E = $(EXAMPLE_C:.c=) @@ -28,11 +24,10 @@ TST_T = $(patsubst tst%,test%,$(TST_E)) all: way-displays $(SRC_O): $(INC_H) $(PRO_H) config.mk GNUmakefile -$(LIB_O): $(LIB_H) $(LIB_C) config.mk GNUmakefile $(PRO_O): $(PRO_H) config.mk GNUmakefile $(EXAMPLE_O): $(INC_H) $(PRO_H) config.mk GNUmakefile -way-displays: $(SRC_O) $(PRO_O) $(LIB_O) +way-displays: $(SRC_O) $(PRO_O) $(CXX) -o $(@) $(^) $(LDFLAGS) $(LDLIBS) $(PRO_H): $(PRO_X) @@ -42,7 +37,7 @@ $(PRO_C): $(PRO_X) wayland-scanner private-code $(@:.c=.xml) $@ clean: - rm -f way-displays $(SRC_O) $(PRO_O) $(PRO_H) $(PRO_C) $(LIB_O) $(TST_O) $(TST_E) $(EXAMPLE_E) $(EXAMPLE_O) + rm -f way-displays $(SRC_O) $(PRO_O) $(PRO_H) $(PRO_C) $(TST_O) $(TST_E) $(EXAMPLE_E) $(EXAMPLE_O) install: way-displays way-displays.1 cfg.yaml mkdir -p $(DESTDIR)$(PREFIX)/bin @@ -84,7 +79,7 @@ $(TST_T): all $(VALGRIND) ./$(EXE) examples: $(EXAMPLE_E) -examples/%: examples/%.o $(filter-out src/main.o,$(SRC_O)) $(PRO_O) $(LIB_O) +examples/%: examples/%.o $(filter-out src/main.o,$(SRC_O)) $(PRO_O) $(CXX) -o $(@) $(^) $(LDFLAGS) $(LDLIBS) .PHONY: all clean install uninstall man cppcheck iwyu test test-vg $(TST_T) diff --git a/config.mk b/config.mk index 2f2ccb2c..59d5f45c 100644 --- a/config.mk +++ b/config.mk @@ -4,7 +4,7 @@ PREFIX ?= /usr/local PREFIX_ETC ?= /usr/local ROOT_ETC ?= /etc -INCS = -Iinc -Ipro -Ilib/alex-c-collections/inc +INCS = -Iinc -Ipro -Ilib/col/inc CPPFLAGS += $(INCS) -D_GNU_SOURCE -DVERSION=\"$(VERSION)\" -DROOT_ETC=\"$(ROOT_ETC)\" diff --git a/lib/alex-c-collections b/lib/alex-c-collections deleted file mode 160000 index 4c3f2b43..00000000 --- a/lib/alex-c-collections +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4c3f2b432c46ea72326e4dd9a5ce229725a8b7f3 diff --git a/lib/col/.source b/lib/col/.source new file mode 100644 index 00000000..2f8c064f --- /dev/null +++ b/lib/col/.source @@ -0,0 +1 @@ +git@github.com:alex-courtis/alex-c-collections.git v1.1.1 diff --git a/lib/col/inc/itable.h b/lib/col/inc/itable.h new file mode 100644 index 00000000..cd77d05a --- /dev/null +++ b/lib/col/inc/itable.h @@ -0,0 +1,67 @@ +#ifndef ITABLE_H +#define ITABLE_H + +#include +#include + +/* + * Array backed integer indexed table. + * Entries preserve insertion order. + * Operations linearly traverse keys. + * NULL values permitted. + * Not thread safe. + */ +struct ITable; + +/* + * Entry iterator. + */ +struct ITableIter { + const uint64_t key; + const void* const val; +}; + +/* + * Lifecycle + */ + +// construct a table with initial size, growing as necessary, NULL on zero param +const struct ITable *itable_init(const size_t initial, const size_t grow); + +// free table +void itable_free(const void* const tab); + +// free table and vals, null free_val uses free() +void itable_free_vals(const struct ITable* const tab, void (*free_val)(const void* const val)); + +// free iter +void itable_iter_free(const struct ITableIter* const iter); + +/* + * Access + */ + +// return val, NULL not present +const void *itable_get(const struct ITable* const tab, const uint64_t key); + +// create an iterator, caller must itable_iter_free or invoke itable_next until NULL +const struct ITableIter *itable_iter(const struct ITable* const tab); + +// next iterator value, NULL at end of list +const struct ITableIter *itable_next(const struct ITableIter* const iter); + +// number of entries with val +size_t itable_size(const struct ITable* const tab); + +/* + * Mutate + */ + +// set key/val, return old val if overwritten +const void *itable_put(const struct ITable* const tab, const uint64_t key, const void* const val); + +// remove key, return old val if present +const void *itable_remove(const struct ITable* const tab, const uint64_t key); + +#endif // ITABLE_H + diff --git a/lib/col/inc/oset.h b/lib/col/inc/oset.h new file mode 100644 index 00000000..1e795b3d --- /dev/null +++ b/lib/col/inc/oset.h @@ -0,0 +1,65 @@ +#ifndef OSET_H +#define OSET_H + +#include +#include + +/* + * Array backed ordered set. + * Operations linearly traverse values. + * NULL not permitted. + * Not thread safe. +*/ +struct OSet; + +/* + * Entry iterator. + */ +struct OSetIter { + const void* const val; +}; + +/* + * Lifecycle + */ + +// construct a set with initial size, grow as needed, NULL on zero param +const struct OSet *oset_init(const size_t initial, const size_t grow); + +// free set +void oset_free(const void* const set); + +// free map and vals, NULL free_val uses free() +void oset_free_vals(const struct OSet* const set, void (*free_val)(const void* const val)); + +// free iter +void oset_iter_free(const struct OSetIter* const iter); + +/* + * Access + */ + +// true if this set contains the specified element +bool oset_contains(const struct OSet* const set, const void* const val); + +// number of values +size_t oset_size(const struct OSet* const set); + +// create an iterator, caller must oset_iter_free or invoke oset_next until NULL +const struct OSetIter *oset_iter(const struct OSet* const set); + +// next iterator value, NULL at end of set +const struct OSetIter *oset_next(const struct OSetIter* const iter); + +/* + * Mutate + */ + +// true if this set did not already contain the specified element +bool oset_add(const struct OSet* const set, const void* const val); + +// true if this set contained the element +bool oset_remove(const struct OSet* const set, const void* const val); + +#endif // OSET_H + diff --git a/lib/col/inc/ptable.h b/lib/col/inc/ptable.h new file mode 100644 index 00000000..7d5fc38f --- /dev/null +++ b/lib/col/inc/ptable.h @@ -0,0 +1,59 @@ +#ifndef PTABLE_H +#define PTABLE_H + +#include + +/* + * ITable convenience wrapper with pointer key. + */ +struct PTable; + +/* + * Entry iterator. + */ +struct PTableIter { + const void *key; + const void *val; +}; + +/* + * Lifecycle + */ + +// construct a table with initial size, growing as necessary, NULL on zero param +const struct PTable *ptable_init(const size_t initial, const size_t grow); + +// free table +void ptable_free(const void* const tab); + +// free table and vals, null free_val uses free() +void ptable_free_vals(const struct PTable* const tab, void (*free_val)(const void* const val)); + +// free iter +void ptable_iter_free(const struct PTableIter* const iter); + +/* + * Access + */ + +// return val, NULL not present +const void *ptable_get(const struct PTable* const tab, const void* const key); + +// create an iterator, caller must ptable_iter_free or invoke ptable_next until NULL +const struct PTableIter *ptable_iter(const struct PTable* const tab); + +// next iterator value, NULL at end of list +const struct PTableIter *ptable_next(const struct PTableIter* const iter); + +// number of entries with val +size_t ptable_size(const struct PTable* const tab); + +/* + * Mutate + */ + +// set key/val, return old val if overwritten, NULL val to remove +const void *ptable_put(const struct PTable* const tab, const void* const key, const void* const val); + +#endif // PTABLE_H + diff --git a/lib/col/inc/slist.h b/lib/col/inc/slist.h new file mode 100644 index 00000000..f5634af0 --- /dev/null +++ b/lib/col/inc/slist.h @@ -0,0 +1,84 @@ +#ifndef SLIST_H +#define SLIST_H + +#include +#include + +struct SList { + void *val; + struct SList *nex; +}; + +/* + * Lifecycle + */ + +// clone the list, setting val pointers +struct SList *slist_shallow_clone(struct SList *head); + +// free list +void slist_free(struct SList **head); + +// free list and vals, NULL free_val uses free() +void slist_free_vals(struct SList **head, void (*free_val)(void *val)); + +/* + * Mutate + */ + +// append val to a list +struct SList *slist_append(struct SList **head, void *val); + +// remove an item, returning the val +void *slist_remove(struct SList **head, struct SList **item); + +// remove items, NULL predicate is val pointer comparison +size_t slist_remove_all(struct SList **head, bool (*predicate)(const void *val, const void *data), const void *data); + +// remove items and free vals, NULL predicate is val pointer comparison, NULL free_val calls free() +size_t slist_remove_all_free(struct SList **head, bool (*predicate)(const void *val, const void *data), const void *data, void (*free_val)(void *val)); + +/* + * Access + */ + +// val at position +void *slist_at(struct SList *head, size_t index); + +// find +struct SList *slist_find(struct SList *head, bool (*test)(const void *val)); + +// find a val +void *slist_find_val(struct SList *head, bool (*test)(const void *val)); + +// find, NULL predicate is val pointer comparison +struct SList *slist_find_equal(struct SList *head, bool (*predicate)(const void *val, const void *data), const void *data); + +// find a val, NULL predicate is val pointer comparison +void *slist_find_equal_val(struct SList *head, bool (*predicate)(const void *val, const void *data), const void *data); + +// same length and every item passes test in order, NULL equal compares pointers +bool slist_equal(struct SList *a, struct SList *b, bool (*equal)(const void *a, const void *b)); + +/* + * Utility + */ + +// length +size_t slist_length(struct SList *head); + +// sort into a new list +struct SList *slist_sort(struct SList *head, bool (*before)(const void *a, const void *b)); + +// move items between lists with predicate, NULL predicate does nothing +void slist_move(struct SList **to, struct SList **from, bool (*predicate)(const void *val, const void *data), const void *data); + +/* + * Predicate + */ + +// test val for equality using strcmp +bool slist_predicate_strcmp(const void *val, const void *data); + +#endif // SLIST_H + diff --git a/lib/col/inc/stable.h b/lib/col/inc/stable.h new file mode 100644 index 00000000..956ac1c7 --- /dev/null +++ b/lib/col/inc/stable.h @@ -0,0 +1,66 @@ +#ifndef STABLE_H +#define STABLE_H + +#include + +/* + * Array backed string indexed table. + * Entries preserve insertion order. + * Operations linearly traverse keys. + * NULL values permitted. + * Not thread safe. + */ +struct STable; + +/* + * Entry iterator. + */ +struct STableIter { + const char* const key; + const void* const val; +}; + +/* + * Lifecycle + */ + +// construct a table with initial size, growing as necessary, NULL on zero param +const struct STable *stable_init(const size_t initial, const size_t grow); + +// free table +void stable_free(const void* const tab); + +// free table and vals, null free_val uses free() +void stable_free_vals(const struct STable* const tab, void (*free_val)(const void* const val)); + +// free iter +void stable_iter_free(const struct STableIter* const iter); + +/* + * Access + */ + +// return val, NULL not present +const void *stable_get(const struct STable* const tab, const char* const key); + +// create an iterator, caller must stable_iter_free or invoke stable_next until NULL +const struct STableIter *stable_iter(const struct STable* const tab); + +// next iterator value, NULL at end of list +const struct STableIter *stable_next(const struct STableIter* const iter); + +// number of entries with val +size_t stable_size(const struct STable* const tab); + +/* + * Mutate + */ + +// set key/val, return old val if overwritten +const void *stable_put(const struct STable* const tab, const char* const key, const void* const val); + +// remove key, return old val if present +const void *stable_remove(const struct STable* const tab, const char* const key); + +#endif // STABLE_H + diff --git a/lib/col/src/itable.c b/lib/col/src/itable.c new file mode 100644 index 00000000..f4a18640 --- /dev/null +++ b/lib/col/src/itable.c @@ -0,0 +1,240 @@ +#include +#include +#include + +#include "itable.h" + +struct ITable { + uint64_t *keys; + const void **vals; + size_t capacity; + size_t grow; + size_t size; +}; + +struct ITableIterP { + /* + * Public, removed const + */ + uint64_t key; + const void *val; + + /* + * Private + */ + const struct ITable *tab; + const uint64_t *k; + const void **v; +}; + +// grow to capacity + grow +void grow_itable(struct ITable *tab) { + + // grow new arrays + uint64_t *new_keys = calloc(tab->capacity + tab->grow, sizeof(uint64_t)); + const void **new_vals = calloc(tab->capacity + tab->grow, sizeof(void*)); + + // copy old arrays + memcpy(new_keys, tab->keys, tab->capacity * sizeof(uint64_t)); + memcpy(new_vals, tab->vals, tab->capacity * sizeof(void*)); + + // free old arrays + free(tab->keys); + free(tab->vals); + + // lock in new + tab->keys = new_keys; + tab->vals = new_vals; + tab->capacity += tab->grow; +} + +const struct ITable *itable_init(const size_t initial, const size_t grow) { + if (initial == 0 || grow == 0) + return NULL; + + struct ITable *tab = calloc(1, sizeof(struct ITable)); + tab->capacity = initial; + tab->grow = grow; + tab->keys = calloc(tab->capacity, sizeof(uint64_t)); + tab->vals = calloc(tab->capacity, sizeof(void*)); + + return tab; +} + +void itable_free(const void* const cvtab) { + if (!cvtab) + return; + + struct ITable *tab = (struct ITable*)cvtab; + + free(tab->keys); + free(tab->vals); + + free(tab); +} + +void itable_free_vals(const struct ITable* const tab, void (*free_val)(const void* const val)) { + if (!tab) + return; + + for (const void **v = tab->vals; v < tab->vals + tab->capacity; v++) { + if (*v) { + if (free_val) { + free_val(*v); + } else { + free((void*)*v); + } + } + } + + itable_free(tab); +} + +void itable_iter_free(const struct ITableIter* const iter) { + if (!iter) + return; + + free((void*)iter); +} + +const void *itable_get(const struct ITable* const tab, const uint64_t key) { + if (!tab) + return NULL; + + // loop over keys + uint64_t *k; + const void **v; + for (k = tab->keys, v = tab->vals; + k < tab->keys + tab->size; + k++, v++) { + if (*k == key) { + return *v; + } + } + + return NULL; +} + +const struct ITableIter *itable_iter(const struct ITable* const tab) { + if (!tab) + return NULL; + + // loop over keys and vals + uint64_t *k; + const void **v; + for (k = tab->keys, v = tab->vals; + v < tab->vals + tab->size && k < tab->keys + tab->size; + k++, v++) { + if (*v) { + struct ITableIterP *iterp = calloc(1, sizeof(struct ITableIterP)); + + iterp->tab = tab; + iterp->key = *k; + iterp->val = *v; + iterp->k = k; + iterp->v = v; + + return (struct ITableIter*)iterp; + } + } + + return NULL; +} + +const struct ITableIter *itable_next(const struct ITableIter* const iter) { + if (!iter) + return NULL; + + struct ITableIterP *iterp = (struct ITableIterP*)iter; + + if (!iterp || !iterp->tab) { + itable_iter_free(iter); + return NULL; + } + + // loop over keys and vals + while (++iterp->v < iterp->tab->vals + iterp->tab->size && + ++iterp->k < iterp->tab->keys + iterp->tab->size) { + if (*iterp->v) { + iterp->key = *(iterp->k); + iterp->val = *(iterp->v); + return iter; + } + } + + itable_iter_free(iter); + return NULL; +} + +size_t itable_size(const struct ITable* const tab) { + if (!tab) + return 0; + + return tab->size; +} + +const void *itable_put(const struct ITable* const ctab, const uint64_t key, const void* const val) { + if (!ctab) + return NULL; + + struct ITable *tab = (struct ITable*)ctab; + + // loop over existing keys + uint64_t *k; + const void **v; + for (k = tab->keys, v = tab->vals; k < tab->keys + tab->size; k++, v++) { + + // overwrite existing values + if (*k == key) { + const void *prev = *v; + *v = val; + return prev; + } + } + + // grow for new entry + if (tab->size >= tab->capacity) { + grow_itable(tab); + k = &tab->keys[tab->size]; + v = &tab->vals[tab->size]; + } + + // new + *k = key; + *v = val; + tab->size++; + + return NULL; +} + +const void *itable_remove(const struct ITable* const ctab, const uint64_t key) { + if (!ctab) + return NULL; + + struct ITable *tab = (struct ITable*)ctab; + + // loop over existing keys + uint64_t *k; + const void **v; + for (k = tab->keys, v = tab->vals; k < tab->keys + tab->size; k++, v++) { + + if (*k == key) { + const void* prev = *v; + *v = NULL; + tab->size--; + + // shift down over removed + uint64_t *mk; + const void **mv; + for (mk = k, mv = v; mk < tab->keys + tab->size; mk++, mv++) { + *mk = *(mk + 1); + *mv = *(mv + 1); + } + + return prev; + } + } + + return NULL; +} + diff --git a/lib/col/src/oset.c b/lib/col/src/oset.c new file mode 100644 index 00000000..1cca7924 --- /dev/null +++ b/lib/col/src/oset.c @@ -0,0 +1,210 @@ +#include +#include +#include + +#include "oset.h" + +struct OSet { + const void **vals; + size_t capacity; + size_t grow; + size_t size; +}; + +struct OSetIterP { + /* + * Public, removed const + */ + const void* val; + + /* + * Private + */ + const struct OSet *set; + const void **v; +}; + +// grow to capacity + grow +void grow_oset(struct OSet *set) { + + // grow new arrays + const void **new_vals = calloc(set->capacity + set->grow, sizeof(void*)); + + // copy old arrays + memcpy(new_vals, set->vals, set->capacity * sizeof(void*)); + + // free old arrays + free(set->vals); + + // lock in new + set->vals = new_vals; + set->capacity += set->grow; +} + +const struct OSet *oset_init(const size_t initial, const size_t grow) { + if (initial == 0 || grow == 0) + return NULL; + + struct OSet *set = calloc(1, sizeof(struct OSet)); + set->capacity = initial; + set->grow = grow; + set->vals = calloc(set->capacity, sizeof(void*)); + + return set; +} + +void oset_free(const void* const cvset) { + if (!cvset) + return; + + struct OSet *set = (struct OSet*)cvset; + + free(set->vals); + + free(set); +} + +void oset_free_vals(const struct OSet* const set, void (*free_val)(const void* const val)) { + if (!set) + return; + + // loop over vals + for (const void **v = set->vals; v < set->vals + set->capacity; v++) { + if (*v) { + if (free_val) { + free_val(*v); + } else { + free((void*)*v); + } + } + } + + oset_free(set); +} + +void oset_iter_free(const struct OSetIter* const iter) { + if (!iter) + return; + + free((struct OSetIterP*)iter); +} + +bool oset_contains(const struct OSet* const set, const void* const val) { + if (!set || !val) + return false; + + // loop over vals + for (const void **v = set->vals; v < set->vals + set->size; v++) { + if (*v == val) { + return true; + } + } + + return false; +} + +size_t oset_size(const struct OSet* const set) { + if (!set) + return 0; + + return set->size; +} + +const struct OSetIter *oset_iter(const struct OSet* const set) { + if (!set) + return NULL; + + // loop over vals + for (const void **v = set->vals; v < set->vals + set->size; v++) { + if (*v) { + struct OSetIterP *iterp = calloc(1, sizeof(struct OSetIterP)); + + iterp->set = set; + iterp->val = *v; + iterp->v = v; + + return (struct OSetIter*)iterp; + } + } + + return NULL; +} + +const struct OSetIter *oset_next(const struct OSetIter* const iter) { + if (!iter) + return NULL; + + struct OSetIterP *iterp = (struct OSetIterP*)iter; + + if (!iterp || !iterp->set) { + oset_iter_free(iter); + return NULL; + } + + // loop over vals + while (++iterp->v < iterp->set->vals + iterp->set->size) { + if (*iterp->v) { + iterp->val = *(iterp->v); + return iter; + } + } + + oset_iter_free(iter); + return NULL; +} + +bool oset_add(const struct OSet* const cset, const void* const val) { + if (!cset || !val) + return false; + + struct OSet *set = (struct OSet*)cset; + + // loop over vals + const void **v; + for (v = set->vals; v < set->vals + set->size; v++) { + + // already present + if (*v == val) { + return false; + } + } + + // maybe grow for new entry + if (set->size >= set->capacity) { + grow_oset(set); + v = &set->vals[set->size]; + } + + // new value + *v = (void*)val; + set->size++; + + return true; +} + +bool oset_remove(const struct OSet* const cset, const void* const val) { + if (!cset || !val) + return false; + + struct OSet *set = (struct OSet*)cset; + + // loop over vals + for (const void **v = set->vals; v < set->vals + set->size; v++) { + if (*v == val) { + + *v = NULL; + set->size--; + + // shift down over removed + const void **m; + for (m = v; m < v + set->size; m++) { + *m = *(m + 1); + } + *m = NULL; + + return true; + } + } + + return false; +} diff --git a/lib/col/src/ptable.c b/lib/col/src/ptable.c new file mode 100644 index 00000000..8ae03911 --- /dev/null +++ b/lib/col/src/ptable.c @@ -0,0 +1,48 @@ +#include +#include +#include + +#include "itable.h" + +#include "ptable.h" + +const struct PTable *ptable_init(const size_t initial, const size_t grow) { + + // pointer has to fit into ITable key + assert(sizeof(void*) <= sizeof(uint64_t)); + + return (struct PTable *)itable_init(initial, grow); +} + +void ptable_free(const void* const tab) { + itable_free(tab); +} + +void ptable_free_vals(const struct PTable* const tab, void (*free_val)(const void* const val)) { + itable_free_vals((const struct ITable* const)tab, free_val); +} + +void ptable_iter_free(const struct PTableIter* const iter) { + itable_iter_free((const struct ITableIter* const)iter); +} + +const void *ptable_get(const struct PTable* const tab, const void* const key) { + return itable_get((const struct ITable* const)tab, (const uint64_t)key); +} + +const struct PTableIter *ptable_iter(const struct PTable* const tab) { + return (struct PTableIter*)itable_iter((struct ITable* const)tab); +} + +const struct PTableIter *ptable_next(const struct PTableIter* const iter) { + return (struct PTableIter*)itable_next((struct ITableIter* const)iter); +} + +size_t ptable_size(const struct PTable* const tab) { + return itable_size((struct ITable* const)tab); +} + +const void *ptable_put(const struct PTable* const tab, const void* const key, const void* const val) { + return itable_put((const struct ITable* const)tab, (const uint64_t)key, val); +} + diff --git a/lib/col/src/slist.c b/lib/col/src/slist.c new file mode 100644 index 00000000..97463590 --- /dev/null +++ b/lib/col/src/slist.c @@ -0,0 +1,265 @@ +#include +#include +#include + +#include "slist.h" + +struct SList *slist_shallow_clone(struct SList *head) { + struct SList *c, *i; + + c = NULL; + for (i = head; i; i = i->nex) { + slist_append(&c, i->val); + } + + return c; +} + +void slist_free(struct SList **head) { + struct SList *i, *f; + + i = *head; + while (i) { + f = i; + i = i->nex; + free(f); + } + + *head = NULL; +} + +void slist_free_vals(struct SList **head, void (*free_val)(void *val)) { + struct SList *i; + + for (i = *head; i; i = i->nex) { + if (free_val) { + free_val(i->val); + } else { + free(i->val); + } + } + + slist_free(head); +} + +struct SList *slist_append(struct SList **head, void *val) { + struct SList *i, *l; + + i = calloc(1, sizeof(struct SList)); + i->val = val; + + if (*head) { + for (l = *head; l->nex; l = l->nex); + l->nex = i; + } else { + *head = i; + } + + return i; +} + +void *slist_remove(struct SList **head, struct SList **item) { + struct SList *i, *f, *p; + void *removed = NULL; + + i = *head; + p = NULL; + f = NULL; + + for (i = *head; i; i = i->nex) { + if (i == *item) { + f = *item; + break; + } + p = i; + } + + if (f) { + if (p) { + p->nex = f->nex; + } else { + *head = f->nex; + } + removed = f->val; + free(f); + *item = NULL; + } + + return removed; +} + +size_t slist_remove_all(struct SList **head, bool (*predicate)(const void *val, const void *data), const void *data) { + struct SList *i; + size_t removed = 0; + + while ((i = slist_find_equal(*head, predicate, data))) { + slist_remove(head, &i); + removed++; + } + + return removed; +} + +size_t slist_remove_all_free(struct SList **head, bool (*predicate)(const void *val, const void *data), const void *data, void (*free_val)(void *val)) { + struct SList *i; + size_t removed = 0; + + while ((i = slist_find_equal(*head, predicate, data))) { + if (free_val) { + free_val(i->val); + } else { + free(i->val); + } + slist_remove(head, &i); + removed++; + } + + return removed; +} + +void *slist_at(struct SList *head, size_t index) { + size_t c = 0; + for (struct SList *i = head; i; i = i->nex, c++) { + if (c == index) { + return i->val; + } + } + + return NULL; +} + +struct SList *slist_find(struct SList *head, bool (*test)(const void *val)) { + struct SList *i; + + if (!test) + return NULL; + + for (i = head; i; i = i->nex) { + if (test(i->val)) { + return i; + } + } + + return NULL; +} + +void *slist_find_val(struct SList *head, bool (*test)(const void *val)) { + struct SList *f = slist_find(head, test); + if (f) + return f->val; + else + return NULL; +} + +struct SList *slist_find_equal(struct SList *head, bool (*predicate)(const void *val, const void *data), const void *data) { + struct SList *i; + + for (i = head; i; i = i->nex) { + if (predicate) { + if (predicate(i->val, data)) { + return i; + } + } else if (i->val == data) { + return i; + } + } + + return NULL; +} + +void *slist_find_equal_val(struct SList *head, bool (*predicate)(const void *val, const void *data), const void *data) { + struct SList *f = slist_find_equal(head, predicate, data); + if (f) + return f->val; + else + return NULL; +} + +bool slist_equal(struct SList *a, struct SList *b, bool (*equal)(const void *a, const void *b)) { + struct SList *ai, *bi; + + for (ai = a, bi = b; ai && bi; ai = ai->nex, bi = bi->nex) { + if (equal) { + if (!equal(ai->val, bi->val)) { + return false; + } + } else if (ai->val != bi->val) { + return false; + } + } + + if (ai || bi) { + return false; + } + + return true; +} + +size_t slist_length(struct SList *head) { + size_t length = 0; + + for (struct SList *i = head; i; i = i->nex) { + length++; + } + + return length; +} + +struct SList *slist_sort(struct SList *head, bool (*before)(const void *a, const void *b)) { + struct SList *sorted = NULL; + + if (!head || !before) { + return sorted; + } + + if (!head->nex) { + slist_append(&sorted, head->val); + return sorted; + } + + struct SList *sorting = slist_shallow_clone(head); + + struct SList *sorting_head = sorting; + struct SList **sorted_trail = &sorted; + + while (sorting != NULL) { + sorting_head = sorting; + sorted_trail = &sorted; + + sorting = sorting->nex; + + while (!(*sorted_trail == NULL || before(sorting_head->val, (*sorted_trail)->val))) { + sorted_trail = &(*sorted_trail)->nex; + } + + sorting_head->nex = *sorted_trail; + *sorted_trail = sorting_head; + } + + slist_free(&sorting); + return sorted; +} + +void slist_move(struct SList **to, struct SList **from, bool (*predicate)(const void *val, const void *data), const void *data) { + if (!to || !from || !predicate) + return; + + struct SList *f = *from; + while (f) { + struct SList *r = f; + void *val = f->val; + f = f->nex; + if (predicate(val, data)) { + slist_append(to, val); + slist_remove(from, &r); + } + } +} + +bool slist_predicate_strcmp(const void *val, const void *data) { + if (!val || !data) { + return false; + } + return strcmp(val, data) == 0; +} + diff --git a/lib/col/src/stable.c b/lib/col/src/stable.c new file mode 100644 index 00000000..6cdc852e --- /dev/null +++ b/lib/col/src/stable.c @@ -0,0 +1,246 @@ +#include +#include + +#include "stable.h" + +struct STable { + const char **keys; + const void **vals; + size_t capacity; + size_t grow; + size_t size; +}; + +struct STableIterP { + /* + * Public, removed const + */ + const char *key; + const void *val; + + /* + * Private + */ + const struct STable *tab; + const char **k; + const void **v; +}; + +// grow to capacity + grow +void grow_stable(struct STable *tab) { + + // grow new arrays + const char **new_keys = calloc(tab->capacity + tab->grow, sizeof(char*)); + const void **new_vals = calloc(tab->capacity + tab->grow, sizeof(void*)); + + // copy old arrays + memcpy(new_keys, tab->keys, tab->capacity * sizeof(char*)); + memcpy(new_vals, tab->vals, tab->capacity * sizeof(void*)); + + // free old arrays + free(tab->keys); + free(tab->vals); + + // lock in new + tab->keys = new_keys; + tab->vals = new_vals; + tab->capacity += tab->grow; +} + +const struct STable *stable_init(const size_t initial, const size_t grow) { + if (initial == 0 || grow == 0) + return NULL; + + struct STable *tab = calloc(1, sizeof(struct STable)); + tab->capacity = initial; + tab->grow = grow; + tab->keys = calloc(tab->capacity, sizeof(char*)); + tab->vals = calloc(tab->capacity, sizeof(void*)); + + return tab; +} + +void stable_free(const void* const cvtab) { + if (!cvtab) + return; + + struct STable *tab = (struct STable*)cvtab; + + for (const char **k = tab->keys; k < tab->keys + tab->capacity; k++) { + free((void*)*k); + } + free(tab->keys); + free(tab->vals); + + free(tab); +} + +void stable_free_vals(const struct STable* const tab, void (*free_val)(const void* const val)) { + if (!tab) + return; + + for (const void **v = tab->vals; v < tab->vals + tab->capacity; v++) { + if (*v) { + if (free_val) { + free_val(*v); + } else { + free((void*)*v); + } + } + } + + stable_free(tab); +} + +void stable_iter_free(const struct STableIter* const iter) { + if (!iter) + return; + + free((void*)iter); +} + +const void *stable_get(const struct STable* const tab, const char* const key) { + if (!tab) + return NULL; + + // loop over keys + const char **k; + const void **v; + for (k = tab->keys, v = tab->vals; + k < tab->keys + tab->size; + k++, v++) { + if (strcmp(*k, key) == 0) { + return *v; + } + } + + return NULL; +} + +const struct STableIter *stable_iter(const struct STable* const tab) { + if (!tab) + return NULL; + + // loop over keys and vals + const char **k; + const void **v; + for (k = tab->keys, v = tab->vals; + v < tab->vals + tab->size && k < tab->keys + tab->size; + k++, v++) { + if (*v) { + struct STableIterP *iterp = calloc(1, sizeof(struct STableIterP)); + + iterp->tab = tab; + iterp->key = *k; + iterp->val = *v; + iterp->k = k; + iterp->v = v; + + return (struct STableIter*)iterp; + } + } + + return NULL; +} + +const struct STableIter *stable_next(const struct STableIter* const iter) { + if (!iter) + return NULL; + + struct STableIterP *iterp = (struct STableIterP*)iter; + + if (!iterp || !iterp->tab) { + stable_iter_free(iter); + return NULL; + } + + // loop over keys and vals + while (++iterp->v < iterp->tab->vals + iterp->tab->size && + ++iterp->k < iterp->tab->keys + iterp->tab->size) { + if (*iterp->v) { + iterp->key = *(iterp->k); + iterp->val = *(iterp->v); + return iter; + } + } + + stable_iter_free(iter); + return NULL; +} + +size_t stable_size(const struct STable* const tab) { + if (!tab) + return 0; + + return tab->size; +} + +const void *stable_put(const struct STable* const ctab, const char* const key, const void* const val) { + if (!ctab || !key) + return NULL; + + struct STable *tab = (struct STable*)ctab; + + // loop over existing keys + const char **k; + const void **v; + for (k = tab->keys, v = tab->vals; k < tab->keys + tab->size; k++, v++) { + + // overwrite existing values + if (strcmp(*k, key) == 0) { + const void *prev = *v; + *v = val; + return prev; + } + } + + // grow for new entry + if (tab->size >= tab->capacity) { + grow_stable(tab); + k = &tab->keys[tab->size]; + v = &tab->vals[tab->size]; + } + + // new + *k = strdup(key); + *v = val; + tab->size++; + + return NULL; +} + +const void *stable_remove(const struct STable* const ctab, const char* const key) { + if (!ctab) + return NULL; + + struct STable *tab = (struct STable*)ctab; + + // loop over existing keys + const char **k; + const void **v; + for (k = tab->keys, v = tab->vals; k < tab->keys + tab->size; k++, v++) { + + if (strcmp(*k, key) == 0) { + free((void*)*k); + *k = NULL; + const void* prev = *v; + *v = NULL; + tab->size--; + + // shift down over removed + const char **mk; + const void **mv; + for (mk = k, mv = v; mk < tab->keys + tab->size; mk++, mv++) { + *mk = *(mk + 1); + *mv = *(mv + 1); + } + *mk = NULL; + *mv = NULL; + + return prev; + } + } + + return NULL; +} + diff --git a/tst/GNUmakefile b/tst/GNUmakefile index 3e542d0a..a2418ea2 100644 --- a/tst/GNUmakefile +++ b/tst/GNUmakefile @@ -8,8 +8,7 @@ LDLIBS += $(foreach p,$(PKGS_TST),$(shell pkg-config --libs $(p))) OBJS = tst/util.o \ $(patsubst %.c,%.o,$(wildcard tst/wrap-*.c)) \ $(filter-out src/main.o,$(SRC_O)) \ - $(PRO_O) \ - $(LIB_O) + $(PRO_O) WRAPS_COMMON = -Wl,$\ --wrap=log_set_threshold,$\ @@ -35,7 +34,7 @@ tst-cfg-file: WRAPS=,$\ --wrap=fd_wd_cfg_dir_create -$(TST_O): $(TST_H) $(SRC_O) $(LIB_O) config.mk GNUmakefile tst/GNUmakefile +$(TST_O): $(TST_H) $(SRC_O) config.mk GNUmakefile tst/GNUmakefile $(TST_E): $(TST_O) $(OBJS) $(CXX) -o $(@) tst/$(@).o $(OBJS) $(LDFLAGS) $(LDLIBS) $(WRAPS_COMMON)$(WRAPS)