aoc-2019-c

git clone https://git.sinitax.com/sinitax/aoc-2019-c
Log | Files | Refs | README | sfeed.txt

commit 57a44cbf548e67798425dd96367c9f5f53101bad
Author: Louis Burda <quent.burda@gmail.com>
Date:   Fri, 15 Mar 2024 22:54:09 +0100

Squashed 'src/lib/liblist/' content from commit fbebd71

git-subtree-dir: src/lib/liblist
git-subtree-split: fbebd71c0ee05f98a54ae7df7065985f58f3ebf6

Diffstat:
A.gitignore | 6++++++
ALICENSE | 21+++++++++++++++++++++
AMakefile | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild.jst.tmpl | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfigure | 3+++
Ainclude/list.h | 219+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aliblist.api | 23+++++++++++++++++++++++
Aliblist.lds | 25+++++++++++++++++++++++++
Asrc/list.c | 224+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
10 files changed, 685 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,6 @@ +compile_commands.json +build +build.jst +.cache +vgcore* +test diff --git a/LICENSE b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Louis Burda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile @@ -0,0 +1,50 @@ +PREFIX ?= /usr/local +LIBDIR ?= /lib +INCLDIR ?= /include + +CFLAGS = -I include -std=c99 +CFLAGS += -Wunused-function -Wunused-variable -Wno-prototype +CFLAGS += -Wconversion -Wsign-compare -Werror + +ifeq "$(DEBUG)" "1" +CFLAGS += -Og -g +else +CFLAGS += -O2 +endif + +ifeq "$(ASSERT_ARGS)" "1" +CFLAGS += -DLIBLIST_ASSERT_ARGS=1 +endif + +all: build/liblist.so build/liblist.a build/test + +clean: + rm -rf build + +cleanall: clean + +build: + mkdir build + +build/liblist.a: src/list.c include/list.h liblist.api | build + $(CC) -o build/tmp.o src/list.c $(CFLAGS) -r + objcopy --keep-global-symbols=liblist.api build/tmp.o build/fixed.o + ar rcs $@ build/fixed.o + +build/liblist.so: src/list.c include/list.h liblist.lds | build + $(CC) -o $@ src/list.c $(CFLAGS) -shared -Wl,-version-script liblist.lds + +build/test: src/test.c build/liblist.a | build + $(CC) -o $@ $^ -I include + +install: + install -m644 include/list.h -t "$(DESTDIR)$(PREFIX)$(INCLDIR)" + install -m755 build/liblist.a -t "$(DESTDIR)$(PREFIX)$(LIBDIR)" + install -m755 build/liblist.so -t "$(DESTDIR)$(PREFIX)$(LIBDIR)" + +uninstall: + rm -f "$(DESTDIR)$(PREFIX)$(INCLDIR)/list.h" + rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/liblist.a" + rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/liblist.so" + +.PHONY: all clean cleanall install uninstall diff --git a/build.jst.tmpl b/build.jst.tmpl @@ -0,0 +1,64 @@ +#default PREFIX /usr/local +#default INCLDIR /include +#default LIBDIR /lib +#default CC gcc + +#ifdef LIBLIST_DEBUG +#define DEBUG 1 +#endif + +#ifdef DEBUG +#define OPT_CFLAGS -Og -g +#else +#define OPT_CFLAGS -O2 +#endif + +cflags = -Wunused-function -Wunused-variable -Wconversion + -I include #{OPT_CFLAGS} #{EXTRA_CFLAGS} #{LIBLIST_EXTRA_CFLAGS} + +rule liba + #{CC} -o $out.tmp.o $in $cflags -r + objcopy --keep-global-symbols=liblist.api $out.tmp.o $out.fixed.o + ar rcs $out $out.fixed.o + rm $out.tmp.o $out.fixed.o + +rule libso + #{CC} -o $out $in $cflags -shared -Wl,-version-script liblist.lds + +rule cc + #{CC} -o $out $in $cflags + +rule mkdir + mkdir $out + +target build + mkdir + +target build/liblist.a + liba src/list.c | include/list.h build + +target build/liblist.so + libso src/list.c | include/list.h build + +target build/test + cc src/test.c build/liblist.a | build + +command clean + rm -rf build + +command cleanall + just clean + +command install + install -m755 build/liblist.a -t "#{DESTDIR}#{PREFIX}#{LIBDIR}" + install -m755 build/liblist.so -t "#{DESTDIR}#{PREFIX}#{LIBDIR}" + install -m644 include/list.h -t "#{DESTDIR}#{PREFIX}#{INCLDIR}" + +command uninstall + rm -f "#{DESTDIR}#{PREFIX}#{LIBDIR}/liblist.a" + rm -f "#{DESTDIR}#{PREFIX}#{LIBDIR}/liblist.so" + rm -f "#{DESTDIR}#{PREFIX}#{INCLDIR}/list.h" + +command all + just build/liblist.a build/liblist.so build/test + diff --git a/configure b/configure @@ -0,0 +1,3 @@ +#!/bin/sh + +tmpl "$@" build.jst.tmpl > build.jst diff --git a/include/list.h b/include/list.h @@ -0,0 +1,219 @@ +#pragma once + +#include <sys/types.h> +#include <stdbool.h> +#include <stddef.h> + +#define LIST_LINK_INIT ((struct list_link) { 0 }) + +#define LIST_OFFSET(type, member) ((size_t) &((type *)0)->member) +#define LIST_UPCAST(ptr, type, member) \ + ((type *)((char *)ptr - LIST_OFFSET(type, member))) + +#define LIST_INNER(link) ((link) != NULL && \ + (link)->prev != NULL && (link)->next != NULL) + +#define LIST_ITER(list, iter) (iter) = (list)->head.next; \ + (iter) != &(list)->tail; (iter) = (iter)->next +#define LIST_ITER_BWD(list, iter) (iter) = (list)->tail.prev; \ + (iter) != &(list)->head; (iter) = (iter)->prev + +#define LIST_ITER_ITEMS(list, item, type, member) \ + struct list_link *_iter = (list)->head.next; \ + _iter != &(list)->tail \ + && ((item) = LIST_UPCAST(_iter, type, member)); \ + _iter = _iter->next +#define LIST_ITER_ITEMS_BWD(list, item, type, member) \ + struct link_link *_iter = (list)->tail.prev; \ + _iter != &(list)->head \ + && ((item) = LIST_UPCAST(_iter, type, member)); \ + _iter = _iter->prev + +#define LIST_FRONT_ITEM(list, type, member) \ + ((type *) ({ void *p = list_front(list); \ + p ? LIST_UPCAST(p, type, member) : p; })) +#define LIST_BACK_ITEM(list, type, member) \ + ((type *) ({ void *p = list_back(list); \ + p ? LIST_UPCAST(p, type, member) : p; })) + +#define LIST_ITEM_AT(list, idx, type, member) \ + ((type *) ({ void *p = list_at(list, idx); \ + p ? LIST_UPCAST(p, type, member) : p; })) +#define LIST_ITEM_AT_BACK(list, idx, type, member) \ + ((type *) ({ void *p = list_at_back(list, idx); \ + p ? LIST_UPCAST(p, type, member) : p; })) + +#ifdef LIBLIST_ASSERT_ARGS +#define LIST_ABORT_ON_ARGS(cond) do { if (cond) abort(); } while (0) +#else +#define LIST_ABORT_ON_ARGS(cond) +#endif + +typedef void (*list_item_free_fn)(void *p); +typedef bool (*list_sort_order_fn)(const void *p1, const void *p2, void *u); + +struct list_link { + struct list_link *prev; + struct list_link *next; +}; + +struct list { + struct list_link head; + struct list_link tail; +}; + +void list_init(struct list *list); +void list_clear(struct list *list); +void list_free_items(struct list *list, + list_item_free_fn free_item, size_t offset); + +static inline struct list_link *list_front(const struct list *list); +static inline struct list_link *list_back(const struct list *list); + +static inline bool list_empty(const struct list *list); +size_t list_len(const struct list *list); +ssize_t list_index(const struct list *list, const struct list_link *link); + +struct list_link *list_at(struct list *list, size_t n); +struct list_link *list_at_back(struct list *list, size_t n); + +void list_insert_sorted(struct list *list, struct list_link *link, + bool reverse, list_sort_order_fn in_order, size_t offset, void *user); +void list_insert_sorted_bwd(struct list *list, struct list_link *link, + bool reverse, list_sort_order_fn in_order, size_t offset, void *user); +void list_insertion_sort(struct list *list, + bool reverse, list_sort_order_fn in_order, size_t offset, void *user); +static inline void list_insert_front(struct list *list, struct list_link *link); +static inline void list_insert_back(struct list *list, struct list_link *link); + +struct list_link *list_pop_front(struct list *list); +struct list_link *list_pop_back(struct list *list); + +static inline bool list_link_inuse(const struct list_link *link); +struct list_link *list_link_pop(struct list_link *link); + +struct list_link *list_iter_fwd(struct list_link *link, size_t n); +struct list_link *list_iter_bwd(struct list_link *link, size_t n); + +static inline void list_link_prepend(struct list_link *a, struct list_link *b); +static inline void list_link_append(struct list_link *a, struct list_link *b); + +static inline void list_link_attach_next(struct list_link *a, struct list_link *b); +static inline void list_link_attach_prev(struct list_link *a, struct list_link *b); + +static inline void list_link_detach_next(struct list_link *link); +static inline void list_link_detach_prev(struct list_link *link); + +static inline struct list_link * +list_front(const struct list *list) +{ + struct list_link *link; + + LIST_ABORT_ON_ARGS(!list); + + link = list->head.next; + + return link != &list->tail ? link : NULL; +} + +static inline struct list_link * +list_back(const struct list *list) +{ + struct list_link *link; + + LIST_ABORT_ON_ARGS(!list); + + link = list->tail.prev; + + return link != &list->head ? link : NULL; +} + +static inline bool +list_empty(const struct list *list) +{ + LIST_ABORT_ON_ARGS(!list); + + return list->head.next == &list->tail; +} + +static inline bool +list_link_inuse(const struct list_link *link) +{ + LIST_ABORT_ON_ARGS(!link); + + return link->prev && link->next; +} + +static inline void +list_insert_front(struct list *list, struct list_link *link) +{ + LIST_ABORT_ON_ARGS(!list); + + list_link_append(&list->head, link); +} + +static inline void +list_insert_back(struct list *list, struct list_link *link) +{ + LIST_ABORT_ON_ARGS(!list); + + list_link_prepend(&list->tail, link); +} + +/* attach b before a: b -> a */ +static inline void +list_link_prepend(struct list_link *a, struct list_link *b) +{ + list_link_attach_prev(a, b); +} + +/* attach b after a: a -> b */ +static inline void +list_link_append(struct list_link *a, struct list_link *b) +{ + list_link_attach_next(a, b); +} + +/* attach b before a: b -> a */ +static inline void +list_link_attach_prev(struct list_link *a, struct list_link *b) +{ + LIST_ABORT_ON_ARGS(!a || !b); + + b->prev = a->prev; + b->next = a; + + if (b->prev) b->prev->next = b; + a->prev = b; +} + +/* attach b after a: a -> b */ +static inline void +list_link_attach_next(struct list_link *a, struct list_link *b) +{ + LIST_ABORT_ON_ARGS(!a || !b); + + b->next = a->next; + b->prev = a; + + if (b->next) b->next->prev = b; + a->next = b; +} + +static inline void +list_link_detach_next(struct list_link *link) +{ + LIST_ABORT_ON_ARGS(!link); + + if (link->next) link->next->prev = NULL; + link->next = NULL; +} + +static inline void +list_link_detach_prev(struct list_link *link) +{ + LIST_ABORT_ON_ARGS(!link); + + if (link->prev) link->prev->next = NULL; + link->prev = NULL; +} diff --git a/liblist.api b/liblist.api @@ -0,0 +1,23 @@ +list_init +list_clear +list_free_items + +list_len +list_index + +list_insert_sorted +list_insert_sorted_bwd +list_insertion_sort + +list_at +list_at_back + +list_pop_front +list_pop_back + +list_link_iter_fwd +list_link_iter_bwd +list_link_pop + +list_link_prepend +list_link_append diff --git a/liblist.lds b/liblist.lds @@ -0,0 +1,25 @@ +LIBLIST_1.2 { + list_init; + list_clear; + list_free_items; + + list_len; + list_index; + + list_insert_sorted; + list_insert_sorted_bwd; + list_insertion_sort; + + list_at; + list_at_back; + + list_pop_front; + list_pop_back; + + list_link_iter_fwd; + list_link_iter_bwd; + list_link_pop; + + list_link_prepend; + list_link_append; +}; diff --git a/src/list.c b/src/list.c @@ -0,0 +1,224 @@ +#include "list.h" + +void +list_init(struct list *list) +{ + LIST_ABORT_ON_ARGS(!list); + + list->head.prev = NULL; + list->head.next = &list->tail; + list->tail.prev = &list->head; + list->tail.next = NULL; +} + +void +list_clear(struct list *list) +{ + LIST_ABORT_ON_ARGS(!list); + + while (!list_empty(list)) + list_pop_back(list); +} + +void +list_free_items(struct list *list, list_item_free_fn free_item, size_t offset) +{ + struct list_link *item; + + LIST_ABORT_ON_ARGS(!list || !free_item); + + while (!list_empty(list)) { + item = list_link_pop(list->head.next); + free_item(((void *) item) - offset); + } +} + +size_t +list_len(const struct list *list) +{ + const struct list_link *link; + size_t len; + + LIST_ABORT_ON_ARGS(!list); + + len = 0; + for (LIST_ITER(list, link)) + len += 1; + + return len; +} + +ssize_t +list_index(const struct list *list, const struct list_link *target) +{ + struct list_link *link; + ssize_t index; + + LIST_ABORT_ON_ARGS(!list || !target); + + index = 0; + for (LIST_ITER(list, link)) { + if (link == target) + return index; + index++; + } + + return -1; +} + +struct list_link * +list_at(struct list *list, size_t n) +{ + struct list_link *link; + + LIST_ABORT_ON_ARGS(!list); + + link = list_iter_fwd(list->head.next, n); + + return LIST_INNER(link) ? link : NULL; +} + +struct list_link * +list_at_back(struct list *list, size_t n) +{ + struct list_link *link; + + LIST_ABORT_ON_ARGS(!list); + + link = list_iter_bwd(&list->tail, n); + + return LIST_INNER(link) ? link : NULL; +} + +void +list_insert_sorted(struct list *list, struct list_link *insert, + bool reverse, list_sort_order_fn in_order, size_t offset, void *user) +{ + struct list_link *link; + void *link_item, *insert_item; + + LIST_ABORT_ON_ARGS(!list || !insert || !in_order); + + insert_item = ((void *) insert) - offset; + for (LIST_ITER(list, link)) { + link_item = ((void *) link) - offset; + if (in_order(insert_item, link_item, user) == !reverse) { + list_link_prepend(link, insert); + return; + } + } + + list_insert_back(list, insert); +} + +void +list_insert_sorted_bwd(struct list *list, struct list_link *insert, + bool reverse, list_sort_order_fn in_order, size_t offset, void *user) +{ + struct list_link *link; + void *link_item, *insert_item; + + LIST_ABORT_ON_ARGS(!list || !insert || !in_order); + + insert_item = ((void *) insert) - offset; + for (LIST_ITER_BWD(list, link)) { + link_item = ((void *) link) - offset; + if (in_order(link_item, insert_item, user) == !reverse) { + list_link_append(link, insert); + return; + } + } + + list_insert_front(list, insert); +} + +void +list_insertion_sort(struct list *list, bool reverse, + list_sort_order_fn in_order, size_t offset, void *user) +{ + struct list_link *link, *cmp, *next; + void *link_item, *cmp_item; + + LIST_ABORT_ON_ARGS(!list || !in_order); + + link = list->head.next; + while (LIST_INNER(link)) { + next = link->next; + cmp = link->prev; + link_item = ((void *) link) - offset; + while (LIST_INNER(cmp)) { + cmp_item = ((void *) cmp) - offset; + if (in_order(cmp_item, link_item, user) == !reverse) + break; + cmp = cmp->prev; + } + if (cmp != link->prev) + list_link_append(cmp, list_link_pop(link)); + link = next; + } +} + +struct list_link * +list_pop_front(struct list *list) +{ + LIST_ABORT_ON_ARGS(!list); + + if (list_empty(list)) return NULL; + + return list_link_pop(list->head.next); +} + +struct list_link * +list_pop_back(struct list *list) +{ + LIST_ABORT_ON_ARGS(!list); + + if (list_empty(list)) return NULL; + + return list_link_pop(list->tail.prev); +} + +struct list_link * +list_link_pop(struct list_link *link) +{ + LIST_ABORT_ON_ARGS(!link); + + if (link->prev) + link->prev->next = link->next; + if (link->next) + link->next->prev = link->prev; + *link = LIST_LINK_INIT; + + return link; +} + +struct list_link * +list_iter_fwd(struct list_link *link, size_t n) +{ + size_t i; + + LIST_ABORT_ON_ARGS(!link); + + for (i = 0; i < n; i++) { + if (!link) return NULL; + link = link->next; + } + + return link; +} + +struct list_link * +list_iter_bwd(struct list_link *link, size_t n) +{ + size_t i; + + LIST_ABORT_ON_ARGS(!link); + + for (i = 0; i < n; i++) { + if (!link) return NULL; + link = link->prev; + } + + return link; +} + diff --git a/src/test.c b/src/test.c @@ -0,0 +1,50 @@ +#include "list.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +struct arg { + const char *str; + + struct list_link link; +}; + +bool +test_sort(const void *p1, const void *p2, void *u) +{ + const struct arg *a1 = p1, *a2 = p2; + + return strcmp(a1->str, a2->str) <= 0; +} + +int +main(int argc, const char **argv) +{ + struct list list; + struct arg *item; + const char **arg; + + list_init(&list); + + if (argc < 3) { + fprintf(stderr, "Usage: test REVERSE [STR]..\n"); + return 1; + } + + for (arg = argv + 2; *arg; arg++) { + item = malloc(sizeof(struct arg)); + if (!item) return 0; + item->str = *arg; + item->link = LIST_LINK_INIT; + list_insert_back(&list, &item->link); + } + + list_insertion_sort(&list, atoi(argv[1]), test_sort, + LIST_OFFSET(struct arg, link), NULL); + + for (LIST_ITER_ITEMS(&list, item, struct arg, link)) + printf("%s\n", item->str); + + list_free_items(&list, free, LIST_OFFSET(struct arg, link)); +}