The forward and reverse substring scans mirror libc’s memchr/memrchr and memmem, but always take explicit lengths and report a pointer into the haystack, or NULL when there is no match.
Like every dispatch point, each takes the mask to pick a capability from and a stream, null on the CPU, and returns sz_success_k, or sz_missing_kernel_k when no capability in the mask has the kernel:
sz_subdocuments_slice_tThe array positions one selector picks, RFC 9535's [begin:end:step], an index n being [n:n+1:1], or [-1::1] for the last element; negative bounds count from the array's end.
Equivalent to strspn(haystack, accepted) and strcspn(haystack, rejected) in LibC. May have identical implementation and performance to sz_rfind_byteset_best. Useful for parsing, when we want to skip a set of characters, such as:
6 whitespaces: " \t\n\r\v\f".
16 digits forming a float number: "0123456789,.eE+-".
5 HTML reserved characters: "\"'&<>", of which "<>" can be useful for parsing.
2 JSON string special characters useful to locate the end of the string: "\"\\".
Parameters
haystack
in
Haystack - the string to scan.
haystack_length
in
Number of bytes in the haystack.
set
in
Set of relevant characters.
match
out
Address of the first matching character from set, or NULL if not found.
capabilities
in
One device's capabilities, like sz_capabilities_enabled_cpu reports.
stream
in
Null on the CPU, or the GPU stream of that device to queue on.
Equivalent to strspn(haystack, accepted) and strcspn(haystack, rejected) in LibC. May have identical implementation and performance to sz_find_byteset_best. Useful for parsing, when we want to skip a set of characters, such as:
6 whitespaces: " \t\n\r\v\f".
16 digits forming a float number: "0123456789,.eE+-".
5 HTML reserved characters: "\"'&<>", of which "<>" can be useful for parsing.
2 JSON string special characters useful to locate the end of the string: "\"\\".
Parameters
haystack
in
Haystack - the string to scan.
haystack_length
in
Number of bytes in the haystack.
set
in
Set of relevant characters.
match
out
Address of the last matching character from set, or NULL if not found.
capabilities
in
One device's capabilities, like sz_capabilities_enabled_cpu reports.
stream
in
Null on the CPU, or the GPU stream of that device to queue on.
A tape read in its own order is searched as one run of bytes, 64 starts at a time, so a string costs no call of its own, and a match crossing into the next string counts for neither. Other layouts and orders search string by string.
Parameters
strings
in
The strings to search, in any layout.
order
in
Indices into strings, possibly repeated, or null for the first count.
count
in
Number of strings to search.
needle
in
The substring to find.
needle_length
in
Number of bytes in the needle, zero matching at every start.
positions
out
The offset of each first match within its string, or STRINGZILLA_SIZE_MAX where a string holds none, count of them.
capabilities
in
One device's capabilities, like sz_capabilities_enabled_cpu reports.
stream
in
Null on the CPU, or the GPU stream of that device to queue on.
The vocabulary; an empty needle is refused rather than skipped, as it would match at every position and dropping it would shift every later needle's reported index. Read on the host.
case_sensitivity
in
Whether both sides are folded before they meet, or compared as is.
overlap_policy
in
The cover every round runs, as the arena is sized for that one alone.
hot_states
in
States to keep in the dense hot rows, or STRINGZILLA_SUBSTRINGS_HOT_STATES_AUTO to fill a fixed byte budget, which holds more states the fewer classes the vocabulary spells.
matches_budget
in
Matches one round may emit, read by a device tier only; a host tier walks straight into the caller's output and ignores it. Zero asks for a tier-chosen default.
haystacks_budget
in
Haystacks one round may carry, read by a device tier only, zero asking for its default. The arena of counts, find and replace is sized for it here, so they allocate nothing; sz_substrings_bm25_scores grows it for its tables on its first call only. A round carrying more is refused with sz_unexpected_dimensions_k.
capabilities
in
One device's capabilities, like sz_capabilities_enabled_cpu or sz_capabilities_enabled_cuda report; its group picks the CPU or a GPU vendor.
Null on the CPU. On a GPU, the stream to queue on, also naming the device: a cudaStream_t, a hipStream_t, or an id<MTLCommandQueue>; null for the default.
sz_*_engine_free× 3Returns both of the engine's blocks to the allocator that built them, once the work queued on stream is done with them, emptying engine.
sz_substrings_containsMarks which haystacks hold at least one match of any needle, stopping each walk at its first match, the lightest verb of the engine.
Every verb runs the kernel of the capability engine was compiled for. A device one enqueues on stream and returns; every round of one engine runs out of its one arena and writes its one report, so the caller orders them - one stream, or events between two - and reads the report only after joining the round that wrote it.
Parameters
engine
in
A compiled vocabulary, whose overlap_policy decides whether matches sharing bytes are all counted or thinned to a leftmost run.
haystacks
in
The texts to search; their bytes are read in place and never copied. Any layout on the CPU, and on a device a tape sz_strings_to_tape_best wrote into a unified allocator, as every verb takes its haystacks and replacements.
counts
out
The per-haystack counts, haystack h at counts[h * stride].
counts_stride
in
Entries from one haystack's count to the next, at least one, so a strided call writes one column of a [haystacks, vocabularies] feature matrix.
stream
in
Null on the CPU. On a GPU, the stream to queue on, which also names the device the round runs on; null for the default.
A capacity too small is not an error: the report's matches_emitted names the true total and shortfall names what did not fit, so a sizing call and a filling call need no walk between.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The texts to search; their bytes are read in place and never copied.
matches
out
Room for matches_capacity matches, ascending by haystack; STRINGZILLA_NULL together with a zero capacity makes the call a pure size query.
matches_capacity
in
Entries matches holds.
matches_offsets
out
One boundary per haystack into matches plus one, the last being the total; filled whether or not the matches fit, which is what sizes the next call.
A target too small is not an error: the report's target_length names the bytes the rewrite needs and shortfall names what did not fit, leaving the contents of target unspecified.
Parameters
engine
in
A vocabulary compiled under a leftmost policy; sz_substrings_overlapping_k is refused, since a substitution over matches that share bytes is not a function.
haystacks
in
The texts to rewrite; their bytes are read in place and never copied.
replacements
in
One replacement per needle, indexed by needle; an empty one deletes.
target
out
Room for target_capacity bytes, or STRINGZILLA_NULL with zero capacity to size only.
target_capacity
in
Bytes target holds.
offsets
out
One rewritten boundary per haystack plus one, the last being the total; filled whether or not the target held the result, which is what sizes the next call.
The vocabulary is the query: needle_weights holds each needle's IDF or boost. Term frequencies are raw overlapping counts, since a leftmost cover would suppress genuine occurrences of a needle nested in another, so the engine's own policy does not apply here. A CPU backend sums in ascending needle order and a CUDA backend in fixed-point integers, so each is bit-stable across its own runs, and the two agree.
The arguments are invalid when needle_weights is STRINGZILLA_NULL, scores_stride is zero, or length_normalization is positive while average_document_length is not.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The documents to score; their bytes are read in place and never copied.
document_lengths
in
One length per haystack to normalize by, in the unit of average_document_length, or STRINGZILLA_NULL to use each haystack's byte length.
parameters
in
BM25's continuous parameters.
needle_weights
in
One weight per needle of the engine.
scores
out
The per-haystack scores, haystack h at scores[h * stride].
scores_stride
in
Entries from one haystack's score to the next, at least one, so a strided call writes one column of a [haystacks, vocabularies] feature matrix.
The vocabulary; an empty needle is refused rather than skipped, as it would match at every position and dropping it would shift every later needle's reported index. Read on the host.
case_sensitivity
in
Whether both sides are folded before they meet, or compared as is.
overlap_policy
in
The cover every round runs, as the arena is sized for that one alone.
hot_states
in
States to keep in the dense hot rows, or STRINGZILLA_SUBSTRINGS_HOT_STATES_AUTO to fill a fixed byte budget, which holds more states the fewer classes the vocabulary spells.
matches_budget
in
Matches one round may emit, read by a device tier only; the serial walk goes straight into the caller's output and ignores it.
haystacks_budget
in
Haystacks one round may carry, read by a device tier only; the serial walk ignores it.
allocator
in
Where both blocks come from, or STRINGZILLA_NULL for sz_allocator_init_unified_serial. Stored by value, so sz_substrings_engine_free needs none and cannot get the wrong one.
sz_substrings_contains_serialMarks which haystacks hold at least one match of any needle, stopping each walk at its first match, the lightest verb of the engine.
Every verb runs the kernel of the capability engine was compiled for. A device one enqueues on stream and returns; every round of one engine runs out of its one arena and writes its one report, so the caller orders them - one stream, or events between two - and reads the report only after joining the round that wrote it.
Parameters
engine
in
A compiled vocabulary, whose overlap_policy decides whether matches sharing bytes are all counted or thinned to a leftmost run.
haystacks
in
The texts to search; their bytes are read in place and never copied. Any layout on the CPU, and on a device a tape sz_strings_to_tape_best wrote into a unified allocator, as every verb takes its haystacks and replacements.
counts
out
The per-haystack counts, haystack h at counts[h * stride].
counts_stride
in
Entries from one haystack's count to the next, at least one, so a strided call writes one column of a [haystacks, vocabularies] feature matrix.
stream
in
Null on the CPU. On a GPU, the stream to queue on, which also names the device the round runs on; null for the default.
A capacity too small is not an error: the report's matches_emitted names the true total and shortfall names what did not fit, so a sizing call and a filling call need no walk between.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The texts to search; their bytes are read in place and never copied.
matches
out
Room for matches_capacity matches, ascending by haystack; STRINGZILLA_NULL together with a zero capacity makes the call a pure size query.
matches_capacity
in
Entries matches holds.
matches_offsets
out
One boundary per haystack into matches plus one, the last being the total; filled whether or not the matches fit, which is what sizes the next call.
A target too small is not an error: the report's target_length names the bytes the rewrite needs and shortfall names what did not fit, leaving the contents of target unspecified.
Parameters
engine
in
A vocabulary compiled under a leftmost policy; sz_substrings_overlapping_k is refused, since a substitution over matches that share bytes is not a function.
haystacks
in
The texts to rewrite; their bytes are read in place and never copied.
replacements
in
One replacement per needle, indexed by needle; an empty one deletes.
target
out
Room for target_capacity bytes, or STRINGZILLA_NULL with zero capacity to size only.
target_capacity
in
Bytes target holds.
offsets
out
One rewritten boundary per haystack plus one, the last being the total; filled whether or not the target held the result, which is what sizes the next call.
The vocabulary is the query: needle_weights holds each needle's IDF or boost. Term frequencies are raw overlapping counts, since a leftmost cover would suppress genuine occurrences of a needle nested in another, so the engine's own policy does not apply here. A CPU backend sums in ascending needle order and a CUDA backend in fixed-point integers, so each is bit-stable across its own runs, and the two agree.
The arguments are invalid when needle_weights is STRINGZILLA_NULL, scores_stride is zero, or length_normalization is positive while average_document_length is not.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The documents to score; their bytes are read in place and never copied.
document_lengths
in
One length per haystack to normalize by, in the unit of average_document_length, or STRINGZILLA_NULL to use each haystack's byte length.
parameters
in
BM25's continuous parameters.
needle_weights
in
One weight per needle of the engine.
scores
out
The per-haystack scores, haystack h at scores[h * stride].
scores_stride
in
Entries from one haystack's score to the next, at least one, so a strided call writes one column of a [haystacks, vocabularies] feature matrix.
The vocabulary, read on the host; a pattern's index is the needle_index its matches report, and the lower index wins between patterns matching at one position.
case_sensitivity
in
Whether patterns match bytes as written, or both sides are folded first, as the section on case folding describes.
Within a haystack, matches share no bytes and come in ascending order of start; an empty match is never reported where the previous match ended, as Rust's find_iter does, nor before a UTF-8 continuation byte, so none splits a codepoint.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The texts to search; their bytes are read in place and never copied.
matches
out
Room for matches_capacity matches, ascending by haystack, then by start; STRINGZILLA_NULL together with a zero capacity makes the call a pure size query.
matches_capacity
in
Entries matches holds; only the first that many are written.
matches_offsets
out
One boundary per haystack into the full list of matches plus one, the last being the total; true whether or not the matches fit, which sizes the next call.
stream
in
Null on the CPU, or the device stream the call is enqueued on.
A replacement is copied as written, except that $ stands for one dollar and $N, ${N} and ${name} for the text of that group of the match's pattern, $0 being the whole match; a group that took no part in the match or does not exist is empty, and a dollar starting no reference stands for itself, so $1a is group one followed by a. Groups are read only for the matches whose replacement names them, by a PikeVM over each such match's own span.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The texts to rewrite; their bytes are read in place and never copied.
replacements
in
One replacement per pattern, indexed by pattern; an empty one deletes.
target
out
Room for target_capacity bytes, or STRINGZILLA_NULL with zero capacity to size only.
target_capacity
in
Bytes target holds; only the first that many are written.
offsets
out
One rewritten boundary per haystack plus one, the last being the total; true whether or not the target held the result, which sizes the next call.
stream
in
Null on the CPU, or the device stream the call is enqueued on.
A haystack with such a match gets one row for the whole match, needle_index zero, then one row per group that took part, needle_index naming the group; a haystack without one gets no rows, so a group that took no part is told apart from an empty one. The first match of a pattern is the first the vocabulary reports with that needle_index.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The texts to search; their bytes are read in place and never copied.
pattern_index
in
The pattern whose groups to locate.
groups
out
Room for groups_capacity rows, or STRINGZILLA_NULL with zero capacity to size only.
groups_capacity
in
Rows groups holds; only the first that many are written.
groups_offsets
out
One boundary per haystack plus one, the last being the total; true whether or not groups held them, which sizes the next call.
stream
in
Null on the CPU, or the device stream the call is enqueued on.
The vocabulary, read on the host; a pattern's index is the needle_index its matches report, and the lower index wins between patterns matching at one position.
case_sensitivity
in
Whether patterns match bytes as written, or both sides are folded first, as the section on case folding describes.
Where both blocks come from, or STRINGZILLA_NULL for sz_allocator_init_unified_serial. Stored by value, so sz_regex_engine_free needs none and cannot get the wrong one. Scratch grows to the widest call seen, so a warm engine allocates nothing.
stream
in
Null on the CPU.
Statuses
sz_invalid_syntax_k An empty vocabulary or a pattern outside the syntax above.
sz_regex_contains_serialMarks which haystacks hold at least one match of any pattern, stopping each walk at its first match, the lightest verb of the engine.
Within a haystack, matches share no bytes and come in ascending order of start; an empty match is never reported where the previous match ended, as Rust's find_iter does, nor before a UTF-8 continuation byte, so none splits a codepoint.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The texts to search; their bytes are read in place and never copied.
matches
out
Room for matches_capacity matches, ascending by haystack, then by start; STRINGZILLA_NULL together with a zero capacity makes the call a pure size query.
matches_capacity
in
Entries matches holds; only the first that many are written.
matches_offsets
out
One boundary per haystack into the full list of matches plus one, the last being the total; true whether or not the matches fit, which sizes the next call.
stream
in
Null on the CPU, or the device stream the call is enqueued on.
A replacement is copied as written, except that $ stands for one dollar and $N, ${N} and ${name} for the text of that group of the match's pattern, $0 being the whole match; a group that took no part in the match or does not exist is empty, and a dollar starting no reference stands for itself, so $1a is group one followed by a. Groups are read only for the matches whose replacement names them, by a PikeVM over each such match's own span.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The texts to rewrite; their bytes are read in place and never copied.
replacements
in
One replacement per pattern, indexed by pattern; an empty one deletes.
target
out
Room for target_capacity bytes, or STRINGZILLA_NULL with zero capacity to size only.
target_capacity
in
Bytes target holds; only the first that many are written.
offsets
out
One rewritten boundary per haystack plus one, the last being the total; true whether or not the target held the result, which sizes the next call.
stream
in
Null on the CPU, or the device stream the call is enqueued on.
A haystack with such a match gets one row for the whole match, needle_index zero, then one row per group that took part, needle_index naming the group; a haystack without one gets no rows, so a group that took no part is told apart from an empty one. The first match of a pattern is the first the vocabulary reports with that needle_index.
Parameters
engine
in
A compiled vocabulary.
haystacks
in
The texts to search; their bytes are read in place and never copied.
pattern_index
in
The pattern whose groups to locate.
groups
out
Room for groups_capacity rows, or STRINGZILLA_NULL with zero capacity to size only.
groups_capacity
in
Rows groups holds; only the first that many are written.
groups_offsets
out
One boundary per haystack plus one, the last being the total; true whether or not groups held them, which sizes the next call.
stream
in
Null on the CPU, or the device stream the call is enqueued on.
JSON paths follow RFC 9535: the root $, child segments .name and .*, and bracketed unions of names 'name' or "name", wildcards *, indices n, slices begin:end:step and filters ?expression, the same after a descendant .., with blank space where the RFC allows it. Negative indices and bounds count from the array's end, and a negative step walks backward, though matches still come in document order. Filters hold comparisons, existence tests of relative queries, &&, ||, ! and parentheses, and the functions length(), count(), value(), match() and search(), whose I-Regexp patterns compile into one regex engine owned by this one. Each path compiles into one step per segment, numbered path after path, each filter's queries taking steps of their own. A path may also be a bare filter ?expression, which tests the document's root as $[?expression] tests an array's elements.
XML paths follow XPath 1.0 along forward axes: absolute paths of / and // steps, each a name test, *, @name, @* or text() with an optional position [n], which counts the siblings passing the same test. Name tests compare QNames as the document spells them, prefix included, and namespace declarations are no attributes. No blank space is allowed.
What no walk evaluates is an absolute query inside a filter, a comparison with no literal, length() or count() on either side, a pattern other than a string literal or one the regex family refuses, and in XML a reverse axis or a predicate other than a position.
Parameters
engine
out
Left untouched unless the call succeeds.
paths
in
The vocabulary, one path per string, read on the host.
format
in
The grammar of the documents every verb of this engine reads.
sz_invalid_syntax_k Anything outside the grammar, and what no walk evaluates, as above.
sz_missing_library_kmatch() or search() in a header-only build, whose regex dispatch links no library.
sz_missing_kernel_k No capability of the mask has an init, a format no kernel reads yet, or on a GPU non-zero options or a bare filter, which malformed_index then names.
sz_subdocuments_containsMarks which documents hold at least one node some path selects, stopping each walk at its first match, the lightest verb of the engine.
A walk validates nothing past the match it stops at, so a document malformed only after its first match is marked rather than refused. Device walks run whole, as the counts' do, so on a device that document fails the call.
Parameters
engine
in
Compiled paths, serving one call at a time.
documents
in
One document per string; their bytes are read in place and never copied.
contained
out
One bit per document, eight to a byte, the lowest bit first: set when that document matches, with the bits past the last document written as zero.
A node several paths select counts once per path, as sz_subdocuments_find reports it.
A document is malformed with unbalanced brackets or tags, an unterminated string, attribute value, comment or CDATA section, a / outside the strings of JSON, broken structure where the walk reads it, or an XML DOCTYPE with an internal subset, and leaves the counts unspecified. A container or element no live step can enter is skipped by counting its nesting, so nothing else it holds is validated.
Parameters
engine
in
Compiled paths; the walk grows the engine's depth stack, so one engine serves one call at a time.
documents
in
One document per string; their bytes are read in place and never copied.
counts
out
The per-document counts, document d at counts[d * stride].
counts_stride
in
Entries from one document's count to the next, at least one.
Matches come by document, then by start offset, then by path, so a container comes before the nodes inside it, and a node is reported once per path that selects it, however many of the path's selectors or descendant routes reach it. Each match spans the node's exact bytes: in JSON a string with its quotes, a number, true, false or null without the blank space around it, or an object or array through its closing bracket; in XML an element through its end tag, an attribute's value without its quotes, or a text node, whose CDATA sections stay as written.
Parameters
engine
in
Compiled paths, serving one call at a time.
documents
in
One document per string; their bytes are read in place and never copied.
matches
out
Room for matches_capacity matches; STRINGZILLA_NULL together with a zero capacity makes the call a pure size query.
matches_capacity
in
Entries matches holds.
matches_offsets
out
One boundary per document into the matches plus one, the last being the total; filled whether or not the matches fit, which is what sizes the next call.
The first path to break the grammar or leave the subset, on failure.
allocator
in
Where both blocks come from, or STRINGZILLA_NULL for sz_allocator_init_unified_serial. Stored by value, so sz_subdocuments_engine_free needs none and cannot get the wrong one. Scratch grows to the widest call seen, so a warm engine allocates nothing.
sz_subdocuments_contains_serialMarks which documents hold at least one node some path selects, stopping each walk at its first match, the lightest verb of the engine.
A walk validates nothing past the match it stops at, so a document malformed only after its first match is marked rather than refused. Device walks run whole, as the counts' do, so on a device that document fails the call.
Parameters
engine
in
Compiled paths, serving one call at a time.
documents
in
One document per string; their bytes are read in place and never copied.
contained
out
One bit per document, eight to a byte, the lowest bit first: set when that document matches, with the bits past the last document written as zero.
A node several paths select counts once per path, as sz_subdocuments_find reports it.
A document is malformed with unbalanced brackets or tags, an unterminated string, attribute value, comment or CDATA section, a / outside the strings of JSON, broken structure where the walk reads it, or an XML DOCTYPE with an internal subset, and leaves the counts unspecified. A container or element no live step can enter is skipped by counting its nesting, so nothing else it holds is validated.
Parameters
engine
in
Compiled paths; the walk grows the engine's depth stack, so one engine serves one call at a time.
documents
in
One document per string; their bytes are read in place and never copied.
counts
out
The per-document counts, document d at counts[d * stride].
counts_stride
in
Entries from one document's count to the next, at least one.
Matches come by document, then by start offset, then by path, so a container comes before the nodes inside it, and a node is reported once per path that selects it, however many of the path's selectors or descendant routes reach it. Each match spans the node's exact bytes: in JSON a string with its quotes, a number, true, false or null without the blank space around it, or an object or array through its closing bracket; in XML an element through its end tag, an attribute's value without its quotes, or a text node, whose CDATA sections stay as written.
Parameters
engine
in
Compiled paths, serving one call at a time.
documents
in
One document per string; their bytes are read in place and never copied.
matches
out
Room for matches_capacity matches; STRINGZILLA_NULL together with a zero capacity makes the call a pure size query.
matches_capacity
in
Entries matches holds.
matches_offsets
out
One boundary per document into the matches plus one, the last being the total; filled whether or not the matches fit, which is what sizes the next call.
The logic is to count the number of "continuation bytes" matching the 10xxxxxx pattern, and then subtract that from the total byte length to get the number of "start bytes" - coinciding with the number of UTF-8 characters. Counting the characters of a string:
sz_utf8_count_strings_bestChecks that every one of strings[order[i]], or of the first count strings, is well-formed UTF-8 and, unless runes is null, counts each one's runes.
Well-formed is RFC 3629: no overlong forms, surrogates, codepoints past U+10FFFF, stray continuation bytes or truncated sequences, and no sequence crossing from one string into the next. A tape read in its own order is validated as one run of bytes, resolving each string at its end in one step. Other layouts and orders go string by string.
Parameters
strings
in
The strings to check, in any layout.
order
in
Indices into strings, possibly repeated, or null for the first count.
count
in
Number of strings to check.
runes
out
Null, or the runes of each string, count of them, unspecified from the first ill-formed string on.
malformed_index
out
The first ill-formed string, or count when all are well-formed.
capabilities
in
One device's capabilities, like sz_capabilities_enabled_cpu reports.
stream
in
Null on the CPU, or the GPU stream of that device to queue on.