authorgravatar for spexguy070@gmail.comMartin Wickham <spexguy070@gmail.com> 2021-02-04 23:04:49-06:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-01 18:52:15-08:00
log7613e51a57d2e2d0ae7d1101d059002f12b96c43
tree9f0af291873f4698f56339a20989c82fcc96de5f
parent1f861ecc95a827fc979f3371901f1ae93dd2c283

Add some bit set variants


4 files changed, 1322 insertions(+), 0 deletions(-)

lib/std/bit_set.zig created+1254
...@@ -0,0 +1,1254 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("std");
8const assert = std.debug.assert;
9const Allocator = std.mem.Allocator;
10
11//! This file defines several variants of bit sets. A bit set
12//! is a densely stored set of integers with a known maximum,
13//! in which each integer gets a single bit. Bit sets have very
14//! fast presence checks, update operations, and union and intersection
15//! operations. However, if the number of possible items is very
16//! large and the number of actual items in a given set is usually
17//! small, they may be less memory efficient than an array set.
18//!
19//! There are five variants defined here:
20//!
21//! IntegerBitSet:
22//! A bit set with static size, which is backed by a single integer.
23//! This set is good for sets with a small size, but may generate
24//! inefficient code for larger sets, especially in debug mode.
25//!
26//! ArrayBitSet:
27//! A bit set with static size, which is backed by an array of usize.
28//! This set is good for sets with a larger size, but may use
29//! more bytes than necessary if your set is small.
30//!
31//! StaticBitSet:
32//! Picks either IntegerBitSet or ArrayBitSet depending on the requested
33//! size. The interfaces of these two types match exactly, except for fields.
34//!
35//! DynamicBitSet:
36//! A bit set with runtime known size, backed by an allocated slice
37//! of usize.
38//!
39//! DynamicBitSetUnmanaged:
40//! A variant of DynamicBitSet which does not store a pointer to its
41//! allocator, in order to save space.
42
43/// Returns the optimal static bit set type for the specified number
44/// of elements. The returned type will perform no allocations,
45/// can be copied by value, and does not require deinitialization.
46/// Both possible implementations fulfill the same interface.
47pub fn StaticBitSet(comptime size: usize) type {
48 if (size <= @bitSizeOf(usize)) {
49 return IntegerBitSet(size);
50 } else {
51 return ArrayBitSet(usize, size);
52 }
53}
54
55/// A bit set with static size, which is backed by a single integer.
56/// This set is good for sets with a small size, but may generate
57/// inefficient code for larger sets, especially in debug mode.
58pub fn IntegerBitSet(comptime size: u16) type {
59 return struct {
60 const Self = @This();
61
62 // TODO: Make this a comptime field once those are fixed
63 /// The number of items in this bit set
64 pub const bit_length: usize = size;
65
66 /// The integer type used to represent a mask in this bit set
67 pub const MaskInt = std.meta.Int(.unsigned, size);
68
69 /// The integer type used to shift a mask in this bit set
70 pub const ShiftInt = std.math.Log2Int(MaskInt);
71
72 /// The bit mask, as a single integer
73 mask: MaskInt,
74
75 /// Creates a bit set with no elements present.
76 pub fn initEmpty() Self {
77 return .{ .mask = 0 };
78 }
79
80 /// Creates a bit set with all elements present.
81 pub fn initFull() Self {
82 return .{ .mask = ~@as(MaskInt, 0) };
83 }
84
85 /// Returns the number of bits in this bit set
86 pub inline fn capacity(self: Self) usize {
87 return bit_length;
88 }
89
90 /// Returns true if the bit at the specified index
91 /// is present in the set, false otherwise.
92 pub fn isSet(self: Self, index: usize) bool {
93 assert(index < bit_length);
94 return (self.mask & maskBit(index)) != 0;
95 }
96
97 /// Returns the total number of set bits in this bit set.
98 pub fn count(self: Self) usize {
99 return @popCount(MaskInt, self.mask);
100 }
101
102 /// Changes the value of the specified bit of the bit
103 /// set to match the passed boolean.
104 pub fn setValue(self: *Self, index: usize, value: bool) void {
105 assert(index < bit_length);
106 if (MaskInt == u0) return;
107 const bit = maskBit(index);
108 const new_bit = bit & std.math.boolMask(MaskInt, value);
109 self.mask = (self.mask & ~bit) | new_bit;
110 }
111
112 /// Adds a specific bit to the bit set
113 pub fn set(self: *Self, index: usize) void {
114 assert(index < bit_length);
115 self.mask |= maskBit(index);
116 }
117
118 /// Removes a specific bit from the bit set
119 pub fn unset(self: *Self, index: usize) void {
120 assert(index < bit_length);
121 // Workaround for #7953
122 if (MaskInt == u0) return;
123 self.mask &= ~maskBit(index);
124 }
125
126 /// Flips a specific bit in the bit set
127 pub fn toggle(self: *Self, index: usize) void {
128 assert(index < bit_length);
129 self.mask ^= maskBit(index);
130 }
131
132 /// Flips all bits in this bit set which are present
133 /// in the toggles bit set.
134 pub fn toggleSet(self: *Self, toggles: Self) void {
135 self.mask ^= toggles.mask;
136 }
137
138 /// Flips every bit in the bit set.
139 pub fn toggleAll(self: *Self) void {
140 self.mask = ~self.mask;
141 }
142
143 /// Performs a union of two bit sets, and stores the
144 /// result in the first one. Bits in the result are
145 /// set if the corresponding bits were set in either input.
146 pub fn setUnion(self: *Self, other: Self) void {
147 self.mask |= other.mask;
148 }
149
150 /// Performs an intersection of two bit sets, and stores
151 /// the result in the first one. Bits in the result are
152 /// set if the corresponding bits were set in both inputs.
153 pub fn setIntersection(self: *Self, other: Self) void {
154 self.mask &= other.mask;
155 }
156
157 /// Finds the index of the first set bit.
158 /// If no bits are set, returns null.
159 pub fn findFirstSet(self: Self) ?usize {
160 const mask = self.mask;
161 if (mask == 0) return null;
162 return @ctz(MaskInt, mask);
163 }
164
165 /// Finds the index of the first set bit, and unsets it.
166 /// If no bits are set, returns null.
167 pub fn toggleFirstSet(self: *Self) ?usize {
168 const mask = self.mask;
169 if (mask == 0) return null;
170 const index = @ctz(MaskInt, mask);
171 self.mask = mask & (mask-1);
172 return index;
173 }
174
175 /// Iterates through the items in the set, according to the options.
176 /// The default options (.{}) will iterate indices of set bits in
177 /// ascending order. Modifications to the underlying bit set may
178 /// or may not be observed by the iterator.
179 pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options.direction) {
180 return .{
181 .bits_remain = switch (options.kind) {
182 .set => self.mask,
183 .unset => ~self.mask,
184 },
185 };
186 }
187
188 fn Iterator(comptime direction: IteratorOptions.Direction) type {
189 return struct {
190 const IterSelf = @This();
191 // all bits which have not yet been iterated over
192 bits_remain: MaskInt,
193
194 /// Returns the index of the next unvisited set bit
195 /// in the bit set, in ascending order.
196 pub fn next(self: *IterSelf) ?usize {
197 if (self.bits_remain == 0) return null;
198
199 switch (direction) {
200 .forward => {
201 const next_index = @ctz(MaskInt, self.bits_remain);
202 self.bits_remain &= self.bits_remain - 1;
203 return next_index;
204 },
205 .reverse => {
206 const leading_zeroes = @clz(MaskInt, self.bits_remain);
207 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
208 self.bits_remain &= (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
209 return top_bit;
210 },
211 }
212 }
213 };
214 }
215
216 fn maskBit(index: usize) MaskInt {
217 if (MaskInt == u0) return 0;
218 return @as(MaskInt, 1) << @intCast(ShiftInt, index);
219 }
220 fn boolMaskBit(index: usize, value: bool) MaskInt {
221 if (MaskInt == u0) return 0;
222 return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
223 }
224 };
225}
226
227/// A bit set with static size, which is backed by an array of usize.
228/// This set is good for sets with a larger size, but may use
229/// more bytes than necessary if your set is small.
230pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
231 const mask_info: std.builtin.TypeInfo = @typeInfo(MaskIntType);
232
233 // Make sure the mask int is indeed an int
234 if (mask_info != .Int) @compileError("ArrayBitSet can only operate on integer masks, but was passed " ++ @typeName(MaskIntType));
235
236 // It must also be unsigned.
237 if (mask_info.Int.signedness != .unsigned) @compileError("ArrayBitSet requires an unsigned integer mask type, but was passed " ++ @typeName(MaskIntType));
238
239 // And it must not be empty.
240 if (MaskIntType == u0)
241 @compileError("ArrayBitSet requires a sized integer for its mask int. u0 does not work.");
242
243 const byte_size = std.mem.byte_size_in_bits;
244
245 // We use shift and truncate to decompose indices into mask indices and bit indices.
246 // This operation requires that the mask has an exact power of two number of bits.
247 if (!std.math.isPowerOfTwo(@bitSizeOf(MaskIntType))) {
248 var desired_bits = std.math.ceilPowerOfTwoAssert(usize, @bitSizeOf(MaskIntType));
249 if (desired_bits < byte_size) desired_bits = byte_size;
250 const FixedMaskType = std.meta.Int(.unsigned, desired_bits);
251 @compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++
252 ", which is not a power of two. Please round this up to a power of two integer size (i.e. " ++ @typeName(FixedMaskType) ++ ").");
253 }
254
255 // Make sure the integer has no padding bits.
256 // Those would be wasteful here and are probably a mistake by the user.
257 // This case may be hit with small powers of two, like u4.
258 if (@bitSizeOf(MaskIntType) != @sizeOf(MaskIntType) * byte_size) {
259 var desired_bits = @sizeOf(MaskIntType) * byte_size;
260 desired_bits = std.math.ceilPowerOfTwoAssert(usize, desired_bits);
261 const FixedMaskType = std.meta.Int(.unsigned, desired_bits);
262 @compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++
263 ", which contains padding bits. Please round this up to an unpadded integer size (i.e. " ++ @typeName(FixedMaskType) ++ ").");
264 }
265
266 return struct {
267 const Self = @This();
268
269 // TODO: Make this a comptime field once those are fixed
270 /// The number of items in this bit set
271 pub const bit_length: usize = size;
272
273 /// The integer type used to represent a mask in this bit set
274 pub const MaskInt = MaskIntType;
275
276 /// The integer type used to shift a mask in this bit set
277 pub const ShiftInt = std.math.Log2Int(MaskInt);
278
279 // bits in one mask
280 const mask_len = @bitSizeOf(MaskInt);
281 // total number of masks
282 const num_masks = (size + mask_len - 1) / mask_len;
283 // padding bits in the last mask (may be 0)
284 const last_pad_bits = mask_len * num_masks - size;
285 // Mask of valid bits in the last mask.
286 // All functions will ensure that the invalid
287 // bits in the last mask are zero.
288 pub const last_item_mask = ~@as(MaskInt, 0) >> last_pad_bits;
289
290 /// The bit masks, ordered with lower indices first.
291 /// Padding bits at the end are undefined.
292 masks: [num_masks]MaskInt,
293
294 /// Creates a bit set with no elements present.
295 pub fn initEmpty() Self {
296 return .{ .masks = [_]MaskInt{0} ** num_masks };
297 }
298
299 /// Creates a bit set with all elements present.
300 pub fn initFull() Self {
301 if (num_masks == 0) {
302 return .{ .masks = .{} };
303 } else {
304 return .{ .masks = [_]MaskInt{~@as(MaskInt, 0)} ** (num_masks - 1) ++ [_]MaskInt{last_item_mask} };
305 }
306 }
307
308 /// Returns the number of bits in this bit set
309 pub inline fn capacity(self: Self) usize {
310 return bit_length;
311 }
312
313 /// Returns true if the bit at the specified index
314 /// is present in the set, false otherwise.
315 pub fn isSet(self: Self, index: usize) bool {
316 assert(index < bit_length);
317 if (num_masks == 0) return false; // doesn't compile in this case
318 return (self.masks[maskIndex(index)] & maskBit(index)) != 0;
319 }
320
321 /// Returns the total number of set bits in this bit set.
322 pub fn count(self: Self) usize {
323 var total: usize = 0;
324 for (self.masks) |mask| {
325 total += @popCount(MaskInt, mask);
326 }
327 return total;
328 }
329
330 /// Changes the value of the specified bit of the bit
331 /// set to match the passed boolean.
332 pub fn setValue(self: *Self, index: usize, value: bool) void {
333 assert(index < bit_length);
334 if (num_masks == 0) return; // doesn't compile in this case
335 const bit = maskBit(index);
336 const mask_index = maskIndex(index);
337 const new_bit = bit & std.math.boolMask(MaskInt, value);
338 self.masks[mask_index] = (self.masks[mask_index] & ~bit) | new_bit;
339 }
340
341 /// Adds a specific bit to the bit set
342 pub fn set(self: *Self, index: usize) void {
343 assert(index < bit_length);
344 if (num_masks == 0) return; // doesn't compile in this case
345 self.masks[maskIndex(index)] |= maskBit(index);
346 }
347
348 /// Removes a specific bit from the bit set
349 pub fn unset(self: *Self, index: usize) void {
350 assert(index < bit_length);
351 if (num_masks == 0) return; // doesn't compile in this case
352 self.masks[maskIndex(index)] &= ~maskBit(index);
353 }
354
355 /// Flips a specific bit in the bit set
356 pub fn toggle(self: *Self, index: usize) void {
357 assert(index < bit_length);
358 if (num_masks == 0) return; // doesn't compile in this case
359 self.masks[maskIndex(index)] ^= maskBit(index);
360 }
361
362 /// Flips all bits in this bit set which are present
363 /// in the toggles bit set.
364 pub fn toggleSet(self: *Self, toggles: Self) void {
365 for (self.masks) |*mask, i| {
366 mask.* ^= toggles.masks[i];
367 }
368 }
369
370 /// Flips every bit in the bit set.
371 pub fn toggleAll(self: *Self) void {
372 for (self.masks) |*mask, i| {
373 mask.* = ~mask.*;
374 }
375
376 // Zero the padding bits
377 if (num_masks > 0) {
378 self.masks[num_masks - 1] &= last_item_mask;
379 }
380 }
381
382 /// Performs a union of two bit sets, and stores the
383 /// result in the first one. Bits in the result are
384 /// set if the corresponding bits were set in either input.
385 pub fn setUnion(self: *Self, other: Self) void {
386 for (self.masks) |*mask, i| {
387 mask.* |= other.masks[i];
388 }
389 }
390
391 /// Performs an intersection of two bit sets, and stores
392 /// the result in the first one. Bits in the result are
393 /// set if the corresponding bits were set in both inputs.
394 pub fn setIntersection(self: *Self, other: Self) void {
395 for (self.masks) |*mask, i| {
396 mask.* &= other.masks[i];
397 }
398 }
399
400 /// Finds the index of the first set bit.
401 /// If no bits are set, returns null.
402 pub fn findFirstSet(self: Self) ?usize {
403 var offset: usize = 0;
404 const mask = for (self.masks) |mask| {
405 if (mask != 0) break mask;
406 offset += @bitSizeOf(MaskInt);
407 } else return null;
408 return offset + @ctz(MaskInt, mask);
409 }
410
411 /// Finds the index of the first set bit, and unsets it.
412 /// If no bits are set, returns null.
413 pub fn toggleFirstSet(self: *Self) ?usize {
414 var offset: usize = 0;
415 const mask = for (self.masks) |*mask| {
416 if (mask.* != 0) break mask;
417 offset += @bitSizeOf(MaskInt);
418 } else return null;
419 const index = @ctz(MaskInt, mask.*);
420 mask.* &= (mask.* - 1);
421 return offset + index;
422 }
423
424 /// Iterates through the items in the set, according to the options.
425 /// The default options (.{}) will iterate indices of set bits in
426 /// ascending order. Modifications to the underlying bit set may
427 /// or may not be observed by the iterator.
428 pub fn iterator(self: *const Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
429 return BitSetIterator(MaskInt, options).init(&self.masks, last_item_mask);
430 }
431
432 fn maskBit(index: usize) MaskInt {
433 return @as(MaskInt, 1) << @truncate(ShiftInt, index);
434 }
435 fn maskIndex(index: usize) usize {
436 return index >> @bitSizeOf(ShiftInt);
437 }
438 fn boolMaskBit(index: usize, value: bool) MaskInt {
439 return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
440 }
441 };
442}
443
444/// A bit set with runtime known size, backed by an allocated slice
445/// of usize. The allocator must be tracked externally by the user.
446pub const DynamicBitSetUnmanaged = struct {
447 const Self = @This();
448
449 /// The integer type used to represent a mask in this bit set
450 pub const MaskInt = usize;
451
452 /// The integer type used to shift a mask in this bit set
453 pub const ShiftInt = std.math.Log2Int(MaskInt);
454
455 /// The number of valid items in this bit set
456 bit_length: usize = 0,
457
458 /// The bit masks, ordered with lower indices first.
459 /// Padding bits at the end must be zeroed.
460 masks: [*]MaskInt = empty_masks_ptr,
461 // This pointer is one usize after the actual allocation.
462 // That slot holds the size of the true allocation, which
463 // is needed by Zig's allocator interface in case a shrink
464 // fails.
465
466 // Don't modify this value. Ideally it would go in const data so
467 // modifications would cause a bus error, but the only way
468 // to discard a const qualifier is through ptrToInt, which
469 // cannot currently round trip at comptime.
470 var empty_masks_data = [_]MaskInt{ 0, undefined };
471 const empty_masks_ptr = empty_masks_data[1..2];
472
473 /// Creates a bit set with no elements present.
474 /// If bit_length is not zero, deinit must eventually be called.
475 pub fn initEmpty(bit_length: usize, allocator: *Allocator) !Self {
476 var self = Self{};
477 try self.resize(bit_length, false, allocator);
478 return self;
479 }
480
481 /// Creates a bit set with all elements present.
482 /// If bit_length is not zero, deinit must eventually be called.
483 pub fn initFull(bit_length: usize, allocator: *Allocator) !Self {
484 var self = Self{};
485 try self.resize(bit_length, true, allocator);
486 return self;
487 }
488
489 /// Resizes to a new bit_length. If the new length is larger
490 /// than the old length, fills any added bits with `fill`.
491 /// If new_len is not zero, deinit must eventually be called.
492 pub fn resize(self: *@This(), new_len: usize, fill: bool, allocator: *Allocator) !void {
493 const old_len = self.bit_length;
494
495 const old_masks = numMasks(old_len);
496 const new_masks = numMasks(new_len);
497
498 const old_allocation = (self.masks - 1)[0..(self.masks - 1)[0]];
499
500 if (new_masks == 0) {
501 assert(new_len == 0);
502 allocator.free(old_allocation);
503 self.masks = empty_masks_ptr;
504 self.bit_length = 0;
505 return;
506 }
507
508 if (old_allocation.len != new_masks + 1) realloc: {
509 // If realloc fails, it may mean one of two things.
510 // If we are growing, it means we are out of memory.
511 // If we are shrinking, it means the allocator doesn't
512 // want to move the allocation. This means we need to
513 // hold on to the extra 8 bytes required to be able to free
514 // this allocation properly.
515 const new_allocation = allocator.realloc(old_allocation, new_masks + 1) catch |err| {
516 if (new_masks + 1 > old_allocation.len) return err;
517 break :realloc;
518 };
519
520 new_allocation[0] = new_allocation.len;
521 self.masks = new_allocation.ptr + 1;
522 }
523
524 // If we increased in size, we need to set any new bits
525 // to the fill value.
526 if (new_len > old_len) {
527 // set the padding bits in the old last item to 1
528 if (fill and old_masks > 0) {
529 const old_padding_bits = old_masks * @bitSizeOf(MaskInt) - old_len;
530 const old_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, old_padding_bits);
531 self.masks[old_masks - 1] |= ~old_mask;
532 }
533
534 // fill in any new masks
535 if (new_masks > old_masks) {
536 const fill_value = std.math.boolMask(MaskInt, fill);
537 std.mem.set(MaskInt, self.masks[old_masks..new_masks], fill_value);
538 }
539 }
540
541 // Zero out the padding bits
542 if (new_len > 0) {
543 const padding_bits = new_masks * @bitSizeOf(MaskInt) - new_len;
544 const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
545 self.masks[new_masks - 1] &= last_item_mask;
546 }
547
548 // And finally, save the new length.
549 self.bit_length = new_len;
550 }
551
552 /// deinitializes the array and releases its memory.
553 /// The passed allocator must be the same one used for
554 /// init* or resize in the past.
555 pub fn deinit(self: *Self, allocator: *Allocator) void {
556 self.resize(0, false, allocator) catch unreachable;
557 }
558
559 /// Creates a duplicate of this bit set, using the new allocator.
560 pub fn clone(self: *const Self, new_allocator: *Allocator) !Self {
561 const num_masks = numMasks(self.bit_length);
562 var copy = Self{};
563 try copy.resize(self.bit_length, false, new_allocator);
564 std.mem.copy(MaskInt, copy.masks[0..num_masks], self.masks[0..num_masks]);
565 return copy;
566 }
567
568 /// Returns the number of bits in this bit set
569 pub inline fn capacity(self: Self) usize {
570 return self.bit_length;
571 }
572
573 /// Returns true if the bit at the specified index
574 /// is present in the set, false otherwise.
575 pub fn isSet(self: Self, index: usize) bool {
576 assert(index < self.bit_length);
577 return (self.masks[maskIndex(index)] & maskBit(index)) != 0;
578 }
579
580 /// Returns the total number of set bits in this bit set.
581 pub fn count(self: Self) usize {
582 const num_masks = (self.bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt);
583 var total: usize = 0;
584 for (self.masks[0..num_masks]) |mask| {
585 // Note: This is where we depend on padding bits being zero
586 total += @popCount(MaskInt, mask);
587 }
588 return total;
589 }
590
591 /// Changes the value of the specified bit of the bit
592 /// set to match the passed boolean.
593 pub fn setValue(self: *Self, index: usize, value: bool) void {
594 assert(index < self.bit_length);
595 const bit = maskBit(index);
596 const mask_index = maskIndex(index);
597 const new_bit = bit & std.math.boolMask(MaskInt, value);
598 self.masks[mask_index] = (self.masks[mask_index] & ~bit) | new_bit;
599 }
600
601 /// Adds a specific bit to the bit set
602 pub fn set(self: *Self, index: usize) void {
603 assert(index < self.bit_length);
604 self.masks[maskIndex(index)] |= maskBit(index);
605 }
606
607 /// Removes a specific bit from the bit set
608 pub fn unset(self: *Self, index: usize) void {
609 assert(index < self.bit_length);
610 self.masks[maskIndex(index)] &= ~maskBit(index);
611 }
612
613 /// Flips a specific bit in the bit set
614 pub fn toggle(self: *Self, index: usize) void {
615 assert(index < self.bit_length);
616 self.masks[maskIndex(index)] ^= maskBit(index);
617 }
618
619 /// Flips all bits in this bit set which are present
620 /// in the toggles bit set. Both sets must have the
621 /// same bit_length.
622 pub fn toggleSet(self: *Self, toggles: Self) void {
623 assert(toggles.bit_length == self.bit_length);
624 const num_masks = numMasks(self.bit_length);
625 for (self.masks[0..num_masks]) |*mask, i| {
626 mask.* ^= toggles.masks[i];
627 }
628 }
629
630 /// Flips every bit in the bit set.
631 pub fn toggleAll(self: *Self) void {
632 const bit_length = self.bit_length;
633 // avoid underflow if bit_length is zero
634 if (bit_length == 0) return;
635
636 const num_masks = numMasks(self.bit_length);
637 for (self.masks[0..num_masks]) |*mask, i| {
638 mask.* = ~mask.*;
639 }
640
641 const padding_bits = num_masks * @bitSizeOf(MaskInt) - bit_length;
642 const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
643 self.masks[num_masks - 1] &= last_item_mask;
644 }
645
646 /// Performs a union of two bit sets, and stores the
647 /// result in the first one. Bits in the result are
648 /// set if the corresponding bits were set in either input.
649 /// The two sets must both be the same bit_length.
650 pub fn setUnion(self: *Self, other: Self) void {
651 assert(other.bit_length == self.bit_length);
652 const num_masks = numMasks(self.bit_length);
653 for (self.masks[0..num_masks]) |*mask, i| {
654 mask.* |= other.masks[i];
655 }
656 }
657
658 /// Performs an intersection of two bit sets, and stores
659 /// the result in the first one. Bits in the result are
660 /// set if the corresponding bits were set in both inputs.
661 /// The two sets must both be the same bit_length.
662 pub fn setIntersection(self: *Self, other: Self) void {
663 assert(other.bit_length == self.bit_length);
664 const num_masks = numMasks(self.bit_length);
665 for (self.masks[0..num_masks]) |*mask, i| {
666 mask.* &= other.masks[i];
667 }
668 }
669
670 /// Finds the index of the first set bit.
671 /// If no bits are set, returns null.
672 pub fn findFirstSet(self: Self) ?usize {
673 var offset: usize = 0;
674 var mask = self.masks;
675 while (offset < self.bit_length) {
676 if (mask[0] != 0) break;
677 mask += 1;
678 offset += @bitSizeOf(MaskInt);
679 } else return null;
680 return offset + @ctz(MaskInt, mask[0]);
681 }
682
683 /// Finds the index of the first set bit, and unsets it.
684 /// If no bits are set, returns null.
685 pub fn toggleFirstSet(self: *Self) ?usize {
686 var offset: usize = 0;
687 var mask = self.masks;
688 while (offset < self.bit_length) {
689 if (mask[0] != 0) break;
690 mask += 1;
691 offset += @bitSizeOf(MaskInt);
692 } else return null;
693 const index = @ctz(MaskInt, mask[0]);
694 mask[0] &= (mask[0]-1);
695 return offset + index;
696 }
697
698 /// Iterates through the items in the set, according to the options.
699 /// The default options (.{}) will iterate indices of set bits in
700 /// ascending order. Modifications to the underlying bit set may
701 /// or may not be observed by the iterator. Resizing the underlying
702 /// bit set invalidates the iterator.
703 pub fn iterator(self: *const Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
704 const num_masks = numMasks(self.bit_length);
705 const padding_bits = num_masks * @bitSizeOf(MaskInt) - self.bit_length;
706 const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
707 return BitSetIterator(MaskInt, options).init(self.masks[0..num_masks], last_item_mask);
708 }
709
710 fn maskBit(index: usize) MaskInt {
711 return @as(MaskInt, 1) << @truncate(ShiftInt, index);
712 }
713 fn maskIndex(index: usize) usize {
714 return index >> @bitSizeOf(ShiftInt);
715 }
716 fn boolMaskBit(index: usize, value: bool) MaskInt {
717 return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
718 }
719 fn numMasks(bit_length: usize) usize {
720 return (bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt);
721 }
722};
723
724/// A bit set with runtime known size, backed by an allocated slice
725/// of usize. Thin wrapper around DynamicBitSetUnmanaged which keeps
726/// track of the allocator instance.
727pub const DynamicBitSet = struct {
728 const Self = @This();
729
730 /// The integer type used to represent a mask in this bit set
731 pub const MaskInt = usize;
732
733 /// The integer type used to shift a mask in this bit set
734 pub const ShiftInt = std.math.Log2Int(MaskInt);
735
736 /// The allocator used by this bit set
737 allocator: *Allocator,
738
739 /// The number of valid items in this bit set
740 unmanaged: DynamicBitSetUnmanaged = .{},
741
742 /// Creates a bit set with no elements present.
743 pub fn initEmpty(bit_length: usize, allocator: *Allocator) !Self {
744 return Self{
745 .unmanaged = try DynamicBitSetUnmanaged.initEmpty(bit_length, allocator),
746 .allocator = allocator,
747 };
748 }
749
750 /// Creates a bit set with all elements present.
751 pub fn initFull(bit_length: usize, allocator: *Allocator) !Self {
752 return Self{
753 .unmanaged = try DynamicBitSetUnmanaged.initFull(bit_length, allocator),
754 .allocator = allocator,
755 };
756 }
757
758 /// Resizes to a new length. If the new length is larger
759 /// than the old length, fills any added bits with `fill`.
760 pub fn resize(self: *@This(), new_len: usize, fill: bool) !void {
761 try self.unmanaged.resize(new_len, fill, self.allocator);
762 }
763
764 /// deinitializes the array and releases its memory.
765 /// The passed allocator must be the same one used for
766 /// init* or resize in the past.
767 pub fn deinit(self: *Self) void {
768 self.unmanaged.deinit(self.allocator);
769 }
770
771 /// Creates a duplicate of this bit set, using the new allocator.
772 pub fn clone(self: *const Self, new_allocator: *Allocator) !Self {
773 return Self{
774 .unmanaged = try self.unmanaged.clone(new_allocator),
775 .allocator = new_allocator,
776 };
777 }
778
779 /// Returns the number of bits in this bit set
780 pub inline fn capacity(self: Self) usize {
781 return self.unmanaged.capacity();
782 }
783
784 /// Returns true if the bit at the specified index
785 /// is present in the set, false otherwise.
786 pub fn isSet(self: Self, index: usize) bool {
787 return self.unmanaged.isSet(index);
788 }
789
790 /// Returns the total number of set bits in this bit set.
791 pub fn count(self: Self) usize {
792 return self.unmanaged.count();
793 }
794
795 /// Changes the value of the specified bit of the bit
796 /// set to match the passed boolean.
797 pub fn setValue(self: *Self, index: usize, value: bool) void {
798 self.unmanaged.setValue(index, value);
799 }
800
801 /// Adds a specific bit to the bit set
802 pub fn set(self: *Self, index: usize) void {
803 self.unmanaged.set(index);
804 }
805
806 /// Removes a specific bit from the bit set
807 pub fn unset(self: *Self, index: usize) void {
808 self.unmanaged.unset(index);
809 }
810
811 /// Flips a specific bit in the bit set
812 pub fn toggle(self: *Self, index: usize) void {
813 self.unmanaged.toggle(index);
814 }
815
816 /// Flips all bits in this bit set which are present
817 /// in the toggles bit set. Both sets must have the
818 /// same bit_length.
819 pub fn toggleSet(self: *Self, toggles: Self) void {
820 self.unmanaged.toggleSet(toggles.unmanaged);
821 }
822
823 /// Flips every bit in the bit set.
824 pub fn toggleAll(self: *Self) void {
825 self.unmanaged.toggleAll();
826 }
827
828 /// Performs a union of two bit sets, and stores the
829 /// result in the first one. Bits in the result are
830 /// set if the corresponding bits were set in either input.
831 /// The two sets must both be the same bit_length.
832 pub fn setUnion(self: *Self, other: Self) void {
833 self.unmanaged.setUnion(other.unmanaged);
834 }
835
836 /// Performs an intersection of two bit sets, and stores
837 /// the result in the first one. Bits in the result are
838 /// set if the corresponding bits were set in both inputs.
839 /// The two sets must both be the same bit_length.
840 pub fn setIntersection(self: *Self, other: Self) void {
841 self.unmanaged.setIntersection(other.unmanaged);
842 }
843
844 /// Finds the index of the first set bit.
845 /// If no bits are set, returns null.
846 pub fn findFirstSet(self: Self) ?usize {
847 return self.unmanaged.findFirstSet();
848 }
849
850 /// Finds the index of the first set bit, and unsets it.
851 /// If no bits are set, returns null.
852 pub fn toggleFirstSet(self: *Self) ?usize {
853 return self.unmanaged.toggleFirstSet();
854 }
855
856 /// Iterates through the items in the set, according to the options.
857 /// The default options (.{}) will iterate indices of set bits in
858 /// ascending order. Modifications to the underlying bit set may
859 /// or may not be observed by the iterator. Resizing the underlying
860 /// bit set invalidates the iterator.
861 pub fn iterator(self: *Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
862 return self.unmanaged.iterator(options);
863 }
864};
865
866/// Options for configuring an iterator over a bit set
867pub const IteratorOptions = struct {
868 /// determines which bits should be visited
869 kind: Type = .set,
870 /// determines the order in which bit indices should be visited
871 direction: Direction = .forward,
872
873 pub const Type = enum {
874 /// visit indexes of set bits
875 set,
876 /// visit indexes of unset bits
877 unset,
878 };
879
880 pub const Direction = enum {
881 /// visit indices in ascending order
882 forward,
883 /// visit indices in descending order.
884 /// Note that this may be slightly more expensive than forward iteration.
885 reverse,
886 };
887};
888
889// The iterator is reusable between several bit set types
890fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) type {
891 const ShiftInt = std.math.Log2Int(MaskInt);
892 const kind = options.kind;
893 const direction = options.direction;
894 return struct {
895 const Self = @This();
896
897 // all bits which have not yet been iterated over
898 bits_remain: MaskInt,
899 // all words which have not yet been iterated over
900 words_remain: []const MaskInt,
901 // the offset of the current word
902 bit_offset: usize,
903 // the mask of the last word
904 last_word_mask: MaskInt,
905
906 fn init(masks: []const MaskInt, last_word_mask: MaskInt) Self {
907 if (masks.len == 0) {
908 return Self{
909 .bits_remain = 0,
910 .words_remain = &[_]MaskInt{},
911 .last_word_mask = last_word_mask,
912 .bit_offset = 0,
913 };
914 } else {
915 var result = Self{
916 .bits_remain = 0,
917 .words_remain = masks,
918 .last_word_mask = last_word_mask,
919 .bit_offset = if (direction == .forward) 0 else (masks.len - 1) * @bitSizeOf(MaskInt),
920 };
921 result.nextWord(true);
922 return result;
923 }
924 }
925
926 /// Returns the index of the next unvisited set bit
927 /// in the bit set, in ascending order.
928 pub fn next(self: *Self) ?usize {
929 while (self.bits_remain == 0) {
930 if (self.words_remain.len == 0) return null;
931 self.nextWord(false);
932 switch (direction) {
933 .forward => self.bit_offset += @bitSizeOf(MaskInt),
934 .reverse => self.bit_offset -= @bitSizeOf(MaskInt),
935 }
936 }
937
938 switch (direction) {
939 .forward => {
940 const next_index = @ctz(MaskInt, self.bits_remain) + self.bit_offset;
941 self.bits_remain &= self.bits_remain - 1;
942 return next_index;
943 },
944 .reverse => {
945 const leading_zeroes = @clz(MaskInt, self.bits_remain);
946 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
947 const no_top_bit_mask = (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
948 self.bits_remain &= no_top_bit_mask;
949 return top_bit + self.bit_offset;
950 },
951 }
952 }
953
954 // Load the next word. Don't call this if there
955 // isn't a next word. If the next word is the
956 // last word, mask off the padding bits so we
957 // don't visit them.
958 inline fn nextWord(self: *Self, comptime is_first_word: bool) void {
959 var word = switch (direction) {
960 .forward => self.words_remain[0],
961 .reverse => self.words_remain[self.words_remain.len - 1],
962 };
963 switch (kind) {
964 .set => {},
965 .unset => {
966 word = ~word;
967 if ((direction == .reverse and is_first_word) or
968 (direction == .forward and self.words_remain.len == 1))
969 {
970 word &= self.last_word_mask;
971 }
972 },
973 }
974 switch (direction) {
975 .forward => self.words_remain = self.words_remain[1..],
976 .reverse => self.words_remain.len -= 1,
977 }
978 self.bits_remain = word;
979 }
980 };
981}
982
983// ---------------- Tests -----------------
984
985const testing = std.testing;
986
987fn testBitSet(a: anytype, b: anytype, len: usize) void {
988 testing.expectEqual(len, a.capacity());
989 testing.expectEqual(len, b.capacity());
990
991 {
992 var i: usize = 0;
993 while (i < len) : (i += 1) {
994 a.setValue(i, i & 1 == 0);
995 b.setValue(i, i & 2 == 0);
996 }
997 }
998
999 testing.expectEqual((len + 1) / 2, a.count());
1000 testing.expectEqual((len + 3) / 4 + (len + 2) / 4, b.count());
1001
1002 {
1003 var iter = a.iterator(.{});
1004 var i: usize = 0;
1005 while (i < len) : (i += 2) {
1006 testing.expectEqual(@as(?usize, i), iter.next());
1007 }
1008 testing.expectEqual(@as(?usize, null), iter.next());
1009 testing.expectEqual(@as(?usize, null), iter.next());
1010 testing.expectEqual(@as(?usize, null), iter.next());
1011 }
1012 a.toggleAll();
1013 {
1014 var iter = a.iterator(.{});
1015 var i: usize = 1;
1016 while (i < len) : (i += 2) {
1017 testing.expectEqual(@as(?usize, i), iter.next());
1018 }
1019 testing.expectEqual(@as(?usize, null), iter.next());
1020 testing.expectEqual(@as(?usize, null), iter.next());
1021 testing.expectEqual(@as(?usize, null), iter.next());
1022 }
1023
1024 {
1025 var iter = b.iterator(.{ .kind = .unset });
1026 var i: usize = 2;
1027 while (i < len) : (i += 4) {
1028 testing.expectEqual(@as(?usize, i), iter.next());
1029 if (i + 1 < len) {
1030 testing.expectEqual(@as(?usize, i + 1), iter.next());
1031 }
1032 }
1033 testing.expectEqual(@as(?usize, null), iter.next());
1034 testing.expectEqual(@as(?usize, null), iter.next());
1035 testing.expectEqual(@as(?usize, null), iter.next());
1036 }
1037
1038 {
1039 var i: usize = 0;
1040 while (i < len) : (i += 1) {
1041 testing.expectEqual(i & 1 != 0, a.isSet(i));
1042 testing.expectEqual(i & 2 == 0, b.isSet(i));
1043 }
1044 }
1045
1046 a.setUnion(b.*);
1047 {
1048 var i: usize = 0;
1049 while (i < len) : (i += 1) {
1050 testing.expectEqual(i & 1 != 0 or i & 2 == 0, a.isSet(i));
1051 testing.expectEqual(i & 2 == 0, b.isSet(i));
1052 }
1053
1054 i = len;
1055 var set = a.iterator(.{ .direction = .reverse });
1056 var unset = a.iterator(.{ .kind = .unset, .direction = .reverse });
1057 while (i > 0) {
1058 i -= 1;
1059 if (i & 1 != 0 or i & 2 == 0) {
1060 testing.expectEqual(@as(?usize, i), set.next());
1061 } else {
1062 testing.expectEqual(@as(?usize, i), unset.next());
1063 }
1064 }
1065 testing.expectEqual(@as(?usize, null), set.next());
1066 testing.expectEqual(@as(?usize, null), set.next());
1067 testing.expectEqual(@as(?usize, null), set.next());
1068 testing.expectEqual(@as(?usize, null), unset.next());
1069 testing.expectEqual(@as(?usize, null), unset.next());
1070 testing.expectEqual(@as(?usize, null), unset.next());
1071 }
1072
1073 a.toggleSet(b.*);
1074 {
1075 testing.expectEqual(len / 4, a.count());
1076
1077 var i: usize = 0;
1078 while (i < len) : (i += 1) {
1079 testing.expectEqual(i & 1 != 0 and i & 2 != 0, a.isSet(i));
1080 testing.expectEqual(i & 2 == 0, b.isSet(i));
1081 if (i & 1 == 0) {
1082 a.set(i);
1083 } else {
1084 a.unset(i);
1085 }
1086 }
1087 }
1088
1089 a.setIntersection(b.*);
1090 {
1091 testing.expectEqual((len + 3) / 4, a.count());
1092
1093 var i: usize = 0;
1094 while (i < len) : (i += 1) {
1095 testing.expectEqual(i & 1 == 0 and i & 2 == 0, a.isSet(i));
1096 testing.expectEqual(i & 2 == 0, b.isSet(i));
1097 }
1098 }
1099
1100 a.toggleSet(a.*);
1101 {
1102 var iter = a.iterator(.{});
1103 testing.expectEqual(@as(?usize, null), iter.next());
1104 testing.expectEqual(@as(?usize, null), iter.next());
1105 testing.expectEqual(@as(?usize, null), iter.next());
1106 testing.expectEqual(@as(usize, 0), a.count());
1107 }
1108 {
1109 var iter = a.iterator(.{ .direction = .reverse });
1110 testing.expectEqual(@as(?usize, null), iter.next());
1111 testing.expectEqual(@as(?usize, null), iter.next());
1112 testing.expectEqual(@as(?usize, null), iter.next());
1113 testing.expectEqual(@as(usize, 0), a.count());
1114 }
1115
1116 const test_bits = [_]usize{
1117 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 22, 31, 32, 63, 64,
1118 66, 95, 127, 160, 192, 1000 };
1119 for (test_bits) |i| {
1120 if (i < a.capacity()) {
1121 a.set(i);
1122 }
1123 }
1124
1125 for (test_bits) |i| {
1126 if (i < a.capacity()) {
1127 testing.expectEqual(@as(?usize, i), a.findFirstSet());
1128 testing.expectEqual(@as(?usize, i), a.toggleFirstSet());
1129 }
1130 }
1131 testing.expectEqual(@as(?usize, null), a.findFirstSet());
1132 testing.expectEqual(@as(?usize, null), a.toggleFirstSet());
1133 testing.expectEqual(@as(?usize, null), a.findFirstSet());
1134 testing.expectEqual(@as(?usize, null), a.toggleFirstSet());
1135 testing.expectEqual(@as(usize, 0), a.count());
1136}
1137
1138fn testStaticBitSet(comptime Set: type) void {
1139 var a = Set.initEmpty();
1140 var b = Set.initFull();
1141 testing.expectEqual(@as(usize, 0), a.count());
1142 testing.expectEqual(@as(usize, Set.bit_length), b.count());
1143
1144 testBitSet(&a, &b, Set.bit_length);
1145}
1146
1147test "IntegerBitSet" {
1148 testStaticBitSet(IntegerBitSet(0));
1149 testStaticBitSet(IntegerBitSet(1));
1150 testStaticBitSet(IntegerBitSet(2));
1151 testStaticBitSet(IntegerBitSet(5));
1152 testStaticBitSet(IntegerBitSet(8));
1153 testStaticBitSet(IntegerBitSet(32));
1154 testStaticBitSet(IntegerBitSet(64));
1155 testStaticBitSet(IntegerBitSet(127));
1156}
1157
1158test "ArrayBitSet" {
1159 inline for (.{ 0, 1, 2, 31, 32, 33, 63, 64, 65, 254, 500, 3000 }) |size| {
1160 testStaticBitSet(ArrayBitSet(u8, size));
1161 testStaticBitSet(ArrayBitSet(u16, size));
1162 testStaticBitSet(ArrayBitSet(u32, size));
1163 testStaticBitSet(ArrayBitSet(u64, size));
1164 testStaticBitSet(ArrayBitSet(u128, size));
1165 }
1166}
1167
1168test "DynamicBitSetUnmanaged" {
1169 const allocator = std.testing.allocator;
1170 var a = try DynamicBitSetUnmanaged.initEmpty(300, allocator);
1171 testing.expectEqual(@as(usize, 0), a.count());
1172 a.deinit(allocator);
1173
1174 a = try DynamicBitSetUnmanaged.initEmpty(0, allocator);
1175 defer a.deinit(allocator);
1176 for ([_]usize{ 1, 2, 31, 32, 33, 0, 65, 64, 63, 500, 254, 3000 }) |size| {
1177 const old_len = a.capacity();
1178
1179 var tmp = try a.clone(allocator);
1180 defer tmp.deinit(allocator);
1181 testing.expectEqual(old_len, tmp.capacity());
1182 var i: usize = 0;
1183 while (i < old_len) : (i += 1) {
1184 testing.expectEqual(a.isSet(i), tmp.isSet(i));
1185 }
1186
1187 a.toggleSet(a); // zero a
1188 tmp.toggleSet(tmp);
1189
1190 try a.resize(size, true, allocator);
1191 try tmp.resize(size, false, allocator);
1192
1193 if (size > old_len) {
1194 testing.expectEqual(size - old_len, a.count());
1195 } else {
1196 testing.expectEqual(@as(usize, 0), a.count());
1197 }
1198 testing.expectEqual(@as(usize, 0), tmp.count());
1199
1200 var b = try DynamicBitSetUnmanaged.initFull(size, allocator);
1201 defer b.deinit(allocator);
1202 testing.expectEqual(@as(usize, size), b.count());
1203
1204 testBitSet(&a, &b, size);
1205 }
1206}
1207
1208test "DynamicBitSet" {
1209 const allocator = std.testing.allocator;
1210 var a = try DynamicBitSet.initEmpty(300, allocator);
1211 testing.expectEqual(@as(usize, 0), a.count());
1212 a.deinit();
1213
1214 a = try DynamicBitSet.initEmpty(0, allocator);
1215 defer a.deinit();
1216 for ([_]usize{ 1, 2, 31, 32, 33, 0, 65, 64, 63, 500, 254, 3000 }) |size| {
1217 const old_len = a.capacity();
1218
1219 var tmp = try a.clone(allocator);
1220 defer tmp.deinit();
1221 testing.expectEqual(old_len, tmp.capacity());
1222 var i: usize = 0;
1223 while (i < old_len) : (i += 1) {
1224 testing.expectEqual(a.isSet(i), tmp.isSet(i));
1225 }
1226
1227 a.toggleSet(a); // zero a
1228 tmp.toggleSet(tmp); // zero tmp
1229
1230 try a.resize(size, true);
1231 try tmp.resize(size, false);
1232
1233 if (size > old_len) {
1234 testing.expectEqual(size - old_len, a.count());
1235 } else {
1236 testing.expectEqual(@as(usize, 0), a.count());
1237 }
1238 testing.expectEqual(@as(usize, 0), tmp.count());
1239
1240 var b = try DynamicBitSet.initFull(size, allocator);
1241 defer b.deinit();
1242 testing.expectEqual(@as(usize, size), b.count());
1243
1244 testBitSet(&a, &b, size);
1245 }
1246}
1247
1248test "StaticBitSet" {
1249 testing.expectEqual(IntegerBitSet(0), StaticBitSet(0));
1250 testing.expectEqual(IntegerBitSet(5), StaticBitSet(5));
1251 testing.expectEqual(IntegerBitSet(@bitSizeOf(usize)), StaticBitSet(@bitSizeOf(usize)));
1252 testing.expectEqual(ArrayBitSet(usize, @bitSizeOf(usize) + 1), StaticBitSet(@bitSizeOf(usize) + 1));
1253 testing.expectEqual(ArrayBitSet(usize, 500), StaticBitSet(500));
1254}
lib/std/math.zig+56
...@@ -1330,3 +1330,59 @@ test "math.comptime" {...@@ -1330,3 +1330,59 @@ test "math.comptime" {
1330 comptime const v = sin(@as(f32, 1)) + ln(@as(f32, 5));1330 comptime const v = sin(@as(f32, 1)) + ln(@as(f32, 5));
1331 testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5)));1331 testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5)));
1332}1332}
1333
1334/// Returns a mask of all ones if value is true,
1335/// and a mask of all zeroes if value is false.
1336/// Compiles to one instruction for register sized integers.
1337pub inline fn boolMask(comptime MaskInt: type, value: bool) MaskInt {
1338 if (@typeInfo(MaskInt) != .Int)
1339 @compileError("boolMask requires an integer mask type.");
1340
1341 if (MaskInt == u0 or MaskInt == i0)
1342 @compileError("boolMask cannot convert to u0 or i0, they are too small.");
1343
1344 // The u1 and i1 cases tend to overflow,
1345 // so we special case them here.
1346 if (MaskInt == u1) return @boolToInt(value);
1347 if (MaskInt == i1) {
1348 // The @as here is a workaround for #7950
1349 return @bitCast(i1, @as(u1, @boolToInt(value)));
1350 }
1351
1352 // At comptime, -% is disallowed on unsigned values.
1353 // So we need to jump through some hoops in that case.
1354 // This is a workaround for #7951
1355 if (@typeInfo(@TypeOf(.{value})).Struct.fields[0].is_comptime) {
1356 // Since it's comptime, we don't need this to generate nice code.
1357 // We can just do a branch here.
1358 return if (value) ~@as(MaskInt, 0) else 0;
1359 }
1360
1361 return -%@intCast(MaskInt, @boolToInt(value));
1362}
1363
1364test "boolMask" {
1365 const runTest = struct {
1366 fn runTest() void {
1367 testing.expectEqual(@as(u1, 0), boolMask(u1, false));
1368 testing.expectEqual(@as(u1, 1), boolMask(u1, true));
1369
1370 testing.expectEqual(@as(i1, 0), boolMask(i1, false));
1371 testing.expectEqual(@as(i1, -1), boolMask(i1, true));
1372
1373 testing.expectEqual(@as(u13, 0), boolMask(u13, false));
1374 testing.expectEqual(@as(u13, 0x1FFF), boolMask(u13, true));
1375
1376 testing.expectEqual(@as(i13, 0), boolMask(i13, false));
1377 testing.expectEqual(@as(i13, -1), boolMask(i13, true));
1378
1379 testing.expectEqual(@as(u32, 0), boolMask(u32, false));
1380 testing.expectEqual(@as(u32, 0xFFFF_FFFF), boolMask(u32, true));
1381
1382 testing.expectEqual(@as(i32, 0), boolMask(i32, false));
1383 testing.expectEqual(@as(i32, -1), boolMask(i32, true));
1384 }
1385 }.runTest;
1386 runTest();
1387 comptime runTest();
1388}
lib/std/mem.zig+8
...@@ -25,6 +25,14 @@ pub const page_size = switch (builtin.arch) {...@@ -25,6 +25,14 @@ pub const page_size = switch (builtin.arch) {
25 else => 4 * 1024,25 else => 4 * 1024,
26};26};
2727
28/// The standard library currently thoroughly depends on byte size
29/// being 8 bits. (see the use of u8 throughout allocation code as
30/// the "byte" type.) Code which depends on this can reference this
31/// declaration. If we ever try to port the standard library to a
32/// non-8-bit-byte platform, this will allow us to search for things
33/// which need to be updated.
34pub const byte_size_in_bits = 8;
35
28pub const Allocator = @import("mem/Allocator.zig");36pub const Allocator = @import("mem/Allocator.zig");
2937
30/// Detects and asserts if the std.mem.Allocator interface is violated by the caller38/// Detects and asserts if the std.mem.Allocator interface is violated by the caller
lib/std/std.zig+4
...@@ -18,6 +18,8 @@ pub const BufSet = @import("buf_set.zig").BufSet;...@@ -18,6 +18,8 @@ pub const BufSet = @import("buf_set.zig").BufSet;
18pub const ChildProcess = @import("child_process.zig").ChildProcess;18pub const ChildProcess = @import("child_process.zig").ChildProcess;
19pub const ComptimeStringMap = @import("comptime_string_map.zig").ComptimeStringMap;19pub const ComptimeStringMap = @import("comptime_string_map.zig").ComptimeStringMap;
20pub const DynLib = @import("dynamic_library.zig").DynLib;20pub const DynLib = @import("dynamic_library.zig").DynLib;
21pub const DynamicBitSet = bit_set.DynamicBitSet;
22pub const DynamicBitSetUnmanaged = bit_set.DynamicBitSetUnmanaged;
21pub const HashMap = hash_map.HashMap;23pub const HashMap = hash_map.HashMap;
22pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;24pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;
23pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;25pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;
...@@ -29,6 +31,7 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;...@@ -29,6 +31,7 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
29pub const Progress = @import("Progress.zig");31pub const Progress = @import("Progress.zig");
30pub const SemanticVersion = @import("SemanticVersion.zig");32pub const SemanticVersion = @import("SemanticVersion.zig");
31pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;33pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;
34pub const StaticBitSet = bit_set.StaticBitSet;
32pub const StringHashMap = hash_map.StringHashMap;35pub const StringHashMap = hash_map.StringHashMap;
33pub const StringHashMapUnmanaged = hash_map.StringHashMapUnmanaged;36pub const StringHashMapUnmanaged = hash_map.StringHashMapUnmanaged;
34pub const StringArrayHashMap = array_hash_map.StringArrayHashMap;37pub const StringArrayHashMap = array_hash_map.StringArrayHashMap;
...@@ -40,6 +43,7 @@ pub const Thread = @import("Thread.zig");...@@ -40,6 +43,7 @@ pub const Thread = @import("Thread.zig");
40pub const array_hash_map = @import("array_hash_map.zig");43pub const array_hash_map = @import("array_hash_map.zig");
41pub const atomic = @import("atomic.zig");44pub const atomic = @import("atomic.zig");
42pub const base64 = @import("base64.zig");45pub const base64 = @import("base64.zig");
46pub const bit_set = @import("bit_set.zig");
43pub const build = @import("build.zig");47pub const build = @import("build.zig");
44pub const builtin = @import("builtin.zig");48pub const builtin = @import("builtin.zig");
45pub const c = @import("c.zig");49pub const c = @import("c.zig");