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.0.tar.gz (646.3 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.0-cp313-cp313-win_arm64.whl (123.3 kB view details)

Uploaded CPython 3.13Windows ARM64

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

Uploaded CPython 3.13Windows x86-64

stringzilla-4.6.0-cp313-cp313-win32.whl (114.8 kB view details)

Uploaded CPython 3.13Windows x86

stringzilla-4.6.0-cp313-cp313-musllinux_1_2_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

stringzilla-4.6.0-cp313-cp313-musllinux_1_2_s390x.whl (613.1 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ s390x

stringzilla-4.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl (618.8 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ ppc64le

stringzilla-4.6.0-cp313-cp313-musllinux_1_2_i686.whl (626.1 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ i686

stringzilla-4.6.0-cp313-cp313-musllinux_1_2_armv7l.whl (586.8 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.0-cp313-cp313-musllinux_1_2_aarch64.whl (653.5 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ ARM64

stringzilla-4.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

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

stringzilla-4.6.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (640.4 kB view details)

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

stringzilla-4.6.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (657.1 kB view details)

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

stringzilla-4.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (689.3 kB view details)

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

stringzilla-4.6.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (644.0 kB view details)

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

stringzilla-4.6.0-cp313-cp313-macosx_11_0_arm64.whl (199.4 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

stringzilla-4.6.0-cp313-cp313-macosx_10_13_x86_64.whl (212.3 kB view details)

Uploaded CPython 3.13macOS 10.13+ x86-64

stringzilla-4.6.0-cp312-cp312-win_arm64.whl (123.3 kB view details)

Uploaded CPython 3.12Windows ARM64

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

Uploaded CPython 3.12Windows x86-64

stringzilla-4.6.0-cp312-cp312-win32.whl (114.8 kB view details)

Uploaded CPython 3.12Windows x86

stringzilla-4.6.0-cp312-cp312-musllinux_1_2_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

stringzilla-4.6.0-cp312-cp312-musllinux_1_2_s390x.whl (613.1 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ s390x

stringzilla-4.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl (618.8 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ ppc64le

stringzilla-4.6.0-cp312-cp312-musllinux_1_2_i686.whl (626.1 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ i686

stringzilla-4.6.0-cp312-cp312-musllinux_1_2_armv7l.whl (586.8 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.0-cp312-cp312-musllinux_1_2_aarch64.whl (653.5 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ ARM64

stringzilla-4.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

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

stringzilla-4.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (640.5 kB view details)

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

stringzilla-4.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (657.2 kB view details)

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

stringzilla-4.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (689.2 kB view details)

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

stringzilla-4.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (644.0 kB view details)

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

stringzilla-4.6.0-cp312-cp312-macosx_11_0_arm64.whl (199.4 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

stringzilla-4.6.0-cp312-cp312-macosx_10_13_x86_64.whl (212.3 kB view details)

Uploaded CPython 3.12macOS 10.13+ x86-64

stringzilla-4.6.0-cp311-cp311-win_arm64.whl (123.1 kB view details)

Uploaded CPython 3.11Windows ARM64

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

Uploaded CPython 3.11Windows x86-64

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

Uploaded CPython 3.11Windows x86

stringzilla-4.6.0-cp311-cp311-musllinux_1_2_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

stringzilla-4.6.0-cp311-cp311-musllinux_1_2_s390x.whl (610.7 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ s390x

stringzilla-4.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl (618.4 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ ppc64le

stringzilla-4.6.0-cp311-cp311-musllinux_1_2_i686.whl (624.3 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ i686

stringzilla-4.6.0-cp311-cp311-musllinux_1_2_armv7l.whl (583.6 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.0-cp311-cp311-musllinux_1_2_aarch64.whl (653.6 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ ARM64

stringzilla-4.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

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

stringzilla-4.6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (639.8 kB view details)

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

stringzilla-4.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (656.5 kB view details)

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

stringzilla-4.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (689.5 kB view details)

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

stringzilla-4.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (640.7 kB view details)

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

stringzilla-4.6.0-cp311-cp311-macosx_11_0_arm64.whl (199.1 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

stringzilla-4.6.0-cp311-cp311-macosx_10_13_x86_64.whl (211.6 kB view details)

Uploaded CPython 3.11macOS 10.13+ x86-64

stringzilla-4.6.0-cp310-cp310-win_arm64.whl (123.1 kB view details)

Uploaded CPython 3.10Windows ARM64

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

Uploaded CPython 3.10Windows x86-64

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

Uploaded CPython 3.10Windows x86

stringzilla-4.6.0-cp310-cp310-musllinux_1_2_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

stringzilla-4.6.0-cp310-cp310-musllinux_1_2_s390x.whl (604.4 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ s390x

stringzilla-4.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl (612.0 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ ppc64le

stringzilla-4.6.0-cp310-cp310-musllinux_1_2_i686.whl (620.3 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ i686

stringzilla-4.6.0-cp310-cp310-musllinux_1_2_armv7l.whl (578.5 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.0-cp310-cp310-musllinux_1_2_aarch64.whl (647.2 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ ARM64

stringzilla-4.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

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

stringzilla-4.6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (633.4 kB view details)

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

stringzilla-4.6.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (649.4 kB view details)

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

stringzilla-4.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (683.7 kB view details)

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

stringzilla-4.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (633.7 kB view details)

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

stringzilla-4.6.0-cp310-cp310-macosx_11_0_arm64.whl (199.1 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

stringzilla-4.6.0-cp310-cp310-macosx_10_13_x86_64.whl (211.5 kB view details)

Uploaded CPython 3.10macOS 10.13+ x86-64

stringzilla-4.6.0-cp39-cp39-win_arm64.whl (123.1 kB view details)

Uploaded CPython 3.9Windows ARM64

stringzilla-4.6.0-cp39-cp39-win_amd64.whl (162.4 kB view details)

Uploaded CPython 3.9Windows x86-64

stringzilla-4.6.0-cp39-cp39-win32.whl (114.5 kB view details)

Uploaded CPython 3.9Windows x86

stringzilla-4.6.0-cp39-cp39-musllinux_1_2_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ x86-64

stringzilla-4.6.0-cp39-cp39-musllinux_1_2_s390x.whl (604.2 kB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ s390x

stringzilla-4.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl (610.9 kB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ ppc64le

stringzilla-4.6.0-cp39-cp39-musllinux_1_2_i686.whl (620.6 kB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ i686

stringzilla-4.6.0-cp39-cp39-musllinux_1_2_armv7l.whl (578.0 kB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.0-cp39-cp39-musllinux_1_2_aarch64.whl (646.9 kB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ ARM64

stringzilla-4.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

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

stringzilla-4.6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (633.0 kB view details)

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

stringzilla-4.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (648.3 kB view details)

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

stringzilla-4.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (683.2 kB view details)

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

stringzilla-4.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (633.4 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

stringzilla-4.6.0-cp39-cp39-macosx_11_0_arm64.whl (199.0 kB view details)

Uploaded CPython 3.9macOS 11.0+ ARM64

stringzilla-4.6.0-cp39-cp39-macosx_10_13_x86_64.whl (211.5 kB view details)

Uploaded CPython 3.9macOS 10.13+ x86-64

stringzilla-4.6.0-cp38-cp38-win_amd64.whl (162.3 kB view details)

Uploaded CPython 3.8Windows x86-64

stringzilla-4.6.0-cp38-cp38-win32.whl (114.4 kB view details)

Uploaded CPython 3.8Windows x86

stringzilla-4.6.0-cp38-cp38-musllinux_1_2_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.8musllinux: musl 1.2+ x86-64

stringzilla-4.6.0-cp38-cp38-musllinux_1_2_s390x.whl (601.5 kB view details)

Uploaded CPython 3.8musllinux: musl 1.2+ s390x

stringzilla-4.6.0-cp38-cp38-musllinux_1_2_ppc64le.whl (608.2 kB view details)

Uploaded CPython 3.8musllinux: musl 1.2+ ppc64le

stringzilla-4.6.0-cp38-cp38-musllinux_1_2_i686.whl (618.4 kB view details)

Uploaded CPython 3.8musllinux: musl 1.2+ i686

stringzilla-4.6.0-cp38-cp38-musllinux_1_2_armv7l.whl (575.7 kB view details)

Uploaded CPython 3.8musllinux: musl 1.2+ ARMv7l

stringzilla-4.6.0-cp38-cp38-musllinux_1_2_aarch64.whl (644.2 kB view details)

Uploaded CPython 3.8musllinux: musl 1.2+ ARM64

stringzilla-4.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

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

stringzilla-4.6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (630.1 kB view details)

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

stringzilla-4.6.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (644.9 kB view details)

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

stringzilla-4.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (679.3 kB view details)

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

stringzilla-4.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (630.4 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

stringzilla-4.6.0-cp38-cp38-macosx_11_0_arm64.whl (198.8 kB view details)

Uploaded CPython 3.8macOS 11.0+ ARM64

stringzilla-4.6.0-cp38-cp38-macosx_10_13_x86_64.whl (211.2 kB view details)

Uploaded CPython 3.8macOS 10.13+ x86-64

File details

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

File metadata

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

File hashes

Hashes for stringzilla-4.6.0.tar.gz
Algorithm Hash digest
SHA256 640c0fb5b6a2ad77b7721bff98f00a3c524ca60dc202f552e486831a751d4bbd
MD5 3bd9365e47e654b0e38dc1b240459bf5
BLAKE2b-256 6168475518f6f4af8273ecd619a5d37d715d36908973f9970faf21571a296821

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-win_arm64.whl
Algorithm Hash digest
SHA256 33192fe820704803a52b90c566838373f45b295e4064e0679ba4f76bb76b6ce7
MD5 961315d89b5421e9871cfb035aa9b28f
BLAKE2b-256 6b891f5a6b4f8fc405e1e76125be9629ad7390bfcf1be9683a6e2e5602911b68

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 0e18442332b72d37465f7959bb72f0be480f4d604c86d165863587113401bb45
MD5 4f89dffa88018c4324181e55314ddca8
BLAKE2b-256 0e21b9bd35292a126a0c2fde103ad5ce5bfe7384cb6eba4ca34fc5cbcaa7ac96

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-win32.whl
Algorithm Hash digest
SHA256 51d3c8504a8038b3d1699f366a56a8d4571741c3993af9562b6f227d56c5ad67
MD5 a6d64e7789810789070119ddee4002c3
BLAKE2b-256 fb99fab077604f45c8ff1d330c26d1cccf94a58ea0a9155c8ba63c038117543a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 dac46e84bcb28b344206dbc21b892c4ec5fa8506ee7027412819be55e75f91e9
MD5 47a8df7f1fdb1cf0a42e78c119706a4e
BLAKE2b-256 46044246dc812a5da8d97176476f79796cfd02e4e1c1ad8ae27f1ca0e869c4eb

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 b21708b71907a3f625e37f9248c37c67542f5665740f2205b9050e1fc67b4d87
MD5 3dad1220c7e69f0d43585e64c909d63b
BLAKE2b-256 8af0a744c287f1bad754a4f03d4c1b64be8939ff7ea32f345352f3c09ed15fb0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 a50fc1237f64fdf79bea5d55c397ac88abc740284ddbfd03bdeab0a0b43711fe
MD5 242070286ef999cf52d2cc3ab1e6d4c4
BLAKE2b-256 08129ecda6d1972ddc2a91a857e5305066e2784392d9e27eafbf99b84c79052a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 fd7d125408f372aee425b0d0dd998199c0dbca599be9942ce41b745f21c98198
MD5 45487cf608193fbe83d549d6c3431453
BLAKE2b-256 86ffad0c3b795a3454e13d9dd59552029713ccec87bdc5ee62e48f5dd63f2e56

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 b035ee7301921cd064421cbd08c84e6adb7244472c7679155716d7ac57a95299
MD5 5435c05ae28a09a8c9dbc85195546f55
BLAKE2b-256 784030f450e4c8edc981c72e155ec41419712701e81eb38a5dda7cd07d7bd24e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 f7f890db95eb00e10df429e5d85fdacb4904fbe9be20f59d87c2981b06b2caf1
MD5 bac10073e1795f57092499b51ed1ccd9
BLAKE2b-256 42655f2a826c7091405db189aac751db6cee5e254fb9b35a99f053889b2d3615

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 899974a4e8231abe3486f7e47f0cc3047d75da99e447153738efd5097db731d1
MD5 52655492960f333836a76043308c3e49
BLAKE2b-256 3044e73fd1c47f23ee7513bf86451464db2eda3d8835e9be408f9dd9ca06a0af

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 ac8fc7c55b612a52855143eff0981c11c80d0a64472bf77b68339bdea01737c0
MD5 d2843e91b01d2db935577e9da684d28a
BLAKE2b-256 f5261e98779e66990d15ad1bb025f24ddef736712333b173926c06977159613c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 e5f8d1d72e23981964aec25a1eb41a9c42814d1a4e90467c0e27fb1f4c2fe948
MD5 a7303889900b66c95a0da3cca2bc46ad
BLAKE2b-256 ba7170bbbf4e59f4dd2e097f36a4e96482a546a0f081721068e32a7d02f60014

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 c1105de1b97b7b8f2c8e4dda0cb370cef882fdb5df8f945c141bc022ca3ba65f
MD5 8ce1e6898c8c62fc0131378d4c8bfe3b
BLAKE2b-256 8e20561b7199cfeacf6ef68d26a8846a0e6f521e96e4be4f9d20098d80b6314d

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 221f53f809d7beac636d369a255fd5d9729a6a8b5fe4e38afc30b41f59eccc39
MD5 32ad0dfe30b16053ce7e695df393ac8b
BLAKE2b-256 ca5cd274c820da68254c105c6c18b31001c1624f78c9cc7c36f6550ca17cc6ef

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 41ec1735fdeaf4e276be0a531d4dd7ad4cb1e7071fd8729c2ca579a5ea49f92a
MD5 db83e5e8d72abc233014a484a5cea91d
BLAKE2b-256 b621641914f44f195fb718e1ebf111f0f70150cf5e4272b3577d6b832fd085f6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp313-cp313-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 0123f724dc63c7e7dbb6eda5f821593effc5fda889ba392e0f7c676924d1131b
MD5 a1206d7374b7f2f7cd2133df62d6760e
BLAKE2b-256 7139ee92df4c6ffc19d763824c061e47b358e1ab8e0724f35d0a41d17dd4e850

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-win_arm64.whl
Algorithm Hash digest
SHA256 c0d11a145a455d73f9bc718295c41611ff55a777a38119a84f47d4b0eaea6df3
MD5 d6f42b73fb63f804f8da460f437a75fb
BLAKE2b-256 357077f31fc6f0a935b61eca735fc11f188ed9d5cd70bbc178b17d50a86ebfac

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 5bcf791ed67570cc1a268da45710796c891819b3e96c14bc3d1a81f388c6e0ee
MD5 99f2791e6f56cade28ea8ccc58e2f0fb
BLAKE2b-256 b4f616981b49f2267e1f39922379125d44134d9326b92f1c044232856a9e1a50

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-win32.whl
Algorithm Hash digest
SHA256 d09f6f0ba17dff5cff7024a29cbb74d8239f3c6692aa706a712cf47f65b39d24
MD5 e10f67b133f020e832c29de915060707
BLAKE2b-256 e1c0d84f8bcaff6831905e54eba0a0cd9b316c0393d453a8a50b81d7937a0f5a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 1d0fef232f918fa93b1b8b64e9c06831cfbe00aef5289c3d4792f219a0f2947a
MD5 89e1a6ae37f8cd52b0cf599b873d8ec9
BLAKE2b-256 139b45714783635d0b13caf2775d2a7a71f05874077ae08c4cbd3aba56e015c6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 88817ba207dc28412ed3e521d0fc4925e86e240f3dc34c5fff62808b01936f1c
MD5 ba41a5dd090cc56f3c0aa6725190dcd6
BLAKE2b-256 f8a15102428c3285d30d8ae647168450749be3ff0309ac34ae71c8eb72ebb420

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 5b14cca3091fb50f56710b3cc5f95830f6f64a44d72739b3dabff2052722dd45
MD5 eb21b2058eb2d1f30492db20a1ced75f
BLAKE2b-256 c8c2df732da9f8cafebfb58db0d9167211c09143f3858d259d1d7ecb4d66f87b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 0f2c706cb6cd522d406874688aaef964eb60e8b24ab027bd7c21fa129f6308a6
MD5 8d20ab2fc96d52ace414abd20aed14c8
BLAKE2b-256 f4c0d9bc41fab3b1261352a80bc8f9ef189c246817bcc66af17b6a6fca27c7fc

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 07db5994130efc77b93ff44982f37b8cd1bffaa6d51033b0d7d37ceb211446d2
MD5 d873153a4c2242e48c8c115196ff568e
BLAKE2b-256 60a6af547d8b2695f93f08b324a9dde6e9bed07a1bbf7f9123427dfc48458a08

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 97062003478a73c5263b1c91cc28a2147469fccf3c9d8c042e4394b8af261446
MD5 1334dc0c8a6facccd8c8997ee95163f5
BLAKE2b-256 07c2b5951bd07abe255f5e3018b52ccf3a31d166e6c91934fba6d7210b9efa3c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 5d01f2bc4e0ee2d1c444ece06b18016f00e16f7b50491fe81984fa9ac584caa5
MD5 4d5da896c3df1da06618b0030ccc90ac
BLAKE2b-256 f2c8fd7101beb8268d231afe3beb20038b17543ab7ea2a59f56eded1782e420f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 cf83c6c1eabed2704cfb884c8f07ddaebd8d7cddcfef6a4bf76c1a6cad381b2f
MD5 2575b47e87eabf0e86200cb19f9ca10a
BLAKE2b-256 417034af64c767656c23b8d0efdd5a783124f3b1067ff57992640f38f439e109

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 5cff924b1ff38cacd05bb9426675dbbd4ce9c12354978fb33922e316a5be4f8c
MD5 a4fbe1570b4a51702e419c6960b0b022
BLAKE2b-256 20e3ec0e5332975a213ef3456acd18d86de076d86026043b7aa3ccba23cec33d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 83a7545b65c8ebc4182d4a6e494995affd4a43871e7cc89d951aa56854a576fb
MD5 070f12e6328e68ca7abd5353067868a8
BLAKE2b-256 33cacb61f293a919fa04bb1b7a2672ea35c69df273fe5aa66410646c50bfc948

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 78b16030d3c554860ec1738844bc8f06a278c76669957287e42195fe0fd4cfb1
MD5 9748f79f1cb7e970fa1358fb3b4dd15a
BLAKE2b-256 0f316e3734d402a17077d91c9ff0bebba6168ac98a71baa06c555521e38cc938

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 5566c46fb89c2885a5e9abaaf94f2e3b632c2b7f30824ed2f4d3a31615b39bfa
MD5 f5191180a37e409dec5f5ae49e7ece7c
BLAKE2b-256 07bb272843655659a0604e32727fdd3d490a11206d7d0ef50f3f0dc6b582ce74

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp312-cp312-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 78210bd526350f305de03de297a96eb9caa52cd6559257e15d0940818f849838
MD5 27d4e88ad4763270f145fd16b5903258
BLAKE2b-256 add31ce995ec1efd59904c4787e0fbc3ef18837459b82a32ee4a6c07a10edff6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-win_arm64.whl
Algorithm Hash digest
SHA256 b7e19783ddd4ac94caaabc1fd9cbf32d8dc7d3ea583137972e4099e1b6dab781
MD5 5b8c0764967045750f24b4fd28631c09
BLAKE2b-256 0366ae16b3b7ec0f43d6b4e64175c0438c7ef8f11270c6429c23628aec5b4a49

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 d4166f71983cdce3817e583961e924572dac61aa45c6e5786f5f6c28d253186c
MD5 46e87477d1f1b0c9e6eeecdb59062e78
BLAKE2b-256 004fad47e0edbb44ba7a4c7e6ba85abe2fb4b03ce091fe85035ea5aad38a3407

See more details on using hashes here.

File details

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

File metadata

  • Download URL: stringzilla-4.6.0-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.7

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-win32.whl
Algorithm Hash digest
SHA256 00fafdc6507bcf18731770f0f1d6ed3afdd9a6ee53af99222d20f27544eb844b
MD5 fd21e975fe1685e08ebee1ef1364a244
BLAKE2b-256 be41eaa8abaa457496677b99ac4bc64e54968826cd06569406968f2d1a8535f9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 2c61ab6e2a1d9f228dcad2a166ad17486f2bad5338e6fd34a4636d9871a82d33
MD5 9056d3f674a81ff9b03ff431ff539148
BLAKE2b-256 21e64b6d7f29977ae51d56b82b6c67f4081c2910d954fe135be09f1c51c8e34f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 66fc74ecaea4097bc08ec24c9418b37fec0e32ce4948503be6fd184ea02a55fd
MD5 317b8ea2447d16f648d88eb741dcc08c
BLAKE2b-256 de972990f2f9b28c4e3e25dd484f637addede84e6f882fda9278f85f8344bed9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 3822017dbe14bcc70225577fc7a16049e1f275b779ec880554db11326110b91f
MD5 a523172383b068e5ec0e4d8b966885bd
BLAKE2b-256 4f34abb821650413a89cf0753d81898a68e8de1992cee0bc3f60a260af0b1686

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 74da0d3faba7be62531802ed2d5dfe619089e74fa9440854cd20f524b3727515
MD5 02b7ed57440a84af4ad0ad742fd31b3c
BLAKE2b-256 3f05991d4e9919e877056eec55d2a136084a333060c765ebc44696065077f9d8

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 d6e8c49ebc87ef2ba5857bd06f4b97cf73327f1f5e4029e98cec153e64a1243b
MD5 c3b133375a88b0310870a89b2511a2e4
BLAKE2b-256 4b80707866bb96f868da7bd051e783df8f7452a9f0a9a04939d9f45f019bc601

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 7d638ba025509c6272982fcd48b3d321281d6060a7d1b95e88f17e07e8bda18d
MD5 a5a8db692ee6d68ceea317780de02fe5
BLAKE2b-256 7905a005f7a2fbc317954ee898a63bf5f1d6b6b437f64042cc8d426f70f68d8d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 96823a3ba0517391e2206c9ffa7587830dbba23daa9d8dd3016b29c4bce03f96
MD5 6bacdd1040d10c0115e50385eff11907
BLAKE2b-256 e80b059ddc45f59c3ee02abd73ff93e22cead10de9b877536a779acab4912283

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 e5ad64a6141f6798d48debfbb3cc28256e0e73ae2aa106d912632db592963933
MD5 af5e43341c63e8a389823d6132731b65
BLAKE2b-256 cd7973c4cc2b09d0890b2bf1da99ee9c17cd13fcd59355aea5df63ec6520f8bf

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 a12559b54e4defa6f1b82746246fe8bbf6b6dd0456cd3e7b12b5b83fea1710b4
MD5 f09788b020553391c538e2dab489b710
BLAKE2b-256 bf6821eaff1a3506f26a9126527866a2738642d083b3b37bf8db0246958bb973

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 59fa412f2066041af6d7df37acb067ebecf230333c6314234baea1b0d29de66c
MD5 e066abfa2062cd1e1e50a45cdf3426b9
BLAKE2b-256 246c58a93deb8faff85fcba679b3a44354ad7ecffdbc41227bf3c2e7e07b24b0

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 5b6062044078e68769b758c6b54e10632ebe1505c5b562edf2b2736a91c49589
MD5 eafe4764baa1fb6b21ed860ec621c5d4
BLAKE2b-256 ab984d165a12fd2a39d6cc793a89f7418d352c49eded4e1f12fea16b287fb0fe

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1249a9144767ce8ec8a6e9fcd42b26085671667e7421cf69cf476da4c4808671
MD5 b31bc4bb88514c3b2233d6e14c06cfc7
BLAKE2b-256 b932174ddab3558e4747cb4a78a2fc1515b5d661869e61161f6a9c5c1261ac56

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp311-cp311-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 f08aa1d161dd2d5f80c1597163a9e5b9206f8ecbadc7608406c7866ba992622c
MD5 00a708db8ac318169e2e8f3bb488d706
BLAKE2b-256 406ade549cb11dd8cb55cb6879864284f2b7375cbf53233588033481b30f9ee8

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-win_arm64.whl
Algorithm Hash digest
SHA256 5ded9fd6bf5f329dbcc13e7c8bbeb89498caf2c3fe285559c0dfa655af7ba390
MD5 8fade8ac1f927584f881a04fa26aa7cf
BLAKE2b-256 a2ece2452049a010191e9c746e0f84345e0e04c8c94f981a9ffd52b9efaca2be

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 f89fa545abf49a8513565b428c7cc98b7082b3fa4ba328cb93665f0b7f65a41d
MD5 4f249f3ac7992266a8844be2eb796c21
BLAKE2b-256 f4997461242a6e38abaceaeac054c0344d5da1efa759322d97fcf6bb32a37d67

See more details on using hashes here.

File details

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

File metadata

  • Download URL: stringzilla-4.6.0-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.7

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-win32.whl
Algorithm Hash digest
SHA256 731dbf77074989f98117e37eee6700806fc45e68b5175dba8a8c6c9470164b35
MD5 6f87f324ef5d1b10a09a17c05e953569
BLAKE2b-256 4edbf40b96eb33faaafc27ee1f62e2cef906c566d82ac809590124968ac00a99

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 e28b066aea2b0ca413fcfd2210519ef61c599663a86bdb9b2921ff50e64a7d8f
MD5 46272a39a64890e5f8b2303bc2dd4e9f
BLAKE2b-256 77481976434ae5a9aead97a3a942276227daa83a7300ecbb9f05dfe692703e1a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 8453cc958688b613c4d6dd1db002828937b36e8a93fd89a16671067e3e5e4933
MD5 daf43f67c1b993b03bd1a8b6bd0a5ef9
BLAKE2b-256 800c3daa2af6fd2b511aa4e0d9ebf5465a8d20ccc0e88e19ea34257a0bda103f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 228f0cd33aab421e53956dc3b4b95ae7c573f077fa8b9cd8d2176a9f85e0ff09
MD5 d1aff08d51b615657d6a3743d38fe854
BLAKE2b-256 5aa2361e23326e98cc8a5e3164668594bf98cd989fb35d997eb27efff989184d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 e4e16980a589f0fc1bb2c1e09513484ba0283f53d4a243cfb440ec40c571051e
MD5 b7b934914c811b73bfeca656fac9a488
BLAKE2b-256 83f84c2dc3e4779c513b28fd76988e36161ce21846e9aa07dcfc82b48c5ee911

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 ac2c52a53e6959901e4b958f7d9b70a4d919ca3c5d5a84333788ae4b469222d6
MD5 f47faca5d5a604c6ca6294e84e4952ff
BLAKE2b-256 14346a5ec8aa9e5afec08534432d4739c812f46a892912cbbbf43eee8cbcf92c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 776937a9325bb9e479b2965257d108bbcaf3216ffd8a1e4b6336e474ca9efaa3
MD5 5f9baf93afc4031a265bbd0fb311d3de
BLAKE2b-256 c87c1a3eea470080bd0b497017f9811a703d50a35ade5c2f2116377289338bf6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 a38bf7c96dbc07dfc5c40f2515fb1f3d32688557731cc5e5a0d1310db559c38f
MD5 9eb92166c241c9cd5e222c444a478d8d
BLAKE2b-256 f46e678528037ceecedf990828dfb3bee130d57a4c79ad4da6cc231ddb36afb3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 e752a1b185a3f1d1a3f24e1f372cc10ce7151d0a3ab72f447dd5e478052e3651
MD5 cf74b6c8b2b782149baa6c38485c1200
BLAKE2b-256 fcc608c51a4a147b0b97d207574d245a4649f5f055ca81e0e5bf287e1ecb7e6b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 4a9746cfa1845be2ea7a176ae1cefa326e67ba3e3e7c2db74f61474f922271ea
MD5 fe57d5302ca4a4bcd68ed3a1367808b7
BLAKE2b-256 3ae5ad292714483d46a08c7591042e5f52b7d26d1177e31f19e2dada49a5b534

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 f1fe624a8f065e9905ce2502cde2ee3128eaa9118fa972c7d99b2879eb006f38
MD5 732426e10cb20808e60b4bb37ba94cdc
BLAKE2b-256 3ad1f446e9835f70750d072de538243d95241bd93ee4b019a318ee4bc4572f91

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 8e4e4ab037ab98d2b0af40840723b8d176c231f20ab1dceaee429eae17a3c173
MD5 45d7ee35ed18744f51ef0540f504dc35
BLAKE2b-256 56cf2d79973a9eca47833d58de7f546c7331a2beba42e77003051cf9eb08a81a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c6afded807dc1b668c124307d31f076de494020ec1b26d84d2291c963a433deb
MD5 bf7951e12e7f5768e3ed80d06ee8dce3
BLAKE2b-256 bf1ebf4bfb53024cc4411788e513f1a36ec8c4fa5c4c26435a9c3e3c7c9d0b58

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp310-cp310-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 c27e0e487448460d27777459c54ff20e88269e8d5c2c59609d08ead7e846ca14
MD5 12dae5194b2a7dce0a76dbd7f5372aea
BLAKE2b-256 5ef88fe356c16ff4b4bc3e604433c311c1a20cfd18aaa630a8671cac00ffbd7d

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-win_arm64.whl.

File metadata

  • Download URL: stringzilla-4.6.0-cp39-cp39-win_arm64.whl
  • Upload date:
  • Size: 123.1 kB
  • Tags: CPython 3.9, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-win_arm64.whl
Algorithm Hash digest
SHA256 d4d5aabccad3baacf2a3d6b608e0ff1d29546ec2dba2b7d9344398c4f851ad5f
MD5 8e5e91de6e30ee6e53e6af092ce5b506
BLAKE2b-256 c67762a1300111af1562709421ccedaf306e624aebf320135b0e0875bf8814bd

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: stringzilla-4.6.0-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 162.4 kB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 0a290a511bf98ba8ecfe9897947c52b06859385ea7deeb06247fd57dc28fc270
MD5 fe6a4e85791b7da301359a23a344bbc7
BLAKE2b-256 24c2f2b061c17bf9cc2a5feb6a64a4071e42fcc3823186534f1634cfd128fb66

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-win32.whl.

File metadata

  • Download URL: stringzilla-4.6.0-cp39-cp39-win32.whl
  • Upload date:
  • Size: 114.5 kB
  • Tags: CPython 3.9, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-win32.whl
Algorithm Hash digest
SHA256 90d14cb943023f01fd51d6c094baeb21d07af0756b03f4cf0ca8911fdf5df474
MD5 064f4566025948d90b26e5ca8ad0de3a
BLAKE2b-256 b3b5e4220982763f6383acdaf168d9f532354830edbdcbbe417076be685c112a

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9b6fef338ca9e4df1609aab65d959945f3b2d28ba06987623b18751f3ef28724
MD5 10c466a2283ab677f7dc27321cfbcd89
BLAKE2b-256 c68581987eb84b9be4e11d8685772b6f3803d22961317488140c587b7143b983

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-musllinux_1_2_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 a35ebcbe2e4b76914c104935a8ee1d02869dddbf35605affb0da5580160c266e
MD5 8abd0dbd6a33a553f72614e84d1288b0
BLAKE2b-256 9f3a797feed6ff7d7821741ae2880ac8fe32c317f210fe513423057c55cc1f90

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 780263a75b103a680dda706f21c8a5a2b9b18f7a0a91cdfccde5e13246d6745f
MD5 1ef36abf3c4298f24bba8706b2bf7984
BLAKE2b-256 4ddc5cad076b814f0ee785aa50d2b17a68edc8b89535147f9869a37941eded67

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 e48fc037bee77e0a981b99ff355605f1a126d72ae99a16e0649aa2b52328946b
MD5 5471019c6949684da6bba1de0e09d309
BLAKE2b-256 4ff96745c2cb7eaeef8c43a64827532c113bca35781f6719e7d3b88caee11719

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 46fbf27ed0a51488683af31120138cbe734531f55dcf5c8c02101f5b960053e7
MD5 dde735c4e379477d482e2307c87a1e84
BLAKE2b-256 2fc8a9b2acac5ebb7fdb354246eb2b6e32be35839cab5b2fd75f260fbc4dcddd

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 fad4080bf45e2806077ff85fc119488a70ec83c7a3ae0c8963bc8386042dbd9a
MD5 21f3e9ce9181a33aea0776ea2b40fc7a
BLAKE2b-256 43f60f35e3dcb0f28133cb516727385e7c62100a45237d950aaebb9e6a65e162

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6b6abb5d9e7fdf0d745e8639556cf58aefb3c1f23d3de2c51f141093077ce697
MD5 94b7ec4d69fdf541167b1449c3fea995
BLAKE2b-256 81d420e2a8820757d1e6ed1f23d1d9c03441ebddf166339e990f1fb73cd1ebe8

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 e7da55dcfab6a942a730543d2d7b29c38204e7a9c5728f5003ef563150877a6f
MD5 92066d0acce02d2e07d24b7aa01b18f0
BLAKE2b-256 d87348e989994c8f2982e40a6dd5521c7bdcd2556ba4aadbbc62db1dba84d244

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 bac446ea1808f9d22bd8b83f461742ef402ebeab6912e29ed3c85f111c9c6c3e
MD5 725dcb91d59d4a177e191ee688fc9dfd
BLAKE2b-256 b176a4ec87fcb007f839569c30070921617d8c1d747263e077d3ca92c39c2f25

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 67abd6841b8f3ad3bac563ba96473d30a26dba10095c9b20eab4a2586821413b
MD5 11e1841afe5775ee5c175497417a5740
BLAKE2b-256 730afc97887dba1205699d4a86e01201cbc9fad20e80bfe08d66e00567d3c33e

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 0952a4b32edae08b97e4311fce1ce6057bc8c3f8e460408b3e87af16c7e338af
MD5 0210cfced5fe92746d7bafbac5c92645
BLAKE2b-256 e92a671aa15a206468a2be33048960ec0ac7ad5b52f5946d97880f193b8fd5c3

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 227d960e5538208e9408f3ef0e546b05a109eb1e684f010468697293ea6ef862
MD5 b2cb668ad13c5e0e01d5ef49fdcfbb2b
BLAKE2b-256 823bb5e7f010af682fd6c0e2f2500419a4b6813f14a25ac9efe439d33ad2f8ff

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp39-cp39-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp39-cp39-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 0823cc96983119d7370655e3349a02e389b197244d380aac3a0711f5c461000f
MD5 90b06bf353372dccc07d1fd2cd0af782
BLAKE2b-256 c39b89e999d2f7aa830bf850385c577db5163a5a7290c4f951802a2ece8c1b9d

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-win_amd64.whl.

File metadata

  • Download URL: stringzilla-4.6.0-cp38-cp38-win_amd64.whl
  • Upload date:
  • Size: 162.3 kB
  • Tags: CPython 3.8, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 d679ba9246f8ce03c96745efd6d85f73a9b6cfbd72fef60347919eac1fb44512
MD5 b836744ffc935af3358d347dd95812a2
BLAKE2b-256 942a8410c8668e463d74a3df8c71ec348e3593b5f3c608ed319c4e4d588961ea

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-win32.whl.

File metadata

  • Download URL: stringzilla-4.6.0-cp38-cp38-win32.whl
  • Upload date:
  • Size: 114.4 kB
  • Tags: CPython 3.8, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-win32.whl
Algorithm Hash digest
SHA256 c951262011f5bf8811fea92673df21acffab89b148e230d012150873565ccaff
MD5 6466fd574c67ab8daf12511abcaafde5
BLAKE2b-256 0dd074aaf12ad1c5b139208a0b0baf3f288cc6ba24baeb552c8d4636957d93cc

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 2b5be407d01a21bf290ebac6f2f6b8c963ca8d01805f7fe81cf3b1311f06c9c2
MD5 ddddde3e17eacff49077006ca991ec33
BLAKE2b-256 e8ba8a74b6b38822daef1469bbaff32fd00562227b6247d2825db4c65865207d

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-musllinux_1_2_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 b8242dd4bf2d03826127f42b0f9ec9fa734cf5ac921a81bbab241902d08a7bdd
MD5 35d2f439ee2e6517bb3ea14fa502c044
BLAKE2b-256 2e510f87f767470aac5d8c7a1c1f9fe7f676e3da641cbd093abda2edaacdb7d6

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-musllinux_1_2_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 b23722b98dae8501d970292426aa153077990ca56bef42afa3b780cc1733701a
MD5 ae39f4b9662f72a1091b21fa53bde71b
BLAKE2b-256 ace847e6559cc57ecbb871c7d83f358b90f35b24909cea65897a2efcc505a9ad

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 123dbd22427e058decec7d39d694e15940cb3e611bdbef7096463b91b70b75b7
MD5 273e94088ab4d9981fcbd6f6b053c44c
BLAKE2b-256 ea9aec413bf26a13f6789eb78b77d9ee35dbc73d242a1d6d2b6684788cca7e0a

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 c9fc6f523e0de0356ef728340437eb696b19ce06ab6a5e4babcc29ee46ed6b69
MD5 7769305cff52515364abad509f58b604
BLAKE2b-256 ebe11fadaf6ce4fa79d36a7beba763b88c56585a3579946c24abfbebb9c937b3

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 9720d10a316628b55c91cde303fae270bbfff55656157e1e90c4a963eff299d1
MD5 e3d850e481b4e556e3fc9df952d88d15
BLAKE2b-256 71c7ab78015545bbc25fa999f5e88d166735ee90f7de5cc949c4ef38290a0e13

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 4bb7b05b3cd7bc68ecec26ceb8009ce079c58dc2eaabcfaaa2c80a5cf4d8ecae
MD5 cd5effff5d075875d0172a655426d5b0
BLAKE2b-256 90a43453e265e2d9fd305f8256efcf6206e16c395216cbb9e9e66d474dce8318

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 c9a37be02460dd07eebe8fa62e60a79f42de4220ce2c64519fb1b88f3a20caab
MD5 fbc9b65b31bca306a6e7ffa2b1cb1f0a
BLAKE2b-256 3e6587a3a3bcc3adc213156bfe768d312eff68185aae21a561a2556003c9c774

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 820236cb6981e7ca7f7d084aff42fc2c506e8ac777117f1b978fe4e15d8fc088
MD5 89d937110698abc7e776435240b0206c
BLAKE2b-256 9d867a286c3f7a4500ac3d8b7429d3a8bf2779faa91e6ea591e35c71b26d5c35

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 d0ba68f51cf42fffb7ff9ebda07c83700a12385c2ae1210e35836cac3ad4a149
MD5 2da3ceed26313f6e47e9c53b69c8792d
BLAKE2b-256 08fb50155368b4a035145ed891c2daf11417b6aa47c6f81a9755ce6c551be2f7

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 d030ca5972bca40c56703831ba33936947306a3c5afba6ce5b1e07a67b9ca407
MD5 156b9ca34f400f9da2cb5e2f21608e44
BLAKE2b-256 8e210b1272afa5b635d5ed1a609e299efa197945dc1f09e8e381a4b1d30211ce

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6f25cb03caadbcb6762472b92014d80257d66691b8bce44d41259afda6046f1f
MD5 e799ed89470b4f13279eb1b25b451879
BLAKE2b-256 9e3ec08958bf99f17b7275628429c00843a561702aac9e5f53901d120975ebea

See more details on using hashes here.

File details

Details for the file stringzilla-4.6.0-cp38-cp38-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-4.6.0-cp38-cp38-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 27b0e4414ea7de33b296a9c55753493cbb33fb76e5998c41f11dff9def07e04c
MD5 0e896b0d1fcefe77d6fa47acf27c91ce
BLAKE2b-256 d38f4e6fca02783069a95c0be4123f614ff7e2daa42fad8b54ef8ad1ccb01a1f

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