typetui 0.1.0

A terminal-based typing test.
Documentation
const std = @import("std");

pub fn gpaExample() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    var list = std.ArrayList(i32).init(allocator);
    defer list.deinit();

    try list.append(10);
    try list.append(20);
    try list.append(30);

    std.debug.print("List items: ", .{});
    for (list.items) |item| {
        std.debug.print("{} ", .{item});
    }
    std.debug.print("\n", .{});
    if (list.items.len > 0) {
        std.debug.print("First: {}\n", .{list.items[0]});
    }
    const last = list.pop();
    std.debug.print("Popped: {}\n", .{last});
}

pub fn arenaExample() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    var arena = std.heap.ArenaAllocator.init(gpa.allocator());
    defer arena.deinit();
    const allocator = arena.allocator();
    const str1 = try allocator.dupe(u8, "Hello");
    const str2 = try allocator.dupe(u8, "World");
    const nums = try allocator.alloc(i32, 100);

    std.debug.print("{s} {s}, allocated {} numbers\n", .{ str1, str2, nums.len });
}

pub fn fixedBufferExample() void {
    var buffer: [1024]u8 = undefined;
    var fba = std.heap.FixedBufferAllocator.init(&buffer);
    const allocator = fba.allocator();
    const small_slice = allocator.alloc(u8, 100) catch {
        std.debug.print("Allocation failed\n", .{});
        return;
    };
    defer allocator.free(small_slice);

    small_slice[0] = 'A';
    std.debug.print("Fixed buffer byte: {}\n", .{small_slice[0]});
}

pub fn pageExample() !void {
    const allocator = std.heap.page_allocator;
    const big_slice = try allocator.alloc(u8, 1024 * 1024);
    defer allocator.free(big_slice);

    std.debug.print("Allocated {} bytes from page allocator\n", .{big_slice.len});
}

type LoggedAllocator = struct {
    allocator: std.mem.Allocator,
    bytes_allocated: usize,
};

fn loggedAlloc(ptr: *anyopaque, len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8 {
    const self = @ptrCast(*LoggedAllocator, @alignCast(ptr));
    self.bytes_allocated += len;
    std.debug.print("Allocated {} bytes (total: {})\n", .{ len, self.bytes_allocated });
    return std.heap.page_allocator.vtable.alloc(ptr, len, ptr_align, ret_addr);
}

pub fn stringMapExample() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var map = std.StringHashMap(i32).init(allocator);
    defer map.deinit();

    try map.put("apple", 100);
    try map.put("banana", 200);
    try map.put("cherry", 300);
    if (map.get("banana")) |value| {
        std.debug.print("Banana price: {}\n", .{value});
    }
    var iter = map.iterator();
    while (iter.next()) |entry| {
        std.debug.print("{s}: {}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
    }
    _ = map.remove("apple");
}

pub fn hashMapExample() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var map = std.AutoHashMap(u32, []const u8).init(allocator);
    defer map.deinit();

    try map.put(1, "one");
    try map.put(2, "two");
    try map.put(3, "three");

    if (map.getPtr(2)) |ptr| {
        ptr.* = "TWO";
    }

    std.debug.print("Entry count: {}\n", .{map.count()});
}

pub fn boundedArrayExample() void {
    var arr = std.BoundedArray(i32, 10){};

    arr.append(1) catch unreachable;
    arr.append(2) catch unreachable;
    arr.append(3) catch unreachable;

    std.debug.print("Bounded array: ", .{});
    for (arr.slice()) |item| {
        std.debug.print("{} ", .{item});
    }
    std.debug.print("(len={}, capacity={})\n", .{ arr.len, arr.capacity() });
}

const Particle = struct {
    x: f32,
    y: f32,
    vx: f32,
    vy: f32,
    active: bool,
};

pub fn multiArrayListExample() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var particles = std.MultiArrayList(Particle){};
    defer particles.deinit(allocator);
    try particles.append(allocator, .{ .x = 0, .y = 0, .vx = 1, .vy = 1, .active = true });
    try particles.append(allocator, .{ .x = 10, .y = 5, .vx = -1, .vy = 0, .active = true });
    try particles.append(allocator, .{ .x = 20, .y = 20, .vx = 0, .vy = -1, .active = false });
    const slice = particles.slice();
    for (slice.items(.x), slice.items(.y), slice.items(.active)) |x, y, active| {
        std.debug.print("Particle at ({}, {}) active={}\n", .{ x, y, active });
    }
}

pub fn linkedListExample() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    var list = std.SinglyLinkedList(i32){};
    var node1 = try allocator.create(std.SinglyLinkedList(i32).Node);
    defer allocator.destroy(node1);
    node1.data = 10;

    var node2 = try allocator.create(std.SinglyLinkedList(i32).Node);
    defer allocator.destroy(node2);
    node2.data = 20;
    list.prepend(node2);
    list.prepend(node1);
    var it = list.first;
    while (it) |node| : (it = node.next) {
        std.debug.print("Node: {}\n", .{node.data});
    }
}

pub fn memoryPoolExample() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    const Node = struct { value: i32, next: ?*@This() };
    var pool = std.heap.MemoryPool(Node).init(allocator);
    defer pool.deinit();

    const n1 = try pool.create();
    n1.* = .{ .value = 1, .next = null };

    const n2 = try pool.create();
    n2.* = .{ .value = 2, .next = n1 };

    std.debug.print("Pool node: {}\n", .{n2.value});

    pool.destroy(n1);
    pool.destroy(n2);
}

pub fn main() !void {
    try gpaExample();
    try arenaExample();
    fixedBufferExample();
    try pageExample();
    try stringMapExample();
    try hashMapExample();
    boundedArrayExample();
    try multiArrayListExample();
    try linkedListExample();
    try memoryPoolExample();
}