Skip to main content

SIMD-accelerated string search, sort, hashes, fingerprints, & edit distances

Project description

StringZilla 🦖

StringZilla banner

The world wastes a minimum of $100M annually due to inefficient string operations. A typical codebase processes strings character by character, resulting in too many branches and data-dependencies, neglecting 90% of modern CPU's potential. LibC is different. It attempts to leverage SIMD instructions to boost some operations, and is often used by higher-level languages, runtimes, and databases. But it isn't perfect. 1️⃣ First, even on common hardware, including over a billion 64-bit ARM CPUs, common functions like strstr and memmem only achieve 1/3 of the CPU's throughput. 2️⃣ Second, SIMD coverage is inconsistent: acceleration in forward scans does not guarantee speed in the reverse-order search. 3️⃣ At last, most high-level languages can't always use LibC, as the strings are often not NULL-terminated or may contain the Unicode "Zero" character in the middle of the string. That's why StringZilla was created. To provide predictably high performance, portable to any modern platform, operating system, and programming language.

StringZilla Python installs StringZilla Rust installs GitHub Actions Workflow Status GitHub Actions Workflow Status GitHub Actions Workflow Status GitHub Actions Workflow Status StringZilla code size

StringZilla is the GodZilla of string libraries, using SIMD and SWAR to accelerate string operations on modern CPUs. It is up to 10x faster than the default and even other SIMD-accelerated string libraries in C, C++, Python, and other languages, while covering broad functionality. It accelerates exact and fuzzy string matching, edit distance computations, sorting, lazily-evaluated ranges to avoid memory allocations, and even random-string generators.

  • 🐂 C : Upgrade LibC's <string.h> to <stringzilla.h> in C 99
  • 🐉 C++: Upgrade STL's <string> to <stringzilla.hpp> in C++ 11
  • 🐍 Python: Upgrade your str to faster Str
  • 🍎 Swift: Use the String+StringZilla extension
  • 🦀 Rust: Use the StringZilla traits crate
  • 🐚 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 setup 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 strings-processing functionality.
  • For students studying SIMD/SWAR applications to non-data-parallel operations.

Performance

C C++ Python StringZilla
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_charset
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_charset
x86: 0.43 · arm: 0.23 GB/s
Random string from a given alphabet, 20 bytes long 5
rand() % n
x86: 18.0 · arm: 9.4 MB/s
uniform_int_distribution
x86: 47.2 · arm: 20.4 MB/s
join(random.choices(...))
x86: 13.3 · arm: 5.9 MB/s
sz_generate
x86: 56.2 · arm: 25.8 MB/s
Get sorted order, ≅ 8 million English words 6
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_sort
x86: 1.91 · arm: 2.37 s
Levenshtein edit distance, ≅ 5 bytes long
via jellyfish 3
x86: 1,550 · arm: 2,220 ns
sz_edit_distance
x86: 99 · arm: 180 ns
Needleman-Wunsch alignment scores, ≅ 10 K aminoacids long
via biopython 4
x86: 257 · arm: 367 ms
sz_alignment_score
x86: 73 · arm: 177 ms

StringZilla has a lot of functionality, most of which is covered by benchmarks across C, C++, Python and other languages. You can find those in the ./scripts directory, with usage notes listed in the CONTRIBUTING.md file. Notably, if the CPU supports misaligned loads, even the 64-bit SWAR backends are faster than either standard library.

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 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 withing x86 CPUs will be larger. 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 Most Python libraries for strings are also implemented in C. 4 Unlike the rest of BioPython, the alignment score computation is implemented in C. 5 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. 6 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. Current StringZilla solution can be at least 4x faster without loss of generality.

Functionality

StringZilla is compatible with most modern CPUs, and provides a broad range of functionality.

  • works on both Little-Endian and Big-Endian architectures.
  • works on 32-bit and 64-bit hardware architectures.
  • compatible with ASCII and UTF-8 encoding.

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

Maturity C 99 C++ 11 Python Swift Rust
Substring Search 🌳
Character Set Search 🌳
Edit Distances 🧐
Small String Class 🧐
Sorting & Sequence Operations 🚧
Lazy Ranges, Compressed Arrays 🧐
Hashes & 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, and can be installed with pip. You can immediately check the installed version and the used hardware capabilities with following commands:

pip install stringzilla
python -c "import stringzilla; print(stringzilla.__version__)"
python -c "import stringzilla; print(stringzilla.__capabilities__)"

Basic Usage

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

from stringzilla import Str, File

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

The File class memory-maps a file from persistent memory 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 sizeable 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 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-bytes-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_charset(separator='chars', maxsplit=sys.maxsize, keepseparator=False)
x: Strs = text.rsplit_charset(separator='chars', maxsplit=sys.maxsize, keepseparator=False)

Collection-Level Operations

Once split into a Strs object, you can sort, shuffle, and reorganize the slices, with minimum 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.shuffle(seed=42) # or shuffle all lines in place and shard with slices
# WIP: lines.sort() # explodes to 16 bytes per line overhead for any length text
# WIP: sorted_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_charset_iter(separator='chars', keepseparator=False)
x: SplitIterator[Str] = text.rsplit_charset_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)

Edit Distances

assert sz.edit_distance("apple", "aple") == 1 # skip one ASCII character
assert sz.edit_distance("αβγδ", "αγδ") == 2 # skip two bytes forming one rune
assert sz.edit_distance_unicode("αβγδ", "αγδ") == 1 # one unicode rune

Several Python libraries provide edit distance computation. Most of them are implemented in C, but are not always as fast as StringZilla. Taking a 1'000 long proteins around 10'000 characters long, computing just a 100 distances:

Moreover, you can pass custom substitution matrices to compute the Needleman-Wunsch alignment scores. That task is very common in bioinformatics and computational biology. It's natively supported in BioPython, and its BLOSUM matrices can be converted to StringZilla's format. Alternatively, you can construct an arbitrary 256 by 256 cost matrix using NumPy. Depending on arguments, the result may be equal to the negative Levenshtein distance.

import numpy as np
import stringzilla as sz

costs = np.zeros((256, 256), dtype=np.int8)
costs.fill(-1)
np.fill_diagonal(costs, 0)

assert sz.alignment_score("first", "second", substitution_matrix=costs, gap_score=-1) == -sz.edit_distance(a, b)

Using the same proteins as for Levenshtein distance benchmarks:

§ 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 for of tri-peptides (made of 3 aminoacids)
glutathione = "ECG" # Need to rebuild human tissue?
thyrotropin_releasing_hormone = "QHP" # Or to regulate your metabolism?

assert sz.alignment_score(
    glutathione,
    thyrotropin_releasing_hormone, 
    substitution_matrix=subs_reconstructed, 
    gap_score=1) == aligner.score(glutathione, thyrotropin_releasing_hormone) # Equal to 6

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 Str

original = "hello"
view = Str(native)
arrow = foreign_buffer(view.address, view.nbytes, view)

That means you can convert Str to pyarrow.Buffer and Strs to pyarrow.Array without extra copies.

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

Or using a pure CMake approach:

FetchContent_Declare(stringzilla GIT_REPOSITORY https://github.com/ashvardanian/stringzilla.git)
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_avx512 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
sz_size_t substring_position = sz_find(haystack.start, haystack.length, needle.start, needle.length);
sz_size_t substring_position = sz_find_avx512(haystack.start, haystack.length, needle.start, needle.length);
sz_size_t substring_position = sz_find_neon(haystack.start, haystack.length, needle.start, needle.length);

// Hash strings
sz_u64_t hash = sz_hash(haystack.start, haystack.length);

// Perform collection level operations
sz_sequence_t array = {your_order, your_count, your_get_start, your_get_length, your_handle};
sz_sort(&array, &your_config);
§ 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_charset maps to strspn and strcspn, while sz_rfind_charset 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, needles) sz_rfind_charset(haystack, haystack_length, needles_bitset)
strspn(haystack, needles) sz_find_charset(haystack, haystack_length, needles_bitset)
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""_sz;
using std::literals::operator""sv;

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

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 it's SSO buffer size with a simple Gist.

libstdc++ in GCC 13 libc++ in Clang 17 StringZilla
sizeof(std::string) 32 24 32
Small String 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?

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"_sz[{-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(char_set(":;")); // Character-set argument
auto [before, match, after] = haystack.partition(" : "); // String argument
auto [before, match, after] = haystack.rpartition(sz::whitespaces); // 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(char_set(" \w\t")) == npos;
text.contains(sz::whitespaces); // == text.find(char_set(sz::whitespaces)) != 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).rstrip(sz::newlines); // like Python
text.front(sz::whitespaces); // all leading whitespaces
text.back(sz::digits); // 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(char_set(" \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(char_set(""))
  • haystack.[r]split(needle)
  • haystack.[r]split(char_set(""))

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_generate 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.randomize("ACGT"); // `noexcept` pre-allocated version
dna.randomize(&std::rand, "ACGT"); // pass any generator, like `std::mt19937`

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

Levenshtein Edit Distance and Alignment Scores

Levenshtein and Hamming edit distance are provided for both byte-strings and UTF-8 strings. The latter will output the distance in Unicode code points, not bytes. Needleman-Wunsch alignment scores are only defined for byte-strings.

// Count number of substitutions in same length strings
sz::hamming_distance(first, second[, upper_bound]) -> std::size_t;
sz::hamming_distance_utf8(first, second[, upper_bound]) -> std::size_t;

// Count number of insertions, deletions and substitutions
sz::edit_distance(first, second[, upper_bound[, allocator]]) -> std::size_t;
sz::edit_distance_utf8(first, second[, upper_bound[, allocator]]) -> std::size_t;

// Substitution-parametrized Needleman-Wunsch global alignment score
std::int8_t costs[256][256]; // Substitution costs matrix
sz::alignment_score(first, second, costs[, gap_score[, allocator]) -> std::ptrdiff_t;

Sorting in C and C++

LibC provides qsort and STL provides std::sort. Both have their quarks. 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_sort, or the high-level sz::sorted_order, 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::sorted_order(data); //< Simple shortcut

// Or, taking care of memory allocation:
sz::sorted_order(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::string_view_less> sorted_words;
std::unordered_map<std::string, int, sz::string_view_hash, sz::string_view_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_X86_AVX512, SZ_USE_X86_AVX2, SZ_USE_ARM_NEON:

One can explicitly disable certain families of SIMD instructions for compatibility purposes. Default values are inferred at compile time.

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:

By default, StringZilla avoids misaligned loads. If supported, it replaces many byte-level operations with word-level ones. Going from char-like types to uint64_t-like ones can significantly accelerate the serial (SWAR) backend. So consider enabling it if you are building for some embedded device.

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 it's symbols over the ones from the LibC and accelerate existing string-heavy applications without recompiling them.

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. To use the latest crate release in your project, add the following to your Cargo.toml:

[dependencies]
stringzilla = ">=3"

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 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_char_from("Hello, world!", "world") // 2
sz::rfind_char_from("Hello, world!", "world") // 11

Unlike memchr, the throughput of stringzilla is high in both normal and reverse-order searches. 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_char_from("world"), Some(2));
assert_eq!(my_string.sz_rfind_char_from("world"), Some(11));
assert_eq!(my_string.sz_find_char_not_from("world"), Some(0));
assert_eq!(my_string.sz_rfind_char_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));

The library also exposes Levenshtein and Hamming edit-distances for byte-arrays and UTF-8 strings, as well as Needleman-Wunch alignment scores.

use stringzilla::sz;

// Handling arbitrary byte arrays:
sz::edit_distance("Hello, world!", "Hello, world?"); // 1
sz::hamming_distance("Hello, world!", "Hello, world?"); // 1
sz::alignment_score("Hello, world!", "Hello, world?", sz::unary_substitution_costs(), -1); // -1

// Handling UTF-8 strings:
sz::hamming_distance_utf8("αβγδ", "αγγδ") // 1
sz::edit_distance_utf8("façade", "facade") // 1

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. 👋"
s.editDistance(from: "Hello, world!")! // 29

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.

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 algorithms are randomized to look at different parts of the needle.

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. The snippet below shows how StringZilla accomplishes that for needles of length two.

https://github.com/ashvardanian/StringZilla/blob/266c01710dddf71fc44800f36c2f992ca9735f87/include/stringzilla/stringzilla.h#L1585-L1637

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.

https://github.com/ashvardanian/StringZilla/blob/46e957cd4f9ecd4945318dd3c48783dd11323f37/include/stringzilla/stringzilla.h#L1774-L1825

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.

https://github.com/ashvardanian/StringZilla/blob/46e957cd4f9ecd4945318dd3c48783dd11323f37/include/stringzilla/stringzilla.h#L1398-L1431

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.

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 introduces a different approach, extensively used in Unum's internal combinatorial optimization libraries. The approach 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. This results in much better vectorization for intra-core parallelism and potentially multi-core evaluation of a single request.

Next design goals:

  • Generalize fast traversals to rectangular matrices.
  • Port x86 AVX-512 solution to Arm NEON.

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

Needleman-Wunsch Alignment Score 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.

StringZilla adapts the fairly efficient two-row Wagner-Fisher algorithm as a baseline serial implementation of the Needleman-Wunsch score. It supports arbitrary alphabets up to 256 characters, and can be used with either BLOSUM, PAM, or other substitution matrices. It also uses SIMD for hardware acceleration of the substitution lookups. This however, does not yet break the data-dependency for insertion costs, where 80% of the time is wasted. With that solved, the SIMD implementation will become 5x faster than the serial one.

Random Generation

Generating random strings from different alphabets is a very common operation. StringZilla accepts an arbitrary Pseudorandom Number Generator to produce noise, and an array of characters to sample from. Sampling is optimized to avoid integer division, a costly operation on modern CPUs. For that a 768-byte long lookup table is used to perform 2 lookups, 1 multiplication, 2 shifts, and 2 accumulations.

https://github.com/ashvardanian/StringZilla/blob/266c01710dddf71fc44800f36c2f992ca9735f87/include/stringzilla/stringzilla.h#L2490-L2533

Sorting

For lexicographic sorting of strings, StringZilla uses a "hybrid-hybrid" approach with $O(n * log(n))$ and.

  1. Radix sort for first bytes exported into a continuous buffer for locality.
  2. IntroSort on partially ordered chunks to balance efficiency and worst-case performance.
    1. IntroSort begins with a QuickSort.
    2. If the recursion depth exceeds a certain threshold, it switches to a HeapSort.

Next design goals:

  • Generalize to arrays with over 4 billion entries.
  • Algorithmic improvements may yield another 3x performance gain.
  • SIMD-acceleration for the Radix slice.

Hashing

[!WARNING] Hash functions are not cryptographically safe and are currently under active development. They may change in future minor releases.

Choosing the right hashing algorithm for your application can be crucial from both performance and security standpoint. In StringZilla a 64-bit rolling hash function is reused for both string hashes and substring hashes, Rabin-style fingerprints. Rolling hashes take the same amount of time to compute hashes with different window sizes, and are fast to update. Those are not however perfect hashes, and collisions are frequent. StringZilla attempts to use SIMD, but the performance is not yet satisfactory. On Intel Sapphire Rapids, the following numbers can be expected for N-way parallel variants.

  • 4-way AVX2 throughput with 64-bit integer multiplication (no native support): 0.28 GB/s.
  • 4-way AVX2 throughput with 32-bit integer multiplication: 0.54 GB/s.
  • 4-way AVX-512DQ throughput with 64-bit integer multiplication: 0.46 GB/s.
  • 4-way AVX-512 throughput with 32-bit integer multiplication: 0.58 GB/s.
  • 8-way AVX-512 throughput with 32-bit integer multiplication: 0.11 GB/s.

Next design goals:

  • Try gear-hash and other rolling approaches.

Why not CRC32?

Cyclic Redundancy Check 32 is one of the most commonly used hash functions in Computer Science. It has in-hardware support on both x86 and Arm, for both 8-bit, 16-bit, 32-bit, and 64-bit words. The 0x1EDC6F41 polynomial is used in iSCSI, Btrfs, ext4, and the 0x04C11DB7 in SATA, Ethernet, Zlib, PNG. In case of Arm more than one polynomial is supported. It is, however, somewhat limiting for Big Data usecases, which often have to deal with more than 4 Billion strings, making collisions unavoidable. Moreover, the existing SIMD approaches are tricky, combining general purpose computations with specialized instructions, to utilize more silicon in every cycle.

§ Reading materials. Comprehensive derivation of approaches Faster computation for 4 KB buffers on x86 Comparing different lookup tables Great open-source implementations. By Peter Cawley By Stephan Brumme

Other Modern Alternatives

MurmurHash from 2008 by Austin Appleby is one of the best known non-cryptographic hashes. It has a very short implementation and is capable of producing 32-bit and 128-bit hashes. The CityHash from 2011 by Google and the xxHash improve on that, better leveraging the super-scalar nature of modern CPUs and producing 64-bit and 128-bit hashes.

Neither of those functions are cryptographic, unlike MD5, SHA, and BLAKE algorithms. Most of cryptographic hashes are based on the Merkle-Damgård construction, and aren't resistant to the length-extension attacks. Current state of the Art, might be the BLAKE3 algorithm. It's resistant to a broad range of attacks, can process 2 bytes per CPU cycle, and comes with a very optimized official implementation for C and Rust. It has the same 128-bit security level as the BLAKE2, and achieves its performance gains by reducing the number of mixing rounds, and processing data in 1 KiB chunks, which is great for longer strings, but may result in poor performance on short ones.

All mentioned libraries have undergone extensive testing and are considered production-ready. They can definitely accelerate your application, but so may the downstream mixer. For instance, when a hash-table is constructed, the hashes are further shrunk to address table buckets. If the mixer looses entropy, the performance gains from the hash function may be lost. An example would be power-of-two modulo, which is a common mixer, but is known to be weak. One alternative would be the fastrange by Daniel Lemire. Another one is the Fibonacci hash trick using the Golden Ratio, also used in StringZilla.

Unicode, UTF-8, and Wide Characters

Most StringZilla operations are byte-level, so they work well with ASCII and UTF8 content out of the box. In some cases, like edit-distance computation, the result of byte-level evaluation and character-level evaluation may differ. So StringZilla provides following functions to work with Unicode:

  • sz_edit_distance_utf8 - computes the Levenshtein distance between two UTF-8 strings.
  • sz_hamming_distance_utf8 - computes the Hamming distance between two UTF-8 strings.

Java, JavaScript, Python 2, C#, and Objective-C, however, use wide characters (wchar) - two byte long codes, instead of the more reasonable fixed-length UTF32 or variable-length UTF8. This leads to all kinds of offset-counting issues when facing four-byte long Unicode characters. So consider transcoding with simdutf, if you are coming from such environments.

Contributing 👾

Please check out the contributing guide for more details on how to setup 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 UTF8, UTF16, and UTF32 LE and BE.
  • hyperscan - regular expressions with SIMD acceleration.
  • pyahocorasick - Aho-Corasick algorithm in Python.
  • rapidfuzz - fast string matching in C++ and Python.

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.

Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

stringzilla-3.9.8-cp312-cp312-win_arm64.whl (62.8 kB view details)

Uploaded CPython 3.12 Windows ARM64

stringzilla-3.9.8-cp312-cp312-win_amd64.whl (73.0 kB view details)

Uploaded CPython 3.12 Windows x86-64

stringzilla-3.9.8-cp312-cp312-win32.whl (64.4 kB view details)

Uploaded CPython 3.12 Windows x86

stringzilla-3.9.8-cp312-cp312-musllinux_1_2_x86_64.whl (255.6 kB view details)

Uploaded CPython 3.12 musllinux: musl 1.2+ x86-64

stringzilla-3.9.8-cp312-cp312-musllinux_1_2_s390x.whl (194.9 kB view details)

Uploaded CPython 3.12 musllinux: musl 1.2+ s390x

stringzilla-3.9.8-cp312-cp312-musllinux_1_2_ppc64le.whl (217.1 kB view details)

Uploaded CPython 3.12 musllinux: musl 1.2+ ppc64le

stringzilla-3.9.8-cp312-cp312-musllinux_1_2_i686.whl (200.0 kB view details)

Uploaded CPython 3.12 musllinux: musl 1.2+ i686

stringzilla-3.9.8-cp312-cp312-musllinux_1_2_aarch64.whl (206.1 kB view details)

Uploaded CPython 3.12 musllinux: musl 1.2+ ARM64

stringzilla-3.9.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (260.2 kB view details)

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

stringzilla-3.9.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (192.5 kB view details)

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

stringzilla-3.9.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (220.7 kB view details)

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

stringzilla-3.9.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (210.3 kB view details)

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

stringzilla-3.9.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (198.5 kB view details)

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

stringzilla-3.9.8-cp312-cp312-macosx_11_0_arm64.whl (74.1 kB view details)

Uploaded CPython 3.12 macOS 11.0+ ARM64

stringzilla-3.9.8-cp312-cp312-macosx_10_13_x86_64.whl (74.0 kB view details)

Uploaded CPython 3.12 macOS 10.13+ x86-64

stringzilla-3.9.8-cp312-cp312-macosx_10_13_universal2.whl (113.1 kB view details)

Uploaded CPython 3.12 macOS 10.13+ universal2 (ARM64, x86-64)

stringzilla-3.9.8-cp311-cp311-win_arm64.whl (62.8 kB view details)

Uploaded CPython 3.11 Windows ARM64

stringzilla-3.9.8-cp311-cp311-win_amd64.whl (72.9 kB view details)

Uploaded CPython 3.11 Windows x86-64

stringzilla-3.9.8-cp311-cp311-win32.whl (64.3 kB view details)

Uploaded CPython 3.11 Windows x86

stringzilla-3.9.8-cp311-cp311-musllinux_1_2_x86_64.whl (255.1 kB view details)

Uploaded CPython 3.11 musllinux: musl 1.2+ x86-64

stringzilla-3.9.8-cp311-cp311-musllinux_1_2_s390x.whl (194.3 kB view details)

Uploaded CPython 3.11 musllinux: musl 1.2+ s390x

stringzilla-3.9.8-cp311-cp311-musllinux_1_2_ppc64le.whl (217.7 kB view details)

Uploaded CPython 3.11 musllinux: musl 1.2+ ppc64le

stringzilla-3.9.8-cp311-cp311-musllinux_1_2_i686.whl (200.1 kB view details)

Uploaded CPython 3.11 musllinux: musl 1.2+ i686

stringzilla-3.9.8-cp311-cp311-musllinux_1_2_aarch64.whl (206.3 kB view details)

Uploaded CPython 3.11 musllinux: musl 1.2+ ARM64

stringzilla-3.9.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (259.5 kB view details)

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

stringzilla-3.9.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (192.6 kB view details)

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

stringzilla-3.9.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (221.2 kB view details)

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

stringzilla-3.9.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (210.8 kB view details)

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

stringzilla-3.9.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (198.3 kB view details)

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

stringzilla-3.9.8-cp311-cp311-macosx_11_0_arm64.whl (73.9 kB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

stringzilla-3.9.8-cp311-cp311-macosx_10_9_x86_64.whl (73.7 kB view details)

Uploaded CPython 3.11 macOS 10.9+ x86-64

stringzilla-3.9.8-cp311-cp311-macosx_10_9_universal2.whl (112.6 kB view details)

Uploaded CPython 3.11 macOS 10.9+ universal2 (ARM64, x86-64)

stringzilla-3.9.8-cp310-cp310-win_arm64.whl (62.8 kB view details)

Uploaded CPython 3.10 Windows ARM64

stringzilla-3.9.8-cp310-cp310-win_amd64.whl (72.7 kB view details)

Uploaded CPython 3.10 Windows x86-64

stringzilla-3.9.8-cp310-cp310-win32.whl (64.3 kB view details)

Uploaded CPython 3.10 Windows x86

stringzilla-3.9.8-cp310-cp310-musllinux_1_2_x86_64.whl (252.6 kB view details)

Uploaded CPython 3.10 musllinux: musl 1.2+ x86-64

stringzilla-3.9.8-cp310-cp310-musllinux_1_2_s390x.whl (191.6 kB view details)

Uploaded CPython 3.10 musllinux: musl 1.2+ s390x

stringzilla-3.9.8-cp310-cp310-musllinux_1_2_ppc64le.whl (214.9 kB view details)

Uploaded CPython 3.10 musllinux: musl 1.2+ ppc64le

stringzilla-3.9.8-cp310-cp310-musllinux_1_2_i686.whl (197.8 kB view details)

Uploaded CPython 3.10 musllinux: musl 1.2+ i686

stringzilla-3.9.8-cp310-cp310-musllinux_1_2_aarch64.whl (203.6 kB view details)

Uploaded CPython 3.10 musllinux: musl 1.2+ ARM64

stringzilla-3.9.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (257.2 kB view details)

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

stringzilla-3.9.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (190.1 kB view details)

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

stringzilla-3.9.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (218.3 kB view details)

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

stringzilla-3.9.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (208.3 kB view details)

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

stringzilla-3.9.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (195.8 kB view details)

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

stringzilla-3.9.8-cp310-cp310-macosx_11_0_arm64.whl (73.9 kB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

stringzilla-3.9.8-cp310-cp310-macosx_10_9_x86_64.whl (73.6 kB view details)

Uploaded CPython 3.10 macOS 10.9+ x86-64

stringzilla-3.9.8-cp310-cp310-macosx_10_9_universal2.whl (112.6 kB view details)

Uploaded CPython 3.10 macOS 10.9+ universal2 (ARM64, x86-64)

stringzilla-3.9.8-cp39-cp39-win_arm64.whl (62.9 kB view details)

Uploaded CPython 3.9 Windows ARM64

stringzilla-3.9.8-cp39-cp39-win_amd64.whl (73.1 kB view details)

Uploaded CPython 3.9 Windows x86-64

stringzilla-3.9.8-cp39-cp39-win32.whl (64.3 kB view details)

Uploaded CPython 3.9 Windows x86

stringzilla-3.9.8-cp39-cp39-musllinux_1_2_x86_64.whl (251.4 kB view details)

Uploaded CPython 3.9 musllinux: musl 1.2+ x86-64

stringzilla-3.9.8-cp39-cp39-musllinux_1_2_s390x.whl (190.5 kB view details)

Uploaded CPython 3.9 musllinux: musl 1.2+ s390x

stringzilla-3.9.8-cp39-cp39-musllinux_1_2_ppc64le.whl (213.7 kB view details)

Uploaded CPython 3.9 musllinux: musl 1.2+ ppc64le

stringzilla-3.9.8-cp39-cp39-musllinux_1_2_i686.whl (196.7 kB view details)

Uploaded CPython 3.9 musllinux: musl 1.2+ i686

stringzilla-3.9.8-cp39-cp39-musllinux_1_2_aarch64.whl (202.6 kB view details)

Uploaded CPython 3.9 musllinux: musl 1.2+ ARM64

stringzilla-3.9.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (256.0 kB view details)

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

stringzilla-3.9.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (188.8 kB view details)

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

stringzilla-3.9.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (216.9 kB view details)

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

stringzilla-3.9.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (207.1 kB view details)

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

stringzilla-3.9.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (194.7 kB view details)

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

stringzilla-3.9.8-cp39-cp39-macosx_11_0_arm64.whl (73.9 kB view details)

Uploaded CPython 3.9 macOS 11.0+ ARM64

stringzilla-3.9.8-cp39-cp39-macosx_10_9_x86_64.whl (73.7 kB view details)

Uploaded CPython 3.9 macOS 10.9+ x86-64

stringzilla-3.9.8-cp39-cp39-macosx_10_9_universal2.whl (112.5 kB view details)

Uploaded CPython 3.9 macOS 10.9+ universal2 (ARM64, x86-64)

stringzilla-3.9.8-cp38-cp38-win_amd64.whl (72.8 kB view details)

Uploaded CPython 3.8 Windows x86-64

stringzilla-3.9.8-cp38-cp38-win32.whl (64.3 kB view details)

Uploaded CPython 3.8 Windows x86

stringzilla-3.9.8-cp38-cp38-musllinux_1_2_x86_64.whl (250.5 kB view details)

Uploaded CPython 3.8 musllinux: musl 1.2+ x86-64

stringzilla-3.9.8-cp38-cp38-musllinux_1_2_s390x.whl (189.3 kB view details)

Uploaded CPython 3.8 musllinux: musl 1.2+ s390x

stringzilla-3.9.8-cp38-cp38-musllinux_1_2_ppc64le.whl (212.8 kB view details)

Uploaded CPython 3.8 musllinux: musl 1.2+ ppc64le

stringzilla-3.9.8-cp38-cp38-musllinux_1_2_i686.whl (196.0 kB view details)

Uploaded CPython 3.8 musllinux: musl 1.2+ i686

stringzilla-3.9.8-cp38-cp38-musllinux_1_2_aarch64.whl (201.7 kB view details)

Uploaded CPython 3.8 musllinux: musl 1.2+ ARM64

stringzilla-3.9.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (255.3 kB view details)

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

stringzilla-3.9.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (187.8 kB view details)

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

stringzilla-3.9.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (215.9 kB view details)

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

stringzilla-3.9.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (206.0 kB view details)

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

stringzilla-3.9.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (193.7 kB view details)

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

stringzilla-3.9.8-cp38-cp38-macosx_11_0_arm64.whl (73.9 kB view details)

Uploaded CPython 3.8 macOS 11.0+ ARM64

stringzilla-3.9.8-cp38-cp38-macosx_10_9_x86_64.whl (73.7 kB view details)

Uploaded CPython 3.8 macOS 10.9+ x86-64

stringzilla-3.9.8-cp38-cp38-macosx_10_9_universal2.whl (112.5 kB view details)

Uploaded CPython 3.8 macOS 10.9+ universal2 (ARM64, x86-64)

stringzilla-3.9.8-cp37-cp37m-win_amd64.whl (72.8 kB view details)

Uploaded CPython 3.7m Windows x86-64

stringzilla-3.9.8-cp37-cp37m-win32.whl (64.3 kB view details)

Uploaded CPython 3.7m Windows x86

stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_x86_64.whl (248.9 kB view details)

Uploaded CPython 3.7m musllinux: musl 1.2+ x86-64

stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_s390x.whl (188.0 kB view details)

Uploaded CPython 3.7m musllinux: musl 1.2+ s390x

stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_ppc64le.whl (210.8 kB view details)

Uploaded CPython 3.7m musllinux: musl 1.2+ ppc64le

stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_i686.whl (194.2 kB view details)

Uploaded CPython 3.7m musllinux: musl 1.2+ i686

stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_aarch64.whl (199.4 kB view details)

Uploaded CPython 3.7m musllinux: musl 1.2+ ARM64

stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (253.8 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.28+ x86-64

stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (186.1 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.17+ s390x manylinux: glibc 2.28+ s390x

stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (213.9 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.17+ ppc64le manylinux: glibc 2.28+ ppc64le

stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (203.6 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.17+ ARM64 manylinux: glibc 2.28+ ARM64

stringzilla-3.9.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (191.8 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

stringzilla-3.9.8-cp37-cp37m-macosx_10_9_x86_64.whl (73.6 kB view details)

Uploaded CPython 3.7m macOS 10.9+ x86-64

stringzilla-3.9.8-cp36-cp36m-win_amd64.whl (72.8 kB view details)

Uploaded CPython 3.6m Windows x86-64

stringzilla-3.9.8-cp36-cp36m-win32.whl (64.2 kB view details)

Uploaded CPython 3.6m Windows x86

stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_x86_64.whl (248.1 kB view details)

Uploaded CPython 3.6m musllinux: musl 1.2+ x86-64

stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_s390x.whl (187.3 kB view details)

Uploaded CPython 3.6m musllinux: musl 1.2+ s390x

stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_ppc64le.whl (210.1 kB view details)

Uploaded CPython 3.6m musllinux: musl 1.2+ ppc64le

stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_i686.whl (193.6 kB view details)

Uploaded CPython 3.6m musllinux: musl 1.2+ i686

stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_aarch64.whl (198.7 kB view details)

Uploaded CPython 3.6m musllinux: musl 1.2+ ARM64

stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl (253.0 kB view details)

Uploaded CPython 3.6m manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.28+ x86-64

stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl (185.1 kB view details)

Uploaded CPython 3.6m manylinux: glibc 2.17+ s390x manylinux: glibc 2.28+ s390x

stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl (213.5 kB view details)

Uploaded CPython 3.6m manylinux: glibc 2.17+ ppc64le manylinux: glibc 2.28+ ppc64le

stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl (202.7 kB view details)

Uploaded CPython 3.6m manylinux: glibc 2.17+ ARM64 manylinux: glibc 2.28+ ARM64

stringzilla-3.9.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (191.3 kB view details)

Uploaded CPython 3.6m manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

stringzilla-3.9.8-cp36-cp36m-macosx_10_9_x86_64.whl (73.3 kB view details)

Uploaded CPython 3.6m macOS 10.9+ x86-64

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-win_arm64.whl
Algorithm Hash digest
SHA256 a167da4b1a932ddb391f0999c558390c4b2bba283d50949920594c1e5702cae9
MD5 20902f87261aff4e2341913d65d92241
BLAKE2b-256 851d1d452e9017223fa5df2b4f44cda67c36c2610638fb77f95a0883e9107582

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 a69476a91e845e493cccbaf824864fca75e9332c2898e39abbec86f5f28d250b
MD5 3a475eb54aae6bb6dae13ca5c92c8d0c
BLAKE2b-256 a88c5c39c83f0a5c9a5c5c8ab388706d6c961a057593f640cbb494eaef669df8

See more details on using hashes here.

File details

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

File metadata

  • Download URL: stringzilla-3.9.8-cp312-cp312-win32.whl
  • Upload date:
  • Size: 64.4 kB
  • Tags: CPython 3.12, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.1 CPython/3.12.6

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-win32.whl
Algorithm Hash digest
SHA256 fde0ea8476fe17a8cb525df2b9cf64cbc1c8ba4ca9f48b34b35091ff9a503e62
MD5 89394c57ee83a39d2b44aa02ee5ead96
BLAKE2b-256 d0302604e1d773235048579edc9028b7cfe98c4356f87cf037fcdfc155dda0c7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 17e662ad81c7c73d3103064a989e3a9d25ef421387dce14ab156e98a05177a7f
MD5 027c68cba3872b718672c2044d85c925
BLAKE2b-256 938bd5a9a5bb8baa9410bd873f905fe9c134c5d1d65b2f099909c6934824624b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 9921cf87f66866204054f218f3fedb64ee6e5794b563b0e6e7dbb530286215bf
MD5 e1a17ab8149e770a128863cd99289a07
BLAKE2b-256 b988ab70ff3a3d511bd7614992935d1c7203ca0d584fd5c6234d6d813355abb9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 6a2d48b6ecea63895082b53f87b53f3962a43dc8b99728f23c93ee2af4306641
MD5 c1a634d40ad8ca95dc16364720ce5eb3
BLAKE2b-256 63cba917664e8c424b14392e5397f1ffb2263859ab1c890e3bc5bee766cc6311

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 d47b12f6b990b1cd04bca7808e6c26b665cd4f8de219d524f27bbb8e1b69a388
MD5 68df957ff20302c6215034972b049c0c
BLAKE2b-256 b7e0683eaca2bae4aa85ae54577bacddcc3695cbdae919844170a18e3b439678

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 3d2e5f69b0fea142fa7b2c3cfac12fe8f93ad5693c0f299017993ee660b6ffcb
MD5 5e0f6d204ed947fc32ef86edc4763e18
BLAKE2b-256 71eff5087309b70a95f5670784512b98e4c4b9a3788d8cd64a16b06fb190f37f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b823d2dfecb3f518a2dff09a7497ee407cecccc01275d92681ce56795fe3fbb5
MD5 76f7cdf2779822f134d4294fdac42f7e
BLAKE2b-256 f3e791b735cafdac9e096d607e65a19067d8c1af1131861f8d6a91611b9721c9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 93a894cdb44a0743cba9953a8a1a53371ad89d7d9e6cf110308928ff2ae76ada
MD5 4ff5ad81b442ffa08857346989cfedd2
BLAKE2b-256 7375e648d253aad19683c320063eb2c9a896907bf2b050b6b4f987b96b0a802b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 dc58018ef15b56a445233a8f863c939d62195cfe35de865fe8f860ea4d5e5e30
MD5 765473bffeb68c544ae71bf3a06da72b
BLAKE2b-256 e71ced61b70ba630eedbdf3fd114d4e6a2e41af92ed3ba8120873ca387a4afa6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 1fd4fa303894eb675e47a531eee5c03c001887fe317d6d1949556f4f3289ceef
MD5 3065e5b619ee1be8a51c5c87e2c878e6
BLAKE2b-256 ca09d848a36358cd921863f7e08978b915d3dd84659f709057f3ecb7f4faab6c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 1ff42bbb1e480e3ac845858fc294b7d9b3a8f3450cea311950d70d97c48732a5
MD5 a6386631298860c12b0443ead41fa0fe
BLAKE2b-256 4d7899f188bb74b3e7a03a9974bb38932d2a0a737e5950b41cd35ce497dce549

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6e2f4e6b98de3dcf124e03b70568957b28df0af4b0f197879aaedaf1eb20e986
MD5 3afff48b73ee6e9d0706f57f9c34ddd5
BLAKE2b-256 6654296df86f30faee41cd3e0a04a830fbed3ec74b64165eaff925127633f5d4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 9dd8044bf19c5234be3ee63a7f3882b6aa016f5a7519f518ec363d9b66325306
MD5 2c3b923c8a143b71dd763e3d1a6cb3aa
BLAKE2b-256 673942e9bcea46ce291bed947f1ca151c696fb56f0d72ba1b61ac23dd5a296b8

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp312-cp312-macosx_10_13_universal2.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp312-cp312-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 be585fc385a9426543bacf5a00ae7fe74b973412b34fa63b6a37c2febe04881e
MD5 49b45de04282b512d6d082c748bb66b4
BLAKE2b-256 7c8215b9dbf0478448320003f02b103ce1303d1db5455016e7c79986a8161f5a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-win_arm64.whl
Algorithm Hash digest
SHA256 4f9864b7c0571ec770660ece4c261876138107d230f769036a27d8a50be43ed2
MD5 5915289ad9a2e9a68d0c8bb4d5cc0db1
BLAKE2b-256 03e12a41be387adea3bbcd2b96197f7634bc1aeedf1fc45c8f8f4e6126b142a7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 3f9c67e05d1da5c2a50cb302123ad7a2dbb48a2cf1423d0796a3d6514fd0e060
MD5 34593183dc700452d515e464b972bf59
BLAKE2b-256 61e32af727de613822b351dbb9cd459b03d8ac669ec1935ef3c8efef5a8d7b90

See more details on using hashes here.

File details

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

File metadata

  • Download URL: stringzilla-3.9.8-cp311-cp311-win32.whl
  • Upload date:
  • Size: 64.3 kB
  • Tags: CPython 3.11, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.1 CPython/3.12.6

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-win32.whl
Algorithm Hash digest
SHA256 a82bb6392fe24d1b00eb4979566581df80ca4828e974eac7158e8bc54ac8efaa
MD5 9b5051c77d18c6d9b540bcaabf27f9b6
BLAKE2b-256 3ed225bd33fa75bc04cf0c9838b29858241878dca780801213cab622b5febae6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 3c1af3760bd4350151218fe442386b3f43c162e1009178d12c3dc87934a76cc2
MD5 38468bf6c18e695fc3e4bfbf9d1ae23a
BLAKE2b-256 1f08456eae099e762d16d607d2ccb5de2961f512b05d98ffe250ed3399eedac1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 175a08a694ef5cb74dd7064c03bacd594bfbb94e48e5984ab085566d07d51aff
MD5 9e92409cd4ac02d855d9472b2d0adf0b
BLAKE2b-256 44800fb3d0b048933f1559dc1d313368e78662cfd108ac8d88e813bebc0295ad

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 b2a15975ecb53d4b67f42fa87f2ba3954fcd8bee86fe8412874a89b6fe984ceb
MD5 2b0758da51d209b5e61981156a3840ad
BLAKE2b-256 2d4c51ffd0efe971938b94e7481362cb05b191689414cb8ac90b917b8d9da25e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 803f315a8447218525bbfda7e0add074ae2ff98f7c57c3513f2f40e108e7ed09
MD5 fb0d3ae395ce4c481ce8c74a1b18e6b1
BLAKE2b-256 55090e45bf75575d7b73f8d09815cab2e2f76aca133342e16bd582d67b84617e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 5cfaf017c1924c6eebaf8697b6d86108c678cb05416c6f58ef8497f98409a6e3
MD5 c4e7530235b7e80280ab83c4aeef8e4b
BLAKE2b-256 fa456ba8186592f104e6372a2626a19a34120c63eb472aae276dca5cbfec8b54

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 acdd09a0980ca8595d85b2dfcb218d572cbf4c8629764b82e8ffc262c243e5a8
MD5 53fe8fb8e9f92ba1a522cc3994cebdfe
BLAKE2b-256 08ed2630f66ae2f9014aae5d595367d50cb127f996cce0bf7af3e6814f4040a3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 385c12192523daec4a0fe62fc0fc273a188b6eb653184aeb8a20c187e51bdcf5
MD5 ae9efb1cd9d90a15982916a03a08d9d4
BLAKE2b-256 ed985c6f383627e644d5c1505e21a105749139c159a7cb4b833329781d6bfcfb

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 eba3f160067507cb9fecf039ef24cee6e96fa5700093e9d676533d45619e3e22
MD5 ea8900c82bb0eae56636fcc724edd3d7
BLAKE2b-256 4eeaaebb3a2118144e449079c56a53a13b58b7478d4ac1988046293155697c02

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 fa3de3d4fcfd376b759b5a7fc45d727e3cda874a6447cfd8f34fd2c79b0a63e2
MD5 103f35795f92f5ab21932e0cbe51dfdc
BLAKE2b-256 a3eb863380a55f9c5aa3c87d0202b514369e92e650540159aa635fe2f05203de

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 d763e962d94ea7591dae34143f837184b9c291a7393b0d28464aca47e9cdfde2
MD5 d69fa3c2d33cafcd129e94d6b7e485c6
BLAKE2b-256 86321cb2d95cce6261e17720456f1376f99af37cd356f54ea57ea4eaaa17cf3c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 94b4ad45b319ba150465c90b240784aaca5cdb03f47b32694dc82865fef716c3
MD5 0b30e2dff29fd6b28d050aae8966eebd
BLAKE2b-256 9f860085f3d0072ab14d9d86701428ce7fe0f022e4edbfb8d42689a9db448246

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp311-cp311-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 3778a8033f7d3ef8fc06ffbd47ccb25556b76fa8bd8223ffbb55db0740c1d85d
MD5 4160558445a55b98d5cb7f6c2379e894
BLAKE2b-256 698e8497797e6d6ace6bd5548a3734e9ce3c9ae556b932c87e4926e02120baa1

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp311-cp311-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp311-cp311-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 6830711734fc67081c01e5f5c5df23e488871fcf7cb9bbef18bae16b5e032b25
MD5 c0e4c8b1e3c97a162b4bda7f45dec8af
BLAKE2b-256 0aaca95496f14353bf23539a0a59c349c79841286c86bb68cf7935a430e629a6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-win_arm64.whl
Algorithm Hash digest
SHA256 4633cabf0257fcbd672a510b02dc24664b89b8a7532f6a074128edbac106c259
MD5 71ad986b4f3486247f8124299cdf930c
BLAKE2b-256 4b596ceaa76786efc32302e11148f330ef7d40c3539ca7ec153559836a0920b0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 58d6e1267499e8e81ab528e314a86fe9161d900cee5ec97d53ec9725e5529473
MD5 7f66f9c94aaab2f065b618fbe36ea2cd
BLAKE2b-256 e81e13c3bf3a9b16c7ed4d1b414158f37a06db3d7b8104535e540a9bc6d91167

See more details on using hashes here.

File details

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

File metadata

  • Download URL: stringzilla-3.9.8-cp310-cp310-win32.whl
  • Upload date:
  • Size: 64.3 kB
  • Tags: CPython 3.10, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.1 CPython/3.12.6

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-win32.whl
Algorithm Hash digest
SHA256 193d4b89fc44c86184bf092df90c7d7c4732e276cb80d4b4d001889359e7cd73
MD5 02c1d3213d0e94e5df49c0c18b9efa1e
BLAKE2b-256 37430c8c79e77fbae3d8315a43cec1b6d2ec8ca2ed8782e21fa8ddeacc63c927

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 faf17dfa70e6a284c9cef15ac7eecda8e013f8bb424bd1e10d8cb2def2f866e4
MD5 7769637992c6cd14d064f4b88fc80880
BLAKE2b-256 5fa08f3cd786d17877b6b2712eafb4d7f7ebf493b864352a5cecd2e10eecc7be

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 fc0bb2fd10bbdf72262fc3304fd2ead059408904f40cf749dcbc1e38a62aa197
MD5 2270d5ce12834916f6509bd1f3783e2f
BLAKE2b-256 15728b574b67c1e8e6c5a4fef7d86ad6c866d117ee7f7aefa2ddbdc507092020

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 39a46ef76356bd021396db8d41771e07b3168fd59fdfa32968416f60017f886c
MD5 4229474ff0904b0793c607857044ec1e
BLAKE2b-256 f77b2db63fe22bdc28e67b020556763b31bcc856f51219a35c420bd7e6bebfa4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 b3df79538ea6b810de6a3e66e6305baee5084160b2b4f2e619d7bcd97072d66d
MD5 296fd4d4a97c632f4fe9e80f31f725ae
BLAKE2b-256 fa026cd328e51005e70ae67e673ff16b6a6e0e7b381095b7b2c24f07c21dbe78

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 79eb65fca4c94595fe725f09f488ea6dcc69198ea225bf48e73a6871703038e9
MD5 508cf876a035675a858b4622f46a2870
BLAKE2b-256 cd5e43b914b1299841ad69c9188dcc9a2beb3acb8d2b8559937c7fb0f0fa452c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 d070c6c0027e8769beec6db8313cc8299a314d2897e690f0a888efac6bd24e98
MD5 f17432c41b30fd18b1eaeec00c4c4d40
BLAKE2b-256 e9f1ff1f8b087332240076223bcfac5c4ea498b02f43cc9155e65af283b73b39

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 6e4f7cf88e02219858bfcf020c18c420c59b5ac2e16a8414a0f056d72f43c20c
MD5 f4a913d9690c8f6222c170ded200dbac
BLAKE2b-256 4561bdc7995c18f431a5cb14ac4645f77b35e46c208e0d02f1eb3c463d2a7cec

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 2ee77b047ca1f63cd04ddf75815c745b56357e052658ae2b311669ad85aa69c5
MD5 33338163b7811efdae8db124de0c6601
BLAKE2b-256 fc43ba467518a6a3d5b0f3b2c857ab997ba3b44ab6efd4f8da4f73abe1403c30

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 4c0317bdb484d41f38ae17560bbe147ed5df1d052f94e5af4bf4ceea8123c799
MD5 a60203beef3e0940b604f5f95510875b
BLAKE2b-256 0ceaf7dfacb477f72097ff454ed414af18a4ebdb433cd56ecf631841ed8c807c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 d277bffdc515783d9cdb3327a87e8e0ecc4c951302866b98e63566e1e9e75fa1
MD5 9c2d7e8cf5c2eb2c9b27603113622912
BLAKE2b-256 6e173cf9d14345a9f13736d8cbad7c6cdc6107c63f115f51389df4f7ebf293d1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9b25ed114bbacdc7d2f25111f9b29f7861f7781c3ba6b9b19d90147d0a802107
MD5 b2ceeb48029bb8fb29ee27a63c0c2f25
BLAKE2b-256 c8830314cb3ea48b3e35e04c66dae61bf11f3b6f07064f16cdc61b484738fcc4

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp310-cp310-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 516f4dd9c7a1a6435b8fdcdea0100efb039cb0f815b8756885d79374e6ccaf0a
MD5 1e95c6fe47df080e2bc7534e019844a4
BLAKE2b-256 971a6ab28448354218239e709d1d967d9e043a04358da1e981b67017887da1ca

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp310-cp310-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp310-cp310-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 31d0b55ba866f76e1240e3337893fea4f90c02960594f2e06ce764b8c20b41b9
MD5 2a38f44cf4466b0cea9f4ccb7aec194d
BLAKE2b-256 2a3cb7cc2d62abcbae96229d190ebab90cabdbf9bd9b0cb94541da9a5da703e9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-win_arm64.whl
Algorithm Hash digest
SHA256 8e9566f9dd5e74fb0f006e68cdcff815285c6c2885de9d02b2d9b61ce83c378e
MD5 b0b2b4bd80638172aebfe73e776cd572
BLAKE2b-256 2d16e1af2626e355e2e46dd92b792ff18244a241ecd1e761f2dadbe13954d82b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 45e478383abc3918165a506bc60daf09391efff5519a3d9eb16f9e1ce403dc51
MD5 8dbac1b63de984ed7562d2aaba5f0b67
BLAKE2b-256 08bc9404eef977fdf225cf65a1c648c7ba22538c44f20f8e1b17b4045b656f10

See more details on using hashes here.

File details

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

File metadata

  • Download URL: stringzilla-3.9.8-cp39-cp39-win32.whl
  • Upload date:
  • Size: 64.3 kB
  • Tags: CPython 3.9, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.1 CPython/3.12.6

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-win32.whl
Algorithm Hash digest
SHA256 2e3d9b39512090d9f7a479e2f6feb4a097de2d9d154c9e1da962eb71dc35707a
MD5 95ef0cbc3fa1f2c5ffae6cb7e270500c
BLAKE2b-256 7cdbe327df207c18adb9335b7a564e5a1fba9e3ee82cc7d1345161b9d97ee6c4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 d9f72e7ff23bceafe8ea3a9d0757015b233c64c7ba66af23cbce12878ff37f40
MD5 5acb2f3c6cae57d8f6c92c929b10037b
BLAKE2b-256 2f2f03d5b4f4b5978d5b35b40dae3e7d7bb8af2b82aa2a40404733e00c8bfdaa

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 0fb14b443793d01594aa276a80dd05b0ae2e5075a00a07eb4fbd4001ab87a1ea
MD5 bf68727de6024d610a00f0d6fe6e7566
BLAKE2b-256 55463deba07658c66fd4f7347303c76e0ea3d50f51387eb56ac0a9e00b6ad0df

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 d6d4cbc5f6463925ce917d75524b9fe3037449447db216c23d27d1f373ae2f30
MD5 34c58eceeecd50bd038db615d0ea7cda
BLAKE2b-256 c3957021a85f9c8687546888940df7ba2f1ced3d4c4a0e2c414da0e60de57b46

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 2571c367dbd043ba5b422dcd17f7e84e986884ade53cefb23c0960c405f43827
MD5 545d04de30cbc85a9fecb89abfe7c9cb
BLAKE2b-256 f760055ec034903f9c92ae1cb5e00a2d094a85f3512ce0c7e72e6f47ca955a25

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 63e6c87dd3dfd357c866bc3493b58d7b7044f9d0df87b1abab95457d6e585c42
MD5 168b0a32caa7008b0e26fa50c4007705
BLAKE2b-256 920be7d2fdd0e51ff968595882424e46d22e7423e002589797fc518463fc77ce

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 be975c7c3f1e2ebc7d79746b87fc3c7da7034216230bdb7aae095513e02c946c
MD5 6b89a119a6f877a232d5d661c4251c83
BLAKE2b-256 e112ba6132fa7ef4f154848cda75ff83389b8ca6c03e18d624f76465cd545170

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 8c5508feba4cf6a2195cf06907ee8a73c00c9a9d22b2375a982112edad9bdb5e
MD5 f551fb70d402e22cef1b614644df078a
BLAKE2b-256 feb907d07b533acac703fba253e355279e6404ec6b51da3de20554c0dfd921a6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 e28c844ec686761e6aa90c8b2728b2f7a2d7d4b82dd79710cff3dcb9bd099f94
MD5 e0ed035da5e820fa545398cc73688d26
BLAKE2b-256 b16bd690248a5623cbc6922842505aaa01d31d2c4f5e33a4b98835b216b11124

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 ce3213e7f4cc3716ce78aa1679a809297c56740aeb9395f0864787905143b1ac
MD5 49c513a9532003458e43b68ffe078563
BLAKE2b-256 9f92bf97f986b23f6913d2cdbb3b71659f6d9adf9e2a2aade5beb81ec525f701

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 0b3b53baa80511b8a308205da00c5ae417706c1d4f746ce7cd9d8d670455a804
MD5 2bdcb7bd9205b8ae958530626a9dac4c
BLAKE2b-256 07c925c70ebdebb276df83c4c39c222c6ff64b4d6ba26f427dcf8347d5e7e380

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 406c8998e0cadd5c5bc1bf04a278dace4d055a6c1e8784329a84954217b209ea
MD5 f8c7546f8e6336d82bd2a9b5ee81205f
BLAKE2b-256 8c292ed8895d92a540e7efc8426c641c5a6b2f75b11dde8cf386ab8bdefce1f5

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp39-cp39-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 6797e83072884fef9f9d8b7884f3690639d988adc1c10bc74a1989212458fa95
MD5 70f9b4a688235b1de670d646edb460cc
BLAKE2b-256 4368834e499f688b8ce3bcd56f741b5f24015971626f66729e8c1b34f060ad1b

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp39-cp39-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp39-cp39-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 cefe55230e54deccaa6a22459bb0ffb987f520fe8df24cc1057b3773cf9759b7
MD5 558df34984123ecb6f9ea042527cf7c3
BLAKE2b-256 a064067993ec399a0d1ee0bf9cdc234a448f6be34a7b2153756521c275ba996a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 43dbf1db8314ceb9073fcbcf211ccb047143174d80063c3be8b582b5cb0997ec
MD5 a7cf694a4d7249ace58c35232cbc7594
BLAKE2b-256 9b587246114d9b7e99aa38dd19c2bafd247f4bd55fdd53966f17752e5f7b59fa

See more details on using hashes here.

File details

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

File metadata

  • Download URL: stringzilla-3.9.8-cp38-cp38-win32.whl
  • Upload date:
  • Size: 64.3 kB
  • Tags: CPython 3.8, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.1 CPython/3.12.6

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-win32.whl
Algorithm Hash digest
SHA256 1fef5d70b0620274aac6b4eb2c19e836caa61d64922b78f5435f735c87983539
MD5 266c22f794dbfebfa35630f91ef1eeaa
BLAKE2b-256 6a46fc758c1bcebf3e8bc2320f638371c57098cafe5762de794b6b62925d7b50

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 4ac3e4b54cc4dda8f7018af1a8c326ddd1d8a4aabb8438249934f9b56c1f4595
MD5 b885c773bba1e0e8dd213e744c4d0725
BLAKE2b-256 b38af8df576a06cb595da18f51e537abccb6fc44ec84c0f311e553c904931c06

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 bf2e80e0d1d5c8ab5e143aea0dd57f8eeda67263d7fb15b75940c7fd8b59e455
MD5 3aeea83910dab9c026b4da18546a301e
BLAKE2b-256 5fdfaced35f8952d3b476a4dc6a308fe0e380190eacb9d4900c9d793442f5f9a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 3486dc25b149f99ff20ddd01d77e1166b90ae0d54b2451aa172ef625d9a3fe05
MD5 90beb0098aab8bf22be256706361a19e
BLAKE2b-256 a433b4ddfa1be3a9904f9dffeb4fa750c848d1500d32cbdd0365adc99026f687

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 133a10a8951d0ddc33ba029459a815c711bd7de823a9a887f4b66339f6193fcd
MD5 cb25794b8f9b36b51f65d9d9be717745
BLAKE2b-256 fb0b631d7dd2037a9540942ec3f5b743e06788123cd8e5defb4863c22f862397

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 921f78517e9290fbca1cb6349be82928b8882d03b2fafc13e15c37e9c2f94ae6
MD5 1f6aa2efe3b0ec2de6bc76dec9a79008
BLAKE2b-256 0d83153cc960fda498e29061658a218d4224e74b4df804f2fc3d24cc480117b0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 05c62ff1f54df9eb83724be3e970e66ffa6e762f2179194457ea45c1d2e78761
MD5 384780622d633e70f0354132dc4e7b49
BLAKE2b-256 e707543e53616719d496d7148da5906328f43bb170839993e0514df54f583bf8

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 862a52495f08764a963a48a172da74833a5983fdca4d1b9e0e5b79bfdd73edea
MD5 1bc4711335de6ff8eb7d948f2af1b632
BLAKE2b-256 27607b14f4d2115f906c690df06c763a8000901681524a5106c83b75780b9e75

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 158699dba03906234f97cd273f86777949aeb1bd4926d59c1eeb73214dc0c4af
MD5 120f8f44aaff440202d640601dc61b31
BLAKE2b-256 3827c9711bc809778684476dc1df844fe35abbc156b816903fb12dfc05bfa72d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 6b237e9d66eab09941ad49b71dba31f069f10b081abeba983de5a79ef04efd46
MD5 4aae41229baace278d631e00bae74df4
BLAKE2b-256 a81b40148ef3557dd09d67b9966ad9579b03e547350eb9a074717cdcbdaed2a5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 ef930425b357367626054117402f2e6b6db91b9eef1458a1f814044d6c143385
MD5 4ace2f4aea561481eefbcdf56dbe8cb2
BLAKE2b-256 44104a69866b2b609f59e75830b3747dac68a71c392eefba18cbc0627980444d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 792897478e2364f52e0eaddfbc290c6ce1a0c406ec31814b043b971cff4c7b69
MD5 490375eb271a39b99a523530f9846886
BLAKE2b-256 ec7511a1a07a7ea1191e0f0fb424ad46aab664ad87bed3aeb031e0608f2b8508

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp38-cp38-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 47adcfac25fc0a09dbd4fb0023da6447239636f308bc39434d44e297120c2848
MD5 201c0eccfa70df5ca74f20d05e830d4d
BLAKE2b-256 d968c202a047849f1987a18b3e7c81b892ab6aec3d1a138d821bdade9d204f6a

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp38-cp38-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp38-cp38-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 99ae3007927b8489723832f9831e3b2b75c67518097ce6aef4a3790bbcd999ce
MD5 8b77fe9f040ca5352fcb657cf51c0848
BLAKE2b-256 470c3ed050f1da4e995615eb07df4a08453283d96d9b8e5a9b13cf3840992c2b

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-win_amd64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 d4c195e3171d6a935445a0925a4b918fa64361634287e804b00e6f8aa1b2cea2
MD5 b61fac58b0db863f337ede43c72f18b0
BLAKE2b-256 c2348bf8d4a1495dbe13721e7c09063387f8918a4ecd34b23cc44f00c5b454f8

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-win32.whl.

File metadata

  • Download URL: stringzilla-3.9.8-cp37-cp37m-win32.whl
  • Upload date:
  • Size: 64.3 kB
  • Tags: CPython 3.7m, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.1 CPython/3.12.6

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-win32.whl
Algorithm Hash digest
SHA256 2968d5ee448eb01c8cc105ab1037883f471f1ff45461d54cc27a7253a00b82da
MD5 cdc6bfb3a29e7b272b563763320e01e9
BLAKE2b-256 ae0fed1f66748c4aaa3df3f1b161323c703e9c621606925a09ad7bd7e8a507d3

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 6973a401e1d52e31a0ca4a59d4503099bf268d4c60f1ff1e06255e1cc2724edd
MD5 677cb88587fc00f46ced6e29056c5285
BLAKE2b-256 f7d290a055f406c0b69cbf06e9760a52afa22144e8b7d9e8ae6c5e93122a4520

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 355285313a7e8b0142e32c765dafc8cfcb39bdccd20e652b7b1a86ab9ff0d2e3
MD5 84f406072c20984b1fff2f9bdb90a1bb
BLAKE2b-256 3cf413f9876e3a512d870d3a356f7f9d3cef75c621dee940b0df67d084e7320a

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 7b6bbbc0c372f1e302d776c72bfaa2aeb0bcf69c7c9330454a55fb88759670ee
MD5 4d861894fcc713d57d75249542bf4177
BLAKE2b-256 759fc174173e37fd2a0ee2cb49515b2b9f73b91bcf02cf23fff43374492eee99

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 02932eeaf86bd1f8dad29db7bd61bf7957531d8d2d8e3589550244c562114d52
MD5 4c6384115cb8ad9bfeab4ad3baf7f557
BLAKE2b-256 ec7abe57a6d0f7c6de7acda735c12db9e0cc5776680bff781e53705a6e0af93f

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 2ab1494dae1209c5a6c126f05a2ebfda751b96f94e4471bcc373c270db7d226d
MD5 619fb66c4d801a20887e4103ab2133d2
BLAKE2b-256 2588258a70e974141589440882a854fa30061958e412c6ebf00a2e2aafcb2103

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 077b230bbd945bf48e8ab068468f97757342e1d2f0636ba401266b35a2da4ea6
MD5 5bf16bb807bbfec1e0583aa537f364ef
BLAKE2b-256 3c11126ab7c399e95bcd6b9eacbb0a29a9ea3906c518d551d5606c6d572a7b25

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 41f88bfc0c94991cacda27072c9469f04ae34fd3e43d66b3c75a72da22f3f902
MD5 6527543d9c6874486bab942d37abb25a
BLAKE2b-256 5eeb2d005a89485e059b9e5da43939fbcc11bd453e0eaed7357081b6899cec70

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 b3468784d0afaa9b0090ffd34b0fb0db1a65a5b7b1e7cac162a23f38c4985872
MD5 982073092f44964dfa67dfc08c8db466
BLAKE2b-256 3b69bc7a245a9c448c60e2201fb00932b42976225596ffa564f26f25c2585a34

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 02460ac2187db1c6038cba032119a39d39de353c3e12553314c61140eb1cfe18
MD5 1a82694fce95a763f92a87e06cf7c691
BLAKE2b-256 54abac5601d49a5b4639988abcda596190bc969af1b7541c090be68e1877ed30

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 14415d4d926a038d33568293ab1653ff8f870075d769a9ef1f481349156ea825
MD5 2f5ea598966eb8da9df117c9d54b2c4e
BLAKE2b-256 307209809476be26a44390912f224a051cd16a37e14e71a286ff08fd067d5667

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp37-cp37m-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp37-cp37m-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 57db5a8415926f9596abec0cbb312d47b5ec978c6a75d12f8747a8de5c28e9c4
MD5 213beac367083566cedf30cdc5149906
BLAKE2b-256 6b8052d1b1c07b034a3f0510580b6f0e4dd8d0c1bdee0b43047a63b2bd6ffe2c

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-win_amd64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-win_amd64.whl
Algorithm Hash digest
SHA256 d89fd44afac289ac02eb2acdd6e53c5300724340d4140ce32f92fc3db83b8be9
MD5 941c1c1f65bf88f033b9f85ac50c6b08
BLAKE2b-256 cb2e08f581b0f44742a0d347d4ba38e4046cc883bd41a3b319e03cd5204a45bc

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-win32.whl.

File metadata

  • Download URL: stringzilla-3.9.8-cp36-cp36m-win32.whl
  • Upload date:
  • Size: 64.2 kB
  • Tags: CPython 3.6m, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.1 CPython/3.12.6

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-win32.whl
Algorithm Hash digest
SHA256 7563f79f89539dd69d3795d47226c4a46c4a07cfb843ea1266a90fda2c259ba6
MD5 d84128ff69232bd89735579c48d83d07
BLAKE2b-256 dd4696c5c5a3add1c7c4b3c758f5bebc2bae556cab2edb2791736cdffa20067e

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9dc3558f167f1a8d6359c8ee018d1e4a1cd0c2dee9b312232f2aef31d6c13ad1
MD5 b35869bfe76d2e8cc9bce57f16768cf5
BLAKE2b-256 dc9f8cb565135561284a4001e043ac18a9cf4745fca13a9d6c62c958893cd41e

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_s390x.whl
Algorithm Hash digest
SHA256 d059e6d2d5e92e5c90a8aa27247e23384604b2b326862ee68e4b53a6b24e24d2
MD5 aee5b8f5c7cb5a4ad7e9a43ead38a315
BLAKE2b-256 9e1f1e1fa88d2ee57c1d4d2ddf51384b113ea15b29d46eba2e38d0ae2ceb8c38

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_ppc64le.whl
Algorithm Hash digest
SHA256 92da2c251610580a1c169e0a5318f7211a76fb18ac4f9ddb1f7ff809daca0e13
MD5 920aa7e6dd7ff9afa337e7207c99fcb7
BLAKE2b-256 5aff5cde72e22dfa90d5d73aa7ddb64581f662163aee006e0651b58b019500e9

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 60b12f1b2eab96d2f7b98d71d2287ff821af55957ff1106cb15664cced973d31
MD5 34d45cf16a59a1a5c132cfe0f9179a68
BLAKE2b-256 8bb3ac928dc25695a5447049c3e754b3a9b7d38447a007b151e9b6485127e46c

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 7fad8ed5f254d6395c9b38528e29d2ca9c74194e30c3d27184231721294066e6
MD5 7c8e7f40e2fd2c8a0655c9f7e6b40e77
BLAKE2b-256 8fb387d016fb06bcc647560b6d01a10d38b12f7e4cc29fc17f2905ab10b34955

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 afdb938faa435dd83981a0f21a7220fae98521bc4af69b13345b81e31ca9bfcc
MD5 065eaf6ac0bd19f39b282b2f1423a543
BLAKE2b-256 a0f398e839ae9647bbdc113da84a8698452ddbb1185fc89e9537adeca44916e1

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl
Algorithm Hash digest
SHA256 b58e1147eef1995f6303407b600a09107c747ef7739c003c064c3e633676d439
MD5 914464c24c9a20052e19eb26b78a3f4c
BLAKE2b-256 458350dd5ff2ed9a1589f0f19a151105e64b6bb8432911249ef959a87af36c99

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl
Algorithm Hash digest
SHA256 a8eff8b3f8ad83fc356c36502e8a508fd6657b1c516d7797c97c95f5a6f64080
MD5 d7a1709940a247e3c1efd6ee087e6158
BLAKE2b-256 311123c1af5488bd6107541ea0510f8af8f6087a877d536f87535a5f183cec14

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 448f5018f3e3451461996fa50c2240a7b7ae63891f61ba496d1dc98f283a11ee
MD5 5787517937c9ea577867dce0acd1e424
BLAKE2b-256 ccdfb27190522212623273ecdc425ac3a5c4f7518a375076d3da88dee0face25

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 aea6b0008238bcc03fa4734426597777c277d224450f2aa18f11a203881a2f9c
MD5 c4584e3f9ed2e0b74963023a62bb0c96
BLAKE2b-256 b73c8a5699d9f61dc33625470ab2ce5b14ccd27c9d8bb7dc05c9078924bec350

See more details on using hashes here.

File details

Details for the file stringzilla-3.9.8-cp36-cp36m-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for stringzilla-3.9.8-cp36-cp36m-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 e8144dd8862ecb0d170581d1d740cff5681d0fb10893d7e4984e3e14752583b0
MD5 f126e9d81914d0f419d03408f579c32c
BLAKE2b-256 85edaecbcef59c2cda0b25402df972bcd28c605a795eb7518e3366471dd8c9c5

See more details on using hashes here.

Supported by

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