From 2fcb1175458ca365820894762445e7a1c9b4e007 Mon Sep 17 00:00:00 2001 From: Ralph Caraveo Date: Sun, 30 Mar 2025 15:50:25 -0700 Subject: [PATCH 1/2] Adding support for isDisjoint across all four versions along with unit tests --- README.md | 1 + src/array_hash_set/managed.zig | 28 +++++++++++++++++++++++ src/array_hash_set/unmanaged.zig | 39 ++++++++++++++++++++++++++++++++ src/hash_set/managed.zig | 28 +++++++++++++++++++++++ src/hash_set/unmanaged.zig | 38 +++++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+) 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/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 From 4de30946f7ed6d268eb6579ffa32bbc71cb55c62 Mon Sep 17 00:00:00 2001 From: Ralph Caraveo Date: Sun, 30 Mar 2025 15:50:49 -0700 Subject: [PATCH 2/2] Adding docs as well --- docs/sources.tar | Bin 14325248 -> 14330368 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/sources.tar b/docs/sources.tar index 2e82da169910da981ef084abaa49d9c97062414a..4b170300b28b7aad54b446f98a7c1a8d2f34ccef 100644 GIT binary patch delta 3052 zcmeIzSyYr|9LI4VW0OTfz-=^NH5Fu=)lm_%G%c3^wbIILgclqfXJ}>saY;Z+lT_eM zAIp?hQ&W>jN7D*Tb1B8jtu9<{vg7HPc8p^eS>G9tf~QU$F7&E7=W{Xd@_*mw`TyrP zWt%RBlpVhqQdOZd7!4*v8-v+uHJZ$3lfl|XQ4A)d#nMJEW6rkCtruckx>h(aIKnf+ z?kRBDonFN)8&YP(_w%Z5kDBAPyPV22)mx&fPQ_c|Qaq~Hqu4!)ce<)LiyRIab6CX6 zs!NSwa?O%S?POp5k!Y=9M`*bHRz+DoTLv<^zyuep# zCo4A2*?F+dt17NyPWqp6^Fog*v-c`-vMS6NnyzFh_BI$G-aad@!r@Wcaf^(*w}{ZG7%fuyuS(4WXxOf9nex~DC*#qBw=`qZ(wn4Ff!{3Yuv^NNzBa<*+lO-*?>gI=$< z>YJxaZ}Cr;(W)QNJY6S(>rbwlY-#bfcVND*WQsvr!@8ij7E8D>12b)f^8D4tZgSrq zangTDeMIB7zPC4^lXm8Ms=Qoa36;Op6-Udz$EZLYSYd-~Y8W z?Qd_5wm#q3yo%b*#c}fN&)Jc(wo=5`XExR8{5{*ey@RNT)L9J%tL0|XEC#E|-!!wC zM&62q$PhVo^w>yEA9}!du8&yU@Bf5oUDo_(LPQczE~nRKcX|?3S-wk**Q$2L%B+Lq zlSBEjldluxki9}z(=*1O9z{tlMpkaRAUezFQc)?Fm5Y+QKcKrR#KP8RhgO-FB6nX9 zVLo2{N}PWpi&ria3%Z)kmRo;O7Q+BzU>*%d)8FP%7S76!mu1OG!E&)qboPx|!RqgL zvJ7vz_2nBye=Y6kX<4>GM96csB1-Gh_@k`4(3qla%{U!6;@h}STSZ;uu&vuTVxGh2ko^gl&c-|C-) z+TGvRwJY^Y!xn{ww8cFLLNG!Q3jeuw2uB1W5ry`M#=VF^2gD){@#u(7=!`Dt3LUzk zJMKddDCmh^=#Bf)2Yt~G2}neLBq13oNJSd-Fu({C%&=eptQd$v7>slbK?a860Sv=~ zcnHHW0uN&(M&S`WiqRN@u^5NPkclj0V>~8cA|A&RcoLH^8BgJ9JcB8C7E|#YY?y`| zd4HLMdir4(4JWUch{mp&S)hfQ5JwFJTcD z<7F&CC0@Z&EW>hCp&B*N@G4edB_vkiHN1}1cmr#&7PWX2Z{cmcgLm;B*5Q4u#|CV~ z2iSzo*n$tS6?OOs_4pXuupK_^z)pOEUD%CJ@fkix1NLAqzQ8{0$Co&OgE)l4_zGX+ e2#%r=$M6ll#dkQ46F7-eIF0XpVIemXU3KN688c>#88gk`n~N|mJ{QkCGr#}u|4%KgbWbg;bk9ojS9DD^yO=dyH!GTE zQ>-pQL1xurQ(P43{na(WE<|*MRJ>bx7%!ZvjENUMvT%YZH)8rUwMRsHwzE4E6T@@z z)(0rMP1US5QC8ht9c9tgzoMLO_Okr(R(q&3JIwf&6e4@Lica#&TC0aFxWBZqoL?o9 z?4N(m^uHP)(!Bg_Hr1y7NwjL!iJC@oO*t=jIXQl)m!WtRIVw7f^ss-sI_Ro|8_vXF z8CWGu^2a8z&B#dFTJ!2@DD!-cl;k+a>#iLMg4E8OxYgW zM5acDyUFwr;p-T3Of2hQggQS|-^o)}oEPadjw8iA-idv`*H@L$C)qizR7oPA!J=8}7G=w*N&}8Y{VvP#ulVwD>ASR z+pz;Xk%=s1BL@a{VK;Iik%v9li+$LS1IR}K4&o3F;|Px87>?rvPT~|!;|vOM7Uyst z7jO}mV8>-#!BseL4cBo4H*pKMaR+yC5BKo^5Ag_(@dQP9if4F^7kG(Rc#StGMhV{H U9ZKOu8Q$XqJ~~W(<=-=Z0mKw@h5!Hn