std: implement subsetOf and supersetOf for DynamicBitSet

This commit is contained in:
Ronald Chen 2022-12-11 12:39:06 -08:00 committed by Veikka Tuominen
parent 5238f9c409
commit 552ecc286a

View File

@ -30,7 +30,7 @@
//! A variant of DynamicBitSet which does not store a pointer to its
//! allocator, in order to save space.
const std = @import("std");
const std = @import("std.zig");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
@ -198,14 +198,14 @@ pub fn IntegerBitSet(comptime size: u16) type {
return bit_length == 0 or self.mask == other.mask;
}
/// Returns iff the first bit set is the subset of the
/// second one.
/// Returns true iff the first bit set is the subset
/// of the second one.
pub fn subsetOf(self: Self, other: Self) bool {
return self.intersectWith(other).eql(self);
}
/// Returns iff the first bit set is the superset of the
/// second one.
/// Returns true iff the first bit set is the superset
/// of the second one.
pub fn supersetOf(self: Self, other: Self) bool {
return other.subsetOf(self);
}
@ -564,14 +564,14 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
} else true;
}
/// Returns iff the first bit set is the subset of the
/// second one.
/// Returns true iff the first bit set is the subset
/// of the second one.
pub fn subsetOf(self: Self, other: Self) bool {
return self.intersectWith(other).eql(self);
}
/// Returns iff the first bit set is the superset of the
/// second one.
/// Returns true iff the first bit set is the superset
/// of the second one.
pub fn supersetOf(self: Self, other: Self) bool {
return other.subsetOf(self);
}
@ -957,6 +957,36 @@ pub const DynamicBitSetUnmanaged = struct {
} else true;
}
/// Returns true iff the first bit set is the subset
/// of the second one.
pub fn subsetOf(self: Self, other: Self) bool {
if (self.bit_length != other.bit_length) {
return false;
}
const num_masks = numMasks(self.bit_length);
var i: usize = 0;
return while (i < num_masks) : (i += 1) {
if (self.masks[i] & other.masks[i] != self.masks[i]) {
break false;
}
} else true;
}
/// Returns true iff the first bit set is the superset
/// of the second one.
pub fn supersetOf(self: Self, other: Self) bool {
if (self.bit_length != other.bit_length) {
return false;
}
const num_masks = numMasks(self.bit_length);
var i: usize = 0;
return while (i < num_masks) : (i += 1) {
if (self.masks[i] & other.masks[i] != other.masks[i]) {
break false;
}
} else true;
}
/// Iterates through the items in the set, according to the options.
/// The default options (.{}) will iterate indices of set bits in
/// ascending order. Modifications to the underlying bit set may
@ -1287,6 +1317,46 @@ fn testEql(empty: anytype, full: anytype, len: usize) !void {
}
}
fn testSubsetOf(empty: anytype, full: anytype, even: anytype, odd: anytype, len: usize) !void {
try testing.expect(empty.subsetOf(empty));
try testing.expect(empty.subsetOf(full));
try testing.expect(full.subsetOf(full));
switch (len) {
0 => {
try testing.expect(even.subsetOf(odd));
try testing.expect(odd.subsetOf(even));
},
1 => {
try testing.expect(!even.subsetOf(odd));
try testing.expect(odd.subsetOf(even));
},
else => {
try testing.expect(!even.subsetOf(odd));
try testing.expect(!odd.subsetOf(even));
},
}
}
fn testSupersetOf(empty: anytype, full: anytype, even: anytype, odd: anytype, len: usize) !void {
try testing.expect(full.supersetOf(full));
try testing.expect(full.supersetOf(empty));
try testing.expect(empty.supersetOf(empty));
switch (len) {
0 => {
try testing.expect(even.supersetOf(odd));
try testing.expect(odd.supersetOf(even));
},
1 => {
try testing.expect(even.supersetOf(odd));
try testing.expect(!odd.supersetOf(even));
},
else => {
try testing.expect(!even.supersetOf(odd));
try testing.expect(!odd.supersetOf(even));
},
}
}
fn testBitSet(a: anytype, b: anytype, len: usize) !void {
try testing.expectEqual(len, a.capacity());
try testing.expectEqual(len, b.capacity());
@ -1485,63 +1555,38 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void {
}
}
fn fillEven(set: anytype, len: usize) void {
var i: usize = 0;
while (i < len) : (i += 1) {
set.setValue(i, i & 1 == 0);
}
}
fn fillOdd(set: anytype, len: usize) void {
var i: usize = 0;
while (i < len) : (i += 1) {
set.setValue(i, i & 1 == 1);
}
}
fn testPureBitSet(comptime Set: type) !void {
const empty = Set.initEmpty();
const full = Set.initFull();
const even = even: {
var bit_set = Set.initEmpty();
var i: usize = 0;
while (i < Set.bit_length) : (i += 1) {
bit_set.setValue(i, i & 1 == 0);
}
fillEven(&bit_set, Set.bit_length);
break :even bit_set;
};
const odd = odd: {
var bit_set = Set.initEmpty();
var i: usize = 0;
while (i < Set.bit_length) : (i += 1) {
bit_set.setValue(i, i & 1 == 1);
}
fillOdd(&bit_set, Set.bit_length);
break :odd bit_set;
};
try testing.expect(empty.subsetOf(empty));
try testing.expect(empty.subsetOf(full));
try testing.expect(full.subsetOf(full));
switch (Set.bit_length) {
0 => {
try testing.expect(even.subsetOf(odd));
try testing.expect(odd.subsetOf(even));
},
1 => {
try testing.expect(!even.subsetOf(odd));
try testing.expect(odd.subsetOf(even));
},
else => {
try testing.expect(!even.subsetOf(odd));
try testing.expect(!odd.subsetOf(even));
},
}
try testing.expect(full.supersetOf(full));
try testing.expect(full.supersetOf(empty));
try testing.expect(empty.supersetOf(empty));
switch (Set.bit_length) {
0 => {
try testing.expect(even.supersetOf(odd));
try testing.expect(odd.supersetOf(even));
},
1 => {
try testing.expect(even.supersetOf(odd));
try testing.expect(!odd.supersetOf(even));
},
else => {
try testing.expect(!even.supersetOf(odd));
try testing.expect(!odd.supersetOf(even));
},
}
try testSubsetOf(empty, full, even, odd, Set.bit_length);
try testSupersetOf(empty, full, even, odd, Set.bit_length);
try testing.expect(empty.complement().eql(full));
try testing.expect(full.complement().eql(empty));
@ -1621,33 +1666,45 @@ test "DynamicBitSetUnmanaged" {
for ([_]usize{ 1, 2, 31, 32, 33, 0, 65, 64, 63, 500, 254, 3000 }) |size| {
const old_len = a.capacity();
var tmp = try a.clone(allocator);
defer tmp.deinit(allocator);
try testing.expectEqual(old_len, tmp.capacity());
var empty = try a.clone(allocator);
defer empty.deinit(allocator);
try testing.expectEqual(old_len, empty.capacity());
var i: usize = 0;
while (i < old_len) : (i += 1) {
try testing.expectEqual(a.isSet(i), tmp.isSet(i));
try testing.expectEqual(a.isSet(i), empty.isSet(i));
}
a.toggleSet(a); // zero a
tmp.toggleSet(tmp);
empty.toggleSet(empty);
try a.resize(allocator, size, true);
try tmp.resize(allocator, size, false);
try empty.resize(allocator, size, false);
if (size > old_len) {
try testing.expectEqual(size - old_len, a.count());
} else {
try testing.expectEqual(@as(usize, 0), a.count());
}
try testing.expectEqual(@as(usize, 0), tmp.count());
try testing.expectEqual(@as(usize, 0), empty.count());
var b = try DynamicBitSetUnmanaged.initFull(allocator, size);
defer b.deinit(allocator);
try testing.expectEqual(@as(usize, size), b.count());
var full = try DynamicBitSetUnmanaged.initFull(allocator, size);
defer full.deinit(allocator);
try testing.expectEqual(@as(usize, size), full.count());
try testEql(tmp, b, size);
try testBitSet(&a, &b, size);
try testEql(empty, full, size);
{
var even = try DynamicBitSetUnmanaged.initEmpty(allocator, size);
defer even.deinit(allocator);
fillEven(&even, size);
var odd = try DynamicBitSetUnmanaged.initEmpty(allocator, size);
defer odd.deinit(allocator);
fillOdd(&odd, size);
try testSubsetOf(empty, full, even, odd, size);
try testSupersetOf(empty, full, even, odd, size);
}
try testBitSet(&a, &full, size);
}
}