Skip to main content

Search, hash, sort, and process strings faster via SWAR and SIMD

Project description

StringZilla 🦖

StringZilla banner

Strings are the first fundamental data type every programming language implements in software rather than hardware, so dedicated CPU instructions are rare - and the few that exist are hardly ideal. That's why most languages lean on the C standard library (libc) for their string operations, which, despite its name, ships its hottest code in hand-tuned assembly. It does exploit SIMD, but it isn't perfect. 1️⃣ Even on ubiquitous hardware - over a billion 64-bit ARM CPUs - routines such as strstr and memmem top out at roughly one-third of available throughput. 2️⃣ SIMD coverage is uneven: fast forward scans don't guarantee speedy reverse searches, hashing and case-mapping is not even part of the standard. 3️⃣ Many higher-level languages can't rely on libc at all because their strings aren't NUL-terminated - or may even contain embedded zeroes. That's why StringZilla exists: predictable, high performance on every modern platform, OS, and programming language.

StringZilla Python installs StringZilla Rust installs StringZilla code size

StringZilla is the GodZilla of string libraries, using SIMD and SWAR to accelerate binary and UTF-8 string operations on modern CPUs and GPUs. It delivers up to 10x higher CPU throughput in C, C++, Rust, Python, and other languages, and can be 100x faster than existing GPU kernels, covering a broad range of functionality. It accelerates exact and fuzzy string matching, hashing, edit distance computations, sorting, provides allocation-free lazily-evaluated smart-iterators, and even random-string generators.

  • 🐂 C: Upgrade LibC's <string.h> to <stringzilla/stringzilla.h> in C 99
  • 🐉 C++: Upgrade STL's <string> to <stringzilla/stringzilla.hpp> in C++ 11
  • 🧮 CUDA: Process in-bulk with <stringzillas/stringzillas.cuh> in CUDA C++ 17
  • 🐍 Python: Upgrade your str to faster Str
  • 🦀 Rust: Use the StringZilla traits crate
  • 🦫 Go: Use the StringZilla cGo module
  • 🍎 Swift: Use the String+StringZilla extension
  • 🟨 JavaScript: Use the StringZilla library
  • 🐚 Shell: Accelerate common CLI tools with sz- prefix
  • 📚 Researcher? Jump to Algorithms & Design Decisions
  • 💡 Thinking to contribute? Look for "good first issues"
  • 🤝 And check the guide to set up the environment
  • Want more bindings or features? Let me know!

Who is this for?

  • For data-engineers parsing large datasets, like the CommonCrawl, RedPajama, or LAION.
  • For software engineers optimizing strings in their apps and services.
  • For bioinformaticians and search engineers looking for edit-distances for USearch.
  • For DBMS devs, optimizing LIKE, ORDER BY, and GROUP BY operations.
  • For hardware designers, needing a SWAR baseline for string-processing functionality.
  • For students studying SIMD/SWAR applications to non-data-parallel operations.

Performance

C C++ Python StringZilla
Unicode case-folding, expanding characters like ßss
.casefold
x86: 0.4 GB/s
sz.utf8_case_fold
x86: 1.3 GB/s
Unicode case-insensitive substring search
icu.StringSearch
x86: 0.02 GB/s
utf8_case_insensitive_find
x86: 3.0 GB/s
find the first occurrence of a random word from text, ≅ 5 bytes long
strstr 1
x86: 7.4 · arm: 2.0 GB/s
.find
x86: 2.9 · arm: 1.6 GB/s
.find
x86: 1.1 · arm: 0.6 GB/s
sz_find
x86: 10.6 · arm: 7.1 GB/s
find the last occurrence of a random word from text, ≅ 5 bytes long
.rfind
x86: 0.5 · arm: 0.4 GB/s
.rfind
x86: 0.9 · arm: 0.5 GB/s
sz_rfind
x86: 10.8 · arm: 6.7 GB/s
split lines separated by \n or \r 2
strcspn 1
x86: 5.42 · arm: 2.19 GB/s
.find_first_of
x86: 0.59 · arm: 0.46 GB/s
re.finditer
x86: 0.06 · arm: 0.02 GB/s
sz_find_byteset
x86: 4.08 · arm: 3.22 GB/s
find the last occurrence of any of 6 whitespaces 2
.find_last_of
x86: 0.25 · arm: 0.25 GB/s
sz_rfind_byteset
x86: 0.43 · arm: 0.23 GB/s
Random string from a given alphabet, 20 bytes long 3
rand() % n
x86: 18.0 · arm: 9.4 MB/s
uniform_int_distribution
x86: 47.2 · arm: 20.4 MB/s
join(random.choices(x))
x86: 13.3 · arm: 5.9 MB/s
sz_fill_random
x86: 56.2 · arm: 25.8 MB/s
Mapping characters with lookup table transforms
std::transform
x86: 3.81 · arm: 2.65 GB/s
str.translate
x86: 260.0 · arm: 140.0 MB/s
sz_lookup
x86: 21.2 · arm: 8.5 GB/s
Get sorted order, ≅ 8 million English words 4
qsort_r
x86: 3.55 · arm: 5.77 s
std::sort
x86: 2.79 · arm: 4.02 s
numpy.argsort
x86: 7.58 · arm: 13.00 s
sz_sequence_argsort
x86: 1.91 · arm: 2.37 s
Levenshtein edit distance, text lines ≅ 100 bytes long
via NLTK 5 and CuDF
x86: 1,615,306 · arm: 1,349,980 · cuda: 6,532,411,354 CUPS
szs_levenshtein_distances_t
x86: 3,434,427,548 · arm: 1,605,340,403 · cuda: 93,662,026,653 CUPS
Needleman-Wunsch alignment scores, proteins ≅ 1 K amino acids long
via biopython 6
x86: 575,981,513 · arm: 436,350,732 CUPS
szs_needleman_wunsch_scores_t
x86: 452,629,942 · arm: 520,170,239 · cuda: 9,017,327,818 CUPS

Most StringZilla modules ship ready-to-run benchmarks for C, C++, Python, and more. Grab them from ./scripts, and see CONTRIBUTING.md for instructions. On CPUs that permit misaligned loads, even the 64-bit SWAR baseline outruns both libc and the STL. For wider head-to-heads against Rust and Python favorites, browse the StringWars repository. To inspect collision resistance and distribution shapes for our hashers, see HashEvals.

Most benchmarks were conducted on a 1 GB English text corpus, with an average word length of 6 characters. The code was compiled with GCC 12, using glibc v2.35. The benchmarks were performed on Arm-based Graviton3 AWS c7g instances and r7iz Intel Sapphire Rapids. Most modern Arm-based 64-bit CPUs will have similar relative speedups. Variance within x86 CPUs will be larger. For CUDA benchmarks, the Nvidia H100 GPUs were used. 1 Unlike other libraries, LibC requires strings to be NULL-terminated. 2 Six whitespaces in the ASCII set are: \t\n\v\f\r. Python's and other standard libraries have specialized functions for those. 3 All modulo operations were conducted with uint8_t to allow compilers more optimization opportunities. The C++ STL and StringZilla benchmarks used a 64-bit Mersenne Twister as the generator. For C, C++, and StringZilla, an in-place update of the string was used. In Python every string had to be allocated as a new object, which makes it less fair. 4 Contrary to the popular opinion, Python's default sorted function works faster than the C and C++ standard libraries. That holds for large lists or tuples of strings, but fails as soon as you need more complex logic, like sorting dictionaries by a string key, or producing the "sorted order" permutation. The latter is very common in database engines and is most similar to numpy.argsort. The current StringZilla solution can be at least 4x faster without loss of generality. 5 Most Python libraries for strings are also implemented in C. 6 Unlike the rest of BioPython, the alignment score computation is implemented in C.

Functionality

StringZilla is compatible with most modern CPUs, and provides a broad range of functionality. It's split into 2 layers:

  1. StringZilla: single-header C library and C++ wrapper for high-performance string operations.
  2. StringZillas: parallel CPU/GPU backends used for large-batch operations and accelerators.

Having a second C++/CUDA layer greatly simplifies the implementation of similarity scoring and fingerprinting functions, which would otherwise require too much error-prone boilerplate code in pure C. Both layers are designed to be extremely portable:

  • across both little-endian and big-endian architectures.
  • across 32-bit and 64-bit hardware architectures.
  • across operating systems and compilers.
  • across ASCII and UTF-8 encoded inputs.

Not all features are available across all bindings. Consider contributing if you need a feature that's not yet implemented.

Maturity C C++ Python Rust JS Swift Go
Substring Search 🌳
Character Set Search 🌳
Sorting & Sequence Operations 🌳
Lazy Ranges, Compressed Arrays 🌳
One-Shot & Streaming Hashes 🌳
Cryptographic Hashes 🌳
Small String Class 🧐
Random String Generation 🌳
Unicode Case Folding 🧐
Case-Insensitive UTF-8 Search 🚧
TR29 Word Boundary Detection 🚧
Parallel Similarity Scoring 🌳
Parallel Rolling Fingerprints 🌳

🌳 parts are used in production. 🧐 parts are in beta. 🚧 parts are under active development, and are likely to break in subsequent releases. ✅ are implemented. ⚪ are considered. ❌ are not intended.

Quick Start: Python

Python bindings are available on PyPI for Python 3.8+, and can be installed with pip.

pip install stringzilla         # for serial algorithms
pip install stringzillas-cpus   # for parallel multi-CPU backends
pip install stringzillas-cuda   # for parallel Nvidia GPU backend

You can immediately check the installed version and the used hardware capabilities with following commands:

python -c "import stringzilla; print(stringzilla.__version__)"
python -c "import stringzillas; print(stringzillas.__version__)"
python -c "import stringzilla; print(stringzilla.__capabilities__)"     # for serial algorithms
python -c "import stringzillas; print(stringzillas.__capabilities__)"   # for parallel algorithms

Basic Usage

If you've ever used the Python str, bytes, bytearray, or memoryview classes, you'll know what to expect. StringZilla's Str class is a hybrid of the above, providing a str-like interface to byte arrays.

from stringzilla import Str, File

text_from_str = Str('some-string') # no copies, just a view
text_from_bytes = Str(b'some-array') # no copies, just a view
text_from_file = Str(File('some-file.txt')) # memory-mapped file

import numpy as np
alphabet_array = np.arange(ord("a"), ord("z"), dtype=np.uint8)
text_from_array = Str(memoryview(alphabet_array))

The File class memory-maps a file from persistent storage without loading its copy into RAM. The contents of that file would remain immutable, and the mapping can be shared by multiple Python processes simultaneously. A standard dataset pre-processing use case would be to map a sizable textual dataset like Common Crawl into memory, spawn child processes, and split the job between them.

Basic Operations

  • Length: len(text) -> int
  • Indexing: text[42] -> str
  • Slicing: text[42:46] -> Str
  • Substring check: 'substring' in text -> bool
  • Hashing: hash(text) -> int
  • String conversion: str(text) -> str

Advanced Operations

import sys

x: bool = text.contains('substring', start=0, end=sys.maxsize)
x: int = text.find('substring', start=0, end=sys.maxsize)
x: int = text.count('substring', start=0, end=sys.maxsize, allowoverlap=False)
x: str = text.decode(encoding='utf-8', errors='strict')
x: Strs = text.split(separator=' ', maxsplit=sys.maxsize, keepseparator=False)
x: Strs = text.rsplit(separator=' ', maxsplit=sys.maxsize, keepseparator=False)
x: Strs = text.splitlines(keeplinebreaks=False, maxsplit=sys.maxsize)

It's important to note that the last function's behavior is slightly different from Python's str.splitlines. The native version matches \n, \r, \v or \x0b, \f or \x0c, \x1c, \x1d, \x1e, \x85, \r\n, \u2028, \u2029, including 3x two-byte-long runes. The StringZilla version matches only \n, \v, \f, \r, \x1c, \x1d, \x1e, \x85, avoiding two-byte-long runes.

Character Set Operations

Python strings don't natively support character set operations. This forces people to use regular expressions, which are slow and hard to read. To avoid the need for re.finditer, StringZilla provides the following interfaces:

x: int = text.find_first_of('chars', start=0, end=sys.maxsize)
x: int = text.find_last_of('chars', start=0, end=sys.maxsize)
x: int = text.find_first_not_of('chars', start=0, end=sys.maxsize)
x: int = text.find_last_not_of('chars', start=0, end=sys.maxsize)
x: Strs = text.split_byteset(separator='chars', maxsplit=sys.maxsize, keepseparator=False)
x: Strs = text.rsplit_byteset(separator='chars', maxsplit=sys.maxsize, keepseparator=False)

StringZilla also provides string trimming functions and random string generation:

x: str = text.lstrip('chars')  # Strip leading characters
x: str = text.rstrip('chars')  # Strip trailing characters
x: str = text.strip('chars')   # Strip both ends
x: bytes = sz.random(length=100, seed=42, alphabet='ACGT')  # Random string generation
sz.fill_random(buffer, seed=42, alphabet=None)  # Fill mutable buffer with random bytes

You can also transform the string using Look-Up Tables (LUTs), mapping it to a different character set. This would result in a copy - str for str inputs and bytes for other types.

x: str = text.translate('chars', {}, start=0, end=sys.maxsize, inplace=False)
x: bytes = text.translate(b'chars', {}, start=0, end=sys.maxsize, inplace=False)

For efficiency reasons, pass the LUT as a string or bytes object, not as a dictionary. This can be useful in high-throughput applications dealing with binary data, including bioinformatics and image processing. Here is an example:

import stringzilla as sz
look_up_table = bytes(range(256)) # Identity LUT
image = open("/image/path.jpeg", "rb").read()
sz.translate(image, look_up_table, inplace=True)

Hash

Single-shot and incremental hashing are both supported:

import stringzilla as sz

# One-shot - stable 64-bit output across all platforms!
one = sz.hash(b"Hello, world!", seed=42)

# Incremental updates return itself; digest does not consume state
hasher = sz.Hasher(seed=42)
hasher.update(b"Hello, ").update(b"world!")
streamed = hasher.digest() # or `hexdigest()` for a string
assert one == streamed

SHA-256 Checksums

SHA-256 cryptographic checksums are also available for single-shot and incremental hashing:

import stringzilla as sz

# One-shot SHA-256
digest_bytes = sz.sha256(b"Hello, world!")
assert len(digest_bytes) == 32

# Incremental SHA-256
hasher = sz.Sha256()
hasher.update(b"Hello, ").update(b"world!")
digest_bytes = hasher.digest()
digest_hex = hasher.hexdigest()  # 64 character lowercase hex string

# HMAC-SHA256 for message authentication
mac = sz.hmac_sha256(key=b"secret", message=b"Hello, world!")

StringZilla integrates seamlessly with memory-mapped files for efficient large file processing. The traditional approach with hashlib:

import hashlib

with open("xlsum.csv", "rb") as streamed_file:
    hasher = hashlib.sha256()
    while chunk := streamed_file.read(4096):
        hasher.update(chunk)
    checksum = hasher.hexdigest()

Can be simplified with StringZilla:

from stringzilla import Sha256, File

mapped_file = File("xlsum.csv")
checksum = Sha256().update(mapped_file).hexdigest()

Both output the same digest: 7278165ce01a4ac1e8806c97f32feae908036ca3d910f5177d2cf375e20aeae1. OpenSSL (powering hashlib) has faster Assembly kernels, but StringZilla avoids file I/O overhead with memory mapping and skips Python's abstraction layers:

  • OpenSSL-backed hashlib.sha256: 12.6s
  • StringZilla end-to-end: 4.0s — 3× faster!

Unicode Case-Folding and Case-Insensitive Search

StringZilla implements both Unicode Case Folding and Case-Insensitive UTF-8 Search. Unlike most libraries only capable of lower-casing ASCII-represented English alphabet, StringZilla covers over 1M+ codepoints. The case-folding API expects the output buffer to be at least 3× larger than the input, to accommodate for the worst-case character expansions scenarios.

import stringzilla as sz

sz.utf8_case_fold('HELLO')      # b'hello'
sz.utf8_case_fold('Straße')     # b'strasse' — ß (1 char) expands to "ss" (2 chars)
sz.utf8_case_fold('efficient')    # b'efficient' — ffi ligature (1 char) expands to "ffi" (3 chars)

The case-insensitive search returns the byte offset of the match, handling expansions correctly.

import stringzilla as sz

sz.utf8_case_insensitive_find('Der große Hund', 'GROSSE')   # 4 — finds "große" at codepoint 4
sz.utf8_case_insensitive_find('Straße', 'STRASSE')          # 0 — ß matches "SS"
sz.utf8_case_insensitive_find('efficient', 'EFFICIENT')       # 0 — ffi ligature matches "FFI"

# Iterator for finding ALL matches
haystack = 'Straße STRASSE strasse'
for match in sz.utf8_case_insensitive_find_iter(haystack, 'strasse'):
    print(match, match.offset_within(haystack))  # Yields: 'Straße', 'STRASSE', 'strasse'

# With overlapping matches
list(sz.utf8_case_insensitive_find_iter('aaaa', 'aa'))  # ['aa', 'aa'] — 2 non-overlapping
list(sz.utf8_case_insensitive_find_iter('aaaa', 'aa', include_overlapping=True))  # 3 matches

Collection-Level Operations

Once split into a Strs object, you can sort, shuffle, and reorganize the slices with minimal memory footprint. If all the chunks are located in consecutive memory regions, the memory overhead can be as low as 4 bytes per chunk.

lines: Strs = text.split(separator='\n') # 4 bytes per line overhead for under 4 GB of text
batch: Strs = lines.sample(seed=42) # 10x faster than `random.choices`
lines_shuffled: Strs = lines.shuffled(seed=42) # or shuffle all lines and shard with slices
lines_sorted: Strs = lines.sorted() # returns a new Strs in sorted order
order: tuple = lines.argsort() # similar to `numpy.argsort`

Working on RedPajama, addressing 20 billion annotated English documents, one will need only 160 GB of RAM instead of terabytes. Once loaded, the data will be memory-mapped, and can be reused between multiple Python processes without copies. And of course, you can use slices to navigate the dataset and shard it between multiple workers.

lines[::3] # every third line
lines[1::1] # every odd line
lines[:-100:-1] # last 100 lines in reverse order

Iterators and Memory Efficiency

Python's operations like split() and readlines() immediately materialize a list of copied parts. This can be very memory-inefficient for large datasets. StringZilla saves a lot of memory by viewing existing memory regions as substrings, but even more memory can be saved by using lazily evaluated iterators.

x: SplitIterator[Str] = text.split_iter(separator=' ', keepseparator=False)
x: SplitIterator[Str] = text.rsplit_iter(separator=' ', keepseparator=False)
x: SplitIterator[Str] = text.split_byteset_iter(separator='chars', keepseparator=False)
x: SplitIterator[Str] = text.rsplit_byteset_iter(separator='chars', keepseparator=False)

StringZilla can easily be 10x more memory efficient than native Python classes for tokenization. With lazy operations, it practically becomes free.

import stringzilla as sz
%load_ext memory_profiler

text = open("enwik9.txt", "r").read() # 1 GB, mean word length 7.73 bytes
%memit text.split() # increment: 8670.12 MiB (152 ms)
%memit sz.split(text) # increment: 530.75 MiB (25 ms)
%memit sum(1 for _ in sz.split_iter(text)) # increment: 0.00 MiB

Low-Level Python API

Aside from calling the methods on the Str and Strs classes, you can also call the global functions directly on str and bytes instances. Assuming StringZilla CPython bindings are implemented without any intermediate tools like SWIG or PyBind, the call latency should be similar to native classes.

import stringzilla as sz

contains: bool = sz.contains("haystack", "needle", start=0, end=sys.maxsize)
offset: int = sz.find("haystack", "needle", start=0, end=sys.maxsize)
count: int = sz.count("haystack", "needle", start=0, end=sys.maxsize, allowoverlap=False)

Similarity Scores

StringZilla exposes high-performance, batch-oriented similarity via the stringzillas module. Use DeviceScope to pick hardware and optionally limit capabilities per engine.

import stringzilla as sz
import stringzillas as szs

cpu_scope = szs.DeviceScope(cpu_cores=4)    # force CPU-only
gpu_scope = szs.DeviceScope(gpu_device=0)   # pick GPU 0 if available

strings_a = sz.Strs(["kitten", "flaw"])
strings_b = sz.Strs(["sitting", "lawn"])

strings_a = szs.to_device(strings_a) # optional ahead of time transfer
strings_b = szs.to_device(strings_b) # optional ahead of time transfer

engine = szs.LevenshteinDistances(
    match=0, mismatch=2,        # costs don't have to be 1
    open=3, extend=1,           # may be different in Bio
    capabilities=("serial",)    # avoid SIMD 🤭
)
distances = engine(strings_a, strings_b, device=cpu_scope)
assert int(distances[0]) == 3 and int(distances[1]) == 2

Note, that this computes byte-level distances. For UTF-8 codepoints, use a different engine class:

strings_a = sz.Strs(["café", "αβγδ"])
strings_b = sz.Strs(["cafe", "αγδ"])
engine = szs.LevenshteinDistancesUTF8(capabilities=("serial",))
distances = engine(strings_a, strings_b, device=cpu_scope)
assert int(distances[0]) == 1 and int(distances[1]) == 1

For alignment scoring provide a 256×256 substitution matrix using NumPy:

import numpy as np
import stringzilla as sz
import stringzillas as szs

substitution_matrix = np.zeros((256, 256), dtype=np.int8)
substitution_matrix.fill(-1)                # mismatch score
np.fill_diagonal(substitution_matrix, 0)    # match score

engine = szs.NeedlemanWunsch(substitution_matrix=substitution_matrix, open=1, extend=1)
scores = engine(strings_a, strings_b, device=cpu_scope)

Several Python libraries provide edit distance computation. Most are implemented in C but may be slower than StringZilla on large inputs. For proteins ~10k chars, 100 pairs:

Using the same proteins for Needleman-Wunsch alignment scores:

§ Example converting from BioPython to StringZilla.
import numpy as np
from Bio import Align
from Bio.Align import substitution_matrices

aligner = Align.PairwiseAligner()
aligner.substitution_matrix = substitution_matrices.load("BLOSUM62")
aligner.open_gap_score = 1
aligner.extend_gap_score = 1

# Convert the matrix to NumPy
subs_packed = np.array(aligner.substitution_matrix).astype(np.int8)
subs_reconstructed = np.zeros((256, 256), dtype=np.int8)

# Initialize all banned characters to a the largest possible penalty
subs_reconstructed.fill(127)
for packed_row, packed_row_aminoacid in enumerate(aligner.substitution_matrix.alphabet):
    for packed_column, packed_column_aminoacid in enumerate(aligner.substitution_matrix.alphabet):
        reconstructed_row = ord(packed_row_aminoacid)
        reconstructed_column = ord(packed_column_aminoacid)
        subs_reconstructed[reconstructed_row, reconstructed_column] = subs_packed[packed_row, packed_column]

# Let's pick two examples of tripeptides (made of 3 amino acids)
glutathione = "ECG" # Need to rebuild human tissue?
thyrotropin_releasing_hormone = "QHP" # Or to regulate your metabolism?

import stringzillas as szs
engine = szs.NeedlemanWunsch(substitution_matrix=subs_reconstructed, open=1, extend=1)
score = int(engine(sz.Strs([glutathione]), sz.Strs([thyrotropin_releasing_hormone]))[0])
assert score == aligner.score(glutathione, thyrotropin_releasing_hormone) # Equal to 6

Rolling Fingerprints

MinHashing is a common technique for Information Retrieval, producing compact representations of large documents. For $D$ hash-functions and a text of length $L$, in the worst case it involves computing $O(D \cdot L)$ hashes.

import numpy as np
import stringzilla as sz
import stringzillas as szs

texts = sz.Strs([
    "quick brown fox jumps over the lazy dog",
    "quick brown fox jumped over a very lazy dog",
])

cpu = szs.DeviceScope(cpu_cores=4)
ndim = 1024
window_widths = np.array([4, 6, 8, 10], dtype=np.uint64)
engine = szs.Fingerprints(
    ndim=ndim,
    window_widths=window_widths,    # optional
    alphabet_size=256,              # default for byte strings
    capabilities=("serial",),       # defaults to all, can also pass a `DeviceScope`
)

hashes, counts = engine(texts, device=cpu)
assert hashes.shape == (len(texts), ndim)
assert counts.shape == (len(texts), ndim)
assert hashes.dtype == np.uint32 and counts.dtype == np.uint32

Serialization

Filesystem

Similar to how File can be used to read a large file, other interfaces can be used to dump strings to disk faster. The Str class has write_to to write the string to a file, and offset_within to obtain integer offsets of substring view in larger string for navigation.

web_archive = Str("<html>...</html><html>...</html>")
_, end_tag, next_doc = web_archive.partition("</html>") # or use `find`
next_doc_offset = next_doc.offset_within(web_archive)
web_archive.write_to("next_doc.html") # no GIL, no copies, just a view

PyArrow

A Str is easy to cast to PyArrow buffers.

from pyarrow import foreign_buffer
from stringzilla import Strs

strs = Strs(["alpha", "beta", "gamma"])
arrow = foreign_buffer(strs.address, strs.nbytes, strs)

And only slightly harder to convert in reverse direction:

arr = pa.Array.from_buffers(
    pa.large_string() if strs.offsets_are_large else pa.string(),
    len(strs),
    [None,
     pa.foreign_buffer(strs.offsets_address, strs.offsets_nbytes, strs),
     pa.foreign_buffer(strs.tape_address, strs.tape_nbytes, strs)],
)

That means you can convert Str to pyarrow.Buffer and Strs to pyarrow.Array without extra copies. For more details on the tape-like layouts, refer to the StringTape repository.

Quick Start: C/C++

The C library is header-only, so you can just copy the stringzilla.h header into your project. Same applies to C++, where you would copy the stringzilla.hpp header. Alternatively, add it as a submodule, and include it in your build system.

git submodule add https://github.com/ashvardanian/StringZilla.git external/stringzilla
git submodule update --init --recursive

Or using a pure CMake approach:

FetchContent_Declare(
    stringzilla
    GIT_REPOSITORY https://github.com/ashvardanian/StringZilla.git
    GIT_TAG main  # or specify a version tag
)
FetchContent_MakeAvailable(stringzilla)

Last, but not the least, you can also install it as a library, and link against it. This approach is worse for inlining, but brings dynamic runtime dispatch for the most advanced CPU features.

Basic Usage with C 99 and Newer

There is a stable C 99 interface, where all function names are prefixed with sz_. Most interfaces are well documented, and come with self-explanatory names and examples. In some cases, hardware specific overloads are available, like sz_find_skylake or sz_find_neon. Both are companions of the sz_find, first for x86 CPUs with AVX-512 support, and second for Arm NEON-capable CPUs.

#include <stringzilla/stringzilla.h>

// Initialize your haystack and needle
sz_string_view_t haystack = {your_text, your_text_length};
sz_string_view_t needle = {your_subtext, your_subtext_length};

// Perform string-level operations auto-picking the backend or dispatching manually
sz_cptr_t ptr = sz_find(haystack.start, haystack.length, needle.start, needle.length);
sz_size_t substring_position = ptr ? (sz_size_t)(ptr - haystack.start) : SZ_SIZE_MAX; // SZ_SIZE_MAX if not found

// Backend-specific variants return pointers as well
sz_cptr_t ptr = sz_find_skylake(haystack.start, haystack.length, needle.start, needle.length);
sz_cptr_t ptr = sz_find_haswell(haystack.start, haystack.length, needle.start, needle.length);
sz_cptr_t ptr = sz_find_westmere(haystack.start, haystack.length, needle.start, needle.length);
sz_cptr_t ptr = sz_find_neon(haystack.start, haystack.length, needle.start, needle.length);

// Hash strings at once
sz_u64_t hash = sz_hash(haystack.start, haystack.length, 42);    // 42 is the seed
sz_u64_t checksum = sz_bytesum(haystack.start, haystack.length); // or accumulate byte values

// Hash strings incrementally with "init", "update", and "digest":
sz_hash_state_t state;
sz_hash_state_init(&state, 42);
sz_hash_state_update(&state, haystack.start, 1);                        // first char
sz_hash_state_update(&state, haystack.start + 1, haystack.length - 1);  // rest of the string
sz_u64_t streamed_hash = sz_hash_state_digest(&state);

// SHA-256 cryptographic checksums
sz_u8_t digest[32];
sz_sha256_state_t sha_state;
sz_sha256_state_init(&sha_state);
sz_sha256_state_update(&sha_state, haystack.start, haystack.length);
sz_sha256_state_digest(&sha_state, digest);

// Perform collection level operations
sz_sequence_t array = {your_handle, your_count, your_get_start, your_get_length};
sz_sorted_idx_t order[your_count];
sz_sequence_argsort(&array, NULL, order); // NULL allocator uses default
§ Mapping from LibC to StringZilla.

By design, StringZilla has a couple of notable differences from LibC:

  1. all strings are expected to have a length, and are not necessarily null-terminated.
  2. every operations has a reverse order counterpart.

That way sz_find and sz_rfind are similar to strstr and strrstr in LibC. Similarly, sz_find_byte and sz_rfind_byte replace memchr and memrchr. The sz_find_byteset maps to strspn and strcspn, while sz_rfind_byteset has no sibling in LibC.

LibC Functionality StringZilla Equivalents
memchr(haystack, needle, haystack_length), strchr sz_find_byte(haystack, haystack_length, needle)
memrchr(haystack, needle, haystack_length) sz_rfind_byte(haystack, haystack_length, needle)
memcmp, strcmp sz_order, sz_equal
strlen(haystack) sz_find_byte(haystack, haystack_length, needle)
strcspn(haystack, reject) sz_find_byteset(haystack, haystack_length, reject_bitset)
strspn(haystack, accept) sz_find_byte_not_from(haystack, haystack_length, accept, accept_length)
memmem(haystack, haystack_length, needle, needle_length), strstr sz_find(haystack, haystack_length, needle, needle_length)
memcpy(destination, source, destination_length) sz_copy(destination, source, destination_length)
memmove(destination, source, destination_length) sz_move(destination, source, destination_length)
memset(destination, value, destination_length) sz_fill(destination, destination_length, value)

Basic Usage with C++ 11 and Newer

There is a stable C++ 11 interface available in the ashvardanian::stringzilla namespace. It comes with two STL-like classes: string_view and string. The first is a non-owning view of a string, and the second is a mutable string with a Small String Optimization.

#include <stringzilla/stringzilla.hpp>

namespace sz = ashvardanian::stringzilla;

sz::string haystack = "some string";
sz::string_view needle = sz::string_view(haystack).substr(0, 4);

auto substring_position = haystack.find(needle); // Or `rfind`
auto hash = std::hash<sz::string_view>{}(haystack); // Compatible with STL's `std::hash`

haystack.end() - haystack.begin() == haystack.size(); // Or `rbegin`, `rend`
haystack.find_first_of(" \v\t") == 4; // Or `find_last_of`, `find_first_not_of`, `find_last_not_of`
haystack.starts_with(needle) == true; // Or `ends_with`
haystack.remove_prefix(needle.size()); // Why is this operation in-place?!
haystack.contains(needle) == true; // STL has this only from C++ 23 onwards
haystack.compare(needle) == 1; // Or `haystack <=> needle` in C++ 20 and beyond

StringZilla also provides string literals for automatic type resolution, similar to STL:

using sz::literals::operator""_sv;
using std::literals::operator""sv;

auto a = "some string"; // char const *
auto b = "some string"sv; // std::string_view
auto b = "some string"_sv; // sz::string_view

Unicode Case-Folding and Case-Insensitive Search

StringZilla implements both Unicode Case Folding and Case-Insensitive UTF-8 Search. Unlike most libraries only capable of lower-casing ASCII-represented English alphabet, StringZilla covers over 1M+ codepoints. The case-folding API expects the output buffer to be at least 3× larger than the input, to accommodate for the worst-case character expansions scenarios.

char source[] = "Straße";  // German: "Street"
char destination[64];      // Must be at least 3x source length
sz_size_t result_len = sz_utf8_case_fold(source, strlen(source), destination);
// destination now contains "strasse" (7 bytes), result_len = 7

The case-insensitive search API returns a pointer to the start of the first relevant glyph in the haystack, or NULL if not found. It outputs the length of the matched haystack substring in bytes, and accepts a metadata structure to speed up repeated searches for the same needle.

sz_utf8_case_insensitive_needle_metadata_t metadata = {};
sz_size_t match_length;
sz_cptr_t match = sz_utf8_case_insensitive_find(
    haystack, haystack_len,
    needle, needle_len,
    &metadata,      // Reuse for queries with the same needle
    &match_length   // Output: bytes consumed in haystack
);

Same functionality is available in C++:

namespace sz = ashvardanian::stringzilla;

sz::string_view text = "Hello World"; // Single search
auto [offset, length] = text.utf8_case_insensitive_find("HELLO");

sz::utf8_case_insensitive_needle pattern("hello"); // Repeated searches with pre-compiled pattern
for (auto const& haystack : haystacks)
    auto match = haystack.utf8_case_insensitive_find(pattern);

Similarity Scores

StringZilla exposes high-performance, batch-oriented similarity via the stringzillas/stringzillas.h header. Use szs_device_scope_t to pick hardware and optionally limit capabilities per engine.

#include <stringzillas/stringzillas.h>

szs_device_scope_t device = NULL;
szs_device_scope_init_default(&device);

szs_levenshtein_distances_t engine = NULL;
szs_levenshtein_distances_init(0, 1, 1, 1, /*alloc*/ NULL, /*caps*/ sz_cap_serial_k, &engine);

sz_sequence_u32tape_t strings_a {data_a, offsets_a, count}; // or `sz_sequence_u64tape_t` for large inputs
sz_sequence_u32tape_t strings_b {data_b, offsets_b, count}; // or `sz_sequence_t` to pass generic containers

sz_size_t distances[count];
szs_levenshtein_distances_u32tape(engine, device, &strings_a, &strings_b, distances, sizeof(distances[0]));

szs_levenshtein_distances_free(engine);
szs_device_scope_free(device);

To target a different device, use the appropriate szs_device_scope_init_{cpu_cores,gpu_device} function. When dealing with GPU backends, make sure to use the "unified memory" allocators exposed as szs_unified_{alloc,free}. Similar stable C ABIs are exposed for other workloads as well.

  • UTF-8: szs_levenshtein_distances_utf8_{sequence,u32tape,u64tape}
  • Needleman-Wunsch: szs_needleman_wunsch_scores_{sequence,u32tape,u64tape}
  • Smith-Waterman: szs_smith_waterman_scores_{sequence,u32tape,u64tape}

Moreover, in C++ codebases one can tap into the raw templates implementing that functionality, customizing them with custom executors, SIMD plugins, etc. For that include stringzillas/similarities.hpp for C++ and stringzillas/similarities.cuh for CUDA.

#include <stringzillas/similarities.hpp>
#include <stringzilla/types.hpp>       // tape of strings
#include <fork_union.hpp>              // optional thread pool

namespace sz = ashvardanian::stringzilla;
namespace szs = ashvardanian::stringzillas;

// Pack strings into an Arrow-like tape
std::vector<std::string> left = {"kitten", "flaw"};
std::vector<std::string> right = {"sitting", "lawn"};
sz::arrow_strings_tape<char, sz::size_t, std::allocator<char>> tape_a, tape_b;
auto _ = tape_a.try_assign(left.begin(), left.end());
auto _ = tape_b.try_assign(right.begin(), right.end());

// Run on the current thread
using levenshtein_t = szs::levenshtein_distances<char, szs::linear_gap_costs_t, std::allocator<char>, sz_cap_serial_k>;
levenshtein_t engine {szs::uniform_substitution_costs_t{0,1}, szs::linear_gap_costs_t{1}};
std::size_t distances[2];
auto _ = engine(tape_a, tape_b, distances);

// Or run in parallel with a pool
fork_union::basic_pool_t pool;
auto _ = pool.try_spawn(std::thread::hardware_concurrency());
auto _ = engine(tape_a, tape_b, distances, pool);

All of the potentially failing StringZillas' interfaces return error codes, and none raise C++ exceptions. Parallelism is enabled at both collection-level and within individual pairs of large inputs.

Rolling Fingerprints

StringZilla exposes parallel fingerprinting (Min-Hashes or Count-Min-Sketches) via the stringzillas/stringzillas.h header. Use szs_device_scope_t to pick hardware and optionally limit capabilities per engine.

#include <stringzillas/stringzillas.h>

szs_device_scope_t device = NULL;
szs_device_scope_init_default(&device);

szs_fingerprints_t engine = NULL;
sz_size_t const dims = 1024; sz_size_t const window_widths[] = {4, 6, 8, 10};
szs_fingerprints_init(dims, /*alphabet*/ 256, window_widths, 4, /*alloc*/ NULL, /*caps*/ sz_cap_serial_k, &engine);

sz_sequence_u32tape_t texts = {data, offsets, count};
sz_u32_t *min_hashes = (sz_u32_t*)szs_unified_alloc(count * dims * sizeof(*min_hashes));
sz_u32_t *min_counts = (sz_u32_t*)szs_unified_alloc(count * dims * sizeof(*min_counts));
szs_fingerprints_u32tape(engine, device, &texts,
    min_hashes, dims * sizeof(*min_hashes),     // support strided matrices
    min_counts, dims * sizeof(*min_counts));    // for both output arguments

szs_fingerprints_free(engine);
szs_device_scope_free(device);

Moreover, in C++ codebases one can tap into the raw templates implementing that functionality, customizing them with custom executors, SIMD plugins, etc. For that include stringzillas/fingerprints.hpp for C++ and stringzillas/fingerprints.cuh for CUDA.

#include <stringzillas/fingerprints.hpp>
#include <stringzilla/types.hpp>       // tape of strings
#include <fork_union.hpp>              // optional thread pool

namespace sz = ashvardanian::stringzilla;
namespace szs = ashvardanian::stringzillas;

// Pack strings into an Arrow-like tape
std::vector<std::string> docs = {"alpha beta", "alpha betta"};
sz::arrow_strings_tape<char, sz::size_t, std::allocator<char>> tape;
auto _ = tape.try_assign(docs.begin(), docs.end());

// Run on the current thread with a Rabin-Karp family hasher
constexpr std::size_t dimensions_k = 256;
constexpr std::size_t window_width_k = 7;
using row_t = std::array<sz_u32_t, 256>;
using fingerprinter_t = szs::floating_rolling_hashers<sz_cap_serial_k, dimensions_k>;
fingerprinter_t engine;
auto _ = engine.try_extend(window_width_k, dimensions_k);
std::vector<row_t> hashes(docs.size()), counts(docs.size());
auto _ = engine(tape, hashes, counts);

// Or run in parallel with a pool
fork_union::basic_pool_t pool;
auto _ = pool.try_spawn(std::thread::hardware_concurrency());
auto _ = engine(tape, hashes, counts, pool);

CUDA

StringZilla provides CUDA C++ templates for composable string batch-processing operations. Different GPUs have varying warp sizes, shared memory capacities, and register counts, affecting algorithm selection, so it's important to query the gpu_specs_t via gpu_specs_fetch. For memory management, ensure that you use GPU-visible' unified memoryexposed in an STL-compatible manner as aunified_alloctemplate class. For error handling,cuda_status_textends the traditionalstatus_twith GPU-specific information. It's implicitly convertible tostatus_t, so you can use it in places expecting a status_t`.

Most algorithms can load-balance both a large number of small strings and a small number of large strings. Still, with large H100-scale GPUs, it's best to submit thousands of inputs at once.

Memory Ownership and Small String Optimization

Most operations in StringZilla don't assume any memory ownership. But in addition to the read-only search-like operations StringZilla provides a minimalistic C and C++ implementations for a memory owning string "class". Like other efficient string implementations, it uses the Small String Optimization (SSO) to avoid heap allocations for short strings.

typedef union sz_string_t {
    struct internal {
        sz_ptr_t start;
        sz_u8_t length;
        char chars[SZ_STRING_INTERNAL_SPACE]; /// Ends with a null-terminator.
    } internal;

    struct external {
        sz_ptr_t start;
        sz_size_t length;        
        sz_size_t space; /// The length of the heap-allocated buffer.
        sz_size_t padding;
    } external;

} sz_string_t;

As one can see, a short string can be kept on the stack, if it fits within internal.chars array. Before 2015 GCC string implementation was just 8 bytes, and could only fit 7 characters. Different STL implementations today have different thresholds for the Small String Optimization. Similar to GCC, StringZilla is 32 bytes in size, and similar to Clang it can fit 22 characters on stack. Our layout might be preferential, if you want to avoid branches. If you use a different compiler, you may want to check its SSO buffer size with a simple Gist.

libstdc++ in GCC 13 libc++ in Clang 17 StringZilla
String sizeof 32 24 32
Inner Capacity 15 22 22

This design has been since ported to many high-level programming languages. Swift, for example, can store 15 bytes in the String instance itself. StringZilla implements SSO at the C level, providing the sz_string_t union and a simple API for primary operations.

sz_memory_allocator_t allocator;
sz_string_t string;

// Init and make sure we are on stack
sz_string_init(&string);
sz_string_is_on_stack(&string); // == sz_true_k

// Optionally pre-allocate space on the heap for future insertions.
sz_string_grow(&string, 100, &allocator); // == sz_true_k

// Append, erase, insert into the string.
sz_string_expand(&string, 0, "_Hello_", 7, &allocator); // == sz_true_k
sz_string_expand(&string, SZ_SIZE_MAX, "world", 5, &allocator); // == sz_true_k
sz_string_erase(&string, 0, 1);

// Unpacking & introspection.
sz_ptr_t string_start;
sz_size_t string_length;
sz_size_t string_space;
sz_bool_t string_is_external;
sz_string_unpack(string, &string_start, &string_length, &string_space, &string_is_external);
sz_equal(string_start, "Hello_world", 11); // == sz_true_k

// Reclaim some memory.
sz_string_shrink_to_fit(&string, &allocator); // == sz_true_k
sz_string_free(&string, &allocator);

Unlike the conventional C strings, the sz_string_t is allowed to contain null characters. To safely print those, pass the string_length to printf as well.

printf("%.*s\n", (int)string_length, string_start);

What's Wrong with the C Standard Library?

StringZilla is not a drop-in replacement for the C Standard Library. It's designed to be a safer and more modern alternative. Conceptually:

  1. LibC strings are expected to be null-terminated, so to use the efficient LibC implementations on slices of larger strings, you'd have to copy them, which is more expensive than the original string operation.
  2. LibC functionality is asymmetric - you can find the first and the last occurrence of a character within a string, but you can't find the last occurrence of a substring.
  3. LibC function names are typically very short and cryptic.
  4. LibC lacks crucial functionality like hashing and doesn't provide primitives for less critical but relevant operations like fuzzy matching.

Something has to be said about its support for UTF-8. Aside from a single-byte char type, LibC provides wchar_t:

  • The size of wchar_t is not consistent across platforms. On Windows, it's typically 16 bits (suitable for UTF-16), while on Unix-like systems, it's usually 32 bits (suitable for UTF-32). This inconsistency can lead to portability issues when writing cross-platform code.
  • wchar_t is designed to represent wide characters in a fixed-width format (UTF-16 or UTF-32). In contrast, UTF-8 is a variable-length encoding, where each character can take from 1 to 4 bytes. This fundamental difference means that wchar_t and UTF-8 are incompatible.

StringZilla partially addresses those issues.

What's Wrong with the C++ Standard Library?

C++ Code Evaluation Result Invoked Signature
"Loose"s.replace(2, 2, "vath"s, 1) "Loathe" 🤢 (pos1, count1, str2, pos2)
"Loose"s.replace(2, 2, "vath", 1) "Love" 🥰 (pos1, count1, str2, count2)

StringZilla is designed to be a drop-in replacement for the C++ Standard Templates Library. That said, some of the design decisions of STL strings are highly controversial, error-prone, and expensive. Most notably:

  1. Argument order for replace, insert, erase and similar functions is impossible to guess.
  2. Bounds-checking exceptions for substr-like functions are only thrown for one side of the range.
  3. Returning string copies in substr-like functions results in absurd volume of allocations.
  4. Incremental construction via push_back-like functions goes through too many branches.
  5. Inconsistency between string and string_view methods, like the lack of remove_prefix and remove_suffix.

Check the following set of asserts validating the std::string specification. It's not realistic to expect the average developer to remember the 14 overloads of std::string::replace.

using str = std::string;

assert(str("hello world").substr(6) == "world");
assert(str("hello world").substr(6, 100) == "world"); // 106 is beyond the length of the string, but its OK
assert_throws(str("hello world").substr(100), std::out_of_range);   // 100 is beyond the length of the string
assert_throws(str("hello world").substr(20, 5), std::out_of_range); // 20 is beyond the length of the string
assert_throws(str("hello world").substr(-1, 5), std::out_of_range); // -1 casts to unsigned without any warnings...
assert(str("hello world").substr(0, -1) == "hello world");          // -1 casts to unsigned without any warnings...

assert(str("hello").replace(1, 2, "123") == "h123lo");
assert(str("hello").replace(1, 2, str("123"), 1) == "h23lo");
assert(str("hello").replace(1, 2, "123", 1) == "h1lo");
assert(str("hello").replace(1, 2, "123", 1, 1) == "h2lo");
assert(str("hello").replace(1, 2, str("123"), 1, 1) == "h2lo");
assert(str("hello").replace(1, 2, 3, 'a') == "haaalo");
assert(str("hello").replace(1, 2, {'a', 'b'}) == "hablo");

To avoid those issues, StringZilla provides an alternative consistent interface. It supports signed arguments, and doesn't have more than 3 arguments per function or The standard API and our alternative can be conditionally disabled with SZ_SAFETY_OVER_COMPATIBILITY=1. When it's enabled, the subjectively risky overloads from the Standard will be disabled.

using str = sz::string;

str("a:b").front(1) == "a"; // no checks, unlike `substr`
str("a:b").front(2) == "2"; // take first 2 characters
str("a:b").back(-1) == "b"; // accepting negative indices
str("a:b").back(-2) == ":b"; // similar to Python's `"a:b"[-2:]`
str("a:b").sub(1, -1) == ":"; // similar to Python's `"a:b"[1:-1]`
str("a:b").sub(-2, -1) == ":"; // similar to Python's `"a:b"[-2:-1]`
str("a:b").sub(-2, 1) == ""; // similar to Python's `"a:b"[-2:1]`
"a:b"_sv[{-2, -1}] == ":"; // works on views and overloads `operator[]`

Assuming StringZilla is a header-only library you can use the full API in some translation units and gradually transition to safer restricted API in others. Bonus - all the bound checking is branchless, so it has a constant cost and won't hurt your branch predictor.

Beyond the C++ Standard Library - Learning from Python

Python is arguably the most popular programming language for data science. In part, that's due to the simplicity of its standard interfaces. StringZilla brings some of that functionality to C++.

  • Content checks: isalnum, isalpha, isascii, isdigit, islower, isspace, isupper.
  • Trimming character sets: lstrip, rstrip, strip.
  • Trimming string matches: remove_prefix, remove_suffix.
  • Ranges of search results: splitlines, split, rsplit.
  • Number of non-overlapping substring matches: count.
  • Partitioning: partition, rpartition.

For example, when parsing documents, it is often useful to split it into substrings. Most often, after that, you would compute the length of the skipped part, the offset and the length of the remaining part. This results in a lot of pointer arithmetic and is error-prone. StringZilla provides a convenient partition function, which returns a tuple of three string views, making the code cleaner.

auto parts = haystack.partition(':'); // Matching a character
auto [before, match, after] = haystack.partition(':'); // Structure unpacking
auto [before, match, after] = haystack.partition(sz::byteset(":;")); // Character-set argument
auto [before, match, after] = haystack.partition(" : "); // String argument
auto [before, match, after] = haystack.rpartition(sz::whitespaces_set()); // Split around the last whitespace

Combining those with the split function, one can easily parse a CSV file or HTTP headers.

for (auto line : haystack.split("\r\n")) {
    auto [key, _, value] = line.partition(':');
    headers[key.strip()] = value.strip();
}

Some other extensions are not present in the Python standard library either. Let's go through the C++ functionality category by category.

Some of the StringZilla interfaces are not available even Python's native str class. Here is a sneak peek of the most useful ones.

text.hash(); // -> 64 bit unsigned integer 
text.ssize(); // -> 64 bit signed length to avoid `static_cast<std::ssize_t>(text.size())`
text.contains_only(" \w\t"); // == text.find_first_not_of(sz::byteset(" \w\t")) == npos;
text.contains(sz::whitespaces_set()); // == text.find(sz::byteset(sz::whitespaces_set())) != npos;

// Simpler slicing than `substr`
text.front(10); // -> sz::string_view
text.back(10); // -> sz::string_view

// Safe variants, which clamp the range into the string bounds
using sz::string::cap;
text.front(10, cap) == text.front(std::min(10, text.size()));
text.back(10, cap) == text.back(std::min(10, text.size()));

// Character set filtering
text.lstrip(sz::whitespaces_set()).rstrip(sz::newlines_set()); // like Python
text.front(sz::whitespaces_set()); // all leading whitespaces
text.back(sz::digits_set()); // all numerical symbols forming the suffix

// Incremental construction
using sz::string::unchecked;
text.push_back('x'); // no surprises here
text.push_back('x', unchecked); // no bounds checking, Rust style
text.try_push_back('x'); // returns `false` if the string is full and the allocation failed

sz::concatenate(text, "@", domain, ".", tld); // No allocations

Splits and Ranges

One of the most common use cases is to split a string into a collection of substrings. Which would often result in StackOverflow lookups and snippets like the one below.

std::vector<std::string> lines = split(haystack, "\r\n"); // string delimiter
std::vector<std::string> words = split(lines, ' '); // character delimiter

Those allocate memory for each string and the temporary vectors. Each allocation can be orders of magnitude more expensive, than even serial for-loop over characters. To avoid those, StringZilla provides lazily-evaluated ranges, compatible with the Range-v3 library.

for (auto line : haystack.split("\r\n"))
    for (auto word : line.split(sz::byteset(" \w\t.,;:!?")))
        std::cout << word << std::endl;

Each of those is available in reverse order as well. It also allows interleaving matches, if you want both inclusions of xx in xxx. Debugging pointer offsets is not a pleasant exercise, so keep the following functions in mind.

  • haystack.[r]find_all(needle, interleaving)
  • haystack.[r]find_all(sz::byteset(""))
  • haystack.[r]split(needle)
  • haystack.[r]split(sz::byteset(""))

For $N$ matches the split functions will report $N+1$ matches, potentially including empty strings. Ranges have a few convenience methods as well:

range.size(); // -> std::size_t
range.empty(); // -> bool
range.template to<std::set<std::sting>>(); 
range.template to<std::vector<std::sting_view>>(); 

Concatenating Strings without Allocations

Another common string operation is concatenation. The STL provides std::string::operator+ and std::string::append, but those are not very efficient, if multiple invocations are performed.

std::string name, domain, tld;
auto email = name + "@" + domain + "." + tld; // 4 allocations

The efficient approach would be to pre-allocate the memory and copy the strings into it.

std::string email;
email.reserve(name.size() + domain.size() + tld.size() + 2);
email.append(name), email.append("@"), email.append(domain), email.append("."), email.append(tld);

That's mouthful and error-prone. StringZilla provides a more convenient concatenate function, which takes a variadic number of arguments. It also overrides the operator| to concatenate strings lazily, without any allocations.

auto email = sz::concatenate(name, "@", domain, ".", tld);   // 0 allocations
auto email = name | "@" | domain | "." | tld;                // 0 allocations
sz::string email = name | "@" | domain | "." | tld;          // 1 allocations

Random Generation

Software developers often need to generate random strings for testing purposes. The STL provides std::generate and std::random_device, that can be used with StringZilla.

sz::string random_string(std::size_t length, char const *alphabet, std::size_t cardinality) {
    sz::string result(length, '\0');
    static std::random_device seed_source; // Expensive to construct - due to system calls
    static std::mt19937 generator(seed_source()); // Also expensive - due to the state size
    std::uniform_int_distribution<std::size_t> distribution(0, cardinality);
    std::generate(result.begin(), result.end(), [&]() { return alphabet[distribution(generator)]; });
    return result;
}

Mouthful and slow. StringZilla provides a C native method - sz_fill_random and a convenient C++ wrapper - sz::generate. Similar to Python it also defines the commonly used character sets.

auto protein = sz::string::random(300, "ARNDCQEGHILKMFPSTWYV"); // static method
auto dna = sz::basic_string<custom_allocator>::random(3_000_000_000, "ACGT");

dna.fill_random("ACGT"); // `noexcept` pre-allocated version
dna.fill_random(&std::rand, "ACGT"); // pass any generator, like `std::mt19937`

char uuid[36];
sz::fill_random(sz::string_span(uuid, 36), "0123456789abcdef-"); // Overwrite any buffer

Bulk Replacements

In text processing, it's often necessary to replace all occurrences of a specific substring or set of characters within a string. Standard library functions may not offer the most efficient or convenient methods for performing bulk replacements, especially when dealing with large strings or performance-critical applications.

  • haystack.replace_all(needle_string, replacement_string)
  • haystack.replace_all(sz::byteset(""), replacement_string)
  • haystack.try_replace_all(needle_string, replacement_string)
  • haystack.try_replace_all(sz::byteset(""), replacement_string)
  • haystack.lookup(sz::look_up_table::identity())
  • haystack.lookup(sz::look_up_table::identity(), haystack.data())

Sorting in C and C++

LibC provides qsort and STL provides std::sort. Both have their quirks. The LibC standard has no way to pass a context to the comparison function, that's only possible with platform-specific extensions. Those have different arguments order on every OS.

// Linux: https://linux.die.net/man/3/qsort_r
void qsort_r(void *elements, size_t count, size_t element_width, 
    int (*compare)(void const *left, void const *right, void *context),
    void *context);
// macOS and FreeBSD: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/qsort_r.3.html
void qsort_r(void *elements, size_t count, size_t element_width, 
    void *context,
    int (*compare)(void *context, void const *left, void const *right));
// Windows conflicts with ISO `qsort_s`: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/qsort-s?view=msvc-170
void qsort_s(id *elements, size_t count, size_t element_width, 
    int (*compare)(void *context, void const *left, void const *right),
    void *context);

C++ generic algorithm is not perfect either. There is no guarantee in the standard that std::sort won't allocate any memory. If you are running on embedded, in real-time or on 100+ CPU cores per node, you may want to avoid that. StringZilla doesn't solve the general case, but hopes to improve the performance for strings. Use sz_sequence_argsort, or the high-level sz::argsort, which can be used sort any collection of elements convertible to sz::string_view.

std::vector<std::string> data({"c", "b", "a"});
std::vector<std::size_t> order = sz::argsort(data); //< Simple shortcut

// Or, taking care of memory allocation:
sz::argsort(data.begin(), data.end(), order.data(), [](auto const &x) -> sz::string_view { return x; });

Standard C++ Containers with String Keys

The C++ Standard Templates Library provides several associative containers, often used with string keys.

std::map<std::string, int, std::less<std::string>> sorted_words;
std::unordered_map<std::string, int, std::hash<std::string>, std::equal_to<std::string>> words;

The performance of those containers is often limited by the performance of the string keys, especially on reads. StringZilla can be used to accelerate containers with std::string keys, by overriding the default comparator and hash functions.

std::map<std::string, int, sz::less> sorted_words;
std::unordered_map<std::string, int, sz::hash, sz::equal_to> words;

Alternatively, a better approach would be to use the sz::string class as a key. The right hash function and comparator would be automatically selected and the performance gains would be more noticeable if the keys are short.

std::map<sz::string, int> sorted_words;
std::unordered_map<sz::string, int> words;

Compilation Settings and Debugging

SZ_DEBUG:

For maximal performance, the C library does not perform any bounds checking in Release builds. In C++, bounds checking happens only in places where the STL std::string would do it. If you want to enable more aggressive bounds-checking, define SZ_DEBUG before including the header. If not explicitly set, it will be inferred from the build type.

SZ_USE_GOLDMONT, SZ_USE_WESTMERE, SZ_USE_HASWELL, SZ_USE_SKYLAKE, SZ_USE_ICE, SZ_USE_NEON, SZ_USE_NEON_AES, SZ_USE_NEON_SHA, SZ_USE_SVE, SZ_USE_SVE2, SZ_USE_SVE2_AES:

One can explicitly disable certain families of SIMD instructions for compatibility purposes. Default values are inferred at compile time depending on compiler support (for dynamic dispatch) and the target architecture (for static dispatch).

SZ_USE_CUDA, SZ_USE_KEPLER, SZ_USE_HOPPER:

One can explicitly disable certain families of PTX instructions for compatibility purposes. Default values are inferred at compile time depending on compiler support (for dynamic dispatch) and the target architecture (for static dispatch).

SZ_ENFORCE_SVE_OVER_NEON:

SVE and SVE2 are expected to supersede NEON on ARM architectures. Still, oftentimes the equivalent SVE kernels are slower due to equally small register files and higher complexity of the instructions. By default, when both SVE and NEON are available, SVE is used selectively only for the algorithms that benefit from it. If you want to enforce SVE usage everywhere, define this flag.

SZ_DYNAMIC_DISPATCH:

By default, StringZilla is a header-only library. But if you are running on different generations of devices, it makes sense to pre-compile the library for all supported generations at once, and dispatch at runtime. This flag does just that and is used to produce the stringzilla.so shared library, as well as the Python bindings.

SZ_USE_MISALIGNED_LOADS:

Default is platform-dependent: enabled on x86 (where unaligned accesses are fast), disabled on others by default. When enabled, many byte-level operations use word-sized loads, which can significantly accelerate the serial (SWAR) backend. Consider enabling it explicitly if you are targeting platforms that support fast unaligned loads.

SZ_AVOID_LIBC and SZ_OVERRIDE_LIBC:

When using the C header-only library one can disable the use of LibC. This may affect the type resolution system on obscure hardware platforms. Moreover, one may let stringzilla override the common symbols like the memcpy and memset with its own implementations. In that case you can use the LD_PRELOAD trick to prioritize its symbols over the ones from the LibC and accelerate existing string-heavy applications without recompiling them. It also adds a layer of security, as the stringzilla isn't undefined for NULL inputs like memcpy(NULL, NULL, 0).

SZ_AVOID_STL and SZ_SAFETY_OVER_COMPATIBILITY:

When using the C++ interface one can disable implicit conversions from std::string to sz::string and back. If not needed, the <string> and <string_view> headers will be excluded, reducing compilation time. Moreover, if STL compatibility is a low priority, one can make the API safer by disabling the overloads, which are subjectively error prone.

STRINGZILLA_BUILD_SHARED, STRINGZILLA_BUILD_TEST, STRINGZILLA_BUILD_BENCHMARK, STRINGZILLA_TARGET_ARCH for CMake users:

When compiling the tests and benchmarks, you can explicitly set the target hardware architecture. It's synonymous to GCC's -march flag and is used to enable/disable the appropriate instruction sets. You can also disable the shared library build, if you don't need it.

Quick Start: Rust

StringZilla is available as a Rust crate, with documentation available on docs.rs/stringzilla. You can immediately check the installed version and the used hardware capabilities with following commands:

cargo add stringzilla
cargo run --example version

To use the latest crate release in your project, add the following to your Cargo.toml:

[dependencies]
stringzilla = ">=3"                                     # for serial algorithms
stringzilla = { version = ">=3", features = ["cpus"] }  # for parallel multi-CPU backends
stringzilla = { version = ">=3", features = ["cuda"] }  # for parallel Nvidia GPU backend

Or if you want to use the latest pre-release version from the repository:

[dependencies]
stringzilla = { git = "https://github.com/ashvardanian/stringzilla", branch = "main-dev" }

Once installed, all of the functionality is available through the stringzilla namespace. Many interfaces will look familiar to the users of the memchr Rust crate.

use stringzilla::sz;

// Identical to `memchr::memmem::find` and `memchr::memmem::rfind` functions
sz::find("Hello, world!", "world") // 7
sz::rfind("Hello, world!", "world") // 7

// Generalizations of `memchr::memrchr[123]`
sz::find_byte_from("Hello, world!", "world") // 2
sz::rfind_byte_from("Hello, world!", "world") // 11

It also provides no constraints on the size of the character set, while memchr allows only 1, 2, or 3 characters. In addition to global functions, stringzilla provides a StringZilla extension trait:

use stringzilla::StringZilla;

let my_string: String = String::from("Hello, world!");
let my_str = my_string.as_str();
let my_cow_str = Cow::from(&my_string);

// Use the generic function with a String
assert_eq!(my_string.sz_find("world"), Some(7));
assert_eq!(my_string.sz_rfind("world"), Some(7));
assert_eq!(my_string.sz_find_byte_from("world"), Some(2));
assert_eq!(my_string.sz_rfind_byte_from("world"), Some(11));
assert_eq!(my_string.sz_find_byte_not_from("world"), Some(0));
assert_eq!(my_string.sz_rfind_byte_not_from("world"), Some(12));

// Same works for &str and Cow<'_, str>
assert_eq!(my_str.sz_find("world"), Some(7));
assert_eq!(my_cow_str.as_ref().sz_find("world"), Some(7));

Hash

Single-shot and incremental hashing are both supported:

let mut hasher = sz::Hasher::new(42);
hasher.write(b"Hello, ");
hasher.write(b"world!");
let streamed = hasher.finish();

let mut hasher = sz::Hasher::new(42);
hasher.write(b"Hello, world!");
assert_eq!(streamed, hasher.finish());

To use StringZilla with std::collections:

use std::collections::HashMap;
let mut map: HashMap<&str, i32, sz::BuildSzHasher> =
    HashMap::with_hasher(sz::BuildSzHasher::with_seed(42));
map.insert("a", 1);
assert_eq!(map.get("a"), Some(&1));

SHA-256 Checksums

SHA-256 cryptographic checksums are available:

use stringzilla::sz;

// One-shot SHA-256
let digest = sz::Sha256::hash(b"Hello, world!");
assert_eq!(digest.len(), 32);

// Incremental SHA-256
let mut hasher = sz::Sha256::new();
hasher.update(b"Hello, ");
hasher.update(b"world!");
let digest = hasher.digest();

// HMAC-SHA256 for message authentication
let mac = sz::hmac_sha256(b"secret", b"Hello, world!");

Unicode Case-Folding and Case-Insensitive Search

StringZilla implements both Unicode Case Folding and Case-Insensitive UTF-8 Search. Unlike most libraries only capable of lower-casing ASCII-represented English alphabet, StringZilla covers over 1M+ codepoints. The case-folding API expects the output buffer to be at least 3× larger than the input, to accommodate for the worst-case character expansions scenarios.

use stringzilla::stringzilla as sz;

let source = "Straße";           // German: "Street"
let mut dest = [0u8; 64];        // Must be at least 3x source length
let len = sz::utf8_case_fold(source, &mut dest);
assert_eq!(&dest[..len], b"strasse");  // ß (2 bytes) → "ss" (2 bytes)

The case-insensitive search returns Some((offset, matched_length)) or None. The matched_length may differ from needle length due to expansions.

use stringzilla::stringzilla::{utf8_case_insensitive_find, Utf8CaseInsensitiveNeedle};

// Single search — ß (C3 9F) matches "SS"
if let Some((offset, len)) = utf8_case_insensitive_find("Straße", "STRASSE") {
    assert_eq!(offset, 0);
    assert_eq!(len, 7);  // "Straße" is 7 bytes
}

// Repeated searches with pre-compiled needle metadata
let needle = Utf8CaseInsensitiveNeedle::new(b"STRASSE");
for haystack in &["Straße", "STRASSE", "strasse"] {
    if let Some((offset, len)) = utf8_case_insensitive_find(haystack, &needle) {
        println!("Found at byte {} with length {}", offset, len);
    }
}

Similarity Scores

StringZilla exposes high-performance, batch-oriented similarity via the szs module. Use DeviceScope to pick hardware and optionally limit capabilities per engine.

use stringzilla::szs; // re-exported as `szs`

let cpu_scope = szs::DeviceScope::cpu_cores(4).unwrap();    // force CPU-only
let gpu_scope = szs::DeviceScope::gpu_device(0).unwrap();   // pick GPU 0 if available
let strings_a = vec!["kitten", "flaw"];
let strings_b = vec!["sitting", "lawn"];

let engine = szs::LevenshteinDistances::new(
    &cpu_scope,
    0,  // match cost
    2,  // mismatch cost - costs don't have to be 1
    3,  // open cost - may be different in Bio
    1,  // extend cost
).unwrap();
let distances = engine.compute(&cpu_scope, &strings_a, &strings_b).unwrap();
assert_eq!(distances[0], 3);
assert_eq!(distances[1], 2);

Note, that this computes byte-level distances. For UTF-8 codepoints, use a different engine class:

let strings_a = vec!["café", "αβγδ"];
let strings_b = vec!["cafe", "αγδ"];
let engine = szs::LevenshteinDistancesUtf8::new(&cpu_scope, 0, 1, 1, 1).unwrap();
let distances = engine.compute(&cpu_scope, &strings_a, &strings_b).unwrap();
assert_eq!(distances, vec![1, 1]);

Similarly, for variable substitution costs, also pass in a a weights matrix:

let mut substitution_matrix = [-1i8; 256 * 256];
for i in 0..256 { substitution_matrix[i * 256 + i] = 0; }
let engine = szs::NeedlemanWunschScores::new(&cpu_scope, &substitution_matrix, -3, -1).unwrap();
let scores = engine.compute(&cpu_scope, &strings_a, &strings_b).unwrap();

Or for local alignment scores:

let engine = szs::SmithWatermanScores::new(&cpu_scope, &substitution_matrix, -3, -1).unwrap();
let local_scores = engine.compute(&cpu_scope, &strings_a, &strings_b).unwrap();

For high-performance applications, use the StringTape crate to pass strings to compute_into methods without extra memory allocations:

use stringzilla::{szs, StringTape};

// Create StringTape from data (zero-copy compatible format)
let tape_a = StringTape::from_strings(&["kitten", "sitting", "flaw"]);
let tape_b = StringTape::from_strings(&["sitting", "kitten", "lawn"]);

// Use unified memory vector for GPU compatibility, initialized with max values
let mut distances = szs::UnifiedVec::<u32>::from_elem(u32::MAX, tape_a.len());

let engine = szs::LevenshteinDistances::new(&gpu_scope, 0, 1, 1, 1).unwrap();
engine.compute_into(&gpu_scope, &tape_a, &tape_b, &mut distances).unwrap();

// Results computed directly into unified memory, accessible from both CPU/GPU
assert_eq!(distances[0], 3);  // kitten -> sitting
assert_eq!(distances[1], 3);  // sitting -> kitten
assert_eq!(distances[2], 2);  // flaw -> lawn

Rolling Fingerprints

MinHashing is a common technique for Information Retrieval, producing compact representations of large documents. For $D$ hash-functions and a text of length $L$, in the worst case it involves computing $O(D \cdot L)$ hashes.

use stringzilla::szs;

let texts = vec![
    "quick brown fox jumps over the lazy dog",
    "quick brown fox jumped over a very lazy dog",
];
let cpu = szs::DeviceScope::cpu_cores(4).unwrap();
let ndim = 1024;
let window_widths = vec![4u64, 6, 8, 10];

let engine = szs::Fingerprints::new(
    ndim,           // number of hash functions & dimensions
    &window_widths, // optional predefined window widths
    256,            // default alphabet size for byte strings
    &cpu            // device scope
).unwrap();

let (hashes, counts) = engine.compute(&cpu, &texts).unwrap();
assert_eq!(hashes.len(), texts.len() * ndim);
assert_eq!(counts.len(), texts.len() * ndim);

For zero-copy processing with StringTape format and unified memory:

use stringzilla::{szs, StringTape};

let tape = StringTape::from_strings(&[
    "quick brown fox jumps over the lazy dog",
    "quick brown fox jumped over a very lazy dog",
]);

// Pre-allocate unified memory buffers
let mut hashes = szs::UnifiedVec::<u32>::from_elem(u32::MAX, tape.len() * ndim);
let mut counts = szs::UnifiedVec::<u32>::from_elem(u32::MAX, tape.len() * ndim);

let engine = szs::Fingerprints::new(ndim, &window_widths, 256, &cpu).unwrap();
engine.compute_into(&cpu, &tape, &mut hashes, &mut counts).unwrap();

// Results computed directly into unified memory buffers
assert!(hashes.iter().any(|&h| h != u32::MAX));  // Verify computation occurred
assert!(counts.iter().any(|&c| c != u32::MAX));

Quick Start: JavaScript

Install the Node.js package and use zero-copy Buffer APIs.

npm install stringzilla
node -p "require('stringzilla').default.capabilities" # for CommonJS
node -e "import('stringzilla').then(m=>console.log(m.default.capabilities)).catch(console.error)" # for ESM
import sz from 'stringzilla';

const haystack = Buffer.from('Hello, world!');
const needle = Buffer.from('world');

// Substring search (BigInt offsets)
const firstIndex = sz.find(haystack, needle);      // 7n
const lastIndex = sz.findLast(haystack, needle);   // 7n

// Character / charset search
const firstOIndex = sz.findByte(haystack, 'o'.charCodeAt(0));                 // 4n
const firstVowelIndex = sz.findByteFrom(haystack, Buffer.from('aeiou'));      // 1n
const lastVowelIndex = sz.findLastByteFrom(haystack, Buffer.from('aeiou'));   // 8n

// Counting (optionally overlapping)
const lCount = sz.count(haystack, Buffer.from('l'));                // 3n
const llOverlapCount = sz.count(haystack, Buffer.from('ll'), true); // 1n

// Equality/ordering utilities
const isEqual = sz.equal(Buffer.from('a'), Buffer.from('a'));
const order = sz.compare(Buffer.from('a'), Buffer.from('b')); // -1, 0, or 1

// Other helpers
const byteSum = sz.byteSum(haystack); // sum of bytes as BigInt

Unicode Case-Folding and Case-Insensitive Search

StringZilla provides full Unicode case folding (including expansions like ß → ss, ligatures like fi → fi, and special folds like µ → μ, K → k) and a case-insensitive substring search that accounts for those expansions.

import sz from "stringzilla";

// Case folding (returns a UTF-8 Buffer)
console.log(sz.utf8CaseFold(Buffer.from("Straße")).toString("utf8")); // "strasse"
console.log(sz.utf8CaseFold(Buffer.from("office")).toString("utf8"));  // "office" (U+FB01 ligature)

// Case-insensitive substring search (full Unicode case folding)
const text = Buffer.from(
    "Die Temperaturschwankungen im kosmischen Mikrowellenhintergrund sind ein Maß von etwa 20 µK.\n" +
    "Typografisch sieht man auch: ein Maß von etwa 20 μK."
);
const patternBytes = Buffer.from("EIN MASS VON ETWA 20 μK");

const first = sz.utf8CaseInsensitiveFind(text, patternBytes);
console.log(first); // { index: 69n, length: ... } (byte offsets)

// Reuse the same needle efficiently
const pattern = new sz.Utf8CaseInsensitiveNeedle(patternBytes);
const again = pattern.findIn(text);
console.log(again.index === first.index);

Hash

Single-shot and incremental hashing are both supported:

import sz from 'stringzilla';

// One-shot - stable 64-bit output across all platforms!
const hash = sz.hash(Buffer.from('Hello, world!'), 42); // returns BigInt

// Incremental updates - hasher maintains state
const hasher = new sz.Hasher(42); // seed: 42
hasher.update(Buffer.from('Hello, '));
hasher.update(Buffer.from('world!'));
const streamedHash = hasher.digest(); // returns BigInt
console.assert(hash === streamedHash);

SHA-256 Checksums

SHA-256 cryptographic checksums are available:

import sz from 'stringzilla';

// One-shot SHA-256
const digest = sz.sha256(Buffer.from('Hello, world!')); // returns Buffer (32 bytes)

// Incremental SHA-256
const hasher = new sz.Sha256();
hasher.update(Buffer.from('Hello, '));
hasher.update(Buffer.from('world!'));
const digestBuffer = hasher.digest();     // returns Buffer (32 bytes)
const digestHex = hasher.hexdigest();     // returns string (64 hex chars)

Quick Start: Swift

StringZilla can be added as a dependency in the Swift Package Manager. In your Package.swift file, add the following:

dependencies: [
    .package(url: "https://github.com/ashvardanian/stringzilla")
]

The package currently covers only the most basic functionality, but is planned to be extended to cover the full C++ API.

var s = "Hello, world! Welcome to StringZilla. 👋"
s[s.findFirst(substring: "world")!...] // "world! Welcome to StringZilla. 👋"
s[s.findLast(substring: "o")!...] // "o StringZilla. 👋"
s[s.findFirst(characterFrom: "aeiou")!...] // "ello, world! Welcome to StringZilla. 👋"
s[s.findLast(characterFrom: "aeiou")!...] // "a. 👋")
s[s.findFirst(characterNotFrom: "aeiou")!...] // "Hello, world! Welcome to StringZilla. 👋"

Unicode Case-Folding and Case-Insensitive Search

import StringZilla

let folded = "Straße".utf8CaseFoldedBytes()
print(String(decoding: folded, as: UTF8.self)) // "strasse"

let haystack =
    "Die Temperaturschwankungen im kosmischen Mikrowellenhintergrund sind ein Maß von etwa 20 µK.\n"
    + "Typografisch sieht man auch: ein Maß von etwa 20 μK."
let needle = "EIN MASS VON ETWA 20 μK"

if let range = haystack.utf8CaseInsensitiveFind(substring: needle) {
    print(haystack[range]) // "ein Maß von etwa 20 µK"
}

// Reuse the same needle efficiently
let compiledNeedle = Utf8CaseInsensitiveNeedle(needle)
if let range = compiledNeedle.findFirst(in: haystack) {
    print(haystack[range])
}

Hash

StringZilla provides high-performance hashing for Swift strings:

import StringZilla

// One-shot hashing - stable 64-bit output across all platforms!
let hash = "Hello, world!".hash(seed: 42)

// Incremental hashing for streaming data
var hasher = StringZillaHasher(seed: 42)
hasher.update("Hello, ")
hasher.update("world!")
let streamedHash = hasher.digest()
assert(hash == streamedHash)

SHA-256 Checksums

SHA-256 cryptographic checksums are available:

import StringZilla

// One-shot SHA-256
let digest = "Hello, world!".sha256() // returns [UInt8] (32 bytes)

// Incremental SHA-256
var hasher = StringZillaSha256()
hasher.update("Hello, ")
hasher.update("world!")
let digestBytes = hasher.digest()     // [UInt8] (32 bytes)
let digestHex = hasher.hexdigest()    // String (64 hex chars)

Quick Start: GoLang

Add the Go binding as a module dependency:

go get github.com/ashvardanian/stringzilla/golang@latest

Build the shared C library once, then ensure your runtime can locate it (Linux shown):

cmake -B build_shared -D STRINGZILLA_BUILD_SHARED=1 -D CMAKE_BUILD_TYPE=Release
cmake --build build_shared --target stringzilla_shared --config Release
export LD_LIBRARY_PATH="$PWD/build_shared:$LD_LIBRARY_PATH"

Use finders (substring, bytes, and sets):

package main

import (
    "fmt"
    sz "github.com/ashvardanian/stringzilla/golang"
)

func main() {
    s := "the quick brown fox jumps over the lazy dog"

    // Substrings
    fmt.Println(sz.Contains(s, "brown"))        // true
    fmt.Println(sz.Index(s, "the"))             // 0
    fmt.Println(sz.LastIndex(s, "the"))         // 35

    // Single bytes
    fmt.Println(sz.IndexByte(s, 'o'))            // 12
    fmt.Println(sz.LastIndexByte(s, 'o'))        // 41

    // Byte sets
    fmt.Println(sz.IndexAny(s, "aeiou"))        // 2  (first vowel)
    fmt.Println(sz.LastIndexAny(s, "aeiou"))    // 43 (last vowel)

    // Counting with/without overlaps
    fmt.Println(sz.Count("aaaaa", "aa", false)) // 2
    fmt.Println(sz.Count("aaaaa", "aa", true))  // 4
    fmt.Println(sz.Count("abc", "", false))     // 4
    fmt.Println(sz.Bytesum("ABC"), sz.Bytesum("ABCD"))
}

Unicode Case-Folding and Case-Insensitive Search

package main

import (
    "fmt"
    sz "github.com/ashvardanian/stringzilla/golang"
)

func main() {
    folded, _ := sz.Utf8CaseFold("Straße", true)
    fmt.Println(folded) // "strasse"

    haystack := "Die Temperaturschwankungen im kosmischen Mikrowellenhintergrund sind ein Maß von etwa 20 µK.\n" +
        "Typografisch sieht man auch: ein Maß von etwa 20 μK."
    needle := "EIN MASS VON ETWA 20 μK"

    start64, len64, _ := sz.Utf8CaseInsensitiveFind(haystack, needle, true)
    start, end := int(start64), int(start64+len64)
    fmt.Println(haystack[start:end]) // "ein Maß von etwa 20 µK"

    // Reuse the same needle efficiently
    compiled, _ := sz.NewUtf8CaseInsensitiveNeedle(needle, true)
    start64, len64, _ = compiled.FindIn(haystack, true)
    start, end = int(start64), int(start64+len64)
    fmt.Println(haystack[start:end])
}

Hash

Single-shot and incremental hashing are both supported. The Hasher type implements Go's standard hash.Hash64 and io.Writer interfaces:

import (
    "io"
    sz "github.com/ashvardanian/stringzilla/golang"
)

// One-shot hashing
one := sz.Hash("Hello, world!", 42)

// Streaming hasher (implements hash.Hash64 and io.Writer)
hasher := sz.NewHasher(42)
hasher.Write([]byte("Hello, "))
hasher.Write([]byte("world!"))
streamed := hasher.Digest()         // or hasher.Sum64()
fmt.Println(one == streamed)        // true

// Works with io.Copy and any io.Reader
file, _ := os.Open("data.txt")
hasher.Reset()
io.Copy(hasher, file)
fileHash := hasher.Sum64()

SHA-256 Checksums

SHA-256 cryptographic checksums are available. The Sha256 type implements Go's standard hash.Hash and io.Writer interfaces:

import (
    "io"
    sz "github.com/ashvardanian/stringzilla/golang"
)

// One-shot SHA-256
digest := sz.HashSha256([]byte("Hello, world!"))
fmt.Printf("%x\n", digest)          // prints 32-byte hash in hex

// Streaming SHA-256 (implements hash.Hash and io.Writer)
hasher := sz.NewSha256()
hasher.Write([]byte("Hello, "))
hasher.Write([]byte("world!"))
digestBytes := hasher.Digest()      // [32]byte
digestHex := hasher.Hexdigest()     // string (64 hex chars)

// Works with io.Copy and any io.Reader
file, _ := os.Open("data.bin")
hasher.Reset()
io.Copy(hasher, file)
fileDigest := hasher.Digest()

// Standard hash.Hash interface methods
sum := hasher.Sum(nil)              // []byte with 32 bytes
size := hasher.Size()               // 32
blockSize := hasher.BlockSize()     // 64

Algorithms & Design Decisions

StringZilla aims to optimize some of the slowest string operations. Some popular operations, however, like equality comparisons and relative order checking, almost always complete on some of the very first bytes in either string. In such operations vectorization is almost useless, unless huge and very similar strings are considered. StringZilla implements those operations as well, but won't result in substantial speedups. Where vectorization stops being effective, parallelism takes over with the new layered cake architecture:

  • StringZilla C library w/out dependencies
  • StringZillas parallel extensions:
    • Parallel C++ algorithms built with Fork Union
    • Parallel CUDA algorithms for Nvidia GPUs
    • Parallel ROCm algorithms for AMD GPUs 🔜

Exact Substring Search

Substring search algorithms are generally divided into: comparison-based, automaton-based, and bit-parallel. Different families are effective for different alphabet sizes and needle lengths. The more operations are needed per-character - the more effective SIMD would be. The longer the needle - the more effective the skip-tables are. StringZilla uses different exact substring search algorithms for different needle lengths and backends:

  • When no SIMD is available - SWAR (SIMD Within A Register) algorithms are used on 64-bit words.
  • Boyer-Moore-Horspool (BMH) algorithm with Raita heuristic variation for longer needles.
  • SIMD backends compare characters at multiple strategically chosen offsets within the needle to reduce degeneracy.

On very short needles, especially 1-4 characters long, brute force with SIMD is the fastest solution. On mid-length needles, bit-parallel algorithms are effective, as the character masks fit into 32-bit or 64-bit words. Either way, if the needle is under 64-bytes long, on haystack traversal we will still fetch every CPU cache line. So the only way to improve performance is to reduce the number of comparisons.

For 2-byte needles, see sz_find_2byte_serial_ in include/stringzilla/find.h:

https://github.com/ashvardanian/StringZilla/blob/e1966de91600298d3c5cf4fe7be40d434f0f405e/include/stringzilla/find.h#L422-L463

Going beyond that, to long needles, Boyer-Moore (BM) and its variants are often the best choice. It has two tables: the good-suffix shift and the bad-character shift. Common choice is to use the simplified BMH algorithm, which only uses the bad-character shift table, reducing the pre-processing time. We do the same for mid-length needles up to 256 bytes long. That way the stack-allocated shift table remains small.

For mid-length needles (≤256 bytes), see sz_find_horspool_upto_256bytes_serial_ in include/stringzilla/find.h:

https://github.com/ashvardanian/StringZilla/blob/e1966de91600298d3c5cf4fe7be40d434f0f405e/include/stringzilla/find.h#L620-L667

In the C++ Standards Library, the std::string::find function uses the BMH algorithm with Raita's heuristic. Before comparing the entire string, it matches the first, last, and the middle character. Very practical, but can be slow for repetitive characters. Both SWAR and SIMD backends of StringZilla have a cheap pre-processing step, where we locate unique characters. This makes the library a lot more practical when dealing with non-English corpora.

The offset selection heuristic is implemented in sz_locate_needle_anomalies_ in include/stringzilla/find.h:

https://github.com/ashvardanian/StringZilla/blob/e1966de91600298d3c5cf4fe7be40d434f0f405e/include/stringzilla/find.h#L244-L305

All those, still, have $O(hn)$ worst case complexity. To guarantee $O(h)$ worst case time complexity, the Apostolico-Giancarlo (AG) algorithm adds an additional skip-table. Preprocessing phase is $O(n+sigma)$ in time and space. On traversal, performs from $(h/n)$ to $(3h/2)$ comparisons. It however, isn't practical on modern CPUs. A simpler idea, the Galil-rule might be a more relevant optimizations, if many matches must be found.

Other algorithms previously considered and deprecated:

  • Apostolico-Giancarlo algorithm for longer needles. Control-flow is too complex for efficient vectorization.
  • Shift-Or-based Bitap algorithm for short needles. Slower than SWAR.
  • Horspool-style bad-character check in SIMD backends. Effective only for very long needles, and very uneven character distributions between the needle and the haystack. Faster "character-in-set" check needed to generalize.

§ Reading materials. Exact String Matching Algorithms in Java. SIMD-friendly algorithms for substring searching.

Exact Multiple Substring Search

Few algorithms for multiple substring search are known. Most are based on the Aho-Corasick automaton, which is a generalization of the KMP algorithm. The naive implementation, however:

  • Allocates disjoint memory for each Trie node and Automaton state.
  • Requires a lot of pointer chasing, limiting speculative execution.
  • Has a lot of branches and conditional moves, which are hard to predict.
  • Matches text a character at a time, which is slow on modern CPUs.

There are several ways to improve the original algorithm. One is to use sparse DFA representation, which is more cache-friendly, but would require extra processing to navigate state transitions.

Levenshtein Edit Distance

Levenshtein distance is the best known edit-distance for strings, that checks, how many insertions, deletions, and substitutions are needed to transform one string to another. It's extensively used in approximate string-matching, spell-checking, and bioinformatics.

The computational cost of the Levenshtein distance is $O(n * m)$, where $n$ and $m$ are the lengths of the string arguments. To compute that, the naive approach requires $O(n * m)$ space to store the "Levenshtein matrix", the bottom-right corner of which will contain the Levenshtein distance. The algorithm producing the matrix has been simultaneously studied/discovered by the Soviet mathematicians Vladimir Levenshtein in 1965, Taras Vintsyuk in 1968, and American computer scientists - Robert Wagner, David Sankoff, Michael J. Fischer in the following years. Several optimizations are known:

  1. Space Optimization: The matrix can be computed in $O(min(n,m))$ space, by only storing the last two rows of the matrix.
  2. Divide and Conquer: Hirschberg's algorithm can be applied to decompose the computation into subtasks.
  3. Automata: Levenshtein automata can be effective, if one of the strings doesn't change, and is a subject to many comparisons.
  4. Shift-Or: Bit-parallel algorithms transpose the matrix into a bit-matrix, and perform bitwise operations on it.

The last approach is quite powerful and performant, and is used by the great RapidFuzz library. It's less known, than the others, derived from the Baeza-Yates-Gonnet algorithm, extended to bounded edit-distance search by Manber and Wu in 1990s, and further extended by Gene Myers in 1999 and Heikki Hyyro between 2002 and 2004.

StringZilla focuses on a different approach, extensively used in Unum's internal combinatorial optimization libraries. It doesn't change the number of trivial operations, but performs them in a different order, removing the data dependency, that occurs when computing the insertion costs. StringZilla evaluates diagonals instead of rows, exploiting the fact that all cells within a diagonal are independent, and can be computed in parallel. We'll store 3 diagonals instead of the 2 rows, and each consecutive diagonal will be computed from the previous two. Substitution costs will come from the sooner diagonal, while insertion and deletion costs will come from the later diagonal.

Row-by-Row Algorithm
Computing row 4:
    ∅  A  B  C  D  E
 ∅  0  1  2  3  4  5
 P  1  ░  ░  ░  ░  ░
 Q  2  ■  ■  ■  ■  ■
 R  3  ■  ■  □  →  .
 S  4  .  .  .  .  .
 T  5  .  .  .  .  .
Anti-Diagonal Algorithm
Computing diagonal 5:
    ∅  A  B  C  D  E
 ∅  0  1  2  3  4  5
 P  1  ░  ░  ■  ■  □
 Q  2  ░  ■  ■  □  ↘
 R  3  ■  ■  □  ↘  .
 S  4  ■  □  ↘  .  .
 T  5  □  ↘  .  .  .
Legend:
0,1,2,3... = initialization constants    = cells processed and forgotten    = stored cells    = computing in parallel    → ↘ = movement direction    . = cells to compute later

This results in much better vectorization for intra-core parallelism and potentially multi-core evaluation of a single request. Moreover, it's easy to generalize to weighted edit-distances, where the cost of a substitution between two characters may not be the same for all pairs, often used in bioinformatics.

§ Reading materials. Faster Levenshtein Distances with a SIMD-friendly Traversal Order.

Needleman-Wunsch and Smith-Waterman Scores for Bioinformatics

The field of bioinformatics studies various representations of biological structures. The "primary" representations are generally strings over sparse alphabets:

  • DNA sequences, where the alphabet is {A, C, G, T}, ranging from ~100 characters for short reads to 3 billion for the human genome.
  • RNA sequences, where the alphabet is {A, C, G, U}, ranging from ~50 characters for tRNA to thousands for mRNA.
  • Proteins, where the alphabet is made of 22 amino acids, ranging from 2 characters for dipeptide to 35,000 for Titin, the longest protein.

The shorter the representation, the more often researchers may want to use custom substitution matrices. Meaning that the cost of a substitution between two characters may not be the same for all pairs. In the general case the serial algorithm is supposed to work for arbitrary substitution costs for each of 256×256 possible character pairs. That lookup table, however, is too large to fit into CPU registers, so instead, the upcoming design focuses on 32×32 substitution matrices, which fit into 1 KB with single-byte "error costs". That said, most BLOSUM and PAM substitution matrices only contain 4-bit values, so they can be packed even further.

Next design goals:

  • Needleman-Wunsch Automata

Memory Copying, Fills, and Moves

A lot has been written about the time computers spend copying memory and how that operation is implemented in LibC. Interestingly, the operation can still be improved, as most Assembly implementations use outdated instructions. Even performance-oriented STL replacements, like Meta's Folly v2024.09.23 focus on AVX2, and don't take advantage of the new masked instructions in AVX-512 or SVE.

In AVX-512, StringZilla uses non-temporal stores to avoid cache pollution, when dealing with very large strings. Moreover, it handles the unaligned head and the tails of the target buffer separately, ensuring that writes in big copies are always aligned to cache-line boundaries. That's true for both AVX2 and AVX-512 backends.

StringZilla also contains "drafts" of smarter, but less efficient algorithms, that minimize the number of unaligned loads, performing shuffles and permutations. That's a topic for future research, as the performance gains are not yet satisfactory.

§ Reading materials. memset benchmarks by Nadav Rotem. Cache Associativity by Sergey Slotin.

Hashing

StringZilla implements a high-performance 64-bit hash function inspired by the "AquaHash", "aHash", and "GxHash" design and optimized for modern CPU architectures. The algorithm utilizes AES encryption rounds combined with shuffle-and-add operations to achieve exceptional mixing properties while maintaining consistent output across platforms. It passes the rigorous SMHasher test suite, including the --extra flag with no collisions.

The core algorithm operates on a dual-state design:

  • AES State: Initialized with seed XOR-ed against π constants.
  • Sum State: Accumulates shuffled input data with a permutation.

For strings ≤64 bytes, a minimal state processes data in 16-byte blocks. Longer strings employ a 4× wider state (512 bits) that processes 64-byte chunks, maximizing throughput on modern superscalar CPUs. The algorithm can be expressed in pseudocode as:

function sz_hash(text: u8[], length: usize, seed: u64) -> u64:
    # 1024 bits worth of π constants
    pi: u64[16] = [
        0x243F6A8885A308D3, 0x13198A2E03707344, 0xA4093822299F31D0, 0x082EFA98EC4E6C89,
        0x452821E638D01377, 0xBE5466CF34E90C6C, 0xC0AC29B7C97C50DD, 0x3F84D5B5B5470917,
        0x9216D5D98979FB1B, 0xD1310BA698DFB5AC, 0x2FFD72DBD01ADFB7, 0xB8E1AFED6A267E96,
        0xBA7C9045F12C7F99, 0x24A19947B3916CF7, 0x0801F2E2858EFC16, 0x636920D871574E69]

    # Permutation order for the sum state
    shuffle_pattern: u8[16] = [
        0x04, 0x0b, 0x09, 0x06, 0x08, 0x0d, 0x0f, 0x05,
        0x0e, 0x03, 0x01, 0x0c, 0x00, 0x07, 0x0a, 0x02]

    # Initialize key and states
    keys_u64s: u64[2] = [seed, seed]
    aes_u64s: u64[2] = [seed ⊕ pi[0], seed ⊕ pi[1]]
    sum_u64s: u64[2] = [seed ⊕ pi[8], seed ⊕ pi[9]]

    if length ≤ 64:
        # Small input: process 1-4 zero-padded blocks of 16 bytes each
        blocks_u8s: u8[16][] = split_into_blocks(text, length, 16)
        for each block_u8s: u8[16] in blocks_u8s:
            aes_u64s = AESENC(aes_u64s, block_u8s)
            sum_u64s = SHUFFLE(sum_u64s, shuffle_pattern) + block_u8s
    else:
        # Large input: use 4× wider 512-bits states
        aes_u64s: u64[8] = [
            seed ⊕ pi[0], seed ⊕ pi[1], seed ⊕ pi[2], seed ⊕ pi[3],
            seed ⊕ pi[4], seed ⊕ pi[5], seed ⊕ pi[6], seed ⊕ pi[7]]
        sum_u64s: u64[8] = [
            seed ⊕ pi[8], seed ⊕ pi[9], seed ⊕ pi[10], seed ⊕ pi[11],
            seed ⊕ pi[12], seed ⊕ pi[13], seed ⊕ pi[14], seed ⊕ pi[15]]

        # Process 64-byte chunks (4×16-byte blocks)
        for each chunk_u8s: u8[64] in text:
            blocks_u8s: u8[16][4] = split_chunk_into_4_blocks(chunk_u8s)
            for i in 0..3:
                offset: usize = i * 2  # Each lane stores two u64s
                aes_u64s[offset:offset+1] = AESENC(aes_u64s[offset:offset+1], blocks_u8s[i])
                sum_u64s[offset:offset+1] = SHUFFLE(sum_u64s[offset:offset+1], shuffle_pattern) + blocks_u8s[i]

        # Fold 8×u64 state back to 2×u64 for finalization
        aes_u64s: u64[2] = fold_to_2u64(aes_u64s)
        sum_u64s: u64[2] = fold_to_2u64(sum_u64s)

    # Finalization: mix length into key
    key_with_length: u64[2] = [keys_u64s[0] + length, keys_u64s[1]]

    # Multiple AES rounds for SMHasher compliance
    mixed_u64s: u64[2] = AESENC(sum_u64s, aes_u64s)
    result_u64s: u64[2] = AESENC(AESENC(mixed_u64s, key_with_length), mixed_u64s)

    return result_u64s[0]  # Extract low 64 bits

This allows us to balance several design trade-offs. First, it allows us to achieve a high port-level parallelism. Looking at AVX-512 capable CPUs and their ZMM instructions, on each cycle, we'll have at least 2 ports busy when dealing with long strings:

  • VAESENC: 5 cycles on port 0 on Intel Ice Lake, 4 cycles on ports 0/1 on AMD Zen4.
  • VPSHUFB_Z: 3 cycles on port 5 on Intel Ice Lake, 2 cycles on ports 1/2 on AMD Zen4.
  • VPADDQ: 1 cycle on ports 0/5 on Intel Ice Lake, 1 cycle on ports 0/1/2/3 on AMD Zen4.

When dealing with smaller strings, we design our approach to avoid large registers and maintain the CPU at the same energy state, thereby avoiding downclocking and expensive power-state transitions.

Unlike some AES-accelerated alternatives, the length of the input is not mixed into the AES block at the start to allow incremental construction, when the final length is not known in advance. Also, unlike some alternatives, with "masked" AVX-512 and "predicated" SVE loads, we avoid expensive block-shuffling procedures on non-divisible-by-16 lengths.

§ Reading materials. Stress-testing hash functions for avalance behaviour, collision bias, and distribution.

SHA-256 Checksums

In addition to the fast AES-based hash, StringZilla implements hardware-accelerated SHA-256 cryptographic checksums. The implementation follows the FIPS 180-4 specification and provides multiple backends.

Random Generation

StringZilla implements a fast Pseudorandom Number Generator inspired by the "AES-CTR-128" algorithm, reusing the same AES primitives as the hash function. Unlike "NIST SP 800-90A" which uses multiple AES rounds, StringZilla uses only one round of AES mixing for performance while maintaining reproducible output across platforms. The generator operates in counter mode with AESENC(nonce + lane_index, nonce ⊕ pi_constants), rotating through the first 512 bits of π for each 16-byte block. The only state required to reproduce an output is a 64-bit nonce, which is much cheaper than a Mersenne Twister.

Sorting

For lexicographic sorting of string collections, StringZilla exports pointer-sized n‑grams ("pgrams") into a contiguous buffer to improve locality, then recursively QuickSorts those pgrams with a 3‑way partition and dives into equal pgrams to compare deeper characters. Very small inputs fall back to insertion sort.

  • Average time complexity: O(n log n)
  • Worst-case time complexity: quadratic (due to QuickSort), mitigated in practice by 3‑way partitioning and the n‑gram staging

Unicode 17, UTF-8, and Wide Characters

Most StringZilla operations are byte-level, so they work well with ASCII and UTF-8 content out of the box. In some cases, like edit-distance computation, the result of byte-level evaluation and character-level evaluation may differ.

  • szs_levenshtein_distances_utf8("αβγδ", "αγδ") == 1 — one unicode symbol.
  • szs_levenshtein_distances("αβγδ", "αγδ") == 2 — one unicode symbol is two bytes long.

Java, JavaScript, Python 2, C#, and Objective-C, however, use wide characters (wchar) - two byte long codes, instead of the more reasonable fixed-length UTF-32 or variable-length UTF-8. This leads to all kinds of offset-counting issues when facing four-byte long Unicode characters. StringZilla uses proper 32-bit "runes" to represent unpacked Unicode codepoints, ensuring correct results in all operations. Moreover, it implements the Unicode 17.0 standard, being practically the only library besides ICU and PCRE2 to do so, but with order(s) of magnitude better performance.

Case-Folding and Case-Insensitive Search

StringZilla provides Unicode-aware case-insensitive substring search that handles the full complexity of Unicode case folding. This includes multi-character expansions:

Character Codepoint UTF-8 Bytes Case-Folds To Result Bytes
ß U+00DF C3 9F ss 73 73
U+FB03 EF AC 83 ffi 66 66 69
İ U+0130 C4 B0 i + ◌̇ 69 CC 87

The search returns byte offsets and lengths in the original haystack, correctly handling length differences. For example, searching for "STRASSE" (7 bytes) in "Straße" (7 bytes: 53 74 72 61 C3 9F 65) succeeds because both case-fold to "strasse".

Note that Turkish İ and ASCII I are distinct: İstanbul case-folds to i̇stanbul (with combining dot), while ISTANBUL case-folds to istanbul (without). They will not match each other — this is correct Unicode behavior for Turkish locale handling.

For wide-character environments (Java, JavaScript, Python 2, C#), consider transcoding with simdutf.

Dynamic Dispatch

Due to the high-level of fragmentation of SIMD support in different CPUs, StringZilla uses the names of select Intel and ARM CPU generations for its backends. You can query supported backends and use them manually. Use it to guarantee constant performance, or to explore how different algorithms scale on your hardware.

sz_find(text, length, pattern, 3);          // Auto-dispatch
sz_find_westmere(text, length, pattern, 3);  // Intel Westmere+ SSE4.2
sz_find_haswell(text, length, pattern, 3);  // Intel Haswell+ AVX2
sz_find_skylake(text, length, pattern, 3);  // Intel Skylake+ AVX-512
sz_find_neon(text, length, pattern, 3);     // Arm NEON 128-bit
sz_find_sve(text, length, pattern, 3);      // Arm SVE 128/256/512/1024/2048-bit

StringZilla automatically picks the most advanced backend for the given CPU. Similarly, in Python, you can log the auto-detected capabilities:

python -c "import stringzilla; print(stringzilla.__capabilities__)"         # ('serial', 'westmere', 'haswell', 'skylake', 'ice', 'neon', 'sve', 'sve2+aes')
python -c "import stringzilla; print(stringzilla.__capabilities_str__)"     # "haswell, skylake, ice, neon, sve, sve2+aes"

You can also explicitly set the backend to use, or scope the backend to a specific function.

import stringzilla as sz
sz.reset_capabilities(('serial',))          # Force SWAR backend
sz.reset_capabilities(('haswell',))         # Force AVX2 backend
sz.reset_capabilities(('neon',))            # Force NEON backend
sz.reset_capabilities(sz.__capabilities__)  # Reset to auto-dispatch

Contributing 👾

Please check out the contributing guide for more details on how to set up the development environment and contribute to this project. If you like this project, you may also enjoy USearch, UCall, UForm, and SimSIMD. 🤗

If you like strings and value efficiency, you may also enjoy the following projects:

  • simdutf - transcoding UTF-8, UTF-16, and UTF-32 LE and BE.
  • hyperscan - regular expressions with SIMD acceleration.
  • pyahocorasick - Aho-Corasick algorithm in Python.
  • rapidfuzz - fast string matching in C++ and Python.
  • memchr - fast string search in Rust.

If you are looking for more reading materials on this topic, consider the following:

License 📜

Feel free to use the project under Apache 2.0 or the Three-clause BSD license at your preference.

Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

stringzilla-4.6.3.tar.gz (646.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

stringzilla-4.6.3-cp314-cp314-win_arm64.whl (127.9 kB view details)

Uploaded CPython 3.14Windows ARM64

stringzilla-4.6.3-cp314-cp314-win_amd64.whl (167.4 kB view details)

Uploaded CPython 3.14Windows x86-64

stringzilla-4.6.3-cp314-cp314-win32.whl (118.0 kB view details)

Uploaded CPython 3.14Windows x86

stringzilla-4.6.3-cp314-cp314-musllinux_1_2_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ x86-64

stringzilla-4.6.3-cp314-cp314-musllinux_1_2_s390x.whl (632.1 kB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ s390x

stringzilla-4.6.3-cp314-cp314-musllinux_1_2_riscv64.whl (602.3 kB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ riscv64

stringzilla-4.6.3-cp314-cp314-musllinux_1_2_ppc64le.whl (612.7 kB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ ppc64le

stringzilla-4.6.3-cp314-cp314-musllinux_1_2_i686.whl (616.6 kB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ i686

stringzilla-4.6.3-cp314-cp314-musllinux_1_2_armv7l.whl (595.0 kB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.3-cp314-cp314-musllinux_1_2_aarch64.whl (661.7 kB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ ARM64

stringzilla-4.6.3-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl (611.3 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.34+ riscv64manylinux: glibc 2.39+ riscv64

stringzilla-4.6.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

stringzilla-4.6.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl (600.4 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ s390xmanylinux: glibc 2.28+ s390x

stringzilla-4.6.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl (594.1 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ ppc64lemanylinux: glibc 2.28+ ppc64le

stringzilla-4.6.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl (650.3 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ ARMv7lmanylinux: glibc 2.31+ ARMv7l

stringzilla-4.6.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl (647.6 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ ARM64manylinux: glibc 2.28+ ARM64

stringzilla-4.6.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl (581.9 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.28+ i686manylinux: glibc 2.5+ i686

stringzilla-4.6.3-cp314-cp314-macosx_11_0_arm64.whl (197.9 kB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

stringzilla-4.6.3-cp314-cp314-macosx_10_15_x86_64.whl (210.6 kB view details)

Uploaded CPython 3.14macOS 10.15+ x86-64

stringzilla-4.6.3-cp313-cp313-win_arm64.whl (123.2 kB view details)

Uploaded CPython 3.13Windows ARM64

stringzilla-4.6.3-cp313-cp313-win_amd64.whl (162.4 kB view details)

Uploaded CPython 3.13Windows x86-64

stringzilla-4.6.3-cp313-cp313-win32.whl (114.7 kB view details)

Uploaded CPython 3.13Windows x86

stringzilla-4.6.3-cp313-cp313-musllinux_1_2_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

stringzilla-4.6.3-cp313-cp313-musllinux_1_2_s390x.whl (632.4 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ s390x

stringzilla-4.6.3-cp313-cp313-musllinux_1_2_riscv64.whl (602.2 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ riscv64

stringzilla-4.6.3-cp313-cp313-musllinux_1_2_ppc64le.whl (612.5 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ ppc64le

stringzilla-4.6.3-cp313-cp313-musllinux_1_2_i686.whl (616.6 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ i686

stringzilla-4.6.3-cp313-cp313-musllinux_1_2_armv7l.whl (596.7 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.3-cp313-cp313-musllinux_1_2_aarch64.whl (661.3 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ ARM64

stringzilla-4.6.3-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl (611.1 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.34+ riscv64manylinux: glibc 2.39+ riscv64

stringzilla-4.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

stringzilla-4.6.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl (600.5 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ s390xmanylinux: glibc 2.28+ s390x

stringzilla-4.6.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl (594.0 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ppc64lemanylinux: glibc 2.28+ ppc64le

stringzilla-4.6.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl (651.0 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARMv7lmanylinux: glibc 2.31+ ARMv7l

stringzilla-4.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl (647.4 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64manylinux: glibc 2.28+ ARM64

stringzilla-4.6.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl (581.8 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.28+ i686manylinux: glibc 2.5+ i686

stringzilla-4.6.3-cp313-cp313-macosx_11_0_arm64.whl (197.9 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

stringzilla-4.6.3-cp313-cp313-macosx_10_13_x86_64.whl (210.6 kB view details)

Uploaded CPython 3.13macOS 10.13+ x86-64

stringzilla-4.6.3-cp312-cp312-win_arm64.whl (123.2 kB view details)

Uploaded CPython 3.12Windows ARM64

stringzilla-4.6.3-cp312-cp312-win_amd64.whl (162.4 kB view details)

Uploaded CPython 3.12Windows x86-64

stringzilla-4.6.3-cp312-cp312-win32.whl (114.7 kB view details)

Uploaded CPython 3.12Windows x86

stringzilla-4.6.3-cp312-cp312-musllinux_1_2_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

stringzilla-4.6.3-cp312-cp312-musllinux_1_2_s390x.whl (632.4 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ s390x

stringzilla-4.6.3-cp312-cp312-musllinux_1_2_riscv64.whl (602.2 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ riscv64

stringzilla-4.6.3-cp312-cp312-musllinux_1_2_ppc64le.whl (612.5 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ ppc64le

stringzilla-4.6.3-cp312-cp312-musllinux_1_2_i686.whl (616.5 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ i686

stringzilla-4.6.3-cp312-cp312-musllinux_1_2_armv7l.whl (596.6 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.3-cp312-cp312-musllinux_1_2_aarch64.whl (661.2 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ ARM64

stringzilla-4.6.3-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl (611.2 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ riscv64manylinux: glibc 2.39+ riscv64

stringzilla-4.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

stringzilla-4.6.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl (600.5 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ s390xmanylinux: glibc 2.28+ s390x

stringzilla-4.6.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl (593.9 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ppc64lemanylinux: glibc 2.28+ ppc64le

stringzilla-4.6.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl (651.1 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARMv7lmanylinux: glibc 2.31+ ARMv7l

stringzilla-4.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl (647.3 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64manylinux: glibc 2.28+ ARM64

stringzilla-4.6.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl (581.8 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ i686manylinux: glibc 2.5+ i686

stringzilla-4.6.3-cp312-cp312-macosx_11_0_arm64.whl (197.9 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

stringzilla-4.6.3-cp312-cp312-macosx_10_13_x86_64.whl (210.6 kB view details)

Uploaded CPython 3.12macOS 10.13+ x86-64

stringzilla-4.6.3-cp311-cp311-win_arm64.whl (122.9 kB view details)

Uploaded CPython 3.11Windows ARM64

stringzilla-4.6.3-cp311-cp311-win_amd64.whl (162.2 kB view details)

Uploaded CPython 3.11Windows x86-64

stringzilla-4.6.3-cp311-cp311-win32.whl (114.4 kB view details)

Uploaded CPython 3.11Windows x86

stringzilla-4.6.3-cp311-cp311-musllinux_1_2_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

stringzilla-4.6.3-cp311-cp311-musllinux_1_2_s390x.whl (631.2 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ s390x

stringzilla-4.6.3-cp311-cp311-musllinux_1_2_riscv64.whl (603.3 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ riscv64

stringzilla-4.6.3-cp311-cp311-musllinux_1_2_ppc64le.whl (611.9 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ ppc64le

stringzilla-4.6.3-cp311-cp311-musllinux_1_2_i686.whl (615.0 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ i686

stringzilla-4.6.3-cp311-cp311-musllinux_1_2_armv7l.whl (592.7 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.3-cp311-cp311-musllinux_1_2_aarch64.whl (661.6 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ ARM64

stringzilla-4.6.3-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl (611.7 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.34+ riscv64manylinux: glibc 2.39+ riscv64

stringzilla-4.6.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

stringzilla-4.6.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl (599.7 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ s390xmanylinux: glibc 2.28+ s390x

stringzilla-4.6.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl (593.1 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ppc64lemanylinux: glibc 2.28+ ppc64le

stringzilla-4.6.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl (647.5 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARMv7lmanylinux: glibc 2.31+ ARMv7l

stringzilla-4.6.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl (647.0 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARM64manylinux: glibc 2.28+ ARM64

stringzilla-4.6.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl (580.5 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ i686manylinux: glibc 2.5+ i686

stringzilla-4.6.3-cp311-cp311-macosx_11_0_arm64.whl (197.5 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

stringzilla-4.6.3-cp311-cp311-macosx_10_13_x86_64.whl (210.0 kB view details)

Uploaded CPython 3.11macOS 10.13+ x86-64

stringzilla-4.6.3-cp310-cp310-win_arm64.whl (122.9 kB view details)

Uploaded CPython 3.10Windows ARM64

stringzilla-4.6.3-cp310-cp310-win_amd64.whl (162.3 kB view details)

Uploaded CPython 3.10Windows x86-64

stringzilla-4.6.3-cp310-cp310-win32.whl (114.4 kB view details)

Uploaded CPython 3.10Windows x86

stringzilla-4.6.3-cp310-cp310-musllinux_1_2_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

stringzilla-4.6.3-cp310-cp310-musllinux_1_2_s390x.whl (624.4 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ s390x

stringzilla-4.6.3-cp310-cp310-musllinux_1_2_riscv64.whl (598.5 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ riscv64

stringzilla-4.6.3-cp310-cp310-musllinux_1_2_ppc64le.whl (604.6 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ ppc64le

stringzilla-4.6.3-cp310-cp310-musllinux_1_2_i686.whl (606.9 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ i686

stringzilla-4.6.3-cp310-cp310-musllinux_1_2_armv7l.whl (586.9 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.3-cp310-cp310-musllinux_1_2_aarch64.whl (655.4 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ ARM64

stringzilla-4.6.3-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl (606.7 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.34+ riscv64manylinux: glibc 2.39+ riscv64

stringzilla-4.6.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

stringzilla-4.6.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl (593.4 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ s390xmanylinux: glibc 2.28+ s390x

stringzilla-4.6.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl (585.3 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ ppc64lemanylinux: glibc 2.28+ ppc64le

stringzilla-4.6.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl (639.9 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ ARMv7lmanylinux: glibc 2.31+ ARMv7l

stringzilla-4.6.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl (640.3 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ ARM64manylinux: glibc 2.28+ ARM64

stringzilla-4.6.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl (575.5 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ i686manylinux: glibc 2.5+ i686

stringzilla-4.6.3-cp310-cp310-macosx_11_0_arm64.whl (197.6 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

stringzilla-4.6.3-cp310-cp310-macosx_10_13_x86_64.whl (210.0 kB view details)

Uploaded CPython 3.10macOS 10.13+ x86-64

File details

Details for the file stringzilla-4.6.3.tar.gz.

File metadata

  • Download URL: stringzilla-4.6.3.tar.gz
  • Upload date:
  • Size: 646.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3.tar.gz
Algorithm Hash digest
SHA256 930b47ccddf13f5bd64ddd006ef6216f03bf04ab3ea356feab5a2639a130845d
MD5 c9618e7cba5c72a5e532ee8cbd9ab359
BLAKE2b-256 fe15a9f64f92af7b59f826e68018896a8a796154ceac8c8ba33c11a5f2c6edf9

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-win_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-win_arm64.whl
Algorithm Hash digest
SHA256 e878a6eaf9f468afc537e1ac6b3aa098b751eb0949a8297541659f9239cd6f10
MD5 4b016b86698ce74bbf8a61df1a0839cc
BLAKE2b-256 271f571c7156b80c7bdaf037baa4716cf71aee0afc2e28ebe04e70be665a9a52

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 167.4 kB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 d19dc4591a9365b55325ebfcb62649e98328330e216b4c55d28a15fa4e5c358d
MD5 113dae82b3400ad019d802f5e1ed7ac5
BLAKE2b-256 aa0f079bb4496facf64a0878ab25e8c47f3d0935f5a56f8a182a91fbe4d3c0da

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-win32.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp314-cp314-win32.whl
  • Upload date:
  • Size: 118.0 kB
  • Tags: CPython 3.14, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-win32.whl
Algorithm Hash digest
SHA256 e40fe0f845c64c3a87810308a7a368e88f85efbc6d5bc4f9d7ad71d2d17c7673
MD5 cf76d8450b2bb085404b978848669e3c
BLAKE2b-256 f588446b51db5f7367bf6fecdd83d02859c13b06ec968c8404dedb0b74f7e2c9

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 cc0dca4a249cb32d165ada9ab26e6cb0fa5b35f42651dfc4d7be6581c40011fb
MD5 3502b1a87b89bdab92fb22291d04d3d3
BLAKE2b-256 9da1c2db7684787fe82aab3bedb60656bbc589bf39ba902525efe28772b12367

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-musllinux_1_2_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 7e215ed73a0bbb908eb8ee9c5aef7176c39121047f6c89bb8ae12a6656ba9844
MD5 0133d0cc024bf219391ffe34e558fed0
BLAKE2b-256 bea8ef0ff103d2798112e7991034c8d2e4e9d9aa8a519282b1ae17449ddbada7

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-musllinux_1_2_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-musllinux_1_2_riscv64.whl
Algorithm Hash digest
SHA256 9af9acc486137d8839969d2fd9956703739dffcbae21500d7858799f5e31ea1b
MD5 21316612350b09a38fba9d79aa44dadd
BLAKE2b-256 cdd99600b95406c02c6dbe1b8522f4dfb40d36b3040d20a325a6670dc1110a86

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-musllinux_1_2_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 0317b545674724e1dd1daf06d9563132d42982e8dcacd7b9682560ead2a854c3
MD5 8c5548839d99b592fdc761e1cd18f18e
BLAKE2b-256 4726263a4f70736b7386da12127c9dad9ae5b2c942bee9e6fa711004c05e5412

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 689424571d5621009bcc472fc1edad031a54ff6f95954e283b15212a4e13d6eb
MD5 f488b0d167a04c6b85cc322e1119bc9a
BLAKE2b-256 6d3c25c48fcd0c224c5b798c175448ae6c7f987771cb06717f3f9a0c064f189f

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 7a42026d0f40035a5683016dcf00fe9ec7b6d3bb005e00c43636136998895160
MD5 e8acff35367ba0370ba1b196344188cd
BLAKE2b-256 b33e66c2a6d46ab80492b1c50341d190d2d798ccbd0a2b45c456383716d6d62e

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 7c2efc3be60b894cc36e59221c9d012f372ba6d1d1513fc6dcb5f5cc96fb481e
MD5 833bcd049fd955ba86d183eac5196fb3
BLAKE2b-256 e69aca3502328495c4e711f9ff618c26f1cdc8790845993e94544cd837d1a8cd

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl
Algorithm Hash digest
SHA256 c8e6c1c5c17edb461128a50bcc968669d85a4341b9d1e28a89cdbbdb4e91c786
MD5 fb55cdb40d2ceb1c9816c8a7034417a8
BLAKE2b-256 bcae97c58c0e284f469ab5bd61c10068637eaaef78bea1cd7a73d837f0622387

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 95af14b9a02e1150aa4b143a4caf31fed39826baef6eae3de3adecb84a34c873
MD5 90c591e04d81a12bd8bacdc9ff936ed1
BLAKE2b-256 2024c8e1ec66261298d21c2946133b2415d3d48b7ff0bbb26fe8036afdef20af

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 0062150c31e63110c53067262eccbbec8ef258778329d65e20bd041f8c5a4caf
MD5 fbd98ac80a16401f3a56bfdf0ee80562
BLAKE2b-256 7813b97d545ffc641c3fc927ccd99193b19e6472e46f915a2b9cc577db5075d0

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 8cc0a496a5aa0c4b97222fa8dfb2547d3b8837d3ae5961e176c483b6fd88efb6
MD5 e7f1c2d873c9a0e2291472db779e94f1
BLAKE2b-256 df93e9b3334967deb25cd173a41f42111b3cd675d5374adcef675a8f30972a36

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl
Algorithm Hash digest
SHA256 d07bb87fc62836e9acfc8560f6fb2eb9da0ccfcf4ba335421dd146b233107c82
MD5 4090ffb273f2f63d750c7ea62b49225a
BLAKE2b-256 f58aaa99f68abe609f39edaeba5da2902a912a635b67729edaf9918e72b3d401

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 5fba1eeb6eb454f9e4df86a4104516b1c4d86c7c9e3fefbd871997ba05e4fc07
MD5 932bc6a4de0f513105048555e9fe60d1
BLAKE2b-256 c7dfb2f0c6b113bb71419c0e38e7572571b6967189c69ff30a163325ec0bd1da

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl
Algorithm Hash digest
SHA256 c9379385d473e97efc5e7e5dd2ae3ec3e5362bf7b1cd82a0ed8f07da97de3990
MD5 694970045d5d57b55c35c636b6e1b211
BLAKE2b-256 9cdfc6f385a6fc3acb3bee6e53fc32e3ca85c01a3fc0140a3bf32e19f5e678ba

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2e44f51fa71e158b08e4e13455e7a8aa7adc1e2e7230593d3f7f81c5f80a094b
MD5 cf364179d5a93f3ff1b4bef419275937
BLAKE2b-256 888cb7d73425aa038244ce3cecc4a8d08f85a69b923e14938480af3feb5864c0

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp314-cp314-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp314-cp314-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 f43afe707fe4f92242e6eb970de801ea0dc19043562e9cd2a58d5e4bc3e262b8
MD5 14b953d0af1346e1ba90859ddaefa290
BLAKE2b-256 4d771c59b9423431cdef9eddec0bea5c2f5001bace28e5fa905644dcec9350f7

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-win_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-win_arm64.whl
Algorithm Hash digest
SHA256 0f62edfc4a6dc5a28e4d917f16272d94399cdbac6541b4f026cd72358f036944
MD5 a87c958c2916e982ed9bc89e50783611
BLAKE2b-256 5c2aebe132f7f9e285e8cd7adb250b3464eda43674b35048493d6ff199646ee3

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 162.4 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 2564a0203cab9c35fbbdedc45a55396d8f114a350eb9694c72a6dd6520b125b0
MD5 efc5551cc226962aed961db6812e2ed2
BLAKE2b-256 5b95f3bdd15aaa427b97e45e2da426b4bb47bee03efa49da8bf05fd5bed90517

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-win32.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp313-cp313-win32.whl
  • Upload date:
  • Size: 114.7 kB
  • Tags: CPython 3.13, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-win32.whl
Algorithm Hash digest
SHA256 f9e40a5fb4d463cfed28a8a3b80b2a223888d4e401b78c3a2b0199b8b1f8b2e2
MD5 862b236f0f8f1851a903a6f621b73ee5
BLAKE2b-256 dd8682587fab566c5205d0c14ce30de63c2c2b3925d1d832cdd61f8efb3b86d8

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 a70d88f69253c53abf442619f3029dd16b5f0f8bb227099a69136c02b617357a
MD5 430d5f53a199fa756f8c34b1fd993595
BLAKE2b-256 449a075fec52865247d33a9753fd3745f6e7d2b259f7b0e95c78c06a1822a0fd

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-musllinux_1_2_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 71736f1098d0ea7e46d1fe0a7fb580f60a875b94b0b6e1d16c7cefd8126222d8
MD5 58266cd0f0ab7d17fcd27b38ba49ea4c
BLAKE2b-256 6e6e36f7816b81b5744b0862b03c1a83d0b55038e72a7789f6c95a5127c2b440

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-musllinux_1_2_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-musllinux_1_2_riscv64.whl
Algorithm Hash digest
SHA256 1f344a3f47a42c83e7fa63bb66d2a63ba2c37a3da21c7ab7bef483fc9dead7ed
MD5 dfb501d4d97a85fc3c33023756a92dfe
BLAKE2b-256 04d7f1673a81f389bce1e35ecaca731575065ce754d92bd13cfa3e5cff6d87ec

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-musllinux_1_2_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 24a9da1b3ac08109ce5eaee471d532a1a72d556c656dcfefe1b9cef8e823898e
MD5 e8f3de2310ecb35a6e98dc64bcb182f2
BLAKE2b-256 de7408cff0c6909ca13174bc218074bee11ce5ee4c444b9f6ad5558370e24420

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 7fef6be62c575ac940134ce5a2bc2f3e49917f686adbeae07f0f79b3bdc4505c
MD5 715ea39e33b6bfe3a0e1333cfb0c5242
BLAKE2b-256 d1f6bded4e4946d2788ee6363f23560e0e29c5f60c23a49a5b65abecf6d096ca

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 d19da215cf5d67425f824adb092cdc8dace3c93387042908ddfee2f0d013279a
MD5 a5788c2ae6fabd77390f25fe396d90f7
BLAKE2b-256 ffbfc49071819edf14204ce057e4d01034e166cf9c7ab56c20b142979da54c22

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 25255a7a7b37d7b2e96bb307382b2821e6a3e57bbceb21f29850749ed42787bc
MD5 21ff6ede9a9a9221743b12a8ac46f7b1
BLAKE2b-256 16cb07fdbb92649694ae98b2e11327c522ade5efd310c4a824670070dea9d5d5

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl
Algorithm Hash digest
SHA256 fdeffa6fbe8298673b9fee3d540fe331a21cbbb9fe64724dc580595b7377f139
MD5 c42ae8f9c21e3b3d893498e330c9f49d
BLAKE2b-256 04b3fb75fa9dbb4df9c9ddb997a5a367ba15fe232724a975baf04d1405a070af

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 197db660f78df5b7ece14f774db8818f4ab9860d359d3e40a506df66a60ba1ee
MD5 8afb98f79bb88e98f7a30577468f8906
BLAKE2b-256 d95479fb6b23575325b89fc6c85eb66a543dc53567f519420cdfc93b647b5542

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 5c8722fb634f6e9f064ef8bf6633863ed65692639e6116004c0a90e766fcee81
MD5 20de1606d1e9f1357950e9eef6d6c30c
BLAKE2b-256 6ce82db18414a3f8f969487598e3476084eee8d4b947b19fa9e3fe74c2303c17

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 0484c0f3f1361dda7bc2e0586bbf1d72f33b87e5c3dcbb5ba520413f6b2e5be6
MD5 cc6efb68893b0bd4613e0f7fee6ba00f
BLAKE2b-256 df288200498b3ebcfa4525423f3cce1ea5bd9557136091ebfc19f0105b20db54

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl
Algorithm Hash digest
SHA256 6c60e1ef89bdcfb19f5dfd63d0df8b35b763202703e7c8d1c1eac070e2aa08d9
MD5 aa610cec53ed0ee358a2bc04f80210f6
BLAKE2b-256 5ecb39e93ed89e4e6100c470f611b252c0da4e6fd0cf0f1d68d3f72543bb3817

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 874989aa647c5878f41997648ba0124c6073df85e4f3249d106c4a20c95924a0
MD5 8992a1bf6dfd41d9f07a1304b1e7d3d9
BLAKE2b-256 310f9e5b2aed21f18b60c715b5eee52ef810175e33bd581f9560668b13ff1f08

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl
Algorithm Hash digest
SHA256 22b57105d6934f9ea320abf9d742ef2f377d453418f4d546875cc2a41581fdfc
MD5 ffbd13a5d3e60aa4fcf629734c6f69ea
BLAKE2b-256 bc658bb0b26485fce43b7d81b3fd223ae1740ed8c405de4ee9dd77d561cdae17

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 49363f5a6bcc59f93bc45fa0498d1d8e50aa293a16ffa21b01d86e2e702af750
MD5 761bea825b41b35e4075c1eedafbfcdc
BLAKE2b-256 3e6daa25ccf048775336f303e1814f2c32e595770f4b32d025e98d6396800746

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp313-cp313-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp313-cp313-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 6705e1392563f7e777a9c2c5ac9d9de6829dd266b2e0b003d35f1d21ebecb0ad
MD5 a10cbe50c11182c5ff12531a02ace98d
BLAKE2b-256 fdffef46226f9bfdadce179f3692b0e99977e7d4801e3cc89830c2d3bd967165

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-win_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-win_arm64.whl
Algorithm Hash digest
SHA256 d8ec623ed4dcbc05731dcb0ae7991735e632e87ddd0b1bbfec26edc0a48fff21
MD5 eaa8d113bf57d1020c82dd4bdfca11c2
BLAKE2b-256 38904fdf4e47af13a9b77b4d5108227d5561f6df36fd4c93613c01221bc53312

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 162.4 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 f91eb0640b2b0fb3e54e1ae20e994da9e6083c250bb56f0ab935efa2d09016e1
MD5 7aaa81f92a4dc972c7985db762932353
BLAKE2b-256 15681aba4e9421a13cc1a71d9df5c6d3ef4864b83f03f75a121339e03b4c4322

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-win32.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp312-cp312-win32.whl
  • Upload date:
  • Size: 114.7 kB
  • Tags: CPython 3.12, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-win32.whl
Algorithm Hash digest
SHA256 77ead27c0b434ae65b66b2c66e80b077a83bcc6f9764367cd6f58ee1e7026e1a
MD5 6326777f9bb6e0b3612b41b61fd8f8f9
BLAKE2b-256 28477b4b40f43e5e7033a8f31fcec5fdb1441425b980543484d7663994463042

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 78223497e76245cc9d7de94005cc0bd505cdf533e746d4f55a5c2b45b27000b3
MD5 0036a218a5aaebc8852073da671346b8
BLAKE2b-256 a448884b1319b213e20783388fe94fc9bc9406b7df28673fe175a5ea5b244570

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-musllinux_1_2_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 02bfb98d2ecbb81fe290d7ef1d55f252b6e79f01fcb7a5eee3cf354ce407bd32
MD5 9b940c159441fa0eb7acbe0c29086315
BLAKE2b-256 31effccbcef45b09edacf2d8b45390bdfbb35234babdd744eabebafbcdbae479

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-musllinux_1_2_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-musllinux_1_2_riscv64.whl
Algorithm Hash digest
SHA256 3e9451e154a656debde3e23503edffa35c08e34fd03094d7b9acc6722bb66b14
MD5 421d39ff63ce86b853de5ed204a6bb7a
BLAKE2b-256 ca91c9680327d02c0821a02d38c61400ec30d9b7aafb6294d55e3a1fa2619b50

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-musllinux_1_2_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 7327d49006b70b2242c9cb3169a0e297b2890edc4951b792ef66f9023fed1608
MD5 2e91fefd1e624ca994737e6830d0a96d
BLAKE2b-256 8ed60ceaefde515bde6bc6319ee1cdb9a36f812304be07bb402d71480124fede

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 5e1b15900e44a7d47342348f987a9a6fa10c356a948147b91bbef7154543721d
MD5 cd0a4b81867a8b782436f72ca3691899
BLAKE2b-256 f2a45f3f632c0d75c20cc51227c4df4d8d68e5c7e88013263626d2fea3e64979

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 0a4da6986e8ed83b0806b3f897c2304e23bfb4a27e00baff6a7fefa91a943ff0
MD5 e72f1413026dc32c1ee8a06bc69f3a1e
BLAKE2b-256 4ada69c1d5bb0f1dba933a4d45587313560c408aabfb2fe4ec36224c59fbee49

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 5abb4aaad8075a15f369601d581274119ef29f1f736217e9968ace67747672bb
MD5 c7b19cd51ce3771c7abe78b33a382a14
BLAKE2b-256 70efeedaff3a78c96f71d13f3ebba8d8447f14ba18affd9c734e9a7938b0f993

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl
Algorithm Hash digest
SHA256 8b09da64c2d10c26d528bb5b9fa46131f1e2b89cbf2fbcaa833a4626022f78d5
MD5 d31405668e8690784d663b94a5376296
BLAKE2b-256 b8fa54612ea68ae9e61c7743ea441e84fa311af207b6e53477e8d60fdff5e5b7

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 4f0ab29e4726d8a5d857357befb2786916d445066b33084be9483342d44708f3
MD5 6e54cf70188c4a459a4132748ba6dc94
BLAKE2b-256 d4a519b3034d096f2b97c7c8721c715e6c8e56cc46197db3f71ce556ce76849c

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 222168a49737e4004b66f6a4e4712923023c4dcbc6081341d573c8a536c2c89d
MD5 86b728334d156049f33967f1a9cef762
BLAKE2b-256 0f5d13b276d4ccac0b23c29c3693bcf210437ca69bc3439fbbf854f771cd55ac

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 491a51d7aaeaf59c7e1055a3cc9d6cf97eac1dd4a15e37c795ccbfeaa01ab105
MD5 768989a9706af3e40657a3f799c82f6c
BLAKE2b-256 e2707480f501ed69b729de17dcccde050ca8d1abf4e0f85ec1d9be43f98240d6

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl
Algorithm Hash digest
SHA256 4297b51691dc382d0590a48e330bc703b0b94da31b4ca0153738a1ef5292d573
MD5 aae4274471385bc8439c99caeb1e0bbe
BLAKE2b-256 cbbc509330d5b88ecc1cf01a2d272895e543be4d9ee26beeb43184575e0d9848

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 00805328a450a55a524ea6e7b79bba5bf69c06b663f2d42417016b43a50b3408
MD5 8b4487973b88635080a41a4655b7855f
BLAKE2b-256 e225a343d2b87289e6b2cf333426f9533bd761e3f21109b55694ee40ff6c7d27

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl
Algorithm Hash digest
SHA256 fa55806f131e2c74c601cdebfed968518c28e502e15a1c72b2dbba7214ca74fd
MD5 c7aaf47bbc55222b7f72d6803ae5c5df
BLAKE2b-256 076293cbb5a0c3fa8feb6211b0ff138e80537e65e48c2bafc8964d20e8f068b4

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 62b2b1535c4dacab6f8bf7c1ea7b5d836565f9c43ade0545d0364b4f5c272de6
MD5 ca3dd8cb5d54132c3ef08d32187ed389
BLAKE2b-256 a484ca8a14c62510c79c9ae40ec9b1a63b62dd828d3424ee3928c1da40ecf9f4

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp312-cp312-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp312-cp312-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 1a32d7b824c66db318c33925552281ca96f2c58fa61c4ad2d52997e12d73e4ca
MD5 bde3076f1bdadb7b308381f29c470e34
BLAKE2b-256 8f8fef57ff14069189378081be5df0b2bb49b0f0d2a093527cc69b05c78db209

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-win_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-win_arm64.whl
Algorithm Hash digest
SHA256 13170885f423ed3efec2ffd68012088d6163c0c075f49539fbe420fea645831a
MD5 0e33ac51eb7369ac635483a22e69f152
BLAKE2b-256 67ba574f32304cc6387888d2886d4d0b4c4ab2a1721cc3b10ee5f2c597a5bbce

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 162.2 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 3b682222dade1e635e5a35e7abf62788a00760c4947f08d3b1ddc56e2708959d
MD5 9b17982d9329b67e934817c2d1e1390f
BLAKE2b-256 4f2b75d2115674f6dd07284c0681eb7a5d7472896b99f75e6cb41ed5301154ca

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-win32.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp311-cp311-win32.whl
  • Upload date:
  • Size: 114.4 kB
  • Tags: CPython 3.11, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-win32.whl
Algorithm Hash digest
SHA256 86509eeee272507fba1af6409a4cfcffad0388d3caaccccfeb78362cda5f0407
MD5 0eb383d31ee688709292eba5af6f9032
BLAKE2b-256 7c975638f88eba12de780dfa64cfa1ae358086f2a8e493eafa4fc507c825dbfd

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 71d56e880bd6d791a2cf441017ef954fca304552cdaf76433273e9a8a9b9f7cc
MD5 bb3d73d8ebd23a5695303efc383e3963
BLAKE2b-256 6315f8854b2e9fc8f9ac49dc090f7d1e0bff51210abb165a0a4232cc7b1ff9ff

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-musllinux_1_2_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 6dac015716fa252d284ed0128d67103d62987981b5be573234a9118e7ce1c1c5
MD5 789841125ca6043e81b0333a81b6ce9f
BLAKE2b-256 1c6f60c05984157f32a3ad7df991ef47af57249a50748763afeb9a03ce833d95

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-musllinux_1_2_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-musllinux_1_2_riscv64.whl
Algorithm Hash digest
SHA256 2561f409102cbf2f5d2eabf366d51904d3c57d5d367e1d09e2fcfe8d1ce63d27
MD5 1d5cba9f63bd916bfc00b4e4d86dd6a1
BLAKE2b-256 b8964b8cffa8be95b65ebe76edec03ac9a9882a3dc61beec88389e9752892c64

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-musllinux_1_2_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 1420614dc91ecad85d8873cba6b1287bf0d788b09a96a754c8750c3f9bc2ca8a
MD5 9b9ce082428a10b8a8cb1cd1dba3b87c
BLAKE2b-256 6b6b4dc284031ab4b65cb7d7ae90ec9773b41661a3a3f506c3f00cd02fdd3b0e

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 f2c9bbacac78e74e1a4e499d03a72f48a13e5100ece0132029b70fa7076eb54c
MD5 d7d592ab56d08973e302af98f5e3a8d6
BLAKE2b-256 af7424760182d3d9c51c9dddba4fa2a967fcb2bd04f5a73e73e9bf8871084861

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 8409c771b58bb09ea23ca2701c497485503fd8302c786abd156f79132aeb94b4
MD5 c3d7634b1d4c819d2905b70fa5fada7f
BLAKE2b-256 569da05479697edcdd4e769097a02a0bdadf74ee7aeeb2b3b0f02153c5a0e1a9

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 9a6964b653a682609d76529987f62b65ee1988e7b6aee74c214e7910a8c553a3
MD5 86a9651afe9de5622b1cced360724ed5
BLAKE2b-256 f2be180c03d021f54a04c47d091c1c8a8684d97039e5be4f47a6938dc995ec12

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl
Algorithm Hash digest
SHA256 5203e8c93b59468f7f08099b0934ed3d579b981abb4e8063ed485226ea66deab
MD5 704fe95e3ed716fa86ce0346c264a0f0
BLAKE2b-256 7fa517ab8f0d3c14b7ed04416c674d2d0cd584722c0d0a0b4d5e908fdace1997

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 03f76da76c4b0c9d7a18bc266de1eed92c997a6270ad7ee4c6967fc864ca75ad
MD5 e2abdeda9cc03497167e27eed44b041c
BLAKE2b-256 cb1277e81f716d26b372dd1d0c522b3879ce82204ab280f90509e60e711d71e0

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 1e09c82e83f53d3c371e3063211665089c99084f8d330a0048f2f57ed2353867
MD5 8abda3af7db1dc6c433a3eecc5592ed9
BLAKE2b-256 39fba08054c66a101d5e9f865601b5d472dd673f869a14e1ac6a44724a2a4d96

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 be0dd1e59a5eac14717ad0fd2c1c1834a243816b72382770be93564535c4c037
MD5 ce10be191b9f39c289075cb90f095ae7
BLAKE2b-256 53a881983f030ac8fa8b55eabd022455148238db3582f333e88bd25cbebde1cf

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl
Algorithm Hash digest
SHA256 1e10a97b470423a191d3aed357d9ee957556c58c59cf2e987b60b96aae8c7205
MD5 bf055f2e5a90c0bd48b53805a415c7c2
BLAKE2b-256 b1e072ec582cba6c12e033dbae6a175c2a663ff5aeb732b5723b7df319577b9c

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 8034fadef1c2b423fa60404eb6dd2576592e8aec4c5fb60de814c2c1271df68a
MD5 bec7fa0960cf551a0f88455238df3e0f
BLAKE2b-256 86c8ffc996f2ff3e7f3bd29dff4a58770225f4e681bb791094dd198977c04ba5

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl
Algorithm Hash digest
SHA256 39bc0dcd427925afcecdedd12f981f7a11be29fc06b12c9f65f3e99f1d7f9821
MD5 a5a882720b993be30bd6b41b28b4341a
BLAKE2b-256 4ca7baddde5b0114f75a8a6d7b3c9dcd709293ac8de53e3aa10a6716d9d4ca57

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 62487cda3ed067d5baecde0046b1a4ac2833049635dde56722a9149c1764dbdd
MD5 b61518a8400bc788811a41f52ea3c390
BLAKE2b-256 fffb6f58609ce75ac26424ba5ef1f10b48310297c8b000c95e29bfd585743860

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp311-cp311-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp311-cp311-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 1bfdd85246fe6b6a25d266d8af7be5aabab5d80794d8590e113181a91dcd6d20
MD5 63397932906b0af20fa9cf033a3b4300
BLAKE2b-256 c86d31ce7f84e46878765f0a27ed935d7701be7093448740a7853fdfe6b0fc43

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-win_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-win_arm64.whl
Algorithm Hash digest
SHA256 9dcea2f699c89919e4bb480a9aa907f3cf2c3ed1569bada637a142cfb3a95452
MD5 f1ee451d8507e492e49421124364e6e5
BLAKE2b-256 bed2da6559d4d25a3e458d1eb53788df9e47e57f46c72ba84adb8b90797d8228

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 162.3 kB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 83a7d3686da9d982c54aeb778c709756c6204f32fe5d31733c27950da28ad1ae
MD5 d7a5a82442f037d67f09e92d3cdeddcd
BLAKE2b-256 d04a36fb4ef33dcbbaf870f19fdca0be5e8edcd008dbb9a422b9e0f4de069cd1

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-win32.whl.

File metadata

  • Download URL: stringzilla-4.6.3-cp310-cp310-win32.whl
  • Upload date:
  • Size: 114.4 kB
  • Tags: CPython 3.10, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-win32.whl
Algorithm Hash digest
SHA256 ef226b272a913d738db92bf477563939fd97e59e4f055bdea2c75fc899b6ae21
MD5 9e214c1d1affcd23b1c71337e305e36b
BLAKE2b-256 d9f4a66030a2991e89cd450471bf4a51a80d8fb977ef164ad69cb23970603e13

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9896ac7096bcac654ac39b1d3c4bbb0af57e66ff6e08268f056b01f37413d8cd
MD5 a347a5f39c7147985baa69b4d79ad463
BLAKE2b-256 af9455f051b2d0ac379ded90cce109b8ac8d8e793b76f0406390c10cf91d9ad2

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-musllinux_1_2_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 c570089faf66869dcda3dd971abcb4d30246f23ef07aa9626ef606733ac9a591
MD5 4ec99ad166481a89317f6d83750b7146
BLAKE2b-256 5b16df515864adae86ce8f87d3fbcde29f3695bdafa6e2cc2474b04857b607e8

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-musllinux_1_2_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-musllinux_1_2_riscv64.whl
Algorithm Hash digest
SHA256 c4ec8dab50e9deb798dbc4a27a0e14dfd7d2461a3dab5263845df8403285df5f
MD5 b39179fa5896aa4c1669bdbe2f34d938
BLAKE2b-256 b9347bd1ca9f35f5569307732da40d3cc65d9bfdf4cd905e809d352ee6c45e2a

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-musllinux_1_2_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 f45efb4ef41faedc856ea0c9447f158b0de513c7dece9e7ef93aec0cab88262e
MD5 fa925aed30b2e845e09f5a4819c3e559
BLAKE2b-256 7ab9b39246e5c3254591bbd915b0d07e01cda48924f67f1b499fc11acf2c492f

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 4a127b3e026e566e5574698927b9ab8cb0f0158e6d096c5d90fe36713cbd52fd
MD5 b96daf6233588e75bb8e01dbbb6dfa76
BLAKE2b-256 03c89478213b11e7a260a52552182eef40af622d9188058b39372d6c6d85b7ae

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 e0e2d30d19dd409d83fe6ac0ecef412c9e9d66ef0a5f377373adf9cfc4bec19c
MD5 8d63f54b02b9cf55156cd21a35f22d3c
BLAKE2b-256 8a181bf809647d7571be6b96e16399a469093063995f96861058c633314333c1

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 39f399b5f08d78b8ff538d1d97000229d66829746c8b11fdd7d3a35487de1e0e
MD5 9c330caf4d0e81b3f4fed080eb171843
BLAKE2b-256 9f592c3c6b864117a85f0594b3ba025cbf890d3e57bfdbc16ea9a1587a8bae23

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl
Algorithm Hash digest
SHA256 38b51e09f5a42747e1198a5cfe57f603c36aab091ea9021bd94c9dc24a255445
MD5 dd1432732198d76b20d088ab28f95d50
BLAKE2b-256 2a9ea9ccf79ea6c26209499e0d8e3ef0e0e89c02d7462e3120d1c1c6cf44b588

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c8dc4b732b87b5a3f53b4cd0223879d987f3bbc8afb5bff2477c4efbdc224131
MD5 7760acdf73e2857074f5458ad58e5372
BLAKE2b-256 d7b0ef4de168fa648cc2d0502165f654a7f69c28e4a85e4eaf5b551f04e9af77

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 b14c557c8e0acf2321332e0fc86008f15a1767931187e8933d4758a1a370b8fe
MD5 852e623e0ada9b9ef17dd812cb0040f5
BLAKE2b-256 9e5956d71075b9eacff36c66cadda5155f99cde0475923b07572f60ba4eda1a5

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 fb434077713313e4d63b2842098593e6113bf955d07f77ffecbe14a7f832a98d
MD5 9e6b0309c493b33e3e62202fc042c2bc
BLAKE2b-256 9ebc47230f94a95d30b67e4f84581c4251304686cf2c07925a5549d3d278558f

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl
Algorithm Hash digest
SHA256 24f88a7d67a3ea831a1f62e9a7d1e6135511bceae9fc5aa5027b758fc1a14cf1
MD5 245781b0dc23b32dfc3ee2b9d490f8f1
BLAKE2b-256 cbcfd6e48dbc1cffa5fbe124dbe66f819ac3486933a45476b78f5aed87af1ab5

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 e687b18cf2316e0ace07d29ff9a7cd70d049a7da82e79709996b706e9c6e280b
MD5 f7164dd4b67086fb0c934570eea835d0
BLAKE2b-256 01622dacff520dfd539cc401f375a34677635dac4c4a6e0235afca8f847bdf66

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl
Algorithm Hash digest
SHA256 806b70eac3556352a4bff3283ad853e317e693b782a07034e426cbc2e9f22d6a
MD5 2e1eb9683457ed7afdca2db6969b7282
BLAKE2b-256 97b453653e60513ad8de54ee8e847e741698d792bf6fd64cdfeba4263df0acb4

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ada6b9821bf2a4b1487eff3ad7ce4776c02805659743e7f9454a5c5ac18d85b4
MD5 9da43e4298b831f0a9a316e3de68eb33
BLAKE2b-256 a8e6619da7c86707eb33174e46bf7f31248c7dc498859174a94f8642fe84518b

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.3-cp310-cp310-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.3-cp310-cp310-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 efdfbee29f15c4dfb4157bc663fab5ad8912c02c3bf412b5a5ab71d9de90b587
MD5 f837a910c9de77130d93884499a6f799
BLAKE2b-256 281811dd43a41ab05078d780e32f779f380d31dd1f2fe89b3b453765e46110a5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page