| ... | @@ -634,14 +634,77 @@ test "lessThan" { | ... | @@ -634,14 +634,77 @@ test "lessThan" { |
| 634 | | 634 | |
| 635 | /// Compares two slices and returns whether they are equal. | 635 | /// Compares two slices and returns whether they are equal. |
| 636 | pub fn eql(comptime T: type, a: []const T, b: []const T) bool { | 636 | pub fn eql(comptime T: type, a: []const T, b: []const T) bool { |
| | 637 | if (@sizeOf(T) == 0) return true; |
| | 638 | if (!@inComptime() and std.meta.hasUniqueRepresentation(T)) return eqlBytes(sliceAsBytes(a), sliceAsBytes(b)); |
| | 639 | |
| 637 | if (a.len != b.len) return false; | 640 | if (a.len != b.len) return false; |
| 638 | if (a.ptr == b.ptr) return true; | 641 | if (a.len == 0 or a.ptr == b.ptr) return true; |
| | 642 | |
| 639 | for (a, b) |a_elem, b_elem| { | 643 | for (a, b) |a_elem, b_elem| { |
| 640 | if (a_elem != b_elem) return false; | 644 | if (a_elem != b_elem) return false; |
| 641 | } | 645 | } |
| 642 | return true; | 646 | return true; |
| 643 | } | 647 | } |
| 644 | | 648 | |
| | 649 | /// std.mem.eql heavily optimized for slices of bytes. |
| | 650 | fn eqlBytes(a: []const u8, b: []const u8) bool { |
| | 651 | if (a.len != b.len) return false; |
| | 652 | if (a.len == 0 or a.ptr == b.ptr) return true; |
| | 653 | |
| | 654 | if (a.len <= 16) { |
| | 655 | if (a.len < 4) { |
| | 656 | const x = (a[0] ^ b[0]) | (a[a.len - 1] ^ b[a.len - 1]) | (a[a.len / 2] ^ b[a.len / 2]); |
| | 657 | return x == 0; |
| | 658 | } |
| | 659 | var x: u32 = 0; |
| | 660 | for ([_]usize{ 0, a.len - 4, (a.len / 8) * 4, a.len - 4 - ((a.len / 8) * 4) }) |n| { |
| | 661 | x |= @as(u32, @bitCast(a[n..][0..4].*)) ^ @as(u32, @bitCast(b[n..][0..4].*)); |
| | 662 | } |
| | 663 | return x == 0; |
| | 664 | } |
| | 665 | |
| | 666 | // Figure out the fastest way to scan through the input in chunks. |
| | 667 | // Uses vectors when supported and falls back to usize/words when not. |
| | 668 | const Scan = if (std.simd.suggestVectorSize(u8)) |vec_size| |
| | 669 | struct { |
| | 670 | pub const size = vec_size; |
| | 671 | pub const Chunk = @Vector(size, u8); |
| | 672 | pub inline fn isNotEqual(chunk_a: Chunk, chunk_b: Chunk) bool { |
| | 673 | return @reduce(.Or, chunk_a != chunk_b); |
| | 674 | } |
| | 675 | } |
| | 676 | else |
| | 677 | struct { |
| | 678 | pub const size = @sizeOf(usize); |
| | 679 | pub const Chunk = usize; |
| | 680 | pub inline fn isNotEqual(chunk_a: Chunk, chunk_b: Chunk) bool { |
| | 681 | return chunk_a != chunk_b; |
| | 682 | } |
| | 683 | }; |
| | 684 | |
| | 685 | inline for (1..6) |s| { |
| | 686 | const n = 16 << s; |
| | 687 | if (n <= Scan.size and a.len <= n) { |
| | 688 | const V = @Vector(n / 2, u8); |
| | 689 | var x = @as(V, a[0 .. n / 2].*) ^ @as(V, b[0 .. n / 2].*); |
| | 690 | x |= @as(V, a[a.len - n / 2 ..][0 .. n / 2].*) ^ @as(V, b[a.len - n / 2 ..][0 .. n / 2].*); |
| | 691 | const zero: V = @splat(0); |
| | 692 | return !@reduce(.Or, x != zero); |
| | 693 | } |
| | 694 | } |
| | 695 | // Compare inputs in chunks at a time (excluding the last chunk). |
| | 696 | for (0..(a.len - 1) / Scan.size) |i| { |
| | 697 | const a_chunk: Scan.Chunk = @bitCast(a[i * Scan.size ..][0..Scan.size].*); |
| | 698 | const b_chunk: Scan.Chunk = @bitCast(b[i * Scan.size ..][0..Scan.size].*); |
| | 699 | if (Scan.isNotEqual(a_chunk, b_chunk)) return false; |
| | 700 | } |
| | 701 | |
| | 702 | // Compare the last chunk using an overlapping read (similar to the previous size strategies). |
| | 703 | const last_a_chunk: Scan.Chunk = @bitCast(a[a.len - Scan.size ..][0..Scan.size].*); |
| | 704 | const last_b_chunk: Scan.Chunk = @bitCast(b[a.len - Scan.size ..][0..Scan.size].*); |
| | 705 | return !Scan.isNotEqual(last_a_chunk, last_b_chunk); |
| | 706 | } |
| | 707 | |
| 645 | /// Compares two slices and returns the index of the first inequality. | 708 | /// Compares two slices and returns the index of the first inequality. |
| 646 | /// Returns null if the slices are equal. | 709 | /// Returns null if the slices are equal. |
| 647 | pub fn indexOfDiff(comptime T: type, a: []const T, b: []const T) ?usize { | 710 | pub fn indexOfDiff(comptime T: type, a: []const T, b: []const T) ?usize { |