diff --git a/lib/std/enums.zig b/lib/std/enums.zig index 45eafdb9a9..de8f4e04ed 100644 --- a/lib/std/enums.zig +++ b/lib/std/enums.zig @@ -18,7 +18,7 @@ const EnumField = std.builtin.TypeInfo.EnumField; pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type { const StructField = std.builtin.TypeInfo.StructField; var fields: []const StructField = &[_]StructField{}; - for (uniqueFields(E)) |field, i| { + for (std.meta.fields(E)) |field, i| { fields = fields ++ &[_]StructField{.{ .name = field.name, .field_type = Data, @@ -48,72 +48,12 @@ pub fn valuesFromFields(comptime E: type, comptime fields: []const EnumField) [] } } -test "std.enums.valuesFromFields" { - const E = extern enum { a, b, c, d = 0 }; - const fields = valuesFromFields(E, &[_]EnumField{ - .{ .name = "b", .value = undefined }, - .{ .name = "a", .value = undefined }, - .{ .name = "a", .value = undefined }, - .{ .name = "d", .value = undefined }, - }); - testing.expectEqual(E.b, fields[0]); - testing.expectEqual(E.a, fields[1]); - testing.expectEqual(E.d, fields[2]); // a == d - testing.expectEqual(E.d, fields[3]); -} - /// Returns the set of all named values in the given enum, in /// declaration order. pub fn values(comptime E: type) []const E { return comptime valuesFromFields(E, @typeInfo(E).Enum.fields); } -test "std.enum.values" { - const E = extern enum { a, b, c, d = 0 }; - testing.expectEqualSlices(E, &.{ .a, .b, .c, .d }, values(E)); -} - -/// Returns the set of all unique named values in the given enum, in -/// declaration order. For repeated values in extern enums, only the -/// first name for each value is included. -pub fn uniqueValues(comptime E: type) []const E { - return comptime valuesFromFields(E, uniqueFields(E)); -} - -test "std.enum.uniqueValues" { - const E = extern enum { a, b, c, d = 0, e, f = 3 }; - testing.expectEqualSlices(E, &.{ .a, .b, .c, .f }, uniqueValues(E)); - - const F = enum { a, b, c }; - testing.expectEqualSlices(F, &.{ .a, .b, .c }, uniqueValues(F)); -} - -/// Returns the set of all unique field values in the given enum, in -/// declaration order. For repeated values in extern enums, only the -/// first name for each value is included. -pub fn uniqueFields(comptime E: type) []const EnumField { - comptime { - const info = @typeInfo(E).Enum; - const raw_fields = info.fields; - // Only extern enums can contain duplicates, - // so fast path other types. - if (info.layout != .Extern) { - return raw_fields; - } - - var unique_fields: []const EnumField = &[_]EnumField{}; - outer: for (raw_fields) |candidate| { - for (unique_fields) |u| { - if (u.value == candidate.value) - continue :outer; - } - unique_fields = unique_fields ++ &[_]EnumField{candidate}; - } - - return unique_fields; - } -} - /// Determines the length of a direct-mapped enum array, indexed by /// @intCast(usize, @enumToInt(enum_value)). /// If the enum is non-exhaustive, the resulting length will only be enough @@ -126,7 +66,7 @@ pub fn uniqueFields(comptime E: type) []const EnumField { fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int { var max_value: comptime_int = -1; const max_usize: comptime_int = ~@as(usize, 0); - const fields = uniqueFields(E); + const fields = std.meta.fields(E); for (fields) |f| { if (f.value < 0) { @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " has a negative value."); @@ -248,8 +188,8 @@ pub fn nameCast(comptime E: type, comptime value: anytype) E { } test "std.enums.nameCast" { - const A = enum { a = 0, b = 1 }; - const B = enum { a = 1, b = 0 }; + const A = enum(u1) { a = 0, b = 1 }; + const B = enum(u1) { a = 1, b = 0 }; testing.expectEqual(A.a, nameCast(A, .a)); testing.expectEqual(A.a, nameCast(A, A.a)); testing.expectEqual(A.a, nameCast(A, B.a)); @@ -796,7 +736,7 @@ pub fn EnumIndexer(comptime E: type) type { @compileError("Cannot create an enum indexer for a non-exhaustive enum."); } - const const_fields = uniqueFields(E); + const const_fields = std.meta.fields(E); var fields = const_fields[0..const_fields.len].*; if (fields.len == 0) { return struct { @@ -848,7 +788,7 @@ pub fn EnumIndexer(comptime E: type) type { } test "std.enums.EnumIndexer dense zeroed" { - const E = enum { b = 1, a = 0, c = 2 }; + const E = enum(u2) { b = 1, a = 0, c = 2 }; const Indexer = EnumIndexer(E); ensureIndexer(Indexer); testing.expectEqual(E, Indexer.Key); @@ -910,379 +850,3 @@ test "std.enums.EnumIndexer sparse" { testing.expectEqual(E.b, Indexer.keyForIndex(1)); testing.expectEqual(E.c, Indexer.keyForIndex(2)); } - -test "std.enums.EnumIndexer repeats" { - const E = extern enum { a = -2, c = 6, b = 4, b2 = 4 }; - const Indexer = EnumIndexer(E); - ensureIndexer(Indexer); - testing.expectEqual(E, Indexer.Key); - testing.expectEqual(@as(usize, 3), Indexer.count); - - testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); - testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); - testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); - - testing.expectEqual(E.a, Indexer.keyForIndex(0)); - testing.expectEqual(E.b, Indexer.keyForIndex(1)); - testing.expectEqual(E.c, Indexer.keyForIndex(2)); -} - -test "std.enums.EnumSet" { - const E = extern enum { a, b, c, d, e = 0 }; - const Set = EnumSet(E); - testing.expectEqual(E, Set.Key); - testing.expectEqual(EnumIndexer(E), Set.Indexer); - testing.expectEqual(@as(usize, 4), Set.len); - - // Empty sets - const empty = Set{}; - comptime testing.expect(empty.count() == 0); - - var empty_b = Set.init(.{}); - testing.expect(empty_b.count() == 0); - - const empty_c = comptime Set.init(.{}); - comptime testing.expect(empty_c.count() == 0); - - const full = Set.initFull(); - testing.expect(full.count() == Set.len); - - const full_b = comptime Set.initFull(); - comptime testing.expect(full_b.count() == Set.len); - - testing.expectEqual(false, empty.contains(.a)); - testing.expectEqual(false, empty.contains(.b)); - testing.expectEqual(false, empty.contains(.c)); - testing.expectEqual(false, empty.contains(.d)); - testing.expectEqual(false, empty.contains(.e)); - { - var iter = empty_b.iterator(); - testing.expectEqual(@as(?E, null), iter.next()); - } - - var mut = Set.init(.{ - .a = true, - .c = true, - }); - testing.expectEqual(@as(usize, 2), mut.count()); - testing.expectEqual(true, mut.contains(.a)); - testing.expectEqual(false, mut.contains(.b)); - testing.expectEqual(true, mut.contains(.c)); - testing.expectEqual(false, mut.contains(.d)); - testing.expectEqual(true, mut.contains(.e)); // aliases a - { - var it = mut.iterator(); - testing.expectEqual(@as(?E, .a), it.next()); - testing.expectEqual(@as(?E, .c), it.next()); - testing.expectEqual(@as(?E, null), it.next()); - } - - mut.toggleAll(); - testing.expectEqual(@as(usize, 2), mut.count()); - testing.expectEqual(false, mut.contains(.a)); - testing.expectEqual(true, mut.contains(.b)); - testing.expectEqual(false, mut.contains(.c)); - testing.expectEqual(true, mut.contains(.d)); - testing.expectEqual(false, mut.contains(.e)); // aliases a - { - var it = mut.iterator(); - testing.expectEqual(@as(?E, .b), it.next()); - testing.expectEqual(@as(?E, .d), it.next()); - testing.expectEqual(@as(?E, null), it.next()); - } - - mut.toggleSet(Set.init(.{ .a = true, .b = true })); - testing.expectEqual(@as(usize, 2), mut.count()); - testing.expectEqual(true, mut.contains(.a)); - testing.expectEqual(false, mut.contains(.b)); - testing.expectEqual(false, mut.contains(.c)); - testing.expectEqual(true, mut.contains(.d)); - testing.expectEqual(true, mut.contains(.e)); // aliases a - - mut.setUnion(Set.init(.{ .a = true, .b = true })); - testing.expectEqual(@as(usize, 3), mut.count()); - testing.expectEqual(true, mut.contains(.a)); - testing.expectEqual(true, mut.contains(.b)); - testing.expectEqual(false, mut.contains(.c)); - testing.expectEqual(true, mut.contains(.d)); - - mut.remove(.c); - mut.remove(.b); - testing.expectEqual(@as(usize, 2), mut.count()); - testing.expectEqual(true, mut.contains(.a)); - testing.expectEqual(false, mut.contains(.b)); - testing.expectEqual(false, mut.contains(.c)); - testing.expectEqual(true, mut.contains(.d)); - - mut.setIntersection(Set.init(.{ .a = true, .b = true })); - testing.expectEqual(@as(usize, 1), mut.count()); - testing.expectEqual(true, mut.contains(.a)); - testing.expectEqual(false, mut.contains(.b)); - testing.expectEqual(false, mut.contains(.c)); - testing.expectEqual(false, mut.contains(.d)); - - mut.insert(.a); - mut.insert(.b); - testing.expectEqual(@as(usize, 2), mut.count()); - testing.expectEqual(true, mut.contains(.a)); - testing.expectEqual(true, mut.contains(.b)); - testing.expectEqual(false, mut.contains(.c)); - testing.expectEqual(false, mut.contains(.d)); - - mut.setPresent(.a, false); - mut.toggle(.b); - mut.toggle(.c); - mut.setPresent(.d, true); - testing.expectEqual(@as(usize, 2), mut.count()); - testing.expectEqual(false, mut.contains(.a)); - testing.expectEqual(false, mut.contains(.b)); - testing.expectEqual(true, mut.contains(.c)); - testing.expectEqual(true, mut.contains(.d)); -} - -test "std.enums.EnumArray void" { - const E = extern enum { a, b, c, d, e = 0 }; - const ArrayVoid = EnumArray(E, void); - testing.expectEqual(E, ArrayVoid.Key); - testing.expectEqual(EnumIndexer(E), ArrayVoid.Indexer); - testing.expectEqual(void, ArrayVoid.Value); - testing.expectEqual(@as(usize, 4), ArrayVoid.len); - - const undef = ArrayVoid.initUndefined(); - var inst = ArrayVoid.initFill({}); - const inst2 = ArrayVoid.init(.{ .a = {}, .b = {}, .c = {}, .d = {} }); - const inst3 = ArrayVoid.initDefault({}, .{}); - - _ = inst.get(.a); - _ = inst.getPtr(.b); - _ = inst.getPtrConst(.c); - inst.set(.a, {}); - - var it = inst.iterator(); - testing.expectEqual(E.a, it.next().?.key); - testing.expectEqual(E.b, it.next().?.key); - testing.expectEqual(E.c, it.next().?.key); - testing.expectEqual(E.d, it.next().?.key); - testing.expect(it.next() == null); -} - -test "std.enums.EnumArray sized" { - const E = extern enum { a, b, c, d, e = 0 }; - const Array = EnumArray(E, usize); - testing.expectEqual(E, Array.Key); - testing.expectEqual(EnumIndexer(E), Array.Indexer); - testing.expectEqual(usize, Array.Value); - testing.expectEqual(@as(usize, 4), Array.len); - - const undef = Array.initUndefined(); - var inst = Array.initFill(5); - const inst2 = Array.init(.{ .a = 1, .b = 2, .c = 3, .d = 4 }); - const inst3 = Array.initDefault(6, .{ .b = 4, .c = 2 }); - - testing.expectEqual(@as(usize, 5), inst.get(.a)); - testing.expectEqual(@as(usize, 5), inst.get(.b)); - testing.expectEqual(@as(usize, 5), inst.get(.c)); - testing.expectEqual(@as(usize, 5), inst.get(.d)); - - testing.expectEqual(@as(usize, 1), inst2.get(.a)); - testing.expectEqual(@as(usize, 2), inst2.get(.b)); - testing.expectEqual(@as(usize, 3), inst2.get(.c)); - testing.expectEqual(@as(usize, 4), inst2.get(.d)); - - testing.expectEqual(@as(usize, 6), inst3.get(.a)); - testing.expectEqual(@as(usize, 4), inst3.get(.b)); - testing.expectEqual(@as(usize, 2), inst3.get(.c)); - testing.expectEqual(@as(usize, 6), inst3.get(.d)); - - testing.expectEqual(&inst.values[0], inst.getPtr(.a)); - testing.expectEqual(&inst.values[1], inst.getPtr(.b)); - testing.expectEqual(&inst.values[2], inst.getPtr(.c)); - testing.expectEqual(&inst.values[3], inst.getPtr(.d)); - - testing.expectEqual(@as(*const usize, &inst.values[0]), inst.getPtrConst(.a)); - testing.expectEqual(@as(*const usize, &inst.values[1]), inst.getPtrConst(.b)); - testing.expectEqual(@as(*const usize, &inst.values[2]), inst.getPtrConst(.c)); - testing.expectEqual(@as(*const usize, &inst.values[3]), inst.getPtrConst(.d)); - - inst.set(.c, 8); - testing.expectEqual(@as(usize, 5), inst.get(.a)); - testing.expectEqual(@as(usize, 5), inst.get(.b)); - testing.expectEqual(@as(usize, 8), inst.get(.c)); - testing.expectEqual(@as(usize, 5), inst.get(.d)); - - var it = inst.iterator(); - const Entry = Array.Entry; - testing.expectEqual(@as(?Entry, Entry{ - .key = .a, - .value = &inst.values[0], - }), it.next()); - testing.expectEqual(@as(?Entry, Entry{ - .key = .b, - .value = &inst.values[1], - }), it.next()); - testing.expectEqual(@as(?Entry, Entry{ - .key = .c, - .value = &inst.values[2], - }), it.next()); - testing.expectEqual(@as(?Entry, Entry{ - .key = .d, - .value = &inst.values[3], - }), it.next()); - testing.expectEqual(@as(?Entry, null), it.next()); -} - -test "std.enums.EnumMap void" { - const E = extern enum { a, b, c, d, e = 0 }; - const Map = EnumMap(E, void); - testing.expectEqual(E, Map.Key); - testing.expectEqual(EnumIndexer(E), Map.Indexer); - testing.expectEqual(void, Map.Value); - testing.expectEqual(@as(usize, 4), Map.len); - - const b = Map.initFull({}); - testing.expectEqual(@as(usize, 4), b.count()); - - const c = Map.initFullWith(.{ .a = {}, .b = {}, .c = {}, .d = {} }); - testing.expectEqual(@as(usize, 4), c.count()); - - const d = Map.initFullWithDefault({}, .{ .b = {} }); - testing.expectEqual(@as(usize, 4), d.count()); - - var a = Map.init(.{ .b = {}, .d = {} }); - testing.expectEqual(@as(usize, 2), a.count()); - testing.expectEqual(false, a.contains(.a)); - testing.expectEqual(true, a.contains(.b)); - testing.expectEqual(false, a.contains(.c)); - testing.expectEqual(true, a.contains(.d)); - testing.expect(a.get(.a) == null); - testing.expect(a.get(.b) != null); - testing.expect(a.get(.c) == null); - testing.expect(a.get(.d) != null); - testing.expect(a.getPtr(.a) == null); - testing.expect(a.getPtr(.b) != null); - testing.expect(a.getPtr(.c) == null); - testing.expect(a.getPtr(.d) != null); - testing.expect(a.getPtrConst(.a) == null); - testing.expect(a.getPtrConst(.b) != null); - testing.expect(a.getPtrConst(.c) == null); - testing.expect(a.getPtrConst(.d) != null); - _ = a.getPtrAssertContains(.b); - _ = a.getAssertContains(.d); - - a.put(.a, {}); - a.put(.a, {}); - a.putUninitialized(.c).* = {}; - a.putUninitialized(.c).* = {}; - - testing.expectEqual(@as(usize, 4), a.count()); - testing.expect(a.get(.a) != null); - testing.expect(a.get(.b) != null); - testing.expect(a.get(.c) != null); - testing.expect(a.get(.d) != null); - - a.remove(.a); - _ = a.fetchRemove(.c); - - var iter = a.iterator(); - const Entry = Map.Entry; - testing.expectEqual(E.b, iter.next().?.key); - testing.expectEqual(E.d, iter.next().?.key); - testing.expect(iter.next() == null); -} - -test "std.enums.EnumMap sized" { - const E = extern enum { a, b, c, d, e = 0 }; - const Map = EnumMap(E, usize); - testing.expectEqual(E, Map.Key); - testing.expectEqual(EnumIndexer(E), Map.Indexer); - testing.expectEqual(usize, Map.Value); - testing.expectEqual(@as(usize, 4), Map.len); - - const b = Map.initFull(5); - testing.expectEqual(@as(usize, 4), b.count()); - testing.expect(b.contains(.a)); - testing.expect(b.contains(.b)); - testing.expect(b.contains(.c)); - testing.expect(b.contains(.d)); - testing.expectEqual(@as(?usize, 5), b.get(.a)); - testing.expectEqual(@as(?usize, 5), b.get(.b)); - testing.expectEqual(@as(?usize, 5), b.get(.c)); - testing.expectEqual(@as(?usize, 5), b.get(.d)); - - const c = Map.initFullWith(.{ .a = 1, .b = 2, .c = 3, .d = 4 }); - testing.expectEqual(@as(usize, 4), c.count()); - testing.expect(c.contains(.a)); - testing.expect(c.contains(.b)); - testing.expect(c.contains(.c)); - testing.expect(c.contains(.d)); - testing.expectEqual(@as(?usize, 1), c.get(.a)); - testing.expectEqual(@as(?usize, 2), c.get(.b)); - testing.expectEqual(@as(?usize, 3), c.get(.c)); - testing.expectEqual(@as(?usize, 4), c.get(.d)); - - const d = Map.initFullWithDefault(6, .{ .b = 2, .c = 4 }); - testing.expectEqual(@as(usize, 4), d.count()); - testing.expect(d.contains(.a)); - testing.expect(d.contains(.b)); - testing.expect(d.contains(.c)); - testing.expect(d.contains(.d)); - testing.expectEqual(@as(?usize, 6), d.get(.a)); - testing.expectEqual(@as(?usize, 2), d.get(.b)); - testing.expectEqual(@as(?usize, 4), d.get(.c)); - testing.expectEqual(@as(?usize, 6), d.get(.d)); - - var a = Map.init(.{ .b = 2, .d = 4 }); - testing.expectEqual(@as(usize, 2), a.count()); - testing.expectEqual(false, a.contains(.a)); - testing.expectEqual(true, a.contains(.b)); - testing.expectEqual(false, a.contains(.c)); - testing.expectEqual(true, a.contains(.d)); - - testing.expectEqual(@as(?usize, null), a.get(.a)); - testing.expectEqual(@as(?usize, 2), a.get(.b)); - testing.expectEqual(@as(?usize, null), a.get(.c)); - testing.expectEqual(@as(?usize, 4), a.get(.d)); - - testing.expectEqual(@as(?*usize, null), a.getPtr(.a)); - testing.expectEqual(@as(?*usize, &a.values[1]), a.getPtr(.b)); - testing.expectEqual(@as(?*usize, null), a.getPtr(.c)); - testing.expectEqual(@as(?*usize, &a.values[3]), a.getPtr(.d)); - - testing.expectEqual(@as(?*const usize, null), a.getPtrConst(.a)); - testing.expectEqual(@as(?*const usize, &a.values[1]), a.getPtrConst(.b)); - testing.expectEqual(@as(?*const usize, null), a.getPtrConst(.c)); - testing.expectEqual(@as(?*const usize, &a.values[3]), a.getPtrConst(.d)); - - testing.expectEqual(@as(*const usize, &a.values[1]), a.getPtrAssertContains(.b)); - testing.expectEqual(@as(*const usize, &a.values[3]), a.getPtrAssertContains(.d)); - testing.expectEqual(@as(usize, 2), a.getAssertContains(.b)); - testing.expectEqual(@as(usize, 4), a.getAssertContains(.d)); - - a.put(.a, 3); - a.put(.a, 5); - a.putUninitialized(.c).* = 7; - a.putUninitialized(.c).* = 9; - - testing.expectEqual(@as(usize, 4), a.count()); - testing.expectEqual(@as(?usize, 5), a.get(.a)); - testing.expectEqual(@as(?usize, 2), a.get(.b)); - testing.expectEqual(@as(?usize, 9), a.get(.c)); - testing.expectEqual(@as(?usize, 4), a.get(.d)); - - a.remove(.a); - testing.expectEqual(@as(?usize, null), a.fetchRemove(.a)); - testing.expectEqual(@as(?usize, 9), a.fetchRemove(.c)); - a.remove(.c); - - var iter = a.iterator(); - const Entry = Map.Entry; - testing.expectEqual(@as(?Entry, Entry{ - .key = .b, - .value = &a.values[1], - }), iter.next()); - testing.expectEqual(@as(?Entry, Entry{ - .key = .d, - .value = &a.values[3], - }), iter.next()); - testing.expectEqual(@as(?Entry, null), iter.next()); -}