aoc-2019-c

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

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:
M.gitignore | 1+
M.gitmodules | 14+++++++++++---
A01/info.mk | 2++
Rsrc/01/input -> 01/input | 0
A01/main.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/01/part1 -> 01/part1 | 0
Rsrc/01/part2 -> 01/part2 | 0
A02/info.mk | 3+++
Rsrc/02/input -> 02/input | 0
A02/main.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/02/part1 -> 02/part1 | 0
Rsrc/02/part2 -> 02/part2 | 0
Rsrc/03/Makefile -> 03/Makefile | 0
Rsrc/03/input -> 03/input | 0
Rsrc/03/main.c -> 03/main.c | 0
Rsrc/03/part1 -> 03/part1 | 0
Rsrc/03/part2 -> 03/part2 | 0
Rsrc/03/test1 -> 03/test1 | 0
Rsrc/03/test2 -> 03/test2 | 0
Rsrc/04/Makefile -> 04/Makefile | 0
Rsrc/04/input -> 04/input | 0
Rsrc/04/main.c -> 04/main.c | 0
Rsrc/04/part1 -> 04/part1 | 0
Rsrc/04/part2 -> 04/part2 | 0
Rsrc/04/test.input -> 04/test.input | 0
Rsrc/05/Makefile -> 05/Makefile | 0
Rsrc/05/input -> 05/input | 0
Rsrc/05/main.c -> 05/main.c | 0
Rsrc/05/part1 -> 05/part1 | 0
Rsrc/05/part2 -> 05/part2 | 0
Rsrc/05/test2.input -> 05/test2.input | 0
Rsrc/06/Makefile -> 06/Makefile | 0
Rsrc/06/input -> 06/input | 0
Rsrc/06/main.c -> 06/main.c | 0
Rsrc/06/part1 -> 06/part1 | 0
Rsrc/06/part2 -> 06/part2 | 0
Rsrc/06/test.input -> 06/test.input | 0
Rsrc/06/test.input2 -> 06/test.input2 | 0
Rsrc/07/Makefile -> 07/Makefile | 0
Rsrc/07/input -> 07/input | 0
Rsrc/07/main.c -> 07/main.c | 0
Rsrc/07/part1 -> 07/part1 | 0
Rsrc/07/part2 -> 07/part2 | 0
Rsrc/07/test.input -> 07/test.input | 0
Rsrc/07/test.input2 -> 07/test.input2 | 0
Rsrc/07/test.input3 -> 07/test.input3 | 0
Rsrc/08/Makefile -> 08/Makefile | 0
Rsrc/08/input -> 08/input | 0
Rsrc/08/main.c -> 08/main.c | 0
Rsrc/08/part1 -> 08/part1 | 0
Rsrc/08/part2 -> 08/part2 | 0
Rsrc/09/Makefile -> 09/Makefile | 0
Rsrc/09/input -> 09/input | 0
Rsrc/09/main.c -> 09/main.c | 0
Rsrc/09/part1 -> 09/part1 | 0
Rsrc/09/part2 -> 09/part2 | 0
Rsrc/10/Makefile -> 10/Makefile | 0
Rsrc/10/input -> 10/input | 0
Rsrc/10/main.c -> 10/main.c | 0
Rsrc/10/part1 -> 10/part1 | 0
Rsrc/10/part2 -> 10/part2 | 0
Rsrc/10/test.input -> 10/test.input | 0
Rsrc/11/Makefile -> 11/Makefile | 0
Rsrc/11/input -> 11/input | 0
Rsrc/11/main.c -> 11/main.c | 0
Rsrc/11/part1 -> 11/part1 | 0
Rsrc/11/part2 -> 11/part2 | 0
Rdata/helper/template/Makefile -> 12/Makefile | 0
Rsrc/12/input -> 12/input | 0
Rsrc/12/main.c -> 12/main.c | 0
Rsrc/12/part1 -> 12/part1 | 0
Rsrc/12/part2 -> 12/part2 | 0
Rsrc/12/test.input -> 12/test.input | 0
Rsrc/12/test.input2 -> 12/test.input2 | 0
A13/Makefile | 15+++++++++++++++
Rsrc/13/input -> 13/input | 0
Rsrc/13/main.c -> 13/main.c | 0
Rsrc/13/part1 -> 13/part1 | 0
Rsrc/13/part2 -> 13/part2 | 0
AMakefile | 41+++++++++++++++++++++++++++++++++++++++++
Rdocs/README.md -> README.md | 0
Acommon/aoc.c | 33+++++++++++++++++++++++++++++++++
Acommon/aoc.h | 25+++++++++++++++++++++++++
Acommon/icc.c | 558+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acommon/icc.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acommon/iccmp.c | 439+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acommon/iccmp.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acommon/main.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acommon/util.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acommon/util.h | 29+++++++++++++++++++++++++++++
Ddata/helper/config | 15---------------
Ddata/helper/init.sh | 9---------
Ddata/helper/template/main.c | 16----------------
Dhelper | 1-
Alib/libdvec/.gitignore | 5+++++
Alib/libdvec/LICENSE | 21+++++++++++++++++++++
Alib/libdvec/Makefile | 41+++++++++++++++++++++++++++++++++++++++++
Alib/libdvec/include/dvec.h | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libdvec/libdvec.api | 19+++++++++++++++++++
Alib/libdvec/libdvec.lds | 23+++++++++++++++++++++++
Alib/libdvec/src/dvec.c | 229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libdvec/src/test.c | 32++++++++++++++++++++++++++++++++
Alib/libhashmap/.gitignore | 5+++++
Alib/libhashmap/LICENSE | 21+++++++++++++++++++++
Alib/libhashmap/Makefile | 42++++++++++++++++++++++++++++++++++++++++++
Alib/libhashmap/include/hashmap.h | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libhashmap/libhashmap.api | 15+++++++++++++++
Alib/libhashmap/libhashmap.lds | 17+++++++++++++++++
Alib/libhashmap/src/hashmap.c | 264+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libhashmap/src/test.c | 34++++++++++++++++++++++++++++++++++
Alib/libmaxint/.gitignore | 3+++
Alib/libmaxint/Makefile | 37+++++++++++++++++++++++++++++++++++++
Alib/libmaxint/include/maxint.h | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libmaxint/libmaxint.api | 26++++++++++++++++++++++++++
Alib/libmaxint/libmaxint.lds | 30++++++++++++++++++++++++++++++
Alib/libmaxint/src/maxint.c | 527+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libmaxint/src/test.c | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dlibs/Makefile | 41-----------------------------------------
Dlibs/include/aoc.h | 28----------------------------
Dlibs/include/hashmap.h | 52----------------------------------------------------
Dlibs/include/icc.h | 59-----------------------------------------------------------
Dlibs/include/iccmp.h | 67-------------------------------------------------------------------
Dlibs/include/maxint.h | 71-----------------------------------------------------------------------
Dlibs/include/memvec.h | 21---------------------
Dlibs/include/util.h | 47-----------------------------------------------
Dlibs/src/aoc.c | 27---------------------------
Dlibs/src/hashmap.c | 158-------------------------------------------------------------------------------
Dlibs/src/icc.c | 354-------------------------------------------------------------------------------
Dlibs/src/iccmp.c | 438-------------------------------------------------------------------------------
Dlibs/src/maxint.c | 378-------------------------------------------------------------------------------
Dlibs/src/memvec.c | 83-------------------------------------------------------------------------------
Dlibs/src/util.c | 117-------------------------------------------------------------------------------
Dlibs/src/wrapper.c | 51---------------------------------------------------
Dlibs/src/wrapper.o | 0
Dlibs/tests/maxint.c | 56--------------------------------------------------------
Dsrc/01/Makefile | 12------------
Dsrc/01/main.c | 61-------------------------------------------------------------
Dsrc/02/Makefile | 13-------------
Dsrc/02/main.c | 63---------------------------------------------------------------
Dsrc/12/Makefile | 13-------------
Dsrc/13/Makefile | 13-------------
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)