C · Memory Operations

Memory Operations

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

§ 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. The owning sz_string_t container, its union layout, and the full lifecycle API are documented under String Collections and Containers; this section covers the design rationale behind that layout.

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

libstdc++ in GCC 13libc++ in Clang 17StringZilla
String sizeof322432
Inner Capacity152222

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, covered with a worked example under String Collections and Containers.

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

sz_ptr_t string_start;
sz_size_t string_length;
sz_string_range(&string, &string_start, &string_length);
printf("%.*s\n", (int)string_length, string_start);

API

Types

sz_allocator_tSome complex pattern matching algorithms may require memory allocations.
types.h:1289 ↗
struct sz_allocator_t

This structure passes the memory allocator to those functions.

Every function takes the caller's stream, which on a GPU names the device a block is made on and the work a release waits behind; host allocators ignore it, and on the CPU it is null. The optional reallocate keeps the first min(old_bytes, new_bytes) bytes, resizing the block where it lies when it can and moving it otherwise, and leaves the block as it was on failure. Without it, a block that must change size moves through allocate and free.

Fields

allocatesz_allocate_t
reallocatesz_reallocate_t
freesz_free_t
handlevoid *

See also

Functions

sz_u16_loadLoad a 16-bit unsigned integer from a potentially unaligned pointer, slow on some platforms.
types.h:2262 ↗
sz_u16_vec_t sz_u16_load(sz_cptr_t ptr);
sz_u32_loadLoad a 32-bit unsigned integer from a potentially unaligned pointer, slow on some platforms.
types.h:2282 ↗
sz_u32_vec_t sz_u32_load(sz_cptr_t ptr);
sz_u64_loadLoad a 64-bit unsigned integer from a potentially unaligned pointer, slow on some platforms.
types.h:2304 ↗
sz_u64_vec_t sz_u64_load(sz_cptr_t ptr);
sz_u16_storeStore a 16-bit unsigned integer to a potentially unaligned pointer, slow on some platforms.
types.h:2330 ↗
void sz_u16_store(sz_ptr_t ptr, sz_u16_t value);
sz_u32_storeStore a 32-bit unsigned integer to a potentially unaligned pointer, slow on some platforms.
types.h:2348 ↗
void sz_u32_store(sz_ptr_t ptr, sz_u32_t value);
sz_u64_storeStore a 64-bit unsigned integer to a potentially unaligned pointer, slow on some platforms.
types.h:2368 ↗
void sz_u64_store(sz_ptr_t ptr, sz_u64_t value);
sz_allocator_init_heapInitializes a memory allocator to use the system default malloc and free.
types.h:2463 ↗
sz_status_t sz_allocator_init_heap(sz_allocator_t *allocator);

Parameters

allocatoroutMemory allocator to initialize.

Notes

Unlike the C standard library, malloc(0) is guaranteed to return a null pointer.

See also

Statuses

sz_allocator_init_arenaInitializes a memory allocator that serves every request from a static-capacity buffer, without any dynamic allocations.
types.h:2476 ↗
sz_status_t sz_allocator_init_arena(
    sz_allocator_t *allocator,
    void *buffer,
    sz_size_t bytes,
    sz_size_t alignment);

Failure leaves both the allocator and buffer unchanged. Three aligned sz_size_t values store capacity, consumption and alignment inside the buffer.

Parameters

allocatoroutMemory allocator to initialize.
bufferinBuffer to use for allocations.
bytesinBuffer size, including metadata and alignment padding.
alignmentinNonzero power-of-two alignment guaranteed for every returned block.

Statuses

sz_allocator_equalChecks if two memory allocators are equivalent.
types.h:2494 ↗
sz_bool_t sz_allocator_equal(
    sz_allocator_t const *a,
    sz_allocator_t const *b);

Parameters

ainFirst memory allocator.
binSecond memory allocator.

Returns

True if the allocators are the same, false otherwise.

sz_allocator_init_unified_bestInitializes an allocator whose blocks both the host and the device of capabilities address: the host heap on the CPU, managed memory on CUDA and ROCm, shared buffers on Metal.
strings.h:1081 ↗
sz_status_t sz_allocator_init_unified_best(
    sz_allocator_t *allocator,
    sz_capability_t capabilities);

Backends

  • sz_allocator_init_unifiedserial

The allocator is stateless, its handle null, and each call allocates on the device of the stream it is given, so one allocator serves every device of its vendor.

Parameters

allocatoroutThe allocator to initialize.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cuda reports; its group picks the CPU or a GPU vendor.

Statuses

sz_allocator_init_device_bestInitializes device storage on CUDA and ROCm, or unified storage on Metal.
strings.h:1086 ↗
sz_status_t sz_allocator_init_device_best(
    sz_allocator_t *allocator,
    sz_capability_t capabilities);

Each callback uses its stream's device. CPU returns sz_missing_kernel_k; GPU vendors omitted from the build return sz_missing_gpu_k.

sz_allocator_init_pinned_bestInitializes page-locked CUDA or ROCm host storage, using each callback's stream.
strings.h:1090 ↗
sz_status_t sz_allocator_init_pinned_best(
    sz_allocator_t *allocator,
    sz_capability_t capabilities);

CPU and Metal return sz_missing_kernel_k; unbuilt GPU vendors return sz_missing_gpu_k.