Day 1
This commit is contained in:
parent
cc23753573
commit
b6c66136f7
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
bin/
|
||||||
|
in/
|
||||||
|
lib/
|
||||||
|
obj/
|
||||||
|
out/
|
5
.vscode/extensions.json
vendored
Normal file
5
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"ms-vscode.cpptools",
|
||||||
|
],
|
||||||
|
}
|
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.default.includePath": [
|
||||||
|
"stdlib/include",
|
||||||
|
],
|
||||||
|
"files.associations": {
|
||||||
|
"*.h": "c",
|
||||||
|
},
|
||||||
|
}
|
18
Makefile
Normal file
18
Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
STDLIB_HEADERS := $(wildcard stdlib/include/*)
|
||||||
|
STDLIB_SOURCES := $(wildcard stdlib/src/*)
|
||||||
|
|
||||||
|
TARGETS := $(patsubst src/%.c,bin/%,$(wildcard src/*.c))
|
||||||
|
|
||||||
|
CFLAGS := -O2 -nostdlib -Istdlib/include -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-builtin -std=c99 -pedantic -Wall -Werror -fno-stack-protector -static -Wl,-n
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: $(TARGETS)
|
||||||
|
|
||||||
|
bin/%: src/%.c $(STDLIB_SOURCES) $(STDLIB_HEADERS)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
gcc $(CFLAGS) $< $(STDLIB_SOURCES) -o $@
|
||||||
|
strip -R .comment $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf bin
|
16
README.md
Normal file
16
README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Advent of Code 2024
|
||||||
|
|
||||||
|
Prerequisites:
|
||||||
|
|
||||||
|
* Linux (WSL may work)
|
||||||
|
* x86_64 CPU
|
||||||
|
* gcc
|
||||||
|
* make
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Run `make` to build everything.
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
Every program accepts the input through `stdin` and outputs through `stdout`.
|
200
src/01.c
Normal file
200
src/01.c
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
#include <common.h>
|
||||||
|
#include <arena.h>
|
||||||
|
#include <buffer.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 4096UL
|
||||||
|
#define ARENA_CAPACITY 2147483648UL
|
||||||
|
|
||||||
|
typedef enum parser_state {
|
||||||
|
parser_state_left,
|
||||||
|
parser_state_whitespace,
|
||||||
|
parser_state_right,
|
||||||
|
parser_state_eol,
|
||||||
|
} parser_state;
|
||||||
|
|
||||||
|
typedef struct parser {
|
||||||
|
i32 left;
|
||||||
|
i32 right;
|
||||||
|
parser_state state;
|
||||||
|
} parser;
|
||||||
|
|
||||||
|
arena left_arena;
|
||||||
|
arena right_arena;
|
||||||
|
|
||||||
|
arena left_occurences_arena;
|
||||||
|
arena right_occurences_arena;
|
||||||
|
|
||||||
|
usize number_pair_count = 0;
|
||||||
|
i32 max_left = -1;
|
||||||
|
i32 max_right = -1;
|
||||||
|
|
||||||
|
void parser_process(parser* parser, const c8* ptr, usize len);
|
||||||
|
void interpreter_process(i32 left, i32 right);
|
||||||
|
bool is_digit(c8 c);
|
||||||
|
void insert_sort(i32* ptr, usize len);
|
||||||
|
void println_u64(u64 value);
|
||||||
|
|
||||||
|
i32 main(i32 argc, char *argv[])
|
||||||
|
{
|
||||||
|
c8* buffer = buffer_init(BUFFER_SIZE);
|
||||||
|
|
||||||
|
left_arena = arena_init(ARENA_CAPACITY);
|
||||||
|
right_arena = arena_init(ARENA_CAPACITY);
|
||||||
|
left_occurences_arena = arena_init(ARENA_CAPACITY);
|
||||||
|
right_occurences_arena = arena_init(ARENA_CAPACITY);
|
||||||
|
|
||||||
|
usize buffer_ptr = 0;
|
||||||
|
isize bytes_read = 0;
|
||||||
|
parser parser = {0};
|
||||||
|
|
||||||
|
while ((bytes_read = read(stdin, &buffer[buffer_ptr], BUFFER_SIZE)) > 0) {
|
||||||
|
parser_process(&parser, &buffer[buffer_ptr], bytes_read);
|
||||||
|
buffer_ptr = (buffer_ptr + bytes_read) % BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 *left_array = left_arena.ptr;
|
||||||
|
i32 *right_array = right_arena.ptr;
|
||||||
|
|
||||||
|
insert_sort(left_array, number_pair_count);
|
||||||
|
insert_sort(right_array, number_pair_count);
|
||||||
|
|
||||||
|
// Calculate part I
|
||||||
|
|
||||||
|
u64 cumdiff = 0;
|
||||||
|
for (usize i = 0; i < number_pair_count; ++i)
|
||||||
|
{
|
||||||
|
i32 diff = left_array[i] - right_array[i];
|
||||||
|
if (diff < 0) {
|
||||||
|
diff = -diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
cumdiff += diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
println_u64(cumdiff);
|
||||||
|
|
||||||
|
// Calculate part II
|
||||||
|
|
||||||
|
u16 *right_occurences = right_occurences_arena.ptr;
|
||||||
|
|
||||||
|
u64 similarity = 0;
|
||||||
|
for (usize i = 0; i < number_pair_count; ++i)
|
||||||
|
{
|
||||||
|
i32 left = left_array[i];
|
||||||
|
if (left > max_right) continue;
|
||||||
|
|
||||||
|
similarity += (u64)left * (u64)right_occurences[left];
|
||||||
|
}
|
||||||
|
|
||||||
|
println_u64(similarity);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parser_process(parser* parser, const c8* ptr, usize len)
|
||||||
|
{
|
||||||
|
const c8* end = &ptr[len];
|
||||||
|
while (ptr < end) {
|
||||||
|
c8 c = *ptr;
|
||||||
|
switch (parser->state) {
|
||||||
|
case parser_state_left:
|
||||||
|
if (is_digit(c)) {
|
||||||
|
parser->left = parser->left * 10 + (c - '0');
|
||||||
|
ptr += 1;
|
||||||
|
} else {
|
||||||
|
parser->state = parser_state_whitespace;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case parser_state_whitespace:
|
||||||
|
if (is_digit(c)) {
|
||||||
|
parser->state = parser_state_right;
|
||||||
|
} else {
|
||||||
|
ptr += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case parser_state_right:
|
||||||
|
if (is_digit(c)) {
|
||||||
|
parser->right = parser->right * 10 + (c - '0');
|
||||||
|
ptr += 1;
|
||||||
|
} else {
|
||||||
|
parser->state = parser_state_eol;
|
||||||
|
interpreter_process(parser->left, parser->right);
|
||||||
|
parser->left = 0;
|
||||||
|
parser->right = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case parser_state_eol:
|
||||||
|
if (is_digit(c)) {
|
||||||
|
parser->state = parser_state_left;
|
||||||
|
} else {
|
||||||
|
ptr += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void interpreter_process(i32 left, i32 right)
|
||||||
|
{
|
||||||
|
i32 *left_array = left_arena.ptr;
|
||||||
|
i32 *right_array = right_arena.ptr;
|
||||||
|
|
||||||
|
u16 *left_occurences = left_occurences_arena.ptr;
|
||||||
|
u16 *right_occurences = right_occurences_arena.ptr;
|
||||||
|
|
||||||
|
ARENA_ENSURE(i32, &left_arena, number_pair_count + 1);
|
||||||
|
ARENA_ENSURE(i32, &right_arena, number_pair_count + 1);
|
||||||
|
ARENA_ENSURE(u16, &left_occurences_arena, left + 1);
|
||||||
|
ARENA_ENSURE(u16, &right_occurences_arena, right + 1);
|
||||||
|
|
||||||
|
left_array[number_pair_count] = left;
|
||||||
|
right_array[number_pair_count] = right;
|
||||||
|
|
||||||
|
left_occurences[left] += 1;
|
||||||
|
right_occurences[right] += 1;
|
||||||
|
|
||||||
|
if (left > max_left) max_left = left;
|
||||||
|
if (right > max_right) max_right = right;
|
||||||
|
|
||||||
|
number_pair_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_digit(c8 c)
|
||||||
|
{
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert_sort(i32* ptr, usize len)
|
||||||
|
{
|
||||||
|
for (usize i = 1; i < len; ++i)
|
||||||
|
{
|
||||||
|
i32 x = ptr[i];
|
||||||
|
usize j = i;
|
||||||
|
while (j > 0 && ptr[j - 1] > x) {
|
||||||
|
ptr[j] = ptr[j - 1];
|
||||||
|
j -= 1;
|
||||||
|
}
|
||||||
|
ptr[j] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void println_u64(u64 value)
|
||||||
|
{
|
||||||
|
/* The longest string we produce would be "18446744073709551615\n", which is
|
||||||
|
* 21 bytes long (we don't care about the null terminator).
|
||||||
|
*/
|
||||||
|
c8 buffer[21];
|
||||||
|
usize strlen = 1;
|
||||||
|
|
||||||
|
buffer[20] = '\n';
|
||||||
|
do
|
||||||
|
{
|
||||||
|
c8 digit = (value % 10) + '0';
|
||||||
|
buffer[20 - strlen] = digit;
|
||||||
|
strlen += 1;
|
||||||
|
value /= 10;
|
||||||
|
} while (value > 0);
|
||||||
|
|
||||||
|
write(stdout, &buffer[21 - strlen], strlen);
|
||||||
|
}
|
18
stdlib/include/arena.h
Normal file
18
stdlib/include/arena.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
typedef struct arena {
|
||||||
|
void* ptr;
|
||||||
|
usize available;
|
||||||
|
usize capacity;
|
||||||
|
} arena;
|
||||||
|
|
||||||
|
// The capacity has to be page-aligned
|
||||||
|
arena arena_init(usize capacity);
|
||||||
|
|
||||||
|
// The available size will be rounded up to a page boundary
|
||||||
|
// Will not grow beyond its capacity
|
||||||
|
void arena_ensure(arena* arena, usize available);
|
||||||
|
|
||||||
|
#define ARENA_ENSURE(T, arena, available) arena_ensure(arena, (available) * sizeof(T))
|
6
stdlib/include/buffer.h
Normal file
6
stdlib/include/buffer.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
// The size has to be page-aligned
|
||||||
|
void* buffer_init(usize size);
|
27
stdlib/include/common.h
Normal file
27
stdlib/include/common.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef char c8;
|
||||||
|
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef unsigned long u64;
|
||||||
|
|
||||||
|
typedef signed char i8;
|
||||||
|
typedef signed short i16;
|
||||||
|
typedef signed int i32;
|
||||||
|
typedef signed long i64;
|
||||||
|
|
||||||
|
typedef unsigned long int usize;
|
||||||
|
typedef signed long isize;
|
||||||
|
|
||||||
|
#define asm __asm__
|
||||||
|
|
||||||
|
#define null ((void*)0)
|
||||||
|
#define bool _Bool
|
||||||
|
#define false 0
|
||||||
|
#define true 1
|
||||||
|
|
||||||
|
#define COUNT(array) (sizeof(array) / sizeof(array[0]))
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096UL
|
24
stdlib/include/syscall.h
Normal file
24
stdlib/include/syscall.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
#define stdin 0
|
||||||
|
#define stdout 1
|
||||||
|
#define stderr 2
|
||||||
|
|
||||||
|
#define PROT_NONE 0x0
|
||||||
|
#define PROT_READ 0x1
|
||||||
|
#define PROT_WRITE 0x2
|
||||||
|
#define PROT_EXEC 0x4
|
||||||
|
|
||||||
|
#define MAP_SHARED 0x01
|
||||||
|
#define MAP_PRIVATE 0x02
|
||||||
|
#define MAP_FIXED 0x10
|
||||||
|
#define MAP_ANONYMOUS 0x20
|
||||||
|
|
||||||
|
isize read(i32 fd, void* buf, usize size);
|
||||||
|
isize write(i32 fd, const void* buf, usize size);
|
||||||
|
void* mmap(void* addr, usize length, i32 prot, i32 flags, i32 fd, isize offset);
|
||||||
|
i32 mprotect(void* addr, usize len, i32 prot);
|
||||||
|
i32 ftruncate(i32 fd, isize length);
|
||||||
|
i32 memfd_create(const char* name, u32 flags);
|
22
stdlib/src/arena.c
Normal file
22
stdlib/src/arena.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <common.h>
|
||||||
|
#include <arena.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
arena arena_init(usize capacity)
|
||||||
|
{
|
||||||
|
void* ptr = mmap(null, capacity, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
return (arena){ .ptr = ptr, .available = 0, .capacity = capacity };
|
||||||
|
}
|
||||||
|
|
||||||
|
void arena_ensure(arena* arena, usize available)
|
||||||
|
{
|
||||||
|
if (arena->available >= available) return;
|
||||||
|
|
||||||
|
available = (available + PAGE_SIZE - 1) & -PAGE_SIZE;
|
||||||
|
if (available > arena->capacity) {
|
||||||
|
available = arena->capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
mprotect((c8*)arena->ptr + arena->available, available - arena->available, PROT_READ | PROT_WRITE);
|
||||||
|
arena->available = available;
|
||||||
|
}
|
14
stdlib/src/buffer.c
Normal file
14
stdlib/src/buffer.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include <common.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
void* buffer_init(usize size)
|
||||||
|
{
|
||||||
|
i32 fd = memfd_create("buffer", 0);
|
||||||
|
ftruncate(fd, size);
|
||||||
|
|
||||||
|
void* ptr = mmap(null, 2 * size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
mmap( ptr, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
|
||||||
|
mmap((c8*)ptr + size, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
12
stdlib/src/start.s
Normal file
12
stdlib/src/start.s
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
.intel_syntax noprefix
|
||||||
|
.text
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
xor rbp, rbp
|
||||||
|
pop rdi
|
||||||
|
mov rsi, rsp
|
||||||
|
and rsp, -16
|
||||||
|
call main
|
||||||
|
mov rdi, rax
|
||||||
|
mov rax, 60
|
||||||
|
syscall
|
77
stdlib/src/syscall.c
Normal file
77
stdlib/src/syscall.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
isize read(i32 fd, void* buf, usize size)
|
||||||
|
{
|
||||||
|
isize ret;
|
||||||
|
asm volatile (
|
||||||
|
"syscall"
|
||||||
|
: "=a" (ret)
|
||||||
|
: "a" (0), "D" (fd), "S" (buf), "d" (size)
|
||||||
|
: "rcx", "r11", "memory"
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
isize write(i32 fd, const void* buf, usize size)
|
||||||
|
{
|
||||||
|
isize ret;
|
||||||
|
asm volatile (
|
||||||
|
"syscall"
|
||||||
|
: "=a" (ret)
|
||||||
|
: "a" (1), "D" (fd), "S" (buf), "d" (size)
|
||||||
|
: "rcx", "r11", "memory"
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mmap(void* addr, usize length, i32 prot, i32 flags, i32 fd, isize offset)
|
||||||
|
{
|
||||||
|
register i32 r10 asm ("r10") = flags;
|
||||||
|
register i32 r8 asm ("r8") = fd;
|
||||||
|
register isize r9 asm ("r9") = offset;
|
||||||
|
|
||||||
|
void* ret;
|
||||||
|
asm volatile (
|
||||||
|
"syscall"
|
||||||
|
: "=a" (ret)
|
||||||
|
: "a" (9), "D" (addr), "S" (length), "d" (prot), "r" (r10), "r" (r8), "r" (r9)
|
||||||
|
: "rcx", "r11", "memory"
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 mprotect(void* addr, usize len, i32 prot)
|
||||||
|
{
|
||||||
|
i32 ret;
|
||||||
|
asm volatile (
|
||||||
|
"syscall"
|
||||||
|
: "=a" (ret)
|
||||||
|
: "a" (10), "D" (addr), "S" (len), "d" (prot)
|
||||||
|
: "rcx", "r11", "memory"
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 ftruncate(i32 fd, isize length)
|
||||||
|
{
|
||||||
|
i32 ret;
|
||||||
|
asm volatile (
|
||||||
|
"syscall"
|
||||||
|
: "=a" (ret)
|
||||||
|
: "a" (77), "D" (fd), "S" (length)
|
||||||
|
: "rcx", "r11", "memory"
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 memfd_create(const char* name, u32 flags)
|
||||||
|
{
|
||||||
|
i32 ret;
|
||||||
|
asm volatile (
|
||||||
|
"syscall"
|
||||||
|
: "=a" (ret)
|
||||||
|
: "a" (319), "D" (name), "S" (flags)
|
||||||
|
: "rcx", "r11", "memory"
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user