| ... | ... | @@ -1746,6 +1746,7 @@ test countScalar { |
| 1746 | 1746 | // |
| 1747 | 1747 | /// See also: `containsAtLeastScalar` |
| 1748 | 1748 | pub fn containsAtLeast(comptime T: type, haystack: []const T, expected_count: usize, needle: []const T) bool { |
| 1749 | if (needle.len == 1) return containsAtLeastScalar(T, haystack, expected_count, needle[0]); |
| 1749 | 1750 | assert(needle.len > 0); |
| 1750 | 1751 | if (expected_count == 0) return true; |
| 1751 | 1752 | |
| ... | ... | @@ -1776,32 +1777,52 @@ test containsAtLeast { |
| 1776 | 1777 | try testing.expect(!containsAtLeast(u8, " radar radar ", 3, "radar")); |
| 1777 | 1778 | } |
| 1778 | 1779 | |
| 1779 | | /// Returns true if the haystack contains expected_count or more needles |
| 1780 | | // |
| 1781 | | /// See also: `containsAtLeast` |
| 1782 | | pub fn containsAtLeastScalar(comptime T: type, haystack: []const T, expected_count: usize, needle: T) bool { |
| 1783 | | if (expected_count == 0) return true; |
| 1780 | /// Deprecated in favor of `containsAtLeastScalar2`. |
| 1781 | pub fn containsAtLeastScalar(comptime T: type, list: []const T, minimum: usize, element: T) bool { |
| 1782 | return containsAtLeastScalar2(T, list, element, minimum); |
| 1783 | } |
| 1784 | 1784 | |
| 1785 | /// Returns true if `element` appears at least `minimum` number of times in `list`. |
| 1786 | // |
| 1787 | /// Related: |
| 1788 | /// * `containsAtLeast` |
| 1789 | /// * `countScalar` |
| 1790 | pub fn containsAtLeastScalar2(comptime T: type, list: []const T, element: T, minimum: usize) bool { |
| 1791 | const n = list.len; |
| 1792 | var i: usize = 0; |
| 1785 | 1793 | var found: usize = 0; |
| 1786 | 1794 | |
| 1787 | | for (haystack) |item| { |
| 1788 | | if (item == needle) { |
| 1789 | | found += 1; |
| 1790 | | if (found == expected_count) return true; |
| 1795 | if (use_vectors_for_comparison and |
| 1796 | (@typeInfo(T) == .int or @typeInfo(T) == .float) and std.math.isPowerOfTwo(@bitSizeOf(T))) |
| 1797 | { |
| 1798 | if (std.simd.suggestVectorLength(T)) |block_size| { |
| 1799 | const Block = @Vector(block_size, T); |
| 1800 | |
| 1801 | const letter_mask: Block = @splat(element); |
| 1802 | while (n - i >= block_size) : (i += block_size) { |
| 1803 | const haystack_block: Block = list[i..][0..block_size].*; |
| 1804 | found += std.simd.countTrues(letter_mask == haystack_block); |
| 1805 | if (found >= minimum) return true; |
| 1806 | } |
| 1791 | 1807 | } |
| 1792 | 1808 | } |
| 1793 | 1809 | |
| 1810 | for (list[i..n]) |item| { |
| 1811 | found += @intFromBool(item == element); |
| 1812 | if (found >= minimum) return true; |
| 1813 | } |
| 1814 | |
| 1794 | 1815 | return false; |
| 1795 | 1816 | } |
| 1796 | 1817 | |
| 1797 | | test containsAtLeastScalar { |
| 1798 | | try testing.expect(containsAtLeastScalar(u8, "aa", 0, 'a')); |
| 1799 | | try testing.expect(containsAtLeastScalar(u8, "aa", 1, 'a')); |
| 1800 | | try testing.expect(containsAtLeastScalar(u8, "aa", 2, 'a')); |
| 1801 | | try testing.expect(!containsAtLeastScalar(u8, "aa", 3, 'a')); |
| 1818 | test containsAtLeastScalar2 { |
| 1819 | try testing.expect(containsAtLeastScalar2(u8, "aa", 'a', 0)); |
| 1820 | try testing.expect(containsAtLeastScalar2(u8, "aa", 'a', 1)); |
| 1821 | try testing.expect(containsAtLeastScalar2(u8, "aa", 'a', 2)); |
| 1822 | try testing.expect(!containsAtLeastScalar2(u8, "aa", 'a', 3)); |
| 1802 | 1823 | |
| 1803 | | try testing.expect(containsAtLeastScalar(u8, "adadda", 3, 'd')); |
| 1804 | | try testing.expect(!containsAtLeastScalar(u8, "adadda", 4, 'd')); |
| 1824 | try testing.expect(containsAtLeastScalar2(u8, "adadda", 'd', 3)); |
| 1825 | try testing.expect(!containsAtLeastScalar2(u8, "adadda", 'd', 4)); |
| 1805 | 1826 | } |
| 1806 | 1827 | |
| 1807 | 1828 | /// Reads an integer from memory with size equal to bytes.len. |