C · Unicode Segmentation

Unicode Segmentation

#include <stringzilla/capabilities.h>#include <stringzilla/utf8_runes.h>#include <stringzilla/utf8_tokens.h>#include <stringzilla/utf8_wordbreaks.h>#include <stringzilla/utf8_graphemes.h>#include <stringzilla/utf8_sentences.h>#include <stringzilla/utf8_linebreaks.h> 6.0.0-rc.1 · 91a27bdd

Splitting Unicode text into the units a human actually perceives is deceptively hard, and getting it wrong corrupts data. A single emoji can be dozens of bytes and several codepoints yet one perceived character, CJK runs carry no spaces, and a period is not always the end of a sentence. StringZilla ships the real algorithms — UAX-29 graphemes, words, and sentences, plus UAX-14 line-break opportunities — as lazy ranges that borrow from the source and yield one sz::string_view_t per segment with no per-segment allocation.

A string’s length is really three different numbers, and only the grapheme count matches what a user sees:

#include <stringzilla/stringzilla.hpp>
#include <cassert>
namespace sz = ashvardanian::stringzilla;

int main() {
    sz::string_view_t family = "👨‍👩‍👧‍👦"; // one emoji, one perceived character

    std::size_t codepoints = 0;
    for (sz_rune_t r : family.utf8_runes()) (void)r, ++codepoints;
    std::size_t graphemes = 0;
    for (sz::string_view_t g : family.utf8_graphemes()) (void)g, ++graphemes;

    assert(family.size() == 25); // 25 bytes on the wire
    assert(codepoints == 7); // four people joined by three zero-width joiners
    assert(graphemes == 1); // one grapheme cluster
    return 0;
}

This is exactly why truncating by bytes or codepoints tears emoji apart — it can slice a skin-tone modifier off its base, or split a flag in half. Iterating graphemes lets you cut on a real boundary:

sz::string_view_t msg = "🙏🏽👍🏿✨ thanks";
std::size_t cut = 0, seen = 0;
for (sz::string_view_t g : msg.utf8_graphemes()) { if (seen++ == 3) break; cut += g.size(); }
assert(msg.sub(0, cut) == "🙏🏽👍🏿✨"); // the three emoji keep their skin-tone modifiers

Word and sentence boundaries are just as treacherous: contractions, CJK, decimals, and URLs all defeat naive splitting. UAX-29 keeps can't whole while separating CJK ideographs that no space divides, and refuses to break a sentence inside $9.99:

sz::string_view_t phrase = "can't stop 北京!";
assert(*phrase.utf8_wordbreaks().begin() == "can't"); // apostrophe is interior; 北 and 京 split apart

sz::string_view_t prose = "She paid $9.99. Cheap.";
std::size_t sentences = 0;
for (sz::string_view_t s : prose.utf8_sentences()) (void)s, ++sentences;
assert(sentences == 2); // the dot inside $9.99 is not a sentence break

The full family of ranges, each borrowing from the source and yielding sz::string_view_t segments, or sz_rune_t for runes. Naming follows one rule: the bare name (newlines/whitespaces/delimiters) yields the separators the kernel finds, while split_* yields the content between them:

  • utf8_runes() — every codepoint as a decoded sz_rune_t UTF-32 scalar, with U+FFFD for ill-formed bytes and a truncated tail.
  • utf8_graphemes() — UAX-29 grapheme clusters, the user-perceived characters.
  • utf8_wordbreaks() — all UAX-29 word segments (words and the separators between them).
  • utf8_sentences() — UAX-29 sentence boundaries.
  • utf8_linebreaks() — UAX-14 line-break opportunities, both hard breaks and soft wrap points.
  • utf8_split_newlines() / utf8_newlines() — content between the seven Unicode newlines (CRLF as one), or the newline runs themselves.
  • utf8_split_whitespaces() / utf8_whitespaces() — content between Unicode “White_Space” runs (tokens), or the whitespace runs.
  • utf8_split_delimiters() / utf8_delimiters() — content between any Unicode punctuation/symbol/separator, or the delimiter runs.

On any split_* range, .skip_empty() drops empty segments and .with_separators() interleaves segments and separators losslessly (concatenation reconstructs the input). The utf8_wordbreaks, utf8_graphemes, utf8_sentences, and utf8_linebreaks ranges tile the input — every byte belongs to exactly one segment, with no gaps and no empty slices. Because every range borrows and walks the buffer once, segmenting a multi-megabyte document into graphemes or words allocates nothing.

In C, sz_utf8_graphemes_best and its three tiling siblings write one length per segment, each segment starting where the previous one ended, so after a full batch the caller resumes at the sum of its lengths. The newline, whitespace and delimiter finders write offsets and lengths of their matches, and after a full batch bytes_consumed ends exactly at the last match; otherwise it is the whole input. sz_utf8_decode_best treats the end of the text as the end of the input, decoding a truncated final sequence to one U+FFFD, so a caller feeding it chunks splits them at a rune boundary.

API

Types

sz_kernel_utf8_seek_tSignature of the kernels behind sz_utf8_seek_best.
capabilities.h:710 ↗
typedef sz_status_t(*) sz_kernel_utf8_seek_t(sz_cptr_t, sz_size_t, sz_size_t, sz_cptr_t *, sz_stream_t);
sz_kernel_utf8_decode_tSignature of the kernels behind sz_utf8_decode_best.
capabilities.h:713 ↗
typedef sz_status_t(*) sz_kernel_utf8_decode_t(sz_cptr_t, sz_size_t, sz_rune_t *, sz_size_t, sz_size_t *, sz_size_t *, sz_stream_t);
sz_kernel_utf8_segmenter_tSignature of the tiling segmenters - graphemes, words, sentences, lines.
capabilities.h:747 ↗
typedef sz_status_t(*) sz_kernel_utf8_segmenter_t(sz_cptr_t, sz_size_t, sz_size_t *, sz_size_t, sz_size_t *, sz_stream_t);

Emits one length per segment and their count; each segment starts where the previous one ended.

sz_kernel_utf8_tokenizer_tSignature of the token kernels - newlines, whitespace, delimiters.
capabilities.h:752 ↗
typedef sz_status_t(*) sz_kernel_utf8_tokenizer_t(sz_cptr_t, sz_size_t, sz_size_t *, sz_size_t *, sz_size_t, sz_size_t *, sz_size_t *, sz_stream_t);

Emits parallel (offset, length) arrays for each match, their count, and a resume bytes_consumed.

Functions

sz_utf8_seek_bestSkip forward to the Nth UTF-8 character.
utf8_runes.h:103 ↗
sz_status_t sz_utf8_seek_best(
    sz_cptr_t text,
    sz_size_t length,
    sz_size_t n,
    sz_cptr_t *position,
    sz_capability_t capabilities,
    sz_stream_t stream);

Backends

  • sz_utf8_seekserialhaswellicelakeneonsve2rvvv128v128relaxedloongsonasxpowervsx

Skipping to character 1000, e.g. for pagination:

char const *position;
sz_utf8_seek_best(text, length, 1000, &position, capabilities, NULL);
if (!position) {
    // String has fewer than 1000 characters
}

Truncating to 280 characters, Twitter-style:

char const *end;
sz_utf8_seek_best(text, length, 280, &end, capabilities, NULL);
size_t truncated_bytes = end ? (end - text) : length;

Parameters

textinString to be scanned.
lengthinNumber of bytes in the string.
ninNumber of UTF-8 characters to skip, 0-indexed, so n = 0 yields text.
positionoutThe Nth character, or NULL if the string has fewer than n characters.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu reports.
streaminNull on the CPU, or the GPU stream of that device to queue on.

Statuses

sz_utf8_decode_bestUnpack a UTF-8 string into UTF-32 codepoints.
utf8_runes.h:152 ↗
sz_status_t sz_utf8_decode_best(
    sz_cptr_t text,
    sz_size_t length,
    sz_rune_t *runes,
    sz_size_t runes_capacity,
    sz_size_t *runes_count,
    sz_size_t *bytes_consumed,
    sz_capability_t capabilities,
    sz_stream_t stream);

Backends

  • sz_utf8_decodeserialhaswellicelakeneonsve2rvvv128loongsonasxpowervsx

This function is designed for streaming-like decoding with smart iterators built on top of it. The iterator would unpack a continuous slice of UTF-8 text into UTF-32 codepoints in chunks, yielding them upstream - only one at a time. This avoids allocating large buffers for the entire UTF-32 string, which can be 4x the size of the UTF-8 input.

This functionality is similar to the simdutf library's UTF-8 to UTF-32 conversion routines, and leverages an assumption that the absolute majority of written text doesn't mix codepoints of every length in each register-sized chunk:

  • English text and source code is predominantly 1-byte ASCII characters.
  • Broader European languages with diacritics: mostly 2-byte characters, 1-byte punctuation.
  • Chinese & Japanese mostly use 3-byte characters with rare 1- or 3-byte punctuation.
  • Korean uses 3-byte characters with 1-byte spaces; word are 2-6 syllables or 6-16 bytes.

It's a different story for emoji-heavy texts, which can mix 4-byte characters more frequently.

Every backend shares one contract, the basis for every codepoint iterator built on it:

  • Fill-or-drain: emits runes until runes_capacity is reached or text is exhausted, looping internally - one call fills the buffer however many byte-widths the text mixes.
  • Total and safe: never reads past text + length; substitutes one U+FFFD per maximal ill-formed subpart (overlong, surrogate, out-of-range, or a stray byte) and resyncs.
  • Valid scalar values: every emitted rune is a Unicode scalar value (incl. U+FFFD), so callers may convert without re-validation.

End of text is end of input: a well-formed but truncated final sequence decodes to one U+FFFD over its maximal subpart and is consumed, so "a\xE2\x82" yields {'a', U+FFFD} over all 3 bytes. Only a full runes buffer stops early, so bytes_consumed falls short of length only when runes_count reaches runes_capacity, and then at a rune boundary. Callers decoding a stream in chunks split it at a rune boundary.

Parameters

textinUTF-8 string to unpack.
lengthinNumber of bytes in the string.
runesoutBuffer for UTF-32 codepoints, recommended to be at least 64 entries wide.
runes_capacityinCapacity of the runes buffer, in sz_rune_t entries.
runes_countoutNumber of runes unpacked.
bytes_consumedoutBytes of text decoded, the offset the next call resumes at.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu reports.
streaminNull on the CPU, or the GPU stream of that device to queue on.

Statuses

sz_utf8_*_find_kernel× 2Finds the UTF-8 runes kernel of kind, from the best of capabilities.
utf8_runes.h:169 ↗
sz_status_t sz_utf8_runes_find_kernel(
    sz_kernel_kind_t kind,
    sz_capability_t capabilities,
    sz_kernel_punned_t *kernel,
    sz_capability_t *capability);
Symbol
sz_utf8_runes_find_kernel
sz_utf8_tokens_find_kernel

Parameters

kindinThe verb whose kernel to find.
capabilitiesinThe mask to pick the best capability from.
kerneloutThe kernel, or null when none of capabilities has it.
capabilityoutThe capability the kernel belongs to, or zero.

Statuses

sz_utf8_newlines_bestEnumerates every UTF-8 newline delimiter in a string.
utf8_tokens.h:59 ↗
sz_status_t sz_utf8_newlines_best(
    sz_cptr_t text,
    sz_size_t length,
    sz_size_t *match_offsets,
    sz_size_t *match_lengths,
    sz_size_t matches_capacity,
    sz_size_t *matches_count,
    sz_size_t *bytes_consumed,
    sz_capability_t capabilities,
    sz_stream_t stream);

Backends

  • sz_utf8_newlinesserialhaswellicelakeneonsve2rvvv128loongsonasxpowervsx

Enumerates every newline delimiter in a single sweep: writes the byte offset and byte length of each match into the parallel match_offsets and match_lengths arrays, a "\r\n" CRLF being one match of length 2, and their number into matches_count. A caller resuming from text + *bytes_consumed after a full output obtains the identical remainder.

Here are all the UTF-8 newline characters we are looking for (7 characters + CRLF):

  • single-byte chars (4 total):

    • U+000A for "\n" (LINE FEED)
    • U+000B for "\v" (VERTICAL TAB / LINE TABULATION)
    • U+000C for "\f" (FORM FEED)
    • U+000D for "\r" (CARRIAGE RETURN)
  • double-byte chars (1 total):

    • U+0085 for 0xC285 (NEXT LINE)
  • triple-byte chars (2 total):

    • U+2028 for 0xE280A8 (LINE SEPARATOR)
    • U+2029 for 0xE280A9 (PARAGRAPH SEPARATOR)
  • double-character sequence:

    • U+000D U+000A for "\r\n" that should be treated as a single new line!

U+001C, U+001D, U+001E (FILE/GROUP/RECORD SEPARATOR) are not included. These are data structure delimiters used in formats like USV (Unicode Separated Values), not line breaks. Use sz_find_byte_best if you need to find these separators.

Parameters

textinString to be scanned.
lengthinNumber of bytes in the string.
match_offsetsoutDelimiter start offsets, at least matches_capacity entries.
match_lengthsoutDelimiter byte lengths, at least matches_capacity entries.
matches_capacityinCapacity of the output arrays.
matches_countoutNumber of delimiters written to the output arrays.
bytes_consumedoutOptional resume offset: once matches_count reaches matches_capacity, the end of the last match, or zero with no capacity; else length.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu reports.
streaminNull on the CPU, or the GPU stream of that device to queue on.

Statuses

sz_utf8_whitespaces_bestEnumerates every UTF-8 whitespace delimiter in a string.
utf8_tokens.h:132 ↗
sz_status_t sz_utf8_whitespaces_best(
    sz_cptr_t text,
    sz_size_t length,
    sz_size_t *match_offsets,
    sz_size_t *match_lengths,
    sz_size_t matches_capacity,
    sz_size_t *matches_count,
    sz_size_t *bytes_consumed,
    sz_capability_t capabilities,
    sz_stream_t stream);

Backends

  • sz_utf8_whitespacesserialhaswellicelakeneonsve2rvvv128loongsonasxpowervsx

Enumerates every whitespace delimiter in a single sweep, with the same contract as sz_utf8_newlines_best: writes the byte offset and byte length of each match into the parallel match_offsets and match_lengths arrays, their number into matches_count, and sets bytes_consumed to the resume offset. Each whitespace codepoint is one match: CR and LF are independent length-1 matches, as there is no CRLF merging in the whitespace set.

Implements the Unicode White_Space property, 25 characters in total. Per the Unicode standard, whitespace includes all newline characters plus horizontal spaces. Matches the behavior of ICU's u_isspace() and Python's str.isspace().

  • single-byte chars (6 total):

    • U+0009 tab "\t" (CHARACTER TABULATION)
    • U+000A "\n" (LINE FEED - newline)
    • U+000B "\v" (LINE TABULATION - newline)
    • U+000C "\f" (FORM FEED - newline)
    • U+000D "\r" (CARRIAGE RETURN - newline)
    • U+0020 (SPACE)
  • double-byte chars (2 total):

    • U+0085 0xC285 (NEXT LINE - newline)
    • U+00A0 0xC2A0 (NO-BREAK SPACE)
  • triple-byte chars (17 total):

    • U+1680 0xE19A80 (OGHAM SPACE MARK)
    • U+2000 0xE28080 (EN QUAD)
    • U+2001 0xE28081 (EM QUAD)
    • U+2002 0xE28082 (EN SPACE)
    • U+2003 0xE28083 (EM SPACE)
    • U+2004 0xE28084 (THREE-PER-EM SPACE)
    • U+2005 0xE28085 (FOUR-PER-EM SPACE)
    • U+2006 0xE28086 (SIX-PER-EM SPACE)
    • U+2007 0xE28087 (FIGURE SPACE)
    • U+2008 0xE28088 (PUNCTUATION SPACE)
    • U+2009 0xE28089 (THIN SPACE)
    • U+200A 0xE2808A (HAIR SPACE)
    • U+2028 0xE280A8 (LINE SEPARATOR - newline)
    • U+2029 0xE280A9 (PARAGRAPH SEPARATOR - newline)
    • U+202F 0xE280AF (NARROW NO-BREAK SPACE)
    • U+205F 0xE2819F (MEDIUM MATHEMATICAL SPACE)
    • U+3000 0xE38080 (IDEOGRAPHIC SPACE)

The last one, the IDEOGRAPHIC SPACE (U+3000), is commonly used in East Asian typography, like Japanese formatted text or Chinese traditional poetry alignments.

Some implementations treat more codepoints as whitespace, but these are not included:

  • U+001C, U+001D, U+001E, U+001F (FILE/GROUP/RECORD/UNIT SEPARATOR) are data structure delimiters for formats like USV (Unicode Separated Values). Only Java's Character.isWhitespace() includes them; Unicode, ICU, and Python do not.
  • U+200B, U+200C, U+200D (ZERO WIDTH SPACE/NON-JOINER/JOINER) are Format characters, not whitespace. They have no width and affect rendering rather than spacing.

Parameters

textinString to be scanned.
lengthinNumber of bytes in the string.
match_offsetsoutDelimiter start offsets, at least matches_capacity entries.
match_lengthsoutDelimiter byte lengths, at least matches_capacity entries.
matches_capacityinCapacity of the output arrays.
matches_countoutNumber of delimiters written to the output arrays.
bytes_consumedoutOptional resume offset: once matches_count reaches matches_capacity, the end of the last match, or zero with no capacity; else length.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu reports.
streaminNull on the CPU, or the GPU stream of that device to queue on.

Statuses

sz_utf8_delimiters_bestEnumerates every UTF-8 delimiter codepoint (punctuation, symbol, separator, whitespace).
utf8_tokens.h:162 ↗
sz_status_t sz_utf8_delimiters_best(
    sz_cptr_t text,
    sz_size_t length,
    sz_size_t *match_offsets,
    sz_size_t *match_lengths,
    sz_size_t matches_capacity,
    sz_size_t *matches_count,
    sz_size_t *bytes_consumed,
    sz_capability_t capabilities,
    sz_stream_t stream);

Backends

  • sz_utf8_delimitersserialhaswellicelakeneonsve2rvvv128loongsonasxpowervsx

The general superset of sz_utf8_newlines_best and sz_utf8_whitespaces_best: every codepoint whose Unicode general category is a punctuation (P*), symbol (S*), or separator (Z*) is a delimiter. Shares the contract of sz_utf8_newlines_best: writes the byte offset and byte length of each match into the parallel match_offsets and match_lengths arrays, their number into matches_count, and sets bytes_consumed to the resume offset. A byte that does not begin a well-formed codepoint is skipped and never reported.

Parameters

textinString to be scanned.
lengthinNumber of bytes in the string.
match_offsetsoutDelimiter start offsets, at least matches_capacity entries.
match_lengthsoutDelimiter byte lengths, at least matches_capacity entries.
matches_capacityinCapacity of the output arrays.
matches_countoutNumber of delimiters written to the output arrays.
bytes_consumedoutOptional resume offset: once matches_count reaches matches_capacity, the end of the last match, or zero with no capacity; else length.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu reports.
streaminNull on the CPU, or the GPU stream of that device to queue on.

Statuses

sz_utf8_wordbreaks_bestSegment UTF-8 text into UAX-29 words in a single pass.
utf8_wordbreaks.h:41 ↗
sz_status_t sz_utf8_wordbreaks_best(
    sz_cptr_t text,
    sz_size_t length,
    sz_size_t *lengths,
    sz_size_t capacity,
    sz_size_t *count,
    sz_capability_t capabilities,
    sz_stream_t stream);

Backends

  • sz_utf8_wordbreaksserialhaswellicelakeneonsve2rvvv128loongsonasxpowervsx

Walks the input left-to-right and writes the byte length of each word into lengths. Words are the spans between consecutive TR29 boundaries and tile the input: each starts where the previous one ended, the first at text. A call covers all of text unless it fills lengths, in which case it covers the sum of the lengths it wrote, and the caller resumes from text advanced by that sum.

Parameters

textinUTF-8 encoded text.
lengthinByte length of text.
lengthsoutWord byte lengths, at least capacity entries.
capacityinCapacity of lengths, in entries.
countoutNumber of words written, at most capacity.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu reports.
streaminNull on the CPU, or the GPU stream of that device to queue on.

Notes

No zero-length words are emitted; length == 0 yields no words.

Statuses

sz_utf8_wordbreaks_find_kernelFinds the UTF-8 word break kernel of kind, from the best of capabilities.
utf8_wordbreaks.h:66 ↗
sz_status_t sz_utf8_wordbreaks_find_kernel(
    sz_kernel_kind_t kind,
    sz_capability_t capabilities,
    sz_kernel_punned_t *kernel,
    sz_capability_t *capability);

Parameters

kindinThe verb whose kernel to find.
capabilitiesinThe mask to pick the best capability from.
kerneloutThe kernel, or null when none of capabilities has it.
capabilityoutThe capability the kernel belongs to, or zero.

Statuses

sz_utf8_graphemes_bestSegment UTF-8 text into UAX-29 grapheme clusters in a single pass.
utf8_graphemes.h:41 ↗
sz_status_t sz_utf8_graphemes_best(
    sz_cptr_t text,
    sz_size_t length,
    sz_size_t *lengths,
    sz_size_t capacity,
    sz_size_t *count,
    sz_capability_t capabilities,
    sz_stream_t stream);

Backends

  • sz_utf8_graphemesserialhaswellicelakeneonsve2

Walks the input left-to-right and writes the byte length of each grapheme cluster into lengths. Clusters are the spans between consecutive UAX-29 grapheme boundaries (GB1-GB999) and tile the input: each starts where the previous one ended, the first at text. A call covers all of text unless it fills lengths, in which case it covers the sum of the lengths it wrote, and the caller resumes from text advanced by that sum.

Parameters

textinUTF-8 encoded text.
lengthinByte length of text.
lengthsoutCluster byte lengths, at least capacity entries.
capacityinCapacity of lengths, in entries.
countoutNumber of clusters written, at most capacity.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu reports.
streaminNull on the CPU, or the GPU stream of that device to queue on.

Notes

No zero-length clusters are emitted; length == 0 yields no clusters.

Statuses

sz_utf8_graphemes_find_kernelFinds the UTF-8 grapheme kernel of kind, from the best of capabilities.
utf8_graphemes.h:56 ↗
sz_status_t sz_utf8_graphemes_find_kernel(
    sz_kernel_kind_t kind,
    sz_capability_t capabilities,
    sz_kernel_punned_t *kernel,
    sz_capability_t *capability);

Parameters

kindinThe verb whose kernel to find.
capabilitiesinThe mask to pick the best capability from.
kerneloutThe kernel, or null when none of capabilities has it.
capabilityoutThe capability the kernel belongs to, or zero.

Statuses

sz_utf8_sentences_bestSegment UTF-8 text into UAX-29 sentences in a single pass.
utf8_sentences.h:42 ↗
sz_status_t sz_utf8_sentences_best(
    sz_cptr_t text,
    sz_size_t length,
    sz_size_t *lengths,
    sz_size_t capacity,
    sz_size_t *count,
    sz_capability_t capabilities,
    sz_stream_t stream);

Backends

  • sz_utf8_sentencesserialhaswellicelakeneonsve2

Walks the input left-to-right and writes the byte length of each sentence into lengths. Sentences are the spans between consecutive UAX-29 sentence boundaries (SB1-SB998) and tile the input: each starts where the previous one ended, the first at text. A call covers all of text unless it fills lengths, in which case it covers the sum of the lengths it wrote, and the caller resumes from text advanced by that sum.

Parameters

textinUTF-8 encoded text.
lengthinByte length of text.
lengthsoutSentence byte lengths, at least capacity entries.
capacityinCapacity of lengths, in entries.
countoutNumber of sentences written, at most capacity.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu reports.
streaminNull on the CPU, or the GPU stream of that device to queue on.

Notes

  • No zero-length sentences are emitted; length == 0 yields no sentences.
  • Sentence segmentation is forward-only.

Statuses

sz_utf8_sentences_find_kernelFinds the UTF-8 sentence kernel of kind, from the best of capabilities.
utf8_sentences.h:57 ↗
sz_status_t sz_utf8_sentences_find_kernel(
    sz_kernel_kind_t kind,
    sz_capability_t capabilities,
    sz_kernel_punned_t *kernel,
    sz_capability_t *capability);

Parameters

kindinThe verb whose kernel to find.
capabilitiesinThe mask to pick the best capability from.
kerneloutThe kernel, or null when none of capabilities has it.
capabilityoutThe capability the kernel belongs to, or zero.

Statuses

sz_utf8_linebreaks_bestSegment UTF-8 text into UAX-14 line-break opportunities in one pass.
utf8_linebreaks.h:46 ↗
sz_status_t sz_utf8_linebreaks_best(
    sz_cptr_t text,
    sz_size_t length,
    sz_size_t *lengths,
    sz_size_t capacity,
    sz_size_t *count,
    sz_capability_t capabilities,
    sz_stream_t stream);

Backends

  • sz_utf8_linebreaksserialhaswellicelakeneonsve2

Walks the input left-to-right and writes the byte length of each line segment into lengths. Segments are the spans between consecutive UAX-14 break opportunities and tile the input: each starts where the previous one ended, the first at text. A call covers all of text unless it fills lengths, in which case it covers the sum of the lengths it wrote, and the caller resumes from text advanced by that sum.

This emits every wrap opportunity (both the mandatory LB4/LB5 hard breaks and the allowed soft-wrap points). To split only on the hard breaks (the str.splitlines behavior) use sz_utf8_newlines_best instead, which enumerates exactly the LB4/LB5 break positions.

Parameters

textinUTF-8 encoded text.
lengthinByte length of text.
lengthsoutSegment byte lengths, at least capacity entries.
capacityinCapacity of lengths, in entries.
countoutNumber of segments written, at most capacity.
capabilitiesinOne device's capabilities, like sz_capabilities_enabled_cpu reports.
streaminNull on the CPU, or the GPU stream of that device to queue on.

Notes

  • No zero-length segments are emitted; length == 0 yields no segments.
  • Line segmentation is forward-only.

Statuses

sz_utf8_linebreaks_find_kernelFinds the UTF-8 line break kernel of kind, from the best of capabilities.
utf8_linebreaks.h:61 ↗
sz_status_t sz_utf8_linebreaks_find_kernel(
    sz_kernel_kind_t kind,
    sz_capability_t capabilities,
    sz_kernel_punned_t *kernel,
    sz_capability_t *capability);

Parameters

kindinThe verb whose kernel to find.
capabilitiesinThe mask to pick the best capability from.
kerneloutThe kernel, or null when none of capabilities has it.
capabilityoutThe capability the kernel belongs to, or zero.

Statuses