authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-08 22:25:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:49-07:00
loge85df854aa86c4f41c3a64d2af1858aed3482fbc
tree47645605329bc307cbd05ec2e0445f5e9c13bb80
parentebcc6f166c9c34d00b750f26687c9ee36b243cb0

std.mem: improve containsAtLeastScalar implementation and rename


1 files changed, 37 insertions(+), 16 deletions(-)

lib/std/mem.zig+37-16
......@@ -1746,6 +1746,7 @@ test countScalar {
17461746//
17471747/// See also: `containsAtLeastScalar`
17481748pub 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]);
17491750 assert(needle.len > 0);
17501751 if (expected_count == 0) return true;
17511752
......@@ -1776,32 +1777,52 @@ test containsAtLeast {
17761777 try testing.expect(!containsAtLeast(u8, " radar radar ", 3, "radar"));
17771778}
17781779
1779/// Returns true if the haystack contains expected_count or more needles
1780//
1781/// See also: `containsAtLeast`
1782pub 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`.
1781pub fn containsAtLeastScalar(comptime T: type, list: []const T, minimum: usize, element: T) bool {
1782 return containsAtLeastScalar2(T, list, element, minimum);
1783}
17841784
1785/// Returns true if `element` appears at least `minimum` number of times in `list`.
1786//
1787/// Related:
1788/// * `containsAtLeast`
1789/// * `countScalar`
1790pub fn containsAtLeastScalar2(comptime T: type, list: []const T, element: T, minimum: usize) bool {
1791 const n = list.len;
1792 var i: usize = 0;
17851793 var found: usize = 0;
17861794
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 }
17911807 }
17921808 }
17931809
1810 for (list[i..n]) |item| {
1811 found += @intFromBool(item == element);
1812 if (found >= minimum) return true;
1813 }
1814
17941815 return false;
17951816}
17961817
1797test 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'));
1818test 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));
18021823
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));
18051826}
18061827
18071828/// Reads an integer from memory with size equal to bytes.len.