Files
Zigmulator/src/partition.zig
T

130 lines
3.1 KiB
Zig

const std = @import("std");
const Allocator = std.mem.Allocator;
pub const EndpointID = u32;
pub const Link = struct {
a: EndpointID,
b: EndpointID,
pub fn init(a: EndpointID, b: EndpointID) Link {
return if (a <= b)
.{ .a = a, .b = b }
else
.{ .a = b, .b = a };
}
pub fn eql(self: Link, other: Link) bool {
return self.a == other.a and self.b == other.b;
}
};
gpa: Allocator,
broken_links: std.ArrayList(Link),
pub fn init(self: *@This(), gpa: Allocator) void {
self.gpa = gpa;
self.broken_links = .empty;
}
pub fn deinit(self: *@This()) void {
self.broken_links.deinit(self.gpa);
}
pub fn breakLink(self: *@This(), a: EndpointID, b: EndpointID) Allocator.Error!void {
if (a == b)
return;
const link = Link.init(a, b);
if (self.contains(link))
return;
try self.broken_links.append(self.gpa, link);
}
pub fn healLink(self: *@This(), a: EndpointID, b: EndpointID) void {
const link = Link.init(a, b);
for (self.broken_links.items, 0..) |item, i| {
if (item.eql(link)) {
_ = self.broken_links.swapRemove(i);
return;
}
}
}
pub fn clear(self: *@This()) void {
self.broken_links.clearRetainingCapacity();
}
pub fn isBroken(self: *const @This(), a: EndpointID, b: EndpointID) bool {
if (a == b)
return false;
return self.contains(Link.init(a, b));
}
pub fn links(self: *const @This()) []const Link {
return self.broken_links.items;
}
fn contains(self: *const @This(), link: Link) bool {
for (self.broken_links.items) |item| {
if (item.eql(link))
return true;
}
return false;
}
test "broken links are symmetric" {
var partition: @This() = undefined;
partition.init(std.testing.allocator);
defer partition.deinit();
try partition.breakLink(1, 2);
try std.testing.expect(partition.isBroken(1, 2));
try std.testing.expect(partition.isBroken(2, 1));
try std.testing.expect(!partition.isBroken(1, 1));
}
test "breaking the same link twice does not duplicate it" {
var partition: @This() = undefined;
partition.init(std.testing.allocator);
defer partition.deinit();
try partition.breakLink(1, 2);
try partition.breakLink(2, 1);
try std.testing.expectEqual(@as(usize, 1), partition.links().len);
}
test "healing a link removes only that link" {
var partition: @This() = undefined;
partition.init(std.testing.allocator);
defer partition.deinit();
try partition.breakLink(1, 2);
try partition.breakLink(2, 3);
partition.healLink(2, 1);
try std.testing.expect(!partition.isBroken(1, 2));
try std.testing.expect(partition.isBroken(2, 3));
}
test "clear heals every link" {
var partition: @This() = undefined;
partition.init(std.testing.allocator);
defer partition.deinit();
try partition.breakLink(1, 2);
try partition.breakLink(3, 4);
partition.clear();
try std.testing.expectEqual(@as(usize, 0), partition.links().len);
try std.testing.expect(!partition.isBroken(1, 2));
try std.testing.expect(!partition.isBroken(3, 4));
}