std.mem: improve containsAtLeastScalar implementation and rename

This commit is contained in:
Andrew Kelley 2025-10-08 22:25:49 -07:00
parent ebcc6f166c
commit e85df854aa

View File

@ -1746,6 +1746,7 @@ test countScalar {
// //
/// See also: `containsAtLeastScalar` /// See also: `containsAtLeastScalar`
pub fn containsAtLeast(comptime T: type, haystack: []const T, expected_count: usize, needle: []const T) bool { pub fn containsAtLeast(comptime T: type, haystack: []const T, expected_count: usize, needle: []const T) bool {
if (needle.len == 1) return containsAtLeastScalar(T, haystack, expected_count, needle[0]);
assert(needle.len > 0); assert(needle.len > 0);
if (expected_count == 0) return true; if (expected_count == 0) return true;
@ -1776,32 +1777,52 @@ test containsAtLeast {
try testing.expect(!containsAtLeast(u8, " radar radar ", 3, "radar")); try testing.expect(!containsAtLeast(u8, " radar radar ", 3, "radar"));
} }
/// Returns true if the haystack contains expected_count or more needles /// Deprecated in favor of `containsAtLeastScalar2`.
// pub fn containsAtLeastScalar(comptime T: type, list: []const T, minimum: usize, element: T) bool {
/// See also: `containsAtLeast` return containsAtLeastScalar2(T, list, element, minimum);
pub fn containsAtLeastScalar(comptime T: type, haystack: []const T, expected_count: usize, needle: T) bool { }
if (expected_count == 0) return true;
/// Returns true if `element` appears at least `minimum` number of times in `list`.
//
/// Related:
/// * `containsAtLeast`
/// * `countScalar`
pub fn containsAtLeastScalar2(comptime T: type, list: []const T, element: T, minimum: usize) bool {
const n = list.len;
var i: usize = 0;
var found: usize = 0; var found: usize = 0;
for (haystack) |item| { if (use_vectors_for_comparison and
if (item == needle) { (@typeInfo(T) == .int or @typeInfo(T) == .float) and std.math.isPowerOfTwo(@bitSizeOf(T)))
found += 1; {
if (found == expected_count) return true; if (std.simd.suggestVectorLength(T)) |block_size| {
const Block = @Vector(block_size, T);
const letter_mask: Block = @splat(element);
while (n - i >= block_size) : (i += block_size) {
const haystack_block: Block = list[i..][0..block_size].*;
found += std.simd.countTrues(letter_mask == haystack_block);
if (found >= minimum) return true;
}
} }
} }
for (list[i..n]) |item| {
found += @intFromBool(item == element);
if (found >= minimum) return true;
}
return false; return false;
} }
test containsAtLeastScalar { test containsAtLeastScalar2 {
try testing.expect(containsAtLeastScalar(u8, "aa", 0, 'a')); try testing.expect(containsAtLeastScalar2(u8, "aa", 'a', 0));
try testing.expect(containsAtLeastScalar(u8, "aa", 1, 'a')); try testing.expect(containsAtLeastScalar2(u8, "aa", 'a', 1));
try testing.expect(containsAtLeastScalar(u8, "aa", 2, 'a')); try testing.expect(containsAtLeastScalar2(u8, "aa", 'a', 2));
try testing.expect(!containsAtLeastScalar(u8, "aa", 3, 'a')); try testing.expect(!containsAtLeastScalar2(u8, "aa", 'a', 3));
try testing.expect(containsAtLeastScalar(u8, "adadda", 3, 'd')); try testing.expect(containsAtLeastScalar2(u8, "adadda", 'd', 3));
try testing.expect(!containsAtLeastScalar(u8, "adadda", 4, 'd')); try testing.expect(!containsAtLeastScalar2(u8, "adadda", 'd', 4));
} }
/// Reads an integer from memory with size equal to bytes.len. /// Reads an integer from memory with size equal to bytes.len.