| ... | @@ -110,6 +110,31 @@ pub fn IntegerBitSet(comptime size: u16) type { | ... | @@ -110,6 +110,31 @@ pub fn IntegerBitSet(comptime size: u16) type { |
| 110 | self.mask |= maskBit(index); | 110 | self.mask |= maskBit(index); |
| 111 | } | 111 | } |
| 112 | | 112 | |
| | 113 | /// Changes the value of all bits in the specified range to |
| | 114 | /// match the passed boolean. |
| | 115 | pub fn setRangeValue(self: *Self, range: Range, value: bool) void { |
| | 116 | assert(range.end <= bit_length); |
| | 117 | assert(range.start <= range.end); |
| | 118 | if (range.start == range.end) return; |
| | 119 | if (MaskInt == u0) return; |
| | 120 | |
| | 121 | const start_bit = @intCast(ShiftInt, range.start); |
| | 122 | |
| | 123 | var mask = std.math.boolMask(MaskInt, true) << start_bit; |
| | 124 | if (range.end != bit_length) { |
| | 125 | const end_bit = @intCast(ShiftInt, range.end); |
| | 126 | mask &= std.math.boolMask(MaskInt, true) >> @truncate(ShiftInt, @as(usize, @bitSizeOf(MaskInt)) - @as(usize, end_bit)); |
| | 127 | } |
| | 128 | self.mask &= ~mask; |
| | 129 | |
| | 130 | mask = std.math.boolMask(MaskInt, value) << start_bit; |
| | 131 | if (range.end != bit_length) { |
| | 132 | const end_bit = @intCast(ShiftInt, range.end); |
| | 133 | mask &= std.math.boolMask(MaskInt, value) >> @truncate(ShiftInt, @as(usize, @bitSizeOf(MaskInt)) - @as(usize, end_bit)); |
| | 134 | } |
| | 135 | self.mask |= mask; |
| | 136 | } |
| | 137 | |
| 113 | /// Removes a specific bit from the bit set | 138 | /// Removes a specific bit from the bit set |
| 114 | pub fn unset(self: *Self, index: usize) void { | 139 | pub fn unset(self: *Self, index: usize) void { |
| 115 | assert(index < bit_length); | 140 | assert(index < bit_length); |
| ... | @@ -345,6 +370,51 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { | ... | @@ -345,6 +370,51 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { |
| 345 | self.masks[maskIndex(index)] |= maskBit(index); | 370 | self.masks[maskIndex(index)] |= maskBit(index); |
| 346 | } | 371 | } |
| 347 | | 372 | |
| | 373 | /// Changes the value of all bits in the specified range to |
| | 374 | /// match the passed boolean. |
| | 375 | pub fn setRangeValue(self: *Self, range: Range, value: bool) void { |
| | 376 | assert(range.end <= bit_length); |
| | 377 | assert(range.start <= range.end); |
| | 378 | if (range.start == range.end) return; |
| | 379 | if (num_masks == 0) return; |
| | 380 | |
| | 381 | const start_mask_index = maskIndex(range.start); |
| | 382 | const start_bit = @truncate(ShiftInt, range.start); |
| | 383 | |
| | 384 | const end_mask_index = maskIndex(range.end); |
| | 385 | const end_bit = @truncate(ShiftInt, range.end); |
| | 386 | |
| | 387 | if (start_mask_index == end_mask_index) { |
| | 388 | var mask1 = std.math.boolMask(MaskInt, true) << start_bit; |
| | 389 | var mask2 = std.math.boolMask(MaskInt, true) >> (mask_len - 1) - (end_bit - 1); |
| | 390 | self.masks[start_mask_index] &= ~(mask1 & mask2); |
| | 391 | |
| | 392 | mask1 = std.math.boolMask(MaskInt, value) << start_bit; |
| | 393 | mask2 = std.math.boolMask(MaskInt, value) >> (mask_len - 1) - (end_bit - 1); |
| | 394 | self.masks[start_mask_index] |= mask1 & mask2; |
| | 395 | } else { |
| | 396 | var bulk_mask_index: usize = undefined; |
| | 397 | if (start_bit > 0) { |
| | 398 | self.masks[start_mask_index] = |
| | 399 | (self.masks[start_mask_index] & ~(std.math.boolMask(MaskInt, true) << start_bit)) | |
| | 400 | (std.math.boolMask(MaskInt, value) << start_bit); |
| | 401 | bulk_mask_index = start_mask_index + 1; |
| | 402 | } else { |
| | 403 | bulk_mask_index = start_mask_index; |
| | 404 | } |
| | 405 | |
| | 406 | while (bulk_mask_index < end_mask_index) : (bulk_mask_index += 1) { |
| | 407 | self.masks[bulk_mask_index] = std.math.boolMask(MaskInt, value); |
| | 408 | } |
| | 409 | |
| | 410 | if (end_bit > 0) { |
| | 411 | self.masks[end_mask_index] = |
| | 412 | (self.masks[end_mask_index] & (std.math.boolMask(MaskInt, true) << end_bit)) | |
| | 413 | (std.math.boolMask(MaskInt, value) >> ((@bitSizeOf(MaskInt) - 1) - (end_bit - 1))); |
| | 414 | } |
| | 415 | } |
| | 416 | } |
| | 417 | |
| 348 | /// Removes a specific bit from the bit set | 418 | /// Removes a specific bit from the bit set |
| 349 | pub fn unset(self: *Self, index: usize) void { | 419 | pub fn unset(self: *Self, index: usize) void { |
| 350 | assert(index < bit_length); | 420 | assert(index < bit_length); |
| ... | @@ -608,6 +678,50 @@ pub const DynamicBitSetUnmanaged = struct { | ... | @@ -608,6 +678,50 @@ pub const DynamicBitSetUnmanaged = struct { |
| 608 | self.masks[maskIndex(index)] |= maskBit(index); | 678 | self.masks[maskIndex(index)] |= maskBit(index); |
| 609 | } | 679 | } |
| 610 | | 680 | |
| | 681 | /// Changes the value of all bits in the specified range to |
| | 682 | /// match the passed boolean. |
| | 683 | pub fn setRangeValue(self: *Self, range: Range, value: bool) void { |
| | 684 | assert(range.end <= self.bit_length); |
| | 685 | assert(range.start <= range.end); |
| | 686 | if (range.start == range.end) return; |
| | 687 | |
| | 688 | const start_mask_index = maskIndex(range.start); |
| | 689 | const start_bit = @truncate(ShiftInt, range.start); |
| | 690 | |
| | 691 | const end_mask_index = maskIndex(range.end); |
| | 692 | const end_bit = @truncate(ShiftInt, range.end); |
| | 693 | |
| | 694 | if (start_mask_index == end_mask_index) { |
| | 695 | var mask1 = std.math.boolMask(MaskInt, true) << start_bit; |
| | 696 | var mask2 = std.math.boolMask(MaskInt, true) >> (@bitSizeOf(MaskInt) - 1) - (end_bit - 1); |
| | 697 | self.masks[start_mask_index] &= ~(mask1 & mask2); |
| | 698 | |
| | 699 | mask1 = std.math.boolMask(MaskInt, value) << start_bit; |
| | 700 | mask2 = std.math.boolMask(MaskInt, value) >> (@bitSizeOf(MaskInt) - 1) - (end_bit - 1); |
| | 701 | self.masks[start_mask_index] |= mask1 & mask2; |
| | 702 | } else { |
| | 703 | var bulk_mask_index: usize = undefined; |
| | 704 | if (start_bit > 0) { |
| | 705 | self.masks[start_mask_index] = |
| | 706 | (self.masks[start_mask_index] & ~(std.math.boolMask(MaskInt, true) << start_bit)) | |
| | 707 | (std.math.boolMask(MaskInt, value) << start_bit); |
| | 708 | bulk_mask_index = start_mask_index + 1; |
| | 709 | } else { |
| | 710 | bulk_mask_index = start_mask_index; |
| | 711 | } |
| | 712 | |
| | 713 | while (bulk_mask_index < end_mask_index) : (bulk_mask_index += 1) { |
| | 714 | self.masks[bulk_mask_index] = std.math.boolMask(MaskInt, value); |
| | 715 | } |
| | 716 | |
| | 717 | if (end_bit > 0) { |
| | 718 | self.masks[end_mask_index] = |
| | 719 | (self.masks[end_mask_index] & (std.math.boolMask(MaskInt, true) << end_bit)) | |
| | 720 | (std.math.boolMask(MaskInt, value) >> ((@bitSizeOf(MaskInt) - 1) - (end_bit - 1))); |
| | 721 | } |
| | 722 | } |
| | 723 | } |
| | 724 | |
| 611 | /// Removes a specific bit from the bit set | 725 | /// Removes a specific bit from the bit set |
| 612 | pub fn unset(self: *Self, index: usize) void { | 726 | pub fn unset(self: *Self, index: usize) void { |
| 613 | assert(index < self.bit_length); | 727 | assert(index < self.bit_length); |
| ... | @@ -811,6 +925,12 @@ pub const DynamicBitSet = struct { | ... | @@ -811,6 +925,12 @@ pub const DynamicBitSet = struct { |
| 811 | self.unmanaged.set(index); | 925 | self.unmanaged.set(index); |
| 812 | } | 926 | } |
| 813 | | 927 | |
| | 928 | /// Changes the value of all bits in the specified range to |
| | 929 | /// match the passed boolean. |
| | 930 | pub fn setRangeValue(self: *Self, range: Range, value: bool) void { |
| | 931 | self.unmanaged.setRangeValue(range, value); |
| | 932 | } |
| | 933 | |
| 814 | /// Removes a specific bit from the bit set | 934 | /// Removes a specific bit from the bit set |
| 815 | pub fn unset(self: *Self, index: usize) void { | 935 | pub fn unset(self: *Self, index: usize) void { |
| 816 | self.unmanaged.unset(index); | 936 | self.unmanaged.unset(index); |
| ... | @@ -990,6 +1110,14 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ | ... | @@ -990,6 +1110,14 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ |
| 990 | }; | 1110 | }; |
| 991 | } | 1111 | } |
| 992 | | 1112 | |
| | 1113 | /// A range of indices within a bitset. |
| | 1114 | pub const Range = struct { |
| | 1115 | /// The index of the first bit of interest. |
| | 1116 | start: usize, |
| | 1117 | /// The index immediately after the last bit of interest. |
| | 1118 | end: usize, |
| | 1119 | }; |
| | 1120 | |
| 993 | // ---------------- Tests ----------------- | 1121 | // ---------------- Tests ----------------- |
| 994 | | 1122 | |
| 995 | const testing = std.testing; | 1123 | const testing = std.testing; |
| ... | @@ -1144,6 +1272,52 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void { | ... | @@ -1144,6 +1272,52 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void { |
| 1144 | try testing.expectEqual(@as(?usize, null), a.findFirstSet()); | 1272 | try testing.expectEqual(@as(?usize, null), a.findFirstSet()); |
| 1145 | try testing.expectEqual(@as(?usize, null), a.toggleFirstSet()); | 1273 | try testing.expectEqual(@as(?usize, null), a.toggleFirstSet()); |
| 1146 | try testing.expectEqual(@as(usize, 0), a.count()); | 1274 | try testing.expectEqual(@as(usize, 0), a.count()); |
| | 1275 | |
| | 1276 | a.setRangeValue(.{ .start = 0, .end = len }, false); |
| | 1277 | try testing.expectEqual(@as(usize, 0), a.count()); |
| | 1278 | |
| | 1279 | a.setRangeValue(.{ .start = 0, .end = len }, true); |
| | 1280 | try testing.expectEqual(len, a.count()); |
| | 1281 | |
| | 1282 | a.setRangeValue(.{ .start = 0, .end = len }, false); |
| | 1283 | a.setRangeValue(.{ .start = 0, .end = 0 }, true); |
| | 1284 | try testing.expectEqual(@as(usize, 0), a.count()); |
| | 1285 | |
| | 1286 | a.setRangeValue(.{ .start = len, .end = len }, true); |
| | 1287 | try testing.expectEqual(@as(usize, 0), a.count()); |
| | 1288 | |
| | 1289 | if (len >= 1) { |
| | 1290 | a.setRangeValue(.{ .start = 0, .end = len }, false); |
| | 1291 | a.setRangeValue(.{ .start = 0, .end = 1 }, true); |
| | 1292 | try testing.expectEqual(@as(usize, 1), a.count()); |
| | 1293 | try testing.expect(a.isSet(0)); |
| | 1294 | |
| | 1295 | a.setRangeValue(.{ .start = 0, .end = len }, false); |
| | 1296 | a.setRangeValue(.{ .start = 0, .end = len - 1 }, true); |
| | 1297 | try testing.expectEqual(len - 1, a.count()); |
| | 1298 | try testing.expect(!a.isSet(len - 1)); |
| | 1299 | |
| | 1300 | a.setRangeValue(.{ .start = 0, .end = len }, false); |
| | 1301 | a.setRangeValue(.{ .start = 1, .end = len }, true); |
| | 1302 | try testing.expectEqual(@as(usize, len - 1), a.count()); |
| | 1303 | try testing.expect(!a.isSet(0)); |
| | 1304 | |
| | 1305 | a.setRangeValue(.{ .start = 0, .end = len }, false); |
| | 1306 | a.setRangeValue(.{ .start = len - 1, .end = len }, true); |
| | 1307 | try testing.expectEqual(@as(usize, 1), a.count()); |
| | 1308 | try testing.expect(a.isSet(len - 1)); |
| | 1309 | |
| | 1310 | if (len >= 4) { |
| | 1311 | a.setRangeValue(.{ .start = 0, .end = len }, false); |
| | 1312 | a.setRangeValue(.{ .start = 1, .end = len - 2 }, true); |
| | 1313 | try testing.expectEqual(@as(usize, len - 3), a.count()); |
| | 1314 | try testing.expect(!a.isSet(0)); |
| | 1315 | try testing.expect(a.isSet(1)); |
| | 1316 | try testing.expect(a.isSet(len - 3)); |
| | 1317 | try testing.expect(!a.isSet(len - 2)); |
| | 1318 | try testing.expect(!a.isSet(len - 1)); |
| | 1319 | } |
| | 1320 | } |
| 1147 | } | 1321 | } |
| 1148 | | 1322 | |
| 1149 | fn testStaticBitSet(comptime Set: type) !void { | 1323 | fn testStaticBitSet(comptime Set: type) !void { |