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
|
||||
day1_input
|
||||
day1_test
|
||||
*.txt
|
||||
*.elf
|
||||
*.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
|
||||
gcc-tree -o $@ -Wall -Werror -pedantic -D_GNU_SOURCE -std=gnu2y -O3 -g $<
|
||||
MUSLFILES = $(wildcard ./musl/*)
|
||||
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 <stdcountof.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
char input[] = {
|
||||
#embed "day1_input"
|
||||
};
|
||||
#define SYS_write 1
|
||||
#define SYS_exit_group 231
|
||||
|
||||
char test[] = {
|
||||
#embed "day1_test"
|
||||
};
|
||||
#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):"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 r = 0;
|
||||
for (; *s >= '0' && *s <= '9'; s++)
|
||||
@@ -18,6 +61,27 @@ unsigned grabnum(const char *s, const char **end) {
|
||||
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]) {
|
||||
const char *s = src;
|
||||
unsigned long count = 0;
|
||||
@@ -36,6 +100,7 @@ unsigned long do_part1(size_t src_len, const char src[src_len]) {
|
||||
return count;
|
||||
}
|
||||
|
||||
static
|
||||
unsigned do_part2(size_t src_len, const char src[src_len]) {
|
||||
const char *s = src, *ns = s + 1;
|
||||
unsigned count = 0;
|
||||
@@ -70,24 +135,40 @@ unsigned do_part2(size_t src_len, const char src[src_len]) {
|
||||
return count;
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("PART 1 TEST: ");
|
||||
if (unsigned long v = do_part1(countof(test), test); v != 3) {
|
||||
printf("FAILED (got %lu, expected 3)\n", v);
|
||||
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 {
|
||||
printf("PASSED\n");
|
||||
print("PASSED\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("PART 1 RESULT: %lu\n",
|
||||
do_part1(countof(input), input));
|
||||
#if RUN_PART1
|
||||
print("PART 1 RESULT: ");
|
||||
printd(do_part1(countof(input), input));
|
||||
print("\n");
|
||||
#endif
|
||||
|
||||
printf("PART 2 TEST: ");
|
||||
if (unsigned v = do_part2(countof(test), test); v != 6) {
|
||||
printf("FAILED (got %u, expected 6)\n", v);
|
||||
#if RUN_TEST2
|
||||
print("PART 2 TEST: ");
|
||||
if (unsigned v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||
print("FAILED (got ");
|
||||
printd(v);
|
||||
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||
} else {
|
||||
printf("PASSED\n");
|
||||
print("PASSED\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("PART 2 RESULT: %u\n",
|
||||
do_part2(countof(input), input));
|
||||
#if RUN_PART2
|
||||
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