ona/src/coral/dag.zig

159 lines
3.4 KiB
Zig

const stack = @import("./stack.zig");
const slices = @import("./slices.zig");
const std = @import("std");
pub fn Graph(comptime Payload: type) type {
return struct {
node_count: usize = 0,
table: NodeTables,
const NodeTables = stack.Parallel(struct {
payload: Payload,
edges: stack.Sequential(Node),
is_occupied: bool = true,
is_visited: bool = false,
});
const Self = @This();
pub fn append(self: *Self, payload: Payload) std.mem.Allocator.Error!Node {
const node = @as(Node, @enumFromInt(self.table.len()));
try self.table.push_grow(.{
.payload = payload,
.edges = .{.allocator = self.table.allocator},
});
self.node_count += 1;
return node;
}
pub fn clear_edges(self: *Self) void {
for (self.table.values.slice(.edges)) |*edges| {
edges.clear();
}
}
pub fn deinit(self: *Self) void {
for (self.table.values.slice(.edges)) |*edges| {
edges.deinit();
}
self.table.deinit();
self.* = undefined;
}
pub fn edge_nodes(self: Self, node: Node) ?[]const Node {
if (!self.exists(node)) {
return null;
}
return self.table.values.get_ptr(.edges, @intFromEnum(node)).?.values;
}
pub fn exists(self: Self, node: Node) bool {
return self.table.values.get(.is_occupied, @intFromEnum(node)) orelse false;
}
pub fn get_ptr(self: Self, node: Node) ?*Payload {
if (!self.exists(node)) {
return null;
}
return self.table.values.get_ptr(.payload, @intFromEnum(node)).?;
}
pub fn init(allocator: std.mem.Allocator) Self {
return .{
.table = .{.allocator = allocator},
};
}
pub fn insert_edge(self: *Self, dependant_node: Node, edge_node: Node) std.mem.Allocator.Error!bool {
if (!self.exists(edge_node)) {
return false;
}
const edges = self.table.values.get_ptr(.edges, @intFromEnum(dependant_node)) orelse {
return false;
};
if (slices.index_of(edges.values, 0, edge_node) == null) {
try edges.push_grow(edge_node);
}
return true;
}
pub fn is_empty(self: Self) bool {
return self.node_count != 0;
}
pub fn nodes(self: *const Self) Nodes {
return .{
.occupied_table = self.table.values.slice(.is_occupied),
};
}
pub fn mark_visited(self: *Self, node: Node) bool {
if (!self.exists(node)) {
return false;
}
std.debug.assert(self.table.values.set(.is_visited, @intFromEnum(node), true));
return true;
}
pub fn remove_node(self: *Self, node: Node) ?Payload {
if (!self.exists(node)) {
return null;
}
const node_index = @intFromEnum(node);
self.table.values.get_ptr(.is_occupied, node_index).?.* = false;
self.node_count -= 1;
return self.table.values.get(.payload, node_index).?;
}
pub fn reset_visited(self: *Self) void {
@memset(self.table.values.slice(.is_visited), false);
}
pub fn visited(self: Self, node: Node) ?bool {
if (!self.exists(node)) {
return null;
}
return self.table.values.get(.is_visited, @intFromEnum(node)).?;
}
};
}
pub const Node = enum (usize) { _ };
pub const Nodes = struct {
occupied_table: []const bool,
iterations: usize = 0,
pub fn next(self: *Nodes) ?Node {
std.debug.assert(self.iterations <= self.occupied_table.len);
while (self.iterations != self.occupied_table.len) {
defer self.iterations += 1;
if (self.occupied_table[self.iterations]) {
return @enumFromInt(self.iterations);
}
}
return null;
}
};