| ... | @@ -304,6 +304,346 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { | ... | @@ -304,6 +304,346 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { |
| 304 | return IndexedMap(EnumIndexer(E), V, mixin.EnumMapExt); | 304 | return IndexedMap(EnumIndexer(E), V, mixin.EnumMapExt); |
| 305 | } | 305 | } |
| 306 | | 306 | |
| | 307 | /// A multiset of enum elements up to a count of usize. Backed |
| | 308 | /// by an EnumArray. This type does no dynamic allocation and can |
| | 309 | /// be copied by value. |
| | 310 | pub fn EnumMultiset(comptime E: type) type { |
| | 311 | return BoundedEnumMultiset(E, usize); |
| | 312 | } |
| | 313 | |
| | 314 | /// A multiset of enum elements up to CountSize. Backed by an |
| | 315 | /// EnumArray. This type does no dynamic allocation and can be |
| | 316 | /// copied by value. |
| | 317 | pub fn BoundedEnumMultiset(comptime E: type, comptime CountSize: type) type { |
| | 318 | return struct { |
| | 319 | const Self = @This(); |
| | 320 | |
| | 321 | counts: EnumArray(E, CountSize), |
| | 322 | |
| | 323 | /// Initializes the multiset using a struct of counts. |
| | 324 | pub fn init(init_counts: EnumFieldStruct(E, CountSize, 0)) Self { |
| | 325 | var self = initWithCount(0); |
| | 326 | inline for (@typeInfo(E).Enum.fields) |field| { |
| | 327 | const c = @field(init_counts, field.name); |
| | 328 | const key = @intToEnum(E, field.value); |
| | 329 | self.counts.set(key, c); |
| | 330 | } |
| | 331 | return self; |
| | 332 | } |
| | 333 | |
| | 334 | /// Initializes the multiset with a count of zero. |
| | 335 | pub fn initEmpty() Self { |
| | 336 | return initWithCount(0); |
| | 337 | } |
| | 338 | |
| | 339 | /// Initializes the multiset with all keys at the |
| | 340 | /// same count. |
| | 341 | pub fn initWithCount(comptime c: CountSize) Self { |
| | 342 | return .{ |
| | 343 | .counts = EnumArray(E, CountSize).initDefault(c, .{}), |
| | 344 | }; |
| | 345 | } |
| | 346 | |
| | 347 | /// Returns the total number of key counts in the multiset. |
| | 348 | pub fn count(self: Self) usize { |
| | 349 | var sum: usize = 0; |
| | 350 | for (self.counts.values) |c| { |
| | 351 | sum += c; |
| | 352 | } |
| | 353 | return sum; |
| | 354 | } |
| | 355 | |
| | 356 | /// Checks if at least one key in multiset. |
| | 357 | pub fn contains(self: Self, key: E) bool { |
| | 358 | return self.counts.get(key) > 0; |
| | 359 | } |
| | 360 | |
| | 361 | /// Removes all instance of a key from multiset. Same as |
| | 362 | /// setCount(key, 0). |
| | 363 | pub fn removeAll(self: *Self, key: E) void { |
| | 364 | return self.counts.set(key, 0); |
| | 365 | } |
| | 366 | |
| | 367 | /// Increases the key count by given amount. Caller asserts |
| | 368 | /// operation will not overflow. |
| | 369 | pub fn addAssertSafe(self: *Self, key: E, c: CountSize) void { |
| | 370 | self.counts.getPtr(key).* += c; |
| | 371 | } |
| | 372 | |
| | 373 | /// Increases the key count by given amount. |
| | 374 | pub fn add(self: *Self, key: E, c: CountSize) error{Overflow}!void { |
| | 375 | self.counts.set(key, try std.math.add(CountSize, self.counts.get(key), c)); |
| | 376 | } |
| | 377 | |
| | 378 | /// Decreases the key count by given amount. If amount is |
| | 379 | /// greater than the number of keys in multset, then key count |
| | 380 | /// will be set to zero. |
| | 381 | pub fn remove(self: *Self, key: E, c: CountSize) void { |
| | 382 | self.counts.getPtr(key).* -= @min(self.getCount(key), c); |
| | 383 | } |
| | 384 | |
| | 385 | /// Returns the count for a key. |
| | 386 | pub fn getCount(self: Self, key: E) CountSize { |
| | 387 | return self.counts.get(key); |
| | 388 | } |
| | 389 | |
| | 390 | /// Set the count for a key. |
| | 391 | pub fn setCount(self: *Self, key: E, c: CountSize) void { |
| | 392 | self.counts.set(key, c); |
| | 393 | } |
| | 394 | |
| | 395 | /// Increases the all key counts by given multiset. Caller |
| | 396 | /// asserts operation will not overflow any key. |
| | 397 | pub fn addSetAssertSafe(self: *Self, other: Self) void { |
| | 398 | inline for (@typeInfo(E).Enum.fields) |field| { |
| | 399 | const key = @intToEnum(E, field.value); |
| | 400 | self.addAssertSafe(key, other.getCount(key)); |
| | 401 | } |
| | 402 | } |
| | 403 | |
| | 404 | /// Increases the all key counts by given multiset. |
| | 405 | pub fn addSet(self: *Self, other: Self) error{Overflow}!void { |
| | 406 | inline for (@typeInfo(E).Enum.fields) |field| { |
| | 407 | const key = @intToEnum(E, field.value); |
| | 408 | try self.add(key, other.getCount(key)); |
| | 409 | } |
| | 410 | } |
| | 411 | |
| | 412 | /// Deccreases the all key counts by given multiset. If |
| | 413 | /// the given multiset has more key counts than this, |
| | 414 | /// then that key will have a key count of zero. |
| | 415 | pub fn removeSet(self: *Self, other: Self) void { |
| | 416 | inline for (@typeInfo(E).Enum.fields) |field| { |
| | 417 | const key = @intToEnum(E, field.value); |
| | 418 | self.remove(key, other.getCount(key)); |
| | 419 | } |
| | 420 | } |
| | 421 | |
| | 422 | /// Returns true iff all key counts are the same as |
| | 423 | /// given multiset. |
| | 424 | pub fn eql(self: Self, other: Self) bool { |
| | 425 | inline for (@typeInfo(E).Enum.fields) |field| { |
| | 426 | const key = @intToEnum(E, field.value); |
| | 427 | if (self.getCount(key) != other.getCount(key)) { |
| | 428 | return false; |
| | 429 | } |
| | 430 | } |
| | 431 | return true; |
| | 432 | } |
| | 433 | |
| | 434 | /// Returns a multiset with the total key count of this |
| | 435 | /// multiset and the other multiset. Caller asserts |
| | 436 | /// operation will not overflow any key. |
| | 437 | pub fn plusAssertSafe(self: Self, other: Self) Self { |
| | 438 | var result = self; |
| | 439 | result.addSetAssertSafe(other); |
| | 440 | return result; |
| | 441 | } |
| | 442 | |
| | 443 | /// Returns a multiset with the total key count of this |
| | 444 | /// multiset and the other multiset. |
| | 445 | pub fn plus(self: Self, other: Self) error{Overflow}!Self { |
| | 446 | var result = self; |
| | 447 | try result.addSet(other); |
| | 448 | return result; |
| | 449 | } |
| | 450 | |
| | 451 | /// Returns a multiset with the key count of this |
| | 452 | /// multiset minus the corresponding key count in the |
| | 453 | /// other multiset. If the other multiset contains |
| | 454 | /// more key count than this set, that key will have |
| | 455 | /// a count of zero. |
| | 456 | pub fn minus(self: Self, other: Self) Self { |
| | 457 | var result = self; |
| | 458 | result.removeSet(other); |
| | 459 | return result; |
| | 460 | } |
| | 461 | |
| | 462 | pub const Entry = EnumArray(E, CountSize).Entry; |
| | 463 | pub const Iterator = EnumArray(E, CountSize).Iterator; |
| | 464 | |
| | 465 | /// Returns an iterator over this multiset. Keys with zero |
| | 466 | /// counts are included. Modifications to the set during |
| | 467 | /// iteration may or may not be observed by the iterator, |
| | 468 | /// but will not invalidate it. |
| | 469 | pub fn iterator(self: *Self) Iterator { |
| | 470 | return self.counts.iterator(); |
| | 471 | } |
| | 472 | }; |
| | 473 | } |
| | 474 | |
| | 475 | test "EnumMultiset" { |
| | 476 | const Ball = enum { red, green, blue }; |
| | 477 | |
| | 478 | const empty = EnumMultiset(Ball).initEmpty(); |
| | 479 | const r0_g1_b2 = EnumMultiset(Ball).init(.{ |
| | 480 | .red = 0, |
| | 481 | .green = 1, |
| | 482 | .blue = 2, |
| | 483 | }); |
| | 484 | const ten_of_each = EnumMultiset(Ball).initWithCount(10); |
| | 485 | |
| | 486 | try testing.expectEqual(empty.count(), 0); |
| | 487 | try testing.expectEqual(r0_g1_b2.count(), 3); |
| | 488 | try testing.expectEqual(ten_of_each.count(), 30); |
| | 489 | |
| | 490 | try testing.expect(!empty.contains(.red)); |
| | 491 | try testing.expect(!empty.contains(.green)); |
| | 492 | try testing.expect(!empty.contains(.blue)); |
| | 493 | |
| | 494 | try testing.expect(!r0_g1_b2.contains(.red)); |
| | 495 | try testing.expect(r0_g1_b2.contains(.green)); |
| | 496 | try testing.expect(r0_g1_b2.contains(.blue)); |
| | 497 | |
| | 498 | try testing.expect(ten_of_each.contains(.red)); |
| | 499 | try testing.expect(ten_of_each.contains(.green)); |
| | 500 | try testing.expect(ten_of_each.contains(.blue)); |
| | 501 | |
| | 502 | { |
| | 503 | var copy = ten_of_each; |
| | 504 | copy.removeAll(.red); |
| | 505 | try testing.expect(!copy.contains(.red)); |
| | 506 | |
| | 507 | // removeAll second time does nothing |
| | 508 | copy.removeAll(.red); |
| | 509 | try testing.expect(!copy.contains(.red)); |
| | 510 | } |
| | 511 | |
| | 512 | { |
| | 513 | var copy = ten_of_each; |
| | 514 | copy.addAssertSafe(.red, 6); |
| | 515 | try testing.expectEqual(copy.getCount(.red), 16); |
| | 516 | } |
| | 517 | |
| | 518 | { |
| | 519 | var copy = ten_of_each; |
| | 520 | try copy.add(.red, 6); |
| | 521 | try testing.expectEqual(copy.getCount(.red), 16); |
| | 522 | |
| | 523 | try testing.expectError(error.Overflow, copy.add(.red, std.math.maxInt(usize))); |
| | 524 | } |
| | 525 | |
| | 526 | { |
| | 527 | var copy = ten_of_each; |
| | 528 | copy.remove(.red, 4); |
| | 529 | try testing.expectEqual(copy.getCount(.red), 6); |
| | 530 | |
| | 531 | // subtracting more it contains does not underflow |
| | 532 | copy.remove(.green, 14); |
| | 533 | try testing.expectEqual(copy.getCount(.green), 0); |
| | 534 | } |
| | 535 | |
| | 536 | try testing.expectEqual(empty.getCount(.green), 0); |
| | 537 | try testing.expectEqual(r0_g1_b2.getCount(.green), 1); |
| | 538 | try testing.expectEqual(ten_of_each.getCount(.green), 10); |
| | 539 | |
| | 540 | { |
| | 541 | var copy = empty; |
| | 542 | copy.setCount(.red, 6); |
| | 543 | try testing.expectEqual(copy.getCount(.red), 6); |
| | 544 | } |
| | 545 | |
| | 546 | { |
| | 547 | var copy = r0_g1_b2; |
| | 548 | copy.addSetAssertSafe(ten_of_each); |
| | 549 | try testing.expectEqual(copy.getCount(.red), 10); |
| | 550 | try testing.expectEqual(copy.getCount(.green), 11); |
| | 551 | try testing.expectEqual(copy.getCount(.blue), 12); |
| | 552 | } |
| | 553 | |
| | 554 | { |
| | 555 | var copy = r0_g1_b2; |
| | 556 | try copy.addSet(ten_of_each); |
| | 557 | try testing.expectEqual(copy.getCount(.red), 10); |
| | 558 | try testing.expectEqual(copy.getCount(.green), 11); |
| | 559 | try testing.expectEqual(copy.getCount(.blue), 12); |
| | 560 | |
| | 561 | const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize)); |
| | 562 | try testing.expectError(error.Overflow, copy.addSet(full)); |
| | 563 | } |
| | 564 | |
| | 565 | { |
| | 566 | var copy = ten_of_each; |
| | 567 | copy.removeSet(r0_g1_b2); |
| | 568 | try testing.expectEqual(copy.getCount(.red), 10); |
| | 569 | try testing.expectEqual(copy.getCount(.green), 9); |
| | 570 | try testing.expectEqual(copy.getCount(.blue), 8); |
| | 571 | |
| | 572 | copy.removeSet(ten_of_each); |
| | 573 | try testing.expectEqual(copy.getCount(.red), 0); |
| | 574 | try testing.expectEqual(copy.getCount(.green), 0); |
| | 575 | try testing.expectEqual(copy.getCount(.blue), 0); |
| | 576 | } |
| | 577 | |
| | 578 | try testing.expect(empty.eql(empty)); |
| | 579 | try testing.expect(r0_g1_b2.eql(r0_g1_b2)); |
| | 580 | try testing.expect(ten_of_each.eql(ten_of_each)); |
| | 581 | try testing.expect(!empty.eql(r0_g1_b2)); |
| | 582 | try testing.expect(!r0_g1_b2.eql(ten_of_each)); |
| | 583 | try testing.expect(!ten_of_each.eql(empty)); |
| | 584 | |
| | 585 | { |
| | 586 | const result = r0_g1_b2.plusAssertSafe(ten_of_each); |
| | 587 | try testing.expectEqual(result.getCount(.red), 10); |
| | 588 | try testing.expectEqual(result.getCount(.green), 11); |
| | 589 | try testing.expectEqual(result.getCount(.blue), 12); |
| | 590 | } |
| | 591 | |
| | 592 | { |
| | 593 | const result = try r0_g1_b2.plus(ten_of_each); |
| | 594 | try testing.expectEqual(result.getCount(.red), 10); |
| | 595 | try testing.expectEqual(result.getCount(.green), 11); |
| | 596 | try testing.expectEqual(result.getCount(.blue), 12); |
| | 597 | |
| | 598 | const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize)); |
| | 599 | try testing.expectError(error.Overflow, result.plus(full)); |
| | 600 | } |
| | 601 | |
| | 602 | { |
| | 603 | const result = ten_of_each.minus(r0_g1_b2); |
| | 604 | try testing.expectEqual(result.getCount(.red), 10); |
| | 605 | try testing.expectEqual(result.getCount(.green), 9); |
| | 606 | try testing.expectEqual(result.getCount(.blue), 8); |
| | 607 | } |
| | 608 | |
| | 609 | { |
| | 610 | const result = ten_of_each.minus(r0_g1_b2).minus(ten_of_each); |
| | 611 | try testing.expectEqual(result.getCount(.red), 0); |
| | 612 | try testing.expectEqual(result.getCount(.green), 0); |
| | 613 | try testing.expectEqual(result.getCount(.blue), 0); |
| | 614 | } |
| | 615 | |
| | 616 | { |
| | 617 | var copy = empty; |
| | 618 | var it = copy.iterator(); |
| | 619 | var entry = it.next().?; |
| | 620 | try testing.expectEqual(entry.key, .red); |
| | 621 | try testing.expectEqual(entry.value.*, 0); |
| | 622 | entry = it.next().?; |
| | 623 | try testing.expectEqual(entry.key, .green); |
| | 624 | try testing.expectEqual(entry.value.*, 0); |
| | 625 | entry = it.next().?; |
| | 626 | try testing.expectEqual(entry.key, .blue); |
| | 627 | try testing.expectEqual(entry.value.*, 0); |
| | 628 | try testing.expectEqual(it.next(), null); |
| | 629 | } |
| | 630 | |
| | 631 | { |
| | 632 | var copy = r0_g1_b2; |
| | 633 | var it = copy.iterator(); |
| | 634 | var entry = it.next().?; |
| | 635 | try testing.expectEqual(entry.key, .red); |
| | 636 | try testing.expectEqual(entry.value.*, 0); |
| | 637 | entry = it.next().?; |
| | 638 | try testing.expectEqual(entry.key, .green); |
| | 639 | try testing.expectEqual(entry.value.*, 1); |
| | 640 | entry = it.next().?; |
| | 641 | try testing.expectEqual(entry.key, .blue); |
| | 642 | try testing.expectEqual(entry.value.*, 2); |
| | 643 | try testing.expectEqual(it.next(), null); |
| | 644 | } |
| | 645 | } |
| | 646 | |
| 307 | /// An array keyed by an enum, backed by a dense array. | 647 | /// An array keyed by an enum, backed by a dense array. |
| 308 | /// If the enum is not dense, a mapping will be constructed from | 648 | /// If the enum is not dense, a mapping will be constructed from |
| 309 | /// enum values to dense indices. This type does no dynamic | 649 | /// enum values to dense indices. This type does no dynamic |