| ... | ... | @@ -8,50 +8,55 @@ |
| 8 | 8 | //! |
| 9 | 9 | //! There are five variants defined here: |
| 10 | 10 | //! |
| 11 | | //! IntegerBitSet: |
| 11 | //! Integer: |
| 12 | 12 | //! A bit set with static size, which is backed by a single integer. |
| 13 | 13 | //! This set is good for sets with a small size, but may generate |
| 14 | 14 | //! inefficient code for larger sets, especially in debug mode. |
| 15 | 15 | //! |
| 16 | | //! ArrayBitSet: |
| 16 | //! Array: |
| 17 | 17 | //! A bit set with static size, which is backed by an array of usize. |
| 18 | 18 | //! This set is good for sets with a larger size, but may use |
| 19 | 19 | //! more bytes than necessary if your set is small. |
| 20 | 20 | //! |
| 21 | | //! StaticBitSet: |
| 22 | | //! Picks either IntegerBitSet or ArrayBitSet depending on the requested |
| 21 | //! Static: |
| 22 | //! Picks either Integer or Array depending on the requested |
| 23 | 23 | //! size. The interfaces of these two types match exactly, except for fields. |
| 24 | 24 | //! |
| 25 | | //! DynamicBitSet: |
| 25 | //! Dynamic: |
| 26 | 26 | //! A bit set with runtime-known size, backed by an allocated slice |
| 27 | 27 | //! of usize. |
| 28 | 28 | //! |
| 29 | | //! DynamicBitSetUnmanaged: |
| 30 | | //! A variant of DynamicBitSet which does not store a pointer to its |
| 31 | | //! allocator, in order to save space. |
| 29 | //! DynamicManaged: |
| 30 | //! A variant of Dynamic which stores an allocator, using it when needed. |
| 32 | 31 | |
| 33 | 32 | const std = @import("std.zig"); |
| 34 | 33 | const assert = std.debug.assert; |
| 35 | 34 | const Allocator = std.mem.Allocator; |
| 36 | 35 | const builtin = @import("builtin"); |
| 37 | 36 | |
| 37 | /// Deprecated: use `Static`. |
| 38 | pub const StaticBitSet = Static; |
| 39 | |
| 38 | 40 | /// Returns the optimal static bit set type for the specified number |
| 39 | 41 | /// of elements: either `IntegerBitSet` or `ArrayBitSet`, |
| 40 | 42 | /// both of which fulfill the same interface. |
| 41 | 43 | /// The returned type will perform no allocations, |
| 42 | 44 | /// can be copied by value, and does not require deinitialization. |
| 43 | | pub fn StaticBitSet(comptime size: usize) type { |
| 45 | pub fn Static(comptime size: usize) type { |
| 44 | 46 | if (size <= @bitSizeOf(usize)) { |
| 45 | | return IntegerBitSet(size); |
| 47 | return Integer(size); |
| 46 | 48 | } else { |
| 47 | | return ArrayBitSet(usize, size); |
| 49 | return Array(usize, size); |
| 48 | 50 | } |
| 49 | 51 | } |
| 50 | 52 | |
| 53 | /// Deprecated: use `Integer`. |
| 54 | pub const IntegerBitSet = Integer; |
| 55 | |
| 51 | 56 | /// A bit set with static size, which is backed by a single integer. |
| 52 | 57 | /// This set is good for sets with a small size, but may generate |
| 53 | 58 | /// inefficient code for larger sets, especially in debug mode. |
| 54 | | pub fn IntegerBitSet(comptime size: u16) type { |
| 59 | pub fn Integer(comptime size: u16) type { |
| 55 | 60 | return packed struct(MaskInt) { |
| 56 | 61 | const Self = @This(); |
| 57 | 62 | |
| ... | ... | @@ -328,21 +333,24 @@ pub fn IntegerBitSet(comptime size: u16) type { |
| 328 | 333 | }; |
| 329 | 334 | } |
| 330 | 335 | |
| 336 | /// Deprecated: use `Array`. |
| 337 | pub const ArrayBitSet = Array; |
| 338 | |
| 331 | 339 | /// A bit set with static size, which is backed by an array of usize. |
| 332 | 340 | /// This set is good for sets with a larger size, but may use |
| 333 | 341 | /// more bytes than necessary if your set is small. |
| 334 | | pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { |
| 342 | pub fn Array(comptime MaskIntType: type, comptime size: usize) type { |
| 335 | 343 | const mask_info: std.builtin.Type = @typeInfo(MaskIntType); |
| 336 | 344 | |
| 337 | 345 | // Make sure the mask int is indeed an int |
| 338 | | if (mask_info != .int) @compileError("ArrayBitSet can only operate on integer masks, but was passed " ++ @typeName(MaskIntType)); |
| 346 | if (mask_info != .int) @compileError("Array can only operate on integer masks, but was passed " ++ @typeName(MaskIntType)); |
| 339 | 347 | |
| 340 | 348 | // It must also be unsigned. |
| 341 | | if (mask_info.int.signedness != .unsigned) @compileError("ArrayBitSet requires an unsigned integer mask type, but was passed " ++ @typeName(MaskIntType)); |
| 349 | if (mask_info.int.signedness != .unsigned) @compileError("Array requires an unsigned integer mask type, but was passed " ++ @typeName(MaskIntType)); |
| 342 | 350 | |
| 343 | 351 | // And it must not be empty. |
| 344 | 352 | if (MaskIntType == u0) |
| 345 | | @compileError("ArrayBitSet requires a sized integer for its mask int. u0 does not work."); |
| 353 | @compileError("Array requires a sized integer for its mask int. u0 does not work."); |
| 346 | 354 | |
| 347 | 355 | const byte_size = std.mem.byte_size_in_bits; |
| 348 | 356 | |
| ... | ... | @@ -352,7 +360,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { |
| 352 | 360 | var desired_bits = std.math.ceilPowerOfTwoAssert(usize, @bitSizeOf(MaskIntType)); |
| 353 | 361 | if (desired_bits < byte_size) desired_bits = byte_size; |
| 354 | 362 | const FixedMaskType = std.meta.Int(.unsigned, desired_bits); |
| 355 | | @compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++ |
| 363 | @compileError("Array was passed integer type " ++ @typeName(MaskIntType) ++ |
| 356 | 364 | ", which is not a power of two. Please round this up to a power of two integer size (i.e. " ++ @typeName(FixedMaskType) ++ ")."); |
| 357 | 365 | } |
| 358 | 366 | |
| ... | ... | @@ -363,7 +371,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { |
| 363 | 371 | var desired_bits = @sizeOf(MaskIntType) * byte_size; |
| 364 | 372 | desired_bits = std.math.ceilPowerOfTwoAssert(usize, desired_bits); |
| 365 | 373 | const FixedMaskType = std.meta.Int(.unsigned, desired_bits); |
| 366 | | @compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++ |
| 374 | @compileError("Array was passed integer type " ++ @typeName(MaskIntType) ++ |
| 367 | 375 | ", which contains padding bits. Please round this up to an unpadded integer size (i.e. " ++ @typeName(FixedMaskType) ++ ")."); |
| 368 | 376 | } |
| 369 | 377 | |
| ... | ... | @@ -673,7 +681,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { |
| 673 | 681 | } |
| 674 | 682 | |
| 675 | 683 | pub fn Iterator(comptime options: IteratorOptions) type { |
| 676 | | return BitSetIterator(MaskInt, options); |
| 684 | return GenericIterator(MaskInt, options); |
| 677 | 685 | } |
| 678 | 686 | |
| 679 | 687 | fn maskBit(index: usize) MaskInt { |
| ... | ... | @@ -688,9 +696,12 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { |
| 688 | 696 | }; |
| 689 | 697 | } |
| 690 | 698 | |
| 699 | /// Deprecated: use `Dynamic`. |
| 700 | pub const DynamicBitSetUnmanaged = Dynamic; |
| 701 | |
| 691 | 702 | /// A bit set with runtime-known size, backed by an allocated slice |
| 692 | 703 | /// of usize. The allocator must be tracked externally by the user. |
| 693 | | pub const DynamicBitSetUnmanaged = struct { |
| 704 | pub const Dynamic = struct { |
| 694 | 705 | const Self = @This(); |
| 695 | 706 | |
| 696 | 707 | /// The integer type used to represent a mask in this bit set |
| ... | ... | @@ -1074,7 +1085,7 @@ pub const DynamicBitSetUnmanaged = struct { |
| 1074 | 1085 | } |
| 1075 | 1086 | |
| 1076 | 1087 | pub fn Iterator(comptime options: IteratorOptions) type { |
| 1077 | | return BitSetIterator(MaskInt, options); |
| 1088 | return GenericIterator(MaskInt, options); |
| 1078 | 1089 | } |
| 1079 | 1090 | |
| 1080 | 1091 | fn maskBit(index: usize) MaskInt { |
| ... | ... | @@ -1091,10 +1102,16 @@ pub const DynamicBitSetUnmanaged = struct { |
| 1091 | 1102 | } |
| 1092 | 1103 | }; |
| 1093 | 1104 | |
| 1105 | /// Deprecated: use `DynamicManaged` or `Dynamic` (will need to update callsites). |
| 1106 | pub const DynamicBitSet = DynamicManaged; |
| 1107 | |
| 1094 | 1108 | /// A bit set with runtime-known size, backed by an allocated slice |
| 1095 | | /// of usize. Thin wrapper around DynamicBitSetUnmanaged which keeps |
| 1109 | /// of usize. Thin wrapper around Dynamic which keeps |
| 1096 | 1110 | /// track of the allocator instance. |
| 1097 | | pub const DynamicBitSet = struct { |
| 1111 | /// |
| 1112 | /// Deprecated in favor of `Dynamic` which accepts an `Allocator` |
| 1113 | /// as a parameter when needed instead of storing it. |
| 1114 | pub const DynamicManaged = struct { |
| 1098 | 1115 | const Self = @This(); |
| 1099 | 1116 | |
| 1100 | 1117 | /// The integer type used to represent a mask in this bit set |
| ... | ... | @@ -1104,12 +1121,12 @@ pub const DynamicBitSet = struct { |
| 1104 | 1121 | pub const ShiftInt = std.math.Log2Int(MaskInt); |
| 1105 | 1122 | |
| 1106 | 1123 | allocator: Allocator, |
| 1107 | | unmanaged: DynamicBitSetUnmanaged = .{}, |
| 1124 | unmanaged: Dynamic = .{}, |
| 1108 | 1125 | |
| 1109 | 1126 | /// Creates a bit set with no elements present. |
| 1110 | 1127 | pub fn initEmpty(allocator: Allocator, bit_length: usize) !Self { |
| 1111 | 1128 | return Self{ |
| 1112 | | .unmanaged = try DynamicBitSetUnmanaged.initEmpty(allocator, bit_length), |
| 1129 | .unmanaged = try .initEmpty(allocator, bit_length), |
| 1113 | 1130 | .allocator = allocator, |
| 1114 | 1131 | }; |
| 1115 | 1132 | } |
| ... | ... | @@ -1117,7 +1134,7 @@ pub const DynamicBitSet = struct { |
| 1117 | 1134 | /// Creates a bit set with all elements present. |
| 1118 | 1135 | pub fn initFull(allocator: Allocator, bit_length: usize) !Self { |
| 1119 | 1136 | return Self{ |
| 1120 | | .unmanaged = try DynamicBitSetUnmanaged.initFull(allocator, bit_length), |
| 1137 | .unmanaged = try .initFull(allocator, bit_length), |
| 1121 | 1138 | .allocator = allocator, |
| 1122 | 1139 | }; |
| 1123 | 1140 | } |
| ... | ... | @@ -1247,7 +1264,7 @@ pub const DynamicBitSet = struct { |
| 1247 | 1264 | return self.unmanaged.iterator(options); |
| 1248 | 1265 | } |
| 1249 | 1266 | |
| 1250 | | pub const Iterator = DynamicBitSetUnmanaged.Iterator; |
| 1267 | pub const Iterator = Dynamic.Iterator; |
| 1251 | 1268 | }; |
| 1252 | 1269 | |
| 1253 | 1270 | /// Options for configuring an iterator over a bit set |
| ... | ... | @@ -1274,7 +1291,7 @@ pub const IteratorOptions = struct { |
| 1274 | 1291 | }; |
| 1275 | 1292 | |
| 1276 | 1293 | // The iterator is reusable between several bit set types |
| 1277 | | fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) type { |
| 1294 | fn GenericIterator(comptime MaskInt: type, comptime options: IteratorOptions) type { |
| 1278 | 1295 | const ShiftInt = std.math.Log2Int(MaskInt); |
| 1279 | 1296 | const kind = options.kind; |
| 1280 | 1297 | const direction = options.direction; |
| ... | ... | @@ -1713,37 +1730,37 @@ fn testStaticBitSet(comptime Set: type) !void { |
| 1713 | 1730 | try testPureBitSet(Set); |
| 1714 | 1731 | } |
| 1715 | 1732 | |
| 1716 | | test IntegerBitSet { |
| 1733 | test Integer { |
| 1717 | 1734 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1718 | 1735 | if (comptime builtin.cpu.has(.riscv, .v) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/24300 |
| 1719 | 1736 | |
| 1720 | | try testStaticBitSet(IntegerBitSet(0)); |
| 1721 | | try testStaticBitSet(IntegerBitSet(1)); |
| 1722 | | try testStaticBitSet(IntegerBitSet(2)); |
| 1723 | | try testStaticBitSet(IntegerBitSet(5)); |
| 1724 | | try testStaticBitSet(IntegerBitSet(8)); |
| 1725 | | try testStaticBitSet(IntegerBitSet(32)); |
| 1726 | | try testStaticBitSet(IntegerBitSet(64)); |
| 1727 | | try testStaticBitSet(IntegerBitSet(127)); |
| 1737 | try testStaticBitSet(Integer(0)); |
| 1738 | try testStaticBitSet(Integer(1)); |
| 1739 | try testStaticBitSet(Integer(2)); |
| 1740 | try testStaticBitSet(Integer(5)); |
| 1741 | try testStaticBitSet(Integer(8)); |
| 1742 | try testStaticBitSet(Integer(32)); |
| 1743 | try testStaticBitSet(Integer(64)); |
| 1744 | try testStaticBitSet(Integer(127)); |
| 1728 | 1745 | } |
| 1729 | 1746 | |
| 1730 | | test ArrayBitSet { |
| 1747 | test Array { |
| 1731 | 1748 | inline for (.{ 0, 1, 2, 31, 32, 33, 63, 64, 65, 254, 500, 3000 }) |size| { |
| 1732 | | try testStaticBitSet(ArrayBitSet(u8, size)); |
| 1733 | | try testStaticBitSet(ArrayBitSet(u16, size)); |
| 1734 | | try testStaticBitSet(ArrayBitSet(u32, size)); |
| 1735 | | try testStaticBitSet(ArrayBitSet(u64, size)); |
| 1736 | | try testStaticBitSet(ArrayBitSet(u128, size)); |
| 1749 | try testStaticBitSet(Array(u8, size)); |
| 1750 | try testStaticBitSet(Array(u16, size)); |
| 1751 | try testStaticBitSet(Array(u32, size)); |
| 1752 | try testStaticBitSet(Array(u64, size)); |
| 1753 | try testStaticBitSet(Array(u128, size)); |
| 1737 | 1754 | } |
| 1738 | 1755 | } |
| 1739 | 1756 | |
| 1740 | | test DynamicBitSetUnmanaged { |
| 1757 | test Dynamic { |
| 1741 | 1758 | const allocator = std.testing.allocator; |
| 1742 | | var a = try DynamicBitSetUnmanaged.initEmpty(allocator, 300); |
| 1759 | var a: Dynamic = try .initEmpty(allocator, 300); |
| 1743 | 1760 | try testing.expectEqual(@as(usize, 0), a.count()); |
| 1744 | 1761 | a.deinit(allocator); |
| 1745 | 1762 | |
| 1746 | | a = try DynamicBitSetUnmanaged.initEmpty(allocator, 0); |
| 1763 | a = try .initEmpty(allocator, 0); |
| 1747 | 1764 | defer a.deinit(allocator); |
| 1748 | 1765 | for ([_]usize{ 1, 2, 31, 32, 33, 0, 65, 64, 63, 500, 254, 3000 }) |size| { |
| 1749 | 1766 | const old_len = a.capacity(); |
| ... | ... | @@ -1769,17 +1786,17 @@ test DynamicBitSetUnmanaged { |
| 1769 | 1786 | } |
| 1770 | 1787 | try testing.expectEqual(@as(usize, 0), empty.count()); |
| 1771 | 1788 | |
| 1772 | | var full = try DynamicBitSetUnmanaged.initFull(allocator, size); |
| 1789 | var full: Dynamic = try .initFull(allocator, size); |
| 1773 | 1790 | defer full.deinit(allocator); |
| 1774 | 1791 | try testing.expectEqual(@as(usize, size), full.count()); |
| 1775 | 1792 | |
| 1776 | 1793 | try testEql(empty, full, size); |
| 1777 | 1794 | { |
| 1778 | | var even = try DynamicBitSetUnmanaged.initEmpty(allocator, size); |
| 1795 | var even: Dynamic = try .initEmpty(allocator, size); |
| 1779 | 1796 | defer even.deinit(allocator); |
| 1780 | 1797 | fillEven(&even, size); |
| 1781 | 1798 | |
| 1782 | | var odd = try DynamicBitSetUnmanaged.initEmpty(allocator, size); |
| 1799 | var odd: Dynamic = try .initEmpty(allocator, size); |
| 1783 | 1800 | defer odd.deinit(allocator); |
| 1784 | 1801 | fillOdd(&odd, size); |
| 1785 | 1802 | |
| ... | ... | @@ -1790,13 +1807,13 @@ test DynamicBitSetUnmanaged { |
| 1790 | 1807 | } |
| 1791 | 1808 | } |
| 1792 | 1809 | |
| 1793 | | test DynamicBitSet { |
| 1810 | test DynamicManaged { |
| 1794 | 1811 | const allocator = std.testing.allocator; |
| 1795 | | var a = try DynamicBitSet.initEmpty(allocator, 300); |
| 1812 | var a: DynamicManaged = try .initEmpty(allocator, 300); |
| 1796 | 1813 | try testing.expectEqual(@as(usize, 0), a.count()); |
| 1797 | 1814 | a.deinit(); |
| 1798 | 1815 | |
| 1799 | | a = try DynamicBitSet.initEmpty(allocator, 0); |
| 1816 | a = try .initEmpty(allocator, 0); |
| 1800 | 1817 | defer a.deinit(); |
| 1801 | 1818 | for ([_]usize{ 1, 2, 31, 32, 33, 0, 65, 64, 63, 500, 254, 3000 }) |size| { |
| 1802 | 1819 | const old_len = a.capacity(); |
| ... | ... | @@ -1822,7 +1839,7 @@ test DynamicBitSet { |
| 1822 | 1839 | } |
| 1823 | 1840 | try testing.expectEqual(@as(usize, 0), tmp.count()); |
| 1824 | 1841 | |
| 1825 | | var b = try DynamicBitSet.initFull(allocator, size); |
| 1842 | var b: DynamicManaged = try .initFull(allocator, size); |
| 1826 | 1843 | defer b.deinit(); |
| 1827 | 1844 | try testing.expectEqual(@as(usize, size), b.count()); |
| 1828 | 1845 | |
| ... | ... | @@ -1831,10 +1848,10 @@ test DynamicBitSet { |
| 1831 | 1848 | } |
| 1832 | 1849 | } |
| 1833 | 1850 | |
| 1834 | | test StaticBitSet { |
| 1835 | | try testing.expectEqual(IntegerBitSet(0), StaticBitSet(0)); |
| 1836 | | try testing.expectEqual(IntegerBitSet(5), StaticBitSet(5)); |
| 1837 | | try testing.expectEqual(IntegerBitSet(@bitSizeOf(usize)), StaticBitSet(@bitSizeOf(usize))); |
| 1838 | | try testing.expectEqual(ArrayBitSet(usize, @bitSizeOf(usize) + 1), StaticBitSet(@bitSizeOf(usize) + 1)); |
| 1839 | | try testing.expectEqual(ArrayBitSet(usize, 500), StaticBitSet(500)); |
| 1851 | test Static { |
| 1852 | try testing.expectEqual(Integer(0), Static(0)); |
| 1853 | try testing.expectEqual(Integer(5), Static(5)); |
| 1854 | try testing.expectEqual(Integer(@bitSizeOf(usize)), Static(@bitSizeOf(usize))); |
| 1855 | try testing.expectEqual(Array(usize, @bitSizeOf(usize) + 1), Static(@bitSizeOf(usize) + 1)); |
| 1856 | try testing.expectEqual(Array(usize, 500), Static(500)); |
| 1840 | 1857 | } |