Compare commits

..

No commits in common. "3963afe3434fa1b766d0c314d6c8d7dff8459b48" and "f46240e879a3e39fefc28a7c0f4ee667ab18856f" have entirely different histories.

11 changed files with 56 additions and 511 deletions

View File

@ -7,7 +7,10 @@
namespace BAN
{
template<typename Key, typename T, typename HASH = BAN::hash<Key>, bool STABLE = true>
template<typename Container>
class HashMapIterator;
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
class HashMap
{
public:
@ -32,12 +35,12 @@ namespace BAN
public:
HashMap() = default;
HashMap(const HashMap<Key, T, HASH, STABLE>&);
HashMap(HashMap<Key, T, HASH, STABLE>&&);
HashMap(const HashMap<Key, T, HASH>&);
HashMap(HashMap<Key, T, HASH>&&);
~HashMap();
HashMap<Key, T, HASH, STABLE>& operator=(const HashMap<Key, T, HASH, STABLE>&);
HashMap<Key, T, HASH, STABLE>& operator=(HashMap<Key, T, HASH, STABLE>&&);
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
ErrorOr<void> insert(const Key&, const T&);
ErrorOr<void> insert(const Key&, T&&);
@ -74,26 +77,26 @@ namespace BAN
friend iterator;
};
template<typename Key, typename T, typename HASH, bool STABLE>
HashMap<Key, T, HASH, STABLE>::HashMap(const HashMap<Key, T, HASH, STABLE>& other)
template<typename Key, typename T, typename HASH>
HashMap<Key, T, HASH>::HashMap(const HashMap<Key, T, HASH>& other)
{
*this = other;
}
template<typename Key, typename T, typename HASH, bool STABLE>
HashMap<Key, T, HASH, STABLE>::HashMap(HashMap<Key, T, HASH, STABLE>&& other)
template<typename Key, typename T, typename HASH>
HashMap<Key, T, HASH>::HashMap(HashMap<Key, T, HASH>&& other)
{
*this = move(other);
}
template<typename Key, typename T, typename HASH, bool STABLE>
HashMap<Key, T, HASH, STABLE>::~HashMap()
template<typename Key, typename T, typename HASH>
HashMap<Key, T, HASH>::~HashMap()
{
clear();
}
template<typename Key, typename T, typename HASH, bool STABLE>
HashMap<Key, T, HASH, STABLE>& HashMap<Key, T, HASH, STABLE>::operator=(const HashMap<Key, T, HASH, STABLE>& other)
template<typename Key, typename T, typename HASH>
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(const HashMap<Key, T, HASH>& other)
{
clear();
m_buckets = other.m_buckets;
@ -101,8 +104,8 @@ namespace BAN
return *this;
}
template<typename Key, typename T, typename HASH, bool STABLE>
HashMap<Key, T, HASH, STABLE>& HashMap<Key, T, HASH, STABLE>::operator=(HashMap<Key, T, HASH, STABLE>&& other)
template<typename Key, typename T, typename HASH>
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(HashMap<Key, T, HASH>&& other)
{
clear();
m_buckets = move(other.m_buckets);
@ -111,21 +114,21 @@ namespace BAN
return *this;
}
template<typename Key, typename T, typename HASH, bool STABLE>
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::insert(const Key& key, const T& value)
template<typename Key, typename T, typename HASH>
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, const T& value)
{
return insert(key, move(T(value)));
}
template<typename Key, typename T, typename HASH, bool STABLE>
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::insert(const Key& key, T&& value)
template<typename Key, typename T, typename HASH>
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, T&& value)
{
return emplace(key, move(value));
}
template<typename Key, typename T, typename HASH, bool STABLE>
template<typename Key, typename T, typename HASH>
template<typename... Args>
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::emplace(const Key& key, Args&&... args)
ErrorOr<void> HashMap<Key, T, HASH>::emplace(const Key& key, Args&&... args)
{
ASSERT(!contains(key));
TRY(rebucket(m_size + 1));
@ -137,15 +140,15 @@ namespace BAN
return {};
}
template<typename Key, typename T, typename HASH, bool STABLE>
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::reserve(size_type size)
template<typename Key, typename T, typename HASH>
ErrorOr<void> HashMap<Key, T, HASH>::reserve(size_type size)
{
TRY(rebucket(size));
return {};
}
template<typename Key, typename T, typename HASH, bool STABLE>
void HashMap<Key, T, HASH, STABLE>::remove(const Key& key)
template<typename Key, typename T, typename HASH>
void HashMap<Key, T, HASH>::remove(const Key& key)
{
if (empty()) return;
auto& bucket = get_bucket(key);
@ -160,15 +163,15 @@ namespace BAN
}
}
template<typename Key, typename T, typename HASH, bool STABLE>
void HashMap<Key, T, HASH, STABLE>::clear()
template<typename Key, typename T, typename HASH>
void HashMap<Key, T, HASH>::clear()
{
m_buckets.clear();
m_size = 0;
}
template<typename Key, typename T, typename HASH, bool STABLE>
T& HashMap<Key, T, HASH, STABLE>::operator[](const Key& key)
template<typename Key, typename T, typename HASH>
T& HashMap<Key, T, HASH>::operator[](const Key& key)
{
ASSERT(!empty());
auto& bucket = get_bucket(key);
@ -178,8 +181,8 @@ namespace BAN
ASSERT(false);
}
template<typename Key, typename T, typename HASH, bool STABLE>
const T& HashMap<Key, T, HASH, STABLE>::operator[](const Key& key) const
template<typename Key, typename T, typename HASH>
const T& HashMap<Key, T, HASH>::operator[](const Key& key) const
{
ASSERT(!empty());
const auto& bucket = get_bucket(key);
@ -189,8 +192,8 @@ namespace BAN
ASSERT(false);
}
template<typename Key, typename T, typename HASH, bool STABLE>
bool HashMap<Key, T, HASH, STABLE>::contains(const Key& key) const
template<typename Key, typename T, typename HASH>
bool HashMap<Key, T, HASH>::contains(const Key& key) const
{
if (empty()) return false;
const auto& bucket = get_bucket(key);
@ -200,20 +203,20 @@ namespace BAN
return false;
}
template<typename Key, typename T, typename HASH, bool STABLE>
bool HashMap<Key, T, HASH, STABLE>::empty() const
template<typename Key, typename T, typename HASH>
bool HashMap<Key, T, HASH>::empty() const
{
return m_size == 0;
}
template<typename Key, typename T, typename HASH, bool STABLE>
typename HashMap<Key, T, HASH, STABLE>::size_type HashMap<Key, T, HASH, STABLE>::size() const
template<typename Key, typename T, typename HASH>
typename HashMap<Key, T, HASH>::size_type HashMap<Key, T, HASH>::size() const
{
return m_size;
}
template<typename Key, typename T, typename HASH, bool STABLE>
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::rebucket(size_type bucket_count)
template<typename Key, typename T, typename HASH>
ErrorOr<void> HashMap<Key, T, HASH>::rebucket(size_type bucket_count)
{
if (m_buckets.size() >= bucket_count)
return {};
@ -223,8 +226,6 @@ namespace BAN
if (new_buckets.resize(new_bucket_count).is_error())
return Error::from_errno(ENOMEM);
if constexpr(STABLE)
{
// NOTE: We have to copy the old entries to the new entries and not move
// since we might run out of memory half way through.
for (auto& bucket : m_buckets)
@ -232,11 +233,8 @@ namespace BAN
for (Entry& entry : bucket)
{
size_type bucket_index = HASH()(entry.key) % new_buckets.size();
if constexpr(STABLE)
TRY(new_buckets[bucket_index].push_back(entry));
else
TRY(new_buckets[bucket_index].push_back(BAN::move(entry)));
}
if (new_buckets[bucket_index].push_back(entry).is_error())
return Error::from_errno(ENOMEM);
}
}
@ -244,27 +242,20 @@ namespace BAN
return {};
}
template<typename Key, typename T, typename HASH, bool STABLE>
LinkedList<typename HashMap<Key, T, HASH, STABLE>::Entry>& HashMap<Key, T, HASH, STABLE>::get_bucket(const Key& key)
template<typename Key, typename T, typename HASH>
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
{
ASSERT(!m_buckets.empty());
auto index = HASH()(key) % m_buckets.size();
return m_buckets[index];
}
template<typename Key, typename T, typename HASH, bool STABLE>
const LinkedList<typename HashMap<Key, T, HASH, STABLE>::Entry>& HashMap<Key, T, HASH, STABLE>::get_bucket(const Key& key) const
template<typename Key, typename T, typename HASH>
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
{
ASSERT(!m_buckets.empty());
auto index = HASH()(key) % m_buckets.size();
return m_buckets[index];
}
// Unstable hash map moves values between container during rebucketing.
// This means that if insertion to map fails, elements could be in invalid state
// and that container is no longer usable. This is better if either way you are
// going to stop using the hash map after insertion fails.
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
using HashMapUnstable = HashMap<Key, T, HASH, false>;
}

View File

@ -17,8 +17,7 @@ int memcmp(const void* s1, const void* s2, size_t n)
return 0;
}
__attribute__((optimize("-O0")))
void* memcpy(void* __restrict__ dstp, const void* __restrict__ srcp, size_t n)
void* memcpy(void* dstp, const void* srcp, size_t n)
{
unsigned char* dst = static_cast<unsigned char*>(dstp);
const unsigned char* src = static_cast<const unsigned char*>(srcp);
@ -46,7 +45,6 @@ void* memmove(void* destp, const void* srcp, size_t n)
return destp;
}
__attribute__((optimize("-O0")))
void* memset(void* s, int c, size_t n)
{
unsigned char* p = static_cast<unsigned char*>(s);
@ -146,7 +144,6 @@ char* strndup(const char* str, size_t size)
}
#endif
__attribute__((optimize("-O0")))
size_t strlen(const char* str)
{
size_t len = 0;

View File

@ -183,7 +183,7 @@ int execve(const char* pathname, char* const argv[], char* const envp[])
int execvp(const char* file, char* const argv[])
{
char buffer[1024];
const char* pathname = NULL;
const char* pathname = file;
// do path resolution if file doesn't contain /
if (strchr(file, '/') == nullptr)
@ -218,16 +218,6 @@ int execvp(const char* file, char* const argv[])
cur++;
}
}
else
{
pathname = file;
}
if (!pathname)
{
errno = ENOENT;
return -1;
}
return execve(pathname, argv, environ);
}

View File

@ -17,8 +17,6 @@ set(AOC2023_PROJECTS
day12
day13
day14
day15
day16
)
set(BANAN_AOC2023_BIN ${BANAN_BIN}/aoc2023)

View File

@ -1,22 +0,0 @@
cmake_minimum_required(VERSION 3.26)
project(aoc2023_day15 CXX)
set(SOURCES
main.cpp
)
add_executable(aoc2023_day15 ${SOURCES})
target_compile_options(aoc2023_day15 PUBLIC -O2 -g)
target_link_libraries(aoc2023_day15 PUBLIC libc ban)
add_dependencies(aoc2023_day15 libc-install ban-install)
add_custom_target(aoc2023_day15-install
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/aoc2023_day15 ${BANAN_AOC2023_BIN}/day15
DEPENDS aoc2023_day15
DEPENDS aoc2023_always
)
add_dependencies(aoc2023 aoc2023_day15)
add_dependencies(aoc2023-install aoc2023_day15-install)

View File

@ -1,150 +0,0 @@
#include <BAN/Array.h>
#include <BAN/LinkedList.h>
#include <BAN/String.h>
#include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
i64 parse_i64(BAN::StringView string)
{
i64 result = 0;
for (char c : string)
result = (result * 10) + (c - '0');
return result;
}
BAN::Vector<BAN::StringView> parse_instructions(FILE* fp)
{
static BAN::String line;
char buffer[128];
while (fgets(buffer, sizeof(buffer), fp))
{
BAN::StringView buffer_sv(buffer);
MUST(line.append(buffer_sv));
if (buffer_sv.back() == '\n')
{
line.pop_back();
break;
}
}
return MUST(line.sv().split(','));
}
i64 calculate_hash(BAN::StringView string)
{
i64 result = 0;
for (char c : string)
result = ((result + c) * 17) % 256;
return result;
}
i64 puzzle1(FILE* fp)
{
auto instructions = parse_instructions(fp);
i64 result = 0;
for (auto insn : instructions)
result += calculate_hash(insn);
return result;
}
i64 puzzle2(FILE* fp)
{
struct Entry
{
BAN::String label;
i64 focal_length;
};
using Box = BAN::LinkedList<Entry>;
auto instructions = parse_instructions(fp);
BAN::Array<Box, 256> boxes;
for (auto insn : instructions)
{
if (insn.back() == '-')
{
auto label = insn.substring(0, insn.size() - 1);
i64 hash = calculate_hash(label);
for (auto it = boxes[hash].begin(); it != boxes[hash].end(); it++)
{
if (it->label == label)
{
boxes[hash].remove(it);
break;
}
}
}
else
{
auto temp = MUST(insn.split('='));
auto label = temp[0];
auto focal_length = parse_i64(temp[1]);
i64 hash = calculate_hash(label);
bool found = false;
for (auto it = boxes[hash].begin(); it != boxes[hash].end(); it++)
{
if (it->label == label)
{
it->focal_length = focal_length;
found = true;
break;
}
}
if (!found)
MUST(boxes[hash].emplace_back(label, focal_length));
}
}
i64 result = 0;
for (size_t i = 0; i < boxes.size(); i++)
{
size_t slot = 0;
for (auto it = boxes[i].begin(); it != boxes[i].end(); it++, slot++)
result += (i + 1) * (slot + 1) * it->focal_length;
}
return result;
}
int main(int argc, char** argv)
{
const char* file_path = "/usr/share/aoc2023/day15_input.txt";
if (argc >= 2)
file_path = argv[1];
FILE* fp = fopen(file_path, "r");
if (fp == nullptr)
{
perror("fopen");
return 1;
}
printf("puzzle1: %" PRId64 "\n", puzzle1(fp));
fseek(fp, 0, SEEK_SET);
printf("puzzle2: %" PRId64 "\n", puzzle2(fp));
fclose(fp);
}

View File

@ -1,22 +0,0 @@
cmake_minimum_required(VERSION 3.26)
project(aoc2023_day16 CXX)
set(SOURCES
main.cpp
)
add_executable(aoc2023_day16 ${SOURCES})
target_compile_options(aoc2023_day16 PUBLIC -O2 -g)
target_link_libraries(aoc2023_day16 PUBLIC libc ban)
add_dependencies(aoc2023_day16 libc-install ban-install)
add_custom_target(aoc2023_day16-install
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/aoc2023_day16 ${BANAN_AOC2023_BIN}/day16
DEPENDS aoc2023_day16
DEPENDS aoc2023_always
)
add_dependencies(aoc2023 aoc2023_day16)
add_dependencies(aoc2023-install aoc2023_day16-install)

View File

@ -1,232 +0,0 @@
#include <BAN/HashSet.h>
#include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
enum class Tile { Empty, PositiveMirror, NegativeMirror, HorizontalSplitter, VerticalSplitter };
enum class Direction { North, South, East, West };
using Grid = BAN::Vector<BAN::Vector<Tile>>;
struct Position
{
i64 y;
i64 x;
Direction dir;
bool operator==(const Position& other) const
{
return x == other.x && y == other.y && dir == other.dir;
}
};
struct PositionHash
{
BAN::hash_t operator()(Position position) const
{
return BAN::hash<i64>()((position.y << 32) | position.x) ^ BAN::hash<i8>()(static_cast<i8>(position.dir));
}
};
Grid parse_grid(FILE* fp)
{
Grid grid;
auto char_to_tile =
[](char c)
{
if (c == '.')
return Tile::Empty;
if (c == '/')
return Tile::PositiveMirror;
if (c == '\\')
return Tile::NegativeMirror;
if (c == '-')
return Tile::HorizontalSplitter;
if (c == '|')
return Tile::VerticalSplitter;
ASSERT_NOT_REACHED();
};
char buffer[128];
while (fgets(buffer, sizeof(buffer), fp))
{
BAN::StringView line(buffer);
ASSERT(line.back() == '\n');
line = line.substring(0, line.size() - 1);
if (line.empty())
break;
MUST(grid.emplace_back(line.size()));
for (size_t i = 0; i < line.size(); i++)
grid.back()[i] = char_to_tile(line[i]);
}
return grid;
}
BAN::Vector<Position> get_next_positions(Position position, const Grid& grid)
{
auto tile = grid[position.y][position.x];
BAN::Vector<Position> next_positions;
switch (tile)
{
case Tile::Empty:
switch (position.dir)
{
case Direction::North: MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North)); break;
case Direction::South: MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South)); break;
case Direction::West: MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West)); break;
case Direction::East: MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East)); break;
}
break;
case Tile::PositiveMirror:
switch (position.dir)
{
case Direction::North: MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East)); break;
case Direction::South: MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West)); break;
case Direction::West: MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South)); break;
case Direction::East: MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North)); break;
}
break;
case Tile::NegativeMirror:
switch (position.dir)
{
case Direction::North: MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West)); break;
case Direction::South: MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East)); break;
case Direction::West: MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North)); break;
case Direction::East: MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South)); break;
}
break;
case Tile::HorizontalSplitter:
switch (position.dir)
{
case Direction::North:
case Direction::South:
MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West));
MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East));
break;
case Direction::West: MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West)); break;
case Direction::East: MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East)); break;
}
break;
case Tile::VerticalSplitter:
switch (position.dir)
{
case Direction::North: MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North)); break;
case Direction::South: MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South)); break;
case Direction::West:
case Direction::East:
MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North));
MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South));
break;
}
break;
}
for (size_t i = 0; i < next_positions.size();)
{
if (next_positions[i].y < 0 || next_positions[i].y >= (i64)grid.size())
next_positions.remove(i);
else if (next_positions[i].x < 0 || next_positions[i].x >= (i64)grid.front().size())
next_positions.remove(i);
else
i++;
}
return next_positions;
}
i64 count_energized_tiles(const Grid& grid, Position start)
{
BAN::HashSet<Position, PositionHash> visited;
BAN::HashSet<Position, PositionHash> energized;
BAN::Vector<Position> current_positions;
MUST(current_positions.push_back(start));
MUST(visited.insert(current_positions.front()));
while (!current_positions.empty())
{
auto position = current_positions.back();
current_positions.pop_back();
MUST(energized.insert({ position.y, position.x, Direction::North }));
auto next_positions = get_next_positions(position, grid);
for (auto next : next_positions)
{
if (visited.contains(next))
continue;
MUST(visited.insert(next));
MUST(current_positions.push_back(next));
}
}
return energized.size();
}
i64 puzzle1(FILE* fp)
{
auto grid = parse_grid(fp);
return count_energized_tiles(grid, { 0, 0, Direction::East });
}
i64 puzzle2(FILE* fp)
{
auto grid = parse_grid(fp);
i64 max_energized = 0;
for (i64 y = 0; y < (i64)grid.size(); y++)
{
max_energized = BAN::Math::max(max_energized, count_energized_tiles(grid, { y, 0, Direction::East }));
max_energized = BAN::Math::max(max_energized, count_energized_tiles(grid, { y, (i64)grid.front().size() - 1, Direction::West }));
}
for (i64 x = 0; x < (i64)grid.front().size(); x++)
{
max_energized = BAN::Math::max(max_energized, count_energized_tiles(grid, { 0, x, Direction::South }));
max_energized = BAN::Math::max(max_energized, count_energized_tiles(grid, { (i64)grid.size() - 1, x, Direction::North }));
}
return max_energized;
}
int main(int argc, char** argv)
{
const char* file_path = "/usr/share/aoc2023/day16_input.txt";
if (argc >= 2)
file_path = argv[1];
FILE* fp = fopen(file_path, "r");
if (fp == nullptr)
{
perror("fopen");
return 1;
}
printf("puzzle1: %" PRId64 "\n", puzzle1(fp));
fseek(fp, 0, SEEK_SET);
printf("puzzle2: %" PRId64 "\n", puzzle2(fp));
fclose(fp);
}

View File

@ -1 +0,0 @@
day*_input.txt

File diff suppressed because one or more lines are too long

View File

@ -1,3 +0,0 @@
#!/bin/bash
wget --no-cookies --header "Cookie: session=$AOC_SESSION" https://adventofcode.com/2023/day/$1/input -O day$1_input.txt