# Memory Operations

> StringZilla for C++

### 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][faq-sso] (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](https://www.unum.cloud/docs/stringzilla/cpp/sorting-and-sets.md#string-collections-and-containers); this section covers the design rationale behind that layout.

[faq-sso]: https://cpp-optimizations.netlify.app/small_strings/

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](https://gist.github.com/ashvardanian/c197f15732d9855c4e070797adf17b21).

|                 | `libstdc++` in GCC 13 | `libc++` in Clang 17 | StringZilla |
| :-------------- | --------------------: | -------------------: | ----------: |
| String `sizeof` |                    32 |                   24 |          32 |
| Inner Capacity  |                    15 |               __22__ |      __22__ |

This design has been since ported to many high-level programming languages.
Swift, for example, [can store 15 bytes](https://developer.apple.com/documentation/swift/substring/withutf8(_:)#discussion) 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](https://www.unum.cloud/docs/stringzilla/cpp/sorting-and-sets.md#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.

```c
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);
```

`#include <stringzilla/types.hpp>`

## heap_alloc

Nullable heap allocator using the C allocation policy.

```cpp
template <typename value_type_>
struct heap_alloc
```

## unified_alloc

Allocator over the __unified__ memory of one device group, which the host and that group's devices all address.

```cpp
template <typename value_type_,
          sz_capability_t capabilities_ = sz_cap_serial_k>
struct unified_alloc
```

Nullable allocator for [strings](https://www.unum.cloud/docs/stringzilla/cpp/types.md#strings) and [vector](https://www.unum.cloud/docs/stringzilla/cpp/types.md#vector). `capabilities_` picks the default vendor; an initialized C allocator can select it at runtime. The allocator handle and stream must outlive its allocations; a null stream uses the vendor's default device. Failure returns null; [`make`](https://www.unum.cloud/docs/stringzilla/cpp/runtime-dispatch.md#make) reports initialization errors.

- `unified` `sz_allocator_t`
- `stream` `sz_stream_t`

