authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-07 15:49:11+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-08 08:02:44+00:00
log17f83ace03a3bcb4f42958b43527792c186cd498
tree9d193005f50d6485b6b96fcd960e8053609e5f9a
parent229800482d28c9d55abf116cb315c78adddabe11
signaturelock-open Commit is signed but in an unrecognized format.

std.enums: remove IndexedMap, IndexedArray, IndexedSet

Searching GitHub indicated that the only use of these types in the wild is support in getty-zig, and testing for that support. This eliminates 3 more uses of usingnamespace from the standard library, and removes some unnecessarily complex generic code.

1 files changed, 715 insertions(+), 819 deletions(-)

lib/std/enums.zig+715-819
...@@ -241,957 +241,794 @@ test nameCast {...@@ -241,957 +241,794 @@ test nameCast {
241/// to dense indices. This type does no dynamic allocation and241/// to dense indices. This type does no dynamic allocation and
242/// can be copied by value.242/// can be copied by value.
243pub fn EnumSet(comptime E: type) type {243pub fn EnumSet(comptime E: type) type {
244 const mixin = struct {244 return struct {
245 fn EnumSetExt(comptime Self: type) type {245 const Self = @This();
246 const Indexer = Self.Indexer;
247 return struct {
248 /// Initializes the set using a struct of bools
249 pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self {
250 var result = Self{};
251 comptime var i: usize = 0;
252 inline while (i < Self.len) : (i += 1) {
253 const key = comptime Indexer.keyForIndex(i);
254 const tag = comptime @tagName(key);
255 if (@field(init_values, tag)) {
256 result.bits.set(i);
257 }
258 }
259 return result;
260 }
261 };
262 }
263 };
264 return IndexedSet(EnumIndexer(E), mixin.EnumSetExt);
265}
266246
267/// A map keyed by an enum, backed by a bitfield and a dense array.247 /// The indexing rules for converting between keys and indices.
268/// If the enum is not dense, a mapping will be constructed from248 pub const Indexer = EnumIndexer(E);
269/// enum values to dense indices. This type does no dynamic249 /// The element type for this set.
270/// allocation and can be copied by value.250 pub const Key = Indexer.Key;
271pub fn EnumMap(comptime E: type, comptime V: type) type {
272 const mixin = struct {
273 fn EnumMapExt(comptime Self: type) type {
274 const Indexer = Self.Indexer;
275 return struct {
276 /// Initializes the map using a sparse struct of optionals
277 pub fn init(init_values: EnumFieldStruct(E, ?V, @as(?V, null))) Self {
278 var result = Self{};
279 comptime var i: usize = 0;
280 inline while (i < Self.len) : (i += 1) {
281 const key = comptime Indexer.keyForIndex(i);
282 const tag = comptime @tagName(key);
283 if (@field(init_values, tag)) |*v| {
284 result.bits.set(i);
285 result.values[i] = v.*;
286 }
287 }
288 return result;
289 }
290 /// Initializes a full mapping with all keys set to value.
291 /// Consider using EnumArray instead if the map will remain full.
292 pub fn initFull(value: V) Self {
293 var result = Self{
294 .bits = Self.BitSet.initFull(),
295 .values = undefined,
296 };
297 @memset(&result.values, value);
298 return result;
299 }
300 /// Initializes a full mapping with supplied values.
301 /// Consider using EnumArray instead if the map will remain full.
302 pub fn initFullWith(init_values: EnumFieldStruct(E, V, @as(?V, null))) Self {
303 return initFullWithDefault(@as(?V, null), init_values);
304 }
305 /// Initializes a full mapping with a provided default.
306 /// Consider using EnumArray instead if the map will remain full.
307 pub fn initFullWithDefault(comptime default: ?V, init_values: EnumFieldStruct(E, V, default)) Self {
308 var result = Self{
309 .bits = Self.BitSet.initFull(),
310 .values = undefined,
311 };
312 comptime var i: usize = 0;
313 inline while (i < Self.len) : (i += 1) {
314 const key = comptime Indexer.keyForIndex(i);
315 const tag = comptime @tagName(key);
316 result.values[i] = @field(init_values, tag);
317 }
318 return result;
319 }
320 };
321 }
322 };
323 return IndexedMap(EnumIndexer(E), V, mixin.EnumMapExt);
324}
325251
326/// A multiset of enum elements up to a count of usize. Backed252 const BitSet = std.StaticBitSet(Indexer.count);
327/// by an EnumArray. This type does no dynamic allocation and can
328/// be copied by value.
329pub fn EnumMultiset(comptime E: type) type {
330 return BoundedEnumMultiset(E, usize);
331}
332253
333/// A multiset of enum elements up to CountSize. Backed by an254 /// The maximum number of items in this set.
334/// EnumArray. This type does no dynamic allocation and can be255 pub const len = Indexer.count;
335/// copied by value.
336pub fn BoundedEnumMultiset(comptime E: type, comptime CountSize: type) type {
337 return struct {
338 const Self = @This();
339256
340 counts: EnumArray(E, CountSize),257 bits: BitSet = BitSet.initEmpty(),
341258
342 /// Initializes the multiset using a struct of counts.259 /// Initializes the set using a struct of bools
343 pub fn init(init_counts: EnumFieldStruct(E, CountSize, 0)) Self {260 pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self {
344 var self = initWithCount(0);261 var result: Self = .{};
345 inline for (@typeInfo(E).Enum.fields) |field| {262 inline for (0..Self.len) |i| {
346 const c = @field(init_counts, field.name);263 const key = comptime Indexer.keyForIndex(i);
347 const key = @as(E, @enumFromInt(field.value));264 const tag = @tagName(key);
348 self.counts.set(key, c);265 if (@field(init_values, tag)) {
266 result.bits.set(i);
267 }
349 }268 }
350 return self;269 return result;
351 }270 }
352271
353 /// Initializes the multiset with a count of zero.272 /// Returns a set containing no keys.
354 pub fn initEmpty() Self {273 pub fn initEmpty() Self {
355 return initWithCount(0);274 return .{ .bits = BitSet.initEmpty() };
356 }275 }
357276
358 /// Initializes the multiset with all keys at the277 /// Returns a set containing all possible keys.
359 /// same count.278 pub fn initFull() Self {
360 pub fn initWithCount(comptime c: CountSize) Self {279 return .{ .bits = BitSet.initFull() };
361 return .{
362 .counts = EnumArray(E, CountSize).initDefault(c, .{}),
363 };
364 }280 }
365281
366 /// Returns the total number of key counts in the multiset.282 /// Returns a set containing multiple keys.
367 pub fn count(self: Self) usize {283 pub fn initMany(keys: []const Key) Self {
368 var sum: usize = 0;284 var set = initEmpty();
369 for (self.counts.values) |c| {285 for (keys) |key| set.insert(key);
370 sum += c;286 return set;
371 }
372 return sum;
373 }287 }
374288
375 /// Checks if at least one key in multiset.289 /// Returns a set containing a single key.
376 pub fn contains(self: Self, key: E) bool {290 pub fn initOne(key: Key) Self {
377 return self.counts.get(key) > 0;291 return initMany(&[_]Key{key});
378 }292 }
379293
380 /// Removes all instance of a key from multiset. Same as294 /// Returns the number of keys in the set.
381 /// setCount(key, 0).295 pub fn count(self: Self) usize {
382 pub fn removeAll(self: *Self, key: E) void {296 return self.bits.count();
383 return self.counts.set(key, 0);
384 }297 }
385298
386 /// Increases the key count by given amount. Caller asserts299 /// Checks if a key is in the set.
387 /// operation will not overflow.300 pub fn contains(self: Self, key: Key) bool {
388 pub fn addAssertSafe(self: *Self, key: E, c: CountSize) void {301 return self.bits.isSet(Indexer.indexOf(key));
389 self.counts.getPtr(key).* += c;
390 }302 }
391303
392 /// Increases the key count by given amount.304 /// Puts a key in the set.
393 pub fn add(self: *Self, key: E, c: CountSize) error{Overflow}!void {305 pub fn insert(self: *Self, key: Key) void {
394 self.counts.set(key, try std.math.add(CountSize, self.counts.get(key), c));306 self.bits.set(Indexer.indexOf(key));
395 }307 }
396308
397 /// Decreases the key count by given amount. If amount is309 /// Removes a key from the set.
398 /// greater than the number of keys in multset, then key count310 pub fn remove(self: *Self, key: Key) void {
399 /// will be set to zero.311 self.bits.unset(Indexer.indexOf(key));
400 pub fn remove(self: *Self, key: E, c: CountSize) void {
401 self.counts.getPtr(key).* -= @min(self.getCount(key), c);
402 }312 }
403313
404 /// Returns the count for a key.314 /// Changes the presence of a key in the set to match the passed bool.
405 pub fn getCount(self: Self, key: E) CountSize {315 pub fn setPresent(self: *Self, key: Key, present: bool) void {
406 return self.counts.get(key);316 self.bits.setValue(Indexer.indexOf(key), present);
407 }317 }
408318
409 /// Set the count for a key.319 /// Toggles the presence of a key in the set. If the key is in
410 pub fn setCount(self: *Self, key: E, c: CountSize) void {320 /// the set, removes it. Otherwise adds it.
411 self.counts.set(key, c);321 pub fn toggle(self: *Self, key: Key) void {
322 self.bits.toggle(Indexer.indexOf(key));
412 }323 }
413324
414 /// Increases the all key counts by given multiset. Caller325 /// Toggles the presence of all keys in the passed set.
415 /// asserts operation will not overflow any key.326 pub fn toggleSet(self: *Self, other: Self) void {
416 pub fn addSetAssertSafe(self: *Self, other: Self) void {327 self.bits.toggleSet(other.bits);
417 inline for (@typeInfo(E).Enum.fields) |field| {
418 const key = @as(E, @enumFromInt(field.value));
419 self.addAssertSafe(key, other.getCount(key));
420 }
421 }328 }
422329
423 /// Increases the all key counts by given multiset.330 /// Toggles all possible keys in the set.
424 pub fn addSet(self: *Self, other: Self) error{Overflow}!void {331 pub fn toggleAll(self: *Self) void {
425 inline for (@typeInfo(E).Enum.fields) |field| {332 self.bits.toggleAll();
426 const key = @as(E, @enumFromInt(field.value));
427 try self.add(key, other.getCount(key));
428 }
429 }333 }
430334
431 /// Decreases the all key counts by given multiset. If335 /// Adds all keys in the passed set to this set.
432 /// the given multiset has more key counts than this,336 pub fn setUnion(self: *Self, other: Self) void {
433 /// then that key will have a key count of zero.337 self.bits.setUnion(other.bits);
434 pub fn removeSet(self: *Self, other: Self) void {
435 inline for (@typeInfo(E).Enum.fields) |field| {
436 const key = @as(E, @enumFromInt(field.value));
437 self.remove(key, other.getCount(key));
438 }
439 }338 }
440339
441 /// Returns true iff all key counts are the same as340 /// Removes all keys which are not in the passed set.
442 /// given multiset.341 pub fn setIntersection(self: *Self, other: Self) void {
342 self.bits.setIntersection(other.bits);
343 }
344
345 /// Returns true iff both sets have the same keys.
443 pub fn eql(self: Self, other: Self) bool {346 pub fn eql(self: Self, other: Self) bool {
444 inline for (@typeInfo(E).Enum.fields) |field| {347 return self.bits.eql(other.bits);
445 const key = @as(E, @enumFromInt(field.value));
446 if (self.getCount(key) != other.getCount(key)) {
447 return false;
448 }
449 }
450 return true;
451 }348 }
452349
453 /// Returns true iff all key counts less than or350 /// Returns true iff all the keys in this set are
454 /// equal to the given multiset.351 /// in the other set. The other set may have keys
352 /// not found in this set.
455 pub fn subsetOf(self: Self, other: Self) bool {353 pub fn subsetOf(self: Self, other: Self) bool {
456 inline for (@typeInfo(E).Enum.fields) |field| {354 return self.bits.subsetOf(other.bits);
457 const key = @as(E, @enumFromInt(field.value));
458 if (self.getCount(key) > other.getCount(key)) {
459 return false;
460 }
461 }
462 return true;
463 }355 }
464356
465 /// Returns true iff all key counts greater than or357 /// Returns true iff this set contains all the keys
466 /// equal to the given multiset.358 /// in the other set. This set may have keys not
359 /// found in the other set.
467 pub fn supersetOf(self: Self, other: Self) bool {360 pub fn supersetOf(self: Self, other: Self) bool {
468 inline for (@typeInfo(E).Enum.fields) |field| {361 return self.bits.supersetOf(other.bits);
469 const key = @as(E, @enumFromInt(field.value));
470 if (self.getCount(key) < other.getCount(key)) {
471 return false;
472 }
473 }
474 return true;
475 }362 }
476363
477 /// Returns a multiset with the total key count of this364 /// Returns a set with all the keys not in this set.
478 /// multiset and the other multiset. Caller asserts365 pub fn complement(self: Self) Self {
479 /// operation will not overflow any key.366 return .{ .bits = self.bits.complement() };
480 pub fn plusAssertSafe(self: Self, other: Self) Self {
481 var result = self;
482 result.addSetAssertSafe(other);
483 return result;
484 }367 }
485368
486 /// Returns a multiset with the total key count of this369 /// Returns a set with keys that are in either this
487 /// multiset and the other multiset.370 /// set or the other set.
488 pub fn plus(self: Self, other: Self) error{Overflow}!Self {371 pub fn unionWith(self: Self, other: Self) Self {
489 var result = self;372 return .{ .bits = self.bits.unionWith(other.bits) };
490 try result.addSet(other);
491 return result;
492 }373 }
493374
494 /// Returns a multiset with the key count of this375 /// Returns a set with keys that are in both this
495 /// multiset minus the corresponding key count in the376 /// set and the other set.
496 /// other multiset. If the other multiset contains377 pub fn intersectWith(self: Self, other: Self) Self {
497 /// more key count than this set, that key will have378 return .{ .bits = self.bits.intersectWith(other.bits) };
498 /// a count of zero.
499 pub fn minus(self: Self, other: Self) Self {
500 var result = self;
501 result.removeSet(other);
502 return result;
503 }379 }
504380
505 pub const Entry = EnumArray(E, CountSize).Entry;381 /// Returns a set with keys that are in either this
506 pub const Iterator = EnumArray(E, CountSize).Iterator;382 /// set or the other set, but not both.
507383 pub fn xorWith(self: Self, other: Self) Self {
508 /// Returns an iterator over this multiset. Keys with zero384 return .{ .bits = self.bits.xorWith(other.bits) };
509 /// counts are included. Modifications to the set during
510 /// iteration may or may not be observed by the iterator,
511 /// but will not invalidate it.
512 pub fn iterator(self: *Self) Iterator {
513 return self.counts.iterator();
514 }385 }
515 };
516}
517386
518test EnumMultiset {387 /// Returns a set with keys that are in this set
519 const Ball = enum { red, green, blue };388 /// except for keys in the other set.
389 pub fn differenceWith(self: Self, other: Self) Self {
390 return .{ .bits = self.bits.differenceWith(other.bits) };
391 }
520392
521 const empty = EnumMultiset(Ball).initEmpty();393 /// Returns an iterator over this set, which iterates in
522 const r0_g1_b2 = EnumMultiset(Ball).init(.{394 /// index order. Modifications to the set during iteration
523 .red = 0,395 /// may or may not be observed by the iterator, but will
524 .green = 1,396 /// not invalidate it.
525 .blue = 2,397 pub fn iterator(self: *const Self) Iterator {
526 });398 return .{ .inner = self.bits.iterator(.{}) };
527 const ten_of_each = EnumMultiset(Ball).initWithCount(10);399 }
528
529 try testing.expectEqual(empty.count(), 0);
530 try testing.expectEqual(r0_g1_b2.count(), 3);
531 try testing.expectEqual(ten_of_each.count(), 30);
532
533 try testing.expect(!empty.contains(.red));
534 try testing.expect(!empty.contains(.green));
535 try testing.expect(!empty.contains(.blue));
536
537 try testing.expect(!r0_g1_b2.contains(.red));
538 try testing.expect(r0_g1_b2.contains(.green));
539 try testing.expect(r0_g1_b2.contains(.blue));
540
541 try testing.expect(ten_of_each.contains(.red));
542 try testing.expect(ten_of_each.contains(.green));
543 try testing.expect(ten_of_each.contains(.blue));
544
545 {
546 var copy = ten_of_each;
547 copy.removeAll(.red);
548 try testing.expect(!copy.contains(.red));
549
550 // removeAll second time does nothing
551 copy.removeAll(.red);
552 try testing.expect(!copy.contains(.red));
553 }
554400
555 {401 pub const Iterator = struct {
556 var copy = ten_of_each;402 inner: BitSet.Iterator(.{}),
557 copy.addAssertSafe(.red, 6);
558 try testing.expectEqual(copy.getCount(.red), 16);
559 }
560403
561 {404 pub fn next(self: *Iterator) ?Key {
562 var copy = ten_of_each;405 return if (self.inner.next()) |index|
563 try copy.add(.red, 6);406 Indexer.keyForIndex(index)
564 try testing.expectEqual(copy.getCount(.red), 16);407 else
408 null;
409 }
410 };
411 };
412}
565413
566 try testing.expectError(error.Overflow, copy.add(.red, std.math.maxInt(usize)));414/// A map keyed by an enum, backed by a bitfield and a dense array.
567 }415/// If the enum is not dense, a mapping will be constructed from
416/// enum values to dense indices. This type does no dynamic
417/// allocation and can be copied by value.
418pub fn EnumMap(comptime E: type, comptime V: type) type {
419 return struct {
420 const Self = @This();
568421
569 {422 /// The index mapping for this map
570 var copy = ten_of_each;423 pub const Indexer = EnumIndexer(E);
571 copy.remove(.red, 4);424 /// The key type used to index this map
572 try testing.expectEqual(copy.getCount(.red), 6);425 pub const Key = Indexer.Key;
426 /// The value type stored in this map
427 pub const Value = V;
428 /// The number of possible keys in the map
429 pub const len = Indexer.count;
573430
574 // subtracting more it contains does not underflow431 const BitSet = std.StaticBitSet(Indexer.count);
575 copy.remove(.green, 14);
576 try testing.expectEqual(copy.getCount(.green), 0);
577 }
578432
579 try testing.expectEqual(empty.getCount(.green), 0);433 /// Bits determining whether items are in the map
580 try testing.expectEqual(r0_g1_b2.getCount(.green), 1);434 bits: BitSet = BitSet.initEmpty(),
581 try testing.expectEqual(ten_of_each.getCount(.green), 10);435 /// Values of items in the map. If the associated
436 /// bit is zero, the value is undefined.
437 values: [Indexer.count]Value = undefined,
582438
583 {439 /// Initializes the map using a sparse struct of optionals
584 var copy = empty;440 pub fn init(init_values: EnumFieldStruct(E, ?Value, null)) Self {
585 copy.setCount(.red, 6);441 var result: Self = .{};
586 try testing.expectEqual(copy.getCount(.red), 6);442 inline for (0..Self.len) |i| {
587 }443 const key = comptime Indexer.keyForIndex(i);
444 const tag = @tagName(key);
445 if (@field(init_values, tag)) |*v| {
446 result.bits.set(i);
447 result.values[i] = v.*;
448 }
449 }
450 }
588451
589 {452 /// Initializes a full mapping with all keys set to value.
590 var copy = r0_g1_b2;453 /// Consider using EnumArray instead if the map will remain full.
591 copy.addSetAssertSafe(ten_of_each);454 pub fn initFull(value: Value) Self {
592 try testing.expectEqual(copy.getCount(.red), 10);455 var result: Self = .{
593 try testing.expectEqual(copy.getCount(.green), 11);456 .bits = Self.BitSet.initFull(),
594 try testing.expectEqual(copy.getCount(.blue), 12);457 .values = undefined,
595 }458 };
459 @memset(&result.values, value);
460 return result;
461 }
596462
597 {463 /// Initializes a full mapping with supplied values.
598 var copy = r0_g1_b2;464 /// Consider using EnumArray instead if the map will remain full.
599 try copy.addSet(ten_of_each);465 pub fn initFullWith(init_values: EnumFieldStruct(E, Value, null)) Self {
600 try testing.expectEqual(copy.getCount(.red), 10);466 return initFullWithDefault(null, init_values);
601 try testing.expectEqual(copy.getCount(.green), 11);467 }
602 try testing.expectEqual(copy.getCount(.blue), 12);
603468
604 const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize));469 /// Initializes a full mapping with a provided default.
605 try testing.expectError(error.Overflow, copy.addSet(full));470 /// Consider using EnumArray instead if the map will remain full.
606 }471 pub fn initFullWithDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self {
472 var result: Self = .{
473 .bits = Self.BitSet.initFull(),
474 .values = undefined,
475 };
476 inline for (0..Self.len) |i| {
477 const key = comptime Indexer.keyForIndex(i);
478 const tag = @tagName(key);
479 result.values[i] = @field(init_values, tag);
480 }
481 return result;
482 }
607483
608 {484 /// The number of items in the map.
609 var copy = ten_of_each;485 pub fn count(self: Self) usize {
610 copy.removeSet(r0_g1_b2);486 return self.bits.count();
611 try testing.expectEqual(copy.getCount(.red), 10);487 }
612 try testing.expectEqual(copy.getCount(.green), 9);
613 try testing.expectEqual(copy.getCount(.blue), 8);
614488
615 copy.removeSet(ten_of_each);489 /// Checks if the map contains an item.
616 try testing.expectEqual(copy.getCount(.red), 0);490 pub fn contains(self: Self, key: Key) bool {
617 try testing.expectEqual(copy.getCount(.green), 0);491 return self.bits.isSet(Indexer.indexOf(key));
618 try testing.expectEqual(copy.getCount(.blue), 0);492 }
619 }
620493
621 try testing.expect(empty.eql(empty));494 /// Gets the value associated with a key.
622 try testing.expect(r0_g1_b2.eql(r0_g1_b2));495 /// If the key is not in the map, returns null.
623 try testing.expect(ten_of_each.eql(ten_of_each));496 pub fn get(self: Self, key: Key) ?Value {
624 try testing.expect(!empty.eql(r0_g1_b2));497 const index = Indexer.indexOf(key);
625 try testing.expect(!r0_g1_b2.eql(ten_of_each));498 return if (self.bits.isSet(index)) self.values[index] else null;
626 try testing.expect(!ten_of_each.eql(empty));499 }
627500
628 try testing.expect(empty.subsetOf(empty));501 /// Gets the value associated with a key, which must
629 try testing.expect(r0_g1_b2.subsetOf(r0_g1_b2));502 /// exist in the map.
630 try testing.expect(empty.subsetOf(r0_g1_b2));503 pub fn getAssertContains(self: Self, key: Key) Value {
631 try testing.expect(r0_g1_b2.subsetOf(ten_of_each));504 const index = Indexer.indexOf(key);
632 try testing.expect(!ten_of_each.subsetOf(r0_g1_b2));505 assert(self.bits.isSet(index));
633 try testing.expect(!r0_g1_b2.subsetOf(empty));506 return self.values[index];
507 }
634508
635 try testing.expect(empty.supersetOf(empty));509 /// Gets the address of the value associated with a key.
636 try testing.expect(r0_g1_b2.supersetOf(r0_g1_b2));510 /// If the key is not in the map, returns null.
637 try testing.expect(r0_g1_b2.supersetOf(empty));511 pub fn getPtr(self: *Self, key: Key) ?*Value {
638 try testing.expect(ten_of_each.supersetOf(r0_g1_b2));512 const index = Indexer.indexOf(key);
639 try testing.expect(!r0_g1_b2.supersetOf(ten_of_each));513 return if (self.bits.isSet(index)) &self.values[index] else null;
640 try testing.expect(!empty.supersetOf(r0_g1_b2));514 }
641515
642 {516 /// Gets the address of the const value associated with a key.
643 // with multisets it could be the case where two517 /// If the key is not in the map, returns null.
644 // multisets are neither subset nor superset of each518 pub fn getPtrConst(self: *const Self, key: Key) ?*const Value {
645 // other.519 const index = Indexer.indexOf(key);
520 return if (self.bits.isSet(index)) &self.values[index] else null;
521 }
646522
647 const r10 = EnumMultiset(Ball).init(.{523 /// Gets the address of the value associated with a key.
648 .red = 10,524 /// The key must be present in the map.
649 });525 pub fn getPtrAssertContains(self: *Self, key: Key) *Value {
650 const b10 = EnumMultiset(Ball).init(.{526 const index = Indexer.indexOf(key);
651 .blue = 10,527 assert(self.bits.isSet(index));
652 });528 return &self.values[index];
529 }
653530
654 try testing.expect(!r10.subsetOf(b10));531 /// Gets the address of the const value associated with a key.
655 try testing.expect(!b10.subsetOf(r10));532 /// The key must be present in the map.
656 try testing.expect(!r10.supersetOf(b10));533 pub fn getPtrConstAssertContains(self: *const Self, key: Key) *const Value {
657 try testing.expect(!b10.supersetOf(r10));534 const index = Indexer.indexOf(key);
658 }535 assert(self.bits.isSet(index));
536 return &self.values[index];
537 }
659538
660 {539 /// Adds the key to the map with the supplied value.
661 const result = r0_g1_b2.plusAssertSafe(ten_of_each);540 /// If the key is already in the map, overwrites the value.
662 try testing.expectEqual(result.getCount(.red), 10);541 pub fn put(self: *Self, key: Key, value: Value) void {
663 try testing.expectEqual(result.getCount(.green), 11);542 const index = Indexer.indexOf(key);
664 try testing.expectEqual(result.getCount(.blue), 12);543 self.bits.set(index);
665 }544 self.values[index] = value;
545 }
666546
667 {547 /// Adds the key to the map with an undefined value.
668 const result = try r0_g1_b2.plus(ten_of_each);548 /// If the key is already in the map, the value becomes undefined.
669 try testing.expectEqual(result.getCount(.red), 10);549 /// A pointer to the value is returned, which should be
670 try testing.expectEqual(result.getCount(.green), 11);550 /// used to initialize the value.
671 try testing.expectEqual(result.getCount(.blue), 12);551 pub fn putUninitialized(self: *Self, key: Key) *Value {
552 const index = Indexer.indexOf(key);
553 self.bits.set(index);
554 self.values[index] = undefined;
555 return &self.values[index];
556 }
672557
673 const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize));558 /// Sets the value associated with the key in the map,
674 try testing.expectError(error.Overflow, result.plus(full));559 /// and returns the old value. If the key was not in
675 }560 /// the map, returns null.
561 pub fn fetchPut(self: *Self, key: Key, value: Value) ?Value {
562 const index = Indexer.indexOf(key);
563 const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;
564 self.bits.set(index);
565 self.values[index] = value;
566 return result;
567 }
676568
677 {569 /// Removes a key from the map. If the key was not in the map,
678 const result = ten_of_each.minus(r0_g1_b2);570 /// does nothing.
679 try testing.expectEqual(result.getCount(.red), 10);571 pub fn remove(self: *Self, key: Key) void {
680 try testing.expectEqual(result.getCount(.green), 9);572 const index = Indexer.indexOf(key);
681 try testing.expectEqual(result.getCount(.blue), 8);573 self.bits.unset(index);
682 }574 self.values[index] = undefined;
575 }
683576
684 {577 /// Removes a key from the map, and returns the old value.
685 const result = ten_of_each.minus(r0_g1_b2).minus(ten_of_each);578 /// If the key was not in the map, returns null.
686 try testing.expectEqual(result.getCount(.red), 0);579 pub fn fetchRemove(self: *Self, key: Key) ?Value {
687 try testing.expectEqual(result.getCount(.green), 0);580 const index = Indexer.indexOf(key);
688 try testing.expectEqual(result.getCount(.blue), 0);581 const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;
689 }582 self.bits.unset(index);
583 self.values[index] = undefined;
584 return result;
585 }
690586
691 {587 /// Returns an iterator over the map, which visits items in index order.
692 var copy = empty;588 /// Modifications to the underlying map may or may not be observed by
693 var it = copy.iterator();589 /// the iterator, but will not invalidate it.
694 var entry = it.next().?;590 pub fn iterator(self: *Self) Iterator {
695 try testing.expectEqual(entry.key, .red);591 return .{
696 try testing.expectEqual(entry.value.*, 0);592 .inner = self.bits.iterator(.{}),
697 entry = it.next().?;593 .values = &self.values,
698 try testing.expectEqual(entry.key, .green);594 };
699 try testing.expectEqual(entry.value.*, 0);595 }
700 entry = it.next().?;
701 try testing.expectEqual(entry.key, .blue);
702 try testing.expectEqual(entry.value.*, 0);
703 try testing.expectEqual(it.next(), null);
704 }
705596
706 {597 /// An entry in the map.
707 var copy = r0_g1_b2;598 pub const Entry = struct {
708 var it = copy.iterator();599 /// The key associated with this entry.
709 var entry = it.next().?;600 /// Modifying this key will not change the map.
710 try testing.expectEqual(entry.key, .red);601 key: Key,
711 try testing.expectEqual(entry.value.*, 0);
712 entry = it.next().?;
713 try testing.expectEqual(entry.key, .green);
714 try testing.expectEqual(entry.value.*, 1);
715 entry = it.next().?;
716 try testing.expectEqual(entry.key, .blue);
717 try testing.expectEqual(entry.value.*, 2);
718 try testing.expectEqual(it.next(), null);
719 }
720}
721602
722/// An array keyed by an enum, backed by a dense array.603 /// A pointer to the value in the map associated
723/// If the enum is not dense, a mapping will be constructed from604 /// with this key. Modifications through this
724/// enum values to dense indices. This type does no dynamic605 /// pointer will modify the underlying data.
725/// allocation and can be copied by value.606 value: *Value,
726pub fn EnumArray(comptime E: type, comptime V: type) type {607 };
727 const mixin = struct {608
728 fn EnumArrayExt(comptime Self: type) type {609 pub const Iterator = struct {
729 const Indexer = Self.Indexer;610 inner: BitSet.Iterator(.{}),
730 return struct {611 values: *[Indexer.count]Value,
731 /// Initializes all values in the enum array
732 pub fn init(init_values: EnumFieldStruct(E, V, @as(?V, null))) Self {
733 return initDefault(@as(?V, null), init_values);
734 }
735612
736 /// Initializes values in the enum array, with the specified default.613 pub fn next(self: *Iterator) ?Entry {
737 pub fn initDefault(comptime default: ?V, init_values: EnumFieldStruct(E, V, default)) Self {614 return if (self.inner.next()) |index|
738 var result = Self{ .values = undefined };615 Entry{
739 comptime var i: usize = 0;616 .key = Indexer.keyForIndex(index),
740 inline while (i < Self.len) : (i += 1) {617 .value = &self.values[index],
741 const key = comptime Indexer.keyForIndex(i);
742 const tag = @tagName(key);
743 result.values[i] = @field(init_values, tag);
744 }618 }
745 return result;619 else
746 }620 null;
747 };621 }
748 }622 };
749 };623 };
750 return IndexedArray(EnumIndexer(E), V, mixin.EnumArrayExt);
751}624}
752625
753fn NoExtension(comptime Self: type) type {626/// A multiset of enum elements up to a count of usize. Backed
754 _ = Self;627/// by an EnumArray. This type does no dynamic allocation and can
755 return NoExt;628/// be copied by value.
629pub fn EnumMultiset(comptime E: type) type {
630 return BoundedEnumMultiset(E, usize);
756}631}
757const NoExt = struct {};
758632
759/// A set type with an Indexer mapping from keys to indices.633/// A multiset of enum elements up to CountSize. Backed by an
760/// Presence or absence is stored as a dense bitfield. This634/// EnumArray. This type does no dynamic allocation and can be
761/// type does no allocation and can be copied by value.635/// copied by value.
762pub fn IndexedSet(comptime I: type, comptime Ext: ?fn (type) type) type {636pub fn BoundedEnumMultiset(comptime E: type, comptime CountSize: type) type {
763 comptime ensureIndexer(I);
764 return struct {637 return struct {
765 const Self = @This();638 const Self = @This();
766639
767 pub usingnamespace (Ext orelse NoExtension)(Self);640 counts: EnumArray(E, CountSize),
768
769 /// The indexing rules for converting between keys and indices.
770 pub const Indexer = I;
771 /// The element type for this set.
772 pub const Key = Indexer.Key;
773
774 const BitSet = std.StaticBitSet(Indexer.count);
775
776 /// The maximum number of items in this set.
777 pub const len = Indexer.count;
778
779 bits: BitSet = BitSet.initEmpty(),
780641
781 /// Returns a set containing no keys.642 /// Initializes the multiset using a struct of counts.
782 pub fn initEmpty() Self {643 pub fn init(init_counts: EnumFieldStruct(E, CountSize, 0)) Self {
783 return .{ .bits = BitSet.initEmpty() };644 var self = initWithCount(0);
645 inline for (@typeInfo(E).Enum.fields) |field| {
646 const c = @field(init_counts, field.name);
647 const key = @as(E, @enumFromInt(field.value));
648 self.counts.set(key, c);
649 }
650 return self;
784 }651 }
785652
786 /// Returns a set containing all possible keys.653 /// Initializes the multiset with a count of zero.
787 pub fn initFull() Self {654 pub fn initEmpty() Self {
788 return .{ .bits = BitSet.initFull() };655 return initWithCount(0);
789 }656 }
790657
791 /// Returns a set containing multiple keys.658 /// Initializes the multiset with all keys at the
792 pub fn initMany(keys: []const Key) Self {659 /// same count.
793 var set = initEmpty();660 pub fn initWithCount(comptime c: CountSize) Self {
794 for (keys) |key| set.insert(key);661 return .{
795 return set;662 .counts = EnumArray(E, CountSize).initDefault(c, .{}),
663 };
796 }664 }
797665
798 /// Returns a set containing a single key.666 /// Returns the total number of key counts in the multiset.
799 pub fn initOne(key: Key) Self {667 pub fn count(self: Self) usize {
800 return initMany(&[_]Key{key});668 var sum: usize = 0;
669 for (self.counts.values) |c| {
670 sum += c;
671 }
672 return sum;
801 }673 }
802674
803 /// Returns the number of keys in the set.675 /// Checks if at least one key in multiset.
804 pub fn count(self: Self) usize {676 pub fn contains(self: Self, key: E) bool {
805 return self.bits.count();677 return self.counts.get(key) > 0;
806 }678 }
807679
808 /// Checks if a key is in the set.680 /// Removes all instance of a key from multiset. Same as
809 pub fn contains(self: Self, key: Key) bool {681 /// setCount(key, 0).
810 return self.bits.isSet(Indexer.indexOf(key));682 pub fn removeAll(self: *Self, key: E) void {
683 return self.counts.set(key, 0);
811 }684 }
812685
813 /// Puts a key in the set.686 /// Increases the key count by given amount. Caller asserts
814 pub fn insert(self: *Self, key: Key) void {687 /// operation will not overflow.
815 self.bits.set(Indexer.indexOf(key));688 pub fn addAssertSafe(self: *Self, key: E, c: CountSize) void {
689 self.counts.getPtr(key).* += c;
816 }690 }
817691
818 /// Removes a key from the set.692 /// Increases the key count by given amount.
819 pub fn remove(self: *Self, key: Key) void {693 pub fn add(self: *Self, key: E, c: CountSize) error{Overflow}!void {
820 self.bits.unset(Indexer.indexOf(key));694 self.counts.set(key, try std.math.add(CountSize, self.counts.get(key), c));
821 }695 }
822696
823 /// Changes the presence of a key in the set to match the passed bool.697 /// Decreases the key count by given amount. If amount is
824 pub fn setPresent(self: *Self, key: Key, present: bool) void {698 /// greater than the number of keys in multset, then key count
825 self.bits.setValue(Indexer.indexOf(key), present);699 /// will be set to zero.
700 pub fn remove(self: *Self, key: E, c: CountSize) void {
701 self.counts.getPtr(key).* -= @min(self.getCount(key), c);
826 }702 }
827703
828 /// Toggles the presence of a key in the set. If the key is in704 /// Returns the count for a key.
829 /// the set, removes it. Otherwise adds it.705 pub fn getCount(self: Self, key: E) CountSize {
830 pub fn toggle(self: *Self, key: Key) void {706 return self.counts.get(key);
831 self.bits.toggle(Indexer.indexOf(key));
832 }707 }
833708
834 /// Toggles the presence of all keys in the passed set.709 /// Set the count for a key.
835 pub fn toggleSet(self: *Self, other: Self) void {710 pub fn setCount(self: *Self, key: E, c: CountSize) void {
836 self.bits.toggleSet(other.bits);711 self.counts.set(key, c);
837 }712 }
838713
839 /// Toggles all possible keys in the set.714 /// Increases the all key counts by given multiset. Caller
840 pub fn toggleAll(self: *Self) void {715 /// asserts operation will not overflow any key.
841 self.bits.toggleAll();716 pub fn addSetAssertSafe(self: *Self, other: Self) void {
717 inline for (@typeInfo(E).Enum.fields) |field| {
718 const key = @as(E, @enumFromInt(field.value));
719 self.addAssertSafe(key, other.getCount(key));
720 }
842 }721 }
843722
844 /// Adds all keys in the passed set to this set.723 /// Increases the all key counts by given multiset.
845 pub fn setUnion(self: *Self, other: Self) void {724 pub fn addSet(self: *Self, other: Self) error{Overflow}!void {
846 self.bits.setUnion(other.bits);725 inline for (@typeInfo(E).Enum.fields) |field| {
726 const key = @as(E, @enumFromInt(field.value));
727 try self.add(key, other.getCount(key));
728 }
847 }729 }
848730
849 /// Removes all keys which are not in the passed set.731 /// Decreases the all key counts by given multiset. If
850 pub fn setIntersection(self: *Self, other: Self) void {732 /// the given multiset has more key counts than this,
851 self.bits.setIntersection(other.bits);733 /// then that key will have a key count of zero.
734 pub fn removeSet(self: *Self, other: Self) void {
735 inline for (@typeInfo(E).Enum.fields) |field| {
736 const key = @as(E, @enumFromInt(field.value));
737 self.remove(key, other.getCount(key));
738 }
852 }739 }
853740
854 /// Returns true iff both sets have the same keys.741 /// Returns true iff all key counts are the same as
742 /// given multiset.
855 pub fn eql(self: Self, other: Self) bool {743 pub fn eql(self: Self, other: Self) bool {
856 return self.bits.eql(other.bits);744 inline for (@typeInfo(E).Enum.fields) |field| {
745 const key = @as(E, @enumFromInt(field.value));
746 if (self.getCount(key) != other.getCount(key)) {
747 return false;
748 }
749 }
750 return true;
857 }751 }
858752
859 /// Returns true iff all the keys in this set are753 /// Returns true iff all key counts less than or
860 /// in the other set. The other set may have keys754 /// equal to the given multiset.
861 /// not found in this set.
862 pub fn subsetOf(self: Self, other: Self) bool {755 pub fn subsetOf(self: Self, other: Self) bool {
863 return self.bits.subsetOf(other.bits);756 inline for (@typeInfo(E).Enum.fields) |field| {
757 const key = @as(E, @enumFromInt(field.value));
758 if (self.getCount(key) > other.getCount(key)) {
759 return false;
760 }
761 }
762 return true;
864 }763 }
865764
866 /// Returns true iff this set contains all the keys765 /// Returns true iff all key counts greater than or
867 /// in the other set. This set may have keys not766 /// equal to the given multiset.
868 /// found in the other set.
869 pub fn supersetOf(self: Self, other: Self) bool {767 pub fn supersetOf(self: Self, other: Self) bool {
870 return self.bits.supersetOf(other.bits);768 inline for (@typeInfo(E).Enum.fields) |field| {
871 }769 const key = @as(E, @enumFromInt(field.value));
872770 if (self.getCount(key) < other.getCount(key)) {
873 /// Returns a set with all the keys not in this set.771 return false;
874 pub fn complement(self: Self) Self {772 }
875 return .{ .bits = self.bits.complement() };773 }
876 }774 return true;
877
878 /// Returns a set with keys that are in either this
879 /// set or the other set.
880 pub fn unionWith(self: Self, other: Self) Self {
881 return .{ .bits = self.bits.unionWith(other.bits) };
882 }
883
884 /// Returns a set with keys that are in both this
885 /// set and the other set.
886 pub fn intersectWith(self: Self, other: Self) Self {
887 return .{ .bits = self.bits.intersectWith(other.bits) };
888 }775 }
889776
890 /// Returns a set with keys that are in either this777 /// Returns a multiset with the total key count of this
891 /// set or the other set, but not both.778 /// multiset and the other multiset. Caller asserts
892 pub fn xorWith(self: Self, other: Self) Self {779 /// operation will not overflow any key.
893 return .{ .bits = self.bits.xorWith(other.bits) };780 pub fn plusAssertSafe(self: Self, other: Self) Self {
781 var result = self;
782 result.addSetAssertSafe(other);
783 return result;
894 }784 }
895785
896 /// Returns a set with keys that are in this set786 /// Returns a multiset with the total key count of this
897 /// except for keys in the other set.787 /// multiset and the other multiset.
898 pub fn differenceWith(self: Self, other: Self) Self {788 pub fn plus(self: Self, other: Self) error{Overflow}!Self {
899 return .{ .bits = self.bits.differenceWith(other.bits) };789 var result = self;
790 try result.addSet(other);
791 return result;
900 }792 }
901793
902 /// Returns an iterator over this set, which iterates in794 /// Returns a multiset with the key count of this
903 /// index order. Modifications to the set during iteration795 /// multiset minus the corresponding key count in the
904 /// may or may not be observed by the iterator, but will796 /// other multiset. If the other multiset contains
905 /// not invalidate it.797 /// more key count than this set, that key will have
906 pub fn iterator(self: *const Self) Iterator {798 /// a count of zero.
907 return .{ .inner = self.bits.iterator(.{}) };799 pub fn minus(self: Self, other: Self) Self {
800 var result = self;
801 result.removeSet(other);
802 return result;
908 }803 }
909804
910 pub const Iterator = struct {805 pub const Entry = EnumArray(E, CountSize).Entry;
911 inner: BitSet.Iterator(.{}),806 pub const Iterator = EnumArray(E, CountSize).Iterator;
912807
913 pub fn next(self: *Iterator) ?Key {808 /// Returns an iterator over this multiset. Keys with zero
914 return if (self.inner.next()) |index|809 /// counts are included. Modifications to the set during
915 Indexer.keyForIndex(index)810 /// iteration may or may not be observed by the iterator,
916 else811 /// but will not invalidate it.
917 null;812 pub fn iterator(self: *Self) Iterator {
918 }813 return self.counts.iterator();
919 };814 }
920 };815 };
921}816}
922817
923test "pure EnumSet fns" {818test EnumMultiset {
924 const Suit = enum { spades, hearts, clubs, diamonds };819 const Ball = enum { red, green, blue };
925
926 const empty = EnumSet(Suit).initEmpty();
927 const full = EnumSet(Suit).initFull();
928 const black = EnumSet(Suit).initMany(&[_]Suit{ .spades, .clubs });
929 const red = EnumSet(Suit).initMany(&[_]Suit{ .hearts, .diamonds });
930
931 try testing.expect(empty.eql(empty));
932 try testing.expect(full.eql(full));
933 try testing.expect(!empty.eql(full));
934 try testing.expect(!full.eql(empty));
935 try testing.expect(!empty.eql(black));
936 try testing.expect(!full.eql(red));
937 try testing.expect(!red.eql(empty));
938 try testing.expect(!black.eql(full));
939
940 try testing.expect(empty.subsetOf(empty));
941 try testing.expect(empty.subsetOf(full));
942 try testing.expect(full.subsetOf(full));
943 try testing.expect(!black.subsetOf(red));
944 try testing.expect(!red.subsetOf(black));
945
946 try testing.expect(full.supersetOf(full));
947 try testing.expect(full.supersetOf(empty));
948 try testing.expect(empty.supersetOf(empty));
949 try testing.expect(!black.supersetOf(red));
950 try testing.expect(!red.supersetOf(black));
951
952 try testing.expect(empty.complement().eql(full));
953 try testing.expect(full.complement().eql(empty));
954 try testing.expect(black.complement().eql(red));
955 try testing.expect(red.complement().eql(black));
956820
957 try testing.expect(empty.unionWith(empty).eql(empty));821 const empty = EnumMultiset(Ball).initEmpty();
958 try testing.expect(empty.unionWith(full).eql(full));822 const r0_g1_b2 = EnumMultiset(Ball).init(.{
959 try testing.expect(full.unionWith(full).eql(full));823 .red = 0,
960 try testing.expect(full.unionWith(empty).eql(full));824 .green = 1,
961 try testing.expect(black.unionWith(red).eql(full));825 .blue = 2,
962 try testing.expect(red.unionWith(black).eql(full));826 });
827 const ten_of_each = EnumMultiset(Ball).initWithCount(10);
963828
964 try testing.expect(empty.intersectWith(empty).eql(empty));829 try testing.expectEqual(empty.count(), 0);
965 try testing.expect(empty.intersectWith(full).eql(empty));830 try testing.expectEqual(r0_g1_b2.count(), 3);
966 try testing.expect(full.intersectWith(full).eql(full));831 try testing.expectEqual(ten_of_each.count(), 30);
967 try testing.expect(full.intersectWith(empty).eql(empty));
968 try testing.expect(black.intersectWith(red).eql(empty));
969 try testing.expect(red.intersectWith(black).eql(empty));
970832
971 try testing.expect(empty.xorWith(empty).eql(empty));833 try testing.expect(!empty.contains(.red));
972 try testing.expect(empty.xorWith(full).eql(full));834 try testing.expect(!empty.contains(.green));
973 try testing.expect(full.xorWith(full).eql(empty));835 try testing.expect(!empty.contains(.blue));
974 try testing.expect(full.xorWith(empty).eql(full));
975 try testing.expect(black.xorWith(red).eql(full));
976 try testing.expect(red.xorWith(black).eql(full));
977836
978 try testing.expect(empty.differenceWith(empty).eql(empty));837 try testing.expect(!r0_g1_b2.contains(.red));
979 try testing.expect(empty.differenceWith(full).eql(empty));838 try testing.expect(r0_g1_b2.contains(.green));
980 try testing.expect(full.differenceWith(full).eql(empty));839 try testing.expect(r0_g1_b2.contains(.blue));
981 try testing.expect(full.differenceWith(empty).eql(full));
982 try testing.expect(full.differenceWith(red).eql(black));
983 try testing.expect(full.differenceWith(black).eql(red));
984}
985840
986test "EnumSet empty" {841 try testing.expect(ten_of_each.contains(.red));
987 const E = enum {};842 try testing.expect(ten_of_each.contains(.green));
988 const empty = EnumSet(E).initEmpty();843 try testing.expect(ten_of_each.contains(.blue));
989 const full = EnumSet(E).initFull();
990844
991 try std.testing.expect(empty.eql(full));845 {
992 try std.testing.expect(empty.complement().eql(full));846 var copy = ten_of_each;
993 try std.testing.expect(empty.complement().eql(full.complement()));847 copy.removeAll(.red);
994 try std.testing.expect(empty.eql(full.complement()));848 try testing.expect(!copy.contains(.red));
995}
996849
997test "EnumSet const iterator" {850 // removeAll second time does nothing
998 const Direction = enum { up, down, left, right };851 copy.removeAll(.red);
999 const diag_move = init: {852 try testing.expect(!copy.contains(.red));
1000 var move = EnumSet(Direction).initEmpty();853 }
1001 move.insert(.right);
1002 move.insert(.up);
1003 break :init move;
1004 };
1005854
1006 var result = EnumSet(Direction).initEmpty();855 {
1007 var it = diag_move.iterator();856 var copy = ten_of_each;
1008 while (it.next()) |dir| {857 copy.addAssertSafe(.red, 6);
1009 result.insert(dir);858 try testing.expectEqual(copy.getCount(.red), 16);
1010 }859 }
1011860
1012 try testing.expect(result.eql(diag_move));861 {
1013}862 var copy = ten_of_each;
863 try copy.add(.red, 6);
864 try testing.expectEqual(copy.getCount(.red), 16);
1014865
1015/// A map from keys to values, using an index lookup. Uses a866 try testing.expectError(error.Overflow, copy.add(.red, std.math.maxInt(usize)));
1016/// bitfield to track presence and a dense array of values.867 }
1017/// This type does no allocation and can be copied by value.
1018pub fn IndexedMap(comptime I: type, comptime V: type, comptime Ext: ?fn (type) type) type {
1019 comptime ensureIndexer(I);
1020 return struct {
1021 const Self = @This();
1022868
1023 pub usingnamespace (Ext orelse NoExtension)(Self);869 {
870 var copy = ten_of_each;
871 copy.remove(.red, 4);
872 try testing.expectEqual(copy.getCount(.red), 6);
1024873
1025 /// The index mapping for this map874 // subtracting more it contains does not underflow
1026 pub const Indexer = I;875 copy.remove(.green, 14);
1027 /// The key type used to index this map876 try testing.expectEqual(copy.getCount(.green), 0);
1028 pub const Key = Indexer.Key;877 }
1029 /// The value type stored in this map
1030 pub const Value = V;
1031 /// The number of possible keys in the map
1032 pub const len = Indexer.count;
1033878
1034 const BitSet = std.StaticBitSet(Indexer.count);879 try testing.expectEqual(empty.getCount(.green), 0);
880 try testing.expectEqual(r0_g1_b2.getCount(.green), 1);
881 try testing.expectEqual(ten_of_each.getCount(.green), 10);
1035882
1036 /// Bits determining whether items are in the map883 {
1037 bits: BitSet = BitSet.initEmpty(),884 var copy = empty;
1038 /// Values of items in the map. If the associated885 copy.setCount(.red, 6);
1039 /// bit is zero, the value is undefined.886 try testing.expectEqual(copy.getCount(.red), 6);
1040 values: [Indexer.count]Value = undefined,887 }
1041888
1042 /// The number of items in the map.889 {
1043 pub fn count(self: Self) usize {890 var copy = r0_g1_b2;
1044 return self.bits.count();891 copy.addSetAssertSafe(ten_of_each);
1045 }892 try testing.expectEqual(copy.getCount(.red), 10);
893 try testing.expectEqual(copy.getCount(.green), 11);
894 try testing.expectEqual(copy.getCount(.blue), 12);
895 }
1046896
1047 /// Checks if the map contains an item.897 {
1048 pub fn contains(self: Self, key: Key) bool {898 var copy = r0_g1_b2;
1049 return self.bits.isSet(Indexer.indexOf(key));899 try copy.addSet(ten_of_each);
1050 }900 try testing.expectEqual(copy.getCount(.red), 10);
901 try testing.expectEqual(copy.getCount(.green), 11);
902 try testing.expectEqual(copy.getCount(.blue), 12);
1051903
1052 /// Gets the value associated with a key.904 const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize));
1053 /// If the key is not in the map, returns null.905 try testing.expectError(error.Overflow, copy.addSet(full));
1054 pub fn get(self: Self, key: Key) ?Value {906 }
1055 const index = Indexer.indexOf(key);
1056 return if (self.bits.isSet(index)) self.values[index] else null;
1057 }
1058907
1059 /// Gets the value associated with a key, which must908 {
1060 /// exist in the map.909 var copy = ten_of_each;
1061 pub fn getAssertContains(self: Self, key: Key) Value {910 copy.removeSet(r0_g1_b2);
1062 const index = Indexer.indexOf(key);911 try testing.expectEqual(copy.getCount(.red), 10);
1063 assert(self.bits.isSet(index));912 try testing.expectEqual(copy.getCount(.green), 9);
1064 return self.values[index];913 try testing.expectEqual(copy.getCount(.blue), 8);
1065 }
1066914
1067 /// Gets the address of the value associated with a key.915 copy.removeSet(ten_of_each);
1068 /// If the key is not in the map, returns null.916 try testing.expectEqual(copy.getCount(.red), 0);
1069 pub fn getPtr(self: *Self, key: Key) ?*Value {917 try testing.expectEqual(copy.getCount(.green), 0);
1070 const index = Indexer.indexOf(key);918 try testing.expectEqual(copy.getCount(.blue), 0);
1071 return if (self.bits.isSet(index)) &self.values[index] else null;919 }
1072 }
1073920
1074 /// Gets the address of the const value associated with a key.921 try testing.expect(empty.eql(empty));
1075 /// If the key is not in the map, returns null.922 try testing.expect(r0_g1_b2.eql(r0_g1_b2));
1076 pub fn getPtrConst(self: *const Self, key: Key) ?*const Value {923 try testing.expect(ten_of_each.eql(ten_of_each));
1077 const index = Indexer.indexOf(key);924 try testing.expect(!empty.eql(r0_g1_b2));
1078 return if (self.bits.isSet(index)) &self.values[index] else null;925 try testing.expect(!r0_g1_b2.eql(ten_of_each));
1079 }926 try testing.expect(!ten_of_each.eql(empty));
1080927
1081 /// Gets the address of the value associated with a key.928 try testing.expect(empty.subsetOf(empty));
1082 /// The key must be present in the map.929 try testing.expect(r0_g1_b2.subsetOf(r0_g1_b2));
1083 pub fn getPtrAssertContains(self: *Self, key: Key) *Value {930 try testing.expect(empty.subsetOf(r0_g1_b2));
1084 const index = Indexer.indexOf(key);931 try testing.expect(r0_g1_b2.subsetOf(ten_of_each));
1085 assert(self.bits.isSet(index));932 try testing.expect(!ten_of_each.subsetOf(r0_g1_b2));
1086 return &self.values[index];933 try testing.expect(!r0_g1_b2.subsetOf(empty));
1087 }
1088934
1089 /// Gets the address of the const value associated with a key.935 try testing.expect(empty.supersetOf(empty));
1090 /// The key must be present in the map.936 try testing.expect(r0_g1_b2.supersetOf(r0_g1_b2));
1091 pub fn getPtrConstAssertContains(self: *const Self, key: Key) *const Value {937 try testing.expect(r0_g1_b2.supersetOf(empty));
1092 const index = Indexer.indexOf(key);938 try testing.expect(ten_of_each.supersetOf(r0_g1_b2));
1093 assert(self.bits.isSet(index));939 try testing.expect(!r0_g1_b2.supersetOf(ten_of_each));
1094 return &self.values[index];940 try testing.expect(!empty.supersetOf(r0_g1_b2));
1095 }
1096941
1097 /// Adds the key to the map with the supplied value.942 {
1098 /// If the key is already in the map, overwrites the value.943 // with multisets it could be the case where two
1099 pub fn put(self: *Self, key: Key, value: Value) void {944 // multisets are neither subset nor superset of each
1100 const index = Indexer.indexOf(key);945 // other.
1101 self.bits.set(index);
1102 self.values[index] = value;
1103 }
1104946
1105 /// Adds the key to the map with an undefined value.947 const r10 = EnumMultiset(Ball).init(.{
1106 /// If the key is already in the map, the value becomes undefined.948 .red = 10,
1107 /// A pointer to the value is returned, which should be949 });
1108 /// used to initialize the value.950 const b10 = EnumMultiset(Ball).init(.{
1109 pub fn putUninitialized(self: *Self, key: Key) *Value {951 .blue = 10,
1110 const index = Indexer.indexOf(key);952 });
1111 self.bits.set(index);
1112 self.values[index] = undefined;
1113 return &self.values[index];
1114 }
1115953
1116 /// Sets the value associated with the key in the map,954 try testing.expect(!r10.subsetOf(b10));
1117 /// and returns the old value. If the key was not in955 try testing.expect(!b10.subsetOf(r10));
1118 /// the map, returns null.956 try testing.expect(!r10.supersetOf(b10));
1119 pub fn fetchPut(self: *Self, key: Key, value: Value) ?Value {957 try testing.expect(!b10.supersetOf(r10));
1120 const index = Indexer.indexOf(key);958 }
1121 const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;
1122 self.bits.set(index);
1123 self.values[index] = value;
1124 return result;
1125 }
1126959
1127 /// Removes a key from the map. If the key was not in the map,960 {
1128 /// does nothing.961 const result = r0_g1_b2.plusAssertSafe(ten_of_each);
1129 pub fn remove(self: *Self, key: Key) void {962 try testing.expectEqual(result.getCount(.red), 10);
1130 const index = Indexer.indexOf(key);963 try testing.expectEqual(result.getCount(.green), 11);
1131 self.bits.unset(index);964 try testing.expectEqual(result.getCount(.blue), 12);
1132 self.values[index] = undefined;965 }
1133 }
1134966
1135 /// Removes a key from the map, and returns the old value.967 {
1136 /// If the key was not in the map, returns null.968 const result = try r0_g1_b2.plus(ten_of_each);
1137 pub fn fetchRemove(self: *Self, key: Key) ?Value {969 try testing.expectEqual(result.getCount(.red), 10);
1138 const index = Indexer.indexOf(key);970 try testing.expectEqual(result.getCount(.green), 11);
1139 const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;971 try testing.expectEqual(result.getCount(.blue), 12);
1140 self.bits.unset(index);
1141 self.values[index] = undefined;
1142 return result;
1143 }
1144972
1145 /// Returns an iterator over the map, which visits items in index order.973 const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize));
1146 /// Modifications to the underlying map may or may not be observed by974 try testing.expectError(error.Overflow, result.plus(full));
1147 /// the iterator, but will not invalidate it.975 }
1148 pub fn iterator(self: *Self) Iterator {
1149 return .{
1150 .inner = self.bits.iterator(.{}),
1151 .values = &self.values,
1152 };
1153 }
1154976
1155 /// An entry in the map.977 {
1156 pub const Entry = struct {978 const result = ten_of_each.minus(r0_g1_b2);
1157 /// The key associated with this entry.979 try testing.expectEqual(result.getCount(.red), 10);
1158 /// Modifying this key will not change the map.980 try testing.expectEqual(result.getCount(.green), 9);
1159 key: Key,981 try testing.expectEqual(result.getCount(.blue), 8);
982 }
1160983
1161 /// A pointer to the value in the map associated984 {
1162 /// with this key. Modifications through this985 const result = ten_of_each.minus(r0_g1_b2).minus(ten_of_each);
1163 /// pointer will modify the underlying data.986 try testing.expectEqual(result.getCount(.red), 0);
1164 value: *Value,987 try testing.expectEqual(result.getCount(.green), 0);
1165 };988 try testing.expectEqual(result.getCount(.blue), 0);
989 }
1166990
1167 pub const Iterator = struct {991 {
1168 inner: BitSet.Iterator(.{}),992 var copy = empty;
1169 values: *[Indexer.count]Value,993 var it = copy.iterator();
994 var entry = it.next().?;
995 try testing.expectEqual(entry.key, .red);
996 try testing.expectEqual(entry.value.*, 0);
997 entry = it.next().?;
998 try testing.expectEqual(entry.key, .green);
999 try testing.expectEqual(entry.value.*, 0);
1000 entry = it.next().?;
1001 try testing.expectEqual(entry.key, .blue);
1002 try testing.expectEqual(entry.value.*, 0);
1003 try testing.expectEqual(it.next(), null);
1004 }
11701005
1171 pub fn next(self: *Iterator) ?Entry {1006 {
1172 return if (self.inner.next()) |index|1007 var copy = r0_g1_b2;
1173 Entry{1008 var it = copy.iterator();
1174 .key = Indexer.keyForIndex(index),1009 var entry = it.next().?;
1175 .value = &self.values[index],1010 try testing.expectEqual(entry.key, .red);
1176 }1011 try testing.expectEqual(entry.value.*, 0);
1177 else1012 entry = it.next().?;
1178 null;1013 try testing.expectEqual(entry.key, .green);
1179 }1014 try testing.expectEqual(entry.value.*, 1);
1180 };1015 entry = it.next().?;
1181 };1016 try testing.expectEqual(entry.key, .blue);
1017 try testing.expectEqual(entry.value.*, 2);
1018 try testing.expectEqual(it.next(), null);
1019 }
1182}1020}
11831021
1184/// A dense array of values, using an indexed lookup.1022/// An array keyed by an enum, backed by a dense array.
1185/// This type does no allocation and can be copied by value.1023/// If the enum is not dense, a mapping will be constructed from
1186pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: ?fn (type) type) type {1024/// enum values to dense indices. This type does no dynamic
1187 comptime ensureIndexer(I);1025/// allocation and can be copied by value.
1026pub fn EnumArray(comptime E: type, comptime V: type) type {
1188 return struct {1027 return struct {
1189 const Self = @This();1028 const Self = @This();
11901029
1191 pub usingnamespace (Ext orelse NoExtension)(Self);
1192
1193 /// The index mapping for this map1030 /// The index mapping for this map
1194 pub const Indexer = I;1031 pub const Indexer = EnumIndexer(E);
1195 /// The key type used to index this map1032 /// The key type used to index this map
1196 pub const Key = Indexer.Key;1033 pub const Key = Indexer.Key;
1197 /// The value type stored in this map1034 /// The value type stored in this map
...@@ -1201,6 +1038,21 @@ pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: ?fn (type)...@@ -1201,6 +1038,21 @@ pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: ?fn (type)
12011038
1202 values: [Indexer.count]Value,1039 values: [Indexer.count]Value,
12031040
1041 pub fn init(init_values: EnumFieldStruct(E, Value, null)) Self {
1042 return initDefault(null, init_values);
1043 }
1044
1045 /// Initializes values in the enum array, with the specified default.
1046 pub fn initDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self {
1047 var result: Self = .{ .values = undefined };
1048 inline for (0..Self.len) |i| {
1049 const key = comptime Indexer.keyForIndex(i);
1050 const tag = @tagName(key);
1051 result.values[i] = @field(init_values, tag);
1052 }
1053 return result;
1054 }
1055
1204 pub fn initUndefined() Self {1056 pub fn initUndefined() Self {
1205 return Self{ .values = undefined };1057 return Self{ .values = undefined };
1206 }1058 }
...@@ -1269,46 +1121,96 @@ pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: ?fn (type)...@@ -1269,46 +1121,96 @@ pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: ?fn (type)
1269 };1121 };
1270}1122}
12711123
1272/// Verifies that a type is a valid Indexer, providing a helpful1124test "pure EnumSet fns" {
1273/// compile error if not. An Indexer maps a comptime-known set1125 const Suit = enum { spades, hearts, clubs, diamonds };
1274/// of keys to a dense set of zero-based indices.1126
1275/// The indexer interface must look like this:1127 const empty = EnumSet(Suit).initEmpty();
1276/// ```1128 const full = EnumSet(Suit).initFull();
1277/// struct {1129 const black = EnumSet(Suit).initMany(&[_]Suit{ .spades, .clubs });
1278/// /// The key type which this indexer converts to indices1130 const red = EnumSet(Suit).initMany(&[_]Suit{ .hearts, .diamonds });
1279/// pub const Key: type,1131
1280/// /// The number of indexes in the dense mapping1132 try testing.expect(empty.eql(empty));
1281/// pub const count: comptime_int,1133 try testing.expect(full.eql(full));
1282/// /// Converts from a key to an index1134 try testing.expect(!empty.eql(full));
1283/// pub fn indexOf(Key) usize;1135 try testing.expect(!full.eql(empty));
1284/// /// Converts from an index to a key1136 try testing.expect(!empty.eql(black));
1285/// pub fn keyForIndex(usize) Key;1137 try testing.expect(!full.eql(red));
1286/// }1138 try testing.expect(!red.eql(empty));
1287/// ```1139 try testing.expect(!black.eql(full));
1288pub fn ensureIndexer(comptime T: type) void {1140
1289 comptime {1141 try testing.expect(empty.subsetOf(empty));
1290 if (!@hasDecl(T, "Key")) @compileError("Indexer must have decl Key: type.");1142 try testing.expect(empty.subsetOf(full));
1291 if (@TypeOf(T.Key) != type) @compileError("Indexer.Key must be a type.");1143 try testing.expect(full.subsetOf(full));
1292 if (!@hasDecl(T, "count")) @compileError("Indexer must have decl count: comptime_int.");1144 try testing.expect(!black.subsetOf(red));
1293 if (@TypeOf(T.count) != comptime_int) @compileError("Indexer.count must be a comptime_int.");1145 try testing.expect(!red.subsetOf(black));
1294 if (!@hasDecl(T, "indexOf")) @compileError("Indexer.indexOf must be a fn (Key) usize.");1146
1295 if (@TypeOf(T.indexOf) != fn (T.Key) usize) @compileError("Indexer must have decl indexOf: fn (Key) usize.");1147 try testing.expect(full.supersetOf(full));
1296 if (!@hasDecl(T, "keyForIndex")) @compileError("Indexer must have decl keyForIndex: fn (usize) Key.");1148 try testing.expect(full.supersetOf(empty));
1297 if (@TypeOf(T.keyForIndex) != fn (usize) T.Key) @compileError("Indexer.keyForIndex must be a fn (usize) Key.");1149 try testing.expect(empty.supersetOf(empty));
1298 }1150 try testing.expect(!black.supersetOf(red));
1151 try testing.expect(!red.supersetOf(black));
1152
1153 try testing.expect(empty.complement().eql(full));
1154 try testing.expect(full.complement().eql(empty));
1155 try testing.expect(black.complement().eql(red));
1156 try testing.expect(red.complement().eql(black));
1157
1158 try testing.expect(empty.unionWith(empty).eql(empty));
1159 try testing.expect(empty.unionWith(full).eql(full));
1160 try testing.expect(full.unionWith(full).eql(full));
1161 try testing.expect(full.unionWith(empty).eql(full));
1162 try testing.expect(black.unionWith(red).eql(full));
1163 try testing.expect(red.unionWith(black).eql(full));
1164
1165 try testing.expect(empty.intersectWith(empty).eql(empty));
1166 try testing.expect(empty.intersectWith(full).eql(empty));
1167 try testing.expect(full.intersectWith(full).eql(full));
1168 try testing.expect(full.intersectWith(empty).eql(empty));
1169 try testing.expect(black.intersectWith(red).eql(empty));
1170 try testing.expect(red.intersectWith(black).eql(empty));
1171
1172 try testing.expect(empty.xorWith(empty).eql(empty));
1173 try testing.expect(empty.xorWith(full).eql(full));
1174 try testing.expect(full.xorWith(full).eql(empty));
1175 try testing.expect(full.xorWith(empty).eql(full));
1176 try testing.expect(black.xorWith(red).eql(full));
1177 try testing.expect(red.xorWith(black).eql(full));
1178
1179 try testing.expect(empty.differenceWith(empty).eql(empty));
1180 try testing.expect(empty.differenceWith(full).eql(empty));
1181 try testing.expect(full.differenceWith(full).eql(empty));
1182 try testing.expect(full.differenceWith(empty).eql(full));
1183 try testing.expect(full.differenceWith(red).eql(black));
1184 try testing.expect(full.differenceWith(black).eql(red));
1299}1185}
13001186
1301test ensureIndexer {1187test "EnumSet empty" {
1302 ensureIndexer(struct {1188 const E = enum {};
1303 pub const Key = u32;1189 const empty = EnumSet(E).initEmpty();
1304 pub const count: comptime_int = 8;1190 const full = EnumSet(E).initFull();
1305 pub fn indexOf(k: Key) usize {1191
1306 return @as(usize, @intCast(k));1192 try std.testing.expect(empty.eql(full));
1307 }1193 try std.testing.expect(empty.complement().eql(full));
1308 pub fn keyForIndex(index: usize) Key {1194 try std.testing.expect(empty.complement().eql(full.complement()));
1309 return @as(Key, @intCast(index));1195 try std.testing.expect(empty.eql(full.complement()));
1310 }1196}
1311 });1197
1198test "EnumSet const iterator" {
1199 const Direction = enum { up, down, left, right };
1200 const diag_move = init: {
1201 var move = EnumSet(Direction).initEmpty();
1202 move.insert(.right);
1203 move.insert(.up);
1204 break :init move;
1205 };
1206
1207 var result = EnumSet(Direction).initEmpty();
1208 var it = diag_move.iterator();
1209 while (it.next()) |dir| {
1210 result.insert(dir);
1211 }
1212
1213 try testing.expect(result.eql(diag_move));
1312}1214}
13131215
1314pub fn EnumIndexer(comptime E: type) type {1216pub fn EnumIndexer(comptime E: type) type {
...@@ -1438,7 +1340,6 @@ test "EnumIndexer non-exhaustive" {...@@ -1438,7 +1340,6 @@ test "EnumIndexer non-exhaustive" {
1438 _,1340 _,
1439 };1341 };
1440 const Indexer = EnumIndexer(E);1342 const Indexer = EnumIndexer(E);
1441 ensureIndexer(Indexer);
14421343
1443 const min_tag: E = @enumFromInt(std.math.minInt(BackingInt));1344 const min_tag: E = @enumFromInt(std.math.minInt(BackingInt));
1444 const max_tag: E = @enumFromInt(std.math.maxInt(BackingInt));1345 const max_tag: E = @enumFromInt(std.math.maxInt(BackingInt));
...@@ -1466,7 +1367,6 @@ test "EnumIndexer non-exhaustive" {...@@ -1466,7 +1367,6 @@ test "EnumIndexer non-exhaustive" {
1466test "EnumIndexer dense zeroed" {1367test "EnumIndexer dense zeroed" {
1467 const E = enum(u2) { b = 1, a = 0, c = 2 };1368 const E = enum(u2) { b = 1, a = 0, c = 2 };
1468 const Indexer = EnumIndexer(E);1369 const Indexer = EnumIndexer(E);
1469 ensureIndexer(Indexer);
1470 try testing.expectEqual(E, Indexer.Key);1370 try testing.expectEqual(E, Indexer.Key);
1471 try testing.expectEqual(3, Indexer.count);1371 try testing.expectEqual(3, Indexer.count);
14721372
...@@ -1482,7 +1382,6 @@ test "EnumIndexer dense zeroed" {...@@ -1482,7 +1382,6 @@ test "EnumIndexer dense zeroed" {
1482test "EnumIndexer dense positive" {1382test "EnumIndexer dense positive" {
1483 const E = enum(u4) { c = 6, a = 4, b = 5 };1383 const E = enum(u4) { c = 6, a = 4, b = 5 };
1484 const Indexer = EnumIndexer(E);1384 const Indexer = EnumIndexer(E);
1485 ensureIndexer(Indexer);
1486 try testing.expectEqual(E, Indexer.Key);1385 try testing.expectEqual(E, Indexer.Key);
1487 try testing.expectEqual(3, Indexer.count);1386 try testing.expectEqual(3, Indexer.count);
14881387
...@@ -1498,7 +1397,6 @@ test "EnumIndexer dense positive" {...@@ -1498,7 +1397,6 @@ test "EnumIndexer dense positive" {
1498test "EnumIndexer dense negative" {1397test "EnumIndexer dense negative" {
1499 const E = enum(i4) { a = -6, c = -4, b = -5 };1398 const E = enum(i4) { a = -6, c = -4, b = -5 };
1500 const Indexer = EnumIndexer(E);1399 const Indexer = EnumIndexer(E);
1501 ensureIndexer(Indexer);
1502 try testing.expectEqual(E, Indexer.Key);1400 try testing.expectEqual(E, Indexer.Key);
1503 try testing.expectEqual(3, Indexer.count);1401 try testing.expectEqual(3, Indexer.count);
15041402
...@@ -1514,7 +1412,6 @@ test "EnumIndexer dense negative" {...@@ -1514,7 +1412,6 @@ test "EnumIndexer dense negative" {
1514test "EnumIndexer sparse" {1412test "EnumIndexer sparse" {
1515 const E = enum(i4) { a = -2, c = 6, b = 4 };1413 const E = enum(i4) { a = -2, c = 6, b = 4 };
1516 const Indexer = EnumIndexer(E);1414 const Indexer = EnumIndexer(E);
1517 ensureIndexer(Indexer);
1518 try testing.expectEqual(E, Indexer.Key);1415 try testing.expectEqual(E, Indexer.Key);
1519 try testing.expectEqual(3, Indexer.count);1416 try testing.expectEqual(3, Indexer.count);
15201417
...@@ -1530,7 +1427,6 @@ test "EnumIndexer sparse" {...@@ -1530,7 +1427,6 @@ test "EnumIndexer sparse" {
1530test "EnumIndexer empty" {1427test "EnumIndexer empty" {
1531 const E = enum {};1428 const E = enum {};
1532 const Indexer = EnumIndexer(E);1429 const Indexer = EnumIndexer(E);
1533 ensureIndexer(Indexer);
1534 try testing.expectEqual(E, Indexer.Key);1430 try testing.expectEqual(E, Indexer.Key);
1535 try testing.expectEqual(0, Indexer.count);1431 try testing.expectEqual(0, Indexer.count);
1536}1432}