std: add bit_set.findLastSet() (#22411)

This commit is contained in:
Meghan Denny 2025-03-24 07:12:23 -08:00 committed by GitHub
parent c1db72cdbc
commit 972cab5bb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -184,6 +184,14 @@ pub fn IntegerBitSet(comptime size: u16) type {
return @ctz(mask); return @ctz(mask);
} }
/// Finds the index of the last set bit.
/// If no bits are set, returns null.
pub fn findLastSet(self: Self) ?usize {
const mask = self.mask;
if (mask == 0) return null;
return bit_length - @clz(mask) - 1;
}
/// Finds the index of the first set bit, and unsets it. /// Finds the index of the first set bit, and unsets it.
/// If no bits are set, returns null. /// If no bits are set, returns null.
pub fn toggleFirstSet(self: *Self) ?usize { pub fn toggleFirstSet(self: *Self) ?usize {
@ -542,6 +550,24 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
return offset + @ctz(mask); return offset + @ctz(mask);
} }
/// Finds the index of the last set bit.
/// If no bits are set, returns null.
pub fn findLastSet(self: Self) ?usize {
if (bit_length == 0) return null;
const bs = @bitSizeOf(MaskInt);
var len = bit_length / bs;
if (bit_length % bs != 0) len += 1;
var offset: usize = len * bs;
var idx: usize = len - 1;
while (self.masks[idx] == 0) : (idx -= 1) {
offset -= bs;
if (idx == 0) return null;
}
offset -= @clz(self.masks[idx]);
offset -= 1;
return offset;
}
/// Finds the index of the first set bit, and unsets it. /// Finds the index of the first set bit, and unsets it.
/// If no bits are set, returns null. /// If no bits are set, returns null.
pub fn toggleFirstSet(self: *Self) ?usize { pub fn toggleFirstSet(self: *Self) ?usize {
@ -941,6 +967,24 @@ pub const DynamicBitSetUnmanaged = struct {
return offset + @ctz(mask[0]); return offset + @ctz(mask[0]);
} }
/// Finds the index of the last set bit.
/// If no bits are set, returns null.
pub fn findLastSet(self: Self) ?usize {
if (self.bit_length == 0) return null;
const bs = @bitSizeOf(MaskInt);
var len = self.bit_length / bs;
if (self.bit_length % bs != 0) len += 1;
var offset: usize = len * bs;
var idx: usize = len - 1;
while (self.masks[idx] == 0) : (idx -= 1) {
offset -= bs;
if (idx == 0) return null;
}
offset -= @clz(self.masks[idx]);
offset -= 1;
return offset;
}
/// Finds the index of the first set bit, and unsets it. /// Finds the index of the first set bit, and unsets it.
/// If no bits are set, returns null. /// If no bits are set, returns null.
pub fn toggleFirstSet(self: *Self) ?usize { pub fn toggleFirstSet(self: *Self) ?usize {
@ -1160,6 +1204,12 @@ pub const DynamicBitSet = struct {
return self.unmanaged.findFirstSet(); return self.unmanaged.findFirstSet();
} }
/// Finds the index of the last set bit.
/// If no bits are set, returns null.
pub fn findLastSet(self: Self) ?usize {
return self.unmanaged.findLastSet();
}
/// Finds the index of the first set bit, and unsets it. /// Finds the index of the first set bit, and unsets it.
/// If no bits are set, returns null. /// If no bits are set, returns null.
pub fn toggleFirstSet(self: *Self) ?usize { pub fn toggleFirstSet(self: *Self) ?usize {
@ -1514,8 +1564,10 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void {
} }
} }
try testing.expectEqual(@as(?usize, null), a.findFirstSet()); try testing.expectEqual(@as(?usize, null), a.findFirstSet());
try testing.expectEqual(@as(?usize, null), a.findLastSet());
try testing.expectEqual(@as(?usize, null), a.toggleFirstSet()); try testing.expectEqual(@as(?usize, null), a.toggleFirstSet());
try testing.expectEqual(@as(?usize, null), a.findFirstSet()); try testing.expectEqual(@as(?usize, null), a.findFirstSet());
try testing.expectEqual(@as(?usize, null), a.findLastSet());
try testing.expectEqual(@as(?usize, null), a.toggleFirstSet()); try testing.expectEqual(@as(?usize, null), a.toggleFirstSet());
try testing.expectEqual(@as(usize, 0), a.count()); try testing.expectEqual(@as(usize, 0), a.count());