Compare commits
18 Commits
5d24720761
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| f895accae6 | |||
| 2994837ebc | |||
| d6f3266154 | |||
| 75a8e72093 | |||
| e71c742863 | |||
| f43acb06fe | |||
| e851e48f1e | |||
| af2c148dc1 | |||
| fda2b0d523 | |||
| 1be8a18ccb | |||
| 91f73e2aa5 | |||
| 5b71ad8ed0 | |||
| 511bf09d65 | |||
| 28d44f2bbf | |||
| 4ca5884255 | |||
| 137fd441e1 | |||
| 26dd9df8c7 | |||
| 06816c068c |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
day1
|
*.txt
|
||||||
day1_input
|
*.elf
|
||||||
day1_test
|
*.o
|
||||||
|
blink.log
|
||||||
|
compile_commands.json
|
||||||
|
|||||||
29
Makefile
29
Makefile
@@ -1,4 +1,27 @@
|
|||||||
all: day1
|
FILES = $(wildcard ./*)
|
||||||
|
SRCS = $(filter %.c,$(FILES))
|
||||||
|
BINS = $(SRCS:%.c=%.elf)
|
||||||
|
|
||||||
%: %.c
|
MUSLFILES = $(wildcard ./musl/*)
|
||||||
gcc-tree -o $@ -Wall -Werror -pedantic -D_GNU_SOURCE -std=gnu2y -O3 -g $<
|
MUSLOBJS = $(filter %.o,$(MUSLFILES))
|
||||||
|
|
||||||
|
CFLAGS = -Wall -Werror -pedantic -Wno-unused -std=gnu2y\
|
||||||
|
-O3 -c -g -fno-stack-protector -fno-pie\
|
||||||
|
-fno-semantic-interposition -fno-trapping-math\
|
||||||
|
-march=x86-64 -mprefer-vector-width=128 -mpopcnt -malign-data=compat -malign-stringops
|
||||||
|
|
||||||
|
LFLAGS = -Ttext=C475000 -static -nostdlib -no-pie
|
||||||
|
|
||||||
|
all: $(BINS)
|
||||||
|
|
||||||
|
%.elf: %.o start.o | %.c $(MUSLOBJS)
|
||||||
|
ld -o $@ $(LFLAGS) start.o $< $(MUSLOBJS)
|
||||||
|
|
||||||
|
start.o: start.s
|
||||||
|
nasm -f elf64 -o $@ $<
|
||||||
|
|
||||||
|
%.o: %.c | lib.h
|
||||||
|
gcc-tree -o $@ $(CFLAGS) $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.elf *.o
|
||||||
|
|||||||
91
day0.h
Normal file
91
day0.h
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
|
||||||
|
static
|
||||||
|
ch input[] = {
|
||||||
|
#embed "day0_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
ch test[] = {
|
||||||
|
#embed "day0_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(0x40) static
|
||||||
|
struct {
|
||||||
|
line padstart[4];
|
||||||
|
struct { ch *s; num _extra[7]; };
|
||||||
|
union { line l; struct { ch s[16]; num n; }; } result;
|
||||||
|
line padend;
|
||||||
|
} m;
|
||||||
|
static_assert(offsetof(typeof(m),result) % 64 == 0);
|
||||||
|
static_assert(offsetof(typeof(m),padend) % 64 == 0);
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part1(size_t file_len, ch file[file_len]) {
|
||||||
|
m = (typeof(m)){ };
|
||||||
|
m.s = file;
|
||||||
|
m.result.n = 0;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
do {
|
||||||
|
m.s++;
|
||||||
|
} while (m.s != &file[file_len]);
|
||||||
|
|
||||||
|
return m.result.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part2(size_t file_len, ch file[file_len]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_PART1 0
|
||||||
|
#define RUN_TEST2 0
|
||||||
|
#define RUN_PART2 0
|
||||||
|
|
||||||
|
#define TEST1_EXPECT -1
|
||||||
|
#define TEST2_EXPECT -1
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (num v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (num v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
121
day1.c
121
day1.c
@@ -1,15 +1,58 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdcountof.h>
|
#include <stdcountof.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
char input[] = {
|
#define SYS_write 1
|
||||||
#embed "day1_input"
|
#define SYS_exit_group 231
|
||||||
};
|
|
||||||
|
|
||||||
char test[] = {
|
#define STDOUT_FILENO 1
|
||||||
#embed "day1_test"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
static
|
||||||
|
void write(uint64_t fileno, void *buffer, size_t len) {
|
||||||
|
uint64_t a,d;
|
||||||
|
asm volatile("syscall"
|
||||||
|
:"=a"(a),"=d"(d):"a"(SYS_write),"D"(fileno),"S"(buffer),"d"(len):"memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[noreturn]] static
|
||||||
|
void exit_group() {
|
||||||
|
asm volatile(
|
||||||
|
"syscall\n"
|
||||||
|
"ud2"
|
||||||
|
::"a"(SYS_exit_group),"D"(0));
|
||||||
|
for (;;);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define xstr(s) str(s)
|
||||||
|
#define str(s) #s
|
||||||
|
|
||||||
|
static
|
||||||
|
void print_many_char(size_t len, char chars[len]) {
|
||||||
|
write(STDOUT_FILENO, chars, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define print(string) print_many_char(sizeof(string)-1, string)
|
||||||
|
|
||||||
|
static
|
||||||
|
void printd(unsigned long v) {
|
||||||
|
if (!v) {
|
||||||
|
print("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char buf[32];
|
||||||
|
char *p = buf+32;
|
||||||
|
unsigned count = 0;
|
||||||
|
while (v) {
|
||||||
|
p--;
|
||||||
|
*p = '0' + (v % 10);
|
||||||
|
v /= 10;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
write(STDOUT_FILENO, p, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
unsigned grabnum(const char *s, const char **end) {
|
unsigned grabnum(const char *s, const char **end) {
|
||||||
unsigned r = 0;
|
unsigned r = 0;
|
||||||
for (; *s >= '0' && *s <= '9'; s++)
|
for (; *s >= '0' && *s <= '9'; s++)
|
||||||
@@ -18,6 +61,27 @@ unsigned grabnum(const char *s, const char **end) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DBG 1
|
||||||
|
|
||||||
|
#define RUN_PART1 1
|
||||||
|
#define RUN_PART2 1
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_TEST2 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 3
|
||||||
|
#define TEST2_EXPECT 6
|
||||||
|
|
||||||
|
static
|
||||||
|
char input[] = {
|
||||||
|
#embed "day1_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
char test[] = {
|
||||||
|
#embed "day1_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
unsigned long do_part1(size_t src_len, const char src[src_len]) {
|
unsigned long do_part1(size_t src_len, const char src[src_len]) {
|
||||||
const char *s = src;
|
const char *s = src;
|
||||||
unsigned long count = 0;
|
unsigned long count = 0;
|
||||||
@@ -36,6 +100,7 @@ unsigned long do_part1(size_t src_len, const char src[src_len]) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
unsigned do_part2(size_t src_len, const char src[src_len]) {
|
unsigned do_part2(size_t src_len, const char src[src_len]) {
|
||||||
const char *s = src, *ns = s + 1;
|
const char *s = src, *ns = s + 1;
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
@@ -70,24 +135,40 @@ unsigned do_part2(size_t src_len, const char src[src_len]) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
void run() {
|
||||||
printf("PART 1 TEST: ");
|
#if RUN_TEST1
|
||||||
if (unsigned long v = do_part1(countof(test), test); v != 3) {
|
print("PART 1 TEST: ");
|
||||||
printf("FAILED (got %lu, expected 3)\n", v);
|
if (unsigned long v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
} else {
|
} else {
|
||||||
printf("PASSED\n");
|
print("PASSED\n");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
printf("PART 1 RESULT: %lu\n",
|
#if RUN_PART1
|
||||||
do_part1(countof(input), input));
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
printf("PART 2 TEST: ");
|
#if RUN_TEST2
|
||||||
if (unsigned v = do_part2(countof(test), test); v != 6) {
|
print("PART 2 TEST: ");
|
||||||
printf("FAILED (got %u, expected 6)\n", v);
|
if (unsigned v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
} else {
|
} else {
|
||||||
printf("PASSED\n");
|
print("PASSED\n");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
printf("PART 2 RESULT: %u\n",
|
#if RUN_PART2
|
||||||
do_part2(countof(input), input));
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group();
|
||||||
}
|
}
|
||||||
|
|||||||
296
day2.c
Normal file
296
day2.c
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char input[] = {
|
||||||
|
#embed "day2_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char test[] = {
|
||||||
|
#embed "day2_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct id {
|
||||||
|
size_t len;
|
||||||
|
bcdint v;
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
struct id next_palindrome_part1(struct id s) {
|
||||||
|
if (s.len % 2 == 1) {
|
||||||
|
size_t len = s.len + 1;
|
||||||
|
unsigned high_shift = (len / 2) * 4;
|
||||||
|
|
||||||
|
bcdint high = 1 << (high_shift - 4);
|
||||||
|
|
||||||
|
return (struct id) {
|
||||||
|
.len = len,
|
||||||
|
.v = (high << high_shift) | high
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned high_shift = (s.len / 2) * 4;
|
||||||
|
bcdint low_mask = (1 << high_shift) - 1;
|
||||||
|
|
||||||
|
bcdint high = s.v >> high_shift;
|
||||||
|
bcdint low = s.v & low_mask;
|
||||||
|
|
||||||
|
if (low > high)
|
||||||
|
high = bcdadd(high, 1);
|
||||||
|
|
||||||
|
return (struct id) {
|
||||||
|
.len = s.len,
|
||||||
|
.v = (high << high_shift) | high
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint do_part1(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char *src = file, *tmp;
|
||||||
|
bcdint result = 0;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
do {
|
||||||
|
#if DBG
|
||||||
|
print_watch_ptr(src);
|
||||||
|
print("\t");
|
||||||
|
print(str(src) ":");
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
print(" ");
|
||||||
|
print_hex_char(src[i]);
|
||||||
|
}
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tmp = src;
|
||||||
|
bcdint rs = grabbcd(src, &src);
|
||||||
|
struct id first = {
|
||||||
|
.len = src - tmp,
|
||||||
|
.v = rs
|
||||||
|
};
|
||||||
|
|
||||||
|
src++;
|
||||||
|
|
||||||
|
tmp = src;
|
||||||
|
bcdint re = grabbcd(src, &src);
|
||||||
|
|
||||||
|
src++;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
printh(rs);
|
||||||
|
print(" to ");
|
||||||
|
printh(re);
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct id next = first;
|
||||||
|
do {
|
||||||
|
next = next_palindrome_part1(next);
|
||||||
|
if (next.v <= re) {
|
||||||
|
result = bcdadd(result, next.v);
|
||||||
|
#if DBG
|
||||||
|
print_watch_hex(next.v);
|
||||||
|
print("\t");
|
||||||
|
print_watch_hex(next.len);
|
||||||
|
print("\t");
|
||||||
|
print_watch_hex(result);
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
bcdint tmp = bcdadd(next.v, 1);
|
||||||
|
for (bcdint chk = next.v; chk > 0; chk >>= 4) {
|
||||||
|
if ((chk & 0xF) != 9) goto no_len_change;
|
||||||
|
}
|
||||||
|
next.len++;
|
||||||
|
no_len_change:
|
||||||
|
next.v = tmp;
|
||||||
|
} while (next.v <= re);
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("reached ");
|
||||||
|
printh(re);
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} while (src != &file[file_len]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
struct id next_palindrome_part2(struct id s) {
|
||||||
|
bcdint best = -1;
|
||||||
|
|
||||||
|
for (unsigned i = 2; i <= s.len; i++) {
|
||||||
|
if (s.len % i == 0) {
|
||||||
|
unsigned high_shift = (s.len / i) * 4;
|
||||||
|
|
||||||
|
bcdint high = s.v >> (high_shift * (i - 1));
|
||||||
|
|
||||||
|
for (int j = i - 2; j >= 0; j--) {
|
||||||
|
bcdint low = (s.v >> (high_shift * (j))) & ((1 << high_shift) - 1);
|
||||||
|
|
||||||
|
if (low < high) {
|
||||||
|
break;
|
||||||
|
} else if (low > high) {
|
||||||
|
high = bcdadd(high, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bcdint next = 0;
|
||||||
|
for (unsigned j = 0; j < i; j++) {
|
||||||
|
next |= high << (high_shift * j);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next < best) {
|
||||||
|
best = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best != -1) {
|
||||||
|
return (struct id) {
|
||||||
|
.len = s.len,
|
||||||
|
.v = best
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = s.len + 1;
|
||||||
|
unsigned high_shift = (len / 2) * 4;
|
||||||
|
|
||||||
|
bcdint high = 1 << (high_shift - 4);
|
||||||
|
|
||||||
|
return (struct id) {
|
||||||
|
.len = len,
|
||||||
|
.v = (high << high_shift) | high
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint do_part2(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char *src = file, *tmp;
|
||||||
|
bcdint result = 0;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
do {
|
||||||
|
#if DBG
|
||||||
|
print_watch_ptr(src);
|
||||||
|
print("\t");
|
||||||
|
print(str(src) ":");
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
print(" ");
|
||||||
|
print_hex_char(src[i]);
|
||||||
|
}
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tmp = src;
|
||||||
|
bcdint rs = grabbcd(src, &src);
|
||||||
|
struct id first = {
|
||||||
|
.len = src - tmp,
|
||||||
|
.v = rs
|
||||||
|
};
|
||||||
|
|
||||||
|
src++;
|
||||||
|
|
||||||
|
tmp = src;
|
||||||
|
bcdint re = grabbcd(src, &src);
|
||||||
|
|
||||||
|
src++;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
printh(rs);
|
||||||
|
print(" to ");
|
||||||
|
printh(re);
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct id next = first;
|
||||||
|
do {
|
||||||
|
next = next_palindrome_part2(next);
|
||||||
|
if (next.v <= re) {
|
||||||
|
result = bcdadd(result, next.v);
|
||||||
|
#if DBG
|
||||||
|
print_watch_hex(next.v);
|
||||||
|
print("\t");
|
||||||
|
print_watch_hex(next.len);
|
||||||
|
print("\t");
|
||||||
|
print_watch_hex(result);
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
bcdint tmp = bcdadd(next.v, 1);
|
||||||
|
for (bcdint chk = next.v; chk > 0; chk >>= 4) {
|
||||||
|
if ((chk & 0xF) != 9) goto no_len_change;
|
||||||
|
}
|
||||||
|
next.len++;
|
||||||
|
no_len_change:
|
||||||
|
next.v = tmp;
|
||||||
|
} while (next.v <= re);
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("reached ");
|
||||||
|
printh(re);
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} while (src != &file[file_len]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 0
|
||||||
|
#define RUN_PART1 0
|
||||||
|
#define RUN_TEST2 0
|
||||||
|
#define RUN_PART2 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 0x1227775554l
|
||||||
|
#define TEST2_EXPECT 0x4174379265l
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (bcdint v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printh(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printh(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (bcdint v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printh(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printh(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
130
day2_plasl.c
Normal file
130
day2_plasl.c
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char input[] = {
|
||||||
|
#embed "day2_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char test[] = {
|
||||||
|
#embed "day2_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t ipow(uint64_t a, uint64_t b) {
|
||||||
|
uint64_t m = a;
|
||||||
|
for (;b;b--) m += a;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
uint64_t range(uint64_t start, uint64_t end, uint64_t len) {
|
||||||
|
#if DBG
|
||||||
|
print("==\n");
|
||||||
|
printd(start); print(" "); printd(end); print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((len & 1) == 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t divisor = ipow(10, len / 2);
|
||||||
|
|
||||||
|
uint64_t first = (start + divisor - 1) / divisor;
|
||||||
|
uint64_t second = end / divisor;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
printd(divisor); print("\n");
|
||||||
|
printd(first); print(" "); printd(second); print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64_t r = (((second + first) * (second + 1 - first)) / 2) * divisor;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
printd(r); print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
uint64_t do_part1(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char buffer[65535];
|
||||||
|
memcpy(buffer, file, file_len);
|
||||||
|
size_t size = file_len;
|
||||||
|
buffer[file_len-1] = ',';
|
||||||
|
|
||||||
|
uint64_t out = 0;
|
||||||
|
uint64_t i = 0;
|
||||||
|
|
||||||
|
while (i < size) {
|
||||||
|
#if DBG
|
||||||
|
print("--------------\n");
|
||||||
|
#endif
|
||||||
|
uint64_t startlen = 0, endlen = 0;
|
||||||
|
uint64_t start = grabnum(buffer+i, NULL);
|
||||||
|
|
||||||
|
while (buffer[i] != '-') {
|
||||||
|
i++;
|
||||||
|
startlen++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
|
||||||
|
uint64_t end = grabnum(buffer+i, NULL);
|
||||||
|
|
||||||
|
while (buffer[i] != ',') {
|
||||||
|
i++;
|
||||||
|
endlen++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
printd(startlen); print(" "); printd(start); print((char[]){ 10 });
|
||||||
|
printd(startlen); print(" "); printd(start); print((char[]){ 10 });
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (endlen != startlen) {
|
||||||
|
out += range(start, ipow(10, startlen) - 1, startlen)
|
||||||
|
+ range(ipow(10, startlen), end, endlen);
|
||||||
|
} else {
|
||||||
|
out += range(start, end, startlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print((char[]) { 10 });
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_PART1 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 0x1227775554l
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
volatile uintptr_t s = (uintptr_t)&s;
|
||||||
|
printh(s);
|
||||||
|
print("\n");
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (uint64_t v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
257
day2opt.c
Normal file
257
day2opt.c
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
|
||||||
|
static
|
||||||
|
alignas(0x40) unsigned char input[] = {
|
||||||
|
#embed "day2_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
struct id {
|
||||||
|
size_t len;
|
||||||
|
bcdint v;
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint next_palindrome_len2(bcdint in) {
|
||||||
|
bcdint low = in & 0xF;
|
||||||
|
bcdint high = in >> 4;
|
||||||
|
|
||||||
|
bcdint higher = high + 1;
|
||||||
|
|
||||||
|
bcdint high_pd = 0x11 * high;
|
||||||
|
bcdint higher_pd = 0x11 * higher;
|
||||||
|
|
||||||
|
return low > high ? higher_pd : high_pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint next_palindrome_len3(bcdint in) {
|
||||||
|
bcdint nib0 = in & 0xF;
|
||||||
|
bcdint nib1 = (in >> 4) & 0xF;
|
||||||
|
bcdint high = in >> 8;
|
||||||
|
|
||||||
|
bcdint higher = high + 1;
|
||||||
|
|
||||||
|
bcdint high_pd = 0x111 * high;
|
||||||
|
bcdint higher_pd = 0x111 * higher;
|
||||||
|
|
||||||
|
if (nib1 < high) return high_pd;
|
||||||
|
return nib0 > high ? higher_pd : high_pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint next_palindrome_len4(bcdint in) {
|
||||||
|
bcdint nib0 = in & 0xF;
|
||||||
|
bcdint nib1 = (in >> 4) & 0xF;
|
||||||
|
bcdint nib2 = (in >> 8) & 0xF;
|
||||||
|
bcdint nib3 = in >> 12;
|
||||||
|
|
||||||
|
bcdint nib3er = nib3 + 1;
|
||||||
|
|
||||||
|
bcdint nib3_pd = 0x1111 * nib3;
|
||||||
|
bcdint nib3er_pd = 0x1111 * nib3er;
|
||||||
|
|
||||||
|
bcdint nib10 = in & 0xFF;
|
||||||
|
bcdint nib32 = in >> 8;
|
||||||
|
|
||||||
|
bcdint nib32er = bcdadd(nib32, 1);
|
||||||
|
|
||||||
|
bcdint nib32_pd = 0x0101 * nib32;
|
||||||
|
bcdint nib32er_pd = 0x0101 * nib32er;
|
||||||
|
|
||||||
|
bcdint r = nib3er_pd;
|
||||||
|
if (nib3_pd > in) r = nib3_pd;
|
||||||
|
if (nib32er_pd > in) r = nib32er_pd;
|
||||||
|
if (nib32_pd > in) r = nib32_pd;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint next_palindrome_len6(bcdint in) {
|
||||||
|
bcdint nib0 = in & 0xF;
|
||||||
|
bcdint nib1 = (in >> 4) & 0xF;
|
||||||
|
bcdint nib2 = (in >> 8) & 0xF;
|
||||||
|
bcdint nib3 = (in >> 12) & 0xF;
|
||||||
|
bcdint nib4 = (in >> 16) & 0xF;
|
||||||
|
bcdint nib5 = in >> 20;
|
||||||
|
|
||||||
|
bcdint nib5er = nib5 + 1;
|
||||||
|
|
||||||
|
bcdint nib5_pd = 0x111111 * nib5;
|
||||||
|
bcdint nib5er_pd = 0x111111 * nib5er;
|
||||||
|
|
||||||
|
bcdint nib10 = in & 0xFF;
|
||||||
|
bcdint nib32 = (in >> 8) & 0xFF;
|
||||||
|
bcdint nib54 = in >> 16;
|
||||||
|
|
||||||
|
bcdint nib54er = bcdadd(nib54, 1);
|
||||||
|
|
||||||
|
bcdint nib54_pd = 0x010101 * nib54;
|
||||||
|
bcdint nib54er_pd = 0x010101 * nib54er;
|
||||||
|
|
||||||
|
bcdint nib210 = in & 0xFFF;
|
||||||
|
bcdint nib543 = in >> 12;
|
||||||
|
|
||||||
|
bcdint nib543er = bcdadd(nib543, 1);
|
||||||
|
|
||||||
|
bcdint nib543_pd = 0x001001 * nib543;
|
||||||
|
bcdint nib543er_pd = 0x001001 * nib543er;
|
||||||
|
|
||||||
|
bcdint r = nib5er_pd;
|
||||||
|
if (nib5_pd > in) r = MIN(r,nib5_pd);
|
||||||
|
if (nib54er_pd > in) r = MIN(r,nib54er_pd);
|
||||||
|
if (nib54_pd > in) r = MIN(r,nib54_pd);
|
||||||
|
if (nib543er_pd > in) r = MIN(r,nib543er_pd);
|
||||||
|
if (nib543_pd > in) r = MIN(r,nib543_pd);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint next_palindrome_len8(bcdint in) {
|
||||||
|
bcdint nib0 = in & 0xF;
|
||||||
|
bcdint nib1 = (in >> 4) & 0xF;
|
||||||
|
bcdint nib2 = (in >> 8) & 0xF;
|
||||||
|
bcdint nib3 = (in >> 12) & 0xF;
|
||||||
|
bcdint nib4 = (in >> 16) & 0xF;
|
||||||
|
bcdint nib5 = (in >> 20) & 0xF;
|
||||||
|
bcdint nib6 = (in >> 24) & 0xF;
|
||||||
|
bcdint nib7 = in >> 28;
|
||||||
|
|
||||||
|
bcdint nib7er = nib7 + 1;
|
||||||
|
|
||||||
|
bcdint nib7_pd = 0x11111111 * nib7;
|
||||||
|
bcdint nib7er_pd = 0x11111111 * nib7er;
|
||||||
|
|
||||||
|
bcdint nib10 = in & 0xFF;
|
||||||
|
bcdint nib32 = (in >> 8) & 0xFF;
|
||||||
|
bcdint nib54 = (in >> 16) & 0xFF;
|
||||||
|
bcdint nib76 = in >> 24;
|
||||||
|
|
||||||
|
bcdint nib76er = bcdadd(nib76, 1);
|
||||||
|
|
||||||
|
bcdint nib76_pd = 0x01010101 * nib76;
|
||||||
|
bcdint nib76er_pd = 0x01010101 * nib76er;
|
||||||
|
|
||||||
|
bcdint nib3210 = in & 0xFFFF;
|
||||||
|
bcdint nib7654 = in >> 16;
|
||||||
|
|
||||||
|
bcdint nib7654er = bcdadd(nib7654, 1);
|
||||||
|
|
||||||
|
bcdint nib7654_pd = 0x00010001 * nib7654;
|
||||||
|
bcdint nib7654er_pd = 0x00010001 * nib7654er;
|
||||||
|
|
||||||
|
bcdint r = nib7er_pd;
|
||||||
|
if (nib7_pd > in) r = MIN(r,nib7_pd);
|
||||||
|
if (nib76er_pd > in) r = MIN(r,nib76er_pd);
|
||||||
|
if (nib76_pd > in) r = MIN(r,nib76_pd);
|
||||||
|
if (nib7654er_pd > in) r = MIN(r,nib7654er_pd);
|
||||||
|
if (nib7654_pd > in) r = MIN(r,nib7654_pd);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint next_palindrome_part2(struct id s) {
|
||||||
|
if (s.len == 2) return next_palindrome_len2(s.v);
|
||||||
|
else if (s.len == 3) return next_palindrome_len3(s.v);
|
||||||
|
else if (s.len == 4) return next_palindrome_len4(s.v);
|
||||||
|
else if (s.len == 6) return next_palindrome_len6(s.v);
|
||||||
|
else if (s.len == 8) return next_palindrome_len8(s.v);
|
||||||
|
|
||||||
|
unsigned len = s.len;
|
||||||
|
bcdint in = s.v;
|
||||||
|
|
||||||
|
bcdint best = -1;
|
||||||
|
for (unsigned i = 2; i <= len; i++) {
|
||||||
|
if (len % i == 0) {
|
||||||
|
unsigned high_shift = (len / i) * 4;
|
||||||
|
|
||||||
|
bcdint high = in >> (high_shift * (i - 1));
|
||||||
|
|
||||||
|
for (int j = i - 2; j >= 0; j--) {
|
||||||
|
bcdint low = (in >> (high_shift * (j))) & ((1 << high_shift) - 1);
|
||||||
|
|
||||||
|
if (low < high) {
|
||||||
|
break;
|
||||||
|
} else if (low > high) {
|
||||||
|
high = bcdadd(high, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bcdint next = 0;
|
||||||
|
for (unsigned j = 0; j < i; j++) {
|
||||||
|
next |= high << (high_shift * j);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next < best) {
|
||||||
|
best = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint do_part2(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char *src = file;
|
||||||
|
bcdint result = 0;
|
||||||
|
|
||||||
|
alignas(0x40) struct id ranges[128];
|
||||||
|
size_t range_count = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned char *tmp;
|
||||||
|
bcdint rs = grabbcd(src, &tmp);
|
||||||
|
ranges[range_count * 2 + 0] = (struct id) {
|
||||||
|
.len = tmp - src,
|
||||||
|
.v = rs
|
||||||
|
};
|
||||||
|
src = tmp + 1;
|
||||||
|
|
||||||
|
bcdint re = grabbcd(src, &tmp);
|
||||||
|
ranges[range_count * 2 + 1] = (struct id) {
|
||||||
|
.v = re
|
||||||
|
};
|
||||||
|
src = tmp + 1;
|
||||||
|
|
||||||
|
range_count++;
|
||||||
|
} while (src != &file[file_len]);
|
||||||
|
|
||||||
|
do {
|
||||||
|
range_count--;
|
||||||
|
struct id next = ranges[range_count * 2 + 0];
|
||||||
|
bcdint re = ranges[range_count * 2 + 1].v;
|
||||||
|
do {
|
||||||
|
if (next.len == 1) {
|
||||||
|
next = (struct id) { .len = 2, .v = 0x11 };
|
||||||
|
} else {
|
||||||
|
next.v = next_palindrome_part2(next);
|
||||||
|
}
|
||||||
|
if (next.v <= re) {
|
||||||
|
result = bcdadd(result, next.v);
|
||||||
|
}
|
||||||
|
bcdint tmp = bcdadd(next.v, 1);
|
||||||
|
for (bcdint chk = next.v; chk > 0; chk >>= 4) {
|
||||||
|
if ((chk & 0xF) != 9) goto no_len_change;
|
||||||
|
}
|
||||||
|
next.len++;
|
||||||
|
no_len_change:
|
||||||
|
next.v = tmp;
|
||||||
|
} while (next.v <= re);
|
||||||
|
} while (range_count);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printh(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
125
day3.c
Normal file
125
day3.c
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char input[] = {
|
||||||
|
#embed "day3_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char test_input[] = {
|
||||||
|
#embed "day3_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned long do_part1(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned long result = 0;
|
||||||
|
unsigned char *s = file;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned char n0 = 0, n1 = 0;
|
||||||
|
unsigned char *n0p = NULL;
|
||||||
|
do {
|
||||||
|
if (s[0] > n0) {
|
||||||
|
n0 = s[0];
|
||||||
|
n0p = s;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
} while (s[1] != '\n');
|
||||||
|
s = n0p+1;
|
||||||
|
do {
|
||||||
|
if (s[0] > n1) {
|
||||||
|
n1 = s[0];
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
} while (s[0] != '\n');
|
||||||
|
s++;
|
||||||
|
unsigned n = (n0 - '0') * 10 + (n1 - '0');
|
||||||
|
result += n;
|
||||||
|
} while(s < &file[file_len]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned long do_part2(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned long result = 0;
|
||||||
|
unsigned char *s = file;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned char n[12] = { };
|
||||||
|
unsigned char *np = NULL;
|
||||||
|
for (int i = 0; i < 12; i++) {
|
||||||
|
do {
|
||||||
|
if (s[0] > n[i]) {
|
||||||
|
n[i] = s[0];
|
||||||
|
np = s;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
} while (s[11-i] != '\n');
|
||||||
|
s = np+1;
|
||||||
|
}
|
||||||
|
unsigned long v = 0;
|
||||||
|
for (int i = 0; i < 12; i++) {
|
||||||
|
v = v * 10 + (n[i] - '0');
|
||||||
|
}
|
||||||
|
#if DBG
|
||||||
|
print("got ");
|
||||||
|
printd(v);
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
result += v;
|
||||||
|
while (*s != '\n') s++;
|
||||||
|
s++;
|
||||||
|
} while(s < &file[file_len]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 0
|
||||||
|
#define RUN_PART1 0
|
||||||
|
#define RUN_TEST2 1
|
||||||
|
#define RUN_PART2 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 357
|
||||||
|
#define TEST2_EXPECT 3121910778619l
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (unsigned long v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (unsigned long v = do_part2(countof(test_input), test_input); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
216
day4.c
Normal file
216
day4.c
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char input[] = {
|
||||||
|
#embed "day4_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char test[] = {
|
||||||
|
#embed "day4_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas (0x40) static
|
||||||
|
unsigned char buf[UINT16_MAX];
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned long do_part1(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char *s = file, *d = buf;
|
||||||
|
unsigned long result = 0;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned file_stride;
|
||||||
|
while (*s != '\n') s++;
|
||||||
|
file_stride = s - file + 1;
|
||||||
|
s = file;
|
||||||
|
|
||||||
|
unsigned line_count = file_len / file_stride;
|
||||||
|
|
||||||
|
unsigned line_stride = MAX(file_stride + 1, 0x40);
|
||||||
|
|
||||||
|
memset(d, 0, sizeof(buf));
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
printh(file_stride); print("\n");
|
||||||
|
printh(line_stride * (line_count + 2)); print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
printns(line_stride, d); print("\n");
|
||||||
|
#endif
|
||||||
|
d += line_stride;
|
||||||
|
do {
|
||||||
|
memcpy(d + 1, s, file_stride - 1);
|
||||||
|
#if DBG
|
||||||
|
printns(line_stride, d); print("\n");
|
||||||
|
#endif
|
||||||
|
d += line_stride;
|
||||||
|
s += file_stride;
|
||||||
|
} while (s != &file[file_len]);
|
||||||
|
#if DBG
|
||||||
|
printns(line_stride, d); print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned char *l = buf + line_stride + 1;
|
||||||
|
for (unsigned i = line_count; i; i--) {
|
||||||
|
d = l;
|
||||||
|
for (unsigned j = file_stride - 1; j; j--) {
|
||||||
|
if (*d == '@') {
|
||||||
|
unsigned neighbors = 0
|
||||||
|
+ (*(d - 1 - line_stride) == '@')
|
||||||
|
+ (*(d - 0 - line_stride) == '@')
|
||||||
|
+ (*(d + 1 - line_stride) == '@')
|
||||||
|
+ (*(d - 1 - 0) == '@')
|
||||||
|
+ (*(d + 1 - 0) == '@')
|
||||||
|
+ (*(d - 1 + line_stride) == '@')
|
||||||
|
+ (*(d - 0 + line_stride) == '@')
|
||||||
|
+ (*(d + 1 + line_stride) == '@')
|
||||||
|
+ (*(d - 1 - line_stride) == 'X')
|
||||||
|
+ (*(d - 0 - line_stride) == 'X')
|
||||||
|
+ (*(d + 1 - line_stride) == 'X')
|
||||||
|
+ (*(d - 1 - 0) == 'X')
|
||||||
|
+ (*(d + 1 - 0) == 'X')
|
||||||
|
+ (*(d - 1 + line_stride) == 'X')
|
||||||
|
+ (*(d - 0 + line_stride) == 'X')
|
||||||
|
+ (*(d + 1 + line_stride) == 'X');
|
||||||
|
if (neighbors < 4) {
|
||||||
|
result++;
|
||||||
|
*d = 'X';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d++;
|
||||||
|
}
|
||||||
|
l += line_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned long do_part2(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char *s = file, *d = buf;
|
||||||
|
unsigned long result = 0;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned file_stride;
|
||||||
|
while (*s != '\n') s++;
|
||||||
|
file_stride = s - file + 1;
|
||||||
|
s = file;
|
||||||
|
|
||||||
|
unsigned line_count = file_len / file_stride;
|
||||||
|
|
||||||
|
unsigned line_stride = MAX(file_stride + 1, 0x40);
|
||||||
|
|
||||||
|
memset(d, 0, sizeof(buf));
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
printh(file_stride); print("\n");
|
||||||
|
printh(line_stride * (line_count + 2)); print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
printns(line_stride, d); print("\n");
|
||||||
|
#endif
|
||||||
|
d += line_stride;
|
||||||
|
do {
|
||||||
|
memcpy(d + 1, s, file_stride - 1);
|
||||||
|
#if DBG
|
||||||
|
printns(line_stride, d); print("\n");
|
||||||
|
#endif
|
||||||
|
d += line_stride;
|
||||||
|
s += file_stride;
|
||||||
|
} while (s != &file[file_len]);
|
||||||
|
#if DBG
|
||||||
|
printns(line_stride, d); print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned char *l = buf + line_stride + 1;
|
||||||
|
for (unsigned i = line_count; i; i--) {
|
||||||
|
line_start:
|
||||||
|
d = l;
|
||||||
|
for (unsigned j = file_stride - 1; j; j--) {
|
||||||
|
if (*d == '@') {
|
||||||
|
unsigned neighbors = 0
|
||||||
|
+ (*(d - 1 - line_stride) == '@')
|
||||||
|
+ (*(d - 0 - line_stride) == '@')
|
||||||
|
+ (*(d + 1 - line_stride) == '@')
|
||||||
|
+ (*(d - 1 - 0) == '@')
|
||||||
|
+ (*(d + 1 - 0) == '@')
|
||||||
|
+ (*(d - 1 + line_stride) == '@')
|
||||||
|
+ (*(d - 0 + line_stride) == '@')
|
||||||
|
+ (*(d + 1 + line_stride) == '@');
|
||||||
|
if (neighbors < 4) {
|
||||||
|
(*((volatile unsigned long *)&result))++;
|
||||||
|
*(volatile unsigned char *)d = '.';
|
||||||
|
if (i > line_count-1) {
|
||||||
|
i = line_count;
|
||||||
|
l = buf + line_stride + 1;
|
||||||
|
goto line_start;
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
l -= line_stride * 1;
|
||||||
|
goto line_start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d++;
|
||||||
|
}
|
||||||
|
l += line_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_PART1 0
|
||||||
|
#define RUN_TEST2 1
|
||||||
|
#define RUN_PART2 0
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 13
|
||||||
|
#define TEST2_EXPECT 43
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (unsigned long v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (unsigned long v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
236
day5.c
Normal file
236
day5.c
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
#define PRETTY 1
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char input[] = {
|
||||||
|
#embed "day5_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char test[] = {
|
||||||
|
#embed "day5_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
#if PRETTY
|
||||||
|
struct line {
|
||||||
|
union {
|
||||||
|
unsigned char l[64];
|
||||||
|
struct {
|
||||||
|
unsigned char s[16];
|
||||||
|
unsigned char pad0[4];
|
||||||
|
unsigned char e[16];
|
||||||
|
unsigned char pad1[4];
|
||||||
|
num sv;
|
||||||
|
num ev;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(struct line) == 0x40);
|
||||||
|
#else
|
||||||
|
struct line {
|
||||||
|
num sv;
|
||||||
|
num ev;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
alignas(0x40) static
|
||||||
|
struct line ranges[256];
|
||||||
|
|
||||||
|
static
|
||||||
|
int linecmp(const void *av, const void *bv) {
|
||||||
|
const struct line *a = av;
|
||||||
|
const struct line *b = bv;
|
||||||
|
if (a->sv < b->sv) return -1;
|
||||||
|
else if (a->sv > b->sv) return 1;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned long do_part1(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char *s = file;
|
||||||
|
unsigned long result = 0;
|
||||||
|
|
||||||
|
memset(ranges, 0, sizeof(ranges));
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct line *d = ranges;
|
||||||
|
do {
|
||||||
|
unsigned char *tmp;
|
||||||
|
d->sv = grabbcd(s, &tmp);
|
||||||
|
#if PRETTY
|
||||||
|
memcpy(d->s, s, tmp - s);
|
||||||
|
#endif
|
||||||
|
s = tmp;
|
||||||
|
s++;
|
||||||
|
d->ev = grabbcd(s, &tmp);
|
||||||
|
#if PRETTY
|
||||||
|
memcpy(d->e, s, tmp - s);
|
||||||
|
#endif
|
||||||
|
s = tmp;
|
||||||
|
s++;
|
||||||
|
d++;
|
||||||
|
} while (*s != '\n');
|
||||||
|
|
||||||
|
#if PRETTY
|
||||||
|
size_t range_cnt = d - ranges;
|
||||||
|
qsort(ranges, range_cnt, sizeof(*ranges), linecmp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
d->sv = 0;
|
||||||
|
s++;
|
||||||
|
|
||||||
|
do {
|
||||||
|
bcdint id = grabbcd(s, &s);
|
||||||
|
for (d = ranges; d->sv; d++) {
|
||||||
|
bcdint ds = d->sv;
|
||||||
|
bcdint de = d->ev;
|
||||||
|
if (id >= ds && id <= de) {
|
||||||
|
result++;
|
||||||
|
goto next_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next_id:
|
||||||
|
s++;
|
||||||
|
} while (s != &file[file_len]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned long do_part2(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char *s = file;
|
||||||
|
unsigned long result = 0;
|
||||||
|
|
||||||
|
memset(ranges, 0, sizeof(ranges));
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct line *d = ranges;
|
||||||
|
do {
|
||||||
|
unsigned char *tmp;
|
||||||
|
d->sv = grabbcd(s, &tmp);
|
||||||
|
#if PRETTY
|
||||||
|
snprinth(d->sv, sizeof(d->s), d->s);
|
||||||
|
#endif
|
||||||
|
s = tmp;
|
||||||
|
s++;
|
||||||
|
d->ev = grabbcd(s, &tmp);
|
||||||
|
#if PRETTY
|
||||||
|
snprinth(d->ev, sizeof(d->e), d->e);
|
||||||
|
#endif
|
||||||
|
s = tmp;
|
||||||
|
s++;
|
||||||
|
d++;
|
||||||
|
} while (*s != '\n');
|
||||||
|
|
||||||
|
size_t range_cnt = d - ranges;
|
||||||
|
qsort(ranges, range_cnt, sizeof(*ranges), linecmp);
|
||||||
|
|
||||||
|
d->sv = 0;
|
||||||
|
|
||||||
|
outer:
|
||||||
|
for (struct line *di = ranges; di->sv; di++) {
|
||||||
|
bcdint dis = di->sv;
|
||||||
|
bcdint die = di->ev;
|
||||||
|
if (dis == -1) continue;
|
||||||
|
for (struct line *dj = di+1; dj->sv; dj++) {
|
||||||
|
bcdint djs = dj->sv;
|
||||||
|
bcdint dje = dj->ev;
|
||||||
|
if (djs == -1) continue;
|
||||||
|
if (djs > die) continue outer;
|
||||||
|
if (djs <= die && djs >= dis) {
|
||||||
|
djs = bcdadd(die, 1);
|
||||||
|
}
|
||||||
|
if (djs == dj->sv && dje == dj->ev)
|
||||||
|
continue;
|
||||||
|
if (dje < djs) {
|
||||||
|
#if DBG
|
||||||
|
print("FOR: "); printd(dis); print(" "); printd(die); print("\n");
|
||||||
|
print(" "); printd(dj->sv); print(" "); printd(dj->ev); print("\n");
|
||||||
|
print(" -> "); printd(djs); print(" "); printd(dje); print(" BAD\n");
|
||||||
|
#endif
|
||||||
|
dj->sv = -1;
|
||||||
|
dj->ev = -1;
|
||||||
|
#if PRETTY
|
||||||
|
snprinth(dj->sv, sizeof(dj->s), dj->s);
|
||||||
|
snprinth(dj->ev, sizeof(dj->e), dj->e);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if DBG
|
||||||
|
print("FOR: "); printd(dis); print(" "); printd(die); print("\n");
|
||||||
|
print(" "); printd(dj->sv); print(" "); printd(dj->ev); print("\n");
|
||||||
|
print(" -> "); printd(djs); print(" "); printd(dje); print("\n");
|
||||||
|
#endif
|
||||||
|
dj->sv = djs;
|
||||||
|
dj->ev = dje;
|
||||||
|
#if PRETTY
|
||||||
|
snprinth(dj->sv, sizeof(dj->s), dj->s);
|
||||||
|
snprinth(dj->ev, sizeof(dj->e), dj->e);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct line *di = ranges; di->sv; di++) {
|
||||||
|
if (di->sv == -1) continue;
|
||||||
|
unsigned long dis = bcdtonum(di->sv);
|
||||||
|
unsigned long die = bcdtonum(di->ev);
|
||||||
|
result += die - dis + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_PART1 1
|
||||||
|
#define RUN_TEST2 1
|
||||||
|
#define RUN_PART2 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 3
|
||||||
|
#define TEST2_EXPECT 14
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (unsigned long v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (unsigned long v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
228
day6.c
Normal file
228
day6.c
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
|
||||||
|
static
|
||||||
|
ch input[] = {
|
||||||
|
#embed "day6_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
ch test[] = {
|
||||||
|
#embed "day6_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part1(size_t file_len, ch file[file_len]) {
|
||||||
|
ch *s = file;
|
||||||
|
num result = 0;
|
||||||
|
|
||||||
|
s = memchr(s, '\n', file_len);
|
||||||
|
num stride = s - file;
|
||||||
|
|
||||||
|
s = file;
|
||||||
|
while (*s != '+' && *s != '*') s += stride;
|
||||||
|
num heightb = (s - file);
|
||||||
|
num height = (s - file) / stride;
|
||||||
|
ch *op = s;
|
||||||
|
|
||||||
|
// constructing a pointer more than 1 past the end of an array
|
||||||
|
// is UB, sadly, so we'll use offsets
|
||||||
|
num op_off = op - file;
|
||||||
|
s = file;
|
||||||
|
do {
|
||||||
|
num ledge_off = op_off - heightb;
|
||||||
|
if (s[op_off] == '+') {
|
||||||
|
num a = 0;
|
||||||
|
num rem = height;
|
||||||
|
do {
|
||||||
|
ch *t = s + ledge_off;
|
||||||
|
while (*t < '0') t++;
|
||||||
|
num b = grabnum(t, NULL);
|
||||||
|
a += b;
|
||||||
|
ledge_off += stride;
|
||||||
|
rem--;
|
||||||
|
} while (rem);
|
||||||
|
result += a;
|
||||||
|
} else if (s[op_off] == '*') {
|
||||||
|
num a = 1;
|
||||||
|
num rem = height;
|
||||||
|
do {
|
||||||
|
ch *t = s + ledge_off;
|
||||||
|
while (*t < '0') t++;
|
||||||
|
num b = grabnum(t, NULL);
|
||||||
|
#if DBG
|
||||||
|
if (rem < height) { print("\t*\t"); }
|
||||||
|
printd(b);
|
||||||
|
#endif
|
||||||
|
a *= b;
|
||||||
|
ledge_off += stride;
|
||||||
|
rem--;
|
||||||
|
} while (rem);
|
||||||
|
result += a;
|
||||||
|
#if DBG
|
||||||
|
print("\t= "); printd(a); print("\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if DBG
|
||||||
|
else {
|
||||||
|
print("INVALID OP\n");
|
||||||
|
exit_group(-1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
op_off++;
|
||||||
|
while (op_off < file_len) {
|
||||||
|
if (s[op_off] == '+' || s[op_off] == '*')
|
||||||
|
break;
|
||||||
|
op_off++;
|
||||||
|
}
|
||||||
|
} while (op_off < file_len);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part2(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
ch *s = file;
|
||||||
|
num result = 0;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s = memchr(s, '\n', file_len);
|
||||||
|
num stride = s - file;
|
||||||
|
|
||||||
|
s = file;
|
||||||
|
while (*s != '+' && *s != '*') s += stride;
|
||||||
|
num heightb = (s - file);
|
||||||
|
num height = (s - file) / stride;
|
||||||
|
ch *op = s;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("STRIDE\t"); printd(stride); print("\n");
|
||||||
|
print("HEIGHT\t"); printd(height); print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// constructing a pointer more than 1 past the end of an array
|
||||||
|
// is UB, sadly, so we'll use offsets
|
||||||
|
num fop_off = op - file;
|
||||||
|
num prev_op_off = fop_off + stride - 1;
|
||||||
|
s = file;
|
||||||
|
do {
|
||||||
|
// we don't need to do these in the same order as the example
|
||||||
|
// because both these operations are commutative.
|
||||||
|
// but you know what? we can anyway. for fun. and pretty output
|
||||||
|
num op_off = prev_op_off - 1;
|
||||||
|
while (s[op_off] != '+' && s[op_off] != '*' && s[op_off] != '\n')
|
||||||
|
op_off--;
|
||||||
|
num ledge_off = op_off - heightb;
|
||||||
|
num redge_off = (s[prev_op_off] == '\n' ? -1 : -2) + prev_op_off - heightb;
|
||||||
|
if (s[op_off] == '+') {
|
||||||
|
num a = 0;
|
||||||
|
num rem = redge_off - ledge_off + 1;
|
||||||
|
num frem = rem;
|
||||||
|
do {
|
||||||
|
num b = 0;
|
||||||
|
ch *t = s + redge_off;
|
||||||
|
for (num i = height; i; i--,t+=stride) {
|
||||||
|
if (*t >= '0') {
|
||||||
|
b *= 10;
|
||||||
|
b += *t - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if DBG
|
||||||
|
if (rem < frem) { print("\t+\t"); }
|
||||||
|
printd(b);
|
||||||
|
#endif
|
||||||
|
a += b;
|
||||||
|
redge_off--;
|
||||||
|
rem--;
|
||||||
|
} while (rem);
|
||||||
|
result += a;
|
||||||
|
#if DBG
|
||||||
|
print("\t=\t"); printd(a); print("\n");
|
||||||
|
#endif
|
||||||
|
} else if (s[op_off] == '*') {
|
||||||
|
num a = 1;
|
||||||
|
num rem = redge_off - ledge_off + 1;
|
||||||
|
num frem = rem;
|
||||||
|
do {
|
||||||
|
num b = 0;
|
||||||
|
ch *t = s + redge_off;
|
||||||
|
for (num i = height; i; i--,t+=stride) {
|
||||||
|
if (*t >= '0') {
|
||||||
|
b *= 10;
|
||||||
|
b += *t - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if DBG
|
||||||
|
if (rem < frem) { print("\t*\t"); }
|
||||||
|
printd(b);
|
||||||
|
#endif
|
||||||
|
a *= b;
|
||||||
|
redge_off--;
|
||||||
|
rem--;
|
||||||
|
} while (rem);
|
||||||
|
result += a;
|
||||||
|
#if DBG
|
||||||
|
print("\t=\t"); printd(a); print("\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if DBG
|
||||||
|
else {
|
||||||
|
print("INVALID OP\n");
|
||||||
|
exit_group(-1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
prev_op_off = op_off;
|
||||||
|
} while (prev_op_off != fop_off);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_PART1 1
|
||||||
|
#define RUN_TEST2 1
|
||||||
|
#define RUN_PART2 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 4277556
|
||||||
|
#define TEST2_EXPECT 3263827
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (num v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (num v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
228
day6pretty.c
Normal file
228
day6pretty.c
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
static
|
||||||
|
ch input[] = {
|
||||||
|
#embed "day6_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
ch test[] = {
|
||||||
|
#embed "day6_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct { ch l[64]; } line;
|
||||||
|
static_assert(sizeof(line) == 0x40);
|
||||||
|
|
||||||
|
alignas(0x40) static
|
||||||
|
struct {
|
||||||
|
line padstart[4];
|
||||||
|
struct { num pad[3]; num prev_op_off, op_off, ledge_off, redge_off, rem; };
|
||||||
|
union { line l; struct { ch s[16]; num op, pad0, pad1, v; }; } b;
|
||||||
|
union { line l; struct { ch s[16], pad0, sr[16], pad1; num v, vr; }; } a;
|
||||||
|
line padend;
|
||||||
|
} m;
|
||||||
|
static_assert(offsetof(typeof(m),b) % 64 == 0);
|
||||||
|
static_assert(sizeof(m.b) == 64);
|
||||||
|
static_assert(sizeof(m.a) == 64);
|
||||||
|
static_assert(offsetof(typeof(m),padend) % 64 == 0);
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part1(size_t file_len, ch file[file_len]) {
|
||||||
|
ch *s = file;
|
||||||
|
m = (typeof(m)){ };
|
||||||
|
|
||||||
|
s = memchr(s, '\n', file_len);
|
||||||
|
const num stride = s - file;
|
||||||
|
|
||||||
|
s = file;
|
||||||
|
while (*s != '+' && *s != '*') s += stride;
|
||||||
|
const num heightb = (s - file);
|
||||||
|
const num height = (s - file) / stride;
|
||||||
|
ch *const op = s;
|
||||||
|
|
||||||
|
// constructing a pointer more than 1 past the end of an array
|
||||||
|
// is UB, sadly, so we'll use offsets
|
||||||
|
m.op_off = op - file;
|
||||||
|
s = file;
|
||||||
|
do {
|
||||||
|
m.ledge_off = m.op_off - heightb;
|
||||||
|
if (s[m.op_off] == '+') {
|
||||||
|
m.a.v = 0;
|
||||||
|
m.rem = height;
|
||||||
|
m.b.op = '+' << 8;
|
||||||
|
snprintd(m.a.v, 16, m.a.s);
|
||||||
|
do {
|
||||||
|
ch *t = s + m.ledge_off;
|
||||||
|
while (*t < '0') t++;
|
||||||
|
m.b.v = grabnum(t, NULL);
|
||||||
|
snprintd(m.b.v, 16, m.b.s);
|
||||||
|
m.a.v += m.b.v;
|
||||||
|
snprintd(m.a.v, 16, m.a.s);
|
||||||
|
m.ledge_off += stride;
|
||||||
|
m.rem--;
|
||||||
|
} while (m.rem);
|
||||||
|
m.a.vr += m.a.v;
|
||||||
|
snprintd(m.a.vr, 16, m.a.sr);
|
||||||
|
} else if (s[m.op_off] == '*') {
|
||||||
|
m.a.v = 1;
|
||||||
|
m.rem = height;
|
||||||
|
m.b.op = '*' << 8;
|
||||||
|
snprintd(m.a.v, 16, m.a.s);
|
||||||
|
do {
|
||||||
|
ch *t = s + m.ledge_off;
|
||||||
|
while (*t < '0') t++;
|
||||||
|
m.b.v = grabnum(t, NULL);
|
||||||
|
snprintd(m.b.v, 16, m.b.s);
|
||||||
|
m.a.v *= m.b.v;
|
||||||
|
snprintd(m.a.v, 16, m.a.s);
|
||||||
|
m.ledge_off += stride;
|
||||||
|
m.rem--;
|
||||||
|
} while (m.rem);
|
||||||
|
m.a.vr += m.a.v;
|
||||||
|
snprintd(m.a.vr, 16, m.a.sr);
|
||||||
|
}
|
||||||
|
m.op_off++;
|
||||||
|
while (m.op_off < file_len) {
|
||||||
|
if (s[m.op_off] == '+' || s[m.op_off] == '*')
|
||||||
|
break;
|
||||||
|
m.op_off++;
|
||||||
|
}
|
||||||
|
} while (m.op_off < file_len);
|
||||||
|
|
||||||
|
return m.a.vr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part2(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
ch *s = file;
|
||||||
|
m = (typeof(m)){ };
|
||||||
|
|
||||||
|
s = memchr(s, '\n', file_len);
|
||||||
|
const num stride = s - file;
|
||||||
|
|
||||||
|
s = file;
|
||||||
|
while (*s != '+' && *s != '*') s += stride;
|
||||||
|
const num heightb = (s - file);
|
||||||
|
const num height = (s - file) / stride;
|
||||||
|
ch *const op = s;
|
||||||
|
|
||||||
|
// constructing a pointer more than 1 past the end of an array
|
||||||
|
// is UB, sadly, so we'll use offsets
|
||||||
|
const num fop_off = op - file;
|
||||||
|
m.prev_op_off = fop_off + stride - 1;
|
||||||
|
s = file;
|
||||||
|
do {
|
||||||
|
// we don't need to do these in the same order as the example
|
||||||
|
// because both these operations are commutative.
|
||||||
|
// but you know what? we can anyway. for fun. and pretty output
|
||||||
|
{
|
||||||
|
num op_off = m.prev_op_off - 1;
|
||||||
|
while (s[op_off] != '+' && s[op_off] != '*' && s[op_off] != '\n')
|
||||||
|
op_off--;
|
||||||
|
m.op_off = op_off;
|
||||||
|
}
|
||||||
|
m.ledge_off = m.op_off - heightb;
|
||||||
|
m.redge_off = (s[m.prev_op_off] == '\n' ? -1 : -2) + m.prev_op_off - heightb;
|
||||||
|
if (s[m.op_off] == '+') {
|
||||||
|
m.a.v = 0;
|
||||||
|
m.rem = m.redge_off - m.ledge_off + 1;
|
||||||
|
const num frem = m.rem;
|
||||||
|
|
||||||
|
m.b.op = '+' << 8;
|
||||||
|
snprintd(m.a.v, 16, m.a.s);
|
||||||
|
|
||||||
|
do {
|
||||||
|
m.b.v = 0;
|
||||||
|
ch *t = s + m.redge_off;
|
||||||
|
for (num i = height; i; i--,t+=stride) {
|
||||||
|
if (*t >= '0') {
|
||||||
|
m.b.v *= 10;
|
||||||
|
m.b.v += *t - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snprintd(m.b.v, 16, m.b.s);
|
||||||
|
m.a.v += m.b.v;
|
||||||
|
snprintd(m.a.v, 16, m.a.s);
|
||||||
|
m.redge_off--;
|
||||||
|
m.rem--;
|
||||||
|
} while (m.rem);
|
||||||
|
m.a.vr += m.a.v;
|
||||||
|
snprintd(m.a.vr, 16, m.a.sr);
|
||||||
|
} else if (s[m.op_off] == '*') {
|
||||||
|
m.a.v = 1;
|
||||||
|
m.rem = m.redge_off - m.ledge_off + 1;
|
||||||
|
const num frem = m.rem;
|
||||||
|
|
||||||
|
m.b.op = '*' << 8;
|
||||||
|
snprintd(m.a.v, 16, m.a.s);
|
||||||
|
|
||||||
|
do {
|
||||||
|
m.b.v = 0;
|
||||||
|
ch *t = s + m.redge_off;
|
||||||
|
for (num i = height; i; i--,t+=stride) {
|
||||||
|
if (*t >= '0') {
|
||||||
|
m.b.v *= 10;
|
||||||
|
m.b.v += *t - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snprintd(m.b.v, 16, m.b.s);
|
||||||
|
m.a.v *= m.b.v;
|
||||||
|
snprintd(m.a.v, 16, m.a.s);
|
||||||
|
m.redge_off--;
|
||||||
|
m.rem--;
|
||||||
|
} while (m.rem);
|
||||||
|
m.a.vr += m.a.v;
|
||||||
|
snprintd(m.a.vr, 16, m.a.sr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.prev_op_off = m.op_off;
|
||||||
|
} while (m.prev_op_off != fop_off);
|
||||||
|
|
||||||
|
return m.a.vr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_PART1 1
|
||||||
|
#define RUN_TEST2 1
|
||||||
|
#define RUN_PART2 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 4277556
|
||||||
|
#define TEST2_EXPECT 3263827
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (num v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (num v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
178
day7.c
Normal file
178
day7.c
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
|
||||||
|
static
|
||||||
|
ch input[32768] = {
|
||||||
|
#embed "day7_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
ch test[512] = {
|
||||||
|
#embed "day7_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct { ch l[64]; } line;
|
||||||
|
static_assert(sizeof(line) == 0x40);
|
||||||
|
|
||||||
|
alignas(0x40) static
|
||||||
|
struct {
|
||||||
|
line padstart[4];
|
||||||
|
num file_stride;
|
||||||
|
num stride;
|
||||||
|
num _extra[6];
|
||||||
|
union { line l; struct { ch s[16]; num n; }; } result;
|
||||||
|
line padend;
|
||||||
|
} m;
|
||||||
|
static_assert(offsetof(typeof(m),result) % 64 == 0);
|
||||||
|
static_assert(offsetof(typeof(m),padend) % 64 == 0);
|
||||||
|
|
||||||
|
alignas(4096) ch buf1[256];
|
||||||
|
alignas(4096) num buf[256];
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part1(size_t file_len, ch file[file_len]) {
|
||||||
|
m = (typeof(m)){ };
|
||||||
|
m.result.n = 0;
|
||||||
|
#if DBG
|
||||||
|
pnl();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memset(buf1, 0, sizeof(buf1));
|
||||||
|
|
||||||
|
m.file_stride = findc(file, '\n', file_len) - file;
|
||||||
|
num linecnt = (findc(file, 0, file_len) - file) / m.file_stride;
|
||||||
|
#if DBG
|
||||||
|
print("stride "); printd(m.file_stride); pnl();
|
||||||
|
print("lines "); printd(linecnt); pnl();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
num s_pos = findc(file, 'S', - 1) - 1 - file;
|
||||||
|
buf1[s_pos] = '|';
|
||||||
|
num line = 2;
|
||||||
|
do {
|
||||||
|
ch *l = file + line * m.file_stride;
|
||||||
|
for (num col = 0; col < m.file_stride - 1; col++) {
|
||||||
|
ch c = l[col];
|
||||||
|
if (c == '^') {
|
||||||
|
m.result.n += buf1[col] > 0;
|
||||||
|
buf1[col-1] |= buf1[col];
|
||||||
|
buf1[col+1] |= buf1[col];
|
||||||
|
buf1[col] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if DBG
|
||||||
|
for (num col = 0; col < m.file_stride; col++) {
|
||||||
|
if (buf1[col] == '|') print("|");
|
||||||
|
else if (l[col] == '^') print("^");
|
||||||
|
else print(" ");
|
||||||
|
}
|
||||||
|
pnl();
|
||||||
|
#endif
|
||||||
|
line+=2;
|
||||||
|
} while (line < linecnt);
|
||||||
|
|
||||||
|
return m.result.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part2(size_t file_len, ch file[file_len]) {
|
||||||
|
m = (typeof(m)){ };
|
||||||
|
#if DBG
|
||||||
|
pnl();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
m.file_stride = findc(file, '\n', file_len) - file;
|
||||||
|
num linecnt = (findc(file, 0, file_len) - file) / m.file_stride;
|
||||||
|
#if DBG
|
||||||
|
print("stride "); printd(m.file_stride); pnl();
|
||||||
|
print("lines "); printd(linecnt); pnl();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
num s_pos = findc(file, 'S', - 1) - 1 - file;
|
||||||
|
buf[s_pos] = 1;
|
||||||
|
num line = 2;
|
||||||
|
do {
|
||||||
|
ch *l = file + line * m.file_stride;
|
||||||
|
for (num col = 0; col < m.file_stride - 1; col++) {
|
||||||
|
ch c = l[col];
|
||||||
|
if (c == '^') {
|
||||||
|
buf[col-1] += buf[col];
|
||||||
|
buf[col+1] += buf[col];
|
||||||
|
buf[col] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (num col = 0; col < m.file_stride; col++) {
|
||||||
|
num v = buf[col];
|
||||||
|
#if DBG
|
||||||
|
if (l[col] == '^') print(" ");
|
||||||
|
else if (v >> 32) print("█");
|
||||||
|
else if (v >> 16) print("▓");
|
||||||
|
else if (v >> 8) print("▒");
|
||||||
|
else if (v >> 4) print("░");
|
||||||
|
else if (v >> 2) print("-");
|
||||||
|
else if (v >> 0) print(".");
|
||||||
|
else print(" ");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if DBG
|
||||||
|
pnl();
|
||||||
|
#endif
|
||||||
|
line+=2;
|
||||||
|
} while (line < linecnt);
|
||||||
|
|
||||||
|
m.result.n = 0;
|
||||||
|
for (num col = 0; col < m.file_stride; col++) {
|
||||||
|
m.result.n += buf[col];
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.result.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_PART1 1
|
||||||
|
#define RUN_TEST2 1
|
||||||
|
#define RUN_PART2 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 21
|
||||||
|
#define TEST2_EXPECT 40
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (num v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (num v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
317
day8.c
Normal file
317
day8.c
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
|
||||||
|
static
|
||||||
|
ch input[] = {
|
||||||
|
#embed "day8_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
ch test[] = {
|
||||||
|
#embed "day8_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef num point __attribute__((vector_size(4*sizeof(num))));
|
||||||
|
|
||||||
|
alignas(64) static
|
||||||
|
point positions[1000];
|
||||||
|
|
||||||
|
alignas(64) static
|
||||||
|
unsigned short circuits[1000];
|
||||||
|
|
||||||
|
alignas(1024) static
|
||||||
|
struct { num min_dist; unsigned short min_target; } targets[1000][1024];
|
||||||
|
|
||||||
|
alignas(64) static
|
||||||
|
unsigned short next_targets[1000];
|
||||||
|
|
||||||
|
alignas(64) static
|
||||||
|
num next_dists[1000];
|
||||||
|
|
||||||
|
alignas(64) static
|
||||||
|
unsigned short next_indices[1000];
|
||||||
|
|
||||||
|
static
|
||||||
|
int targetcompar(const void *a, const void *b) {
|
||||||
|
const num ad = ((typeof(**targets)*)a)->min_dist;
|
||||||
|
const num bd = ((typeof(**targets)*)b)->min_dist;
|
||||||
|
if (ad > bd) return 1;
|
||||||
|
else if (ad < bd) return -1;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part1(size_t file_len, ch file[file_len], bool istest) {
|
||||||
|
const num iters = istest ? 10 : 1000;
|
||||||
|
const num pointcount = istest ? 20 : 1000;
|
||||||
|
num iter = 0;
|
||||||
|
#if DBG
|
||||||
|
pnl();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// read in positions from file
|
||||||
|
{ ch *s = file;
|
||||||
|
for (num i = 0; i < pointcount; i++) {
|
||||||
|
unsigned x = grabnum(s, &s);
|
||||||
|
s++;
|
||||||
|
unsigned y = grabnum(s, &s);
|
||||||
|
s++;
|
||||||
|
unsigned z = grabnum(s, &s);
|
||||||
|
s++;
|
||||||
|
positions[i] = (point){ x,y,z };
|
||||||
|
} }
|
||||||
|
// set up initial circuits
|
||||||
|
for (num i = 0; i < pointcount; i += 4) {
|
||||||
|
circuits[i+0] = i+0;
|
||||||
|
circuits[i+1] = i+1;
|
||||||
|
circuits[i+2] = i+2;
|
||||||
|
circuits[i+3] = i+3;
|
||||||
|
}
|
||||||
|
// find distances between all points
|
||||||
|
for (num i = 0; i < pointcount; i++) {
|
||||||
|
point pi = positions[i];
|
||||||
|
for (num j = 0; j < pointcount; j += 4) {
|
||||||
|
point pj0 = positions[j+0];
|
||||||
|
point pj1 = positions[j+1];
|
||||||
|
point pj2 = positions[j+2];
|
||||||
|
point pj3 = positions[j+3];
|
||||||
|
|
||||||
|
point dvp0 = (pi - pj0) * (pi - pj0);
|
||||||
|
point dvp1 = (pi - pj1) * (pi - pj1);
|
||||||
|
point dvp2 = (pi - pj2) * (pi - pj2);
|
||||||
|
point dvp3 = (pi - pj3) * (pi - pj3);
|
||||||
|
|
||||||
|
num d0 = dvp0[0] + dvp0[1] + dvp0[2] + dvp0[3];
|
||||||
|
num d1 = dvp1[0] + dvp1[1] + dvp1[2] + dvp1[3];
|
||||||
|
num d2 = dvp2[0] + dvp2[1] + dvp2[2] + dvp2[3];
|
||||||
|
num d3 = dvp3[0] + dvp3[1] + dvp3[2] + dvp3[3];
|
||||||
|
|
||||||
|
targets[i][j+0] = (typeof(**targets)) { d0, j+0 };
|
||||||
|
targets[i][j+1] = (typeof(**targets)) { d1, j+1 };
|
||||||
|
targets[i][j+2] = (typeof(**targets)) { d2, j+2 };
|
||||||
|
targets[i][j+3] = (typeof(**targets)) { d3, j+3 };
|
||||||
|
}
|
||||||
|
// sort targets. slow.
|
||||||
|
qsort(targets[i], pointcount, sizeof(**targets), targetcompar);
|
||||||
|
}
|
||||||
|
// set up initial next targets
|
||||||
|
for (num i = 0; i < pointcount; i++) {
|
||||||
|
next_targets[i] = targets[i][1].min_target;
|
||||||
|
next_dists[i] = targets[i][1].min_dist;
|
||||||
|
next_indices[i] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXED JOIN ITERATIONS
|
||||||
|
do {
|
||||||
|
// find min dist
|
||||||
|
num min_dist = -1;
|
||||||
|
num min_i = 0;
|
||||||
|
for (num i = 0; i < pointcount; i++)
|
||||||
|
if (next_dists[i] < min_dist)
|
||||||
|
min_dist = next_dists[min_i = i];
|
||||||
|
num min_j = next_targets[min_i];
|
||||||
|
// -- join the pair --
|
||||||
|
#if DBG
|
||||||
|
point ipos = positions[min_i];
|
||||||
|
point jpos = positions[min_j];
|
||||||
|
printd(ipos[0]); print(","); printd(ipos[1]); print(","); printd(ipos[2]);
|
||||||
|
print("\t->\t");
|
||||||
|
printd(jpos[0]); print(","); printd(jpos[1]); print(","); printd(jpos[2]);
|
||||||
|
pnl();
|
||||||
|
#endif
|
||||||
|
// update circuits
|
||||||
|
unsigned old_circuit = circuits[min_j];
|
||||||
|
unsigned new_circuit = circuits[min_i];
|
||||||
|
if (old_circuit != new_circuit) {
|
||||||
|
for (num c = 0; c < pointcount; c++)
|
||||||
|
if (circuits[c] == old_circuit)
|
||||||
|
circuits[c] = new_circuit;
|
||||||
|
}
|
||||||
|
// update targets
|
||||||
|
unsigned niidx = ++next_indices[min_i];
|
||||||
|
unsigned njidx = ++next_indices[min_j];
|
||||||
|
next_targets[min_i] = targets[min_i][niidx].min_target;
|
||||||
|
next_targets[min_j] = targets[min_j][njidx].min_target;
|
||||||
|
next_dists[min_i] = targets[min_i][niidx].min_dist;
|
||||||
|
next_dists[min_j] = targets[min_j][njidx].min_dist;
|
||||||
|
|
||||||
|
iter++;
|
||||||
|
} while(iter < iters);
|
||||||
|
|
||||||
|
// reuse next_targets to store circuit counts
|
||||||
|
for (num i = 0; i < pointcount; i++) {
|
||||||
|
next_targets[i] = 0;
|
||||||
|
}
|
||||||
|
for (num i = 0; i < pointcount; i++) {
|
||||||
|
next_targets[circuits[i]]++;
|
||||||
|
}
|
||||||
|
num circ0 = 0, circ1 = 0, circ2 = 0;
|
||||||
|
for (num i = 0; i < pointcount; i++) {
|
||||||
|
if (next_targets[i] > circ0) {
|
||||||
|
circ2 = circ1;
|
||||||
|
circ1 = circ0;
|
||||||
|
circ0 = next_targets[i];
|
||||||
|
} else if (next_targets[i] > circ1) {
|
||||||
|
circ2 = circ1;
|
||||||
|
circ1 = next_targets[i];
|
||||||
|
} else if (next_targets[i] > circ2) {
|
||||||
|
circ2 = next_targets[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return circ0 * circ1 * circ2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
num do_part2(size_t file_len, ch file[file_len], bool istest) {
|
||||||
|
const num pointcount = istest ? 20 : 1000;
|
||||||
|
#if DBG
|
||||||
|
pnl();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// read in positions from file
|
||||||
|
{ ch *s = file;
|
||||||
|
for (num i = 0; i < pointcount; i++) {
|
||||||
|
unsigned x = grabnum(s, &s);
|
||||||
|
s++;
|
||||||
|
unsigned y = grabnum(s, &s);
|
||||||
|
s++;
|
||||||
|
unsigned z = grabnum(s, &s);
|
||||||
|
s++;
|
||||||
|
positions[i] = (point){ x,y,z };
|
||||||
|
} }
|
||||||
|
// set up initial circuits
|
||||||
|
for (num i = 0; i < pointcount; i += 4) {
|
||||||
|
circuits[i+0] = i+0;
|
||||||
|
circuits[i+1] = i+1;
|
||||||
|
circuits[i+2] = i+2;
|
||||||
|
circuits[i+3] = i+3;
|
||||||
|
}
|
||||||
|
// find distances between all points
|
||||||
|
for (num i = 0; i < pointcount; i++) {
|
||||||
|
point pi = positions[i];
|
||||||
|
for (num j = 0; j < pointcount; j += 4) {
|
||||||
|
point pj0 = positions[j+0];
|
||||||
|
point pj1 = positions[j+1];
|
||||||
|
point pj2 = positions[j+2];
|
||||||
|
point pj3 = positions[j+3];
|
||||||
|
|
||||||
|
point dvp0 = (pi - pj0) * (pi - pj0);
|
||||||
|
point dvp1 = (pi - pj1) * (pi - pj1);
|
||||||
|
point dvp2 = (pi - pj2) * (pi - pj2);
|
||||||
|
point dvp3 = (pi - pj3) * (pi - pj3);
|
||||||
|
|
||||||
|
num d0 = dvp0[0] + dvp0[1] + dvp0[2] + dvp0[3];
|
||||||
|
num d1 = dvp1[0] + dvp1[1] + dvp1[2] + dvp1[3];
|
||||||
|
num d2 = dvp2[0] + dvp2[1] + dvp2[2] + dvp2[3];
|
||||||
|
num d3 = dvp3[0] + dvp3[1] + dvp3[2] + dvp3[3];
|
||||||
|
|
||||||
|
targets[i][j+0] = (typeof(**targets)) { d0, j+0 };
|
||||||
|
targets[i][j+1] = (typeof(**targets)) { d1, j+1 };
|
||||||
|
targets[i][j+2] = (typeof(**targets)) { d2, j+2 };
|
||||||
|
targets[i][j+3] = (typeof(**targets)) { d3, j+3 };
|
||||||
|
}
|
||||||
|
// sort targets. slow.
|
||||||
|
qsort(targets[i], pointcount, sizeof(**targets), targetcompar);
|
||||||
|
}
|
||||||
|
// set up initial next targets
|
||||||
|
for (num i = 0; i < pointcount; i++) {
|
||||||
|
next_targets[i] = targets[i][1].min_target;
|
||||||
|
next_dists[i] = targets[i][1].min_dist;
|
||||||
|
next_indices[i] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned last_i = 0, last_j = 0;
|
||||||
|
// main iterations
|
||||||
|
do {
|
||||||
|
// find min dist
|
||||||
|
num min_dist = -1;
|
||||||
|
num min_i = 0;
|
||||||
|
for (num i = 0; i < pointcount; i++)
|
||||||
|
if (next_dists[i] < min_dist)
|
||||||
|
min_dist = next_dists[min_i = i];
|
||||||
|
num min_j = next_targets[min_i];
|
||||||
|
last_i = min_i;
|
||||||
|
last_j = min_j;
|
||||||
|
// -- join the pair --
|
||||||
|
#if DBG
|
||||||
|
point ipos = positions[min_i];
|
||||||
|
point jpos = positions[min_j];
|
||||||
|
printd(ipos[0]); print(","); printd(ipos[1]); print(","); printd(ipos[2]);
|
||||||
|
print("\t->\t");
|
||||||
|
printd(jpos[0]); print(","); printd(jpos[1]); print(","); printd(jpos[2]);
|
||||||
|
pnl();
|
||||||
|
#endif
|
||||||
|
// update circuits
|
||||||
|
unsigned old_circuit = circuits[min_j];
|
||||||
|
unsigned new_circuit = circuits[min_i];
|
||||||
|
if (old_circuit != new_circuit) {
|
||||||
|
bool done = true;
|
||||||
|
for (num c = 0; c < pointcount; c++) {
|
||||||
|
if (circuits[c] == old_circuit)
|
||||||
|
circuits[c] = new_circuit;
|
||||||
|
if (circuits[c] != new_circuit)
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
if (done) break;
|
||||||
|
}
|
||||||
|
// update targets
|
||||||
|
unsigned niidx = ++next_indices[min_i];
|
||||||
|
unsigned njidx = ++next_indices[min_j];
|
||||||
|
next_targets[min_i] = targets[min_i][niidx].min_target;
|
||||||
|
next_targets[min_j] = targets[min_j][njidx].min_target;
|
||||||
|
next_dists[min_i] = targets[min_i][niidx].min_dist;
|
||||||
|
next_dists[min_j] = targets[min_j][njidx].min_dist;
|
||||||
|
} while(true);
|
||||||
|
|
||||||
|
return positions[last_i][0] * positions[last_j][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_PART1 1
|
||||||
|
#define RUN_TEST2 1
|
||||||
|
#define RUN_PART2 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 40
|
||||||
|
#define TEST2_EXPECT 25272
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (num v = do_part1(countof(test), test, true); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input, false));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (num v = do_part2(countof(test), test, true); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input, false));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
288
lib.h
Normal file
288
lib.h
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdcountof.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SYS_write 1
|
||||||
|
#define SYS_exit_group 231
|
||||||
|
|
||||||
|
#define STDOUT_FILENO 1
|
||||||
|
|
||||||
|
static
|
||||||
|
void write(uint64_t fileno, void *buffer, size_t len) {
|
||||||
|
uint64_t a,d;
|
||||||
|
asm volatile("syscall"
|
||||||
|
:"=a"(a),"=d"(d)
|
||||||
|
:"a"(SYS_write),"D"(fileno),"S"(buffer),"d"(len)
|
||||||
|
:"cc","memory","%rcx","%r11");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[noreturn]] static
|
||||||
|
void exit_group(uint64_t code) {
|
||||||
|
asm volatile(
|
||||||
|
"syscall\n"
|
||||||
|
"ud2"
|
||||||
|
::"a"(SYS_exit_group),"D"(code));
|
||||||
|
for (;;);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||||
|
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||||
|
|
||||||
|
#define xstr(s) str(s)
|
||||||
|
#define str(s) #s
|
||||||
|
|
||||||
|
typedef uint64_t bcdint;
|
||||||
|
typedef uint64_t num;
|
||||||
|
typedef unsigned char ch;
|
||||||
|
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
ch *findc(const ch *s, ch c, size_t n) {
|
||||||
|
uint64_t dispose;
|
||||||
|
void *d;
|
||||||
|
asm("repnz scasb":"=D"(d),"=c"(dispose):"D"(s),"c"(n),"a"(c):"memory","cc");
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
num *findnum(const num *s, num c, size_t n) {
|
||||||
|
uint64_t dispose;
|
||||||
|
void *d;
|
||||||
|
asm("repnz scasq":"=D"(d),"=c"(dispose):"D"(s),"c"(n),"a"(c):"memory","cc");
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
num *findnotnum(const num *s, num c, size_t n) {
|
||||||
|
uint64_t dispose;
|
||||||
|
void *d;
|
||||||
|
asm("repz scasq":"=D"(d),"=c"(dispose):"D"(s),"c"(n),"a"(c):"memory","cc");
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline num alignnum(num v, num align) {
|
||||||
|
num extra = v % align;
|
||||||
|
num adjust = (align - extra) % align;
|
||||||
|
return v + adjust;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void printns(size_t len, unsigned char chars[len]) {
|
||||||
|
write(STDOUT_FILENO, chars, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void printptr(uintptr_t v) {
|
||||||
|
char buf[sizeof(uintptr_t)*2] = { };
|
||||||
|
char *p = buf+countof(buf);
|
||||||
|
for (size_t i = 0; i < countof(buf); i++) {
|
||||||
|
p--;
|
||||||
|
if ((v & 0x0F) < 0xA) {
|
||||||
|
*p = '0' + (v & 0x0F);
|
||||||
|
} else {
|
||||||
|
*p = 'A' - 0xA + (v & 0x0F);
|
||||||
|
}
|
||||||
|
v >>= 4;
|
||||||
|
}
|
||||||
|
write(STDOUT_FILENO, p, countof(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void print_many_char(size_t len, char chars[len]) {
|
||||||
|
write(STDOUT_FILENO, chars, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define print(string) print_many_char(sizeof(string)-1, string)
|
||||||
|
#define pnl() print("\n")
|
||||||
|
|
||||||
|
static
|
||||||
|
void printd(unsigned long v) {
|
||||||
|
if (!v) {
|
||||||
|
print("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char buf[32];
|
||||||
|
char *p = buf+32;
|
||||||
|
unsigned count = 0;
|
||||||
|
while (v) {
|
||||||
|
p--;
|
||||||
|
*p = '0' + (v % 10);
|
||||||
|
v /= 10;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
write(STDOUT_FILENO, p, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void snprintd(unsigned long v, size_t n, unsigned char d[n]) {
|
||||||
|
memset(d, 0, n);
|
||||||
|
if (!v) {
|
||||||
|
d[n-1] = '0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsigned char *p = d+n;
|
||||||
|
unsigned count = 0;
|
||||||
|
while (v) {
|
||||||
|
p--;
|
||||||
|
*p = '0' + (v % 10);
|
||||||
|
v /= 10;
|
||||||
|
if (p == d) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void printh(unsigned long v) {
|
||||||
|
if (!v) {
|
||||||
|
print("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char buf[32];
|
||||||
|
char *p = buf+32;
|
||||||
|
unsigned count = 0;
|
||||||
|
while (v) {
|
||||||
|
p--;
|
||||||
|
if ((v & 0x0F) < 0xA) {
|
||||||
|
*p = '0' + (v & 0x0F);
|
||||||
|
} else {
|
||||||
|
*p = 'A' - 0xA + (v & 0x0F);
|
||||||
|
}
|
||||||
|
v >>= 4;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
write(STDOUT_FILENO, p, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void snprinth(unsigned long v, size_t n, unsigned char d[n]) {
|
||||||
|
memset(d, 0, n);
|
||||||
|
if (!v) {
|
||||||
|
d[n-1] = '0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsigned char *p = d+n;
|
||||||
|
unsigned count = 0;
|
||||||
|
while (v) {
|
||||||
|
p--;
|
||||||
|
if ((v & 0x0F) < 0xA) {
|
||||||
|
*p = '0' + (v & 0x0F);
|
||||||
|
} else {
|
||||||
|
*p = 'A' - 0xA + (v & 0x0F);
|
||||||
|
}
|
||||||
|
v >>= 4;
|
||||||
|
if (p == d) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void print_hex_char(unsigned char v) {
|
||||||
|
char buf[2];
|
||||||
|
|
||||||
|
if ((v >> 4) < 0x0A) {
|
||||||
|
buf[0] = '0' + (v >> 4);
|
||||||
|
} else {
|
||||||
|
buf[0] = 'A' - 0xA + (v >> 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((v & 0x0F) < 0xA) {
|
||||||
|
buf[1] = '0' + (v & 0x0F);
|
||||||
|
} else {
|
||||||
|
buf[1] = 'A' - 0xA + (v & 0x0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
write(STDOUT_FILENO, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void print_pre_hex(size_t len, unsigned char prefix[len], unsigned long v) {
|
||||||
|
printns(len, prefix);
|
||||||
|
printh(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void print_pre_ptr(size_t len, unsigned char prefix[len], void *ptr) {
|
||||||
|
printns(len, prefix);
|
||||||
|
printptr((uintptr_t)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define print_watch_ptr(expr) print_pre_ptr(\
|
||||||
|
sizeof(#expr ": ")-1, (unsigned char*)(#expr ": "), expr)
|
||||||
|
#define print_watch_hex(expr) print_pre_hex(\
|
||||||
|
sizeof(#expr ": ")-1, (unsigned char*)(#expr ": "), expr)
|
||||||
|
|
||||||
|
static
|
||||||
|
bcdint grabbcd(unsigned char *s, unsigned char **end) {
|
||||||
|
bcdint r = 0;
|
||||||
|
for (; *s >= '0' && *s <= '9'; s++)
|
||||||
|
r = (r << 4) + (*s - '0');
|
||||||
|
if (end) *end = s;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned long grabnum(unsigned char *s, unsigned char **end) {
|
||||||
|
unsigned long r = 0;
|
||||||
|
for (; *s >= '0' && *s <= '9'; s++)
|
||||||
|
r = r * 10 + (*s - '0');
|
||||||
|
if (end) *end = s;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from wikipedia, the free encyclopedia
|
||||||
|
// https://en.wikipedia.org/wiki/Binary-coded_decimal
|
||||||
|
static bcdint bcdadd(bcdint a, bcdint b) {
|
||||||
|
bcdint t1, t2;
|
||||||
|
t1 = a + 0x0666666666666666;
|
||||||
|
t2 = t1 ^ b;
|
||||||
|
t1 = t1 + b;
|
||||||
|
t2 = t1 ^ t2;
|
||||||
|
t2 = ~t2 & 0x1111111111111110;
|
||||||
|
t2 = (t2 >> 2) | (t2 >> 3);
|
||||||
|
return t1 - t2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://homepage.cs.uiowa.edu/~jones/bcd/bcd.html
|
||||||
|
static bcdint bcdcomp(bcdint a) {
|
||||||
|
bcdint t1, t2, t3, t4, t5, t6;
|
||||||
|
t1 = 0xFFFFFFFFFFFFFFFF - a;
|
||||||
|
t2 = - a;
|
||||||
|
t3 = t1 ^ 0x0000000000000001;
|
||||||
|
t4 = t2 ^ t3;
|
||||||
|
t5 = ~t4 & 0x1111111111111110;
|
||||||
|
t6 = (t5 >> 2) | (t5 >> 3);
|
||||||
|
return t2 - t6;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bcdint bcdsub(bcdint a, bcdint b) {
|
||||||
|
return bcdadd(a, bcdcomp(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
static num bcdtonum(bcdint a) {
|
||||||
|
return 0
|
||||||
|
+ ((a >> 0) & 0xF) * 1
|
||||||
|
+ ((a >> 4) & 0xF) * 10
|
||||||
|
+ ((a >> 8) & 0xF) * 100
|
||||||
|
+ ((a >> 12) & 0xF) * 1000
|
||||||
|
+ ((a >> 16) & 0xF) * 10000
|
||||||
|
+ ((a >> 20) & 0xF) * 100000
|
||||||
|
+ ((a >> 24) & 0xF) * 1000000
|
||||||
|
+ ((a >> 28) & 0xF) * 10000000
|
||||||
|
+ ((a >> 32) & 0xF) * 100000000
|
||||||
|
+ ((a >> 36) & 0xF) * 1000000000
|
||||||
|
+ ((a >> 40) & 0xF) * 10000000000
|
||||||
|
+ ((a >> 44) & 0xF) * 100000000000
|
||||||
|
+ ((a >> 48) & 0xF) * 1000000000000
|
||||||
|
+ ((a >> 52) & 0xF) * 10000000000000
|
||||||
|
+ ((a >> 56) & 0xF) * 100000000000000
|
||||||
|
+ ((a >> 60) & 0xF) * 1000000000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bcdint numtobcd(num a) {
|
||||||
|
bcdint r = 0;
|
||||||
|
while (a) {
|
||||||
|
r <<= 4;
|
||||||
|
r |= (a % 10);
|
||||||
|
a /= 10;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
193
musl/COPYRIGHT
Normal file
193
musl/COPYRIGHT
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
musl as a whole is licensed under the following standard MIT license:
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
Copyright © 2005-2020 Rich Felker, et al.
|
||||||
|
|
||||||
|
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.
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Authors/contributors include:
|
||||||
|
|
||||||
|
A. Wilcox
|
||||||
|
Ada Worcester
|
||||||
|
Alex Dowad
|
||||||
|
Alex Suykov
|
||||||
|
Alexander Monakov
|
||||||
|
Andre McCurdy
|
||||||
|
Andrew Kelley
|
||||||
|
Anthony G. Basile
|
||||||
|
Aric Belsito
|
||||||
|
Arvid Picciani
|
||||||
|
Bartosz Brachaczek
|
||||||
|
Benjamin Peterson
|
||||||
|
Bobby Bingham
|
||||||
|
Boris Brezillon
|
||||||
|
Brent Cook
|
||||||
|
Chris Spiegel
|
||||||
|
Clément Vasseur
|
||||||
|
Daniel Micay
|
||||||
|
Daniel Sabogal
|
||||||
|
Daurnimator
|
||||||
|
David Carlier
|
||||||
|
David Edelsohn
|
||||||
|
Denys Vlasenko
|
||||||
|
Dmitry Ivanov
|
||||||
|
Dmitry V. Levin
|
||||||
|
Drew DeVault
|
||||||
|
Emil Renner Berthing
|
||||||
|
Fangrui Song
|
||||||
|
Felix Fietkau
|
||||||
|
Felix Janda
|
||||||
|
Gianluca Anzolin
|
||||||
|
Hauke Mehrtens
|
||||||
|
He X
|
||||||
|
Hiltjo Posthuma
|
||||||
|
Isaac Dunham
|
||||||
|
Jaydeep Patil
|
||||||
|
Jens Gustedt
|
||||||
|
Jeremy Huntwork
|
||||||
|
Jo-Philipp Wich
|
||||||
|
Joakim Sindholt
|
||||||
|
John Spencer
|
||||||
|
Julien Ramseier
|
||||||
|
Justin Cormack
|
||||||
|
Kaarle Ritvanen
|
||||||
|
Khem Raj
|
||||||
|
Kylie McClain
|
||||||
|
Leah Neukirchen
|
||||||
|
Luca Barbato
|
||||||
|
Luka Perkov
|
||||||
|
Lynn Ochs
|
||||||
|
M Farkas-Dyck (Strake)
|
||||||
|
Mahesh Bodapati
|
||||||
|
Markus Wichmann
|
||||||
|
Masanori Ogino
|
||||||
|
Michael Clark
|
||||||
|
Michael Forney
|
||||||
|
Mikhail Kremnyov
|
||||||
|
Natanael Copa
|
||||||
|
Nicholas J. Kain
|
||||||
|
orc
|
||||||
|
Pascal Cuoq
|
||||||
|
Patrick Oppenlander
|
||||||
|
Petr Hosek
|
||||||
|
Petr Skocik
|
||||||
|
Pierre Carrier
|
||||||
|
Reini Urban
|
||||||
|
Rich Felker
|
||||||
|
Richard Pennington
|
||||||
|
Ryan Fairfax
|
||||||
|
Samuel Holland
|
||||||
|
Segev Finer
|
||||||
|
Shiz
|
||||||
|
sin
|
||||||
|
Solar Designer
|
||||||
|
Stefan Kristiansson
|
||||||
|
Stefan O'Rear
|
||||||
|
Szabolcs Nagy
|
||||||
|
Timo Teräs
|
||||||
|
Trutz Behn
|
||||||
|
Will Dietz
|
||||||
|
William Haddon
|
||||||
|
William Pitcock
|
||||||
|
|
||||||
|
Portions of this software are derived from third-party works licensed
|
||||||
|
under terms compatible with the above MIT license:
|
||||||
|
|
||||||
|
The TRE regular expression implementation (src/regex/reg* and
|
||||||
|
src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed
|
||||||
|
under a 2-clause BSD license (license text in the source files). The
|
||||||
|
included version has been heavily modified by Rich Felker in 2012, in
|
||||||
|
the interests of size, simplicity, and namespace cleanliness.
|
||||||
|
|
||||||
|
Much of the math library code (src/math/* and src/complex/*) is
|
||||||
|
Copyright © 1993,2004 Sun Microsystems or
|
||||||
|
Copyright © 2003-2011 David Schultz or
|
||||||
|
Copyright © 2003-2009 Steven G. Kargl or
|
||||||
|
Copyright © 2003-2009 Bruce D. Evans or
|
||||||
|
Copyright © 2008 Stephen L. Moshier or
|
||||||
|
Copyright © 2017-2018 Arm Limited
|
||||||
|
and labelled as such in comments in the individual source files. All
|
||||||
|
have been licensed under extremely permissive terms.
|
||||||
|
|
||||||
|
The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008
|
||||||
|
The Android Open Source Project and is licensed under a two-clause BSD
|
||||||
|
license. It was taken from Bionic libc, used on Android.
|
||||||
|
|
||||||
|
The AArch64 memcpy and memset code (src/string/aarch64/*) are
|
||||||
|
Copyright © 1999-2019, Arm Limited.
|
||||||
|
|
||||||
|
The implementation of DES for crypt (src/crypt/crypt_des.c) is
|
||||||
|
Copyright © 1994 David Burren. It is licensed under a BSD license.
|
||||||
|
|
||||||
|
The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was
|
||||||
|
originally written by Solar Designer and placed into the public
|
||||||
|
domain. The code also comes with a fallback permissive license for use
|
||||||
|
in jurisdictions that may not recognize the public domain.
|
||||||
|
|
||||||
|
The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011
|
||||||
|
Lynn Ochs and is licensed under an MIT-style license.
|
||||||
|
|
||||||
|
The x86_64 port was written by Nicholas J. Kain and is licensed under
|
||||||
|
the standard MIT terms.
|
||||||
|
|
||||||
|
The mips and microblaze ports were originally written by Richard
|
||||||
|
Pennington for use in the ellcc project. The original code was adapted
|
||||||
|
by Rich Felker for build system and code conventions during upstream
|
||||||
|
integration. It is licensed under the standard MIT terms.
|
||||||
|
|
||||||
|
The mips64 port was contributed by Imagination Technologies and is
|
||||||
|
licensed under the standard MIT terms.
|
||||||
|
|
||||||
|
The powerpc port was also originally written by Richard Pennington,
|
||||||
|
and later supplemented and integrated by John Spencer. It is licensed
|
||||||
|
under the standard MIT terms.
|
||||||
|
|
||||||
|
All other files which have no copyright comments are original works
|
||||||
|
produced specifically for use as part of this library, written either
|
||||||
|
by Rich Felker, the main author of the library, or by one or more
|
||||||
|
contibutors listed above. Details on authorship of individual files
|
||||||
|
can be found in the git version control history of the project. The
|
||||||
|
omission of copyright and license comments in each file is in the
|
||||||
|
interest of source tree size.
|
||||||
|
|
||||||
|
In addition, permission is hereby granted for all public header files
|
||||||
|
(include/* and arch/*/bits/*) and crt files intended to be linked into
|
||||||
|
applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit
|
||||||
|
the copyright notice and permission notice otherwise required by the
|
||||||
|
license, and to use these files without any requirement of
|
||||||
|
attribution. These files include substantial contributions from:
|
||||||
|
|
||||||
|
Bobby Bingham
|
||||||
|
John Spencer
|
||||||
|
Nicholas J. Kain
|
||||||
|
Rich Felker
|
||||||
|
Richard Pennington
|
||||||
|
Stefan Kristiansson
|
||||||
|
Szabolcs Nagy
|
||||||
|
|
||||||
|
all of whom have explicitly granted such permission.
|
||||||
|
|
||||||
|
This file previously contained text expressing a belief that most of
|
||||||
|
the files covered by the above exception were sufficiently trivial not
|
||||||
|
to be subject to copyright, resulting in confusion over whether it
|
||||||
|
negated the permissions granted in the license. In the spirit of
|
||||||
|
permissive licensing, and of not having licensing issues being an
|
||||||
|
obstacle to adoption, that text has been removed.
|
||||||
333
musl/atomic.h
Normal file
333
musl/atomic.h
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
#ifndef _ATOMIC_H
|
||||||
|
#define _ATOMIC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "atomic_arch.h"
|
||||||
|
|
||||||
|
#ifdef a_ll
|
||||||
|
|
||||||
|
#ifndef a_pre_llsc
|
||||||
|
#define a_pre_llsc()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_post_llsc
|
||||||
|
#define a_post_llsc()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_cas
|
||||||
|
#define a_cas a_cas
|
||||||
|
static inline int a_cas(volatile int *p, int t, int s)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
a_pre_llsc();
|
||||||
|
do old = a_ll(p);
|
||||||
|
while (old==t && !a_sc(p, s));
|
||||||
|
a_post_llsc();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_swap
|
||||||
|
#define a_swap a_swap
|
||||||
|
static inline int a_swap(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
a_pre_llsc();
|
||||||
|
do old = a_ll(p);
|
||||||
|
while (!a_sc(p, v));
|
||||||
|
a_post_llsc();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_fetch_add
|
||||||
|
#define a_fetch_add a_fetch_add
|
||||||
|
static inline int a_fetch_add(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
a_pre_llsc();
|
||||||
|
do old = a_ll(p);
|
||||||
|
while (!a_sc(p, (unsigned)old + v));
|
||||||
|
a_post_llsc();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_fetch_and
|
||||||
|
#define a_fetch_and a_fetch_and
|
||||||
|
static inline int a_fetch_and(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
a_pre_llsc();
|
||||||
|
do old = a_ll(p);
|
||||||
|
while (!a_sc(p, old & v));
|
||||||
|
a_post_llsc();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_fetch_or
|
||||||
|
#define a_fetch_or a_fetch_or
|
||||||
|
static inline int a_fetch_or(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
a_pre_llsc();
|
||||||
|
do old = a_ll(p);
|
||||||
|
while (!a_sc(p, old | v));
|
||||||
|
a_post_llsc();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef a_ll_p
|
||||||
|
|
||||||
|
#ifndef a_cas_p
|
||||||
|
#define a_cas_p a_cas_p
|
||||||
|
static inline void *a_cas_p(volatile void *p, void *t, void *s)
|
||||||
|
{
|
||||||
|
void *old;
|
||||||
|
a_pre_llsc();
|
||||||
|
do old = a_ll_p(p);
|
||||||
|
while (old==t && !a_sc_p(p, s));
|
||||||
|
a_post_llsc();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_cas
|
||||||
|
#error missing definition of a_cas
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_swap
|
||||||
|
#define a_swap a_swap
|
||||||
|
static inline int a_swap(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
do old = *p;
|
||||||
|
while (a_cas(p, old, v) != old);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_fetch_add
|
||||||
|
#define a_fetch_add a_fetch_add
|
||||||
|
static inline int a_fetch_add(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
do old = *p;
|
||||||
|
while (a_cas(p, old, (unsigned)old+v) != old);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_fetch_and
|
||||||
|
#define a_fetch_and a_fetch_and
|
||||||
|
static inline int a_fetch_and(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
do old = *p;
|
||||||
|
while (a_cas(p, old, old&v) != old);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifndef a_fetch_or
|
||||||
|
#define a_fetch_or a_fetch_or
|
||||||
|
static inline int a_fetch_or(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
do old = *p;
|
||||||
|
while (a_cas(p, old, old|v) != old);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_and
|
||||||
|
#define a_and a_and
|
||||||
|
static inline void a_and(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
a_fetch_and(p, v);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_or
|
||||||
|
#define a_or a_or
|
||||||
|
static inline void a_or(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
a_fetch_or(p, v);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_inc
|
||||||
|
#define a_inc a_inc
|
||||||
|
static inline void a_inc(volatile int *p)
|
||||||
|
{
|
||||||
|
a_fetch_add(p, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_dec
|
||||||
|
#define a_dec a_dec
|
||||||
|
static inline void a_dec(volatile int *p)
|
||||||
|
{
|
||||||
|
a_fetch_add(p, -1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_store
|
||||||
|
#define a_store a_store
|
||||||
|
static inline void a_store(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
#ifdef a_barrier
|
||||||
|
a_barrier();
|
||||||
|
*p = v;
|
||||||
|
a_barrier();
|
||||||
|
#else
|
||||||
|
a_swap(p, v);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_barrier
|
||||||
|
#define a_barrier a_barrier
|
||||||
|
static inline void a_barrier()
|
||||||
|
{
|
||||||
|
volatile int tmp = 0;
|
||||||
|
a_cas(&tmp, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_spin
|
||||||
|
#define a_spin a_barrier
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_and_64
|
||||||
|
#define a_and_64 a_and_64
|
||||||
|
static inline void a_and_64(volatile uint64_t *p, uint64_t v)
|
||||||
|
{
|
||||||
|
union { uint64_t v; uint32_t r[2]; } u = { v };
|
||||||
|
if (u.r[0]+1) a_and((int *)p, u.r[0]);
|
||||||
|
if (u.r[1]+1) a_and((int *)p+1, u.r[1]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_or_64
|
||||||
|
#define a_or_64 a_or_64
|
||||||
|
static inline void a_or_64(volatile uint64_t *p, uint64_t v)
|
||||||
|
{
|
||||||
|
union { uint64_t v; uint32_t r[2]; } u = { v };
|
||||||
|
if (u.r[0]) a_or((int *)p, u.r[0]);
|
||||||
|
if (u.r[1]) a_or((int *)p+1, u.r[1]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_cas_p
|
||||||
|
typedef char a_cas_p_undefined_but_pointer_not_32bit[-sizeof(char) == 0xffffffff ? 1 : -1];
|
||||||
|
#define a_cas_p a_cas_p
|
||||||
|
static inline void *a_cas_p(volatile void *p, void *t, void *s)
|
||||||
|
{
|
||||||
|
return (void *)a_cas((volatile int *)p, (int)t, (int)s);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_or_l
|
||||||
|
#define a_or_l a_or_l
|
||||||
|
static inline void a_or_l(volatile void *p, long v)
|
||||||
|
{
|
||||||
|
if (sizeof(long) == sizeof(int)) a_or(p, v);
|
||||||
|
else a_or_64(p, v);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_crash
|
||||||
|
#define a_crash a_crash
|
||||||
|
static inline void a_crash()
|
||||||
|
{
|
||||||
|
*(volatile char *)0=0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_ctz_32
|
||||||
|
#define a_ctz_32 a_ctz_32
|
||||||
|
static inline int a_ctz_32(uint32_t x)
|
||||||
|
{
|
||||||
|
#ifdef a_clz_32
|
||||||
|
return 31-a_clz_32(x&-x);
|
||||||
|
#else
|
||||||
|
static const char debruijn32[32] = {
|
||||||
|
0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13,
|
||||||
|
31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14
|
||||||
|
};
|
||||||
|
return debruijn32[(x&-x)*0x076be629 >> 27];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_ctz_64
|
||||||
|
#define a_ctz_64 a_ctz_64
|
||||||
|
static inline int a_ctz_64(uint64_t x)
|
||||||
|
{
|
||||||
|
static const char debruijn64[64] = {
|
||||||
|
0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
|
||||||
|
62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
|
||||||
|
63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
|
||||||
|
51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
|
||||||
|
};
|
||||||
|
if (sizeof(long) < 8) {
|
||||||
|
uint32_t y = x;
|
||||||
|
if (!y) {
|
||||||
|
y = x>>32;
|
||||||
|
return 32 + a_ctz_32(y);
|
||||||
|
}
|
||||||
|
return a_ctz_32(y);
|
||||||
|
}
|
||||||
|
return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int a_ctz_l(unsigned long x)
|
||||||
|
{
|
||||||
|
return (sizeof(long) < 8) ? a_ctz_32(x) : a_ctz_64(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef a_clz_64
|
||||||
|
#define a_clz_64 a_clz_64
|
||||||
|
static inline int a_clz_64(uint64_t x)
|
||||||
|
{
|
||||||
|
#ifdef a_clz_32
|
||||||
|
if (x>>32)
|
||||||
|
return a_clz_32(x>>32);
|
||||||
|
return a_clz_32(x) + 32;
|
||||||
|
#else
|
||||||
|
uint32_t y;
|
||||||
|
int r;
|
||||||
|
if (x>>32) y=x>>32, r=0; else y=x, r=32;
|
||||||
|
if (y>>16) y>>=16; else r |= 16;
|
||||||
|
if (y>>8) y>>=8; else r |= 8;
|
||||||
|
if (y>>4) y>>=4; else r |= 4;
|
||||||
|
if (y>>2) y>>=2; else r |= 2;
|
||||||
|
return r | !(y>>1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef a_clz_32
|
||||||
|
#define a_clz_32 a_clz_32
|
||||||
|
static inline int a_clz_32(uint32_t x)
|
||||||
|
{
|
||||||
|
x >>= 1;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
x++;
|
||||||
|
return 31-a_ctz_32(x);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
123
musl/atomic_arch.h
Normal file
123
musl/atomic_arch.h
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#define a_cas a_cas
|
||||||
|
static inline int a_cas(volatile int *p, int t, int s)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"lock ; cmpxchg %3, %1"
|
||||||
|
: "=a"(t), "=m"(*p) : "a"(t), "r"(s) : "memory" );
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_cas_p a_cas_p
|
||||||
|
static inline void *a_cas_p(volatile void *p, void *t, void *s)
|
||||||
|
{
|
||||||
|
__asm__( "lock ; cmpxchg %3, %1"
|
||||||
|
: "=a"(t), "=m"(*(void *volatile *)p)
|
||||||
|
: "a"(t), "r"(s) : "memory" );
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_swap a_swap
|
||||||
|
static inline int a_swap(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"xchg %0, %1"
|
||||||
|
: "=r"(v), "=m"(*p) : "0"(v) : "memory" );
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_fetch_add a_fetch_add
|
||||||
|
static inline int a_fetch_add(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"lock ; xadd %0, %1"
|
||||||
|
: "=r"(v), "=m"(*p) : "0"(v) : "memory" );
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_and a_and
|
||||||
|
static inline void a_and(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"lock ; and %1, %0"
|
||||||
|
: "=m"(*p) : "r"(v) : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_or a_or
|
||||||
|
static inline void a_or(volatile int *p, int v)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"lock ; or %1, %0"
|
||||||
|
: "=m"(*p) : "r"(v) : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_and_64 a_and_64
|
||||||
|
static inline void a_and_64(volatile uint64_t *p, uint64_t v)
|
||||||
|
{
|
||||||
|
__asm__ __volatile(
|
||||||
|
"lock ; and %1, %0"
|
||||||
|
: "=m"(*p) : "r"(v) : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_or_64 a_or_64
|
||||||
|
static inline void a_or_64(volatile uint64_t *p, uint64_t v)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"lock ; or %1, %0"
|
||||||
|
: "=m"(*p) : "r"(v) : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_inc a_inc
|
||||||
|
static inline void a_inc(volatile int *p)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"lock ; incl %0"
|
||||||
|
: "=m"(*p) : "m"(*p) : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_dec a_dec
|
||||||
|
static inline void a_dec(volatile int *p)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"lock ; decl %0"
|
||||||
|
: "=m"(*p) : "m"(*p) : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_store a_store
|
||||||
|
static inline void a_store(volatile int *p, int x)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"mov %1, %0 ; lock ; orl $0,(%%rsp)"
|
||||||
|
: "=m"(*p) : "r"(x) : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_barrier a_barrier
|
||||||
|
static inline void a_barrier()
|
||||||
|
{
|
||||||
|
__asm__ __volatile__( "" : : : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_spin a_spin
|
||||||
|
static inline void a_spin()
|
||||||
|
{
|
||||||
|
__asm__ __volatile__( "pause" : : : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_crash a_crash
|
||||||
|
static inline void a_crash()
|
||||||
|
{
|
||||||
|
__asm__ __volatile__( "hlt" : : : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_ctz_64 a_ctz_64
|
||||||
|
static inline int a_ctz_64(uint64_t x)
|
||||||
|
{
|
||||||
|
__asm__( "bsf %1,%0" : "=r"(x) : "r"(x) );
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define a_clz_64 a_clz_64
|
||||||
|
static inline int a_clz_64(uint64_t x)
|
||||||
|
{
|
||||||
|
__asm__( "bsr %1,%0 ; xor $63,%0" : "=r"(x) : "r"(x) );
|
||||||
|
return x;
|
||||||
|
}
|
||||||
25
musl/memcpy.s
Normal file
25
musl/memcpy.s
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
.global memcpy
|
||||||
|
.global __memcpy_fwd
|
||||||
|
.hidden __memcpy_fwd
|
||||||
|
.type memcpy,@function
|
||||||
|
memcpy:
|
||||||
|
__memcpy_fwd:
|
||||||
|
mov %rdi,%rax
|
||||||
|
cmp $8,%rdx
|
||||||
|
jc 1f
|
||||||
|
test $7,%edi
|
||||||
|
jz 1f
|
||||||
|
2: movsb
|
||||||
|
dec %rdx
|
||||||
|
test $7,%edi
|
||||||
|
jnz 2b
|
||||||
|
1: mov %rdx,%rcx
|
||||||
|
shr $3,%rcx
|
||||||
|
rep
|
||||||
|
movsq
|
||||||
|
and $7,%edx
|
||||||
|
jz 1f
|
||||||
|
2: movsb
|
||||||
|
dec %edx
|
||||||
|
jnz 2b
|
||||||
|
1: ret
|
||||||
72
musl/memset.s
Normal file
72
musl/memset.s
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
.global memset
|
||||||
|
.type memset,@function
|
||||||
|
memset:
|
||||||
|
movzbq %sil,%rax
|
||||||
|
mov $0x101010101010101,%r8
|
||||||
|
imul %r8,%rax
|
||||||
|
|
||||||
|
cmp $126,%rdx
|
||||||
|
ja 2f
|
||||||
|
|
||||||
|
test %edx,%edx
|
||||||
|
jz 1f
|
||||||
|
|
||||||
|
mov %sil,(%rdi)
|
||||||
|
mov %sil,-1(%rdi,%rdx)
|
||||||
|
cmp $2,%edx
|
||||||
|
jbe 1f
|
||||||
|
|
||||||
|
mov %ax,1(%rdi)
|
||||||
|
mov %ax,(-1-2)(%rdi,%rdx)
|
||||||
|
cmp $6,%edx
|
||||||
|
jbe 1f
|
||||||
|
|
||||||
|
mov %eax,(1+2)(%rdi)
|
||||||
|
mov %eax,(-1-2-4)(%rdi,%rdx)
|
||||||
|
cmp $14,%edx
|
||||||
|
jbe 1f
|
||||||
|
|
||||||
|
mov %rax,(1+2+4)(%rdi)
|
||||||
|
mov %rax,(-1-2-4-8)(%rdi,%rdx)
|
||||||
|
cmp $30,%edx
|
||||||
|
jbe 1f
|
||||||
|
|
||||||
|
mov %rax,(1+2+4+8)(%rdi)
|
||||||
|
mov %rax,(1+2+4+8+8)(%rdi)
|
||||||
|
mov %rax,(-1-2-4-8-16)(%rdi,%rdx)
|
||||||
|
mov %rax,(-1-2-4-8-8)(%rdi,%rdx)
|
||||||
|
cmp $62,%edx
|
||||||
|
jbe 1f
|
||||||
|
|
||||||
|
mov %rax,(1+2+4+8+16)(%rdi)
|
||||||
|
mov %rax,(1+2+4+8+16+8)(%rdi)
|
||||||
|
mov %rax,(1+2+4+8+16+16)(%rdi)
|
||||||
|
mov %rax,(1+2+4+8+16+24)(%rdi)
|
||||||
|
mov %rax,(-1-2-4-8-16-32)(%rdi,%rdx)
|
||||||
|
mov %rax,(-1-2-4-8-16-24)(%rdi,%rdx)
|
||||||
|
mov %rax,(-1-2-4-8-16-16)(%rdi,%rdx)
|
||||||
|
mov %rax,(-1-2-4-8-16-8)(%rdi,%rdx)
|
||||||
|
|
||||||
|
1: mov %rdi,%rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
2: test $15,%edi
|
||||||
|
mov %rdi,%r8
|
||||||
|
mov %rax,-8(%rdi,%rdx)
|
||||||
|
mov %rdx,%rcx
|
||||||
|
jnz 2f
|
||||||
|
|
||||||
|
1: shr $3,%rcx
|
||||||
|
rep
|
||||||
|
stosq
|
||||||
|
mov %r8,%rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
2: xor %edx,%edx
|
||||||
|
sub %edi,%edx
|
||||||
|
and $15,%edx
|
||||||
|
mov %rax,(%rdi)
|
||||||
|
mov %rax,8(%rdi)
|
||||||
|
sub %rdx,%rcx
|
||||||
|
add %rdx,%rdi
|
||||||
|
jmp 1b
|
||||||
219
musl/qsort.c
Normal file
219
musl/qsort.c
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
/* Copyright (C) 2011 by Lynn Ochs
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Minor changes by Rich Felker for integration in musl, 2011-04-27. */
|
||||||
|
|
||||||
|
/* Smoothsort, an adaptive variant of Heapsort. Memory usage: O(1).
|
||||||
|
Run time: Worst case O(n log n), close to O(n) in the mostly-sorted case. */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "atomic.h"
|
||||||
|
#define ntz(x) a_ctz_l((x))
|
||||||
|
|
||||||
|
typedef int (*cmpfun)(const void *, const void *, void *);
|
||||||
|
|
||||||
|
static inline int pntz(size_t p[2]) {
|
||||||
|
int r = ntz(p[0] - 1);
|
||||||
|
if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cycle(size_t width, unsigned char* ar[], int n)
|
||||||
|
{
|
||||||
|
unsigned char tmp[256];
|
||||||
|
size_t l;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(n < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar[n] = tmp;
|
||||||
|
while(width) {
|
||||||
|
l = sizeof(tmp) < width ? sizeof(tmp) : width;
|
||||||
|
memcpy(ar[n], ar[0], l);
|
||||||
|
for(i = 0; i < n; i++) {
|
||||||
|
memcpy(ar[i], ar[i + 1], l);
|
||||||
|
ar[i] += l;
|
||||||
|
}
|
||||||
|
width -= l;
|
||||||
|
}
|
||||||
|
ar[n] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shl() and shr() need n > 0 */
|
||||||
|
static inline void shl(size_t p[2], int n)
|
||||||
|
{
|
||||||
|
if(n >= 8 * sizeof(size_t)) {
|
||||||
|
n -= 8 * sizeof(size_t);
|
||||||
|
p[1] = p[0];
|
||||||
|
p[0] = 0;
|
||||||
|
}
|
||||||
|
p[1] <<= n;
|
||||||
|
p[1] |= p[0] >> (sizeof(size_t) * 8 - n);
|
||||||
|
p[0] <<= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void shr(size_t p[2], int n)
|
||||||
|
{
|
||||||
|
if(n >= 8 * sizeof(size_t)) {
|
||||||
|
n -= 8 * sizeof(size_t);
|
||||||
|
p[0] = p[1];
|
||||||
|
p[1] = 0;
|
||||||
|
}
|
||||||
|
p[0] >>= n;
|
||||||
|
p[0] |= p[1] << (sizeof(size_t) * 8 - n);
|
||||||
|
p[1] >>= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sift(unsigned char *head, size_t width, cmpfun cmp, void *arg, int pshift, size_t lp[])
|
||||||
|
{
|
||||||
|
unsigned char *rt, *lf;
|
||||||
|
unsigned char *ar[14 * sizeof(size_t) + 1];
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
ar[0] = head;
|
||||||
|
while(pshift > 1) {
|
||||||
|
rt = head - width;
|
||||||
|
lf = head - width - lp[pshift - 2];
|
||||||
|
|
||||||
|
if(cmp(ar[0], lf, arg) >= 0 && cmp(ar[0], rt, arg) >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(cmp(lf, rt, arg) >= 0) {
|
||||||
|
ar[i++] = lf;
|
||||||
|
head = lf;
|
||||||
|
pshift -= 1;
|
||||||
|
} else {
|
||||||
|
ar[i++] = rt;
|
||||||
|
head = rt;
|
||||||
|
pshift -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cycle(width, ar, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, size_t pp[2], int pshift, int trusty, size_t lp[])
|
||||||
|
{
|
||||||
|
unsigned char *stepson,
|
||||||
|
*rt, *lf;
|
||||||
|
size_t p[2];
|
||||||
|
unsigned char *ar[14 * sizeof(size_t) + 1];
|
||||||
|
int i = 1;
|
||||||
|
int trail;
|
||||||
|
|
||||||
|
p[0] = pp[0];
|
||||||
|
p[1] = pp[1];
|
||||||
|
|
||||||
|
ar[0] = head;
|
||||||
|
while(p[0] != 1 || p[1] != 0) {
|
||||||
|
stepson = head - lp[pshift];
|
||||||
|
if(cmp(stepson, ar[0], arg) <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!trusty && pshift > 1) {
|
||||||
|
rt = head - width;
|
||||||
|
lf = head - width - lp[pshift - 2];
|
||||||
|
if(cmp(rt, stepson, arg) >= 0 || cmp(lf, stepson, arg) >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ar[i++] = stepson;
|
||||||
|
head = stepson;
|
||||||
|
trail = pntz(p);
|
||||||
|
shr(p, trail);
|
||||||
|
pshift += trail;
|
||||||
|
trusty = 0;
|
||||||
|
}
|
||||||
|
if(!trusty) {
|
||||||
|
cycle(width, ar, i);
|
||||||
|
sift(head, width, cmp, arg, pshift, lp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void qsort_r(void *base, size_t nel, size_t width, cmpfun cmp, void *arg)
|
||||||
|
{
|
||||||
|
size_t lp[12*sizeof(size_t)];
|
||||||
|
size_t i, size = width * nel;
|
||||||
|
unsigned char *head, *high;
|
||||||
|
size_t p[2] = {1, 0};
|
||||||
|
int pshift = 1;
|
||||||
|
int trail;
|
||||||
|
|
||||||
|
if (!size) return;
|
||||||
|
|
||||||
|
head = base;
|
||||||
|
high = head + size - width;
|
||||||
|
|
||||||
|
/* Precompute Leonardo numbers, scaled by element width */
|
||||||
|
for(lp[0]=lp[1]=width, i=2; (lp[i]=lp[i-2]+lp[i-1]+width) < size; i++);
|
||||||
|
|
||||||
|
while(head < high) {
|
||||||
|
if((p[0] & 3) == 3) {
|
||||||
|
sift(head, width, cmp, arg, pshift, lp);
|
||||||
|
shr(p, 2);
|
||||||
|
pshift += 2;
|
||||||
|
} else {
|
||||||
|
if(lp[pshift - 1] >= high - head) {
|
||||||
|
trinkle(head, width, cmp, arg, p, pshift, 0, lp);
|
||||||
|
} else {
|
||||||
|
sift(head, width, cmp, arg, pshift, lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pshift == 1) {
|
||||||
|
shl(p, 1);
|
||||||
|
pshift = 0;
|
||||||
|
} else {
|
||||||
|
shl(p, pshift - 1);
|
||||||
|
pshift = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p[0] |= 1;
|
||||||
|
head += width;
|
||||||
|
}
|
||||||
|
|
||||||
|
trinkle(head, width, cmp, arg, p, pshift, 0, lp);
|
||||||
|
|
||||||
|
while(pshift != 1 || p[0] != 1 || p[1] != 0) {
|
||||||
|
if(pshift <= 1) {
|
||||||
|
trail = pntz(p);
|
||||||
|
shr(p, trail);
|
||||||
|
pshift += trail;
|
||||||
|
} else {
|
||||||
|
shl(p, 2);
|
||||||
|
pshift -= 2;
|
||||||
|
p[0] ^= 7;
|
||||||
|
shr(p, 1);
|
||||||
|
trinkle(head - lp[pshift] - width, width, cmp, arg, p, pshift + 1, 1, lp);
|
||||||
|
shl(p, 1);
|
||||||
|
p[0] |= 1;
|
||||||
|
trinkle(head - width, width, cmp, arg, p, pshift, 1, lp);
|
||||||
|
}
|
||||||
|
head -= width;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
musl/qsort_nr.c
Normal file
16
musl/qsort_nr.c
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef int (*cmpfun)(const void *, const void *);
|
||||||
|
typedef int (*cmpfun_r)(const void *, const void *, cmpfun);
|
||||||
|
void qsort_r(void *base, size_t nel, size_t width, cmpfun_r cmp, cmpfun arg);
|
||||||
|
|
||||||
|
|
||||||
|
static int wrapper_cmp(const void *v1, const void *v2, cmpfun cmp)
|
||||||
|
{
|
||||||
|
return cmp(v1, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qsort(void *base, size_t nel, size_t width, cmpfun cmp)
|
||||||
|
{
|
||||||
|
qsort_r(base, nel, width, wrapper_cmp, cmp);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user