Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std.DynamicBitSetUnmanaged: respect padding bits #19945

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions lib/std/bit_set.zig
Original file line number Diff line number Diff line change
Expand Up @@ -865,10 +865,17 @@ pub const DynamicBitSetUnmanaged = struct {
@memset(self.masks[0..masks_len], 0);
}

/// Set all bits to 1.
/// Set all bits to 1. Leaves padding bits unchanged.
pub fn setAll(self: *Self) void {
const masks_len = numMasks(self.bit_length);
@memset(self.masks[0..masks_len], std.math.maxInt(MaskInt));
const full_masks_len = self.bit_length / @bitSizeOf(MaskInt);
const last_mask_bit_len = self.bit_length % @bitSizeOf(MaskInt);
const mask = ~@as(MaskInt, 0);
@memset(self.masks[0..full_masks_len], mask);
// @truncate instead of @intCast to avoid overflow when
// last_mask_bit_len == 0 (when bit_length is a multiple of
// @bitSizeOf(MaskInt))
self.masks[full_masks_len] |=
mask >> @truncate(@bitSizeOf(MaskInt) - last_mask_bit_len);
}

/// Flips a specific bit in the bit set
Expand Down Expand Up @@ -1295,6 +1302,7 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ
}
},
}

switch (direction) {
.forward => self.words_remain = self.words_remain[1..],
.reverse => self.words_remain.len -= 1,
Expand Down Expand Up @@ -1672,7 +1680,7 @@ test ArrayBitSet {
}

test DynamicBitSetUnmanaged {
const allocator = std.testing.allocator;
const allocator = testing.allocator;
var a = try DynamicBitSetUnmanaged.initEmpty(allocator, 300);
try testing.expectEqual(@as(usize, 0), a.count());
a.deinit(allocator);
Expand Down Expand Up @@ -1722,10 +1730,29 @@ test DynamicBitSetUnmanaged {
}
try testBitSet(&a, &full, size);
}

// from https://github.com/ziglang/zig/issues/19933
// check that setAll() doesn't change padding bits
var bitset = try DynamicBitSetUnmanaged.initFull(allocator, 19);
defer bitset.deinit(allocator);
bitset.setAll();
try testing.expectEqual(19, bitset.count());
// check that iterator() loops count times
try testing.expectEqual(19, iterCount(bitset, .{}));
try testing.expectEqual(19, iterCount(bitset, .{ .direction = .reverse }));
try testing.expectEqual(0, iterCount(bitset, .{ .kind = .unset }));
try testing.expectEqual(0, iterCount(bitset, .{ .kind = .unset, .direction = .reverse }));
}

fn iterCount(bitset: DynamicBitSetUnmanaged, comptime options: IteratorOptions) usize {
var iter = bitset.iterator(options);
var result: usize = 0;
while (iter.next()) |_| : (result += 1) {}
return result;
}

test DynamicBitSet {
const allocator = std.testing.allocator;
const allocator = testing.allocator;
var a = try DynamicBitSet.initEmpty(allocator, 300);
try testing.expectEqual(@as(usize, 0), a.count());
a.deinit();
Expand Down