Add some enum utilities

This commit is contained in:
Martin Wickham 2021-03-06 18:25:04 -06:00 committed by Andrew Kelley
parent 5e5b35f107
commit 96ae451bbe
4 changed files with 1384 additions and 7 deletions

View File

@ -176,7 +176,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
/// The default options (.{}) will iterate indices of set bits in
/// ascending order. Modifications to the underlying bit set may
/// or may not be observed by the iterator.
pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options.direction) {
pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) {
return .{
.bits_remain = switch (options.kind) {
.set => self.mask,
@ -185,7 +185,11 @@ pub fn IntegerBitSet(comptime size: u16) type {
};
}
fn Iterator(comptime direction: IteratorOptions.Direction) type {
pub fn Iterator(comptime options: IteratorOptions) type {
return SingleWordIterator(options.direction);
}
fn SingleWordIterator(comptime direction: IteratorOptions.Direction) type {
return struct {
const IterSelf = @This();
// all bits which have not yet been iterated over
@ -425,8 +429,12 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
/// The default options (.{}) will iterate indices of set bits in
/// ascending order. Modifications to the underlying bit set may
/// or may not be observed by the iterator.
pub fn iterator(self: *const Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
return BitSetIterator(MaskInt, options).init(&self.masks, last_item_mask);
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 {
@ -700,11 +708,15 @@ pub const DynamicBitSetUnmanaged = struct {
/// ascending order. Modifications to the underlying bit set may
/// or may not be observed by the iterator. Resizing the underlying
/// bit set invalidates the iterator.
pub fn iterator(self: *const Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
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 BitSetIterator(MaskInt, options).init(self.masks[0..num_masks], last_item_mask);
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 {
@ -858,9 +870,11 @@ pub const DynamicBitSet = struct {
/// ascending order. Modifications to the underlying bit set may
/// or may not be observed by the iterator. Resizing the underlying
/// bit set invalidates the iterator.
pub fn iterator(self: *Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
pub fn iterator(self: *Self, comptime options: IteratorOptions) Iterator(options) {
return self.unmanaged.iterator(options);
}
pub const Iterator = DynamicBitSetUnmanaged.Iterator;
};
/// Options for configuring an iterator over a bit set

1281
lib/std/enums.zig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -408,6 +408,84 @@ test "std.meta.trait.isTuple" {
testing.expect(isTuple(@TypeOf(t3)));
}
/// Returns true if the passed type will coerce to []const u8.
/// Any of the following are considered strings:
/// ```
/// []const u8, [:S]const u8, *const [N]u8, *const [N:S]u8,
/// []u8, [:S]u8, *[:S]u8, *[N:S]u8.
/// ```
/// These types are not considered strings:
/// ```
/// u8, [N]u8, [*]const u8, [*:0]const u8,
/// [*]const [N]u8, []const u16, []const i8,
/// *const u8, ?[]const u8, ?*const [N]u8.
/// ```
pub fn isZigString(comptime T: type) bool {
comptime {
// Only pointer types can be strings, no optionals
const info = @typeInfo(T);
if (info != .Pointer) return false;
const ptr = &info.Pointer;
// Check for CV qualifiers that would prevent coerction to []const u8
if (ptr.is_volatile or ptr.is_allowzero) return false;
// If it's already a slice, simple check.
if (ptr.size == .Slice) {
return ptr.child == u8;
}
// Otherwise check if it's an array type that coerces to slice.
if (ptr.size == .One) {
const child = @typeInfo(ptr.child);
if (child == .Array) {
const arr = &child.Array;
return arr.child == u8;
}
}
return false;
}
}
test "std.meta.trait.isZigString" {
testing.expect(isZigString([]const u8));
testing.expect(isZigString([]u8));
testing.expect(isZigString([:0]const u8));
testing.expect(isZigString([:0]u8));
testing.expect(isZigString([:5]const u8));
testing.expect(isZigString([:5]u8));
testing.expect(isZigString(*const [0]u8));
testing.expect(isZigString(*[0]u8));
testing.expect(isZigString(*const [0:0]u8));
testing.expect(isZigString(*[0:0]u8));
testing.expect(isZigString(*const [0:5]u8));
testing.expect(isZigString(*[0:5]u8));
testing.expect(isZigString(*const [10]u8));
testing.expect(isZigString(*[10]u8));
testing.expect(isZigString(*const [10:0]u8));
testing.expect(isZigString(*[10:0]u8));
testing.expect(isZigString(*const [10:5]u8));
testing.expect(isZigString(*[10:5]u8));
testing.expect(!isZigString(u8));
testing.expect(!isZigString([4]u8));
testing.expect(!isZigString([4:0]u8));
testing.expect(!isZigString([*]const u8));
testing.expect(!isZigString([*]const [4]u8));
testing.expect(!isZigString([*c]const u8));
testing.expect(!isZigString([*c]const [4]u8));
testing.expect(!isZigString([*:0]const u8));
testing.expect(!isZigString([*:0]const u8));
testing.expect(!isZigString(*[]const u8));
testing.expect(!isZigString(?[]const u8));
testing.expect(!isZigString(?*const [4]u8));
testing.expect(!isZigString([]allowzero u8));
testing.expect(!isZigString([]volatile u8));
testing.expect(!isZigString(*allowzero [4]u8));
testing.expect(!isZigString(*volatile [4]u8));
}
pub fn hasDecls(comptime T: type, comptime names: anytype) bool {
inline for (names) |name| {
if (!@hasDecl(T, name))

View File

@ -20,6 +20,9 @@ pub const ComptimeStringMap = @import("comptime_string_map.zig").ComptimeStringM
pub const DynLib = @import("dynamic_library.zig").DynLib;
pub const DynamicBitSet = bit_set.DynamicBitSet;
pub const DynamicBitSetUnmanaged = bit_set.DynamicBitSetUnmanaged;
pub const EnumArray = enums.EnumArray;
pub const EnumMap = enums.EnumMap;
pub const EnumSet = enums.EnumSet;
pub const HashMap = hash_map.HashMap;
pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;
pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;
@ -54,6 +57,7 @@ pub const cstr = @import("cstr.zig");
pub const debug = @import("debug.zig");
pub const dwarf = @import("dwarf.zig");
pub const elf = @import("elf.zig");
pub const enums = @import("enums.zig");
pub const event = @import("event.zig");
pub const fifo = @import("fifo.zig");
pub const fmt = @import("fmt.zig");