C

StringZilla for C

#include <stringzilla/stringzilla.h> 6.0.0-rc.1 · 91a27bdd

It bundles:

  • a precompiled static or shared library that compiles every capability once and picks one per call, for maximum portability,
  • the C headers <stringzilla/stringzilla.h>, which declare that library, or compile the kernels inline with STRINGZILLA_HEADER_ONLY=1,
  • the C++ headers <stringzilla/stringzilla.hpp>, built on the library.

The plain C ABI exposes each kernel family as a stable C 99 surface: substring and byte-set search, non-cryptographic hashing and checksums, lexicographic comparison, sorting and intersection of string collections, collection conversions from escaping and normalization to byte translation, and the stateful cross-product engines for edit distances, window overlap, and multi-pattern search. The thin C++ binding rebuilds the STL <string> and <string_view> surface on top of those kernels, adding an owning Small-String-Optimized container, allocation-free splitting and partitioning views, and free functions for hashing, sorting, and translation.

Every verb has a dispatch point, like sz_find_best, which runs the best capability a mask shares with the verb’s list, and the mask to pass on the CPU is the one sz_capabilities_enabled_cpu reports. There is no hidden global allocation and no thread pool: every function that may allocate takes an explicit sz_allocator_t *, and an engine holds the blocks its allocator handed it until you free it. An engine is prepared by sz_levenshtein_engine_init, and its twins for overlap and substrings, for one device’s capabilities and a stream, which names the device, so choosing a device is choosing the mask and the stream an engine is built with rather than setting a global. Its rounds, such as sz_levenshtein_distances, take a trailing stream: null on the CPU, while on a GPU they enqueue there and return, leaving the join to the caller. A GPU engine’s init uses its stream for its own work alone and sizes a round’s device memory from the budgets it takes, so no compute verb allocates or joins, and a round carrying more haystacks than its budget, or on Metal more candidates, is refused with sz_unexpected_dimensions_k. Overlap and Levenshtein engines keep no per-round state on a CUDA device, so several streams may score one engine at once, while the rounds of one substrings engine share its arena and its report, so the caller orders them.

The headers compile as freestanding C 99 — set STRINGZILLA_WITH_LIBC=0 to drop the libc dependency — and as C++20 or newer for the sz:: layer. Per-family hubs find.h, hash.h, sort.h, compare.h, intersect.h, strings.h, small_string.h, levenshtein.h, overlap.h, and substrings.h declare the family’s dispatch points and its kernels, each capability’s under its STRINGZILLA_TARGET_* macro, from the c/ header root. The kernels are defined under the matching subdirectories of the include/ root — find/haswell.h, hash/icelake.h, strings/neon.h, and so on — and the C++ headers live in the cpp/ root; a build passes all three as include paths. The library compiles the kernels once, one capability per unit in src/capabilities/, and header-only builds include them into every translation unit.

Topics

Installation3The headers declare the StringZilla library, so the simplest integration links it and includes the umbrella header.
Types51The C API is built around length-bounded raw pointers, so most functions take a szcptrt, an alias of char const , or a szptrt, an alias of char , together with a szsizet length, and return either a szcptrt into the input or one of the small enums below.
Searching and Counting71The 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.
Comparison and Equality6
Splitting and Partitioning7
Trimming and Translating5
Unicode Segmentation18Splitting Unicode text into the units a human actually perceives is deceptively hard, and getting it wrong corrupts data.
Case Folding and Normalization21Case-insensitive matching across full Unicode is more than ASCII tolower — ß matches ss, accents fold, and the matched byte-length can differ from the needle's.
Hashing and Checksums53Hashing comes in three flavors: a byte checksum, a seeded single-shot hash, and an incremental streaming state.
Sorting and Sets27These operate on a read-only szstringsviewt in any layout and never reorder the underlying data — they fill an order permutation array instead.
Memory Operations13Most operations in StringZilla don't assume any memory ownership.
Edit Distances13
Fingerprints8
Runtime Dispatch56Every kernel exists in a serial form plus one or more per-ISA forms, named with a backend suffix (serial, westmere, goldmont, haswell, skylake, icelake, neon, neonaes, neonsha, sve, sve2, sve2aes, v128, v128relaxed, rvv, rvvcrypto, loongsonasx, powervsx), and the engines add one per GPU vendor, cuda, rocm and metal.
Platform Notes6StringZilla is not a drop-in replacement for the C Standard Library.