const std = @import("std.zig");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
pub fn StaticBitSet(comptime size: usize) type {
if (size <= @bitSizeOf(usize)) {
return IntegerBitSet(size);
} else {
return ArrayBitSet(usize, size);
}
}
pub fn IntegerBitSet(comptime size: u16) type {
return packed struct {
const Self = @This();
pub const bit_length: usize = size;
pub const MaskInt = std.meta.Int(.unsigned, size);
pub const ShiftInt = std.math.Log2Int(MaskInt);
mask: MaskInt,
pub fn initEmpty() Self {
return .{ .mask = 0 };
}
pub fn initFull() Self {
return .{ .mask = ~@as(MaskInt, 0) };
}
pub inline fn capacity(self: Self) usize {
_ = self;
return bit_length;
}
pub fn isSet(self: Self, index: usize) bool {
assert(index < bit_length);
return (self.mask & maskBit(index)) != 0;
}
pub fn count(self: Self) usize {
return @popCount(self.mask);
}
pub fn setValue(self: *Self, index: usize, value: bool) void {
assert(index < bit_length);
if (MaskInt == u0) return;
const bit = maskBit(index);
const new_bit = bit & std.math.boolMask(MaskInt, value);
self.mask = (self.mask & ~bit) | new_bit;
}
pub fn set(self: *Self, index: usize) void {
assert(index < bit_length);
self.mask |= maskBit(index);
}
pub fn setRangeValue(self: *Self, range: Range, value: bool) void {
assert(range.end <= bit_length);
assert(range.start <= range.end);
if (range.start == range.end) return;
if (MaskInt == u0) return;
const start_bit = @intCast(ShiftInt, range.start);
var mask = std.math.boolMask(MaskInt, true) << start_bit;
if (range.end != bit_length) {
const end_bit = @intCast(ShiftInt, range.end);
mask &= std.math.boolMask(MaskInt, true) >> @truncate(ShiftInt, @as(usize, @bitSizeOf(MaskInt)) - @as(usize, end_bit));
}
self.mask &= ~mask;
mask = std.math.boolMask(MaskInt, value) << start_bit;
if (range.end != bit_length) {
const end_bit = @intCast(ShiftInt, range.end);
mask &= std.math.boolMask(MaskInt, value) >> @truncate(ShiftInt, @as(usize, @bitSizeOf(MaskInt)) - @as(usize, end_bit));
}
self.mask |= mask;
}
pub fn unset(self: *Self, index: usize) void {
assert(index < bit_length);
if (MaskInt == u0) return;
self.mask &= ~maskBit(index);
}
pub fn toggle(self: *Self, index: usize) void {
assert(index < bit_length);
self.mask ^= maskBit(index);
}
pub fn toggleSet(self: *Self, toggles: Self) void {
self.mask ^= toggles.mask;
}
pub fn toggleAll(self: *Self) void {
self.mask = ~self.mask;
}
pub fn setUnion(self: *Self, other: Self) void {
self.mask |= other.mask;
}
pub fn setIntersection(self: *Self, other: Self) void {
self.mask &= other.mask;
}
pub fn findFirstSet(self: Self) ?usize {
const mask = self.mask;
if (mask == 0) return null;
return @ctz(mask);
}
pub fn toggleFirstSet(self: *Self) ?usize {
const mask = self.mask;
if (mask == 0) return null;
const index = @ctz(mask);
self.mask = mask & (mask - 1);
return index;
}
pub fn eql(self: Self, other: Self) bool {
return bit_length == 0 or self.mask == other.mask;
}
pub fn subsetOf(self: Self, other: Self) bool {
return self.intersectWith(other).eql(self);
}
pub fn supersetOf(self: Self, other: Self) bool {
return other.subsetOf(self);
}
pub fn complement(self: Self) Self {
var result = self;
result.toggleAll();
return result;
}
pub fn unionWith(self: Self, other: Self) Self {
var result = self;
result.setUnion(other);
return result;
}
pub fn intersectWith(self: Self, other: Self) Self {
var result = self;
result.setIntersection(other);
return result;
}
pub fn xorWith(self: Self, other: Self) Self {
var result = self;
result.toggleSet(other);
return result;
}
pub fn differenceWith(self: Self, other: Self) Self {
var result = self;
result.setIntersection(other.complement());
return result;
}
pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) {
return .{
.bits_remain = switch (options.kind) {
.set => self.mask,
.unset => ~self.mask,
},
};
}
pub fn Iterator(comptime options: IteratorOptions) type {
return SingleWordIterator(options.direction);
}
fn SingleWordIterator(comptime direction: IteratorOptions.Direction) type {
return struct {
const IterSelf = @This();
bits_remain: MaskInt,
pub fn next(self: *IterSelf) ?usize {
if (self.bits_remain == 0) return null;
switch (direction) {
.forward => {
const next_index = @ctz(self.bits_remain);
self.bits_remain &= self.bits_remain - 1;
return next_index;
},
.reverse => {
const leading_zeroes = @clz(self.bits_remain);
const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
self.bits_remain &= (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
return top_bit;
},
}
}
};
}
fn maskBit(index: usize) MaskInt {
if (MaskInt == u0) return 0;
return @as(MaskInt, 1) << @intCast(ShiftInt, index);
}
fn boolMaskBit(index: usize, value: bool) MaskInt {
if (MaskInt == u0) return 0;
return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
}
};
}
pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
const mask_info: std.builtin.Type = @typeInfo(MaskIntType);
if (mask_info != .Int) @compileError("ArrayBitSet can only operate on integer masks, but was passed " ++ @typeName(MaskIntType));
if (mask_info.Int.signedness != .unsigned) @compileError("ArrayBitSet requires an unsigned integer mask type, but was passed " ++ @typeName(MaskIntType));
if (MaskIntType == u0)
@compileError("ArrayBitSet requires a sized integer for its mask int. u0 does not work.");
const byte_size = std.mem.byte_size_in_bits;
if (!std.math.isPowerOfTwo(@bitSizeOf(MaskIntType))) {
var desired_bits = std.math.ceilPowerOfTwoAssert(usize, @bitSizeOf(MaskIntType));
if (desired_bits < byte_size) desired_bits = byte_size;
const FixedMaskType = std.meta.Int(.unsigned, desired_bits);
@compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++
", which is not a power of two. Please round this up to a power of two integer size (i.e. " ++ @typeName(FixedMaskType) ++ ").");
}
if (@bitSizeOf(MaskIntType) != @sizeOf(MaskIntType) * byte_size) {
var desired_bits = @sizeOf(MaskIntType) * byte_size;
desired_bits = std.math.ceilPowerOfTwoAssert(usize, desired_bits);
const FixedMaskType = std.meta.Int(.unsigned, desired_bits);
@compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++
", which contains padding bits. Please round this up to an unpadded integer size (i.e. " ++ @typeName(FixedMaskType) ++ ").");
}
return extern struct {
const Self = @This();
pub const bit_length: usize = size;
pub const MaskInt = MaskIntType;
pub const ShiftInt = std.math.Log2Int(MaskInt);
const mask_len = @bitSizeOf(MaskInt);
const num_masks = (size + mask_len - 1) / mask_len;
const last_pad_bits = mask_len * num_masks - size;
pub const last_item_mask = ~@as(MaskInt, 0) >> last_pad_bits;
masks: [num_masks]MaskInt,
pub fn initEmpty() Self {
return .{ .masks = [_]MaskInt{0} ** num_masks };
}
pub fn initFull() Self {
if (num_masks == 0) {
return .{ .masks = .{} };
} else {
return .{ .masks = [_]MaskInt{~@as(MaskInt, 0)} ** (num_masks - 1) ++ [_]MaskInt{last_item_mask} };
}
}
pub inline fn capacity(self: Self) usize {
_ = self;
return bit_length;
}
pub fn isSet(self: Self, index: usize) bool {
assert(index < bit_length);
if (num_masks == 0) return false;
return (self.masks[maskIndex(index)] & maskBit(index)) != 0;
}
pub fn count(self: Self) usize {
var total: usize = 0;
for (self.masks) |mask| {
total += @popCount(mask);
}
return total;
}
pub fn setValue(self: *Self, index: usize, value: bool) void {
assert(index < bit_length);
if (num_masks == 0) return;
const bit = maskBit(index);
const mask_index = maskIndex(index);
const new_bit = bit & std.math.boolMask(MaskInt, value);
self.masks[mask_index] = (self.masks[mask_index] & ~bit) | new_bit;
}
pub fn set(self: *Self, index: usize) void {
assert(index < bit_length);
if (num_masks == 0) return;
self.masks[maskIndex(index)] |= maskBit(index);
}
pub fn setRangeValue(self: *Self, range: Range, value: bool) void {
assert(range.end <= bit_length);
assert(range.start <= range.end);
if (range.start == range.end) return;
if (num_masks == 0) return;
const start_mask_index = maskIndex(range.start);
const start_bit = @truncate(ShiftInt, range.start);
const end_mask_index = maskIndex(range.end);
const end_bit = @truncate(ShiftInt, range.end);
if (start_mask_index == end_mask_index) {
var mask1 = std.math.boolMask(MaskInt, true) << start_bit;
var mask2 = std.math.boolMask(MaskInt, true) >> (mask_len - 1) - (end_bit - 1);
self.masks[start_mask_index] &= ~(mask1 & mask2);
mask1 = std.math.boolMask(MaskInt, value) << start_bit;
mask2 = std.math.boolMask(MaskInt, value) >> (mask_len - 1) - (end_bit - 1);
self.masks[start_mask_index] |= mask1 & mask2;
} else {
var bulk_mask_index: usize = undefined;
if (start_bit > 0) {
self.masks[start_mask_index] =
(self.masks[start_mask_index] & ~(std.math.boolMask(MaskInt, true) << start_bit)) |
(std.math.boolMask(MaskInt, value) << start_bit);
bulk_mask_index = start_mask_index + 1;
} else {
bulk_mask_index = start_mask_index;
}
while (bulk_mask_index < end_mask_index) : (bulk_mask_index += 1) {
self.masks[bulk_mask_index] = std.math.boolMask(MaskInt, value);
}
if (end_bit > 0) {
self.masks[end_mask_index] =
(self.masks[end_mask_index] & (std.math.boolMask(MaskInt, true) << end_bit)) |
(std.math.boolMask(MaskInt, value) >> ((@bitSizeOf(MaskInt) - 1) - (end_bit - 1)));
}
}
}
pub fn unset(self: *Self, index: usize) void {
assert(index < bit_length);
if (num_masks == 0) return;
self.masks[maskIndex(index)] &= ~maskBit(index);
}
pub fn toggle(self: *Self, index: usize) void {
assert(index < bit_length);
if (num_masks == 0) return;
self.masks[maskIndex(index)] ^= maskBit(index);
}
pub fn toggleSet(self: *Self, toggles: Self) void {
for (&self.masks, 0..) |*mask, i| {
mask.* ^= toggles.masks[i];
}
}
pub fn toggleAll(self: *Self) void {
for (&self.masks) |*mask| {
mask.* = ~mask.*;
}
if (num_masks > 0) {
self.masks[num_masks - 1] &= last_item_mask;
}
}
pub fn setUnion(self: *Self, other: Self) void {
for (&self.masks, 0..) |*mask, i| {
mask.* |= other.masks[i];
}
}
pub fn setIntersection(self: *Self, other: Self) void {
for (&self.masks, 0..) |*mask, i| {
mask.* &= other.masks[i];
}
}
pub fn findFirstSet(self: Self) ?usize {
var offset: usize = 0;
const mask = for (self.masks) |mask| {
if (mask != 0) break mask;
offset += @bitSizeOf(MaskInt);
} else return null;
return offset + @ctz(mask);
}
pub fn toggleFirstSet(self: *Self) ?usize {
var offset: usize = 0;
const mask = for (&self.masks) |*mask| {
if (mask.* != 0) break mask;
offset += @bitSizeOf(MaskInt);
} else return null;
const index = @ctz(mask.*);
mask.* &= (mask.* - 1);
return offset + index;
}
pub fn eql(self: Self, other: Self) bool {
var i: usize = 0;
return while (i < num_masks) : (i += 1) {
if (self.masks[i] != other.masks[i]) {
break false;
}
} else true;
}
pub fn subsetOf(self: Self, other: Self) bool {
return self.intersectWith(other).eql(self);
}
pub fn supersetOf(self: Self, other: Self) bool {
return other.subsetOf(self);
}
pub fn complement(self: Self) Self {
var result = self;
result.toggleAll();
return result;
}
pub fn unionWith(self: Self, other: Self) Self {
var result = self;
result.setUnion(other);
return result;
}
pub fn intersectWith(self: Self, other: Self) Self {
var result = self;
result.setIntersection(other);
return result;
}
pub fn xorWith(self: Self, other: Self) Self {
var result = self;
result.toggleSet(other);
return result;
}
pub fn differenceWith(self: Self, other: Self) Self {
var result = self;
result.setIntersection(other.complement());
return result;
}
pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) {
return Iterator(options).init(&self.masks, last_item_mask);
}
pub fn Iterator(comptime options: IteratorOptions) type {
return BitSetIterator(MaskInt, options);
}
fn maskBit(index: usize) MaskInt {
return @as(MaskInt, 1) << @truncate(ShiftInt, index);
}
fn maskIndex(index: usize) usize {
return index >> @bitSizeOf(ShiftInt);
}
fn boolMaskBit(index: usize, value: bool) MaskInt {
return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
}
};
}
pub const DynamicBitSetUnmanaged = struct {
const Self = @This();
pub const MaskInt = usize;
pub const ShiftInt = std.math.Log2Int(MaskInt);
bit_length: usize = 0,
masks: [*]MaskInt = empty_masks_ptr,
var empty_masks_data = [_]MaskInt{ 0, undefined };
const empty_masks_ptr = empty_masks_data[1..2];
pub fn initEmpty(allocator: Allocator, bit_length: usize) !Self {
var self = Self{};
try self.resize(allocator, bit_length, false);
return self;
}
pub fn initFull(allocator: Allocator, bit_length: usize) !Self {
var self = Self{};
try self.resize(allocator, bit_length, true);
return self;
}
pub fn resize(self: *@This(), allocator: Allocator, new_len: usize, fill: bool) !void {
const old_len = self.bit_length;
const old_masks = numMasks(old_len);
const new_masks = numMasks(new_len);
const old_allocation = (self.masks - 1)[0..(self.masks - 1)[0]];
if (new_masks == 0) {
assert(new_len == 0);
allocator.free(old_allocation);
self.masks = empty_masks_ptr;
self.bit_length = 0;
return;
}
if (old_allocation.len != new_masks + 1) realloc: {
const new_allocation = allocator.realloc(old_allocation, new_masks + 1) catch |err| {
if (new_masks + 1 > old_allocation.len) return err;
break :realloc;
};
new_allocation[0] = new_allocation.len;
self.masks = new_allocation.ptr + 1;
}
if (new_len > old_len) {
if (fill and old_masks > 0) {
const old_padding_bits = old_masks * @bitSizeOf(MaskInt) - old_len;
const old_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, old_padding_bits);
self.masks[old_masks - 1] |= ~old_mask;
}
if (new_masks > old_masks) {
const fill_value = std.math.boolMask(MaskInt, fill);
std.mem.set(MaskInt, self.masks[old_masks..new_masks], fill_value);
}
}
if (new_len > 0) {
const padding_bits = new_masks * @bitSizeOf(MaskInt) - new_len;
const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
self.masks[new_masks - 1] &= last_item_mask;
}
self.bit_length = new_len;
}
pub fn deinit(self: *Self, allocator: Allocator) void {
self.resize(allocator, 0, false) catch unreachable;
}
pub fn clone(self: *const Self, new_allocator: Allocator) !Self {
const num_masks = numMasks(self.bit_length);
var copy = Self{};
try copy.resize(new_allocator, self.bit_length, false);
std.mem.copy(MaskInt, copy.masks[0..num_masks], self.masks[0..num_masks]);
return copy;
}
pub inline fn capacity(self: Self) usize {
return self.bit_length;
}
pub fn isSet(self: Self, index: usize) bool {
assert(index < self.bit_length);
return (self.masks[maskIndex(index)] & maskBit(index)) != 0;
}
pub fn count(self: Self) usize {
const num_masks = (self.bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt);
var total: usize = 0;
for (self.masks[0..num_masks]) |mask| {
total += @popCount(mask);
}
return total;
}
pub fn setValue(self: *Self, index: usize, value: bool) void {
assert(index < self.bit_length);
const bit = maskBit(index);
const mask_index = maskIndex(index);
const new_bit = bit & std.math.boolMask(MaskInt, value);
self.masks[mask_index] = (self.masks[mask_index] & ~bit) | new_bit;
}
pub fn set(self: *Self, index: usize) void {
assert(index < self.bit_length);
self.masks[maskIndex(index)] |= maskBit(index);
}
pub fn setRangeValue(self: *Self, range: Range, value: bool) void {
assert(range.end <= self.bit_length);
assert(range.start <= range.end);
if (range.start == range.end) return;
const start_mask_index = maskIndex(range.start);
const start_bit = @truncate(ShiftInt, range.start);
const end_mask_index = maskIndex(range.end);
const end_bit = @truncate(ShiftInt, range.end);
if (start_mask_index == end_mask_index) {
var mask1 = std.math.boolMask(MaskInt, true) << start_bit;
var mask2 = std.math.boolMask(MaskInt, true) >> (@bitSizeOf(MaskInt) - 1) - (end_bit - 1);
self.masks[start_mask_index] &= ~(mask1 & mask2);
mask1 = std.math.boolMask(MaskInt, value) << start_bit;
mask2 = std.math.boolMask(MaskInt, value) >> (@bitSizeOf(MaskInt) - 1) - (end_bit - 1);
self.masks[start_mask_index] |= mask1 & mask2;
} else {
var bulk_mask_index: usize = undefined;
if (start_bit > 0) {
self.masks[start_mask_index] =
(self.masks[start_mask_index] & ~(std.math.boolMask(MaskInt, true) << start_bit)) |
(std.math.boolMask(MaskInt, value) << start_bit);
bulk_mask_index = start_mask_index + 1;
} else {
bulk_mask_index = start_mask_index;
}
while (bulk_mask_index < end_mask_index) : (bulk_mask_index += 1) {
self.masks[bulk_mask_index] = std.math.boolMask(MaskInt, value);
}
if (end_bit > 0) {
self.masks[end_mask_index] =
(self.masks[end_mask_index] & (std.math.boolMask(MaskInt, true) << end_bit)) |
(std.math.boolMask(MaskInt, value) >> ((@bitSizeOf(MaskInt) - 1) - (end_bit - 1)));
}
}
}
pub fn unset(self: *Self, index: usize) void {
assert(index < self.bit_length);
self.masks[maskIndex(index)] &= ~maskBit(index);
}
pub fn toggle(self: *Self, index: usize) void {
assert(index < self.bit_length);
self.masks[maskIndex(index)] ^= maskBit(index);
}
pub fn toggleSet(self: *Self, toggles: Self) void {
assert(toggles.bit_length == self.bit_length);
const num_masks = numMasks(self.bit_length);
for (self.masks[0..num_masks], 0..) |*mask, i| {
mask.* ^= toggles.masks[i];
}
}
pub fn toggleAll(self: *Self) void {
const bit_length = self.bit_length;
if (bit_length == 0) return;
const num_masks = numMasks(self.bit_length);
for (self.masks[0..num_masks]) |*mask| {
mask.* = ~mask.*;
}
const padding_bits = num_masks * @bitSizeOf(MaskInt) - bit_length;
const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
self.masks[num_masks - 1] &= last_item_mask;
}
pub fn setUnion(self: *Self, other: Self) void {
assert(other.bit_length == self.bit_length);
const num_masks = numMasks(self.bit_length);
for (self.masks[0..num_masks], 0..) |*mask, i| {
mask.* |= other.masks[i];
}
}
pub fn setIntersection(self: *Self, other: Self) void {
assert(other.bit_length == self.bit_length);
const num_masks = numMasks(self.bit_length);
for (self.masks[0..num_masks], 0..) |*mask, i| {
mask.* &= other.masks[i];
}
}
pub fn findFirstSet(self: Self) ?usize {
var offset: usize = 0;
var mask = self.masks;
while (offset < self.bit_length) {
if (mask[0] != 0) break;
mask += 1;
offset += @bitSizeOf(MaskInt);
} else return null;
return offset + @ctz(mask[0]);
}
pub fn toggleFirstSet(self: *Self) ?usize {
var offset: usize = 0;
var mask = self.masks;
while (offset < self.bit_length) {
if (mask[0] != 0) break;
mask += 1;
offset += @bitSizeOf(MaskInt);
} else return null;
const index = @ctz(mask[0]);
mask[0] &= (mask[0] - 1);
return offset + index;
}
pub fn eql(self: Self, other: Self) bool {
if (self.bit_length != other.bit_length) {
return false;
}
const num_masks = numMasks(self.bit_length);
var i: usize = 0;
return while (i < num_masks) : (i += 1) {
if (self.masks[i] != other.masks[i]) {
break false;
}
} else true;
}
pub fn subsetOf(self: Self, other: Self) bool {
if (self.bit_length != other.bit_length) {
return false;
}
const num_masks = numMasks(self.bit_length);
var i: usize = 0;
return while (i < num_masks) : (i += 1) {
if (self.masks[i] & other.masks[i] != self.masks[i]) {
break false;
}
} else true;
}
pub fn supersetOf(self: Self, other: Self) bool {
if (self.bit_length != other.bit_length) {
return false;
}
const num_masks = numMasks(self.bit_length);
var i: usize = 0;
return while (i < num_masks) : (i += 1) {
if (self.masks[i] & other.masks[i] != other.masks[i]) {
break false;
}
} else true;
}
pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) {
const num_masks = numMasks(self.bit_length);
const padding_bits = num_masks * @bitSizeOf(MaskInt) - self.bit_length;
const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
return Iterator(options).init(self.masks[0..num_masks], last_item_mask);
}
pub fn Iterator(comptime options: IteratorOptions) type {
return BitSetIterator(MaskInt, options);
}
fn maskBit(index: usize) MaskInt {
return @as(MaskInt, 1) << @truncate(ShiftInt, index);
}
fn maskIndex(index: usize) usize {
return index >> @bitSizeOf(ShiftInt);
}
fn boolMaskBit(index: usize, value: bool) MaskInt {
return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
}
fn numMasks(bit_length: usize) usize {
return (bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt);
}
};
pub const DynamicBitSet = struct {
const Self = @This();
pub const MaskInt = usize;
pub const ShiftInt = std.math.Log2Int(MaskInt);
allocator: Allocator,
unmanaged: DynamicBitSetUnmanaged = .{},
pub fn initEmpty(allocator: Allocator, bit_length: usize) !Self {
return Self{
.unmanaged = try DynamicBitSetUnmanaged.initEmpty(allocator, bit_length),
.allocator = allocator,
};
}
pub fn initFull(allocator: Allocator, bit_length: usize) !Self {
return Self{
.unmanaged = try DynamicBitSetUnmanaged.initFull(allocator, bit_length),
.allocator = allocator,
};
}
pub fn resize(self: *@This(), new_len: usize, fill: bool) !void {
try self.unmanaged.resize(self.allocator, new_len, fill);
}
pub fn deinit(self: *Self) void {
self.unmanaged.deinit(self.allocator);
}
pub fn clone(self: *const Self, new_allocator: Allocator) !Self {
return Self{
.unmanaged = try self.unmanaged.clone(new_allocator),
.allocator = new_allocator,
};
}
pub inline fn capacity(self: Self) usize {
return self.unmanaged.capacity();
}
pub fn isSet(self: Self, index: usize) bool {
return self.unmanaged.isSet(index);
}
pub fn count(self: Self) usize {
return self.unmanaged.count();
}
pub fn setValue(self: *Self, index: usize, value: bool) void {
self.unmanaged.setValue(index, value);
}
pub fn set(self: *Self, index: usize) void {
self.unmanaged.set(index);
}
pub fn setRangeValue(self: *Self, range: Range, value: bool) void {
self.unmanaged.setRangeValue(range, value);
}
pub fn unset(self: *Self, index: usize) void {
self.unmanaged.unset(index);
}
pub fn toggle(self: *Self, index: usize) void {
self.unmanaged.toggle(index);
}
pub fn toggleSet(self: *Self, toggles: Self) void {
self.unmanaged.toggleSet(toggles.unmanaged);
}
pub fn toggleAll(self: *Self) void {
self.unmanaged.toggleAll();
}
pub fn setUnion(self: *Self, other: Self) void {
self.unmanaged.setUnion(other.unmanaged);
}
pub fn setIntersection(self: *Self, other: Self) void {
self.unmanaged.setIntersection(other.unmanaged);
}
pub fn findFirstSet(self: Self) ?usize {
return self.unmanaged.findFirstSet();
}
pub fn toggleFirstSet(self: *Self) ?usize {
return self.unmanaged.toggleFirstSet();
}
pub fn eql(self: Self, other: Self) bool {
return self.unmanaged.eql(other.unmanaged);
}
pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) {
return self.unmanaged.iterator(options);
}
pub const Iterator = DynamicBitSetUnmanaged.Iterator;
};
pub const IteratorOptions = struct {
kind: Type = .set,
direction: Direction = .forward,
pub const Type = enum {
set,
unset,
};
pub const Direction = enum {
forward,
reverse,
};
};
fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) type {
const ShiftInt = std.math.Log2Int(MaskInt);
const kind = options.kind;
const direction = options.direction;
return struct {
const Self = @This();
bits_remain: MaskInt,
words_remain: []const MaskInt,
bit_offset: usize,
last_word_mask: MaskInt,
fn init(masks: []const MaskInt, last_word_mask: MaskInt) Self {
if (masks.len == 0) {
return Self{
.bits_remain = 0,
.words_remain = &[_]MaskInt{},
.last_word_mask = last_word_mask,
.bit_offset = 0,
};
} else {
var result = Self{
.bits_remain = 0,
.words_remain = masks,
.last_word_mask = last_word_mask,
.bit_offset = if (direction == .forward) 0 else (masks.len - 1) * @bitSizeOf(MaskInt),
};
result.nextWord(true);
return result;
}
}
pub fn next(self: *Self) ?usize {
while (self.bits_remain == 0) {
if (self.words_remain.len == 0) return null;
self.nextWord(false);
switch (direction) {
.forward => self.bit_offset += @bitSizeOf(MaskInt),
.reverse => self.bit_offset -= @bitSizeOf(MaskInt),
}
}
switch (direction) {
.forward => {
const next_index = @ctz(self.bits_remain) + self.bit_offset;
self.bits_remain &= self.bits_remain - 1;
return next_index;
},
.reverse => {
const leading_zeroes = @clz(self.bits_remain);
const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
const no_top_bit_mask = (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
self.bits_remain &= no_top_bit_mask;
return top_bit + self.bit_offset;
},
}
}
inline fn nextWord(self: *Self, comptime is_first_word: bool) void {
var word = switch (direction) {
.forward => self.words_remain[0],
.reverse => self.words_remain[self.words_remain.len - 1],
};
switch (kind) {
.set => {},
.unset => {
word = ~word;
if ((direction == .reverse and is_first_word) or
(direction == .forward and self.words_remain.len == 1))
{
word &= self.last_word_mask;
}
},
}
switch (direction) {
.forward => self.words_remain = self.words_remain[1..],
.reverse => self.words_remain.len -= 1,
}
self.bits_remain = word;
}
};
}
pub const Range = struct {
start: usize,
end: usize,
};
const testing = std.testing;
fn testEql(empty: anytype, full: anytype, len: usize) !void {
try testing.expect(empty.eql(empty));
try testing.expect(full.eql(full));
switch (len) {
0 => {
try testing.expect(empty.eql(full));
try testing.expect(full.eql(empty));
},
else => {
try testing.expect(!empty.eql(full));
try testing.expect(!full.eql(empty));
},
}
}
fn testSubsetOf(empty: anytype, full: anytype, even: anytype, odd: anytype, len: usize) !void {
try testing.expect(empty.subsetOf(empty));
try testing.expect(empty.subsetOf(full));
try testing.expect(full.subsetOf(full));
switch (len) {
0 => {
try testing.expect(even.subsetOf(odd));
try testing.expect(odd.subsetOf(even));
},
1 => {
try testing.expect(!even.subsetOf(odd));
try testing.expect(odd.subsetOf(even));
},
else => {
try testing.expect(!even.subsetOf(odd));
try testing.expect(!odd.subsetOf(even));
},
}
}
fn testSupersetOf(empty: anytype, full: anytype, even: anytype, odd: anytype, len: usize) !void {
try testing.expect(full.supersetOf(full));
try testing.expect(full.supersetOf(empty));
try testing.expect(empty.supersetOf(empty));
switch (len) {
0 => {
try testing.expect(even.supersetOf(odd));
try testing.expect(odd.supersetOf(even));
},
1 => {
try testing.expect(even.supersetOf(odd));
try testing.expect(!odd.supersetOf(even));
},
else => {
try testing.expect(!even.supersetOf(odd));
try testing.expect(!odd.supersetOf(even));
},
}
}
fn testBitSet(a: anytype, b: anytype, len: usize) !void {
try testing.expectEqual(len, a.capacity());
try testing.expectEqual(len, b.capacity());
{
var i: usize = 0;
while (i < len) : (i += 1) {
a.setValue(i, i & 1 == 0);
b.setValue(i, i & 2 == 0);
}
}
try testing.expectEqual((len + 1) / 2, a.count());
try testing.expectEqual((len + 3) / 4 + (len + 2) / 4, b.count());
{
var iter = a.iterator(.{});
var i: usize = 0;
while (i < len) : (i += 2) {
try testing.expectEqual(@as(?usize, i), iter.next());
}
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
}
a.toggleAll();
{
var iter = a.iterator(.{});
var i: usize = 1;
while (i < len) : (i += 2) {
try testing.expectEqual(@as(?usize, i), iter.next());
}
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
}
{
var iter = b.iterator(.{ .kind = .unset });
var i: usize = 2;
while (i < len) : (i += 4) {
try testing.expectEqual(@as(?usize, i), iter.next());
if (i + 1 < len) {
try testing.expectEqual(@as(?usize, i + 1), iter.next());
}
}
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
}
{
var i: usize = 0;
while (i < len) : (i += 1) {
try testing.expectEqual(i & 1 != 0, a.isSet(i));
try testing.expectEqual(i & 2 == 0, b.isSet(i));
}
}
a.setUnion(b.*);
{
var i: usize = 0;
while (i < len) : (i += 1) {
try testing.expectEqual(i & 1 != 0 or i & 2 == 0, a.isSet(i));
try testing.expectEqual(i & 2 == 0, b.isSet(i));
}
i = len;
var set = a.iterator(.{ .direction = .reverse });
var unset = a.iterator(.{ .kind = .unset, .direction = .reverse });
while (i > 0) {
i -= 1;
if (i & 1 != 0 or i & 2 == 0) {
try testing.expectEqual(@as(?usize, i), set.next());
} else {
try testing.expectEqual(@as(?usize, i), unset.next());
}
}
try testing.expectEqual(@as(?usize, null), set.next());
try testing.expectEqual(@as(?usize, null), set.next());
try testing.expectEqual(@as(?usize, null), set.next());
try testing.expectEqual(@as(?usize, null), unset.next());
try testing.expectEqual(@as(?usize, null), unset.next());
try testing.expectEqual(@as(?usize, null), unset.next());
}
a.toggleSet(b.*);
{
try testing.expectEqual(len / 4, a.count());
var i: usize = 0;
while (i < len) : (i += 1) {
try testing.expectEqual(i & 1 != 0 and i & 2 != 0, a.isSet(i));
try testing.expectEqual(i & 2 == 0, b.isSet(i));
if (i & 1 == 0) {
a.set(i);
} else {
a.unset(i);
}
}
}
a.setIntersection(b.*);
{
try testing.expectEqual((len + 3) / 4, a.count());
var i: usize = 0;
while (i < len) : (i += 1) {
try testing.expectEqual(i & 1 == 0 and i & 2 == 0, a.isSet(i));
try testing.expectEqual(i & 2 == 0, b.isSet(i));
}
}
a.toggleSet(a.*);
{
var iter = a.iterator(.{});
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(usize, 0), a.count());
}
{
var iter = a.iterator(.{ .direction = .reverse });
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(?usize, null), iter.next());
try testing.expectEqual(@as(usize, 0), a.count());
}
const test_bits = [_]usize{
0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 22, 31, 32, 63, 64,
66, 95, 127, 160, 192, 1000,
};
for (test_bits) |i| {
if (i < a.capacity()) {
a.set(i);
}
}
for (test_bits) |i| {
if (i < a.capacity()) {
try testing.expectEqual(@as(?usize, i), a.findFirstSet());
try testing.expectEqual(@as(?usize, i), a.toggleFirstSet());
}
}
try testing.expectEqual(@as(?usize, null), a.findFirstSet());
try testing.expectEqual(@as(?usize, null), a.toggleFirstSet());
try testing.expectEqual(@as(?usize, null), a.findFirstSet());
try testing.expectEqual(@as(?usize, null), a.toggleFirstSet());
try testing.expectEqual(@as(usize, 0), a.count());
a.setRangeValue(.{ .start = 0, .end = len }, false);
try testing.expectEqual(@as(usize, 0), a.count());
a.setRangeValue(.{ .start = 0, .end = len }, true);
try testing.expectEqual(len, a.count());
a.setRangeValue(.{ .start = 0, .end = len }, false);
a.setRangeValue(.{ .start = 0, .end = 0 }, true);
try testing.expectEqual(@as(usize, 0), a.count());
a.setRangeValue(.{ .start = len, .end = len }, true);
try testing.expectEqual(@as(usize, 0), a.count());
if (len >= 1) {
a.setRangeValue(.{ .start = 0, .end = len }, false);
a.setRangeValue(.{ .start = 0, .end = 1 }, true);
try testing.expectEqual(@as(usize, 1), a.count());
try testing.expect(a.isSet(0));
a.setRangeValue(.{ .start = 0, .end = len }, false);
a.setRangeValue(.{ .start = 0, .end = len - 1 }, true);
try testing.expectEqual(len - 1, a.count());
try testing.expect(!a.isSet(len - 1));
a.setRangeValue(.{ .start = 0, .end = len }, false);
a.setRangeValue(.{ .start = 1, .end = len }, true);
try testing.expectEqual(@as(usize, len - 1), a.count());
try testing.expect(!a.isSet(0));
a.setRangeValue(.{ .start = 0, .end = len }, false);
a.setRangeValue(.{ .start = len - 1, .end = len }, true);
try testing.expectEqual(@as(usize, 1), a.count());
try testing.expect(a.isSet(len - 1));
if (len >= 4) {
a.setRangeValue(.{ .start = 0, .end = len }, false);
a.setRangeValue(.{ .start = 1, .end = len - 2 }, true);
try testing.expectEqual(@as(usize, len - 3), a.count());
try testing.expect(!a.isSet(0));
try testing.expect(a.isSet(1));
try testing.expect(a.isSet(len - 3));
try testing.expect(!a.isSet(len - 2));
try testing.expect(!a.isSet(len - 1));
}
}
}
fn fillEven(set: anytype, len: usize) void {
var i: usize = 0;
while (i < len) : (i += 1) {
set.setValue(i, i & 1 == 0);
}
}
fn fillOdd(set: anytype, len: usize) void {
var i: usize = 0;
while (i < len) : (i += 1) {
set.setValue(i, i & 1 == 1);
}
}
fn testPureBitSet(comptime Set: type) !void {
const empty = Set.initEmpty();
const full = Set.initFull();
const even = even: {
var bit_set = Set.initEmpty();
fillEven(&bit_set, Set.bit_length);
break :even bit_set;
};
const odd = odd: {
var bit_set = Set.initEmpty();
fillOdd(&bit_set, Set.bit_length);
break :odd bit_set;
};
try testSubsetOf(empty, full, even, odd, Set.bit_length);
try testSupersetOf(empty, full, even, odd, Set.bit_length);
try testing.expect(empty.complement().eql(full));
try testing.expect(full.complement().eql(empty));
try testing.expect(even.complement().eql(odd));
try testing.expect(odd.complement().eql(even));
try testing.expect(empty.unionWith(empty).eql(empty));
try testing.expect(empty.unionWith(full).eql(full));
try testing.expect(full.unionWith(full).eql(full));
try testing.expect(full.unionWith(empty).eql(full));
try testing.expect(even.unionWith(odd).eql(full));
try testing.expect(odd.unionWith(even).eql(full));
try testing.expect(empty.intersectWith(empty).eql(empty));
try testing.expect(empty.intersectWith(full).eql(empty));
try testing.expect(full.intersectWith(full).eql(full));
try testing.expect(full.intersectWith(empty).eql(empty));
try testing.expect(even.intersectWith(odd).eql(empty));
try testing.expect(odd.intersectWith(even).eql(empty));
try testing.expect(empty.xorWith(empty).eql(empty));
try testing.expect(empty.xorWith(full).eql(full));
try testing.expect(full.xorWith(full).eql(empty));
try testing.expect(full.xorWith(empty).eql(full));
try testing.expect(even.xorWith(odd).eql(full));
try testing.expect(odd.xorWith(even).eql(full));
try testing.expect(empty.differenceWith(empty).eql(empty));
try testing.expect(empty.differenceWith(full).eql(empty));
try testing.expect(full.differenceWith(full).eql(empty));
try testing.expect(full.differenceWith(empty).eql(full));
try testing.expect(full.differenceWith(odd).eql(even));
try testing.expect(full.differenceWith(even).eql(odd));
}
fn testStaticBitSet(comptime Set: type) !void {
var a = Set.initEmpty();
var b = Set.initFull();
try testing.expectEqual(@as(usize, 0), a.count());
try testing.expectEqual(@as(usize, Set.bit_length), b.count());
try testEql(a, b, Set.bit_length);
try testBitSet(&a, &b, Set.bit_length);
try testPureBitSet(Set);
}
test "IntegerBitSet" {
if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest;
try testStaticBitSet(IntegerBitSet(0));
try testStaticBitSet(IntegerBitSet(1));
try testStaticBitSet(IntegerBitSet(2));
try testStaticBitSet(IntegerBitSet(5));
try testStaticBitSet(IntegerBitSet(8));
try testStaticBitSet(IntegerBitSet(32));
try testStaticBitSet(IntegerBitSet(64));
try testStaticBitSet(IntegerBitSet(127));
}
test "ArrayBitSet" {
inline for (.{ 0, 1, 2, 31, 32, 33, 63, 64, 65, 254, 500, 3000 }) |size| {
try testStaticBitSet(ArrayBitSet(u8, size));
try testStaticBitSet(ArrayBitSet(u16, size));
try testStaticBitSet(ArrayBitSet(u32, size));
try testStaticBitSet(ArrayBitSet(u64, size));
try testStaticBitSet(ArrayBitSet(u128, size));
}
}
test "DynamicBitSetUnmanaged" {
const allocator = std.testing.allocator;
var a = try DynamicBitSetUnmanaged.initEmpty(allocator, 300);
try testing.expectEqual(@as(usize, 0), a.count());
a.deinit(allocator);
a = try DynamicBitSetUnmanaged.initEmpty(allocator, 0);
defer a.deinit(allocator);
for ([_]usize{ 1, 2, 31, 32, 33, 0, 65, 64, 63, 500, 254, 3000 }) |size| {
const old_len = a.capacity();
var empty = try a.clone(allocator);
defer empty.deinit(allocator);
try testing.expectEqual(old_len, empty.capacity());
var i: usize = 0;
while (i < old_len) : (i += 1) {
try testing.expectEqual(a.isSet(i), empty.isSet(i));
}
a.toggleSet(a);
empty.toggleSet(empty);
try a.resize(allocator, size, true);
try empty.resize(allocator, size, false);
if (size > old_len) {
try testing.expectEqual(size - old_len, a.count());
} else {
try testing.expectEqual(@as(usize, 0), a.count());
}
try testing.expectEqual(@as(usize, 0), empty.count());
var full = try DynamicBitSetUnmanaged.initFull(allocator, size);
defer full.deinit(allocator);
try testing.expectEqual(@as(usize, size), full.count());
try testEql(empty, full, size);
{
var even = try DynamicBitSetUnmanaged.initEmpty(allocator, size);
defer even.deinit(allocator);
fillEven(&even, size);
var odd = try DynamicBitSetUnmanaged.initEmpty(allocator, size);
defer odd.deinit(allocator);
fillOdd(&odd, size);
try testSubsetOf(empty, full, even, odd, size);
try testSupersetOf(empty, full, even, odd, size);
}
try testBitSet(&a, &full, size);
}
}
test "DynamicBitSet" {
const allocator = std.testing.allocator;
var a = try DynamicBitSet.initEmpty(allocator, 300);
try testing.expectEqual(@as(usize, 0), a.count());
a.deinit();
a = try DynamicBitSet.initEmpty(allocator, 0);
defer a.deinit();
for ([_]usize{ 1, 2, 31, 32, 33, 0, 65, 64, 63, 500, 254, 3000 }) |size| {
const old_len = a.capacity();
var tmp = try a.clone(allocator);
defer tmp.deinit();
try testing.expectEqual(old_len, tmp.capacity());
var i: usize = 0;
while (i < old_len) : (i += 1) {
try testing.expectEqual(a.isSet(i), tmp.isSet(i));
}
a.toggleSet(a);
tmp.toggleSet(tmp);
try a.resize(size, true);
try tmp.resize(size, false);
if (size > old_len) {
try testing.expectEqual(size - old_len, a.count());
} else {
try testing.expectEqual(@as(usize, 0), a.count());
}
try testing.expectEqual(@as(usize, 0), tmp.count());
var b = try DynamicBitSet.initFull(allocator, size);
defer b.deinit();
try testing.expectEqual(@as(usize, size), b.count());
try testEql(tmp, b, size);
try testBitSet(&a, &b, size);
}
}
test "StaticBitSet" {
try testing.expectEqual(IntegerBitSet(0), StaticBitSet(0));
try testing.expectEqual(IntegerBitSet(5), StaticBitSet(5));
try testing.expectEqual(IntegerBitSet(@bitSizeOf(usize)), StaticBitSet(@bitSizeOf(usize)));
try testing.expectEqual(ArrayBitSet(usize, @bitSizeOf(usize) + 1), StaticBitSet(@bitSizeOf(usize) + 1));
try testing.expectEqual(ArrayBitSet(usize, 500), StaticBitSet(500));
}