authorgravatar for spexguy070@gmail.comMartin Wickham <spexguy070@gmail.com> 2021-03-06 18:25:04-06:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-18 14:05:01-07:00
log96ae451bbe78cd35a62e00e3fb48a32f24ebd315
treea11930cd240610a90eb486510055075fe18decc4
parent5e5b35f1077d5cf77a89aee5dde939de35f2e247

Add some enum utilities


4 files changed, 1384 insertions(+), 7 deletions(-)

lib/std/bit_set.zig+21-7
......@@ -176,7 +176,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
176176 /// The default options (.{}) will iterate indices of set bits in
177177 /// ascending order. Modifications to the underlying bit set may
178178 /// or may not be observed by the iterator.
179 pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options.direction) {
179 pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) {
180180 return .{
181181 .bits_remain = switch (options.kind) {
182182 .set => self.mask,
......@@ -185,7 +185,11 @@ pub fn IntegerBitSet(comptime size: u16) type {
185185 };
186186 }
187187
188 fn Iterator(comptime direction: IteratorOptions.Direction) type {
188 pub fn Iterator(comptime options: IteratorOptions) type {
189 return SingleWordIterator(options.direction);
190 }
191
192 fn SingleWordIterator(comptime direction: IteratorOptions.Direction) type {
189193 return struct {
190194 const IterSelf = @This();
191195 // all bits which have not yet been iterated over
......@@ -425,8 +429,12 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
425429 /// The default options (.{}) will iterate indices of set bits in
426430 /// ascending order. Modifications to the underlying bit set may
427431 /// or may not be observed by the iterator.
428 pub fn iterator(self: *const Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
429 return BitSetIterator(MaskInt, options).init(&self.masks, last_item_mask);
432 pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) {
433 return Iterator(options).init(&self.masks, last_item_mask);
434 }
435
436 pub fn Iterator(comptime options: IteratorOptions) type {
437 return BitSetIterator(MaskInt, options);
430438 }
431439
432440 fn maskBit(index: usize) MaskInt {
......@@ -700,11 +708,15 @@ pub const DynamicBitSetUnmanaged = struct {
700708 /// ascending order. Modifications to the underlying bit set may
701709 /// or may not be observed by the iterator. Resizing the underlying
702710 /// bit set invalidates the iterator.
703 pub fn iterator(self: *const Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
711 pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) {
704712 const num_masks = numMasks(self.bit_length);
705713 const padding_bits = num_masks * @bitSizeOf(MaskInt) - self.bit_length;
706714 const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
707 return BitSetIterator(MaskInt, options).init(self.masks[0..num_masks], last_item_mask);
715 return Iterator(options).init(self.masks[0..num_masks], last_item_mask);
716 }
717
718 pub fn Iterator(comptime options: IteratorOptions) type {
719 return BitSetIterator(MaskInt, options);
708720 }
709721
710722 fn maskBit(index: usize) MaskInt {
......@@ -858,9 +870,11 @@ pub const DynamicBitSet = struct {
858870 /// ascending order. Modifications to the underlying bit set may
859871 /// or may not be observed by the iterator. Resizing the underlying
860872 /// bit set invalidates the iterator.
861 pub fn iterator(self: *Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
873 pub fn iterator(self: *Self, comptime options: IteratorOptions) Iterator(options) {
862874 return self.unmanaged.iterator(options);
863875 }
876
877 pub const Iterator = DynamicBitSetUnmanaged.Iterator;
864878};
865879
866880/// Options for configuring an iterator over a bit set
lib/std/enums.zig created+1281
......@@ -0,0 +1,1281 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7//! This module contains utilities and data structures for working with enums.
8
9const std = @import("std.zig");
10const assert = std.debug.assert;
11const testing = std.testing;
12const EnumField = std.builtin.TypeInfo.EnumField;
13
14/// Returns a struct with a field matching each unique named enum element.
15/// If the enum is extern and has multiple names for the same value, only
16/// the first name is used. Each field is of type Data and has the provided
17/// default, which may be undefined.
18pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type {
19 const StructField = std.builtin.TypeInfo.StructField;
20 var fields: []const StructField = &[_]StructField{};
21 for (uniqueFields(E)) |field, i| {
22 fields = fields ++ &[_]StructField{.{
23 .name = field.name,
24 .field_type = Data,
25 .default_value = field_default,
26 .is_comptime = false,
27 .alignment = if (@sizeOf(Data) > 0) @alignOf(Data) else 0,
28 }};
29 }
30 return @Type(.{ .Struct = .{
31 .layout = .Auto,
32 .fields = fields,
33 .decls = &[_]std.builtin.TypeInfo.Declaration{},
34 .is_tuple = false,
35 }});
36}
37
38/// Looks up the supplied fields in the given enum type.
39/// Uses only the field names, field values are ignored.
40/// The result array is in the same order as the input.
41pub fn valuesFromFields(comptime E: type, comptime fields: []const EnumField) []const E {
42 comptime {
43 var result: [fields.len]E = undefined;
44 for (fields) |f, i| {
45 result[i] = @field(E, f.name);
46 }
47 return &result;
48 }
49}
50
51test "std.enums.valuesFromFields" {
52 const E = extern enum { a, b, c, d = 0 };
53 const fields = valuesFromFields(E, &[_]EnumField{
54 .{ .name = "b", .value = undefined },
55 .{ .name = "a", .value = undefined },
56 .{ .name = "a", .value = undefined },
57 .{ .name = "d", .value = undefined },
58 });
59 testing.expectEqual(E.b, fields[0]);
60 testing.expectEqual(E.a, fields[1]);
61 testing.expectEqual(E.d, fields[2]); // a == d
62 testing.expectEqual(E.d, fields[3]);
63}
64
65/// Returns the set of all named values in the given enum, in
66/// declaration order.
67pub fn values(comptime E: type) []const E {
68 return comptime valuesFromFields(E, @typeInfo(E).Enum.fields);
69}
70
71test "std.enum.values" {
72 const E = extern enum { a, b, c, d = 0 };
73 testing.expectEqualSlices(E, &.{.a, .b, .c, .d}, values(E));
74}
75
76/// Returns the set of all unique named values in the given enum, in
77/// declaration order. For repeated values in extern enums, only the
78/// first name for each value is included.
79pub fn uniqueValues(comptime E: type) []const E {
80 return comptime valuesFromFields(E, uniqueFields(E));
81}
82
83test "std.enum.uniqueValues" {
84 const E = extern enum { a, b, c, d = 0, e, f = 3 };
85 testing.expectEqualSlices(E, &.{.a, .b, .c, .f}, uniqueValues(E));
86
87 const F = enum { a, b, c };
88 testing.expectEqualSlices(F, &.{.a, .b, .c}, uniqueValues(F));
89}
90
91/// Returns the set of all unique field values in the given enum, in
92/// declaration order. For repeated values in extern enums, only the
93/// first name for each value is included.
94pub fn uniqueFields(comptime E: type) []const EnumField {
95 comptime {
96 const info = @typeInfo(E).Enum;
97 const raw_fields = info.fields;
98 // Only extern enums can contain duplicates,
99 // so fast path other types.
100 if (info.layout != .Extern) {
101 return raw_fields;
102 }
103
104 var unique_fields: []const EnumField = &[_]EnumField{};
105 outer:
106 for (raw_fields) |candidate| {
107 for (unique_fields) |u| {
108 if (u.value == candidate.value)
109 continue :outer;
110 }
111 unique_fields = unique_fields ++ &[_]EnumField{candidate};
112 }
113
114 return unique_fields;
115 }
116}
117
118/// Determines the length of a direct-mapped enum array, indexed by
119/// @intCast(usize, @enumToInt(enum_value)). The enum must be exhaustive.
120/// If the enum contains any fields with values that cannot be represented
121/// by usize, a compile error is issued. The max_unused_slots parameter limits
122/// the total number of items which have no matching enum key (holes in the enum
123/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots
124/// must be at least 3, to allow unused slots 0, 3, and 4.
125fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int {
126 const info = @typeInfo(E).Enum;
127 if (!info.is_exhaustive) {
128 @compileError("Cannot create direct array of non-exhaustive enum "++@typeName(E));
129 }
130
131 var max_value: comptime_int = -1;
132 const max_usize: comptime_int = ~@as(usize, 0);
133 const fields = uniqueFields(E);
134 for (fields) |f| {
135 if (f.value < 0) {
136 @compileError("Cannot create a direct enum array for "++@typeName(E)++", field ."++f.name++" has a negative value.");
137 }
138 if (f.value > max_value) {
139 if (f.value > max_usize) {
140 @compileError("Cannot create a direct enum array for "++@typeName(E)++", field ."++f.name++" is larger than the max value of usize.");
141 }
142 max_value = f.value;
143 }
144 }
145
146 const unused_slots = max_value + 1 - fields.len;
147 if (unused_slots > max_unused_slots) {
148 const unused_str = std.fmt.comptimePrint("{d}", .{unused_slots});
149 const allowed_str = std.fmt.comptimePrint("{d}", .{max_unused_slots});
150 @compileError("Cannot create a direct enum array for "++@typeName(E)++". It would have "++unused_str++" unused slots, but only "++allowed_str++" are allowed.");
151 }
152
153 return max_value + 1;
154}
155
156/// Initializes an array of Data which can be indexed by
157/// @intCast(usize, @enumToInt(enum_value)). The enum must be exhaustive.
158/// If the enum contains any fields with values that cannot be represented
159/// by usize, a compile error is issued. The max_unused_slots parameter limits
160/// the total number of items which have no matching enum key (holes in the enum
161/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots
162/// must be at least 3, to allow unused slots 0, 3, and 4.
163/// The init_values parameter must be a struct with field names that match the enum values.
164/// If the enum has multiple fields with the same value, the name of the first one must
165/// be used.
166pub fn directEnumArray(
167 comptime E: type,
168 comptime Data: type,
169 comptime max_unused_slots: comptime_int,
170 init_values: EnumFieldStruct(E, Data, null),
171) [directEnumArrayLen(E, max_unused_slots)]Data {
172 return directEnumArrayDefault(E, Data, null, max_unused_slots, init_values);
173}
174
175test "std.enums.directEnumArray" {
176 const E = enum(i4) { a = 4, b = 6, c = 2 };
177 var runtime_false: bool = false;
178 const array = directEnumArray(E, bool, 4, .{
179 .a = true,
180 .b = runtime_false,
181 .c = true,
182 });
183
184 testing.expectEqual([7]bool, @TypeOf(array));
185 testing.expectEqual(true, array[4]);
186 testing.expectEqual(false, array[6]);
187 testing.expectEqual(true, array[2]);
188}
189
190/// Initializes an array of Data which can be indexed by
191/// @intCast(usize, @enumToInt(enum_value)). The enum must be exhaustive.
192/// If the enum contains any fields with values that cannot be represented
193/// by usize, a compile error is issued. The max_unused_slots parameter limits
194/// the total number of items which have no matching enum key (holes in the enum
195/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots
196/// must be at least 3, to allow unused slots 0, 3, and 4.
197/// The init_values parameter must be a struct with field names that match the enum values.
198/// If the enum has multiple fields with the same value, the name of the first one must
199/// be used.
200pub fn directEnumArrayDefault(
201 comptime E: type,
202 comptime Data: type,
203 comptime default: ?Data,
204 comptime max_unused_slots: comptime_int,
205 init_values: EnumFieldStruct(E, Data, default),
206) [directEnumArrayLen(E, max_unused_slots)]Data {
207 const len = comptime directEnumArrayLen(E, max_unused_slots);
208 var result: [len]Data = if (default) |d| [_]Data{d} ** len else undefined;
209 inline for (@typeInfo(@TypeOf(init_values)).Struct.fields) |f, i| {
210 const enum_value = @field(E, f.name);
211 const index = @intCast(usize, @enumToInt(enum_value));
212 result[index] = @field(init_values, f.name);
213 }
214 return result;
215}
216
217test "std.enums.directEnumArrayDefault" {
218 const E = enum(i4) { a = 4, b = 6, c = 2 };
219 var runtime_false: bool = false;
220 const array = directEnumArrayDefault(E, bool, false, 4, .{
221 .a = true,
222 .b = runtime_false,
223 });
224
225 testing.expectEqual([7]bool, @TypeOf(array));
226 testing.expectEqual(true, array[4]);
227 testing.expectEqual(false, array[6]);
228 testing.expectEqual(false, array[2]);
229}
230
231/// Cast an enum literal, value, or string to the enum value of type E
232/// with the same name.
233pub fn nameCast(comptime E: type, comptime value: anytype) E {
234 comptime {
235 const V = @TypeOf(value);
236 if (V == E) return value;
237 var name: ?[]const u8 = switch (@typeInfo(V)) {
238 .EnumLiteral, .Enum => @tagName(value),
239 .Pointer => if (std.meta.trait.isZigString(V)) value else null,
240 else => null,
241 };
242 if (name) |n| {
243 if (@hasField(E, n)) {
244 return @field(E, n);
245 }
246 @compileError("Enum "++@typeName(E)++" has no field named "++n);
247 }
248 @compileError("Cannot cast from "++@typeName(@TypeOf(value))++" to "++@typeName(E));
249 }
250}
251
252test "std.enums.nameCast" {
253 const A = enum { a = 0, b = 1 };
254 const B = enum { a = 1, b = 0 };
255 testing.expectEqual(A.a, nameCast(A, .a));
256 testing.expectEqual(A.a, nameCast(A, A.a));
257 testing.expectEqual(A.a, nameCast(A, B.a));
258 testing.expectEqual(A.a, nameCast(A, "a"));
259 testing.expectEqual(A.a, nameCast(A, @as(*const[1]u8, "a")));
260 testing.expectEqual(A.a, nameCast(A, @as([:0]const u8, "a")));
261 testing.expectEqual(A.a, nameCast(A, @as([]const u8, "a")));
262
263 testing.expectEqual(B.a, nameCast(B, .a));
264 testing.expectEqual(B.a, nameCast(B, A.a));
265 testing.expectEqual(B.a, nameCast(B, B.a));
266 testing.expectEqual(B.a, nameCast(B, "a"));
267
268 testing.expectEqual(B.b, nameCast(B, .b));
269 testing.expectEqual(B.b, nameCast(B, A.b));
270 testing.expectEqual(B.b, nameCast(B, B.b));
271 testing.expectEqual(B.b, nameCast(B, "b"));
272}
273
274/// A set of enum elements, backed by a bitfield. If the enum
275/// is not dense, a mapping will be constructed from enum values
276/// to dense indices. This type does no dynamic allocation and
277/// can be copied by value.
278pub fn EnumSet(comptime E: type) type {
279 const mixin = struct {
280 fn EnumSetExt(comptime Self: type) type {
281 const Indexer = Self.Indexer;
282 return struct {
283 /// Initializes the set using a struct of bools
284 pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self {
285 var result = Self{};
286 comptime var i: usize = 0;
287 inline while (i < Self.len) : (i += 1) {
288 comptime const key = Indexer.keyForIndex(i);
289 comptime const tag = @tagName(key);
290 if (@field(init_values, tag)) {
291 result.bits.set(i);
292 }
293 }
294 return result;
295 }
296 };
297 }
298 };
299 return IndexedSet(EnumIndexer(E), mixin.EnumSetExt);
300}
301
302/// A map keyed by an enum, backed by a bitfield and a dense array.
303/// If the enum is not dense, a mapping will be constructed from
304/// enum values to dense indices. This type does no dynamic
305/// allocation and can be copied by value.
306pub fn EnumMap(comptime E: type, comptime V: type) type {
307 const mixin = struct {
308 fn EnumMapExt(comptime Self: type) type {
309 const Indexer = Self.Indexer;
310 return struct {
311 /// Initializes the map using a sparse struct of optionals
312 pub fn init(init_values: EnumFieldStruct(E, ?V, @as(?V, null))) Self {
313 var result = Self{};
314 comptime var i: usize = 0;
315 inline while (i < Self.len) : (i += 1) {
316 comptime const key = Indexer.keyForIndex(i);
317 comptime const tag = @tagName(key);
318 if (@field(init_values, tag)) |*v| {
319 result.bits.set(i);
320 result.values[i] = v.*;
321 }
322 }
323 return result;
324 }
325 /// Initializes a full mapping with all keys set to value.
326 /// Consider using EnumArray instead if the map will remain full.
327 pub fn initFull(value: V) Self {
328 var result = Self{
329 .bits = Self.BitSet.initFull(),
330 .values = undefined,
331 };
332 std.mem.set(V, &result.values, value);
333 return result;
334 }
335 /// Initializes a full mapping with supplied values.
336 /// Consider using EnumArray instead if the map will remain full.
337 pub fn initFullWith(init_values: EnumFieldStruct(E, V, @as(?V, null))) Self {
338 return initFullWithDefault(@as(?V, null), init_values);
339 }
340 /// Initializes a full mapping with a provided default.
341 /// Consider using EnumArray instead if the map will remain full.
342 pub fn initFullWithDefault(comptime default: ?V, init_values: EnumFieldStruct(E, V, default)) Self {
343 var result = Self{
344 .bits = Self.BitSet.initFull(),
345 .values = undefined,
346 };
347 comptime var i: usize = 0;
348 inline while (i < Self.len) : (i += 1) {
349 comptime const key = Indexer.keyForIndex(i);
350 comptime const tag = @tagName(key);
351 result.values[i] = @field(init_values, tag);
352 }
353 return result;
354 }
355 };
356 }
357 };
358 return IndexedMap(EnumIndexer(E), V, mixin.EnumMapExt);
359}
360
361/// An array keyed by an enum, backed by a dense array.
362/// If the enum is not dense, a mapping will be constructed from
363/// enum values to dense indices. This type does no dynamic
364/// allocation and can be copied by value.
365pub fn EnumArray(comptime E: type, comptime V: type) type {
366 const mixin = struct {
367 fn EnumArrayExt(comptime Self: type) type {
368 const Indexer = Self.Indexer;
369 return struct {
370 /// Initializes all values in the enum array
371 pub fn init(init_values: EnumFieldStruct(E, V, @as(?V, null))) Self {
372 return initDefault(@as(?V, null), init_values);
373 }
374
375 /// Initializes values in the enum array, with the specified default.
376 pub fn initDefault(comptime default: ?V, init_values: EnumFieldStruct(E, V, default)) Self {
377 var result = Self{ .values = undefined };
378 comptime var i: usize = 0;
379 inline while (i < Self.len) : (i += 1) {
380 const key = comptime Indexer.keyForIndex(i);
381 const tag = @tagName(key);
382 result.values[i] = @field(init_values, tag);
383 }
384 return result;
385 }
386 };
387 }
388 };
389 return IndexedArray(EnumIndexer(E), V, mixin.EnumArrayExt);
390}
391
392/// Pass this function as the Ext parameter to Indexed* if you
393/// do not want to attach any extensions. This parameter was
394/// originally an optional, but optional generic functions
395/// seem to be broken at the moment.
396/// TODO: Once #8169 is fixed, consider switching this param
397/// back to an optional.
398pub fn NoExtension(comptime Self: type) type {
399 return NoExt;
400}
401const NoExt = struct{};
402
403/// A set type with an Indexer mapping from keys to indices.
404/// Presence or absence is stored as a dense bitfield. This
405/// type does no allocation and can be copied by value.
406pub fn IndexedSet(comptime I: type, comptime Ext: fn(type)type) type {
407 comptime ensureIndexer(I);
408 return struct {
409 const Self = @This();
410
411 pub usingnamespace Ext(Self);
412
413 /// The indexing rules for converting between keys and indices.
414 pub const Indexer = I;
415 /// The element type for this set.
416 pub const Key = Indexer.Key;
417
418 const BitSet = std.StaticBitSet(Indexer.count);
419
420 /// The maximum number of items in this set.
421 pub const len = Indexer.count;
422
423 bits: BitSet = BitSet.initEmpty(),
424
425 /// Returns a set containing all possible keys.
426 pub fn initFull() Self {
427 return .{ .bits = BitSet.initFull() };
428 }
429
430 /// Returns the number of keys in the set.
431 pub fn count(self: Self) usize {
432 return self.bits.count();
433 }
434
435 /// Checks if a key is in the set.
436 pub fn contains(self: Self, key: Key) bool {
437 return self.bits.isSet(Indexer.indexOf(key));
438 }
439
440 /// Puts a key in the set.
441 pub fn insert(self: *Self, key: Key) void {
442 self.bits.set(Indexer.indexOf(key));
443 }
444
445 /// Removes a key from the set.
446 pub fn remove(self: *Self, key: Key) void {
447 self.bits.unset(Indexer.indexOf(key));
448 }
449
450 /// Changes the presence of a key in the set to match the passed bool.
451 pub fn setPresent(self: *Self, key: Key, present: bool) void {
452 self.bits.setValue(Indexer.indexOf(key), present);
453 }
454
455 /// Toggles the presence of a key in the set. If the key is in
456 /// the set, removes it. Otherwise adds it.
457 pub fn toggle(self: *Self, key: Key) void {
458 self.bits.toggle(Indexer.indexOf(key));
459 }
460
461 /// Toggles the presence of all keys in the passed set.
462 pub fn toggleSet(self: *Self, other: Self) void {
463 self.bits.toggleSet(other.bits);
464 }
465
466 /// Toggles all possible keys in the set.
467 pub fn toggleAll(self: *Self) void {
468 self.bits.toggleAll();
469 }
470
471 /// Adds all keys in the passed set to this set.
472 pub fn setUnion(self: *Self, other: Self) void {
473 self.bits.setUnion(other.bits);
474 }
475
476 /// Removes all keys which are not in the passed set.
477 pub fn setIntersection(self: *Self, other: Self) void {
478 self.bits.setIntersection(other.bits);
479 }
480
481 /// Returns an iterator over this set, which iterates in
482 /// index order. Modifications to the set during iteration
483 /// may or may not be observed by the iterator, but will
484 /// not invalidate it.
485 pub fn iterator(self: *Self) Iterator {
486 return .{ .inner = self.bits.iterator(.{}) };
487 }
488
489 pub const Iterator = struct {
490 inner: BitSet.Iterator(.{}),
491
492 pub fn next(self: *Iterator) ?Key {
493 return if (self.inner.next()) |index|
494 Indexer.keyForIndex(index)
495 else null;
496 }
497 };
498 };
499}
500
501/// A map from keys to values, using an index lookup. Uses a
502/// bitfield to track presence and a dense array of values.
503/// This type does no allocation and can be copied by value.
504pub fn IndexedMap(comptime I: type, comptime V: type, comptime Ext: fn(type)type) type {
505 comptime ensureIndexer(I);
506 return struct {
507 const Self = @This();
508
509 pub usingnamespace Ext(Self);
510
511 /// The index mapping for this map
512 pub const Indexer = I;
513 /// The key type used to index this map
514 pub const Key = Indexer.Key;
515 /// The value type stored in this map
516 pub const Value = V;
517 /// The number of possible keys in the map
518 pub const len = Indexer.count;
519
520 const BitSet = std.StaticBitSet(Indexer.count);
521
522 /// Bits determining whether items are in the map
523 bits: BitSet = BitSet.initEmpty(),
524 /// Values of items in the map. If the associated
525 /// bit is zero, the value is undefined.
526 values: [Indexer.count]Value = undefined,
527
528 /// The number of items in the map.
529 pub fn count(self: Self) usize {
530 return self.bits.count();
531 }
532
533 /// Checks if the map contains an item.
534 pub fn contains(self: Self, key: Key) bool {
535 return self.bits.isSet(Indexer.indexOf(key));
536 }
537
538 /// Gets the value associated with a key.
539 /// If the key is not in the map, returns null.
540 pub fn get(self: Self, key: Key) ?Value {
541 const index = Indexer.indexOf(key);
542 return if (self.bits.isSet(index)) self.values[index] else null;
543 }
544
545 /// Gets the value associated with a key, which must
546 /// exist in the map.
547 pub fn getAssertContains(self: Self, key: Key) Value {
548 const index = Indexer.indexOf(key);
549 assert(self.bits.isSet(index));
550 return self.values[index];
551 }
552
553 /// Gets the address of the value associated with a key.
554 /// If the key is not in the map, returns null.
555 pub fn getPtr(self: *Self, key: Key) ?*Value {
556 const index = Indexer.indexOf(key);
557 return if (self.bits.isSet(index)) &self.values[index] else null;
558 }
559
560 /// Gets the address of the const value associated with a key.
561 /// If the key is not in the map, returns null.
562 pub fn getPtrConst(self: *const Self, key: Key) ?*const Value {
563 const index = Indexer.indexOf(key);
564 return if (self.bits.isSet(index)) &self.values[index] else null;
565 }
566
567 /// Gets the address of the value associated with a key.
568 /// The key must be present in the map.
569 pub fn getPtrAssertContains(self: *Self, key: Key) *Value {
570 const index = Indexer.indexOf(key);
571 assert(self.bits.isSet(index));
572 return &self.values[index];
573 }
574
575 /// Adds the key to the map with the supplied value.
576 /// If the key is already in the map, overwrites the value.
577 pub fn put(self: *Self, key: Key, value: Value) void {
578 const index = Indexer.indexOf(key);
579 self.bits.set(index);
580 self.values[index] = value;
581 }
582
583 /// Adds the key to the map with an undefined value.
584 /// If the key is already in the map, the value becomes undefined.
585 /// A pointer to the value is returned, which should be
586 /// used to initialize the value.
587 pub fn putUninitialized(self: *Self, key: Key) *Value {
588 const index = Indexer.indexOf(key);
589 self.bits.set(index);
590 self.values[index] = undefined;
591 return &self.values[index];
592 }
593
594 /// Sets the value associated with the key in the map,
595 /// and returns the old value. If the key was not in
596 /// the map, returns null.
597 pub fn fetchPut(self: *Self, key: Key, value: Value) ?Value {
598 const index = Indexer.indexOf(key);
599 const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;
600 self.bits.set(index);
601 self.values[index] = value;
602 return result;
603 }
604
605 /// Removes a key from the map. If the key was not in the map,
606 /// does nothing.
607 pub fn remove(self: *Self, key: Key) void {
608 const index = Indexer.indexOf(key);
609 self.bits.unset(index);
610 self.values[index] = undefined;
611 }
612
613 /// Removes a key from the map, and returns the old value.
614 /// If the key was not in the map, returns null.
615 pub fn fetchRemove(self: *Self, key: Key) ?Value {
616 const index = Indexer.indexOf(key);
617 const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;
618 self.bits.unset(index);
619 self.values[index] = undefined;
620 return result;
621 }
622
623 /// Returns an iterator over the map, which visits items in index order.
624 /// Modifications to the underlying map may or may not be observed by
625 /// the iterator, but will not invalidate it.
626 pub fn iterator(self: *Self) Iterator {
627 return .{
628 .inner = self.bits.iterator(.{}),
629 .values = &self.values,
630 };
631 }
632
633 /// An entry in the map.
634 pub const Entry = struct {
635 /// The key associated with this entry.
636 /// Modifying this key will not change the map.
637 key: Key,
638
639 /// A pointer to the value in the map associated
640 /// with this key. Modifications through this
641 /// pointer will modify the underlying data.
642 value: *Value,
643 };
644
645 pub const Iterator = struct {
646 inner: BitSet.Iterator(.{}),
647 values: *[Indexer.count]Value,
648
649 pub fn next(self: *Iterator) ?Entry {
650 return if (self.inner.next()) |index|
651 Entry{
652 .key = Indexer.keyForIndex(index),
653 .value = &self.values[index],
654 }
655 else null;
656 }
657 };
658 };
659}
660
661/// A dense array of values, using an indexed lookup.
662/// This type does no allocation and can be copied by value.
663pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: fn(type)type) type {
664 comptime ensureIndexer(I);
665 return struct {
666 const Self = @This();
667
668 pub usingnamespace Ext(Self);
669
670 /// The index mapping for this map
671 pub const Indexer = I;
672 /// The key type used to index this map
673 pub const Key = Indexer.Key;
674 /// The value type stored in this map
675 pub const Value = V;
676 /// The number of possible keys in the map
677 pub const len = Indexer.count;
678
679 values: [Indexer.count]Value,
680
681 pub fn initUndefined() Self {
682 return Self{ .values = undefined };
683 }
684
685 pub fn initFill(v: Value) Self {
686 var self: Self = undefined;
687 std.mem.set(Value, &self.values, v);
688 return self;
689 }
690
691 /// Returns the value in the array associated with a key.
692 pub fn get(self: Self, key: Key) Value {
693 return self.values[Indexer.indexOf(key)];
694 }
695
696 /// Returns a pointer to the slot in the array associated with a key.
697 pub fn getPtr(self: *Self, key: Key) *Value {
698 return &self.values[Indexer.indexOf(key)];
699 }
700
701 /// Returns a const pointer to the slot in the array associated with a key.
702 pub fn getPtrConst(self: *const Self, key: Key) *const Value {
703 return &self.values[Indexer.indexOf(key)];
704 }
705
706 /// Sets the value in the slot associated with a key.
707 pub fn set(self: *Self, key: Key, value: Value) void {
708 self.values[Indexer.indexOf(key)] = value;
709 }
710
711 /// Iterates over the items in the array, in index order.
712 pub fn iterator(self: *Self) Iterator {
713 return .{
714 .values = &self.values,
715 };
716 }
717
718 /// An entry in the array.
719 pub const Entry = struct {
720 /// The key associated with this entry.
721 /// Modifying this key will not change the array.
722 key: Key,
723
724 /// A pointer to the value in the array associated
725 /// with this key. Modifications through this
726 /// pointer will modify the underlying data.
727 value: *Value,
728 };
729
730 pub const Iterator = struct {
731 index: usize = 0,
732 values: *[Indexer.count]Value,
733
734 pub fn next(self: *Iterator) ?Entry {
735 const index = self.index;
736 if (index < Indexer.count) {
737 self.index += 1;
738 return Entry{
739 .key = Indexer.keyForIndex(index),
740 .value = &self.values[index],
741 };
742 }
743 return null;
744 }
745 };
746 };
747}
748
749/// Verifies that a type is a valid Indexer, providing a helpful
750/// compile error if not. An Indexer maps a comptime known set
751/// of keys to a dense set of zero-based indices.
752/// The indexer interface must look like this:
753/// ```
754/// struct {
755/// /// The key type which this indexer converts to indices
756/// pub const Key: type,
757/// /// The number of indexes in the dense mapping
758/// pub const count: usize,
759/// /// Converts from a key to an index
760/// pub fn indexOf(Key) usize;
761/// /// Converts from an index to a key
762/// pub fn keyForIndex(usize) Key;
763/// }
764/// ```
765pub fn ensureIndexer(comptime T: type) void {
766 comptime {
767 if (!@hasDecl(T, "Key")) @compileError("Indexer must have decl Key: type.");
768 if (@TypeOf(T.Key) != type) @compileError("Indexer.Key must be a type.");
769 if (!@hasDecl(T, "count")) @compileError("Indexer must have decl count: usize.");
770 if (@TypeOf(T.count) != usize) @compileError("Indexer.count must be a usize.");
771 if (!@hasDecl(T, "indexOf")) @compileError("Indexer.indexOf must be a fn(Key)usize.");
772 if (@TypeOf(T.indexOf) != fn(T.Key)usize) @compileError("Indexer must have decl indexOf: fn(Key)usize.");
773 if (!@hasDecl(T, "keyForIndex")) @compileError("Indexer must have decl keyForIndex: fn(usize)Key.");
774 if (@TypeOf(T.keyForIndex) != fn(usize)T.Key) @compileError("Indexer.keyForIndex must be a fn(usize)Key.");
775 }
776}
777
778test "std.enums.ensureIndexer" {
779 ensureIndexer(struct {
780 pub const Key = u32;
781 pub const count: usize = 8;
782 pub fn indexOf(k: Key) usize {
783 return @intCast(usize, k);
784 }
785 pub fn keyForIndex(index: usize) Key {
786 return @intCast(Key, index);
787 }
788 });
789}
790
791fn ascByValue(ctx: void, comptime a: EnumField, comptime b: EnumField) bool {
792 return a.value < b.value;
793}
794pub fn EnumIndexer(comptime E: type) type {
795 if (!@typeInfo(E).Enum.is_exhaustive) {
796 @compileError("Cannot create an enum indexer for a non-exhaustive enum.");
797 }
798
799 const const_fields = uniqueFields(E);
800 var fields = const_fields[0..const_fields.len].*;
801 if (fields.len == 0) {
802 return struct {
803 pub const Key = E;
804 pub const count: usize = 0;
805 pub fn indexOf(e: E) usize { unreachable; }
806 pub fn keyForIndex(i: usize) E { unreachable; }
807 };
808 }
809 std.sort.sort(EnumField, &fields, {}, ascByValue);
810 const min = fields[0].value;
811 const max = fields[fields.len-1].value;
812 if (max - min == fields.len-1) {
813 return struct {
814 pub const Key = E;
815 pub const count = fields.len;
816 pub fn indexOf(e: E) usize {
817 return @intCast(usize, @enumToInt(e) - min);
818 }
819 pub fn keyForIndex(i: usize) E {
820 // TODO fix addition semantics. This calculation
821 // gives up some safety to avoid artificially limiting
822 // the range of signed enum values to max_isize.
823 const enum_value = if (min < 0) @bitCast(isize, i) +% min else i + min;
824 return @intToEnum(E, @intCast(std.meta.Tag(E), enum_value));
825 }
826 };
827 }
828
829 const keys = valuesFromFields(E, &fields);
830
831 return struct {
832 pub const Key = E;
833 pub const count = fields.len;
834 pub fn indexOf(e: E) usize {
835 for (keys) |k, i| {
836 if (k == e) return i;
837 }
838 unreachable;
839 }
840 pub fn keyForIndex(i: usize) E {
841 return keys[i];
842 }
843 };
844}
845
846test "std.enums.EnumIndexer dense zeroed" {
847 const E = enum{ b = 1, a = 0, c = 2 };
848 const Indexer = EnumIndexer(E);
849 ensureIndexer(Indexer);
850 testing.expectEqual(E, Indexer.Key);
851 testing.expectEqual(@as(usize, 3), Indexer.count);
852
853 testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a));
854 testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b));
855 testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c));
856
857 testing.expectEqual(E.a, Indexer.keyForIndex(0));
858 testing.expectEqual(E.b, Indexer.keyForIndex(1));
859 testing.expectEqual(E.c, Indexer.keyForIndex(2));
860}
861
862test "std.enums.EnumIndexer dense positive" {
863 const E = enum(u4) { c = 6, a = 4, b = 5 };
864 const Indexer = EnumIndexer(E);
865 ensureIndexer(Indexer);
866 testing.expectEqual(E, Indexer.Key);
867 testing.expectEqual(@as(usize, 3), Indexer.count);
868
869 testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a));
870 testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b));
871 testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c));
872
873 testing.expectEqual(E.a, Indexer.keyForIndex(0));
874 testing.expectEqual(E.b, Indexer.keyForIndex(1));
875 testing.expectEqual(E.c, Indexer.keyForIndex(2));
876}
877
878test "std.enums.EnumIndexer dense negative" {
879 const E = enum(i4) { a = -6, c = -4, b = -5 };
880 const Indexer = EnumIndexer(E);
881 ensureIndexer(Indexer);
882 testing.expectEqual(E, Indexer.Key);
883 testing.expectEqual(@as(usize, 3), Indexer.count);
884
885 testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a));
886 testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b));
887 testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c));
888
889 testing.expectEqual(E.a, Indexer.keyForIndex(0));
890 testing.expectEqual(E.b, Indexer.keyForIndex(1));
891 testing.expectEqual(E.c, Indexer.keyForIndex(2));
892}
893
894test "std.enums.EnumIndexer sparse" {
895 const E = enum(i4) { a = -2, c = 6, b = 4 };
896 const Indexer = EnumIndexer(E);
897 ensureIndexer(Indexer);
898 testing.expectEqual(E, Indexer.Key);
899 testing.expectEqual(@as(usize, 3), Indexer.count);
900
901 testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a));
902 testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b));
903 testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c));
904
905 testing.expectEqual(E.a, Indexer.keyForIndex(0));
906 testing.expectEqual(E.b, Indexer.keyForIndex(1));
907 testing.expectEqual(E.c, Indexer.keyForIndex(2));
908}
909
910test "std.enums.EnumIndexer repeats" {
911 const E = extern enum{ a = -2, c = 6, b = 4, b2 = 4 };
912 const Indexer = EnumIndexer(E);
913 ensureIndexer(Indexer);
914 testing.expectEqual(E, Indexer.Key);
915 testing.expectEqual(@as(usize, 3), Indexer.count);
916
917 testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a));
918 testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b));
919 testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c));
920
921 testing.expectEqual(E.a, Indexer.keyForIndex(0));
922 testing.expectEqual(E.b, Indexer.keyForIndex(1));
923 testing.expectEqual(E.c, Indexer.keyForIndex(2));
924}
925
926test "std.enums.EnumSet" {
927 const E = extern enum { a, b, c, d, e = 0 };
928 const Set = EnumSet(E);
929 testing.expectEqual(E, Set.Key);
930 testing.expectEqual(EnumIndexer(E), Set.Indexer);
931 testing.expectEqual(@as(usize, 4), Set.len);
932
933 // Empty sets
934 const empty = Set{};
935 comptime testing.expect(empty.count() == 0);
936
937 var empty_b = Set.init(.{});
938 testing.expect(empty_b.count() == 0);
939
940 const empty_c = comptime Set.init(.{});
941 comptime testing.expect(empty_c.count() == 0);
942
943 const full = Set.initFull();
944 testing.expect(full.count() == Set.len);
945
946 const full_b = comptime Set.initFull();
947 comptime testing.expect(full_b.count() == Set.len);
948
949 testing.expectEqual(false, empty.contains(.a));
950 testing.expectEqual(false, empty.contains(.b));
951 testing.expectEqual(false, empty.contains(.c));
952 testing.expectEqual(false, empty.contains(.d));
953 testing.expectEqual(false, empty.contains(.e));
954 {
955 var iter = empty_b.iterator();
956 testing.expectEqual(@as(?E, null), iter.next());
957 }
958
959 var mut = Set.init(.{
960 .a=true, .c=true,
961 });
962 testing.expectEqual(@as(usize, 2), mut.count());
963 testing.expectEqual(true, mut.contains(.a));
964 testing.expectEqual(false, mut.contains(.b));
965 testing.expectEqual(true, mut.contains(.c));
966 testing.expectEqual(false, mut.contains(.d));
967 testing.expectEqual(true, mut.contains(.e)); // aliases a
968 {
969 var it = mut.iterator();
970 testing.expectEqual(@as(?E, .a), it.next());
971 testing.expectEqual(@as(?E, .c), it.next());
972 testing.expectEqual(@as(?E, null), it.next());
973 }
974
975 mut.toggleAll();
976 testing.expectEqual(@as(usize, 2), mut.count());
977 testing.expectEqual(false, mut.contains(.a));
978 testing.expectEqual(true, mut.contains(.b));
979 testing.expectEqual(false, mut.contains(.c));
980 testing.expectEqual(true, mut.contains(.d));
981 testing.expectEqual(false, mut.contains(.e)); // aliases a
982 {
983 var it = mut.iterator();
984 testing.expectEqual(@as(?E, .b), it.next());
985 testing.expectEqual(@as(?E, .d), it.next());
986 testing.expectEqual(@as(?E, null), it.next());
987 }
988
989 mut.toggleSet(Set.init(.{ .a=true, .b=true }));
990 testing.expectEqual(@as(usize, 2), mut.count());
991 testing.expectEqual(true, mut.contains(.a));
992 testing.expectEqual(false, mut.contains(.b));
993 testing.expectEqual(false, mut.contains(.c));
994 testing.expectEqual(true, mut.contains(.d));
995 testing.expectEqual(true, mut.contains(.e)); // aliases a
996
997 mut.setUnion(Set.init(.{ .a=true, .b=true }));
998 testing.expectEqual(@as(usize, 3), mut.count());
999 testing.expectEqual(true, mut.contains(.a));
1000 testing.expectEqual(true, mut.contains(.b));
1001 testing.expectEqual(false, mut.contains(.c));
1002 testing.expectEqual(true, mut.contains(.d));
1003
1004 mut.remove(.c);
1005 mut.remove(.b);
1006 testing.expectEqual(@as(usize, 2), mut.count());
1007 testing.expectEqual(true, mut.contains(.a));
1008 testing.expectEqual(false, mut.contains(.b));
1009 testing.expectEqual(false, mut.contains(.c));
1010 testing.expectEqual(true, mut.contains(.d));
1011
1012 mut.setIntersection(Set.init(.{ .a=true, .b=true }));
1013 testing.expectEqual(@as(usize, 1), mut.count());
1014 testing.expectEqual(true, mut.contains(.a));
1015 testing.expectEqual(false, mut.contains(.b));
1016 testing.expectEqual(false, mut.contains(.c));
1017 testing.expectEqual(false, mut.contains(.d));
1018
1019 mut.insert(.a);
1020 mut.insert(.b);
1021 testing.expectEqual(@as(usize, 2), mut.count());
1022 testing.expectEqual(true, mut.contains(.a));
1023 testing.expectEqual(true, mut.contains(.b));
1024 testing.expectEqual(false, mut.contains(.c));
1025 testing.expectEqual(false, mut.contains(.d));
1026
1027 mut.setPresent(.a, false);
1028 mut.toggle(.b);
1029 mut.toggle(.c);
1030 mut.setPresent(.d, true);
1031 testing.expectEqual(@as(usize, 2), mut.count());
1032 testing.expectEqual(false, mut.contains(.a));
1033 testing.expectEqual(false, mut.contains(.b));
1034 testing.expectEqual(true, mut.contains(.c));
1035 testing.expectEqual(true, mut.contains(.d));
1036}
1037
1038test "std.enums.EnumArray void" {
1039 const E = extern enum { a, b, c, d, e = 0 };
1040 const ArrayVoid = EnumArray(E, void);
1041 testing.expectEqual(E, ArrayVoid.Key);
1042 testing.expectEqual(EnumIndexer(E), ArrayVoid.Indexer);
1043 testing.expectEqual(void, ArrayVoid.Value);
1044 testing.expectEqual(@as(usize, 4), ArrayVoid.len);
1045
1046 const undef = ArrayVoid.initUndefined();
1047 var inst = ArrayVoid.initFill({});
1048 const inst2 = ArrayVoid.init(.{ .a = {}, .b = {}, .c = {}, .d = {} });
1049 const inst3 = ArrayVoid.initDefault({}, .{});
1050
1051 _ = inst.get(.a);
1052 _ = inst.getPtr(.b);
1053 _ = inst.getPtrConst(.c);
1054 inst.set(.a, {});
1055
1056 var it = inst.iterator();
1057 testing.expectEqual(E.a, it.next().?.key);
1058 testing.expectEqual(E.b, it.next().?.key);
1059 testing.expectEqual(E.c, it.next().?.key);
1060 testing.expectEqual(E.d, it.next().?.key);
1061 testing.expect(it.next() == null);
1062}
1063
1064test "std.enums.EnumArray sized" {
1065 const E = extern enum { a, b, c, d, e = 0 };
1066 const Array = EnumArray(E, usize);
1067 testing.expectEqual(E, Array.Key);
1068 testing.expectEqual(EnumIndexer(E), Array.Indexer);
1069 testing.expectEqual(usize, Array.Value);
1070 testing.expectEqual(@as(usize, 4), Array.len);
1071
1072 const undef = Array.initUndefined();
1073 var inst = Array.initFill(5);
1074 const inst2 = Array.init(.{ .a = 1, .b = 2, .c = 3, .d = 4 });
1075 const inst3 = Array.initDefault(6, .{.b = 4, .c = 2});
1076
1077 testing.expectEqual(@as(usize, 5), inst.get(.a));
1078 testing.expectEqual(@as(usize, 5), inst.get(.b));
1079 testing.expectEqual(@as(usize, 5), inst.get(.c));
1080 testing.expectEqual(@as(usize, 5), inst.get(.d));
1081
1082 testing.expectEqual(@as(usize, 1), inst2.get(.a));
1083 testing.expectEqual(@as(usize, 2), inst2.get(.b));
1084 testing.expectEqual(@as(usize, 3), inst2.get(.c));
1085 testing.expectEqual(@as(usize, 4), inst2.get(.d));
1086
1087 testing.expectEqual(@as(usize, 6), inst3.get(.a));
1088 testing.expectEqual(@as(usize, 4), inst3.get(.b));
1089 testing.expectEqual(@as(usize, 2), inst3.get(.c));
1090 testing.expectEqual(@as(usize, 6), inst3.get(.d));
1091
1092 testing.expectEqual(&inst.values[0], inst.getPtr(.a));
1093 testing.expectEqual(&inst.values[1], inst.getPtr(.b));
1094 testing.expectEqual(&inst.values[2], inst.getPtr(.c));
1095 testing.expectEqual(&inst.values[3], inst.getPtr(.d));
1096
1097 testing.expectEqual(@as(*const usize, &inst.values[0]), inst.getPtrConst(.a));
1098 testing.expectEqual(@as(*const usize, &inst.values[1]), inst.getPtrConst(.b));
1099 testing.expectEqual(@as(*const usize, &inst.values[2]), inst.getPtrConst(.c));
1100 testing.expectEqual(@as(*const usize, &inst.values[3]), inst.getPtrConst(.d));
1101
1102 inst.set(.c, 8);
1103 testing.expectEqual(@as(usize, 5), inst.get(.a));
1104 testing.expectEqual(@as(usize, 5), inst.get(.b));
1105 testing.expectEqual(@as(usize, 8), inst.get(.c));
1106 testing.expectEqual(@as(usize, 5), inst.get(.d));
1107
1108 var it = inst.iterator();
1109 const Entry = Array.Entry;
1110 testing.expectEqual(@as(?Entry, Entry{
1111 .key = .a,
1112 .value = &inst.values[0],
1113 }), it.next());
1114 testing.expectEqual(@as(?Entry, Entry{
1115 .key = .b,
1116 .value = &inst.values[1],
1117 }), it.next());
1118 testing.expectEqual(@as(?Entry, Entry{
1119 .key = .c,
1120 .value = &inst.values[2],
1121 }), it.next());
1122 testing.expectEqual(@as(?Entry, Entry{
1123 .key = .d,
1124 .value = &inst.values[3],
1125 }), it.next());
1126 testing.expectEqual(@as(?Entry, null), it.next());
1127}
1128
1129test "std.enums.EnumMap void" {
1130 const E = extern enum { a, b, c, d, e = 0 };
1131 const Map = EnumMap(E, void);
1132 testing.expectEqual(E, Map.Key);
1133 testing.expectEqual(EnumIndexer(E), Map.Indexer);
1134 testing.expectEqual(void, Map.Value);
1135 testing.expectEqual(@as(usize, 4), Map.len);
1136
1137 const b = Map.initFull({});
1138 testing.expectEqual(@as(usize, 4), b.count());
1139
1140 const c = Map.initFullWith(.{ .a = {}, .b = {}, .c = {}, .d = {} });
1141 testing.expectEqual(@as(usize, 4), c.count());
1142
1143 const d = Map.initFullWithDefault({}, .{ .b = {} });
1144 testing.expectEqual(@as(usize, 4), d.count());
1145
1146 var a = Map.init(.{ .b = {}, .d = {} });
1147 testing.expectEqual(@as(usize, 2), a.count());
1148 testing.expectEqual(false, a.contains(.a));
1149 testing.expectEqual(true, a.contains(.b));
1150 testing.expectEqual(false, a.contains(.c));
1151 testing.expectEqual(true, a.contains(.d));
1152 testing.expect(a.get(.a) == null);
1153 testing.expect(a.get(.b) != null);
1154 testing.expect(a.get(.c) == null);
1155 testing.expect(a.get(.d) != null);
1156 testing.expect(a.getPtr(.a) == null);
1157 testing.expect(a.getPtr(.b) != null);
1158 testing.expect(a.getPtr(.c) == null);
1159 testing.expect(a.getPtr(.d) != null);
1160 testing.expect(a.getPtrConst(.a) == null);
1161 testing.expect(a.getPtrConst(.b) != null);
1162 testing.expect(a.getPtrConst(.c) == null);
1163 testing.expect(a.getPtrConst(.d) != null);
1164 _ = a.getPtrAssertContains(.b);
1165 _ = a.getAssertContains(.d);
1166
1167 a.put(.a, {});
1168 a.put(.a, {});
1169 a.putUninitialized(.c).* = {};
1170 a.putUninitialized(.c).* = {};
1171
1172 testing.expectEqual(@as(usize, 4), a.count());
1173 testing.expect(a.get(.a) != null);
1174 testing.expect(a.get(.b) != null);
1175 testing.expect(a.get(.c) != null);
1176 testing.expect(a.get(.d) != null);
1177
1178 a.remove(.a);
1179 _ = a.fetchRemove(.c);
1180
1181 var iter = a.iterator();
1182 const Entry = Map.Entry;
1183 testing.expectEqual(E.b, iter.next().?.key);
1184 testing.expectEqual(E.d, iter.next().?.key);
1185 testing.expect(iter.next() == null);
1186}
1187
1188test "std.enums.EnumMap sized" {
1189 const E = extern enum { a, b, c, d, e = 0 };
1190 const Map = EnumMap(E, usize);
1191 testing.expectEqual(E, Map.Key);
1192 testing.expectEqual(EnumIndexer(E), Map.Indexer);
1193 testing.expectEqual(usize, Map.Value);
1194 testing.expectEqual(@as(usize, 4), Map.len);
1195
1196 const b = Map.initFull(5);
1197 testing.expectEqual(@as(usize, 4), b.count());
1198 testing.expect(b.contains(.a));
1199 testing.expect(b.contains(.b));
1200 testing.expect(b.contains(.c));
1201 testing.expect(b.contains(.d));
1202 testing.expectEqual(@as(?usize, 5), b.get(.a));
1203 testing.expectEqual(@as(?usize, 5), b.get(.b));
1204 testing.expectEqual(@as(?usize, 5), b.get(.c));
1205 testing.expectEqual(@as(?usize, 5), b.get(.d));
1206
1207 const c = Map.initFullWith(.{ .a = 1, .b = 2, .c = 3, .d = 4 });
1208 testing.expectEqual(@as(usize, 4), c.count());
1209 testing.expect(c.contains(.a));
1210 testing.expect(c.contains(.b));
1211 testing.expect(c.contains(.c));
1212 testing.expect(c.contains(.d));
1213 testing.expectEqual(@as(?usize, 1), c.get(.a));
1214 testing.expectEqual(@as(?usize, 2), c.get(.b));
1215 testing.expectEqual(@as(?usize, 3), c.get(.c));
1216 testing.expectEqual(@as(?usize, 4), c.get(.d));
1217
1218 const d = Map.initFullWithDefault(6, .{ .b = 2, .c = 4 });
1219 testing.expectEqual(@as(usize, 4), d.count());
1220 testing.expect(d.contains(.a));
1221 testing.expect(d.contains(.b));
1222 testing.expect(d.contains(.c));
1223 testing.expect(d.contains(.d));
1224 testing.expectEqual(@as(?usize, 6), d.get(.a));
1225 testing.expectEqual(@as(?usize, 2), d.get(.b));
1226 testing.expectEqual(@as(?usize, 4), d.get(.c));
1227 testing.expectEqual(@as(?usize, 6), d.get(.d));
1228
1229 var a = Map.init(.{ .b = 2, .d = 4 });
1230 testing.expectEqual(@as(usize, 2), a.count());
1231 testing.expectEqual(false, a.contains(.a));
1232 testing.expectEqual(true, a.contains(.b));
1233 testing.expectEqual(false, a.contains(.c));
1234 testing.expectEqual(true, a.contains(.d));
1235
1236 testing.expectEqual(@as(?usize, null), a.get(.a));
1237 testing.expectEqual(@as(?usize, 2), a.get(.b));
1238 testing.expectEqual(@as(?usize, null), a.get(.c));
1239 testing.expectEqual(@as(?usize, 4), a.get(.d));
1240
1241 testing.expectEqual(@as(?*usize, null), a.getPtr(.a));
1242 testing.expectEqual(@as(?*usize, &a.values[1]), a.getPtr(.b));
1243 testing.expectEqual(@as(?*usize, null), a.getPtr(.c));
1244 testing.expectEqual(@as(?*usize, &a.values[3]), a.getPtr(.d));
1245
1246 testing.expectEqual(@as(?*const usize, null), a.getPtrConst(.a));
1247 testing.expectEqual(@as(?*const usize, &a.values[1]), a.getPtrConst(.b));
1248 testing.expectEqual(@as(?*const usize, null), a.getPtrConst(.c));
1249 testing.expectEqual(@as(?*const usize, &a.values[3]), a.getPtrConst(.d));
1250
1251 testing.expectEqual(@as(*const usize, &a.values[1]), a.getPtrAssertContains(.b));
1252 testing.expectEqual(@as(*const usize, &a.values[3]), a.getPtrAssertContains(.d));
1253 testing.expectEqual(@as(usize, 2), a.getAssertContains(.b));
1254 testing.expectEqual(@as(usize, 4), a.getAssertContains(.d));
1255
1256 a.put(.a, 3);
1257 a.put(.a, 5);
1258 a.putUninitialized(.c).* = 7;
1259 a.putUninitialized(.c).* = 9;
1260
1261 testing.expectEqual(@as(usize, 4), a.count());
1262 testing.expectEqual(@as(?usize, 5), a.get(.a));
1263 testing.expectEqual(@as(?usize, 2), a.get(.b));
1264 testing.expectEqual(@as(?usize, 9), a.get(.c));
1265 testing.expectEqual(@as(?usize, 4), a.get(.d));
1266
1267 a.remove(.a);
1268 testing.expectEqual(@as(?usize, null), a.fetchRemove(.a));
1269 testing.expectEqual(@as(?usize, 9), a.fetchRemove(.c));
1270 a.remove(.c);
1271
1272 var iter = a.iterator();
1273 const Entry = Map.Entry;
1274 testing.expectEqual(@as(?Entry, Entry{
1275 .key = .b, .value = &a.values[1],
1276 }), iter.next());
1277 testing.expectEqual(@as(?Entry, Entry{
1278 .key = .d, .value = &a.values[3],
1279 }), iter.next());
1280 testing.expectEqual(@as(?Entry, null), iter.next());
1281}
lib/std/meta/trait.zig+78
......@@ -408,6 +408,84 @@ test "std.meta.trait.isTuple" {
408408 testing.expect(isTuple(@TypeOf(t3)));
409409}
410410
411/// Returns true if the passed type will coerce to []const u8.
412/// Any of the following are considered strings:
413/// ```
414/// []const u8, [:S]const u8, *const [N]u8, *const [N:S]u8,
415/// []u8, [:S]u8, *[:S]u8, *[N:S]u8.
416/// ```
417/// These types are not considered strings:
418/// ```
419/// u8, [N]u8, [*]const u8, [*:0]const u8,
420/// [*]const [N]u8, []const u16, []const i8,
421/// *const u8, ?[]const u8, ?*const [N]u8.
422/// ```
423pub fn isZigString(comptime T: type) bool {
424 comptime {
425 // Only pointer types can be strings, no optionals
426 const info = @typeInfo(T);
427 if (info != .Pointer) return false;
428
429 const ptr = &info.Pointer;
430 // Check for CV qualifiers that would prevent coerction to []const u8
431 if (ptr.is_volatile or ptr.is_allowzero) return false;
432
433 // If it's already a slice, simple check.
434 if (ptr.size == .Slice) {
435 return ptr.child == u8;
436 }
437
438 // Otherwise check if it's an array type that coerces to slice.
439 if (ptr.size == .One) {
440 const child = @typeInfo(ptr.child);
441 if (child == .Array) {
442 const arr = &child.Array;
443 return arr.child == u8;
444 }
445 }
446
447 return false;
448 }
449}
450
451test "std.meta.trait.isZigString" {
452 testing.expect(isZigString([]const u8));
453 testing.expect(isZigString([]u8));
454 testing.expect(isZigString([:0]const u8));
455 testing.expect(isZigString([:0]u8));
456 testing.expect(isZigString([:5]const u8));
457 testing.expect(isZigString([:5]u8));
458 testing.expect(isZigString(*const [0]u8));
459 testing.expect(isZigString(*[0]u8));
460 testing.expect(isZigString(*const [0:0]u8));
461 testing.expect(isZigString(*[0:0]u8));
462 testing.expect(isZigString(*const [0:5]u8));
463 testing.expect(isZigString(*[0:5]u8));
464 testing.expect(isZigString(*const [10]u8));
465 testing.expect(isZigString(*[10]u8));
466 testing.expect(isZigString(*const [10:0]u8));
467 testing.expect(isZigString(*[10:0]u8));
468 testing.expect(isZigString(*const [10:5]u8));
469 testing.expect(isZigString(*[10:5]u8));
470
471 testing.expect(!isZigString(u8));
472 testing.expect(!isZigString([4]u8));
473 testing.expect(!isZigString([4:0]u8));
474 testing.expect(!isZigString([*]const u8));
475 testing.expect(!isZigString([*]const [4]u8));
476 testing.expect(!isZigString([*c]const u8));
477 testing.expect(!isZigString([*c]const [4]u8));
478 testing.expect(!isZigString([*:0]const u8));
479 testing.expect(!isZigString([*:0]const u8));
480 testing.expect(!isZigString(*[]const u8));
481 testing.expect(!isZigString(?[]const u8));
482 testing.expect(!isZigString(?*const [4]u8));
483 testing.expect(!isZigString([]allowzero u8));
484 testing.expect(!isZigString([]volatile u8));
485 testing.expect(!isZigString(*allowzero [4]u8));
486 testing.expect(!isZigString(*volatile [4]u8));
487}
488
411489pub fn hasDecls(comptime T: type, comptime names: anytype) bool {
412490 inline for (names) |name| {
413491 if (!@hasDecl(T, name))
lib/std/std.zig+4
......@@ -20,6 +20,9 @@ pub const ComptimeStringMap = @import("comptime_string_map.zig").ComptimeStringM
2020pub const DynLib = @import("dynamic_library.zig").DynLib;
2121pub const DynamicBitSet = bit_set.DynamicBitSet;
2222pub const DynamicBitSetUnmanaged = bit_set.DynamicBitSetUnmanaged;
23pub const EnumArray = enums.EnumArray;
24pub const EnumMap = enums.EnumMap;
25pub const EnumSet = enums.EnumSet;
2326pub const HashMap = hash_map.HashMap;
2427pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;
2528pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;
......@@ -54,6 +57,7 @@ pub const cstr = @import("cstr.zig");
5457pub const debug = @import("debug.zig");
5558pub const dwarf = @import("dwarf.zig");
5659pub const elf = @import("elf.zig");
60pub const enums = @import("enums.zig");
5761pub const event = @import("event.zig");
5862pub const fifo = @import("fifo.zig");
5963pub const fmt = @import("fmt.zig");