Repository: ashvardanian/StringZilla (language: rust)

Issue:
Documentation is incorrect? `sz_string_append` does not exist
In the readme, a function named `sz_string_append` is referenced, but looking through the source code, its not defined at all, and I cannot use it in any code


Discussion / hints:
You are right! It was superseded by the expand API, and the docs fell behind. Can you please open a PR to refresh those? Thanks!
Will do, I am currently adding Lua bindings to this library, and that will be in a later PR aswell
Might be a good idea to split into separate smaller PRs, what do you think @Frityet?
> Might be a good idea to split into separate smaller PRs, what do you think @Frityet?

yeah, that is better, I'm still tryna get a hand with the new API (i don't see any documentation, so i am just doing testing) so it will be a bit
What do you mean by the lack of docs? I believe the header is quite extensively documented 🤷‍♂️

Fix patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8f23584a..a844cbdc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -374,6 +374,17 @@ echo "export PATH=/usr/share/swift/usr/bin:$PATH" >> ~/.bashrc
 source ~/.bashrc
 ```
 
+You can check the available images on [`swift.org/download` page](https://www.swift.org/download/#releases).
+For x86 CPUs, the following commands would work:
+
+```bash
+wget https://download.swift.org/swift-5.9.2-release/ubuntu2204/swift-5.9.2-RELEASE/swift-5.9.2-RELEASE-ubuntu22.04.tar.gz
+tar xzf swift-5.9.2-RELEASE-ubuntu22.04.tar.gz
+sudo mv swift-5.9.2-RELEASE-ubuntu22.04 /usr/share/swift
+echo "export PATH=/usr/share/swift/usr/bin:$PATH" >> ~/.bashrc
+source ~/.bashrc
+```
+
 Alternatively, on Linux, the official Swift Docker image can be used for builds and tests:
 
 ```bash
diff --git a/README.md b/README.md
index 6dbf5172..acd7bcff 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,16 @@
 # StringZilla 🦖
 
+_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 thoughput.
+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](https://static.pepy.tech/personalized-badge/stringzilla?period=total&units=abbreviation&left_color=black&right_color=blue&left_text=StringZilla%20Python%20installs)](https://github.com/ashvardanian/stringzilla)
 [![StringZilla Rust installs](https://img.shields.io/crates/d/stringzilla?logo=rust&label=Rust%20installs)](https://crates.io/crates/stringzilla)
 [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/ashvardanian/StringZilla/release.yml?branch=main&label=Ubuntu)](https://github.com/ashvardanian/StringZilla/actions/workflows/release.yml)
@@ -20,12 +31,14 @@ It __accelerates exact and fuzzy string matching, edit distance computations, so
 - 🐍 __[Python](#quick-start-python-🐍):__ Upgrade your `str` to faster `Str`
 - 🍎 __[Swift](#quick-start-swift-🍏):__ Use the `String+StringZilla` extension
 - 🦀 __[Rust](#quick-start-rust-🦀):__ Use the `StringZilla` traits crate
-- 🐚 __[Shell][faq-shell]__: Accelerate common CLI tools
+- 🐚 __[Shell][faq-shell]__: Accelerate common CLI tools with `sz_` prefix
 - 📚 Researcher? Jump to [Algorithms & Design Decisions](#algorithms--design-decisions-📚)
-- 🤝 Want to benchmark or contribute? Jump to [Contributing](CONTRIBUTING.md)
-- Code in other languages? Let [me](https://github.com/ashvardanian) know!
+- 💡 Thinking to contribute? Look for ["good first issues"][first-issues]
+- 🤝 And check the [guide](CONTRIBUTING.md) to setup the environment
+- Want more bindings or features? Let [me](https://github.com/ashvardanian) know!
 
 [faq-shell]: https://github.com/ashvardanian/StringZilla/blob/main/cli/README.md
+[first-issues]: https://github.com/ashvardanian/StringZilla/issues
 
 __Who is this for?__
 
@@ -641,8 +654,8 @@ sz_string_is_on_stack(&string); // == sz_true_k
 sz_string_grow(&string, 100, &allocator); // == sz_true_k
 
 // Append, erase, insert into the string.
-sz_string_append(&string, "_Hello_", 7, &allocator); // == sz_true_k
-sz_string_append(&string, "world", 5, &allocator); // == sz_true_k
+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.
@@ -1279,6 +1292,13 @@ If you like this project, you may also enjoy [USearch][usearch], [UCall][ucall],
 [uform]: https://github.com/unum-cloud/uform
 [simsimd]: https://github.com/ashvardanian/simsimd
 
+If you like strings and value efficiency, you may also enjoy the following projects:
+
+- [simdutf](https://github.com/simdutf/simdutf) - transcoding UTF8, UTF16, and UTF32 LE and BE.
+- [hyperscan](https://github.com/intel/hyperscan) - regular expressions with SIMD acceleration.
+- [pyahocorasick](https://github.com/WojciechMula/pyahocorasick) - Aho-Corasick algorithm in Python.
+- [rapidfuzz](https://github.com/rapidfuzz/RapidFuzz) - fast string matching in C++ and Python.
+
 ## License 📜
 
 Feel free to use the project under Apache 2.0 or the Three-clause BSD license at your preference.
diff --git a/cli/README.md b/cli/README.md
index 0a75d30d..06f51216 100644
--- a/cli/README.md
+++ b/cli/README.md
@@ -1,13 +1,14 @@
 # SIMD-accelerated CLI utilities based on StringZilla
 
-This section of the project is pretty much a work-in-progress.
+This section of the project is pretty much a work in progress.
 The goal is to provide a set of command-line utilities that:
 
-- ✅ are accelerated by SIMD instructions, 
-- ✅ are extremely core StringZilla functionality,
-- ✅ work the same on Linux, MacOS, and Windows.
+- ✅ that benefit the most from SIMD instructions, 
+- ✅ rely solely on core StringZilla functionality,
+- ✅ works the same on Linux, MacOS, and Windows.
 
-To install, just pull the Python package from PyPi:
+Other utilities are, of course, welcome to use StringZilla but may not be good candidates for this repository.
+To install, pull the Python package from PyPi:
 
 ```bash
 pip install stringzilla
diff --git a/include/stringzilla/stringzilla.h b/include/stringzilla/stringzilla.h
index dd394ca2..5811b8ef 100644
--- a/include/stringzilla/stringzilla.h
+++ b/include/stringzilla/stringzilla.h
@@ -2879,10 +2879,11 @@ SZ_INTERNAL sz_u8_t sz_u8_toupper(sz_u8_t c) {
  *  @brief  Uses two small lookup tables (768 bytes total) to accelerate division by a small
  *          unsigned integer. Performs two lookups, one multiplication, two shifts, and two accumulations.
  *
- *  @param  divisor Integral value larger than one.
+ *  @param  divisor Integral value @b larger than one.
  *  @param  number  Integral value to divide.
  */
 SZ_INTERNAL sz_u8_t sz_u8_divide(sz_u8_t number, sz_u8_t divisor) {
+    sz_assert(divisor > 1);
     static sz_u16_t const multipliers[256] = {
         0,     0,     0,     21846, 0,     39322, 21846, 9363,  0,     50973, 39322, 29790, 21846, 15124, 9363,  4370,
         0,     57826, 50973, 44841, 39322, 34329, 29790, 25645, 21846, 18351, 15124, 12137, 9363,  6780,  4370,  2115,
@@ -2975,13 +2976,16 @@ SZ_PUBLIC void sz_generate(sz_cptr_t alphabet, sz_size_t alphabet_size, sz_ptr_t
 
     sz_assert(alphabet_size > 0 && alphabet_size <= 256 && "Inadequate alphabet size");
 
-    if (alphabet_size == 1)
-        for (sz_cptr_t end = result + result_length; result != end; ++result) *result = *alphabet;
+    if (alphabet_size == 1) sz_fill(result, result_length, *alphabet);
 
     else {
         sz_assert(generator && "Expects a valid random generator");
-        for (sz_cptr_t end = result + result_length; result != end; ++result)
-            *result = alphabet[sz_u8_divide(generator(generator_user_data) & 0xFF, (sz_u8_t)alphabet_size)];
+        sz_u8_t divisor = (sz_u8_t)alphabet_size;
+        for (sz_cptr_t end = result + result_length; result != end; ++result) {
+            sz_u8_t random = generator(generator_user_data) & 0xFF;
+            sz_u8_t quotient = sz_u8_divide(random, divisor);
+            *result = alphabet[random - quotient * divisor];
+        }
     }
 }
 
diff --git a/include/stringzilla/stringzilla.hpp b/include/stringzilla/stringzilla.hpp
index 0c8e1bd1..daf47d50 100644
--- a/include/stringzilla/stringzilla.hpp
+++ b/include/stringzilla/stringzilla.hpp
@@ -3160,7 +3160,8 @@ class basic_string {
      *  @param  alphabet   A string of characters to choose from.
      */
     basic_string &randomize(string_view alphabet = "abcdefghijklmnopqrstuvwxyz") noexcept {
-        return randomize(&std::rand, alphabet);
+        auto generator = []() { return static_cast<sz_u64_t>(std::rand()); };
+        return randomize(generator, alphabet);
     }
 
     /**


Test patch:
diff --git a/scripts/test.cpp b/scripts/test.cpp
index f8d4af25..80f43442 100644
--- a/scripts/test.cpp
+++ b/scripts/test.cpp
@@ -102,6 +102,10 @@ static void test_arithmetical_utilities() {
     assert(sz_size_bit_ceil((1ull << 62) + 1) == (1ull << 63));
     assert(sz_size_bit_ceil((1ull << 63)) == (1ull << 63));
 #endif
+
+    for (sz_u16_t number = 0; number != 256; ++number)
+        for (sz_u16_t divisor = 2; divisor != 256; ++divisor)
+            assert(sz_u8_divide(number, divisor) == (number / divisor));
 }
 
 /**
@@ -640,6 +644,14 @@ void test_api_mutable_extensions() {
 
     assert(str(sz::concatenate("a"_sz, "b"_sz)) == "ab");
     assert(str(sz::concatenate("a"_sz, "b"_sz, "c"_sz)) == "abc");
+
+    // Randomization.
+    assert(str::random(0).empty());
+    assert(str::random(4, "a") == "aaaa");
+    assert(str::random(4, "aaaa") == "aaaa");
+    assert(str::random(global_random_generator(), 4, "aaaa") == "aaaa");
+    assert_scoped(str s = str::random(128, "ACGT"), (void)s,
+                  s.contains('A') && s.contains('C') && s.contains('G') && s.contains('T'));
 }
 
 /**