summaryrefslogtreecommitdiff
path: root/src/trie.zig
blob: ee7795459917396407fa4d1d382c661691c6c7de (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
const std = @import("std");
const mem = std.mem;

pub const Color = enum { red, blue };

pub const Node = struct {
    children: [256]?*Node = [_]?*Node{null} ** 256,
    value: ?Color = null,
};

pub const Trie = struct {
    allocator: mem.Allocator,
    root: Node,
    node_count: usize = 0,

    fn asBytes(cp: u24) []const u8 {
        const bytes: [3]u8 = @bitCast(cp);

        return if (bytes[0] < 128)
            bytes[0..1]
        else if (bytes[1] == 0)
            bytes[0..1]
        else if (bytes[2] == 0)
            bytes[0..2]
        else
            bytes[0..];
    }

    pub fn put(self: *Trie, cp: u24, v: Color) !void {
        const s = asBytes(cp);
        var current: *Node = &self.root;

        for (s, 0..) |b, i| {
            if (current.children[b]) |n| {
                if (i == s.len - 1) {
                    n.value = v;
                    return;
                }

                current = n;
                continue;
            }

            self.node_count += 1;
            const new_node = try self.allocator.create(Node);
            new_node.* = .{ .value = if (i == s.len - 1) v else null };
            current.children[b] = new_node;
            current = new_node;
        }
    }

    pub fn get(self: Trie, cp: u24) ?Color {
        const s = asBytes(cp);
        var current = &self.root;

        return for (s, 0..) |b, i| {
            if (current.children[b]) |n| {
                if (i == s.len - 1) break if (n.value) |v| v else null;
                current = n;
            }
        } else null;
    }
};

test "Trie works" {
    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
    defer arena.deinit();
    const allocator = arena.allocator();

    var trie = Trie{ .allocator = allocator, .root = .{} };

    const cp_1: u21 = '\u{10ffff}';
    const cp_2: u21 = '\u{10ff}';
    const cp_3: u21 = '\u{10}';

    try trie.put(cp_1, .red);
    try trie.put(cp_3, .blue);
    try std.testing.expectEqual(@as(?Color, .red), trie.get(cp_1));
    try std.testing.expectEqual(@as(?Color, null), trie.get(cp_2));
    try std.testing.expectEqual(@as(?Color, .blue), trie.get(cp_3));
}