diff --git a/README.md b/README.md index ca98071..071e573 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ This implementation gives credit and acknowledgement to the [Zig language](https * union, unionUpdate (in-place variant) * difference, differenceUpdate (in-place variant) * symmetricDifference, symmetricDifferenceUpdate (in-place variant) + * isDisjoint * isSubset * isSuperset * isProperSubset diff --git a/docs/sources.tar b/docs/sources.tar index 2e82da1..4b17030 100644 Binary files a/docs/sources.tar and b/docs/sources.tar differ diff --git a/src/array_hash_set/managed.zig b/src/array_hash_set/managed.zig index 91ae1f9..b71bb84 100644 --- a/src/array_hash_set/managed.zig +++ b/src/array_hash_set/managed.zig @@ -289,6 +289,12 @@ pub fn ArraySetManaged(comptime E: type) type { self.unmanaged = interSet.unmanaged; } + /// isDisjoint returns true if the intersection between two sets is the null set. + /// Otherwise returns false. + pub fn isDisjoint(self: Self, other: Self) bool { + return self.unmanaged.isDisjoint(other.unmanaged); + } + /// In place style: /// differenceOfUpdate /// symmetric_differenceOf_update @@ -575,6 +581,28 @@ test "comprehensive usage" { // supersetOf } +test "isDisjoint" { + var a = ArraySetManaged(u32).init(std.testing.allocator); + defer a.deinit(); + _ = try a.appendSlice(&.{ 20, 30, 40 }); + + var b = ArraySetManaged(u32).init(std.testing.allocator); + defer b.deinit(); + _ = try b.appendSlice(&.{ 202, 303, 403 }); + + // Test the true case. + try expect(a.isDisjoint(b)); + try expect(b.isDisjoint(a)); + + // Test the false case. + var c = ArraySetManaged(u32).init(std.testing.allocator); + defer c.deinit(); + _ = try c.appendSlice(&.{ 20, 30, 400 }); + + try expect(!a.isDisjoint(c)); + try expect(!c.isDisjoint(a)); +} + test "clear/capacity" { var a = ArraySetManaged(u32).init(std.testing.allocator); defer a.deinit(); diff --git a/src/array_hash_set/unmanaged.zig b/src/array_hash_set/unmanaged.zig index de534d4..d7d4705 100644 --- a/src/array_hash_set/unmanaged.zig +++ b/src/array_hash_set/unmanaged.zig @@ -298,6 +298,23 @@ pub fn ArraySetUnmanaged(comptime E: type) type { self.unmanaged = interSet.unmanaged; } + /// isDisjoint returns true if the intersection between two sets is the null set. + /// Otherwise returns false. + pub fn isDisjoint(self: Self, other: Self) bool { + // Optimization: Find the smaller of the two, and iterate over the smaller set + const smaller = if (self.cardinality() <= other.cardinality()) self else other; + const larger = if (self.cardinality() <= other.cardinality()) other else self; + + var iter = smaller.iterator(); + while (iter.next()) |el| { + if (larger.contains(el.key_ptr.*)) { + return false; + } + } + return true; + } + + /// Returns true if this Set is empty otherwise false. pub fn isEmpty(self: Self) bool { return self.unmanaged.count() == 0; } @@ -614,6 +631,28 @@ test "comprehensive usage" { // supersetOf } +test "isDisjoint" { + var a = ArraySetUnmanaged(u32).init(); + defer a.deinit(testing.allocator); + _ = try a.appendSlice(testing.allocator, &.{ 20, 30, 40 }); + + var b = ArraySetUnmanaged(u32).init(); + defer b.deinit(testing.allocator); + _ = try b.appendSlice(testing.allocator, &.{ 202, 303, 403 }); + + // Test the true case. + try expect(a.isDisjoint(b)); + try expect(b.isDisjoint(a)); + + // Test the false case. + var c = ArraySetUnmanaged(u32).init(); + defer c.deinit(testing.allocator); + _ = try c.appendSlice(testing.allocator, &.{ 20, 30, 400 }); + + try expect(!a.isDisjoint(c)); + try expect(!c.isDisjoint(a)); +} + test "clone" { // clone diff --git a/src/hash_set/managed.zig b/src/hash_set/managed.zig index 0246815..5ced230 100644 --- a/src/hash_set/managed.zig +++ b/src/hash_set/managed.zig @@ -347,6 +347,12 @@ pub fn HashSetManagedWithContext(comptime E: type, comptime Context: type, compt self.map = interSet.map; } + /// isDisjoint returns true if the intersection between two sets is the null set. + /// Otherwise returns false. + pub fn isDisjoint(self: Self, other: Self) bool { + return self.map.isDisjoint(other.map); + } + /// In place style: /// differenceOfUpdate /// symmetric_differenceOf_update @@ -659,6 +665,28 @@ test "comprehensive usage" { // supersetOf } +test "isDisjoint" { + var a = HashSetManaged(u32).init(std.testing.allocator); + defer a.deinit(); + _ = try a.appendSlice(&.{ 20, 30, 40 }); + + var b = HashSetManaged(u32).init(std.testing.allocator); + defer b.deinit(); + _ = try b.appendSlice(&.{ 202, 303, 403 }); + + // Test the true case. + try expect(a.isDisjoint(b)); + try expect(b.isDisjoint(a)); + + // Test the false case. + var c = HashSetManaged(u32).init(std.testing.allocator); + defer c.deinit(); + _ = try c.appendSlice(&.{ 20, 30, 400 }); + + try expect(!a.isDisjoint(c)); + try expect(!c.isDisjoint(a)); +} + test "clear/capacity" { var a = HashSetManaged(u32).init(std.testing.allocator); defer a.deinit(); diff --git a/src/hash_set/unmanaged.zig b/src/hash_set/unmanaged.zig index 65dd56f..b9f9d77 100644 --- a/src/hash_set/unmanaged.zig +++ b/src/hash_set/unmanaged.zig @@ -351,6 +351,22 @@ pub fn HashSetUnmanagedWithContext(comptime E: type, comptime Context: type, com self.unmanaged = interSet.unmanaged; } + /// isDisjoint returns true if the intersection between two sets is the null set. + /// Otherwise returns false. + pub fn isDisjoint(self: Self, other: Self) bool { + // Optimization: Find the smaller of the two, and iterate over the smaller set + const smaller = if (self.cardinality() <= other.cardinality()) self else other; + const larger = if (self.cardinality() <= other.cardinality()) other else self; + + var iter = smaller.iterator(); + while (iter.next()) |el| { + if (larger.contains(el.*)) { + return false; + } + } + return true; + } + pub fn isEmpty(self: Self) bool { return self.unmanaged.count() == 0; } @@ -658,6 +674,28 @@ test "comprehensive usage" { // supersetOf } +test "isDisjoint" { + var a = HashSetUnmanaged(u32).init(); + defer a.deinit(testing.allocator); + _ = try a.appendSlice(testing.allocator, &.{ 20, 30, 40 }); + + var b = HashSetUnmanaged(u32).init(); + defer b.deinit(testing.allocator); + _ = try b.appendSlice(testing.allocator, &.{ 202, 303, 403 }); + + // Test the true case. + try expect(a.isDisjoint(b)); + try expect(b.isDisjoint(a)); + + // Test the false case. + var c = HashSetUnmanaged(u32).init(); + defer c.deinit(testing.allocator); + _ = try c.appendSlice(testing.allocator, &.{ 20, 30, 400 }); + + try expect(!a.isDisjoint(c)); + try expect(!c.isDisjoint(a)); +} + test "clone" { // clone