commit 5588ce9f309f4a64f649b189692cb17a076573d0
parent ba06b0ed0aed7bc7c2e92d6a9683a37706a91795
Author: Louis Burda <quent.burda@gmail.com>
Date: Fri, 17 Mar 2023 16:23:09 +0100
Restructure repo and add libraries
Diffstat:
141 files changed, 3305 insertions(+), 2267 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,4 +1,5 @@
compile_commands.json
+.aoc-headers
main
.cache
build
diff --git a/.gitmodules b/.gitmodules
@@ -1,3 +1,11 @@
-[submodule "aoc-helper"]
- path = helper
- url = git@github.com:Sinitax/aoc-helper
+[submodule "helper"]
+ url = git@sinitax.com:sinitax/aoc-helper
+[submodule "src/lib/libdvec"]
+ path = src/lib/libdvec
+ url = git@sinitax.com:snx/libdvec
+[submodule "src/lib/libhashmap"]
+ path = src/lib/libhashmap
+ url = git@sinitax.com:snx/libhashmap
+[submodule "src/lib/libmaxint"]
+ path = src/lib/libmaxint
+ url = git@sinitax.com:snx/libmaxint
diff --git a/01/info.mk b/01/info.mk
@@ -0,0 +1,2 @@
+01_SRC = 01/main.c common/aoc.c common/main.c common/util.c
+01_HDR = common/aoc.h common/util.h
diff --git a/src/01/input b/01/input
diff --git a/01/main.c b/01/main.c
@@ -0,0 +1,50 @@
+#include "aoc.h"
+#include "util.h"
+
+#include <err.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+void
+part1(void)
+{
+ const char *pos, *end;
+ char buf[256];
+ int64_t fuel, ans;
+
+ pos = aoc.input;
+ end = aoc.input + aoc.input_size;
+
+ ans = 0;
+ while (readtok(buf, sizeof(buf), '\n', &pos, end)) {
+ fuel = strtoull(buf, NULL, 0);
+ ans += fuel / 3 - 2;
+ }
+
+ aoc.answer = aprintf("%llu", ans);
+ aoc.solution = "3286680";
+}
+
+void
+part2(void)
+{
+ const char *pos, *end;
+ char buf[256];
+ int64_t fuel, ans;
+
+ pos = aoc.input;
+ end = aoc.input + aoc.input_size;
+
+ ans = 0;
+ while (readtok(buf, sizeof(buf), '\n', &pos, end)) {
+ fuel = strtoull(buf, NULL, 0);
+ while ((fuel = fuel / 3 - 2) > 0) {
+ ans += fuel;
+ }
+ }
+
+ aoc.answer = aprintf("%llu", ans);
+ aoc.solution = "4927158";
+}
diff --git a/src/01/part1 b/01/part1
diff --git a/src/01/part2 b/01/part2
diff --git a/02/info.mk b/02/info.mk
@@ -0,0 +1,3 @@
+02_SRC = 02/main.c common/main.c common/aoc.c common/icc.c common/util.c
+02_SRC += lib/libdvec/build/libdvec.a
+02_HDR = common/aoc.h common/icc.h common/util.h
diff --git a/src/02/input b/02/input
diff --git a/02/main.c b/02/main.c
@@ -0,0 +1,81 @@
+#include "aoc.h"
+#include "icc.h"
+#include "util.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void
+part1(void)
+{
+ struct icc icc;
+ int res, rc;
+
+ icc_init(&icc);
+ icc_parse_inst(&icc, aoc.input, aoc.input_size);
+
+ icc_set_inst(&icc, 1, 12);
+ icc_set_inst(&icc, 2, 2);
+
+ while (icc.state != ICC_HALT) {
+ rc = icc_step_inst(&icc);
+ if (rc) die("icc step failed");
+ }
+
+ icc_get_inst(&icc, 0, &res);
+ aoc.answer = aprintf("%i", res);
+ aoc.solution = "5098658";
+
+ icc_deinit(&icc);
+}
+
+void
+part2(void)
+{
+ struct icc icc;
+ struct dvec inst;
+ int a, b, c;
+ int rc;
+
+ icc_init(&icc);
+ icc.abort_on_err = false;
+ icc_parse_inst(&icc, aoc.input, aoc.input_size);
+
+ dvec_init(&inst, sizeof(int), 0);
+ dvec_copy(&inst, &icc.instructions);
+ icc_debug_dump(&icc, &inst);
+
+ for (a = 0; a < 100; a++) {
+ for (b = 0; b < 100; b++) {
+ icc_reset(&icc, &inst);
+
+ icc_set_inst(&icc, 1, a);
+ icc_set_inst(&icc, 2, b);
+
+ aoc_debug("\nTrying a:%i b:%i\n\n", a, b);
+ while (icc.state != ICC_HALT) {
+ rc = icc_step_inst(&icc);
+ if (rc == ICC_OOB_WRITE) {
+ dvec_reserve(&icc.instructions, icc.write_addr + 1);
+ icc.instructions.len =
+ MAX(icc.instructions.len, icc.write_addr + 1);
+ } else if (rc != ICC_OK) {
+ break;
+ }
+ }
+
+ icc_debug_dump(&icc, &inst);
+
+ icc_get_inst(&icc, 0, &c);
+ if (c == 19690720)
+ goto exit;
+ }
+ }
+
+exit:
+ aoc.answer = aprintf("%02i%02i", a, b);
+ aoc.solution = "5064";
+
+ dvec_deinit(&inst);
+ icc_deinit(&icc);
+}
diff --git a/src/02/part1 b/02/part1
diff --git a/src/02/part2 b/02/part2
diff --git a/src/03/Makefile b/03/Makefile
diff --git a/src/03/input b/03/input
diff --git a/src/03/main.c b/03/main.c
diff --git a/src/03/part1 b/03/part1
diff --git a/src/03/part2 b/03/part2
diff --git a/src/03/test1 b/03/test1
diff --git a/src/03/test2 b/03/test2
diff --git a/src/04/Makefile b/04/Makefile
diff --git a/src/04/input b/04/input
diff --git a/src/04/main.c b/04/main.c
diff --git a/src/04/part1 b/04/part1
diff --git a/src/04/part2 b/04/part2
diff --git a/src/04/test.input b/04/test.input
diff --git a/src/05/Makefile b/05/Makefile
diff --git a/src/05/input b/05/input
diff --git a/src/05/main.c b/05/main.c
diff --git a/src/05/part1 b/05/part1
diff --git a/src/05/part2 b/05/part2
diff --git a/src/05/test2.input b/05/test2.input
diff --git a/src/06/Makefile b/06/Makefile
diff --git a/src/06/input b/06/input
diff --git a/src/06/main.c b/06/main.c
diff --git a/src/06/part1 b/06/part1
diff --git a/src/06/part2 b/06/part2
diff --git a/src/06/test.input b/06/test.input
diff --git a/src/06/test.input2 b/06/test.input2
diff --git a/src/07/Makefile b/07/Makefile
diff --git a/src/07/input b/07/input
diff --git a/src/07/main.c b/07/main.c
diff --git a/src/07/part1 b/07/part1
diff --git a/src/07/part2 b/07/part2
diff --git a/src/07/test.input b/07/test.input
diff --git a/src/07/test.input2 b/07/test.input2
diff --git a/src/07/test.input3 b/07/test.input3
diff --git a/src/08/Makefile b/08/Makefile
diff --git a/src/08/input b/08/input
diff --git a/src/08/main.c b/08/main.c
diff --git a/src/08/part1 b/08/part1
diff --git a/src/08/part2 b/08/part2
diff --git a/src/09/Makefile b/09/Makefile
diff --git a/src/09/input b/09/input
diff --git a/src/09/main.c b/09/main.c
diff --git a/src/09/part1 b/09/part1
diff --git a/src/09/part2 b/09/part2
diff --git a/src/10/Makefile b/10/Makefile
diff --git a/src/10/input b/10/input
diff --git a/src/10/main.c b/10/main.c
diff --git a/src/10/part1 b/10/part1
diff --git a/src/10/part2 b/10/part2
diff --git a/src/10/test.input b/10/test.input
diff --git a/src/11/Makefile b/11/Makefile
diff --git a/src/11/input b/11/input
diff --git a/src/11/main.c b/11/main.c
diff --git a/src/11/part1 b/11/part1
diff --git a/src/11/part2 b/11/part2
diff --git a/data/helper/template/Makefile b/12/Makefile
diff --git a/src/12/input b/12/input
diff --git a/src/12/main.c b/12/main.c
diff --git a/src/12/part1 b/12/part1
diff --git a/src/12/part2 b/12/part2
diff --git a/src/12/test.input b/12/test.input
diff --git a/src/12/test.input2 b/12/test.input2
diff --git a/13/Makefile b/13/Makefile
@@ -0,0 +1,15 @@
+CFLAGS = -g -I ../../libs/include -L ../../libs/build
+LDLIBS = -liccmp -laoc
+
+all: lib main
+
+clean:
+ rm -f main
+
+lib:
+ make -C ../../libs
+
+main: main.c ../../libs/build/*
+ $(CC) -o $@ $< $(CFLAGS) $(LDLIBS)
+
+.PHONY: all clean lib
diff --git a/src/13/input b/13/input
diff --git a/src/13/main.c b/13/main.c
diff --git a/src/13/part1 b/13/part1
diff --git a/src/13/part2 b/13/part2
diff --git a/Makefile b/Makefile
@@ -0,0 +1,41 @@
+CFLAGS = -I lib/libdvec/include -I lib/libhashmap/include
+CFLAGS += -I lib/libmaxint/include -I common -g
+
+DAYS = $(shell seq 1 24 | xargs printf "%02i\n")
+
+all::
+
+include */info.mk
+
+lib/libdvec/build/libdvec.a:
+ make -C lib/libdvec build/libdvec.a
+
+lib/libhashmap/build/libhashmap.a:
+ make -C lib/libhashmap build/libhashmap.a
+
+lib/libmaxint/build/libmaxint.a:
+ make -C lib/libmaxint build/libmaxint.a
+
+define make-day
+all:: $1/main
+run:: $1/run
+$1/main: $($(1)_SRC) $($(1)_HDR)
+ $(CC) -o $1/main $($(1)_SRC) $(CFLAGS) $($(1)_CFLAGS) \
+ $(LDFLAGS) $($(1)_LDFLAGS) $(LDLIBS) $($(1)_LDLIBS)
+$1/run: $1/main
+ @echo "== day $1 =="
+ @echo -en "\npart 1: " && cd $1 && time ./main 1
+ @echo -en "\npart 2: " && cd $1 && time ./main 2
+ @echo ""
+endef
+$(foreach day,$(DAYS),$(eval $(call make-day,$(day))))
+
+clean:
+ rm -f */main
+
+cleanall: clean
+ make -C lib/libdvec clean
+ make -C lib/libhashmap clean
+ make -C lib/libmaxint clean
+
+.PHONY: all clean cleanall
diff --git a/docs/README.md b/README.md
diff --git a/common/aoc.c b/common/aoc.c
@@ -0,0 +1,33 @@
+#include "aoc.h"
+#include "util.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+void
+aoc_check(const char *sol, const char *fmtstr, ...)
+{
+ char buf[256];
+ va_list ap;
+
+ va_start(ap, fmtstr);
+ vsnprintf(buf, 256, fmtstr, ap);
+ va_end(ap);
+
+ if (strcmp(sol, buf))
+ die("aoc: solution check failed");
+}
+
+void
+aoc_debug(const char *fmtstr, ...)
+{
+ va_list ap;
+
+ if (!aoc.debug) return;
+
+ va_start(ap, fmtstr);
+ vfprintf(stderr, fmtstr, ap);
+ va_end(ap);
+}
+
diff --git a/common/aoc.h b/common/aoc.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <stdlib.h>
+
+struct aoc {
+ int debug;
+ int part;
+
+ char *answer;
+ const char *solution;
+
+ const char *inputfile;
+ char *input;
+ size_t input_size;
+
+ const char **args;
+};
+
+extern struct aoc aoc;
+
+void aoc_check(const char *sol, const char *fmtstr, ...);
+void aoc_debug(const char *fmtstr, ...);
+
+void part1(void);
+void part2(void);
diff --git a/common/icc.c b/common/icc.c
@@ -0,0 +1,558 @@
+#include "icc.h"
+#include "aoc.h"
+#include "util.h"
+#include "dvec.h"
+#include <stdbool.h>
+
+const char *icc_err[] = {
+ [ICC_OK] = "ok",
+ [ICC_INV_INST] = "invalid instruction",
+ [ICC_OOB_WRITE] = "write addr oob",
+ [ICC_OOB_READ] = "read addr oob",
+};
+
+void
+icc_init(struct icc *icc)
+{
+ int rc;
+
+ icc->rip = 0;
+ icc->state = ICC_RUN;
+ icc->base = 0;
+
+ icc->in = 0;
+ icc->out = 0;
+
+ icc->read_addr = 0;
+ icc->write_addr = 0;
+ icc->abort_on_err = true;
+
+ icc->line_terminated = true;
+
+ rc = dvec_init(&icc->instructions, sizeof(int), 0);
+ if (rc) die("icc: dvec_init: failed");
+}
+
+void
+icc_deinit(struct icc *icc)
+{
+ dvec_deinit(&icc->instructions);
+}
+
+void
+icc_copy(struct icc *dst, struct icc *src)
+{
+ dst->rip = src->rip;
+ dst->in = src->in;
+ dst->out = src->out;
+ dst->state = src->state;
+ dst->base = src->base;
+ dvec_copy(&dst->instructions, &src->instructions);
+}
+
+void
+icc_reset(struct icc *icc, struct dvec *inst)
+{
+ int rc;
+
+ icc->state = ICC_RUN;
+ icc->rip = 0;
+ icc->base = 0;
+ if (inst) {
+ rc = dvec_copy(&icc->instructions, inst);
+ if (rc) die("icc: icc_reset: dvec_copy");
+ }
+}
+
+void
+icc_parse_inst(struct icc *icc, const char *str, size_t len)
+{
+ const char *pos, *end;
+ char buf[256];
+ size_t linelen;
+ int val, *slot;
+ int rc;
+
+ pos = str;
+ end = str + len;
+ while (readtok(buf, sizeof(buf), ',', &pos, end)) {
+ val = parsei64(buf);
+ slot = dvec_add_slot(&icc->instructions, &rc);
+ if (rc) die("icc: dvec_add_slot");
+ *slot = val;
+ }
+}
+
+const char*
+icc_param_str(struct icc *icc, int param)
+{
+ static char buf[32];
+ int val;
+
+ icc_get_inst(icc, icc->rip + param, &val);
+ snprintf(buf, sizeof(buf), "%i", val);
+
+ return buf;
+}
+
+void
+icc_debug_op_pre(struct icc *icc)
+{
+ int inst, rc;
+
+ if (!aoc.debug) return;
+
+ rc = icc_get_inst(icc, icc->rip, &inst);
+ if (!rc) fprintf(stderr, "%04li: (%05i) ", icc->rip, inst);
+ else fprintf(stderr, "%04li: (\?\?\?\?\?) ", icc->rip);
+
+ icc->line_terminated = false;
+}
+
+void
+icc_debug_op_main(struct icc *icc, const char *opstr, int n)
+{
+ int i, val, val2, inst;
+ int rc;
+
+ if (!aoc.debug) return;
+
+ rc = icc_get_inst(icc, icc->rip, &inst);
+ if (rc) die("icc: debug: oob rip");
+
+ fprintf(stderr, "%s ", opstr);
+ icc->line_terminated = false;
+
+ for (i = 1; i <= n; i++) {
+ if (i > 1) fprintf(stderr, ", ");
+ rc = icc_get_inst(icc, icc->rip + i, &val);
+ if (rc) die("icc: debug: oob param %i", i);
+ switch (icc_param_mode(inst, i)) {
+ case ICC_PARAM_IMM:
+ fprintf(stderr, "%i", val);
+ break;
+ case ICC_PARAM_POS:
+ rc = icc_get_inst(icc, val, &val2);
+ if (!rc) fprintf(stderr, "[%i]=%i", val, val2);
+ else fprintf(stderr, "[%i]=?", val);
+ break;
+ default:
+ die("icc: unknown parmeter mode");
+ }
+ }
+}
+
+void
+icc_debug_op_post(struct icc *icc, int dst)
+{
+ int val, inst;
+ int rc;
+
+ if (!aoc.debug) return;
+
+ rc = icc_get_inst(icc, icc->rip, &inst);
+ if (rc) die("icc: debug: oob rip");
+
+ fprintf(stderr, " -> ");
+
+ rc = icc_get_inst(icc, dst, &val);
+ if (!rc) fprintf(stderr, "[%i]=%i", dst, val);
+ else fprintf(stderr, "[%i]=?", dst);
+
+ fprintf(stderr, "\n");
+ icc->line_terminated = true;
+}
+
+void
+icc_debug_op(struct icc *icc, const char *opstr, int n)
+{
+ int inst;
+ int rc;
+
+ if (!aoc.debug) return;
+
+ icc_debug_op_main(icc, opstr, n);
+ fprintf(stderr, "\n");
+ icc->line_terminated = true;
+}
+
+int
+icc_inst_add(struct icc *icc)
+{
+ int a, b, dst;
+ int rc;
+
+ icc_debug_op_main(icc, "ADD", 3);
+
+ rc = icc_get_param(icc, 1, &a);
+ if (rc) return rc;
+ rc = icc_get_param(icc, 2, &b);
+ if (rc) return rc;
+ rc = icc_get_dest(icc, 3, &dst);
+ if (rc) return rc;
+
+ rc = icc_set_inst(icc, dst, a + b);
+ if (rc) return rc;
+
+ icc_debug_op_post(icc, dst);
+
+ icc->rip += 4;
+ icc->state = ICC_RUN;
+
+ return 0;
+}
+
+int
+icc_inst_mul(struct icc *icc)
+{
+ int a, b, dst;
+ int rc;
+
+ icc_debug_op_main(icc, "MUL", 3);
+
+ rc = icc_get_param(icc, 1, &a);
+ if (rc) return rc;
+ rc = icc_get_param(icc, 2, &b);
+ if (rc) return rc;
+ rc = icc_get_dest(icc, 3, &dst);
+ if (rc) return rc;
+
+ rc = icc_set_inst(icc, dst, a * b);
+ if (rc) return rc;
+
+ icc_debug_op_post(icc, dst);
+
+ icc->rip += 4;
+ icc->state = ICC_RUN;
+
+ return 0;
+}
+
+int
+icc_inst_store(struct icc *icc)
+{
+ int dst, rc;
+
+ if (icc->state != ICC_INPUT) {
+ icc_debug_op(icc, "INPUT", 0);
+ icc->state = ICC_INPUT;
+ } else {
+ icc_debug_op_main(icc, "STORE", 1);
+
+ rc = icc_get_dest(icc, 1, &dst);
+ if (rc) return rc;
+
+ rc = icc_set_inst(icc, dst, icc->in);
+ if (rc) return rc;
+
+ icc_debug_op_post(icc, dst);
+
+ icc->rip += 2;
+ icc->state = ICC_RUN;
+ }
+
+ return 0;
+}
+
+int
+icc_inst_load(struct icc *icc)
+{
+ int out, rc;
+
+ if (icc->state != ICC_OUTPUT) {
+ icc_debug_op(icc, "LOAD", 1);
+
+ rc = icc_get_param(icc, 1, &out);
+ if (rc) return rc;
+
+ icc->out = out;
+ icc->state = ICC_OUTPUT;
+
+ icc_debug_op(icc, "OUTPUT", 0);
+ } else {
+ icc->rip += 2;
+ icc->state = ICC_RUN;
+ }
+
+ return 0;
+}
+
+int
+icc_inst_jmp_true(struct icc *icc)
+{
+ int cond, addr;
+ int rc;
+
+ icc_debug_op(icc, "JMPT", 2);
+
+ rc = icc_get_param(icc, 1, &cond);
+ if (rc) return rc;
+ rc = icc_get_param(icc, 2, &addr);
+ if (rc) return rc;
+
+ if (cond) icc->rip = addr;
+ else icc->rip += 3;
+
+ icc->state = ICC_RUN;
+
+ return 0;
+}
+
+int
+icc_inst_jmp_false(struct icc *icc)
+{
+ int cond, addr;
+ int rc;
+
+ icc_debug_op(icc, "JMPF", 2);
+
+ rc = icc_get_param(icc, 1, &cond);
+ if (rc) return rc;
+ rc = icc_get_param(icc, 2, &addr);
+ if (rc) return rc;
+
+ if (!cond) icc->rip = addr;
+ else icc->rip += 3;
+
+ icc->state = ICC_RUN;
+
+ return 0;
+}
+
+int
+icc_inst_test_lt(struct icc *icc)
+{
+ int a, b, dst;
+ int rc;
+
+ icc_debug_op(icc, "TLT", 3);
+
+ rc = icc_get_param(icc, 1, &a);
+ if (rc) return rc;
+ rc = icc_get_param(icc, 2, &b);
+ if (rc) return rc;
+ rc = icc_get_dest(icc, 3, &dst);
+ if (rc) return rc;
+
+ rc = icc_set_inst(icc, dst, a < b);
+ if (rc) return rc;
+
+ icc->rip += 4;
+ icc->state = ICC_RUN;
+
+ return 0;
+}
+
+int
+icc_inst_test_eq(struct icc *icc)
+{
+ int a, b, dst;
+ int rc;
+
+ icc_debug_op(icc, "TEQ", 3);
+
+ rc = icc_get_param(icc, 1, &a);
+ if (rc) return rc;
+ rc = icc_get_param(icc, 2, &b);
+ if (rc) return rc;
+ rc = icc_get_dest(icc, 3, &dst);
+ if (rc) return rc;
+
+ rc = icc_set_inst(icc, dst, a == b);
+ if (rc) return rc;
+
+ icc->rip += 4;
+ icc->state = ICC_RUN;
+
+ return 0;
+}
+
+int
+icc_inst_base(struct icc *icc)
+{
+ int off, rc;
+
+ icc_debug_op(icc, "BASE", 1);
+
+ rc = icc_get_param(icc, 1, &off);
+ if (rc) return rc;
+
+ icc->base += off;
+ icc->rip += 2;
+ icc->state = ICC_RUN;
+
+ return 0;
+}
+
+int
+icc_inst_halt(struct icc *icc)
+{
+ icc_debug_op(icc, "HALT", 0);
+
+ icc->state = ICC_HALT;
+
+ return 0;
+}
+
+int
+icc_step_inst(struct icc *icc)
+{
+ int inst, rc;
+
+ icc_debug_op_pre(icc);
+
+ rc = icc_get_inst(icc, icc->rip, &inst);
+ if (rc) return rc;
+
+ switch (inst % 100) {
+ case ICC_INST_ADD:
+ rc = icc_inst_add(icc);
+ break;
+ case ICC_INST_MULT:
+ rc = icc_inst_mul(icc);
+ break;
+ case ICC_INST_STORE:
+ rc = icc_inst_store(icc);
+ break;
+ case ICC_INST_LOAD:
+ rc = icc_inst_load(icc);
+ break;
+ case ICC_INST_JMPT:
+ rc = icc_inst_jmp_true(icc);
+ break;
+ case ICC_INST_JMPF:
+ rc = icc_inst_jmp_false(icc);
+ break;
+ case ICC_INST_TLT:
+ rc = icc_inst_test_lt(icc);
+ break;
+ case ICC_INST_TEQ:
+ rc = icc_inst_test_eq(icc);
+ break;
+ case ICC_INST_BASE:
+ rc = icc_inst_base(icc);
+ break;
+ case ICC_INST_HALT:
+ rc = icc_inst_halt(icc);
+ break;
+ default:
+ rc = ICC_INV_INST;
+ break;
+ }
+
+ if (aoc.debug) {
+ if (!icc->line_terminated) {
+ fprintf(stderr, "\n");
+ icc->line_terminated = true;
+ }
+ if (rc != ICC_OK)
+ fprintf(stderr, " -- error: %s --\n", icc_err[rc]);
+ }
+
+ return rc;
+}
+
+int
+icc_set_inst(struct icc *icc, size_t addr, int val)
+{
+ int *slot;
+
+ if (addr >= icc->instructions.len) {
+ icc->write_addr = addr;
+ if (icc->abort_on_err)
+ die("icc: oob write");
+ return ICC_OOB_WRITE;
+ }
+
+ slot = dvec_at(&icc->instructions, addr);
+ *slot = val;
+
+ return 0;
+}
+
+int
+icc_get_inst(struct icc *icc, size_t addr, int *out)
+{
+ if (addr >= icc->instructions.len) {
+ icc->read_addr = addr;
+ if (icc->abort_on_err)
+ die("icc: oob read");
+ return ICC_OOB_READ;
+ }
+
+ *out = *(int*)dvec_at(&icc->instructions, addr);
+
+ return 0;
+}
+
+int
+icc_param_mode(int inst, int param)
+{
+ int div, i;
+
+ div = 100;
+ for (i = 1; i < param; i++) div *= 10;
+
+ return (inst / div) % 10 == 1 ? ICC_PARAM_IMM : ICC_PARAM_POS;
+}
+
+int
+icc_get_param(struct icc *icc, int param, int *out)
+{
+ int inst, val;
+ int rc;
+
+ rc = icc_get_inst(icc, icc->rip, &inst);
+ if (rc) return rc;
+ rc = icc_get_inst(icc, icc->rip + param, &val);
+ if (rc) return rc;
+
+ switch (icc_param_mode(inst, param)) {
+ case ICC_PARAM_IMM:
+ *out = val;
+ break;
+ case ICC_PARAM_POS:
+ rc = icc_get_inst(icc, val, out);
+ if (rc) return rc;
+ break;
+ case ICC_PARAM_REL:
+ *out = icc->base + val;
+ break;
+ default:
+ die("icc: unknown parmeter mode");
+ };
+
+ return 0;
+}
+
+int
+icc_get_dest(struct icc *icc, int param, int *out)
+{
+ return icc_get_inst(icc, icc->rip + param, out);
+}
+
+void
+icc_debug_dump(struct icc *icc, struct dvec *inst)
+{
+ int *rip;
+ size_t i;
+
+ if (!aoc.debug) return;
+
+ rip = icc->instructions.data;
+ for (i = 0; i < icc->instructions.len; i++, rip++) {
+ if (i % 8 == 0)
+ fprintf(stderr, "%4u: ", (int) i);
+ if (inst != NULL && (i >= inst->len
+ || *(int *)dvec_at(inst, i) != *rip)) {
+ fprintf(stderr, "\x1b[1m%8i\x1b[0m ", *rip);
+ } else {
+ fprintf(stderr, "%8i ", *rip);
+ }
+ if ((i + 1) % 8 == 0)
+ fprintf(stderr, "\n");
+ }
+ if (i % 8 != 0)
+ fprintf(stderr, "\n");
+}
+
diff --git a/common/icc.h b/common/icc.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include "dvec.h"
+
+enum {
+ ICC_RUN,
+ ICC_INPUT,
+ ICC_OUTPUT,
+ ICC_HALT
+};
+
+enum {
+ ICC_OK,
+ ICC_INV_INST,
+ ICC_OOB_WRITE,
+ ICC_OOB_READ,
+};
+
+enum {
+ ICC_PARAM_IMM,
+ ICC_PARAM_POS,
+ ICC_PARAM_REL
+};
+
+enum {
+ ICC_INST_ADD = 1,
+ ICC_INST_MULT = 2,
+ ICC_INST_STORE = 3,
+ ICC_INST_LOAD = 4,
+ ICC_INST_JMPT = 5,
+ ICC_INST_JMPF = 6,
+ ICC_INST_TLT = 7,
+ ICC_INST_TEQ = 8,
+ ICC_INST_BASE = 9,
+
+ ICC_INST_HALT = 99
+};
+
+struct icc {
+ int state;
+ int in, out;
+
+ size_t read_addr;
+ size_t write_addr;
+ bool abort_on_err;
+
+ bool line_terminated;
+
+ size_t rip, base;
+ struct dvec instructions;
+};
+
+extern const char *icc_err[];
+
+void icc_init(struct icc *icc);
+void icc_deinit(struct icc *icc);
+void icc_copy(struct icc *dst, struct icc *src);
+void icc_reset(struct icc *icc, struct dvec *inst);
+
+void icc_parse_inst(struct icc *icc, const char *str, size_t len);
+int icc_step_inst(struct icc *icc);
+
+int icc_set_inst(struct icc *icc, size_t addr, int in);
+int icc_get_inst(struct icc *icc, size_t addr, int *out);
+
+int icc_param_mode(int inst, int param);
+int icc_get_param(struct icc *icc, int param, int *out);
+int icc_get_dest(struct icc *icc, int param, int *out);
+
+void icc_input_callback(struct icc *icc, int (*callback)(int));
+
+void icc_debug_dump(struct icc *icc, struct dvec *inst);
diff --git a/common/iccmp.c b/common/iccmp.c
@@ -0,0 +1,439 @@
+#include "iccmp.h"
+#include "aoc.h"
+
+int
+icc_init(struct icc *icc)
+{
+ icc->instp = 0;
+ icc->status = ICC_OK;
+ icc->base = MI_INIT;
+ icc->debug = aoc.debug;
+ mi_setv(&icc->base, 0, MI_POS);
+ icc->in = icc->out = MI_INIT;
+ icc->r1 = icc->r2 = icc->r3 = icc->r4 = MI_INIT;
+ return memvec_init(&icc->instructions, 0, sizeof(struct maxint));
+}
+
+void
+icc_free(struct icc *icc)
+{
+ struct maxint *mi;
+ int i;
+
+ mi_free(&icc->base);
+ mi_free(&icc->in);
+ mi_free(&icc->out);
+ mi_free(&icc->r1);
+ mi_free(&icc->r2);
+ mi_free(&icc->r3);
+ mi_free(&icc->r4);
+
+ for (i = 0; i < memvec_len(&icc->instructions); i++)
+ mi_free(memvec_get(&icc->instructions, i));
+ memvec_free(&icc->instructions);
+}
+
+void
+icc_copy(struct icc *dst, struct icc *src)
+{
+ dst->instp = src->instp;
+ dst->status = src->status;
+ dst->base = src->base;
+ dst->in = MI_INIT;
+ mi_set(&dst->in, &src->in);
+ dst->out = MI_INIT;
+ mi_set(&dst->out, &src->out);
+ memvec_copy(&dst->instructions, &src->instructions);
+}
+
+void *
+icc_inst_copy(struct icc *icc)
+{
+ return CHKP(memdup(icc->instructions.data, icc->instructions.len));
+}
+
+void
+icc_reset(struct icc *icc, void *instcopy)
+{
+ icc->status = ICC_OK;
+ icc->instp = 0;
+ mi_setv(&icc->base, 0, MI_POS);
+ mi_setv(&icc->in, 0, MI_POS);
+ mi_setv(&icc->out, 0, MI_POS);
+ if (instcopy)
+ memcpy(icc->instructions.data, instcopy, icc->instructions.len);
+}
+
+int
+icc_parse_inst(struct icc *icc, const char *str, size_t len)
+{
+ const char *line = str, *nline, *end = str + len;
+ const char *endptr = NULL;
+ struct maxint val;
+ size_t linelen;
+
+ do {
+ nline = ntoken(line, end, &linelen, ",\n");
+ val = MI_INIT;
+ mi_parse(&val, line, &endptr, "0123456789");
+ if (endptr && !memchr(",\n", *endptr, 3))
+ goto fail;
+ if (!memvec_add(&icc->instructions, &val))
+ goto fail;
+ line = nline;
+ } while (nline);
+
+ return OK;
+
+fail:
+ mi_free(&val);
+ return FAIL;
+}
+
+void
+icc_debug_op(struct icc *icc, const char *opstr, int n, int dst)
+{
+ inst_t inst;
+ char *str;
+ int i;
+
+ if (!icc->debug) return;
+
+ icc_get_inst(icc, icc->instp, &inst);
+
+ fprintf(stderr, "%04li: (%05lu) %s ", icc->instp, inst, opstr);
+
+ str = NULL;
+ for (i = 1; i <= n; i++) {
+ if (i > 1) fprintf(stderr, ", ");
+ icc_get_val(icc, icc->instp + i, &icc->r1);
+ switch (icc_param_mode(inst, i)) {
+ case ICC_PARAM_IMM:
+ str = mi_decstr(str, &icc->r1);
+ fprintf(stderr, "%s", str);
+ break;
+ case ICC_PARAM_POS:
+ str = mi_decstr(str, &icc->r1);
+ fprintf(stderr, "[%s]", str);
+ if (i != dst) {
+ icc_get_val(icc, mi_cast_ul(&icc->r1), &icc->r1);
+ str = mi_decstr(str, &icc->r1);
+ fprintf(stderr, "=%s", str);
+ }
+ break;
+ case ICC_PARAM_REL:
+ str = mi_decstr(str, &icc->r1);
+ fprintf(stderr, "[B%s%s=", *str == '-' ? "" : "+", str);
+ mi_add(&icc->r1, &icc->base);
+ str = mi_decstr(str, &icc->r1);
+ fprintf(stderr, "%s]", str);
+ if (i != dst) {
+ icc_get_val(icc, mi_cast_ul(&icc->r1), &icc->r1);
+ str = mi_decstr(str, &icc->r1);
+ fprintf(stderr, "=%s", str);
+ }
+ break;
+ default:
+ die("ICC: Unknown parmeter mode\n");
+ }
+ }
+ free(str);
+
+ fprintf(stderr, "\n");
+}
+
+void
+icc_inst_add(struct icc *icc)
+{
+ icc_debug_op(icc, "ADD", 3, 3);
+
+ icc_get_param(icc, 1, &icc->r1);
+ icc_get_param(icc, 2, &icc->r2);
+ icc_get_dest(icc, 3, &icc->r3);
+
+ mi_add(&icc->r1, &icc->r2);
+ icc_set_val(icc, mi_cast_ul(&icc->r3), &icc->r1);
+
+ icc->instp += 4;
+ icc->status = ICC_OK;
+}
+
+void
+icc_inst_mul(struct icc *icc)
+{
+ icc_debug_op(icc, "MUL", 3, 3);
+
+ icc_get_param(icc, 1, &icc->r1);
+ icc_get_param(icc, 2, &icc->r2);
+ icc_get_dest(icc, 3, &icc->r3);
+
+ mi_mul(&icc->r1, &icc->r2);
+ icc_set_val(icc, mi_cast_ul(&icc->r3), &icc->r1);
+
+ icc->instp += 4;
+ icc->status = ICC_OK;
+}
+
+void
+icc_inst_store(struct icc *icc)
+{
+ if (icc->status != ICC_INPUT) {
+ icc_debug_op(icc, "INPUT", 0, 0);
+ icc->status = ICC_INPUT;
+ } else {
+ icc_debug_op(icc, "STORE", 1, 1);
+ icc_get_dest(icc, 1, &icc->r1);
+ icc_set_val(icc, mi_cast_ul(&icc->r1), &icc->in);
+
+ icc->instp += 2;
+ icc->status = ICC_OK;
+ }
+}
+
+void
+icc_inst_load(struct icc *icc)
+{
+ if (icc->status != ICC_OUTPUT) {
+ icc_debug_op(icc, "LOAD", 1, 0);
+ icc_get_param(icc, 1, &icc->out);
+
+ icc->status = ICC_OUTPUT;
+ icc_debug_op(icc, "OUTPUT", 0, 0);
+ } else {
+ icc->instp += 2;
+ icc->status = ICC_OK;
+ }
+}
+
+void
+icc_inst_jmp_true(struct icc *icc)
+{
+ icc_debug_op(icc, "JMPT", 2, 0);
+
+ icc_get_param(icc, 1, &icc->r1);
+ icc_get_param(icc, 2, &icc->r2);
+
+ if (!mi_zero(&icc->r1)) icc->instp = mi_cast_ul(&icc->r2);
+ else icc->instp += 3;
+
+ icc->status = ICC_OK;}
+
+void
+icc_inst_jmp_false(struct icc *icc)
+{
+ icc_debug_op(icc, "JMPF", 2, 0);
+
+ icc_get_param(icc, 1, &icc->r1);
+ icc_get_param(icc, 2, &icc->r2);
+
+ if (mi_zero(&icc->r1)) icc->instp = mi_cast_ul(&icc->r2);
+ else icc->instp += 3;
+
+ icc->status = ICC_OK;
+}
+
+void
+icc_inst_test_lt(struct icc *icc)
+{
+ icc_debug_op(icc, "TLT", 3, 3);
+
+ icc_get_param(icc, 1, &icc->r1);
+ icc_get_param(icc, 2, &icc->r2);
+ icc_get_dest(icc, 3, &icc->r3);
+
+ mi_setv(&icc->r4, mi_cmp(&icc->r1, &icc->r2) < 0, MI_POS);
+ icc_set_val(icc, mi_cast_ul(&icc->r3), &icc->r4);
+
+ icc->instp += 4;
+ icc->status = ICC_OK;
+}
+
+void
+icc_inst_test_eq(struct icc *icc)
+{
+ icc_debug_op(icc, "TEQ", 3, 3);
+
+ icc_get_param(icc, 1, &icc->r1);
+ icc_get_param(icc, 2, &icc->r2);
+ icc_get_dest(icc, 3, &icc->r3);
+
+ mi_setv(&icc->r4, mi_cmp(&icc->r1, &icc->r2) == 0, MI_POS);
+ icc_set_val(icc, mi_cast_ul(&icc->r3), &icc->r4);
+
+ icc->instp += 4;
+ icc->status = ICC_OK;
+}
+
+void
+icc_inst_base(struct icc *icc)
+{
+ icc_debug_op(icc, "BASE", 1, 0);
+
+ icc_get_param(icc, 1, &icc->r1);
+ mi_add(&icc->base, &icc->r1);
+
+ icc->instp += 2;
+ icc->status = ICC_OK;
+}
+
+void
+icc_inst_halt(struct icc *icc)
+{
+ icc_debug_op(icc, "HALT", 0, 0);
+
+ icc->status = ICC_HALT;
+}
+
+void
+icc_step_inst(struct icc *icc)
+{
+ inst_t inst;
+
+ icc_get_inst(icc, icc->instp, &inst);
+ inst %= 100;
+
+ switch (inst) {
+ case ICC_INST_ADD:
+ icc_inst_add(icc);
+ break;
+ case ICC_INST_MULT:
+ icc_inst_mul(icc);
+ break;
+ case ICC_INST_STORE:
+ icc_inst_store(icc);
+ break;
+ case ICC_INST_LOAD:
+ icc_inst_load(icc);
+ break;
+ case ICC_INST_JMPT:
+ icc_inst_jmp_true(icc);
+ break;
+ case ICC_INST_JMPF:
+ icc_inst_jmp_false(icc);
+ break;
+ case ICC_INST_TLT:
+ icc_inst_test_lt(icc);
+ break;
+ case ICC_INST_TEQ:
+ icc_inst_test_eq(icc);
+ break;
+ case ICC_INST_BASE:
+ icc_inst_base(icc);
+ break;
+ case ICC_INST_HALT:
+ icc_inst_halt(icc);
+ break;
+ default:
+ die("ICC: Unknown instruction: '%i'\n", inst);
+ }
+}
+
+void
+icc_set_val(struct icc *icc, size_t addr, struct maxint *val)
+{
+ struct maxint *v, blank;
+ size_t i, len;
+
+ len = memvec_len(&icc->instructions);
+ if (addr >= len) {
+ blank = MI_INIT;
+ memvec_resize(&icc->instructions, addr + 1);
+ for (i = len; i <= addr; i++)
+ memvec_set(&icc->instructions, i, &blank);
+ }
+ v = memvec_get(&icc->instructions, addr);
+ mi_set(v, val);
+}
+
+void
+icc_get_val(struct icc *icc, size_t addr, struct maxint *out)
+{
+ struct maxint *src;
+
+ if (addr >= memvec_len(&icc->instructions)) {
+ mi_setv(out, 0, MI_POS);
+ } else {
+ src = memvec_get(&icc->instructions, addr);
+ mi_set(out, src);
+ }
+}
+
+void
+icc_get_inst(struct icc *icc, size_t addr, inst_t *out)
+{
+ struct maxint *src;
+
+ src = memvec_get(&icc->instructions, addr);
+ *out = mi_cast_ul(src);
+}
+
+int
+icc_param_mode(inst_t inst, int param)
+{
+ int div, i;
+
+ div = 100;
+ for (i = 1; i < param; i++) div *= 10;
+
+ switch ((inst / div) % 10) {
+ case 0:
+ return ICC_PARAM_POS;
+ case 1:
+ return ICC_PARAM_IMM;
+ case 2:
+ return ICC_PARAM_REL;
+ }
+
+ die("ICC: Invalid param mode %i\n");
+ return -1;
+}
+
+void
+icc_get_param(struct icc *icc, int param, struct maxint *out)
+{
+ inst_t inst;
+
+ icc_get_inst(icc, icc->instp, &inst);
+ switch (icc_param_mode(inst, param)) {
+ case ICC_PARAM_IMM:
+ icc_get_val(icc, icc->instp + param, out);
+ break;
+ case ICC_PARAM_POS:
+ icc_get_val(icc, icc->instp + param, out);
+ icc_get_val(icc, mi_cast_ul(out), out);
+ break;
+ case ICC_PARAM_REL:
+ icc_get_val(icc, icc->instp + param, out);
+ mi_add(out, &icc->base);
+ icc_get_val(icc, mi_cast_ul(out), out);
+ break;
+ default:
+ die("ICC: Invalid parmeter mode\n");
+ };
+}
+
+void
+icc_get_dest(struct icc *icc, int param, struct maxint *out)
+{
+ inst_t inst;
+
+ icc_get_inst(icc, icc->instp, &inst);
+ switch (icc_param_mode(inst, param)) {
+ case ICC_PARAM_POS:
+ icc_get_val(icc, icc->instp + param, out);
+ break;
+ case ICC_PARAM_REL:
+ icc_get_val(icc, icc->instp + param, out);
+ mi_add(out, &icc->base);
+ break;
+ default:
+ die("ICC: Invalid destination parmeter mode\n");
+ };
+}
+
+void
+icc_set_debug(struct icc *icc, int debug)
+{
+ icc->debug = debug;
+}
+
diff --git a/common/iccmp.h b/common/iccmp.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "memvec.h"
+#include "maxint.h"
+
+enum {
+ ICC_OK,
+ ICC_INPUT,
+ ICC_OUTPUT,
+ ICC_HALT
+};
+
+enum {
+ ICC_PARAM_IMM,
+ ICC_PARAM_POS,
+ ICC_PARAM_REL
+};
+
+enum {
+ ICC_INST_ADD = 1,
+ ICC_INST_MULT = 2,
+ ICC_INST_STORE = 3,
+ ICC_INST_LOAD = 4,
+ ICC_INST_JMPT = 5,
+ ICC_INST_JMPF = 6,
+ ICC_INST_TLT = 7,
+ ICC_INST_TEQ = 8,
+ ICC_INST_BASE = 9,
+
+ ICC_INST_HALT = 99
+};
+
+typedef uint64_t inst_t;
+
+struct icc {
+ int status, debug;
+ struct maxint in, out;
+ struct maxint base;
+
+ /* general purpose registers */
+ struct maxint r1, r2, r3, r4;
+
+ size_t instp;
+ struct memvec instructions;
+};
+
+int icc_init(struct icc *icc);
+void icc_free(struct icc *icc);
+void icc_copy(struct icc *dst, struct icc *src);
+
+void * icc_inst_copy(struct icc *icc);
+void icc_reset(struct icc *icc, void *instcopy);
+
+int icc_parse_inst(struct icc *icc, const char *str, size_t len);
+void icc_step_inst(struct icc *icc);
+
+void icc_set_val(struct icc *icc, size_t addr, struct maxint *in);
+void icc_get_val(struct icc *icc, size_t addr, struct maxint *out);
+void icc_get_inst(struct icc *icc, size_t addr, inst_t *out);
+
+int icc_param_mode(inst_t inst, int param);
+void icc_get_param(struct icc *icc, int param, struct maxint *out);
+void icc_get_dest(struct icc *icc, int param, struct maxint *out);
+
+void icc_set_debug(struct icc *icc, int debug);
diff --git a/common/main.c b/common/main.c
@@ -0,0 +1,59 @@
+#include "aoc.h"
+#include "util.h"
+#include <err.h>
+#include <stdio.h>
+
+struct aoc aoc;
+
+int
+main(int argc, const char **argv)
+{
+ const char *envvar;
+ FILE *f;
+
+ if (argc <= 1) {
+ fprintf(stderr, "Usage: main PART [ARG]..\n");
+ exit(0);
+ }
+
+ aoc.part = atoi(argv[1]);
+ aoc.args = &argv[2];
+
+ envvar = getenv("AOCDEBUG");
+ aoc.debug = envvar ? atoi(envvar) : 0;
+
+ /* parse user input */
+ aoc.inputfile = getenv("AOCINPUT");
+ if (!aoc.inputfile) aoc.inputfile = "input";
+ else aoc_debug("Using input file: '%s'\n", aoc.inputfile);
+
+ /* read input file */
+ if (!(f = fopen(aoc.inputfile, "r")))
+ err(1, "fopen %s", aoc.inputfile);
+ readall(f, (void**) &aoc.input, &aoc.input_size);
+ fclose(f);
+
+ /* add null terminator */
+ aoc.input = realloc(aoc.input, aoc.input_size + 1);
+ if (!aoc.input) err(1, "realloc");
+ aoc.input[aoc.input_size] = '\0';
+
+ /* call solution */
+ aoc.answer = NULL;
+ aoc.solution = NULL;
+ if (aoc.part == 1) part1();
+ else if (aoc.part == 2) part2();
+ else errx(1, "Invalid part number");
+
+ /* check answer if given */
+ if (aoc.answer) {
+ printf("%s\n", aoc.answer);
+ if (aoc.solution && strcmp(aoc.answer, aoc.solution))
+ errx(1, "Incorrect solution!");
+ else if (!aoc.solution)
+ errx(1, "Solution missing!");
+ }
+
+ free(aoc.answer);
+ free(aoc.input);
+}
diff --git a/common/util.c b/common/util.c
@@ -0,0 +1,105 @@
+#include "util.h"
+#include "aoc.h"
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdio.h>
+
+void
+die(const char *fmtstr, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmtstr);
+ fprintf(stderr, "\n");
+ vfprintf(stderr, fmtstr, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+
+ abort();
+}
+
+bool
+readtok(char *buf, size_t buflen, char sep, const char **pos, const char *end)
+{
+ const char *c;
+ size_t len;
+
+ if (*pos >= end)
+ return false;
+
+ len = 0;
+ for (c = *pos; c != end && *c != sep; c++) {
+ if (len == buflen) die("util: readline: no space");
+ buf[len++] = *c;
+ }
+
+ if (len == buflen)
+ die("util: readline: no space");
+ buf[len++] = '\0';
+ *pos = c + 1;
+
+ return true;
+}
+
+int64_t
+parsei64(const char *str)
+{
+ int64_t val;
+ char *end;
+
+ val = strtoll(str, &end, 0);
+ if (end && *end && !isspace(*end))
+ die("util: parsei64: invalid %s", str);
+
+ return val;
+}
+
+char *
+aprintf(const char *fmtstr, ...)
+{
+ va_list ap, cpy;
+ ssize_t nb;
+ char *str;
+
+ va_copy(cpy, ap);
+
+ va_start(cpy, fmtstr);
+ nb = vsnprintf(NULL, 0, fmtstr, cpy);
+ if (nb < 0) die("util: aprintf: invalid fmtstr: %s", fmtstr);
+ va_end(cpy);
+
+ str = malloc(nb + 1);
+ if (!str) die("util: aprintf: malloc %lu", nb + 1);
+
+ va_start(ap, fmtstr);
+ nb = vsnprintf(str, nb + 1, fmtstr, ap);
+ va_end(ap);
+
+ return str;
+}
+
+void *
+memdup(void *data, size_t size)
+{
+ void *new;
+
+ new = malloc(size);
+ if (!new) die("util: memdup: malloc %lu", size);
+ memcpy(new, data, size);
+ return new;
+}
+
+void
+readall(FILE *file, void **data, size_t *size)
+{
+ fseek(file, 0, SEEK_END);
+ *size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ *data = malloc(*size);
+ if (!*data) die("util: readall: malloc %lu", *size);
+
+ if (fread(*data, 1, *size, file) != *size)
+ die("util: readall: incomplete");
+}
diff --git a/common/util.h b/common/util.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ASSERT(expr) assert(expr, __FILE__, __LINE__, #expr)
+
+#define ABS(a) ((a) > 0 ? (a) : -(a))
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+#define XORSWAP(a, b) ((a) ^= (b) ^= (a))
+
+__attribute__((noreturn)) void die(const char *fmtstr, ...);
+
+bool readtok(char *buf, size_t buflen,
+ char sep, const char **pos, const char *end);
+int64_t parsei64(const char *str);
+
+char *aprintf(const char *fmtstr, ...);
+void *memdup(void *data, size_t size);
+
+void readall(FILE *f, void **data, size_t *read);
+
diff --git a/data/helper/config b/data/helper/config
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-# year you are solving problems for
-export AOCYEAR=2019
-
-# directory you want day directories to be prepared in (format: src/dayN/..)
-export SRCDIR="src"
-
-# specify what files to copy to your day directory on prepare
-export TEMPLATE_DIR="data/helper/template"
-export TEMPLATE_FILES="
-main.c:main.c
-Makefile:Makefile
-"
-
diff --git a/data/helper/init.sh b/data/helper/init.sh
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-REPOROOT=$(git rev-parse --show-toplevel)
-
-ln -sf "$REPOROOT/data/helper/config" "$REPOROOT/helper/data/config"
-
-for f in "$REPOROOT/data/helper/scripts"/*; do
- ln -sf "$f" "$REPOROOT/helper/scripts"
-done
diff --git a/data/helper/template/main.c b/data/helper/template/main.c
@@ -1,16 +0,0 @@
-#include "aoc.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-
-void
-part1(void)
-{
-
-}
-
-void
-part2(void)
-{
-
-}
diff --git a/helper b/helper
@@ -1 +0,0 @@
-Subproject commit 94a615b088590f4395caa932cc1870dc96f9283c
diff --git a/lib/libdvec/.gitignore b/lib/libdvec/.gitignore
@@ -0,0 +1,5 @@
+compile_commands.json
+build
+.cache
+vgcore*
+test
diff --git a/lib/libdvec/LICENSE b/lib/libdvec/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/lib/libdvec/Makefile b/lib/libdvec/Makefile
@@ -0,0 +1,41 @@
+PREFIX ?= /usr/local
+LIBDIR ?= /lib
+INCLDIR ?= /include
+
+CFLAGS = -I include -Wno-prototype -Wunused-function -Wunused-variable
+
+ifeq "$(DEBUG)" "1"
+CFLAGS += -g -DLIBDVEC_CHECK_ENABLE=1
+endif
+
+all: build/libdvec.so build/libdvec.a build/test
+
+clean:
+ rm -rf build
+
+build:
+ mkdir build
+
+build/libdvec.a: src/dvec.c include/dvec.h libdvec.api | build
+ $(CC) -o build/tmp.o src/dvec.c $(CFLAGS) -r
+ objcopy --keep-global-symbols=libdvec.api build/tmp.o build/fixed.o
+ ar rcs $@ build/fixed.o
+
+build/libdvec.so: src/dvec.c include/dvec.h libdvec.lds | build
+ $(CC) -o $@ src/dvec.c -fPIC $(CFLAGS) \
+ -shared -Wl,-version-script libdvec.lds
+
+build/test: src/test.c build/libdvec.a
+ $(CC) -o $@ $^ $(CFLAGS)
+
+install:
+ install -m644 include/dvec.h -t "$(DESTDIR)$(PREFIX)$(INCLDIR)"
+ install -m755 build/libdvec.so -t "$(DESTDIR)$(PREFIX)$(LIBDIR)"
+ install -m755 build/libdvec.a -t "$(DESTDIR)$(PREFIX)$(LIBDIR)"
+
+uninstall:
+ rm -f "$(DESTDIR)$(PREFIX)$(INCLDIR)/dvec.h"
+ rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/libdvec.so"
+ rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/libdvec.a"
+
+.PHONY: all clean install uninstall
diff --git a/lib/libdvec/include/dvec.h b/lib/libdvec/include/dvec.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct dvec {
+ size_t dsize;
+ size_t len, cap;
+
+ void *data;
+};
+
+int dvec_init(struct dvec *dvec, size_t dsize, size_t cap);
+void dvec_deinit(struct dvec *dvec);
+
+int dvec_alloc(struct dvec **dvec, size_t dsize, size_t cap);
+void dvec_free(struct dvec *dvec);
+
+int dvec_copy(struct dvec *dst, struct dvec *src);
+void dvec_swap(struct dvec *dst, struct dvec *src);
+
+void dvec_clear(struct dvec *dvec);
+int dvec_reserve(struct dvec *dvec, size_t cap);
+int dvec_shrink(struct dvec *dvec);
+
+int dvec_add(struct dvec *dvec, size_t index, size_t count);
+void dvec_remove(struct dvec *dvec, size_t index, size_t count);
+void dvec_replace(struct dvec *dvec, size_t index, const void *data, size_t count);
+
+bool dvec_iter_fwd(struct dvec *dvec, void **p);
+bool dvec_iter_bwd(struct dvec *dvec, void **p);
+
+static inline void *
+dvec_at(struct dvec *dvec, size_t index)
+{
+ return dvec->data + index * dvec->dsize;
+}
+
+static inline void *
+dvec_front(struct dvec *dvec)
+{
+ return dvec->data;
+}
+
+static inline void *
+dvec_back(struct dvec *dvec)
+{
+ return dvec->data + (dvec->len - 1) * dvec->dsize;
+}
+
+static inline bool
+dvec_empty(struct dvec *dvec)
+{
+ return !dvec->len;
+}
+
+static inline void *
+dvec_add_slots(struct dvec *dvec, int *rc, size_t count)
+{
+ *rc = dvec_add(dvec, dvec->len, count);
+ if (*rc) return NULL;
+
+ return dvec->data + (dvec->len - count) * dvec->dsize;
+}
+
+static inline void *
+dvec_add_slot(struct dvec *dvec, int *rc)
+{
+ return dvec_add_slots(dvec, rc, 1);
+}
+
+static inline void
+dvec_rm_slots(struct dvec *dvec, void *slot, size_t count)
+{
+ dvec_remove(dvec, (slot - dvec->data) / dvec->dsize, count);
+}
+
+static inline void
+dvec_rm_slot(struct dvec *dvec, void *slot)
+{
+ dvec_rm_slots(dvec, slot, 1);
+}
diff --git a/lib/libdvec/libdvec.api b/lib/libdvec/libdvec.api
@@ -0,0 +1,19 @@
+dvec_init
+dvec_deinit
+
+dvec_alloc
+dvec_free
+
+dvec_copy
+dvec_swap
+
+dvec_clear
+dvec_reserve
+dvec_shrink
+
+dvec_add
+dvec_remove
+dvec_replace
+
+dvec_iter_fwd
+dvec_iter_bwd
diff --git a/lib/libdvec/libdvec.lds b/lib/libdvec/libdvec.lds
@@ -0,0 +1,23 @@
+LIBDVEC_1.1 {
+ global:
+ dvec_init;
+ dvec_deinit;
+
+ dvec_alloc;
+ dvec_free;
+
+ dvec_copy;
+ dvec_swap;
+
+ dvec_clear;
+ dvec_reserve;
+ dvec_shrink;
+
+ dvec_add;
+ dvec_remove;
+ dvec_replace;
+
+ dvec_iter_fwd;
+ dvec_iter_bwd;
+ local: *;
+};
diff --git a/lib/libdvec/src/dvec.c b/lib/libdvec/src/dvec.c
@@ -0,0 +1,229 @@
+#include "dvec.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef LIBDVEC_CHECK_ENABLE
+#include <stdio.h>
+#define LIBDVEC_CHECK(x) libdvec_assert((x), __FILE__, __LINE__, #x)
+#else
+#define LIBDVEC_CHECK(x)
+#endif
+
+#ifdef LIBDVEC_CHECK_ENABLE
+static inline void
+libdvec_assert(int cond, const char *file, int line, const char *condstr)
+{
+ if (cond) return;
+
+ fprintf(stderr, "libdvec: Assertion failed at %s:%i (%s)\n",
+ file, line, condstr);
+ abort();
+}
+#endif
+
+int
+dvec_init(struct dvec *dvec, size_t dsize, size_t cap)
+{
+ LIBDVEC_CHECK(dvec != NULL && dsize > 0 && cap >= 0);
+
+ dvec->dsize = dsize;
+ dvec->cap = cap;
+
+ dvec->len = 0;
+ dvec->data = NULL;
+ if (dvec->cap) {
+ dvec->data = calloc(cap, dsize);
+ if (!dvec->data) return -errno;
+ }
+
+ return 0;
+}
+
+void
+dvec_deinit(struct dvec *dvec)
+{
+ LIBDVEC_CHECK(dvec != NULL);
+
+ free(dvec->data);
+}
+
+int
+dvec_alloc(struct dvec **dvec, size_t dsize, size_t cap)
+{
+ int rc;
+
+ LIBDVEC_CHECK(dvec != NULL && dsize > 0 && cap > 0);
+
+ *dvec = malloc(sizeof(struct dvec));
+ if (!*dvec) return -errno;
+
+ rc = dvec_init(*dvec, dsize, cap);
+ if (rc) {
+ free(dvec);
+ return rc;
+ }
+
+ return 0;
+}
+
+void
+dvec_free(struct dvec *dvec)
+{
+ LIBDVEC_CHECK(dvec != NULL);
+
+ dvec_deinit(dvec);
+ free(dvec);
+}
+
+int
+dvec_copy(struct dvec *dst, struct dvec *src)
+{
+ int rc;
+
+ rc = dvec_reserve(dst, src->len);
+ if (rc) return rc;
+
+ dst->dsize = src->dsize;
+ dst->len = src->len;
+ memcpy(dst->data, src->data, src->len * src->dsize);
+
+ return 0;
+}
+
+void
+dvec_swap(struct dvec *dst, struct dvec *src)
+{
+ struct dvec tmp;
+
+ memcpy(&tmp, dst, sizeof(struct dvec));
+ memcpy(dst, src, sizeof(struct dvec));
+ memcpy(src, &tmp, sizeof(struct dvec));
+}
+
+void
+dvec_clear(struct dvec *dvec)
+{
+ LIBDVEC_CHECK(dvec != NULL);
+
+ dvec->len = 0;
+}
+
+int
+dvec_reserve(struct dvec *dvec, size_t len)
+{
+ void *alloc;
+
+ if (len <= dvec->cap) return 0;
+
+ dvec->cap *= 2;
+ if (len > dvec->cap) dvec->cap = len;
+ alloc = realloc(dvec->data, dvec->cap * dvec->dsize);
+ if (!alloc) return -errno;
+ dvec->data = alloc;
+
+ return 0;
+}
+
+int
+dvec_shrink(struct dvec *dvec)
+{
+ void *alloc;
+
+ LIBDVEC_CHECK(dvec != NULL);
+
+ if (!dvec->len) {
+ dvec->cap = 0;
+ free(dvec->data);
+ return 0;
+ }
+
+ dvec->cap = dvec->len;
+ alloc = realloc(dvec->data, dvec->cap * dvec->dsize);
+ if (!alloc) return -errno;
+ dvec->data = alloc;
+
+ return 0;
+}
+
+int
+dvec_add(struct dvec *dvec, size_t index, size_t len)
+{
+ LIBDVEC_CHECK(dvec != NULL && index <= dvec->len);
+
+ dvec_reserve(dvec, dvec->len + len);
+
+ if (index < dvec->len) {
+ memmove(dvec->data + (index + len) * dvec->dsize,
+ dvec->data + index * dvec->dsize,
+ (dvec->len - index) * dvec->dsize);
+ }
+
+ dvec->len += len;
+
+ return 0;
+}
+
+void
+dvec_remove(struct dvec *dvec, size_t index, size_t count)
+{
+ LIBDVEC_CHECK(dvec != NULL && count >= dvec->len
+ && index + count <= dvec->len);
+
+ if (index + count < dvec->len) {
+ memmove(dvec->data + index * dvec->dsize,
+ dvec->data + (index + count) * dvec->dsize,
+ (dvec->len - (index + count)) * dvec->dsize);
+ }
+
+ dvec->len -= count;
+}
+
+void
+dvec_replace(struct dvec *dvec, size_t index, const void *data, size_t count)
+{
+ LIBDVEC_CHECK(dvec != NULL && data != NULL && index + count < dvec->len);
+
+ memcpy(dvec->data + index * dvec->dsize, data, count * dvec->dsize);
+}
+
+bool
+dvec_iter_fwd(struct dvec *dvec, void **p)
+{
+ void **iter;
+
+ LIBDVEC_CHECK(dvec != NULL && p != NULL);
+
+ if (!dvec->len) return false;
+
+ iter = p;
+ if (*iter == NULL) {
+ *iter = dvec->data;
+ } else {
+ *iter += dvec->dsize;
+ }
+
+ return *iter < dvec->data + dvec->dsize * dvec->len;
+}
+
+bool
+dvec_iter_bwd(struct dvec *dvec, void **p)
+{
+ void **iter;
+
+ LIBDVEC_CHECK(dvec != NULL && p != NULL);
+
+ if (!dvec->len) return false;
+
+ iter = p;
+ if (*iter == NULL) {
+ *iter = dvec->data + (dvec->len - 1) * dvec->dsize;
+ } else if (*iter > dvec->data) {
+ *iter -= dvec->dsize;
+ } else {
+ return false;
+ }
+
+ return true;
+}
diff --git a/lib/libdvec/src/test.c b/lib/libdvec/src/test.c
@@ -0,0 +1,32 @@
+#include "dvec.h"
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define LIBDVEC_ERR(rc) errx(1, "libdvec: %s", rc < 0 ? strerror(-rc) : "???")
+
+int
+main(int argc, const char **argv)
+{
+ struct dvec dvec;
+ int i, rc;
+ int *val;
+
+ rc = dvec_init(&dvec, sizeof(int), 10);
+ if (rc) LIBDVEC_ERR(rc);
+
+ for (i = 1; i < argc; i++) {
+ val = dvec_add_slot(&dvec, &rc);
+ if (rc) LIBDVEC_ERR(rc);
+ *val = atoi(argv[i]);
+ }
+
+ for (i = 0; i < dvec.len; i++)
+ printf("%i\n", *(int *)dvec_at(&dvec, i));
+
+ printf("dvec len: %lu\n", dvec.len);
+
+ dvec_deinit(&dvec);
+}
diff --git a/lib/libhashmap/.gitignore b/lib/libhashmap/.gitignore
@@ -0,0 +1,5 @@
+compile_commands.json
+build
+.cache
+vgcore*
+test
diff --git a/lib/libhashmap/LICENSE b/lib/libhashmap/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/lib/libhashmap/Makefile b/lib/libhashmap/Makefile
@@ -0,0 +1,42 @@
+PREFIX ?= /usr/local
+INCLDIR ?= /include
+LIBDIR ?= /lib
+
+CFLAGS = -I include -Wno-prototype -Wunused-function
+CFLAGS += -Wunused-variable -Wconversion
+
+ifeq "$(DEBUG)" "1"
+CFLAGS += -g -Dlibhashmap_CHECK_ENABLE=1
+endif
+
+all: build/libhashmap.so build/libhashmap.a build/test
+
+clean:
+ rm -rf build
+
+build:
+ mkdir build
+
+build/libhashmap.a: src/hashmap.c include/hashmap.h | build
+ $(CC) -o build/tmp.o src/hashmap.c $(CFLAGS) -r
+ objcopy --keep-global-symbols=libhashmap.api build/tmp.o build/fixed.o
+ $(AR) rcs $@ build/fixed.o
+
+build/libhashmap.so: src/hashmap.c include/hashmap.h | build
+ $(CC) -o $@ src/hashmap.c -fPIC $(CFLAGS) -shared \
+ -Wl,-version-script libhashmap.lds
+
+build/test: src/test.c build/libhashmap.a | build
+ $(CC) -o $@ $^ -I include -g
+
+install:
+ install -m 644 include/hashmap.h -t "$(DESTDIR)$(PREFIX)$(INCLDIR)"
+ install -m 755 build/libhashmap.a -t "$(DESTDIR)$(PREFIX)$(LIBDIR)"
+ install -m 755 build/libhashmap.so -t "$(DESTDIR)$(PREFIX)$(LIBDIR)"
+
+uninstall:
+ rm -f "$(DESTDIR)$(PREFIX)$(INCLDIR)/hashmap.h"
+ rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/libhashmap.a"
+ rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/libhashmap.so"
+
+.PHONY: all clean install uninstall
diff --git a/lib/libhashmap/include/hashmap.h b/lib/libhashmap/include/hashmap.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#define HASHMAP_ITER(map, iter) \
+ hashmap_iter_init(iter); hashmap_iter_next(map, iter);
+
+typedef uint32_t (*map_hash_func)(const void *data, size_t size);
+
+struct hashmap_link {
+ uint8_t *key;
+ size_t key_size;
+ uint8_t *value;
+ size_t value_size;
+ struct hashmap_link *next;
+};
+
+struct hashmap_iter {
+ struct hashmap_link *link;
+ size_t bucket;
+};
+
+struct hashmap {
+ map_hash_func hash;
+ struct hashmap_link **buckets;
+ size_t size;
+};
+
+int hashmap_init(struct hashmap *map, size_t size, map_hash_func hasher);
+void hashmap_deinit(struct hashmap *map);
+
+int hashmap_alloc(struct hashmap **map, size_t size, map_hash_func hasher);
+void hashmap_free(struct hashmap *map);
+
+void hashmap_clear(struct hashmap *map);
+
+struct hashmap_link *hashmap_get(struct hashmap *map,
+ const void *key, size_t size);
+struct hashmap_link *hashmap_pop(struct hashmap *map,
+ const void *key, size_t size);
+
+void hashmap_link_set(struct hashmap_link *link, void *key, size_t key_size,
+ void *value, size_t value_size);
+int hashmap_set(struct hashmap *map, void *key, size_t key_size,
+ void *value, size_t value_size);
+
+void hashmap_iter_init(struct hashmap_iter *iter);
+bool hashmap_iter_next(struct hashmap *map, struct hashmap_iter *iter);
+
+uint32_t hashmap_str_hasher(const void *data, size_t size);
+
diff --git a/lib/libhashmap/libhashmap.api b/lib/libhashmap/libhashmap.api
@@ -0,0 +1,15 @@
+hashmap_init
+hashmap_deinit
+
+hashmap_clear
+
+hashmap_get
+hashmap_pop
+
+hashmap_link_set
+hashmap_set
+
+hashmap_iter_init
+hashmap_iter_next
+
+hashmap_str_hasher
diff --git a/lib/libhashmap/libhashmap.lds b/lib/libhashmap/libhashmap.lds
@@ -0,0 +1,17 @@
+LIBHASHMAP_1.1 {
+ hashmap_init;
+ hashmap_deinit;
+
+ hashmap_clear;
+
+ hashmap_get;
+ hashmap_pop;
+
+ hashmap_link_set;
+ hashmap_set;
+
+ hashmap_iter_init;
+ hashmap_iter_next;
+
+ hashmap_str_hasher;
+};
diff --git a/lib/libhashmap/src/hashmap.c b/lib/libhashmap/src/hashmap.c
@@ -0,0 +1,264 @@
+#include "hashmap.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef LIBHASHMAP_CHECK_ENABLE
+#define LIBHASHMAP_CHECK(x) libhashmap_assert((x), __FILE__, __LINE__, #x)
+#else
+#define LIBHASHMAP_CHECK(x)
+#endif
+
+static struct hashmap_link **hashmap_get_linkp(struct hashmap *map,
+ const void *key, size_t size);
+static int hashmap_link_alloc(struct hashmap_link **link,
+ void *key, size_t key_size, void *value, size_t value_size);
+
+static inline void libhashmap_assert(int cond,
+ const char *file, int line, const char *condstr)
+{
+ if (cond) return;
+
+ fprintf(stderr, "libhashmap: Assertion failed at %s:%i (%s)\n",
+ file, line, condstr);
+ abort();
+}
+
+static inline size_t
+hashmap_key_bucket(struct hashmap *map, const void *key, size_t size)
+{
+ return map->hash(key, size) % map->size;
+}
+
+static inline bool
+hashmap_key_cmp(const void *a, size_t asize, const void *b, size_t bsize)
+{
+ return asize == bsize && !memcmp(a, b, asize);
+}
+
+struct hashmap_link **
+hashmap_get_linkp(struct hashmap *map, const void *key, size_t size)
+{
+ struct hashmap_link **iter, *link;
+
+ LIBHASHMAP_CHECK(map != NULL && key != NULL && size != 0);
+
+ iter = &map->buckets[hashmap_key_bucket(map, key, size)];
+ while (*iter != NULL) {
+ link = *iter;
+ if (hashmap_key_cmp(link->key, link->key_size, key, size))
+ return iter;
+ iter = &(*iter)->next;
+ }
+
+ return NULL;
+}
+
+int
+hashmap_link_alloc(struct hashmap_link **out, void *key, size_t key_size,
+ void *value, size_t value_size)
+{
+ struct hashmap_link *link;
+
+ LIBHASHMAP_CHECK(key != NULL && value != NULL);
+
+ link = malloc(sizeof(struct hashmap_link));
+ if (!link) return -errno;
+ link->key = key;
+ link->key_size = key_size;
+ link->value = value;
+ link->value_size = value_size;
+ link->next = NULL;
+ *out = link;
+
+ return 0;
+}
+
+int
+hashmap_init(struct hashmap *map, size_t size, map_hash_func hasher)
+{
+ LIBHASHMAP_CHECK(map != NULL && size != 0 && hasher != NULL);
+
+ map->buckets = calloc(size, sizeof(struct hashmap_link *));
+ if (!map->buckets) return -errno;
+ map->size = size;
+ map->hash = hasher;
+
+ return 0;
+}
+
+void
+hashmap_deinit(struct hashmap *map)
+{
+ LIBHASHMAP_CHECK(map != NULL);
+
+ hashmap_clear(map);
+ free(map->buckets);
+}
+
+int
+hashmap_alloc(struct hashmap **map, size_t size, map_hash_func hasher)
+{
+ int rc;
+
+ *map = malloc(sizeof(struct hashmap));
+ if (!*map) return -errno;
+
+ rc = hashmap_init(*map, size, hasher);
+ if (rc) {
+ free(*map);
+ return rc;
+ }
+
+ return 0;
+}
+
+void
+hashmap_free(struct hashmap *map)
+{
+ hashmap_deinit(map);
+ free(map);
+}
+
+void
+hashmap_clear(struct hashmap *map)
+{
+ struct hashmap_iter iter;
+ struct hashmap_link *prev;
+ size_t i;
+
+ LIBHASHMAP_CHECK(map != NULL);
+
+ prev = NULL;
+ for (HASHMAP_ITER(map, &iter)) {
+ free(iter.link->key);
+ free(iter.link->value);
+ free(prev);
+ prev = iter.link;
+ }
+ free(prev);
+
+ for (i = 0; i < map->size; i++)
+ map->buckets[i] = NULL;
+}
+
+struct hashmap_link *
+hashmap_get(struct hashmap *map, const void *key, size_t size)
+{
+ struct hashmap_link **iter;
+
+ LIBHASHMAP_CHECK(map != NULL);
+
+ iter = hashmap_get_linkp(map, key, size);
+
+ return iter ? *iter : NULL;
+}
+
+struct hashmap_link *
+hashmap_pop(struct hashmap *map, const void *key, size_t size)
+{
+ struct hashmap_link **iter;
+
+ LIBHASHMAP_CHECK(map != NULL);
+
+ iter = hashmap_get_linkp(map, key, size);
+ if (iter) {
+ *iter = (*iter)->next;
+ return *iter;
+ }
+
+ return NULL;
+}
+
+void
+hashmap_link_set(struct hashmap_link *link, void *key, size_t key_size,
+ void *value, size_t value_size)
+{
+ LIBHASHMAP_CHECK(link != NULL);
+
+ free(link->key);
+ link->key = key;
+ link->key_size = key_size;
+
+ free(link->value);
+ link->value = value;
+ link->value_size = value_size;
+}
+
+int
+hashmap_set(struct hashmap *map, void *key, size_t key_size,
+ void *value, size_t value_size)
+{
+ struct hashmap_link **iter;
+ int rc;
+
+ LIBHASHMAP_CHECK(map != NULL);
+
+ iter = hashmap_get_linkp(map, key, key_size);
+ if (iter == NULL) {
+ iter = &map->buckets[hashmap_key_bucket(map, key, key_size)];
+ while (*iter) iter = &((*iter)->next);
+ }
+
+ if (*iter) {
+ hashmap_link_set(*iter, key, key_size, value, value_size);
+ } else {
+ rc = hashmap_link_alloc(iter, key, key_size, value, value_size);
+ if (rc) return rc;
+ }
+
+ return 0;
+}
+
+void
+hashmap_iter_init(struct hashmap_iter *iter)
+{
+ LIBHASHMAP_CHECK(iter != NULL);
+
+ iter->bucket = 0;
+ iter->link = NULL;
+}
+
+bool
+hashmap_iter_next(struct hashmap *map, struct hashmap_iter *iter)
+{
+ size_t i;
+
+ LIBHASHMAP_CHECK(map != NULL && iter != NULL);
+
+ if (iter->link && iter->link->next) {
+ iter->link = iter->link->next;
+ return true;
+ }
+
+ i = iter->bucket + (iter->link ? 1 : 0);
+ for (; i < map->size; i++) {
+ if (map->buckets[i]) {
+ iter->bucket = i;
+ iter->link = map->buckets[i];
+ return true;
+ }
+ }
+
+ iter->link = NULL;
+
+ return false;
+}
+
+uint32_t
+hashmap_str_hasher(const void *data, size_t size)
+{
+ uint32_t hash;
+ size_t i;
+
+ LIBHASHMAP_CHECK(data != NULL && size > 0);
+
+ hash = 5381;
+ for (i = 0; i < size; i++)
+ hash = 33 * hash + ((uint8_t *) data)[i];
+
+ return hash;
+}
+
diff --git a/lib/libhashmap/src/test.c b/lib/libhashmap/src/test.c
@@ -0,0 +1,34 @@
+#include "hashmap.h"
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define LIBHASHMAP_ERR(rc) errx(1, "libhashmap: %s", rc < 0 ? strerror(-rc) : "???")
+
+int
+main(int argc, const char **argv)
+{
+ struct hashmap hashmap;
+ struct hashmap_iter iter;
+ void *key, *value;
+ int i, rc;
+
+ rc = hashmap_init(&hashmap, 10, hashmap_str_hasher);
+ if (rc) LIBHASHMAP_ERR(rc);
+
+ for (i = 1; i < argc; i++) {
+ key = strdup(argv[i]);
+ value = malloc(sizeof(int));
+ memcpy(value, &i, sizeof(int));
+ rc = hashmap_set(&hashmap, key, strlen(key) + 1,
+ value, sizeof(int));
+ if (rc) LIBHASHMAP_ERR(rc);
+ }
+
+ for (HASHMAP_ITER(&hashmap, &iter))
+ printf("%s: %i\n", iter.link->key, *(int*)iter.link->value);
+
+ hashmap_deinit(&hashmap);
+}
diff --git a/lib/libmaxint/.gitignore b/lib/libmaxint/.gitignore
@@ -0,0 +1,3 @@
+compile_commands.json
+build
+.cache
diff --git a/lib/libmaxint/Makefile b/lib/libmaxint/Makefile
@@ -0,0 +1,37 @@
+PREFIX ?= /usr/local
+LIBDIR ?= /lib
+
+CFLAGS = -Wunused-variable -Wunused-function -I include
+
+ifeq "$(DEBUG)" "1"
+CFLAGS += -g
+endif
+
+all: build/libmaxint.a build/libmaxint.so build/test
+
+clean:
+ rm -rf build
+
+build:
+ mkdir build
+
+build/libmaxint.a: src/maxint.c include/maxint.h libmaxint.api | build
+ $(CC) -o build/tmp.o $< $(CFLAGS) -r
+ objcopy --keep-global-symbols=libmaxint.api build/tmp.o build/fixed.o
+ ar rcs $@ build/fixed.o
+
+build/libmaxint.so: src/maxint.c include/maxint.h libmaxint.lds | build
+ $(CC) -o $@ $< -fPIC $(CFLAGS) -shared -Wl,-version-script libmaxint.lds
+
+build/test: src/test.c build/libmaxint.a | build
+ $(CC) -o $@ $^ -g -I include
+
+install:
+ install -m755 build/libmaxint.a -t "$(DESTDIR)$(PREFIX)$(LIBDIR)"
+ install -m755 build/libmaxint.so -t "$(DESTDIR)$(PREFIX)$(LIBDIR)"
+
+uninstall:
+ rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/libmaxint.a"
+ rm -f "$(DESTDIR)$(PREFIX)$(LIBDIR)/libmaxint.so"
+
+.PHONY: all clean install uninstall
diff --git a/lib/libmaxint/include/maxint.h b/lib/libmaxint/include/maxint.h
@@ -0,0 +1,108 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#define MI_NEG 1
+#define MI_POS 0
+
+#define MI_BIT(a,n) ((mi_ul) ((a) >> (n)) & 1)
+#define MI_BITA(a,m,n) ((mi_ul) ((a)[(n) / (m)] >> ((n) % (m))) & 1)
+
+#define MI_ULBYTES (sizeof(mi_ul))
+#define MI_ULBITS (8 * sizeof(mi_ul))
+
+#define MI_INIT ((struct maxint) { \
+ .data = NULL, \
+ .size = 0, \
+ .cap = 0, \
+ .sign = MI_POS, \
+})
+
+/* unsigned underlying type */
+typedef uint64_t mi_ul;
+
+enum {
+ MI_OK,
+ MI_ERR_OOM,
+ MI_ERR_INVAL,
+};
+
+struct maxint {
+ mi_ul *data;
+ size_t size, cap;
+ int sign;
+};
+
+/* void mi_init(struct maxint *m); */
+void mi_deinit(struct maxint *m);
+
+int mi_set(struct maxint *m1, const struct maxint *m2);
+int mi_setv(struct maxint *m, mi_ul v, int sign);
+int mi_setstr(struct maxint *m, const char *str,
+ const char **end, const char *alph);
+
+int mi_resize(struct maxint *m, size_t size);
+
+mi_ul mi_cast_ul(const struct maxint *m);
+
+bool mi_zero(const struct maxint *m);
+
+size_t mi_lastset(const struct maxint *m);
+
+ssize_t mi_str(const struct maxint *m, char *buf, size_t buflen,
+ mi_ul base, const char *alph);
+ssize_t mi_hex(const struct maxint *m, char *buf, size_t buflen, bool capital);
+ssize_t mi_dec(const struct maxint *m, char *buf, size_t buflen);
+ssize_t mi_bin(const struct maxint *m, char *buf, size_t buflen);
+
+/* mi_add: o1 = i1 + i2
+ * allowed: o1 == i1 */
+int mi_add(struct maxint *o1, const struct maxint *i1, const struct maxint *i2);
+
+/* mi_sub: o1 = i1 - i2
+ * allowed: o1 == i1 */
+int mi_sub(struct maxint *o1, const struct maxint *i1, const struct maxint *i2);
+
+/* mi_shl: o1 = i1 << shift
+ * allowed: o1 == i1 */
+int mi_shl(struct maxint *o1, const struct maxint *i1, size_t shift);
+
+/* mi_shr: o1 = i1 >> shift
+ * allowed: o1 == i1 */
+int mi_shr(struct maxint *o1, const struct maxint *i1, size_t shift);
+
+/* mi_mul: o1 = i1 * i2
+ * allowed: o1 == i1 */
+int mi_mul(struct maxint *o1, const struct maxint *i1, const struct maxint *i2);
+
+/* mi_div: o1 = i1 / i2, o2 = i1 % i2
+ * allowed: o1 == i1 */
+int mi_div(struct maxint *o1, struct maxint *o2,
+ const struct maxint *i1, const struct maxint *i2);
+
+/* mi_swap: o1 <=> o2 */
+void mi_swap(struct maxint *o1, struct maxint *o2);
+
+/* mi_gcm: o1 = gcm(i1, i2)
+ * allowed: o1 == i1 */
+int mi_gcm(struct maxint *o1, const struct maxint *i1, const struct maxint *i2);
+
+/* mi_lcm: o1 = lcm(i1, i2)
+ * allowed: o1 == i1 */
+int mi_lcm(struct maxint *o1, const struct maxint *i1, const struct maxint *i2);
+
+/* mi_cmp: (i1 < i2) => -1 | (i1 == i2) => 0 | (i1 < i2) => 1 */
+int mi_cmp(const struct maxint *i1, const struct maxint *i2);
+
+extern const struct maxint mi_one;
+
+static inline void
+mi_init(struct maxint *m)
+{
+ m->data = NULL;
+ m->size = 0;
+ m->cap = 0;
+ m->sign = MI_POS;
+}
diff --git a/lib/libmaxint/libmaxint.api b/lib/libmaxint/libmaxint.api
@@ -0,0 +1,26 @@
+mi_init
+mi_deinit
+mi_set
+mi_setv
+mi_setstr
+
+mi_resize
+mi_cast_ul
+mi_zero
+mi_lastset
+
+mi_str
+mi_hex
+mi_dec
+mi_bin
+
+mi_add
+mi_sub
+mi_shl
+mi_shr
+mi_mul
+mi_div
+mi_swap
+mi_gcm
+mi_lcm
+mi_cmp
diff --git a/lib/libmaxint/libmaxint.lds b/lib/libmaxint/libmaxint.lds
@@ -0,0 +1,30 @@
+LIBMAXINT_1.0 {
+ global:
+ mi_init;
+ mi_deinit;
+ mi_set;
+ mi_setv;
+ mi_setstr;
+
+ mi_resize;
+ mi_cast_ul;
+ mi_zero;
+ mi_lastset;
+
+ mi_str;
+ mi_hex;
+ mi_dec;
+ mi_bin;
+
+ mi_add;
+ mi_sub;
+ mi_shl;
+ mi_shr;
+ mi_mul;
+ mi_div;
+ mi_swap;
+ mi_gcm;
+ mi_lcm;
+ mi_cmp;
+ local: *;
+};
diff --git a/lib/libmaxint/src/maxint.c b/lib/libmaxint/src/maxint.c
@@ -0,0 +1,527 @@
+#include "maxint.h"
+
+#include <sys/types.h>
+#include <err.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define MAXINT_MAX_OVERCOMMIT 256
+
+#ifndef MAXINT_REALLOC
+#define MAXINT_REALLOC realloc
+#endif
+
+#ifndef MAXINT_FREE
+#define MAXINT_FREE free
+#endif
+
+#define MIN(a, b) ((b) > (a) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define DIVCEIL(a, b) ((a) / (b) + ((a) % (b) != 0))
+
+static mi_ul mi_one_v = 1;
+const struct maxint mi_one = {
+ .data = &mi_one_v,
+ .size = 1,
+ .cap = 1,
+ .sign = MI_POS
+};
+
+void
+mi_deinit(struct maxint *m)
+{
+ MAXINT_FREE(m->data);
+}
+
+int
+mi_set(struct maxint *m1, const struct maxint *m2)
+{
+ int rc;
+
+ rc = mi_resize(m1, m2->size);
+ if (rc) return rc;
+
+ memcpy(m1->data, m2->data, m2->size * MI_ULBYTES);
+ m1->sign = m2->sign;
+
+ return 0;
+}
+
+int
+mi_setv(struct maxint *m, mi_ul v, int sign)
+{
+ int rc;
+
+ rc = mi_resize(m, 1);
+ if (rc) return rc;
+
+ memcpy(m->data, &v, MI_ULBYTES);
+ m->sign = sign;
+
+ return 0;
+}
+
+int
+mi_setstr(struct maxint *m, const char *str, const char **end, const char *alph)
+{
+ const char *p, *cp;
+ struct maxint tmp, base;
+ int sign;
+ int rc;
+
+ sign = MI_POS;
+ if (*str == '-') {
+ sign = MI_NEG;
+ str++;
+ } else if (*str == '+') {
+ str++;
+ }
+
+ mi_init(&base);
+ rc = mi_setv(&base, strlen(alph), sign);
+ if (rc) return rc;
+
+ mi_init(&tmp);
+ rc = mi_setv(m, 0, MI_POS);
+ if (rc) return rc;
+
+ for (p = str; *p && (cp = strchr(alph, *p)); p++) {
+ rc = mi_mul(m, m, &base);
+ if (rc) return rc;
+
+ rc = mi_setv(&tmp, cp - alph, sign);
+ if (rc) return rc;
+
+ rc = mi_add(m, m, &tmp);
+ if (rc) return rc;
+ }
+
+ *end = p;
+
+ mi_deinit(&tmp);
+ mi_deinit(&base);
+
+ return 0;
+}
+
+int
+mi_resize(struct maxint *m, size_t size)
+{
+ void *alloc;
+
+ if (m->cap < size || m->cap > size + MAXINT_MAX_OVERCOMMIT) {
+ if (size > m->cap) {
+ m->cap = MAX(size, m->cap * 2);
+ m->cap = MIN(m->cap, size + MAXINT_MAX_OVERCOMMIT - 1);
+ } else {
+ m->cap = size + 1;
+ }
+ alloc = MAXINT_REALLOC(m->data, m->cap * MI_ULBYTES);
+ if (!alloc) return MI_ERR_OOM;
+ m->data = alloc;
+ }
+
+ if (size > m->size)
+ memset(&m->data[m->size], 0, (size - m->size) * MI_ULBYTES);
+
+ m->size = size;
+
+ return 0;
+}
+
+static int
+mi_add_internal(struct maxint *o1, const struct maxint *i1,
+ const struct maxint *i2, int i2_sign)
+{
+ mi_ul v;
+ int carry;
+ int i, msbs;
+ int rc;
+
+ if (o1 != i1) {
+ rc = mi_set(o1, i1);
+ if (rc) return rc;
+ }
+
+ msbs = i2->data[i2->size - 1] >> (MI_ULBITS - 1);
+ msbs &= i1->data[i1->size - 1] >> (MI_ULBITS - 1);
+ rc = mi_resize(o1, MAX(i1->size, i2->size) + (msbs != 0));
+ if (rc) return rc;
+
+ if (o1->sign != i2_sign) {
+ for (carry = i = 0; i < o1->size; i++) {
+ v = (i < i2->size ? i2->data[i] : 0);
+ o1->data[i] -= v + carry;
+ carry = o1->data[i] + v + carry < o1->data[i];
+ }
+
+ if (carry == 1) {
+ if (o1->data[0] > 0) {
+ o1->data[0]--;
+ for (i = 0; i < o1->size; i++)
+ o1->data[i] = ~o1->data[i];
+ } else {
+ for (i = 0; i < o1->size; i++)
+ o1->data[i] = ~o1->data[i];
+ o1->data[0]++;
+ }
+ o1->sign ^= 1;
+ }
+ } else {
+ for (carry = i = 0; i < o1->size; i++) {
+ v = (i < i2->size ? i2->data[i] : 0);
+ o1->data[i] += v + carry;
+ carry = o1->data[i] - v - carry > o1->data[i];
+ }
+ }
+
+ return 0;
+}
+
+size_t
+mi_lastset(const struct maxint *m1)
+{
+ size_t i;
+
+ for (i = m1->size - 1; i >= 0; i--)
+ if (m1->data[i] != 0) return i;
+
+ return 0;
+}
+
+int
+mi_add(struct maxint *o1, const struct maxint *i1, const struct maxint *i2)
+{
+ return mi_add_internal(o1, i1, i2, i2->sign);
+}
+
+int
+mi_sub(struct maxint *o1, const struct maxint *i1, const struct maxint *i2)
+{
+ return mi_add_internal(o1, i1, i2, i2->sign ^ 1);
+}
+
+int
+mi_shl(struct maxint *o1, const struct maxint *i1, size_t shift)
+{
+ int i, bit;
+ int rc;
+
+ if (!shift) return 0;
+
+ rc = mi_resize(o1, mi_lastset(i1) + 1 + DIVCEIL(shift, MI_ULBITS));
+ if (rc) return rc;
+
+ for (i = o1->size * MI_ULBITS - 1; i >= 0; i--) {
+ o1->data[i / MI_ULBITS] &= ~((mi_ul) 1 << (i % MI_ULBITS));
+ if (i >= shift) {
+ bit = MI_BITA(i1->data, MI_ULBITS, i - shift);
+ o1->data[i / MI_ULBITS] |= (mi_ul) bit << (i % MI_ULBITS);
+ }
+ }
+
+ return 0;
+}
+
+int
+mi_shr(struct maxint *o1, const struct maxint *i1, size_t shift)
+{
+ int i, bit;
+ int rc;
+
+ if (!shift) return 0;
+
+ if (o1 != i1) {
+ rc = mi_resize(o1, mi_lastset(i1) + 1 - shift / MI_ULBITS);
+ if (rc) return rc;
+ }
+
+ for (i = 0; i < i1->size * MI_ULBITS; i++) {
+ i1->data[i / MI_ULBITS] &= ~((mi_ul) 1 << (i % MI_ULBITS));
+ if (i + shift < i1->size * MI_ULBITS) {
+ bit = MI_BITA(i1->data, MI_ULBITS, i + shift);
+ i1->data[i / MI_ULBITS] |= (mi_ul) bit << (i % MI_ULBITS);
+ }
+ }
+
+ return 0;
+}
+
+int
+mi_mul(struct maxint *osum, const struct maxint *i1, const struct maxint *i2)
+{
+ struct maxint isum = MI_INIT;
+ struct maxint *sum;
+ ssize_t i;
+ int rc = 0;
+
+ sum = (osum == i1) ? &isum : osum;
+
+ rc = mi_setv(sum, 0, MI_POS);
+ if (rc) goto exit;
+
+ for (i = i1->size * MI_ULBITS - 1; i >= 0; i--) {
+ rc = mi_shl(sum, sum, 1);
+ if (rc) goto exit;
+
+ if (MI_BITA(i1->data, MI_ULBITS, i)) {
+ if (i1->sign == MI_POS) {
+ rc = mi_add(sum, sum, i2);
+ if (rc) goto exit;
+ } else {
+ rc = mi_sub(sum, sum, i2);
+ if (rc) goto exit;
+ }
+ }
+ }
+
+ if (osum == i1)
+ mi_swap(sum, osum);
+
+exit:
+ if (sum == &isum)
+ mi_deinit(sum);
+
+ return rc;
+}
+
+int
+mi_div(struct maxint *oquot, struct maxint *orem,
+ const struct maxint *num, const struct maxint *div)
+{
+ struct maxint iquot = MI_INIT;
+ struct maxint irem = MI_INIT;
+ struct maxint *quot, *rem;
+ int i, k;
+ int rc;
+
+ quot = (oquot == NULL || oquot == num || oquot == div) ? &iquot : oquot;
+ rem = (orem == NULL || orem == num || orem == div) ? &irem : orem;
+
+ rc = mi_setv(quot, 0, MI_POS);
+ if (rc) goto exit;
+
+ rc = mi_setv(rem, 0, MI_POS);
+ if (rc) goto exit;
+
+ for (i = 0; i < num->size * MI_ULBITS; i++) {
+ k = num->size * MI_ULBITS - 1 - i;
+
+ /* rem = rem * 2 + [bit set] */
+ rc = mi_shl(rem, rem, 1);
+ if (rc) goto exit;
+ if (MI_BITA(num->data, MI_ULBITS, k)) {
+ rc = mi_add(rem, rem, &mi_one);
+ if (rc) goto exit;
+ }
+
+ /* quot = 2 * quot + [rem >= div] */
+ rc = mi_shl(quot, quot, 1);
+ if (rc) goto exit;
+ if (mi_cmp(rem, div) >= 0) {
+ rc = mi_add(quot, quot, &mi_one);
+ if (rc) goto exit;
+ rc = mi_sub(rem, rem, div);
+ if (rc) goto exit;
+ }
+ }
+
+ if (quot->sign != div->sign) {
+ rc = mi_sub(rem, rem, div);
+ if (rc) goto exit;
+ }
+
+ rem->sign = div->sign;
+ quot->sign = num->sign ^ div->sign;
+
+ if (quot == &iquot && oquot)
+ mi_swap(&iquot, oquot);
+
+ if (rem == &irem && orem)
+ mi_swap(&irem, orem);
+
+exit:
+ mi_deinit(&iquot);
+ mi_deinit(&irem);
+
+ return rc;
+}
+
+void
+mi_swap(struct maxint *m1, struct maxint *m2)
+{
+ struct maxint tmp;
+
+ memcpy(&tmp, m1, sizeof(struct maxint));
+ memcpy(m1, m2, sizeof(struct maxint));
+ memcpy(m2, &tmp, sizeof(struct maxint));
+}
+
+int
+mi_gcd(struct maxint *o1, const struct maxint *i1, const struct maxint *i2)
+{
+ struct maxint rem = MI_INIT;
+ struct maxint tmp = MI_INIT;
+ int rc = 0;
+
+ rc = mi_setv(&rem, 0, MI_POS);
+ if (rc) goto exit;
+
+ rc = mi_set(&tmp, i2);
+ if (rc) goto exit;
+
+ if (o1 != i1) {
+ rc = mi_set(o1, i1);
+ if (rc) goto exit;
+ }
+
+ do {
+ rc = mi_div(o1, &rem, o1, &tmp);
+ if (rc) goto exit;
+ mi_swap(o1, &tmp);
+ mi_swap(&tmp, &rem);
+ } while (!mi_zero(&tmp));
+
+exit:
+ mi_deinit(&rem);
+ mi_deinit(&tmp);
+
+ return rc;
+}
+
+int
+mi_lcm(struct maxint *o1, const struct maxint *i1, const struct maxint *i2)
+{
+ struct maxint lcm = MI_INIT;
+ int rc = 0;
+
+ rc = mi_set(&lcm, i1);
+ if (rc) goto exit;
+
+ rc = mi_gcd(&lcm, i1, i2);
+ if (rc) goto exit;
+
+ rc = mi_mul(o1, i1, i2);
+ if (rc) goto exit;
+
+ rc = mi_div(o1, NULL, o1, &lcm);
+ if (rc) goto exit;
+
+exit:
+ mi_deinit(&lcm);
+
+ return rc;
+}
+
+int
+mi_cmp(const struct maxint *m1, const struct maxint *m2)
+{
+ mi_ul v1, v2;
+ size_t i;
+
+ for (i = 0; i < MAX(m1->size, m2->size); i++) {
+ v1 = (i >= m1->size ? 0 : m1->data[i]);
+ v2 = (i >= m2->size ? 0 : m2->data[i]);
+ if (v1 != v2) return v1 > v2 ? 1 : -1;
+ }
+
+ return 0;
+}
+
+mi_ul
+mi_cast_ul(const struct maxint *m1)
+{
+ return m1->data[0];
+}
+
+bool
+mi_zero(const struct maxint *m1)
+{
+ size_t i;
+
+ for (i = 0; i < m1->size; i++) {
+ if (m1->data[i] != 0)
+ return false;
+ }
+
+ return true;
+}
+
+ssize_t
+mi_str(const struct maxint *m, char *buf, size_t buflen,
+ mi_ul base_ul, const char *alph)
+{
+ struct maxint num = MI_INIT;
+ struct maxint rem = MI_INIT;
+ struct maxint base = MI_INIT;
+ size_t i, len;
+ ssize_t ret = -1;
+ mi_ul rem_ul;
+ char tmp;
+ int rc;
+
+ if (!base_ul) return -1;
+ if (!buflen) return -1;
+
+ rc = mi_set(&num, m);
+ if (rc) goto exit;
+ num.sign = MI_POS;
+
+ rc = mi_setv(&rem, 0, MI_POS);
+ if (rc) goto exit;
+
+ rc = mi_setv(&base, base_ul, MI_POS);
+ if (rc) goto exit;
+
+ len = 0;
+ do {
+ if (mi_div(&num, &rem, &num, &base))
+ goto exit;
+ rem_ul = mi_cast_ul(&rem);
+
+ buf[len++] = alph[rem_ul];
+ if (len == buflen)
+ goto exit;
+ } while (!mi_zero(&num));
+
+ if (m->sign == MI_NEG) {
+ buf[len++] = '-';
+ if (len == buflen)
+ goto exit;
+ }
+
+ for (i = 0; i < len / 2; i++) {
+ tmp = buf[i];
+ buf[i] = buf[len - 1 - i];
+ buf[len - 1 - i] = tmp;
+ }
+
+ buf[len++] = '\0';
+ ret = len;
+
+exit:
+ mi_deinit(&rem);
+ mi_deinit(&num);
+ mi_deinit(&base);
+
+ return ret;
+}
+
+ssize_t
+mi_hex(const struct maxint *m, char *buf, size_t buflen, bool capital)
+{
+ return mi_str(m, buf, buflen, 16,
+ capital ? "0123456789ABCDEF" : "0123456789abcdef");
+}
+
+ssize_t
+mi_dec(const struct maxint *m, char *buf, size_t buflen)
+{
+ return mi_str(m, buf, buflen, 10, "0123456789");
+}
+
+ssize_t
+mi_bin(const struct maxint *m, char *buf, size_t buflen)
+{
+ return mi_str(m, buf, buflen, 2, "01");
+}
diff --git a/lib/libmaxint/src/test.c b/lib/libmaxint/src/test.c
@@ -0,0 +1,82 @@
+#include "maxint.h"
+
+#include <stdio.h>
+
+int
+main(int argc, const char **argv)
+{
+ char sa[256], sb[256], sc[256];
+ struct maxint a = MI_INIT;
+ struct maxint b = MI_INIT;
+ struct maxint c = MI_INIT;
+ ssize_t len = 0;
+ int rc = 0;
+
+ rc |= mi_setv(&a, 1014, MI_POS);
+ rc |= mi_setv(&b, 9, MI_NEG);
+ rc |= mi_add(&c, &a, &b);
+ rc |= mi_dec(&a, sa, sizeof(sa)) < 0;
+ rc |= mi_dec(&b, sb, sizeof(sb)) < 0;
+ rc |= mi_dec(&c, sc, sizeof(sc)) < 0;
+ if (rc) goto exit;
+ printf("ADD: %s + %s = %s\n", sa, sb, sc);
+
+ rc |= mi_setv(&a, 10000000000000000000ULL, MI_POS);
+ rc |= mi_setv(&b, 10000000000000000000ULL, MI_POS);
+ rc |= mi_add(&c, &a, &b);
+ rc |= mi_dec(&a, sa, sizeof(sa)) < 0;
+ rc |= mi_dec(&b, sb, sizeof(sb)) < 0;
+ rc |= mi_dec(&c, sc, sizeof(sc)) < 0;
+ if (rc) goto exit;
+ printf("ADD: %s + %s = %s\n", sa, sb, sc);
+
+ rc |= mi_setv(&a, 1, MI_NEG);
+ rc |= mi_setv(&b, 1, MI_POS);
+ rc |= mi_mul(&c, &a, &b);
+ rc |= mi_bin(&a, sa, sizeof(sa)) < 0;
+ rc |= mi_bin(&b, sb, sizeof(sb)) < 0;
+ rc |= mi_bin(&c, sc, sizeof(sc)) < 0;
+ if (rc) goto exit;
+ printf("MUL: %s * %s = %s\n", sa, sb, sc);
+
+ rc |= mi_setv(&a, 10000000000000000000ULL, MI_POS);
+ rc |= mi_bin(&a, sa, sizeof(sa)) < 0;
+ rc |= mi_shl(&b, &a, 2);
+ rc |= mi_bin(&b, sb, sizeof(sb)) < 0;
+ if (rc) goto exit;
+ printf("SHL: %s << 2 = %s\n", sa, sb);
+
+ rc |= mi_setv(&a, 10000000000000000000ULL, MI_POS);
+ rc |= mi_setv(&b, 10000000000000000000ULL, MI_POS);
+ rc |= mi_mul(&c, &a, &b);
+ if (rc) goto exit;
+ printf("%lu * %lu != %lu\n", a.data[0], b.data[0], a.data[0] * b.data[0]);
+ rc |= mi_dec(&a, sa, sizeof(sa)) < 0;
+ rc |= mi_dec(&b, sb, sizeof(sb)) < 0;
+ rc |= mi_dec(&c, sc, sizeof(sc)) < 0;
+ if (rc) goto exit;
+ printf("%s * %s = %s\n", sa, sb, sc);
+
+ rc |= mi_setv(&b, 33, MI_POS);
+ if (rc) goto exit;
+ rc |= mi_dec(&a, sa, sizeof(sa)) < 0;
+ rc |= mi_dec(&b, sb, sizeof(sb)) < 0;
+ printf("%s / %s = ", sa, sb);
+ rc |= mi_div(&a, &c, &a, &b);
+ rc |= mi_dec(&a, sa, sizeof(sa)) < 0;
+ rc |= mi_dec(&c, sc, sizeof(sc)) < 0;
+ if (rc) goto exit;
+ printf("%s R %s\n", sa, sc);
+
+ mi_dec(&a, sa, sizeof(sa));
+ printf("DEC: %s\n", sa);
+ mi_hex(&a, sa, sizeof(sa), true);
+ printf("HEX: %s\n", sa);
+
+exit:
+ mi_deinit(&a);
+ mi_deinit(&b);
+ mi_deinit(&c);
+
+ return rc;
+}
diff --git a/libs/Makefile b/libs/Makefile
@@ -1,41 +0,0 @@
-CFLAGS = -I include -g -L build
-LDLIBS =
-
-AOC_OBJ_ = wrapper.o aoc.o util.o memvec.o hashmap.o maxint.o
-AOC_OBJ = $(addprefix build/, $(AOC_OBJ_))
-
-all: build/libaoc.a build/libicc.a build/libiccmp.a
-
-clean:
- rm -rf build
-
-build:
- mkdir build
-
-build/%.o: src/%.c include/%.h | build
- $(CC) -c -o $@ $< $(CFLAGS) $(LDLIBS)
-
-build/wrapper.o: src/wrapper.c | build
- $(CC) -c -o $@ $< $(CFLAGS) $(LDLIBS)
-
-build/libaoc.a: $(AOC_OBJ) | build
- ar rcs $@ $^
-
-build/libicc.a: build/icc.o | build
- ar rcs $@ $^
-
-build/libiccmp.a: build/iccmp.o | build
- ar rcs $@ $^
-
-build/test_%: tests/%.c | build
- $(CC) -o $@ $< $(CFLAGS) $(LDLIBS)
-
-build/test_maxint: tests/maxint.c build/maxint.o | build
- $(CC) -o $@ $^ $(CFLAGS) $(LDLIBS) -laoc
-
-build/test_%.log: build/test_% | build
- @echo "--- Running test: $< ---"
- @valgrind --track-origins=yes --leak-check=full $< 2>&1 | tee $@
-
-tests: build/test_maxint.log
-
diff --git a/libs/include/aoc.h b/libs/include/aoc.h
@@ -1,28 +0,0 @@
-#ifndef AOC_AOC_H
-#define AOC_AOC_H
-
-#include "util.h"
-
-struct aoc {
- int debug;
- int part;
-
- char *answer;
- const char *solution;
-
- const char *inputfile;
- char *input;
- size_t input_size;
-
- const char **args;
-};
-
-extern struct aoc aoc;
-
-void aoc_check(const char *sol, const char *fmtstr, ...);
-void debug(const char *fmtstr, ...);
-
-void part1(void);
-void part2(void);
-
-#endif
diff --git a/libs/include/hashmap.h b/libs/include/hashmap.h
@@ -1,52 +0,0 @@
-#include "util.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-
-#define HASHMAP_KEY(v, len) ((struct hashmap_key) { (void*) (v), (len) })
-#define HASHMAP_VAL(content) ((union hashmap_val) { content })
-
-struct hashmap_key {
- void *key;
- int len;
-};
-
-union hashmap_val {
- void *p;
- int i;
- float f;
- double d;
- char c;
-};
-
-struct hashmap_link {
- struct hashmap_key key;
- union hashmap_val value;
- struct hashmap_link *next;
-};
-
-struct hashmap_iter {
- struct hashmap_link *link;
- int bucket;
-};
-
-struct hashmap {
- struct hashmap_link **buckets;
- int size;
- uint32_t (*hash)(void *key, int len);
-};
-
-void hashmap_init(struct hashmap *hm, int size, uint32_t (*hasher)(void *key, int len));
-void hashmap_clear(struct hashmap *hm);
-void hashmap_free(struct hashmap *hm);
-
-void hashmap_add(struct hashmap *hm, struct hashmap_key key, union hashmap_val value);
-int hashmap_set(struct hashmap *hm, struct hashmap_key key, union hashmap_val value);
-int hashmap_get(struct hashmap *hm, struct hashmap_key key, struct hashmap_link **dst);
-int hashmap_pop(struct hashmap *hm, struct hashmap_key key, struct hashmap_link **dst);
-
-struct hashmap_iter hashmap_iter(void);
-int hashmap_next(struct hashmap *hm, struct hashmap_iter *next);
-
-uint32_t hashmap_string_hasher(void *key, int len);
diff --git a/libs/include/icc.h b/libs/include/icc.h
@@ -1,59 +0,0 @@
-#include "aoc.h"
-#include "util.h"
-#include "memvec.h"
-
-#include <stdlib.h>
-
-enum {
- ICC_OK,
- ICC_INPUT,
- ICC_OUTPUT,
- ICC_HALT
-};
-
-enum {
- ICC_PARAM_IMM,
- ICC_PARAM_POS,
- ICC_PARAM_REL
-};
-
-enum {
- ICC_INST_ADD = 1,
- ICC_INST_MULT = 2,
- ICC_INST_STORE = 3,
- ICC_INST_LOAD = 4,
- ICC_INST_JMPT = 5,
- ICC_INST_JMPF = 6,
- ICC_INST_TLT = 7,
- ICC_INST_TEQ = 8,
- ICC_INST_BASE = 9,
-
- ICC_INST_HALT = 99
-};
-
-struct icc {
- int status;
- int in, out;
-
- size_t instp, base;
- struct memvec instructions;
-};
-
-int icc_init(struct icc *icc);
-void icc_free(struct icc *icc);
-void icc_copy(struct icc *dst, struct icc *src);
-
-void * icc_inst_copy(struct icc *icc);
-void icc_reset(struct icc *icc, void *instcopy);
-
-int icc_parse_inst(struct icc *icc, const char *str, size_t len);
-void icc_step_inst(struct icc *icc);
-
-void icc_set_inst(struct icc *icc, size_t addr, int in);
-void icc_get_inst(struct icc *icc, size_t addr, int *out);
-
-int icc_param_mode(int inst, int param);
-void icc_get_param(struct icc *icc, int param, int *out);
-void icc_get_dest(struct icc *icc, int param, int *out);
-
-void icc_input_callback(struct icc *icc, int (*callback)(int));
diff --git a/libs/include/iccmp.h b/libs/include/iccmp.h
@@ -1,67 +0,0 @@
-#include "aoc.h"
-#include "util.h"
-#include "memvec.h"
-#include "maxint.h"
-
-#include <stdlib.h>
-
-enum {
- ICC_OK,
- ICC_INPUT,
- ICC_OUTPUT,
- ICC_HALT
-};
-
-enum {
- ICC_PARAM_IMM,
- ICC_PARAM_POS,
- ICC_PARAM_REL
-};
-
-enum {
- ICC_INST_ADD = 1,
- ICC_INST_MULT = 2,
- ICC_INST_STORE = 3,
- ICC_INST_LOAD = 4,
- ICC_INST_JMPT = 5,
- ICC_INST_JMPF = 6,
- ICC_INST_TLT = 7,
- ICC_INST_TEQ = 8,
- ICC_INST_BASE = 9,
-
- ICC_INST_HALT = 99
-};
-
-typedef uint64_t inst_t;
-
-struct icc {
- int status, debug;
- struct maxint in, out;
- struct maxint base;
-
- /* general purpose registers */
- struct maxint r1, r2, r3, r4;
-
- size_t instp;
- struct memvec instructions;
-};
-
-int icc_init(struct icc *icc);
-void icc_free(struct icc *icc);
-void icc_copy(struct icc *dst, struct icc *src);
-
-void * icc_inst_copy(struct icc *icc);
-void icc_reset(struct icc *icc, void *instcopy);
-
-int icc_parse_inst(struct icc *icc, const char *str, size_t len);
-void icc_step_inst(struct icc *icc);
-
-void icc_set_val(struct icc *icc, size_t addr, struct maxint *in);
-void icc_get_val(struct icc *icc, size_t addr, struct maxint *out);
-void icc_get_inst(struct icc *icc, size_t addr, inst_t *out);
-
-int icc_param_mode(inst_t inst, int param);
-void icc_get_param(struct icc *icc, int param, struct maxint *out);
-void icc_get_dest(struct icc *icc, int param, struct maxint *out);
-
-void icc_set_debug(struct icc *icc, int debug);
diff --git a/libs/include/maxint.h b/libs/include/maxint.h
@@ -1,71 +0,0 @@
-#ifndef AOC_MAXINT_H
-#define AOC_MAXINT_H
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "util.h"
-
-#define MI_SWAP(a,b) a ^= b ^= a
-
-#define MI_DIVCEIL(a,b) ((a) / (b) + ((a) % (b) != 0))
-
-#define MI_BIT(a,n) ((mi_ul) ((a) >> (n)) & 1)
-#define MI_BITA(a,m,n) ((mi_ul) ((a)[(n) / (m)] >> ((n) % (m))) & 1)
-
-#define MI_ULBYTES (sizeof(mi_ul))
-#define MI_ULBITS (8 * sizeof(mi_ul))
-
-#define MI_NEG 1
-#define MI_POS 0
-
-#define MI_INIT ((struct maxint) { \
- .data = NULL, \
- .size = 0, \
- .cap = 0, \
- .sign = MI_POS, \
-})
-
-/* unsigned underlying type */
-typedef uint64_t mi_ul;
-
-struct maxint {
- mi_ul *data;
- int size, cap;
- int sign;
-};
-
-void mi_parse(struct maxint *m, const char *str, const char **end, const char *alph);
-void mi_free(struct maxint *m);
-
-void mi_set(struct maxint *m1, const struct maxint *m2); // m1 = m2
-void mi_setv(struct maxint *m, mi_ul v, int sign);
-
-void mi_resize(struct maxint *m, int size);
-
-mi_ul mi_cast_ul(const struct maxint *m);
-
-int mi_zero(const struct maxint *m);
-
-int mi_lastset(const struct maxint *m);
-
-void mi_add(struct maxint *m1, const struct maxint *m2); // m1 += m2
-void mi_sub(struct maxint *m1, const struct maxint *m2); // m1 -= m2
-void mi_shl(struct maxint *m, uint64_t shift); // m1 <<= shift
-void mi_shr(struct maxint *m, uint64_t shift); // m1 >>= shift
-void mi_mul(struct maxint *m1, const struct maxint *m2); // m1 *= m2
-void mi_div(struct maxint *m1, struct maxint *m2, const struct maxint *m3); // m1 /= m3, m2 = m1 % m3
-void mi_swap(struct maxint *m1, struct maxint *m2); // m1 <=> m2
-int mi_cmp(const struct maxint *m1, const struct maxint *m2); // m1 < m2 ? m2 > m1 ? 1 : 0 : -1
-void mi_gcm(struct maxint *m1, const struct maxint *m2); // m1 = gcm(m1, m2)
-void mi_lcm(struct maxint *m1, const struct maxint *m2); // m1 = lcm(m1, m2)
-
-char * mi_convstr(char *alloc, const struct maxint *m, int base, const char *alph);
-char * mi_hexstr(char *alloc, const struct maxint *m, int cap);
-char * mi_decstr(char *alloc, const struct maxint *m);
-char * mi_binstr(char *alloc, const struct maxint *m);
-
-extern struct maxint mi_one;
-
-#endif
diff --git a/libs/include/memvec.h b/libs/include/memvec.h
@@ -1,21 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-
-#include "util.h"
-
-#define MEMVEC_GET(mv, i, type) (*(type*) memvec_get(mv, i))
-
-struct memvec {
- void *data;
- size_t cap, len, itemsize;
-};
-
-int memvec_init(struct memvec *v, size_t cap, size_t itemsize);
-void memvec_free(struct memvec *v);
-void * memvec_add(struct memvec *v, void *item);
-void * memvec_get(struct memvec *v, size_t index);
-void memvec_set(struct memvec *v, size_t index, void *item);
-int memvec_in_range(struct memvec *v, size_t index);
-size_t memvec_len(struct memvec *v);
-void memvec_copy(struct memvec *dst, struct memvec *src);
-void memvec_resize(struct memvec *v, size_t size);
diff --git a/libs/include/util.h b/libs/include/util.h
@@ -1,47 +0,0 @@
-#ifndef AOC_UTIL_H
-#define AOC_UTIL_H
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#define _STR(v) #v
-#define STR(v) _STR(v)
-#define LOC() __FILE__ ":" STR(__LINE__)
-
-#define ASSERT(expr) assert(expr, \
- "Assert '" #expr "' at " LOC() " failed")
-#define ASSERTV(expr, ...) assert(expr, LOC() " : " __VA_ARGS__)
-
-#define CHKP(ptr) chkp(ptr, \
- "Unexpected NULL pointer '" #ptr "' at " LOC())
-
-#define ABS(a) ((a) > 0 ? (a) : -(a))
-
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define MIN(a, b) ((a) > (b) ? (b) : (a))
-
-#define MAXA(a, b) (ABS(a) > ABS(b) ? (a) : (b))
-#define MINA(a, b) (ABS(a) > ABS(b) ? (b) : (a))
-
-#define ISWAP(a, b) (a ^= b ^= a)
-
-enum { OK, FAIL };
-
-enum { MID_TOK, LAST_TOK };
-
-void die(const char *fmtstr, ...);
-void assert(int res, const char *fmtstr, ...);
-void * chkp(void *alloc, const char *fmtstr, ...);
-char * aprintf(const char *fmtstr, ...);
-
-const char * ntoken(const char *start, const char *end,
- size_t *len, const char *sep);
-
-void * memdup(void *data, size_t size);
-
-int readall(int fd, void **data, size_t *read);
-
-#endif
diff --git a/libs/src/aoc.c b/libs/src/aoc.c
@@ -1,27 +0,0 @@
-#include "aoc.h"
-
-void
-aoc_check(const char *sol, const char *fmtstr, ...)
-{
- char buf[256];
- va_list ap;
-
- va_start(ap, fmtstr);
- vsnprintf(buf, 256, fmtstr, ap);
- va_end(ap);
-
- assert(!strcmp(sol, buf), "AOC solution check failed");
-}
-
-void
-debug(const char *fmtstr, ...)
-{
- va_list ap;
-
- if (!aoc.debug) return;
-
- va_start(ap, fmtstr);
- vfprintf(stderr, fmtstr, ap);
- va_end(ap);
-}
-
diff --git a/libs/src/hashmap.c b/libs/src/hashmap.c
@@ -1,158 +0,0 @@
-#include "hashmap.h"
-
-void
-hashmap_init(struct hashmap *hm, int size, uint32_t (*hasher)(void *key, int len))
-{
- if (!size) size = 20;
- hm->size = size;
- hm->buckets = CHKP(malloc(hm->size * sizeof(struct hashmap_link *)));
- hm->hash = hasher;
- memset(hm->buckets, 0, hm->size * sizeof(struct hashmap_link *));
-}
-
-void
-hashmap_clear(struct hashmap *hm)
-{
- struct hashmap_iter iter;
- struct hashmap_link *prev;
-
- prev = NULL;
- iter = hashmap_iter();
- while (hashmap_next(hm, &iter)) {
- free(iter.link->key.key);
- free(prev);
- prev = iter.link;
- }
- free(prev);
- memset(hm->buckets, 0, hm->size * sizeof(struct hashmap_link *));
-}
-
-void
-hashmap_free(struct hashmap *hm)
-{
- hashmap_clear(hm);
- free(hm->buckets);
- hm->buckets = NULL;
-}
-
-int
-hashmap_get(struct hashmap *hm, struct hashmap_key key, struct hashmap_link **dst)
-{
- struct hashmap_link **iter;
- struct hashmap_key ckey;
-
- iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size];
- while (*iter) {
- ckey = (*iter)->key;
- if (ckey.len == key.len && !memcmp(ckey.key, key.key, key.len)) {
- if (dst) *dst = *iter;
- return 1;
- }
- iter = &((*iter)->next);
- }
-
- return 0;
-}
-
-int
-hashmap_pop(struct hashmap *hm, struct hashmap_key key, struct hashmap_link **dst)
-{
- struct hashmap_link **iter;
- struct hashmap_key ckey;
-
- iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size];
- while (*iter) {
- ckey = (*iter)->key;
- if (ckey.len == key.len && !memcmp(ckey.key, key.key, key.len)) {
- *iter = (*iter)->next;
- if (dst) *dst = *iter;
- return 1;
- }
- iter = &((*iter)->next);
- }
-
- return 0;
-}
-
-void
-hashmap_add(struct hashmap *hm, struct hashmap_key key, union hashmap_val value)
-{
- struct hashmap_link **iter;
-
- iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size];
- while (*iter) iter = &((*iter)->next);
-
- *iter = CHKP(malloc(sizeof(struct hashmap_link)));
- (*iter)->key.key = CHKP(memdup(key.key, key.len));
- (*iter)->key.len = key.len;
- (*iter)->value = value;
- (*iter)->next = NULL;
-}
-
-int
-hashmap_set(struct hashmap *hm, struct hashmap_key key, union hashmap_val value)
-{
- struct hashmap_link **iter;
- struct hashmap_key ckey;
-
- iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size];
- while (*iter) {
- ckey = (*iter)->key;
- if (ckey.len == key.len && !memcmp(ckey.key, key.key, key.len)) {
- (*iter)->value = value;
- return 1;
- }
- iter = &((*iter)->next);
- }
-
- *iter = CHKP(malloc(sizeof(struct hashmap_link)));
- (*iter)->key.key = CHKP(memdup(key.key, key.len));
- (*iter)->key.len = key.len;
- (*iter)->value = value;
- (*iter)->next = NULL;
-
- return 0;
-}
-
-struct hashmap_iter
-hashmap_iter(void)
-{
- return (struct hashmap_iter) { NULL, -1 };
-}
-
-int
-hashmap_next(struct hashmap *hm, struct hashmap_iter *iter)
-{
- int i;
-
- if (iter->link && iter->link->next) {
- iter->link = iter->link->next;
- return 1;
- }
-
- for (i = iter->bucket + 1; i < hm->size; i++) {
- if (hm->buckets[i]) {
- iter->bucket = i;
- iter->link = hm->buckets[i];
- return 1;
- }
- }
- iter->link = NULL;
-
- return 0;
-}
-
-uint32_t
-hashmap_string_hasher(void *key, int len)
-{
- uint32_t hash;
- uint8_t *data;
- int i;
-
- hash = 0;
- data = key;
- for (i = 0; i < len; i++)
- hash = 31 * hash + data[i];
-
- return hash;
-}
diff --git a/libs/src/icc.c b/libs/src/icc.c
@@ -1,354 +0,0 @@
-#include "icc.h"
-
-int
-icc_init(struct icc *icc)
-{
- icc->instp = 0;
- icc->status = ICC_OK;
- icc->base = 0;
- return memvec_init(&icc->instructions, 0, sizeof(int));
-}
-
-void
-icc_free(struct icc *icc)
-{
- memvec_free(&icc->instructions);
-}
-
-void
-icc_copy(struct icc *dst, struct icc *src)
-{
- dst->instp = src->instp;
- dst->in = src->in;
- dst->out = src->out;
- dst->status = src->status;
- dst->base = src->base;
- memvec_copy(&dst->instructions, &src->instructions);
-}
-
-void*
-icc_inst_copy(struct icc *icc)
-{
- return CHKP(memdup(icc->instructions.data, icc->instructions.len));
-}
-
-void
-icc_reset(struct icc *icc, void *instcopy)
-{
- icc->status = ICC_OK;
- icc->instp = 0;
- icc->base = 0;
- if (instcopy)
- memcpy(icc->instructions.data, instcopy, icc->instructions.len);
-}
-
-int
-icc_parse_inst(struct icc *icc, const char *str, size_t len)
-{
- const char *line = str, *nline, *end = str + len;
- char *endptr = NULL;
- size_t linelen;
- int val;
-
- do {
- nline = ntoken(line, end, &linelen, ",\n");
- val = strtoul(line, &endptr, 10);
- if (endptr && !memchr(",\n", *endptr, 3))
- return FAIL;
- if (!memvec_add(&icc->instructions, &val))
- return FAIL;
- line = nline;
- } while (nline);
-
- return OK;
-}
-
-const char*
-icc_param_str(struct icc *icc, int param)
-{
- static char buf[32];
- int val;
-
- icc_get_inst(icc, icc->instp + param, &val);
- snprintf(buf, sizeof(buf), "%i", val);
-
- return buf;
-}
-
-void
-icc_debug_op(struct icc *icc, const char *opstr, int n)
-{
- int i, val, val2, inst;
-
- if (!aoc.debug) return;
-
- icc_get_inst(icc, icc->instp, &inst);
-
- fprintf(stderr, "%04li: (%05i) %s ", icc->instp, inst, opstr);
-
- for (i = 1; i <= n; i++) {
- if (i > 1) fprintf(stderr, ", ");
- icc_get_inst(icc, icc->instp + i, &val);
- switch (icc_param_mode(inst, i)) {
- case ICC_PARAM_IMM:
- fprintf(stderr, "%i", val);
- break;
- case ICC_PARAM_POS:
- icc_get_inst(icc, val, &val2);
- fprintf(stderr, "[%i]=%i", val, val2);
- break;
- default:
- die("ICC: Unknown parmeter mode\n");
- }
- }
-
- fprintf(stderr, "\n");
-}
-
-void
-icc_inst_add(struct icc *icc)
-{
- int a, b, dst;
-
- icc_get_param(icc, 1, &a);
- icc_get_param(icc, 2, &b);
- icc_get_dest(icc, 3, &dst);
-
- icc_debug_op(icc, "ADD", 3);
- icc_set_inst(icc, dst, a + b);
-
- icc->instp += 4;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_mul(struct icc *icc)
-{
- int a, b, dst;
-
- icc_get_param(icc, 1, &a);
- icc_get_param(icc, 2, &b);
- icc_get_dest(icc, 3, &dst);
-
- icc_debug_op(icc, "MUL", 3);
- icc_set_inst(icc, dst, a * b);
-
- icc->instp += 4;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_store(struct icc *icc)
-{
- int dst;
-
- if (icc->status != ICC_INPUT) {
- icc_debug_op(icc, "INPUT", 0);
- icc->status = ICC_INPUT;
- } else {
- icc_debug_op(icc, "STORE", 1);
- icc_get_dest(icc, 1, &dst);
- icc_set_inst(icc, dst, icc->in);
-
- icc->instp += 2;
- icc->status = ICC_OK;
- }
-}
-
-void
-icc_inst_load(struct icc *icc)
-{
- int out;
-
- if (icc->status != ICC_OUTPUT) {
- icc_debug_op(icc, "LOAD", 1);
- icc_get_param(icc, 1, &out);
-
- icc->out = out;
- icc->status = ICC_OUTPUT;
- icc_debug_op(icc, "OUTPUT", 0);
- } else {
- icc->instp += 2;
- icc->status = ICC_OK;
- }
-}
-
-void
-icc_inst_jmp_true(struct icc *icc)
-{
- int cond, addr;
-
- icc_get_param(icc, 1, &cond);
- icc_get_param(icc, 2, &addr);
-
- icc_debug_op(icc, "JMPT", 2);
- if (cond) icc->instp = addr;
- else icc->instp += 3;
-
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_jmp_false(struct icc *icc)
-{
- int cond, addr;
-
- icc_get_param(icc, 1, &cond);
- icc_get_param(icc, 2, &addr);
-
- icc_debug_op(icc, "JMPF", 2);
- if (!cond) icc->instp = addr;
- else icc->instp += 3;
-
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_test_lt(struct icc *icc)
-{
- int a, b, dst;
-
- icc_get_param(icc, 1, &a);
- icc_get_param(icc, 2, &b);
- icc_get_dest(icc, 3, &dst);
-
- icc_debug_op(icc, "TLT", 3);
- icc_set_inst(icc, dst, a < b);
-
- icc->instp += 4;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_test_eq(struct icc *icc)
-{
- int a, b, dst;
-
- icc_get_param(icc, 1, &a);
- icc_get_param(icc, 2, &b);
- icc_get_dest(icc, 3, &dst);
-
- icc_debug_op(icc, "TEQ", 3);
- icc_set_inst(icc, dst, a == b);
-
- icc->instp += 4;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_base(struct icc *icc)
-{
- int off;
-
- icc_debug_op(icc, "BASE", 1);
- icc_get_param(icc, 1, &off);
- icc->base += off;
-
- icc->instp += 2;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_halt(struct icc *icc)
-{
- icc_debug_op(icc, "HALT", 0);
- icc->status = ICC_HALT;
-}
-
-void
-icc_step_inst(struct icc *icc)
-{
- int inst;
-
- icc_get_inst(icc, icc->instp, &inst);
- inst %= 100;
-
- switch (inst) {
- case ICC_INST_ADD:
- icc_inst_add(icc);
- break;
- case ICC_INST_MULT:
- icc_inst_mul(icc);
- break;
- case ICC_INST_STORE:
- icc_inst_store(icc);
- break;
- case ICC_INST_LOAD:
- icc_inst_load(icc);
- break;
- case ICC_INST_JMPT:
- icc_inst_jmp_true(icc);
- break;
- case ICC_INST_JMPF:
- icc_inst_jmp_false(icc);
- break;
- case ICC_INST_TLT:
- icc_inst_test_lt(icc);
- break;
- case ICC_INST_TEQ:
- icc_inst_test_eq(icc);
- break;
- case ICC_INST_BASE:
- icc_inst_base(icc);
- break;
- case ICC_INST_HALT:
- icc_inst_halt(icc);
- break;
- default:
- die("ICC: Unknown instruction: '%i'\n", inst);
- }
-}
-
-void
-icc_set_inst(struct icc *icc, size_t addr, int val)
-{
- memvec_set(&icc->instructions, addr, &val);
-}
-
-void
-icc_get_inst(struct icc *icc, size_t addr, int *out)
-{
- *out = *(int*)memvec_get(&icc->instructions, addr);
-}
-
-int
-icc_param_mode(int inst, int param)
-{
- int div, i;
-
- div = 100;
- for (i = 1; i < param; i++) div *= 10;
-
- return (inst / div) % 10 == 1 ? ICC_PARAM_IMM : ICC_PARAM_POS;
-}
-
-void
-icc_get_param(struct icc *icc, int param, int *out)
-{
- int inst, val;
-
- icc_get_inst(icc, icc->instp, &inst);
- icc_get_inst(icc, icc->instp + param, &val);
-
- switch (icc_param_mode(inst, param)) {
- case ICC_PARAM_IMM:
- *out = val;
- break;
- case ICC_PARAM_POS:
- icc_get_inst(icc, val, out);
- break;
- case ICC_PARAM_REL:
- *out = icc->base + val;
- break;
- default:
- die("ICC: Unknown parmeter mode\n");
- };
-}
-
-void
-icc_get_dest(struct icc *icc, int param, int *out)
-{
- icc_get_inst(icc, icc->instp + param, out);
-}
-
-
diff --git a/libs/src/iccmp.c b/libs/src/iccmp.c
@@ -1,438 +0,0 @@
-#include "iccmp.h"
-
-int
-icc_init(struct icc *icc)
-{
- icc->instp = 0;
- icc->status = ICC_OK;
- icc->base = MI_INIT;
- icc->debug = aoc.debug;
- mi_setv(&icc->base, 0, MI_POS);
- icc->in = icc->out = MI_INIT;
- icc->r1 = icc->r2 = icc->r3 = icc->r4 = MI_INIT;
- return memvec_init(&icc->instructions, 0, sizeof(struct maxint));
-}
-
-void
-icc_free(struct icc *icc)
-{
- struct maxint *mi;
- int i;
-
- mi_free(&icc->base);
- mi_free(&icc->in);
- mi_free(&icc->out);
- mi_free(&icc->r1);
- mi_free(&icc->r2);
- mi_free(&icc->r3);
- mi_free(&icc->r4);
-
- for (i = 0; i < memvec_len(&icc->instructions); i++)
- mi_free(memvec_get(&icc->instructions, i));
- memvec_free(&icc->instructions);
-}
-
-void
-icc_copy(struct icc *dst, struct icc *src)
-{
- dst->instp = src->instp;
- dst->status = src->status;
- dst->base = src->base;
- dst->in = MI_INIT;
- mi_set(&dst->in, &src->in);
- dst->out = MI_INIT;
- mi_set(&dst->out, &src->out);
- memvec_copy(&dst->instructions, &src->instructions);
-}
-
-void*
-icc_inst_copy(struct icc *icc)
-{
- return CHKP(memdup(icc->instructions.data, icc->instructions.len));
-}
-
-void
-icc_reset(struct icc *icc, void *instcopy)
-{
- icc->status = ICC_OK;
- icc->instp = 0;
- mi_setv(&icc->base, 0, MI_POS);
- mi_setv(&icc->in, 0, MI_POS);
- mi_setv(&icc->out, 0, MI_POS);
- if (instcopy)
- memcpy(icc->instructions.data, instcopy, icc->instructions.len);
-}
-
-int
-icc_parse_inst(struct icc *icc, const char *str, size_t len)
-{
- const char *line = str, *nline, *end = str + len;
- const char *endptr = NULL;
- struct maxint val;
- size_t linelen;
-
- do {
- nline = ntoken(line, end, &linelen, ",\n");
- val = MI_INIT;
- mi_parse(&val, line, &endptr, "0123456789");
- if (endptr && !memchr(",\n", *endptr, 3))
- goto fail;
- if (!memvec_add(&icc->instructions, &val))
- goto fail;
- line = nline;
- } while (nline);
-
- return OK;
-
-fail:
- mi_free(&val);
- return FAIL;
-}
-
-void
-icc_debug_op(struct icc *icc, const char *opstr, int n, int dst)
-{
- inst_t inst;
- char *str;
- int i;
-
- if (!icc->debug) return;
-
- icc_get_inst(icc, icc->instp, &inst);
-
- fprintf(stderr, "%04li: (%05lu) %s ", icc->instp, inst, opstr);
-
- str = NULL;
- for (i = 1; i <= n; i++) {
- if (i > 1) fprintf(stderr, ", ");
- icc_get_val(icc, icc->instp + i, &icc->r1);
- switch (icc_param_mode(inst, i)) {
- case ICC_PARAM_IMM:
- str = mi_decstr(str, &icc->r1);
- fprintf(stderr, "%s", str);
- break;
- case ICC_PARAM_POS:
- str = mi_decstr(str, &icc->r1);
- fprintf(stderr, "[%s]", str);
- if (i != dst) {
- icc_get_val(icc, mi_cast_ul(&icc->r1), &icc->r1);
- str = mi_decstr(str, &icc->r1);
- fprintf(stderr, "=%s", str);
- }
- break;
- case ICC_PARAM_REL:
- str = mi_decstr(str, &icc->r1);
- fprintf(stderr, "[B%s%s=", *str == '-' ? "" : "+", str);
- mi_add(&icc->r1, &icc->base);
- str = mi_decstr(str, &icc->r1);
- fprintf(stderr, "%s]", str);
- if (i != dst) {
- icc_get_val(icc, mi_cast_ul(&icc->r1), &icc->r1);
- str = mi_decstr(str, &icc->r1);
- fprintf(stderr, "=%s", str);
- }
- break;
- default:
- die("ICC: Unknown parmeter mode\n");
- }
- }
- free(str);
-
- fprintf(stderr, "\n");
-}
-
-void
-icc_inst_add(struct icc *icc)
-{
- icc_debug_op(icc, "ADD", 3, 3);
-
- icc_get_param(icc, 1, &icc->r1);
- icc_get_param(icc, 2, &icc->r2);
- icc_get_dest(icc, 3, &icc->r3);
-
- mi_add(&icc->r1, &icc->r2);
- icc_set_val(icc, mi_cast_ul(&icc->r3), &icc->r1);
-
- icc->instp += 4;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_mul(struct icc *icc)
-{
- icc_debug_op(icc, "MUL", 3, 3);
-
- icc_get_param(icc, 1, &icc->r1);
- icc_get_param(icc, 2, &icc->r2);
- icc_get_dest(icc, 3, &icc->r3);
-
- mi_mul(&icc->r1, &icc->r2);
- icc_set_val(icc, mi_cast_ul(&icc->r3), &icc->r1);
-
- icc->instp += 4;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_store(struct icc *icc)
-{
- if (icc->status != ICC_INPUT) {
- icc_debug_op(icc, "INPUT", 0, 0);
- icc->status = ICC_INPUT;
- } else {
- icc_debug_op(icc, "STORE", 1, 1);
- icc_get_dest(icc, 1, &icc->r1);
- icc_set_val(icc, mi_cast_ul(&icc->r1), &icc->in);
-
- icc->instp += 2;
- icc->status = ICC_OK;
- }
-}
-
-void
-icc_inst_load(struct icc *icc)
-{
- if (icc->status != ICC_OUTPUT) {
- icc_debug_op(icc, "LOAD", 1, 0);
- icc_get_param(icc, 1, &icc->out);
-
- icc->status = ICC_OUTPUT;
- icc_debug_op(icc, "OUTPUT", 0, 0);
- } else {
- icc->instp += 2;
- icc->status = ICC_OK;
- }
-}
-
-void
-icc_inst_jmp_true(struct icc *icc)
-{
- icc_debug_op(icc, "JMPT", 2, 0);
-
- icc_get_param(icc, 1, &icc->r1);
- icc_get_param(icc, 2, &icc->r2);
-
- if (!mi_zero(&icc->r1)) icc->instp = mi_cast_ul(&icc->r2);
- else icc->instp += 3;
-
- icc->status = ICC_OK;}
-
-void
-icc_inst_jmp_false(struct icc *icc)
-{
- icc_debug_op(icc, "JMPF", 2, 0);
-
- icc_get_param(icc, 1, &icc->r1);
- icc_get_param(icc, 2, &icc->r2);
-
- if (mi_zero(&icc->r1)) icc->instp = mi_cast_ul(&icc->r2);
- else icc->instp += 3;
-
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_test_lt(struct icc *icc)
-{
- icc_debug_op(icc, "TLT", 3, 3);
-
- icc_get_param(icc, 1, &icc->r1);
- icc_get_param(icc, 2, &icc->r2);
- icc_get_dest(icc, 3, &icc->r3);
-
- mi_setv(&icc->r4, mi_cmp(&icc->r1, &icc->r2) < 0, MI_POS);
- icc_set_val(icc, mi_cast_ul(&icc->r3), &icc->r4);
-
- icc->instp += 4;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_test_eq(struct icc *icc)
-{
- icc_debug_op(icc, "TEQ", 3, 3);
-
- icc_get_param(icc, 1, &icc->r1);
- icc_get_param(icc, 2, &icc->r2);
- icc_get_dest(icc, 3, &icc->r3);
-
- mi_setv(&icc->r4, mi_cmp(&icc->r1, &icc->r2) == 0, MI_POS);
- icc_set_val(icc, mi_cast_ul(&icc->r3), &icc->r4);
-
- icc->instp += 4;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_base(struct icc *icc)
-{
- icc_debug_op(icc, "BASE", 1, 0);
-
- icc_get_param(icc, 1, &icc->r1);
- mi_add(&icc->base, &icc->r1);
-
- icc->instp += 2;
- icc->status = ICC_OK;
-}
-
-void
-icc_inst_halt(struct icc *icc)
-{
- icc_debug_op(icc, "HALT", 0, 0);
-
- icc->status = ICC_HALT;
-}
-
-void
-icc_step_inst(struct icc *icc)
-{
- inst_t inst;
-
- icc_get_inst(icc, icc->instp, &inst);
- inst %= 100;
-
- switch (inst) {
- case ICC_INST_ADD:
- icc_inst_add(icc);
- break;
- case ICC_INST_MULT:
- icc_inst_mul(icc);
- break;
- case ICC_INST_STORE:
- icc_inst_store(icc);
- break;
- case ICC_INST_LOAD:
- icc_inst_load(icc);
- break;
- case ICC_INST_JMPT:
- icc_inst_jmp_true(icc);
- break;
- case ICC_INST_JMPF:
- icc_inst_jmp_false(icc);
- break;
- case ICC_INST_TLT:
- icc_inst_test_lt(icc);
- break;
- case ICC_INST_TEQ:
- icc_inst_test_eq(icc);
- break;
- case ICC_INST_BASE:
- icc_inst_base(icc);
- break;
- case ICC_INST_HALT:
- icc_inst_halt(icc);
- break;
- default:
- die("ICC: Unknown instruction: '%i'\n", inst);
- }
-}
-
-void
-icc_set_val(struct icc *icc, size_t addr, struct maxint *val)
-{
- struct maxint *v, blank;
- size_t i, len;
-
- len = memvec_len(&icc->instructions);
- if (addr >= len) {
- blank = MI_INIT;
- memvec_resize(&icc->instructions, addr + 1);
- for (i = len; i <= addr; i++)
- memvec_set(&icc->instructions, i, &blank);
- }
- v = memvec_get(&icc->instructions, addr);
- mi_set(v, val);
-}
-
-void
-icc_get_val(struct icc *icc, size_t addr, struct maxint *out)
-{
- struct maxint *src;
-
- if (addr >= memvec_len(&icc->instructions)) {
- mi_setv(out, 0, MI_POS);
- } else {
- src = memvec_get(&icc->instructions, addr);
- mi_set(out, src);
- }
-}
-
-void
-icc_get_inst(struct icc *icc, size_t addr, inst_t *out)
-{
- struct maxint *src;
-
- src = memvec_get(&icc->instructions, addr);
- *out = mi_cast_ul(src);
-}
-
-int
-icc_param_mode(inst_t inst, int param)
-{
- int div, i;
-
- div = 100;
- for (i = 1; i < param; i++) div *= 10;
-
- switch ((inst / div) % 10) {
- case 0:
- return ICC_PARAM_POS;
- case 1:
- return ICC_PARAM_IMM;
- case 2:
- return ICC_PARAM_REL;
- }
-
- die("ICC: Invalid param mode %i\n");
- return -1;
-}
-
-void
-icc_get_param(struct icc *icc, int param, struct maxint *out)
-{
- inst_t inst;
-
- icc_get_inst(icc, icc->instp, &inst);
- switch (icc_param_mode(inst, param)) {
- case ICC_PARAM_IMM:
- icc_get_val(icc, icc->instp + param, out);
- break;
- case ICC_PARAM_POS:
- icc_get_val(icc, icc->instp + param, out);
- icc_get_val(icc, mi_cast_ul(out), out);
- break;
- case ICC_PARAM_REL:
- icc_get_val(icc, icc->instp + param, out);
- mi_add(out, &icc->base);
- icc_get_val(icc, mi_cast_ul(out), out);
- break;
- default:
- die("ICC: Invalid parmeter mode\n");
- };
-}
-
-void
-icc_get_dest(struct icc *icc, int param, struct maxint *out)
-{
- inst_t inst;
-
- icc_get_inst(icc, icc->instp, &inst);
- switch (icc_param_mode(inst, param)) {
- case ICC_PARAM_POS:
- icc_get_val(icc, icc->instp + param, out);
- break;
- case ICC_PARAM_REL:
- icc_get_val(icc, icc->instp + param, out);
- mi_add(out, &icc->base);
- break;
- default:
- die("ICC: Invalid destination parmeter mode\n");
- };
-}
-
-void
-icc_set_debug(struct icc *icc, int debug)
-{
- icc->debug = debug;
-}
-
diff --git a/libs/src/maxint.c b/libs/src/maxint.c
@@ -1,378 +0,0 @@
-#include "maxint.h"
-
-mi_ul mi_one_v = 1;
-struct maxint mi_one = {
- .data = &mi_one_v,
- .size = 1,
- .cap = 1,
- .sign = MI_POS
-};
-
-void
-mi_parse(struct maxint *m, const char *str, const char **end, const char *alph)
-{
- const char *p, *cp;
- struct maxint tmp, base;
- int sign;
-
- sign = MI_POS;
- if (*str == '-') {
- sign = MI_NEG;
- str++;
- } else if (*str == '+')
- str++;
-
- base = MI_INIT;
- mi_setv(&base, strlen(alph), sign);
-
- tmp = MI_INIT;
- mi_setv(m, 0, MI_POS);
- for (p = str; *p && (cp = strchr(alph, *p)); p++) {
- mi_mul(m, &base);
- mi_setv(&tmp, cp - alph, sign);
- mi_add(m, &tmp);
- }
-
- *end = p;
-
- mi_free(&tmp);
- mi_free(&base);
-}
-
-void
-mi_free(struct maxint *m)
-{
- free(m->data);
- m->data = NULL;
- m->size = 0;
- m->cap = 0;
-}
-
-void
-mi_set(struct maxint *m1, const struct maxint *m2)
-{
- mi_resize(m1, m2->size);
- memcpy(m1->data, m2->data, m2->size * MI_ULBYTES);
- m1->sign = m2->sign;
-}
-
-void
-mi_setv(struct maxint *m, mi_ul v, int sign)
-{
- mi_resize(m, 1);
- memcpy(m->data, &v, MI_ULBYTES);
- m->sign = sign;
-}
-
-void
-mi_resize(struct maxint *m, int size)
-{
- if (size > m->cap || size < m->cap - 256) {
- m->cap = MAX(1, size * 2);
- m->data = CHKP(realloc(m->data, m->cap * MI_ULBYTES));
- }
- if (size > m->size) {
- memset(&m->data[m->size], 0, (size - m->size) * MI_ULBYTES);
- }
- m->size = size;
-}
-
-void
-mi_add_internal(struct maxint *m1, const struct maxint *m2, int m2_sign)
-{
- int carry, swapped;
- mi_ul v;
- int i, mbits;
-
- mbits = m2->data[m2->size - 1] >> (MI_ULBITS - 1);
- mbits |= m1->data[m1->size - 1] >> (MI_ULBITS - 1);
- mi_resize(m1, MAX(m1->size, m2->size) + (mbits != 0));
-
- if (m1->sign != m2_sign) {
- for (carry = i = 0; i < m1->size; i++) {
- v = (i < m2->size ? m2->data[i] : 0);
- m1->data[i] -= v + carry;
- carry = m1->data[i] + v + carry < m1->data[i];
- }
-
- if (carry == 1) {
- if (m1->data[0] > 0) {
- m1->data[0]--;
- for (i = 0; i < m1->size; i++)
- m1->data[i] = ~m1->data[i];
- } else {
- for (i = 0; i < m1->size; i++)
- m1->data[i] = ~m1->data[i];
- m1->data[0]++;
- }
- m1->sign ^= 1;
- }
- } else {
- for (carry = i = 0; i < m1->size; i++) {
- v = (i < m2->size ? m2->data[i] : 0);
- m1->data[i] += v + carry;
- carry = m1->data[i] - v - carry > m1->data[i];
- }
- }
-}
-
-void
-mi_add(struct maxint *m1, const struct maxint *m2)
-{
- mi_add_internal(m1, m2, m2->sign);
-}
-
-void
-mi_sub(struct maxint *m1, const struct maxint *m2)
-{
- mi_add_internal(m1, m2, m2->sign ^ 1);
-}
-
-void
-mi_shl(struct maxint *m, uint64_t shift)
-{
- int i, bit;
-
- if (!shift) return;
- mi_resize(m, mi_lastset(m) + 1 + MI_DIVCEIL(shift, MI_ULBITS));
-
- for (i = m->size * MI_ULBITS - 1; i >= 0; i--) {
- m->data[i / MI_ULBITS] &= ~((mi_ul) 1 << (i % MI_ULBITS));
- if (i >= shift) {
- bit = MI_BITA(m->data, MI_ULBITS, i - shift);
- m->data[i / MI_ULBITS] |= (mi_ul) bit << (i % MI_ULBITS);
- }
- }
-}
-
-void
-mi_shr(struct maxint *m, uint64_t shift)
-{
- int i, bit;
-
- if (!shift) return;
-
- for (i = 0; i < m->size * MI_ULBITS; i++) {
- m->data[i / MI_ULBITS] &= ~((mi_ul) 1 << (i % MI_ULBITS));
- if (i + shift < m->size * MI_ULBITS) {
- bit = MI_BITA(m->data, MI_ULBITS, i + shift);
- m->data[i / MI_ULBITS] |= (mi_ul) bit << (i % MI_ULBITS);
- }
- }
-}
-
-void
-mi_mul(struct maxint *m1, const struct maxint *m2)
-{
- struct maxint sum;
- int64_t i;
-
- sum = MI_INIT;
- mi_setv(&sum, 0, MI_POS);
- for (i = m1->size * MI_ULBITS - 1; i >= 0; i--) {
- mi_shl(&sum, 1);
- if (MI_BITA(m1->data, MI_ULBITS, i)) {
- if (m1->sign == MI_POS) mi_add(&sum, m2);
- else mi_sub(&sum, m2);
- }
- }
-
- mi_swap(&sum, m1);
- mi_free(&sum);
-}
-
-void
-mi_div(struct maxint *mul, struct maxint *urem, const struct maxint *div)
-{
- struct maxint orig, irem, one, *rem;
- int i, k;
-
- orig = irem = MI_INIT;
- rem = (urem == NULL) ? &irem : urem;
-
- mi_swap(&orig, mul);
- mi_setv(mul, 0, MI_POS);
- mi_setv(rem, 0, MI_POS);
-
- for (i = 0; i < orig.size * MI_ULBITS; i++) {
- k = orig.size * MI_ULBITS - 1 - i;
- // rem = rem * 2 + [bit set]
- mi_shl(rem, 1);
- if (MI_BITA(orig.data, MI_ULBITS, k))
- mi_add(rem, &mi_one);
-
- // mul = 2 * mul + [rem >= div]
- mi_shl(mul, 1);
- if (mi_cmp(rem, div) >= 0) {
- mi_add(mul, &mi_one);
- mi_sub(rem, div);
- }
- }
-
- if (orig.sign != div->sign)
- mi_sub(rem, div);
- rem->sign = div->sign;
- mul->sign = orig.sign ^ div->sign;
-
- mi_free(&orig);
- if (rem == &irem)
- mi_free(&irem);
-}
-
-void
-mi_swap(struct maxint *m1, struct maxint *m2)
-{
- struct maxint tmp;
-
- memcpy(&tmp, m1, sizeof(struct maxint));
- memcpy(m1, m2, sizeof(struct maxint));
- memcpy(m2, &tmp, sizeof(struct maxint));
-}
-
-int
-mi_cmp(const struct maxint *m1, const struct maxint *m2)
-{
- mi_ul v1, v2;
- int i;
-
- for (i = 0; i < MAX(m1->size, m2->size); i++) {
- v1 = (i >= m1->size ? 0 : m1->data[i]);
- v2 = (i >= m2->size ? 0 : m2->data[i]);
- if (v1 != v2) return v1 > v2 ? 1 : -1;
- }
-
- return 0;
-}
-
-void
-mi_gcd(struct maxint *m1, const struct maxint *m2)
-{
- struct maxint rem, b;
-
- rem = b = MI_INIT;
- mi_setv(&rem, 0, MI_POS);
- mi_set(&b, m2);
-
- do {
- mi_div(m1, &rem, &b);
- mi_swap(m1, &b);
- mi_swap(&b, &rem);
- } while (!mi_zero(&b));
-
- mi_free(&rem);
- mi_free(&b);
-}
-
-void
-mi_lcm(struct maxint *m1, const struct maxint *m2)
-{
- struct maxint lcm;
-
- lcm = MI_INIT;
- mi_set(&lcm, m1);
-
- mi_gcd(m1, m2);
- mi_swap(m1, &lcm);
-
- mi_mul(m1, m2);
- mi_div(m1, NULL, &lcm);
-
- mi_free(&lcm);
-}
-
-int
-mi_lastset(const struct maxint *m1)
-{
- int i;
-
- for (i = m1->size - 1; i >= 0; i--)
- if (m1->data[i] != 0) return i;
-
- return 0;
-}
-
-mi_ul
-mi_cast_ul(const struct maxint *m1)
-{
- assert(mi_lastset(m1) == 0, "MAXINT: Attempted cast on too large value");
- return m1->data[0];
-}
-
-int
-mi_zero(const struct maxint *m1)
-{
- int i;
-
- for (i = 0; i < m1->size; i++)
- if (m1->data[i] != 0) return 0;
-
- return 1;
-}
-
-char *
-mi_convstr(char *alloc, const struct maxint *m, int base_ul, const char *alph)
-{
- struct maxint num, rem, base;
- int i, k, slen, scap;
- char *strbuf, tmp;
- mi_ul rest;
- int carry;
-
- if (base_ul <= 1) return CHKP(strdup(""));
-
- num = rem = base = MI_INIT;
- mi_set(&num, m);
- num.sign = MI_POS;
- mi_setv(&rem, 0, MI_POS);
-
- scap = 16;
- slen = 0;
- strbuf = CHKP(alloc ? realloc(alloc, scap) : malloc(scap));
-
- mi_setv(&base, base_ul, MI_POS);
- do {
- mi_div(&num, &rem, &base);
- rest = mi_cast_ul(&rem);
-
- if (slen + 1 >= scap) {
- scap *= 2;
- strbuf = CHKP(realloc(strbuf, scap));
- }
- strbuf[slen] = alph[rest];
- slen++;
- } while (!mi_zero(&num));
-
- if (m->sign == MI_NEG)
- strbuf[slen++] = '-';
-
- for (i = 0; i < slen / 2; i++) {
- tmp = strbuf[i];
- strbuf[i] = strbuf[slen - 1 - i];
- strbuf[slen - 1 - i] = tmp;
- }
- strbuf[slen] = '\0';
-
- mi_free(&rem);
- mi_free(&num);
- mi_free(&base);
-
- return strbuf;
-}
-
-char *
-mi_hexstr(char *alloc, const struct maxint *m, int cap)
-{
- return mi_convstr(alloc, m, 16, cap ? "0123456789ABCDEF" : "0123456789abcdef");
-}
-
-char *
-mi_decstr(char *alloc, const struct maxint *m)
-{
- return mi_convstr(alloc, m, 10, "0123456789");
-}
-
-char *
-mi_binstr(char *alloc, const struct maxint *m)
-{
- return mi_convstr(alloc, m, 2, "01");
-}
diff --git a/libs/src/memvec.c b/libs/src/memvec.c
@@ -1,83 +0,0 @@
-#include "memvec.h"
-
-int
-memvec_init(struct memvec *v, size_t cap, size_t itemsize)
-{
- if (!cap) cap = 10;
- v->cap = cap * itemsize;
- v->itemsize = itemsize;
- v->len = 0;
- v->data = malloc(v->cap);
-
- return v->data ? OK : FAIL;
-}
-
-void
-memvec_free(struct memvec *v)
-{
- free(v->data);
- v->data = NULL;
-}
-
-void *
-memvec_add(struct memvec *v, void *item)
-{
- void *tmp;
-
- if (v->len == v->cap) {
- v->cap *= 2;
- tmp = realloc(v->data, v->cap);
- if (!tmp) return NULL;
- v->data = tmp;
- }
- memcpy(v->data + v->len, item, v->itemsize);
- v->len += v->itemsize;
-
- return v->data + v->len - v->itemsize;
-}
-
-void *
-memvec_get(struct memvec *v, size_t index)
-{
- return v->data + v->itemsize * index;
-}
-
-void
-memvec_set(struct memvec *v, size_t index, void *item)
-{
- if (!memvec_in_range(v, index))
- die("Index out of range '%i'\n", index);
- memcpy(v->data + v->itemsize * index, item, v->itemsize);
-}
-
-int
-memvec_in_range(struct memvec *v, size_t index)
-{
- return index < v->len / v->itemsize;
-}
-
-size_t
-memvec_len(struct memvec *v)
-{
- return v->len / v->itemsize;
-}
-
-void
-memvec_copy(struct memvec *dst, struct memvec *src)
-{
- dst->itemsize = src->itemsize;
- dst->len = src->len;
- dst->cap = src->cap;
- dst->data = CHKP(malloc(src->cap));
- memcpy(dst->data, src->data, src->cap);
-}
-
-void
-memvec_resize(struct memvec *v, size_t size)
-{
- v->len = size * v->itemsize;
- if (v->len > v->cap || v->len < v->cap - 256) {
- v->cap = v->len;
- v->data = CHKP(realloc(v->data, v->cap));
- }
-}
diff --git a/libs/src/util.c b/libs/src/util.c
@@ -1,117 +0,0 @@
-#include "util.h"
-#include "aoc.h"
-
-void
-die(const char *fmtstr, ...)
-{
- va_list ap;
-
- va_start(ap, fmtstr);
- vprintf(fmtstr, ap);
- va_end(ap);
-
- exit(1);
-}
-
-void
-assert(int res, const char *fmtstr, ...)
-{
- va_list ap;
-
- if (!res) {
- va_start(ap, fmtstr);
- vfprintf(stderr, fmtstr, ap);
- fputc('\n', stderr);
- va_end(ap);
-
- exit(1);
- }
-}
-
-void *
-chkp(void *ptr, const char *fmtstr, ...)
-{
- va_list ap;
-
- if (ptr == NULL) {
- va_start(ap, fmtstr);
- vfprintf(stderr, fmtstr, ap);
- fputc('\n', stderr);
- va_end(ap);
-
- exit(1);
- }
-
- return ptr;
-}
-
-char *
-aprintf(const char *fmtstr, ...)
-{
- va_list ap, cpy;
- size_t nb;
- char *str;
-
- va_copy(cpy, ap);
-
- va_start(cpy, fmtstr);
- nb = vsnprintf(NULL, 0, fmtstr, cpy);
- va_end(cpy);
-
- assert(nb >= 0, "Invalid fmtstr: %s\n");
- str = malloc(nb+1);
- if (!str) return NULL;
-
- va_start(ap, fmtstr);
- nb = vsnprintf(str, nb+1, fmtstr, ap);
- va_end(ap);
-
- return str;
-}
-
-const char *
-ntoken(const char *start, const char *end,
- size_t *len, const char *sep)
-{
- char *tokp;
-
- if ((tokp = strpbrk(start, sep))) {
- *len = tokp - start;
- return tokp + 1;
- } else {
- *len = end - start;
- return NULL;
- }
-}
-
-void *
-memdup(void *data, size_t size)
-{
- void *new;
-
- new = CHKP(malloc(size));
- memcpy(new, data, size);
- return new;
-}
-
-int
-readall(int fileno, void **data, size_t *totalread)
-{
- size_t allocsize = 10, want = allocsize, got;
-
- *data = CHKP(malloc(allocsize));
- *totalread = 0;
-
- while ((got = read(fileno, *data + *totalread, want)) > 0) {
- if (got == want) {
- allocsize *= 2;
- *totalread += got;
- *data = CHKP(realloc(*data, allocsize));
- } else {
- *totalread += got;
- }
- want = allocsize - *totalread;
- }
-
- return (got < 0) ? FAIL : OK;
-}
diff --git a/libs/src/wrapper.c b/libs/src/wrapper.c
@@ -1,51 +0,0 @@
-#include "aoc.h"
-
-struct aoc aoc;
-
-int
-main(int argc, const char **argv)
-{
- const char *envvar;
- FILE *f;
-
- if (argc <= 1) die("Supply the part number to solve\n");
- aoc.args = &argv[2];
-
- /* parse user input */
- envvar = getenv("AOCDEBUG");
- aoc.debug = envvar ? atoi(envvar) : 0;
-
- aoc.inputfile = getenv("AOCINPUT");
- if (!aoc.inputfile) aoc.inputfile = "input";
- else debug("Using input file: '%s'\n", aoc.inputfile);
-
- aoc.part = atoi(argv[1]);
-
- /* read input file */
- if (!(f = fopen(aoc.inputfile, "r")))
- die("Failed to open input file\n");
- if (readall(fileno(f), (void**) &aoc.input, &aoc.input_size) == FAIL)
- die("Failed to read from input file\n");
- fclose(f);
-
- /* add null terminator */
- aoc.input = CHKP(realloc(aoc.input, aoc.input_size + 1));
- aoc.input[aoc.input_size] = '\0';
-
- /* call solution */
- aoc.answer = NULL;
- aoc.solution = NULL;
- if (aoc.part == 1) part1();
- else if (aoc.part == 2) part2();
- else die("Invalid part number\n");
-
- /* check answer if given */
- if (aoc.answer) {
- printf("%s\n", aoc.answer);
- if (aoc.solution && strcmp(aoc.answer, aoc.solution))
- die("\nIncorrect solution!\n");
- }
-
- free(aoc.answer);
- free(aoc.input);
-}
diff --git a/libs/src/wrapper.o b/libs/src/wrapper.o
Binary files differ.
diff --git a/libs/tests/maxint.c b/libs/tests/maxint.c
@@ -1,56 +0,0 @@
-#include "maxint.h"
-
-int
-main()
-{
- struct maxint a, b, c;
- char *s1, *s2;
-
- a = b = c = MI_INIT;
- s1 = s2 = NULL;
-
- mi_setv(&a, 1014, MI_POS);
- mi_setv(&b, 9, MI_NEG);
- printf("ADD: %s + %s = ", (s1 = mi_decstr(s1, &a)), (s2 = mi_decstr(s2, &b)));
- mi_add(&a, &b);
- printf("%s\n", (s1 = mi_decstr(s1, &a)));
-
- mi_setv(&a, 10000000000000000000ULL, MI_POS);
- mi_setv(&b, 10000000000000000000ULL, MI_POS);
- printf("ADD: %s + %s = ", (s1 = mi_decstr(s1, &a)), (s2 = mi_decstr(s2, &b)));
- mi_add(&a, &b);
- printf("%s\n", (s1 = mi_decstr(s1, &a)));
-
- mi_setv(&a, 1, MI_NEG);
- mi_setv(&b, 1, MI_POS);
- printf("MUL: %s * %s = ", (s1 = mi_binstr(s1, &a)), (s2 = mi_decstr(s2, &b)));
- mi_mul(&a, &b);
- printf("%s\n", (s1 = mi_binstr(s1, &a)));
-
- mi_setv(&a, 10000000000000000000ULL, MI_POS);
- printf("SHL: %s << 2 = \n", (s1 = mi_binstr(s1, &a)));
- mi_shl(&a, 2);
- printf("%s\n", (s1 = mi_binstr(s1, &a)));
-
- mi_setv(&a, 10000000000000000000ULL, MI_POS);
- mi_setv(&b, 10000000000000000000ULL, MI_POS);
- printf("%lu * %lu = ..\n", a.data[0], b.data[0]);
- printf("%s * %s = ", (s1 = mi_decstr(s1, &a)), (s2 = mi_decstr(s2, &b)));
- mi_mul(&a, &b);
- printf("%s\n", (s1 = mi_decstr(s1, &a)));
-
- mi_setv(&b, 33, MI_POS);
- printf("%s / %s = ", (s1 = mi_decstr(s1, &a)), (s2 = mi_decstr(s2, &b)));
- mi_div(&a, &c, &b);
- printf("%s R %s\n", (s1 = mi_decstr(s1, &a)), (s2 = mi_decstr(s2, &c)));
-
- printf("DEC: %s\n", (s1 = mi_decstr(s1, &a)));
- printf("HEX: %s\n", (s2 = mi_hexstr(s2, &a, 1)));
-
- free(s1);
- free(s2);
-
- mi_free(&a);
- mi_free(&b);
- mi_free(&c);
-}
diff --git a/src/01/Makefile b/src/01/Makefile
@@ -1,12 +0,0 @@
-CFLAGS = -I ../../libs/include -laoc
-LDLIBS = -L ../../libs/build
-
-all: lib main
-
-clean:
- rm main
-
-lib:
- make -C ../../libs
-
-main: main.c
diff --git a/src/01/main.c b/src/01/main.c
@@ -1,61 +0,0 @@
-#include "aoc.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-void
-part1(void)
-{
- const char *line, *end, *nline;
- char *endp;
- size_t len;
- long long ans, fuel;
-
- line = aoc.input;
- end = aoc.input + aoc.input_size;
-
- endp = NULL;
- ans = 0;
- do {
- nline = ntoken(line, end, &len, "\n");
- if (!len) continue;
- fuel = strtoul(line, &endp, 10) / 3 - 2;
- if (endp && !memchr("\n", *endp, 2))
- die("Failed to parse input '%s' as integer\n", line);
- ans += fuel;
- line = nline;
- } while (nline);
-
- aoc.answer = aprintf("%llu", ans);
- aoc.solution = "3286680";
-}
-
-void
-part2(void)
-{
- const char *line, *end, *nline;
- char *endp;
- size_t len;
- long long ans, fuel;
-
- line = aoc.input;
- end = aoc.input + aoc.input_size;
-
- endp = NULL;
- ans = 0;
- do {
- nline = ntoken(line, end, &len, "\n");
- if (!len) continue;
- fuel = strtoul(line, &endp, 10);
- if (endp && !memchr("\n", *endp, 2))
- die("Failed to parse input '%s' as integer\n", line);
- while ((fuel = fuel / 3 - 2) > 0) {
- ans += fuel;
- }
- line = nline;
- } while (nline);
-
- aoc.answer = aprintf("%llu", ans);
- aoc.solution = "4927158";
-}
diff --git a/src/02/Makefile b/src/02/Makefile
@@ -1,13 +0,0 @@
-CFLAGS = -g -I ../../libs/include -L ../../libs/build
-LDLIBS = -licc -laoc
-
-all: lib main
-
-lib:
- make -C ../../libs
-
-clean:
- rm main
-
-main: main.c ../../libs/build/*
- $(CC) -o $@ $< $(CFLAGS) $(LDLIBS)
diff --git a/src/02/main.c b/src/02/main.c
@@ -1,63 +0,0 @@
-#include "aoc.h"
-#include "icc.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-
-void
-part1(void)
-{
- struct icc icc;
- int res;
-
- ASSERT(icc_init(&icc) == OK);
- ASSERT(icc_parse_inst(&icc, aoc.input, aoc.input_size) == OK);
-
- icc_set_inst(&icc, 1, 12);
- icc_set_inst(&icc, 2, 2);
-
- while (icc.status != ICC_HALT)
- icc_step_inst(&icc);
-
- icc_get_inst(&icc, 0, &res);
- aoc.answer = CHKP(aprintf("%i", res));
- aoc.solution = "5098658";
-
- icc_free(&icc);
-}
-
-void
-part2(void)
-{
- struct icc icc;
- void *instcopy;
- int a, b, c;
-
- ASSERT(icc_init(&icc) == OK);
- ASSERT(icc_parse_inst(&icc, aoc.input, aoc.input_size) == OK);
- instcopy = icc_inst_copy(&icc);
-
- for (a = 0; a < 100; a++) {
- for (b = 0; b < 100; b++) {
- icc_set_inst(&icc, 1, a);
- icc_set_inst(&icc, 2, b);
-
- debug("\nTrying a:%i b:%i\n\n", a, b);
- while (icc.status != ICC_HALT)
- icc_step_inst(&icc);
-
- icc_get_inst(&icc, 0, &c);
- if (c == 19690720) {
- aoc.answer = CHKP(aprintf("%02i%02i", a, b));
- aoc.solution = "5064";
- goto exit;
- } else {
- icc_reset(&icc, instcopy);
- }
- }
- }
-
-exit:
- free(instcopy);
- icc_free(&icc);
-}
diff --git a/src/12/Makefile b/src/12/Makefile
@@ -1,13 +0,0 @@
-CFLAGS = -g -I ../../libs/include -L ../../libs/build
-LDLIBS = -laoc
-
-all: lib main
-
-clean:
- rm main
-
-lib:
- make -C ../../libs
-
-main: main.c ../../libs/build/*
- $(CC) -o $@ $< $(CFLAGS) $(LDLIBS)
diff --git a/src/13/Makefile b/src/13/Makefile
@@ -1,13 +0,0 @@
-CFLAGS = -g -I ../../libs/include -L ../../libs/build
-LDLIBS = -liccmp -laoc
-
-all: lib main
-
-clean:
- rm main
-
-lib:
- make -C ../../libs
-
-main: main.c ../../libs/build/*
- $(CC) -o $@ $< $(CFLAGS) $(LDLIBS)