aoc-zig-2025/shared.zig

123 lines
3.4 KiB
Zig

const std = @import("std");
const Io = std.Io;
var stdout_buffer: [1024]u8 = undefined;
var stdout_file_writer: Io.File.Writer = undefined;
var process: std.process.Init = undefined;
pub fn print(comptime fmt: []const u8, args: anytype) void {
writer().print(fmt ++ "\n", args) catch unreachable;
writer().flush() catch unreachable;
}
pub fn writer() *Io.Writer {
return &stdout_file_writer.interface;
}
pub fn sharedInit(init: std.process.Init) !void {
process = init;
const io = init.io;
stdout_file_writer = .init(.stdout(), io, &stdout_buffer);
}
pub fn loadBytesFile(allocator: std.mem.Allocator, path: []const u8) []u8 {
const bytes = std.Io.Dir.cwd().readFileAlloc(process.io, path, allocator, .unlimited) catch {
std.debug.print("unable to load file {s}\n", .{path});
unreachable;
};
return bytes;
}
pub fn loadBytesArg(allocator: std.mem.Allocator) []const u8 {
// Accessing command line arguments:
const args = process.minimal.args.toSlice(allocator) catch unreachable;
if (args.len < 2) {
print("invalid number of arguments", .{});
unreachable;
}
return trim(normalizeEndings(allocator, loadBytesFile(allocator, args[1])));
}
pub fn normalizeEndings(allocator: std.mem.Allocator, bytes: []const u8) []u8 {
var s: std.ArrayList(u8) = .empty;
for (bytes, 0..) |c, i| {
if (c != '\r' or c != '\n')
s.append(allocator, c) catch unreachable;
if (c == '\r') if (bytes[i + 1] == '\n')
s.append(allocator, '\n') catch unreachable;
}
return s.toOwnedSlice(allocator) catch unreachable;
}
pub fn isWhiteSpace(s: []const u8, off: usize) bool {
const c = s[off];
return c == ' ' or c == '\n' or c == '\r' or c == '\t';
}
pub fn trim(bytes: []const u8) []const u8 {
if (bytes.len == 0) return bytes;
var start: usize = 0;
while (isWhiteSpace(bytes, start)) start += 1;
var end: usize = bytes.len - 1;
while (end - 1 > 0 and isWhiteSpace(bytes, end)) end -= 1;
return bytes[start .. end + 1];
}
pub const LineIter = struct {
line: usize = 0,
s: usize = 0,
e: usize = 0,
pub fn toSlice(self: *@This(), bytes: []const u8) []const u8 {
return trim(bytes[self.s..self.e]);
}
pub fn nextLine(self: *@This(), bytes: []const u8) ?[]const u8 {
if (self.e == bytes.len) {
return null;
}
self.s = self.e;
if (isWhiteSpace(bytes, self.e)) self.s += 1;
self.e = self.s;
self.line += 1;
while (self.e != bytes.len and bytes[self.e] != '\n') {
self.e += 1;
}
if (self.e != bytes.len and bytes[self.e] == '\n') self.e += 1;
return self.toSlice(bytes);
}
};
pub fn countInstancesOf(haystack: []const u8, needle: []const u8) usize {
var count: usize = 0;
var i: usize = 0;
while (i < haystack.len) : (i += 1) {
if (std.mem.eql(u8, needle, haystack[i..@min(haystack.len, i + needle.len)])) {
count += 1;
i += needle.len - 1;
}
}
return count;
}
pub fn countSequencesAt(off: usize, needle: []const u8, haystack: []const u8) usize {
var count: usize = 1;
var offset = off;
while (offset + needle.len < haystack.len and std.mem.eql(u8, needle, haystack[offset .. needle.len + offset])) {
offset += needle.len;
count += 1;
}
return count;
}