| ... | ... | @@ -110,6 +110,31 @@ pub fn IntegerBitSet(comptime size: u16) type { |
| 110 | 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 | 138 | /// Removes a specific bit from the bit set |
| 114 | 139 | pub fn unset(self: *Self, index: usize) void { |
| 115 | 140 | assert(index < bit_length); |
| ... | ... | @@ -345,6 +370,51 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { |
| 345 | 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 | 418 | /// Removes a specific bit from the bit set |
| 349 | 419 | pub fn unset(self: *Self, index: usize) void { |
| 350 | 420 | assert(index < bit_length); |
| ... | ... | @@ -608,6 +678,50 @@ pub const DynamicBitSetUnmanaged = struct { |
| 608 | 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 | 725 | /// Removes a specific bit from the bit set |
| 612 | 726 | pub fn unset(self: *Self, index: usize) void { |
| 613 | 727 | assert(index < self.bit_length); |
| ... | ... | @@ -811,6 +925,12 @@ pub const DynamicBitSet = struct { |
| 811 | 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 | 934 | /// Removes a specific bit from the bit set |
| 815 | 935 | pub fn unset(self: *Self, index: usize) void { |
| 816 | 936 | self.unmanaged.unset(index); |
| ... | ... | @@ -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 | 1121 | // ---------------- Tests ----------------- |
| 994 | 1122 | |
| 995 | 1123 | const testing = std.testing; |
| ... | ... | @@ -1144,6 +1272,52 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void { |
| 1144 | 1272 | try testing.expectEqual(@as(?usize, null), a.findFirstSet()); |
| 1145 | 1273 | try testing.expectEqual(@as(?usize, null), a.toggleFirstSet()); |
| 1146 | 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 | 1323 | fn testStaticBitSet(comptime Set: type) !void { |