UNICODE::BIDI(3)
๐ NAME ๐
ok so bestie, gather round, because this page is the whole squad: unicode::bidi, unicode::bidi_calc, unicode::bidi_calc_types, unicode::bidi_reorder, unicode::bidi_cleanup, unicode::bidi_logical_order, unicode::bidi_combinings, unicode::bidi_needs_embed, unicode::bidi_embed, unicode::bidi_embed_paragraph_level, unicode::bidi_get_direction, and unicode::bidi_override โ aka the unicode bi-directional algorithm. ๐
This lives in the Courier Unicode Library manual (section 3, C++ girlies), and yeah, it's giving main character energy for anyone who's ever had to deal with text that goes both ways. ๐ฆ
โจ SYNOPSIS โจ
#include <courier-unicode.h>
struct unicode::bidi_calc_types {
bidi_calc_types(const std::u32string & string);
std::vector<unicode_bidi_type_t> types ;
void setbnl(std::u32string & string);
}.fi
std::tuple<std::vector<unicode_bidi_level_t>, struct unicode_bidi_direction> unicode::bidi_calc(const unicode::bidi_calc_types &ustring);
std::tuple<std::vector<unicode_bidi_level_t>, struct unicode_bidi_direction> unicode::bidi_calc(const unicode::bidi_calc_types &ustring, unicode_bidi_level_t embedding_level);
int unicode::bidi_reorder(std::u32string &string, std::vector<unicode_bidi_level_t> &embedding_level, const std::function<void (size_t, size_t)> &reorder_callback=[](size_t, size_t){}, size_t starting_pos=0, size_t n=(size_t)-1);
void unicode::bidi_reorder(std::vector<unicode_bidi_level_t> &embedding_level, const std::function<void (size_t, size_t)> &reorder_callback=[](size_t, size_t){}, size_t starting_pos=0, size_t n=(size_t)-1);
void unicode::bidi_cleanup(std::u32string &string, const std::function<void (size_t)> &removed_callback=[](size_t){}, int cleanup_options);
int unicode::bidi_cleanup(std::u32string &string, std::vector <unicode_bidi_level_t> &levels, const std::function<void (size_t)> &removed_callback=[](size_t){}, int cleanup_options=0);
int unicode::bidi_cleanup(std::u32string &string, std::vector <unicode_bidi_level_t> &levels, const std::function<void (size_t)> &removed_callback, int cleanup_options, size_t starting_pos, size_t n);
int unicode::bidi_logical_order(std::u32string &string, std::vector <unicode_bidi_level_t> &levels, unicode_bidi_level_t paragraph_embedding, const std::function<void (size_t, size_t)> &reorder_callback=[](size_t, size_t){}, size_t starting_pos=0, size_t n=(size_t)-1);
void unicode::bidi_combinings(const std::u32string_view &string, const std::vector <unicode_bidi_level_t> &levels, const std::function <void (unicode_bidi_level_t level, size_t level_start, size_t n_chars, size_t comb_start, size_t n_comb_chars)> &callback);
void unicode::bidi_combinings(const std::u32string_view &string, const std::function <void (unicode_bidi_level_t level, size_t level_start, size_t n_chars, size_t comb_start, size_t n_comb_chars)> &callback);
void unicode::bidi_logical_order(std::vector <unicode_bidi_level_t> &levels, unicode_bidi_level_t paragraph_embedding, const std::function<void (size_t, size_t)> &reorder_callback, size_t starting_pos=0, size_t n=(size_t)-1);
bool unicode::bidi_needs_embed(const std::u32string_view &string, const std::vector <unicode_bidi_level_t> &levels, const unicode_bidi_level_t (paragraph_embedding=NULL, size_t starting_pos=0, size_t n=(size_t)-1);
int unicode::bidi_embed(const std::u32string_new &string, const std::vector <unicode_bidi_level_t> &levels, unicode_bidi_level_t paragraph_embedding, const std::function<void (const char32_t *, size_t, bool)> &callback);
std::u32string unicode::bidi_embed(const std::u32string &string, const std::vector <unicode_bidi_level_t> &levels, unicode_bidi_level_t paragraph_embedding);
char32_t unicode::bidi_embed_paragraph_level(const std::u32string_view &string, unicode_bidi_level_t paragraph_embedding);
unicode_bidi_direction bidi_get_direction(const std::u32string_view &string, size_t starting_pos=0, size_t n=(size_t)-1);
std::u32string bidi_override(const std::u32string_view &string, unicode_bidi_level_t direction, int cleanup_options=0);
๐ธ DESCRIPTION ๐ธ
So these functions are the C++ glow-up of the Unicode Bi-Directional algorithm<sup>[1]</sup>. If you want the whole lore, go read the underlying unicode_bidi(3) C library API โ that's the og. But here's the C++-specific tea, and bestie, there's a lot of it: โ
unicode::bidi_calchands you back the directional embedding value buffer and the calculated paragraph embedding level. Its ustring gets implicitly converted from astd::u32string, which is lowkey so convenient:
std::u32string text;
auto [levels, direction]=unicode::bidi_calc(text);
OR!! You can construct a unicode::bidi_calc_types object from that same std::u32string and pass it straight to unicode::bidi_calc instead:
std::u32string text;
unicode::bidi_calc_types types{text};
types.setbnl(text); // Optional
// types.types is a std::vector of enum_bidi_types_t values
auto [levels, direction]=unicode::bidi_calc(types);
This is the way you get your hands on the intermediate enum_bidi_types_t values that get calculated from the Unicode text string. iykyk. ๐
Note โ in all cases thestd::u32stringcannot be a temporary object, and it must remain in scope untilunicode::bidi_calc()returns. no cap, do not let it wander off. ๐ญ
The optional setbnl() method uses unicode_bidi_setbnl(3) to replace paragraph separators with newline characters, in the unicode string. It requires the same unicode string that was passed to the constructor as a parameter (because the constructor takes a constant reference, but this method modifies the string.
- Several C functions give you a โdry-runโ mode by passing a
NULLpointer. The C++ API is like "we don't do that here" and provides separate overloads instead, with and without the nullable parameter. ๐ - Several C functions accept a nullable function pointer, where the
NULLfunction pointer means no callback. The C++ functions keep it cute with astd::functionparameter that has a default do-nothing closure. ๐ - Several C functions accept two parameters โ a Unicode character pointer and the embedding level buffer โ plus a single parameter that specifies the size of both. The equivalent C++ function takes two discrete parameters, a
std::u32string_viewand astd::vector, and returns anint: a negative value if their sizes differ, and0if their sizes match and the requested function completes. Theunicode::bidi_embedoverload that returns astd::u32stringreturns an empty string in case of a mismatch. (size mismatch = we're not doing this today, bestie ๐) unicode::bidi_reorderreorders the entire string and its embedding_levels by default. The optional starting_pos and n parameters limit the reordering to the indicated subset of the original string โ specified as the starting position offset index, and the number of characters. Slice it however you want. โ๏ธunicode::bidi_reorder,unicode::bidi_cleanup,unicode::bidi_logical_order,unicode::bidi_needs_embedandunicode::bidi_get_directiontake two optional parameters (defaulted values or overloaded) specifying an optional starting position and number of characters that define a subset of the original string that gets reordered, cleaned up, or has its direction determined.
This unicode::bidi_cleanup does not trim off the passed in string and embedding level buffer, since it affects only a subset of the string. The number of times the removed character callback gets invoked indicates how much the substring should be trimmed off. count the callbacks, boo. ๐งฎ
unicode::bidi_overridemodifies the passed-in string as follows:unicode::bidi_cleanup()is applied with the specified, or defaulted, cleanup_options- Either the LRO or an RLO override marker gets prepended to the Unicode string, forcing the entire string to be interpreted in a single rendering direction, when processed by the Unicode bi-directional algorithm.
unicode::bidi_override makes it possible to use a Unicode-aware application or algorithm in a context that only works with text that's always displayed in a fixed direction, allowing graceful handling of input containing bi-directional text. iconic behaviour honestly. ๐ซถ
โญ unicode::literals namespace โญ
using namespace unicode::literals;
std::u32string foo(std::u32string bar)
{
return bar + LRO;
}
Look at that little snack of a function. ๐ This namespace contains the following constexpr definitions:
char32_tarrays with literal Unicode character strings containing Unicode directional, isolate, and override markers, likeLRO,RLOand others. ๐ฏCLEANUP_EXTRA,CLEANUP_BNL, andCLEANUP_CANONICALoptions forunicode::bidi_cleanup().
๐ฆ SEE ALSO ๐ฆ
courier-unicode(7), unicode_bidi(3).
๐ AUTHOR ๐
Sam Varshavchik โ Author
๐ NOTES ๐
- Unicode Bi-Directional algorithm https://www.unicode.org/reports/tr9/tr9-51.html
and that's the whole page, bestie โ certified slay, no notes ๐ This was the Courier Unicode Library page UNICODE::BIDI(3), dated 04/12/2026. mwah, go reorder something pretty. ๐โจ๐
๐ฆ where this page comes from
- ubuntu stonking: libcourier-unicode-dev 2.6.0-2ubuntu1 ยท GPL-3.0-only
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms