aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-30 04:42:33 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-30 04:46:52 -0800
commit42be4e52fe5312e30c66ae28dccaa432e509ff86 (patch)
treed0378913a9a61de3e9d905b3f46be5f056e59256 /src
parent385c81d67be14abaaa938c0d7d46acd90d714392 (diff)
downloadbun-42be4e52fe5312e30c66ae28dccaa432e509ff86.tar.gz
bun-42be4e52fe5312e30c66ae28dccaa432e509ff86.tar.zst
bun-42be4e52fe5312e30c66ae28dccaa432e509ff86.zip
Use ArrayBitSet that passes by reference instead of value
Diffstat (limited to 'src')
-rw-r--r--src/bun.zig1
-rw-r--r--src/install/bit_set.zig644
-rw-r--r--src/js_lexer/identifier_cache.zig5
3 files changed, 588 insertions, 62 deletions
diff --git a/src/bun.zig b/src/bun.zig
index 6e0cfc87e..89ae31f4b 100644
--- a/src/bun.zig
+++ b/src/bun.zig
@@ -734,3 +734,4 @@ pub const which = @import("./which.zig").which;
pub const json = @import("./json_parser.zig");
pub const JSAst = @import("./js_ast.zig");
+pub const bit_set = @import("./install/bit_set.zig");
diff --git a/src/install/bit_set.zig b/src/install/bit_set.zig
index b9f63e2ab..bd6d71027 100644
--- a/src/install/bit_set.zig
+++ b/src/install/bit_set.zig
@@ -23,7 +23,7 @@
//! size. The interfaces of these two types match exactly, except for fields.
//!
//! DynamicBitSet:
-//! A bit set with runtime known size, backed by an allocated slice
+//! A bit set with runtime-known size, backed by an allocated slice
//! of usize.
//!
//! DynamicBitSetUnmanaged:
@@ -50,7 +50,7 @@ pub fn StaticBitSet(comptime size: usize) type {
/// This set is good for sets with a small size, but may generate
/// inefficient code for larger sets, especially in debug mode.
pub fn IntegerBitSet(comptime size: u16) type {
- return struct {
+ return packed struct {
const Self = @This();
// TODO: Make this a comptime field once those are fixed
@@ -110,6 +110,31 @@ pub fn IntegerBitSet(comptime size: u16) type {
self.mask |= maskBit(index);
}
+ /// Changes the value of all bits in the specified range to
+ /// match the passed boolean.
+ 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;
+ }
+
/// Removes a specific bit from the bit set
pub fn unset(self: *Self, index: usize) void {
assert(index < bit_length);
@@ -167,6 +192,68 @@ pub fn IntegerBitSet(comptime size: u16) type {
return index;
}
+ /// Returns true iff every corresponding bit in both
+ /// bit sets are the same.
+ pub fn eql(self: Self, other: Self) bool {
+ return bit_length == 0 or self.mask == other.mask;
+ }
+
+ /// Returns true iff the first bit set is the subset
+ /// of the second one.
+ pub fn subsetOf(self: Self, other: Self) bool {
+ return self.intersectWith(other).eql(self);
+ }
+
+ /// Returns true iff the first bit set is the superset
+ /// of the second one.
+ pub fn supersetOf(self: Self, other: Self) bool {
+ return other.subsetOf(self);
+ }
+
+ /// Returns the complement bit sets. Bits in the result
+ /// are set if the corresponding bits were not set.
+ pub fn complement(self: Self) Self {
+ var result = self;
+ result.toggleAll();
+ return result;
+ }
+
+ /// Returns the union of two bit sets. Bits in the
+ /// result are set if the corresponding bits were set
+ /// in either input.
+ pub fn unionWith(self: Self, other: Self) Self {
+ var result = self;
+ result.setUnion(other);
+ return result;
+ }
+
+ /// Returns the intersection of two bit sets. Bits in
+ /// the result are set if the corresponding bits were
+ /// set in both inputs.
+ pub fn intersectWith(self: Self, other: Self) Self {
+ var result = self;
+ result.setIntersection(other);
+ return result;
+ }
+
+ /// Returns the xor of two bit sets. Bits in the
+ /// result are set if the corresponding bits were
+ /// not the same in both inputs.
+ pub fn xorWith(self: Self, other: Self) Self {
+ var result = self;
+ result.toggleSet(other);
+ return result;
+ }
+
+ /// Returns the difference of two bit sets. Bits in
+ /// the result are set if set in the first but not
+ /// set in the second set.
+ pub fn differenceWith(self: Self, other: Self) Self {
+ var result = self;
+ result.setIntersection(other.complement());
+ return result;
+ }
+
/// Iterates through the items in the set, according to the options.
/// The default options (.{}) will iterate indices of set bits in
/// ascending order. Modifications to the underlying bit set may
@@ -262,7 +349,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
", which contains padding bits. Please round this up to an unpadded integer size (i.e. " ++ @typeName(FixedMaskType) ++ ").");
}
- return struct {
+ return extern struct {
const Self = @This();
// TODO: Make this a comptime field once those are fixed
@@ -312,14 +399,14 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
/// Returns true if the bit at the specified index
/// is present in the set, false otherwise.
- pub fn isSet(self: Self, index: usize) bool {
+ pub fn isSet(self: *const Self, index: usize) bool {
assert(index < bit_length);
if (num_masks == 0) return false; // doesn't compile in this case
return (self.masks[maskIndex(index)] & maskBit(index)) != 0;
}
/// Returns the total number of set bits in this bit set.
- pub fn count(self: Self) usize {
+ pub fn count(self: *const Self) usize {
var total: usize = 0;
for (self.masks) |mask| {
total += @popCount(mask);
@@ -345,6 +432,51 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
self.masks[maskIndex(index)] |= maskBit(index);
}
+ /// Changes the value of all bits in the specified range to
+ /// match the passed boolean.
+ 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)));
+ }
+ }
+ }
+
/// Removes a specific bit from the bit set
pub fn unset(self: *Self, index: usize) void {
assert(index < bit_length);
@@ -361,9 +493,10 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
/// Flips all bits in this bit set which are present
/// in the toggles bit set.
- pub fn toggleSet(self: *Self, toggles: Self) void {
+ pub fn toggleSet(self: *Self, toggles: *const Self) void {
+ const other = &toggles.masks;
for (self.masks) |*mask, i| {
- mask.* ^= toggles.masks[i];
+ mask.* ^= other[i];
}
}
@@ -382,7 +515,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
/// Performs a union of two bit sets, and stores the
/// result in the first one. Bits in the result are
/// set if the corresponding bits were set in either input.
- pub fn setUnion(self: *Self, other: Self) void {
+ pub fn setUnion(self: *Self, other: *const Self) void {
for (self.masks) |*mask, i| {
mask.* |= other.masks[i];
}
@@ -391,7 +524,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
/// Performs an intersection of two bit sets, and stores
/// the result in the first one. Bits in the result are
/// set if the corresponding bits were set in both inputs.
- pub fn setIntersection(self: *Self, other: Self) void {
+ pub fn setIntersection(self: *Self, other: *const Self) void {
for (self.masks) |*mask, i| {
mask.* &= other.masks[i];
}
@@ -399,7 +532,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
/// Finds the index of the first set bit.
/// If no bits are set, returns null.
- pub fn findFirstSet(self: Self) ?usize {
+ pub fn findFirstSet(self: *const Self) ?usize {
var offset: usize = 0;
const mask = for (self.masks) |mask| {
if (mask != 0) break mask;
@@ -421,6 +554,73 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
return offset + index;
}
+ /// Returns true iff every corresponding bit in both
+ /// bit sets are the same.
+ pub fn eql(self: *const Self, other: *const Self) bool {
+ var i: usize = 0;
+ return while (i < num_masks) : (i += 1) {
+ if (self.masks[i] != other.masks[i]) {
+ break false;
+ }
+ } else true;
+ }
+
+ /// Returns true iff the first bit set is the subset
+ /// of the second one.
+ pub fn subsetOf(self: *const Self, other: *const Self) bool {
+ return self.intersectWith(other).eql(self);
+ }
+
+ /// Returns true iff the first bit set is the superset
+ /// of the second one.
+ pub fn supersetOf(self: *const Self, other: *const Self) bool {
+ return other.subsetOf(self);
+ }
+
+ /// Returns the complement bit sets. Bits in the result
+ /// are set if the corresponding bits were not set.
+ pub fn complement(self: *const Self) Self {
+ var result = self.*;
+ result.toggleAll();
+ return result;
+ }
+
+ /// Returns the union of two bit sets. Bits in the
+ /// result are set if the corresponding bits were set
+ /// in either input.
+ pub fn unionWith(self: *const Self, other: *const Self) Self {
+ var result = self.*;
+ result.setUnion(other);
+ return result;
+ }
+
+ /// Returns the intersection of two bit sets. Bits in
+ /// the result are set if the corresponding bits were
+ /// set in both inputs.
+ pub fn intersectWith(self: *const Self, other: *const Self) Self {
+ var result = self.*;
+ result.setIntersection(other);
+ return result;
+ }
+
+ /// Returns the xor of two bit sets. Bits in the
+ /// result are set if the corresponding bits were
+ /// not the same in both inputs.
+ pub fn xorWith(self: *const Self, other: *const Self) Self {
+ var result = self.*;
+ result.toggleSet(other);
+ return result;
+ }
+
+ /// Returns the difference of two bit sets. Bits in
+ /// the result are set if set in the first but not
+ /// set in the second set.
+ pub fn differenceWith(self: *const Self, other: *const Self) Self {
+ var result = self.*;
+ result.setIntersection(&other.complement());
+ return result;
+ }
+
/// Iterates through the items in the set, according to the options.
/// The default options (.{}) will iterate indices of set bits in
/// ascending order. Modifications to the underlying bit set may
@@ -445,7 +645,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
};
}
-/// A bit set with runtime known size, backed by an allocated slice
+/// A bit set with runtime-known size, backed by an allocated slice
/// of usize. The allocator must be tracked externally by the user.
pub const DynamicBitSetUnmanaged = struct {
const Self = @This();
@@ -476,24 +676,24 @@ pub const DynamicBitSetUnmanaged = struct {
/// Creates a bit set with no elements present.
/// If bit_length is not zero, deinit must eventually be called.
- pub fn initEmpty(bit_length: usize, allocator: Allocator) !Self {
+ pub fn initEmpty(allocator: Allocator, bit_length: usize) !Self {
var self = Self{};
- try self.resize(bit_length, false, allocator);
+ try self.resize(allocator, bit_length, false);
return self;
}
/// Creates a bit set with all elements present.
/// If bit_length is not zero, deinit must eventually be called.
- pub fn initFull(bit_length: usize, allocator: Allocator) !Self {
+ pub fn initFull(allocator: Allocator, bit_length: usize) !Self {
var self = Self{};
- try self.resize(bit_length, true, allocator);
+ try self.resize(allocator, bit_length, true);
return self;
}
/// Resizes to a new bit_length. If the new length is larger
/// than the old length, fills any added bits with `fill`.
/// If new_len is not zero, deinit must eventually be called.
- pub fn resize(self: *@This(), new_len: usize, fill: bool, allocator: Allocator) !void {
+ 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);
@@ -557,14 +757,14 @@ pub const DynamicBitSetUnmanaged = struct {
/// The passed allocator must be the same one used for
/// init* or resize in the past.
pub fn deinit(self: *Self, allocator: Allocator) void {
- self.resize(0, false, allocator) catch unreachable;
+ self.resize(allocator, 0, false) catch unreachable;
}
/// Creates a duplicate of this bit set, using the new allocator.
pub fn clone(self: *const Self, new_allocator: Allocator) !Self {
const num_masks = numMasks(self.bit_length);
var copy = Self{};
- try copy.resize(self.bit_length, false, new_allocator);
+ 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;
}
@@ -608,6 +808,50 @@ pub const DynamicBitSetUnmanaged = struct {
self.masks[maskIndex(index)] |= maskBit(index);
}
+ /// Changes the value of all bits in the specified range to
+ /// match the passed boolean.
+ 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)));
+ }
+ }
+ }
+
/// Removes a specific bit from the bit set
pub fn unset(self: *Self, index: usize) void {
assert(index < self.bit_length);
@@ -685,6 +929,7 @@ pub const DynamicBitSetUnmanaged = struct {
mask.* &= other.masks[i];
}
}
+
pub fn setExcludeTwo(self: *Self, other: Self, third: Self) void {
assert(other.bit_length == self.bit_length);
const num_masks = numMasks(self.bit_length);
@@ -730,6 +975,51 @@ pub const DynamicBitSetUnmanaged = struct {
return offset + index;
}
+ /// Returns true iff every corresponding bit in both
+ /// bit sets are the same.
+ 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;
+ }
+
+ /// Returns true iff the first bit set is the subset
+ /// of the second one.
+ 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;
+ }
+
+ /// Returns true iff the first bit set is the superset
+ /// of the second one.
+ 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;
+ }
+
/// Iterates through the items in the set, according to the options.
/// The default options (.{}) will iterate indices of set bits in
/// ascending order. Modifications to the underlying bit set may
@@ -760,7 +1050,7 @@ pub const DynamicBitSetUnmanaged = struct {
}
};
-/// A bit set with runtime known size, backed by an allocated slice
+/// A bit set with runtime-known size, backed by an allocated slice
/// of usize. Thin wrapper around DynamicBitSetUnmanaged which keeps
/// track of the allocator instance.
pub const DynamicBitSet = struct {
@@ -779,17 +1069,17 @@ pub const DynamicBitSet = struct {
unmanaged: DynamicBitSetUnmanaged = .{},
/// Creates a bit set with no elements present.
- pub fn initEmpty(bit_length: usize, allocator: Allocator) !Self {
+ pub fn initEmpty(allocator: Allocator, bit_length: usize) !Self {
return Self{
- .unmanaged = try DynamicBitSetUnmanaged.initEmpty(bit_length, allocator),
+ .unmanaged = try DynamicBitSetUnmanaged.initEmpty(allocator, bit_length),
.allocator = allocator,
};
}
/// Creates a bit set with all elements present.
- pub fn initFull(bit_length: usize, allocator: Allocator) !Self {
+ pub fn initFull(allocator: Allocator, bit_length: usize) !Self {
return Self{
- .unmanaged = try DynamicBitSetUnmanaged.initFull(bit_length, allocator),
+ .unmanaged = try DynamicBitSetUnmanaged.initFull(allocator, bit_length),
.allocator = allocator,
};
}
@@ -797,7 +1087,7 @@ pub const DynamicBitSet = struct {
/// Resizes to a new length. If the new length is larger
/// than the old length, fills any added bits with `fill`.
pub fn resize(self: *@This(), new_len: usize, fill: bool) !void {
- try self.unmanaged.resize(new_len, fill, self.allocator);
+ try self.unmanaged.resize(self.allocator, new_len, fill);
}
/// deinitializes the array and releases its memory.
@@ -842,6 +1132,12 @@ pub const DynamicBitSet = struct {
self.unmanaged.set(index);
}
+ /// Changes the value of all bits in the specified range to
+ /// match the passed boolean.
+ pub fn setRangeValue(self: *Self, range: Range, value: bool) void {
+ self.unmanaged.setRangeValue(range, value);
+ }
+
/// Removes a specific bit from the bit set
pub fn unset(self: *Self, index: usize) void {
self.unmanaged.unset(index);
@@ -892,6 +1188,12 @@ pub const DynamicBitSet = struct {
return self.unmanaged.toggleFirstSet();
}
+ /// Returns true iff every corresponding bit in both
+ /// bit sets are the same.
+ pub fn eql(self: Self, other: Self) bool {
+ return self.unmanaged.eql(other.unmanaged);
+ }
+
/// Iterates through the items in the set, according to the options.
/// The default options (.{}) will iterate indices of set bits in
/// ascending order. Modifications to the underlying bit set may
@@ -966,7 +1268,7 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ
/// Returns the index of the next unvisited set bit
/// in the bit set, in ascending order.
- pub inline fn next(self: *Self) ?usize {
+ pub fn next(self: *Self) ?usize {
while (self.bits_remain == 0) {
if (self.words_remain.len == 0) return null;
self.nextWord(false);
@@ -1021,13 +1323,77 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ
};
}
+/// A range of indices within a bitset.
+pub const Range = struct {
+ /// The index of the first bit of interest.
+ start: usize,
+ /// The index immediately after the last bit of interest.
+ end: usize,
+};
+
// ---------------- Tests -----------------
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());
+ const needs_ptr = @hasField(std.meta.Child(@TypeOf(a)), "masks") and @typeInfo(@TypeOf(@field(a, "masks"))) != .Pointer;
{
var i: usize = 0;
@@ -1084,7 +1450,12 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void {
}
}
- a.setUnion(b.*);
+ if (comptime needs_ptr) {
+ a.setUnion(b);
+ } else {
+ a.setUnion(b.*);
+ }
+
{
var i: usize = 0;
while (i < len) : (i += 1) {
@@ -1111,7 +1482,11 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void {
try testing.expectEqual(@as(?usize, null), unset.next());
}
- a.toggleSet(b.*);
+ if (comptime needs_ptr) {
+ a.toggleSet(b);
+ } else {
+ a.toggleSet(b.*);
+ }
{
try testing.expectEqual(len / 4, a.count());
@@ -1127,7 +1502,11 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void {
}
}
- a.setIntersection(b.*);
+ if (comptime needs_ptr) {
+ a.setIntersection(b);
+ } else {
+ a.setIntersection(b.*);
+ }
{
try testing.expectEqual((len + 3) / 4, a.count());
@@ -1138,7 +1517,11 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void {
}
}
- a.toggleSet(a.*);
+ if (comptime needs_ptr) {
+ a.toggleSet(a);
+ } else {
+ a.toggleSet(a.*);
+ }
{
var iter = a.iterator(.{});
try testing.expectEqual(@as(?usize, null), iter.next());
@@ -1175,85 +1558,225 @@ fn testBitSet(a: anytype, b: anytype, len: usize) !void {
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 {
+ var empty_ = Set.initEmpty();
+ var full_ = Set.initFull();
+ const needs_ptr = @hasField(Set, "masks") and @typeInfo(@TypeOf(empty_.masks)) != .Pointer;
+
+ var even_ = even: {
+ var bit_set = Set.initEmpty();
+ fillEven(&bit_set, Set.bit_length);
+ break :even bit_set;
+ };
+
+ var odd_ = odd: {
+ var bit_set = Set.initEmpty();
+ fillOdd(&bit_set, Set.bit_length);
+ break :odd bit_set;
+ };
+
+ var empty = if (needs_ptr) &empty_ else empty_;
+ var full = if (needs_ptr) &full_ else full_;
+ var even = if (needs_ptr) &even_ else even_;
+ var odd = if (needs_ptr) &odd_ else odd_;
+
+ 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 {
+fn testStaticBitSet(comptime Set: type, comptime Container: @Type(.EnumLiteral)) !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());
+ if (comptime Container == .ArrayBitSet) {
+ try testEql(&a, &b, Set.bit_length);
+ } else {
+ try testEql(a, b, Set.bit_length);
+ }
+
try testBitSet(&a, &b, Set.bit_length);
+
+ try testPureBitSet(Set);
}
test "IntegerBitSet" {
- 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));
+ try testStaticBitSet(IntegerBitSet(0), .IntegerBitSet);
+ try testStaticBitSet(IntegerBitSet(1), .IntegerBitSet);
+ try testStaticBitSet(IntegerBitSet(2), .IntegerBitSet);
+ try testStaticBitSet(IntegerBitSet(5), .IntegerBitSet);
+ try testStaticBitSet(IntegerBitSet(8), .IntegerBitSet);
+ try testStaticBitSet(IntegerBitSet(32), .IntegerBitSet);
+ try testStaticBitSet(IntegerBitSet(64), .IntegerBitSet);
+ try testStaticBitSet(IntegerBitSet(127), .IntegerBitSet);
}
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));
+ try testStaticBitSet(ArrayBitSet(u8, size), .ArrayBitSet);
+ try testStaticBitSet(ArrayBitSet(u16, size), .ArrayBitSet);
+ try testStaticBitSet(ArrayBitSet(u32, size), .ArrayBitSet);
+ try testStaticBitSet(ArrayBitSet(u64, size), .ArrayBitSet);
+ try testStaticBitSet(ArrayBitSet(u128, size), .ArrayBitSet);
}
}
test "DynamicBitSetUnmanaged" {
const allocator = std.testing.allocator;
- var a = try DynamicBitSetUnmanaged.initEmpty(300, allocator);
+ var a = try DynamicBitSetUnmanaged.initEmpty(allocator, 300);
try testing.expectEqual(@as(usize, 0), a.count());
a.deinit(allocator);
- a = try DynamicBitSetUnmanaged.initEmpty(0, 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 tmp = try a.clone(allocator);
- defer tmp.deinit(allocator);
- try testing.expectEqual(old_len, tmp.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), tmp.isSet(i));
+ try testing.expectEqual(a.isSet(i), empty.isSet(i));
}
a.toggleSet(a); // zero a
- tmp.toggleSet(tmp);
+ empty.toggleSet(empty);
- try a.resize(size, true, allocator);
- try tmp.resize(size, false, allocator);
+ 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), tmp.count());
+ try testing.expectEqual(@as(usize, 0), empty.count());
- var b = try DynamicBitSetUnmanaged.initFull(size, allocator);
- defer b.deinit(allocator);
- try testing.expectEqual(@as(usize, size), b.count());
+ var full = try DynamicBitSetUnmanaged.initFull(allocator, size);
+ defer full.deinit(allocator);
+ try testing.expectEqual(@as(usize, size), full.count());
- try testBitSet(&a, &b, size);
+ 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(300, allocator);
+ var a = try DynamicBitSet.initEmpty(allocator, 300);
try testing.expectEqual(@as(usize, 0), a.count());
a.deinit();
- a = try DynamicBitSet.initEmpty(0, allocator);
+ 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();
@@ -1279,10 +1802,11 @@ test "DynamicBitSet" {
}
try testing.expectEqual(@as(usize, 0), tmp.count());
- var b = try DynamicBitSet.initFull(size, allocator);
+ 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);
}
}
diff --git a/src/js_lexer/identifier_cache.zig b/src/js_lexer/identifier_cache.zig
index 93d5149c3..c03284c4b 100644
--- a/src/js_lexer/identifier_cache.zig
+++ b/src/js_lexer/identifier_cache.zig
@@ -1,4 +1,5 @@
const std = @import("std");
+const bun = @import("bun");
pub const CachedBitset = extern struct {
range: [2]i32,
@@ -19,8 +20,8 @@ pub const id_continue_meta = CachedBitset.fromFile("id_continue_bitset.meta.blob
pub const id_start_masks = @embedFile("id_start_bitset.blob");
pub const id_continue_masks = @embedFile("id_continue_bitset.blob");
-pub const IDStartType = std.bit_set.StaticBitSet(id_start_meta.len);
-pub const IDContinueType = std.bit_set.StaticBitSet(id_continue_meta.len);
+pub const IDStartType = bun.bit_set.ArrayBitSet(usize, id_start_meta.len);
+pub const IDContinueType = bun.bit_set.ArrayBitSet(usize, id_continue_meta.len);
pub const id_start = IDStartType{
.masks = @bitCast(std.meta.fieldInfo(IDStartType, .masks).type, @ptrCast(*const [id_start_masks.len]u8, id_start_masks).*),
};