authorgravatar for me@arnavion.devArnavion <me@arnavion.dev> 2021-12-22 16:48:46-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-07 14:58:07-05:00
log2a415a033cce07b579a490eca2556e7d700c04b1
tree5c51516a4bcb9a227cbcd7a1bf736085472af866
parent8a94971980001d29d7c8cdfe6ca25aa834552405

std.bit_set: add setRangeValue(Range, bool)

For large ranges, this is faster than having the caller call setValue() for each index in the range. Masks wholly covered by the range can be set to the new mask value in one go, and the two masks at either end that are partially covered can each set the covered range of bits in one go.

1 files changed, 174 insertions(+), 0 deletions(-)

lib/std/bit_set.zig+174
......@@ -110,6 +110,31 @@ pub fn IntegerBitSet(comptime size: u16) type {
110110 self.mask |= maskBit(index);
111111 }
112112
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
113138 /// Removes a specific bit from the bit set
114139 pub fn unset(self: *Self, index: usize) void {
115140 assert(index < bit_length);
......@@ -345,6 +370,51 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
345370 self.masks[maskIndex(index)] |= maskBit(index);
346371 }
347372
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
348418 /// Removes a specific bit from the bit set
349419 pub fn unset(self: *Self, index: usize) void {
350420 assert(index < bit_length);
......@@ -608,6 +678,50 @@ pub const DynamicBitSetUnmanaged = struct {
608678 self.masks[maskIndex(index)] |= maskBit(index);
609679 }
610680
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
611725 /// Removes a specific bit from the bit set
612726 pub fn unset(self: *Self, index: usize) void {
613727 assert(index < self.bit_length);
......@@ -811,6 +925,12 @@ pub const DynamicBitSet = struct {
811925 self.unmanaged.set(index);
812926 }
813927
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
814934 /// Removes a specific bit from the bit set
815935 pub fn unset(self: *Self, index: usize) void {
816936 self.unmanaged.unset(index);
......@@ -990,6 +1110,14 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ
9901110 };
9911111}
9921112
1113/// A range of indices within a bitset.
1114pub 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
9931121// ---------------- Tests -----------------
9941122
9951123const testing = std.testing;
......@@ -1144,6 +1272,52 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void {
11441272 try testing.expectEqual(@as(?usize, null), a.findFirstSet());
11451273 try testing.expectEqual(@as(?usize, null), a.toggleFirstSet());
11461274 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 }
11471321}
11481322
11491323fn testStaticBitSet(comptime Set: type) !void {