+ assert(in.length > 0);
+ assert(in.data != NULL);
+
+ CB_String16 res = {0};
+ s64 res_size = 0, approx_size = in.length * 2;
+ u16 *words = cb_arena_push_many(u16, approx_size), *res_offset = words;
+ if (!words) { return res; }
+
+ CB_UTFCodepoint codepoint = {0};
+ for (const u8 *start = in.data, *end = in.data + in.length;
+ start < end;
+ start += codepoint.size) {
+ if ((*start & 0x80) == 0) {
+ codepoint.codepoint = *start;
+ codepoint.size = 1;
+ } else if ((*start & 0xE0) == 0xC0) {
+ codepoint.codepoint = start[1] & 0x3F;
+ codepoint.codepoint |= (u32)(start[0] & 0x1F) << 6;
+ codepoint.size = 2;
+ } else if ((*start & 0xF0) == 0xE0) {
+ codepoint.codepoint = start[2] & 0x3F;
+ codepoint.codepoint |= (u32)(start[1] & 0x3F) << 6;
+ codepoint.codepoint |= (u32)(start[0] & 0xf) << 12;
+ codepoint.size = 3;
+ } else if ((*start & 0xF8) == 0xF0) {
+ codepoint.codepoint = start[3] & 0x3F;
+ codepoint.codepoint |= (u32)(start[2] & 0x3F) << 6;
+ codepoint.codepoint |= (u32)(start[1] & 0x3F) << 12;
+ codepoint.codepoint |= (u32)(start[0] & 0x7) << 18;
+ codepoint.size = 4;
+ } else {
+ assert(false && "unreachable reached");
+ }
+
+ s64 utf16_codepoint_size;
+ if (codepoint.codepoint <= 0xD7FF || (codepoint.codepoint >= 0xE000 && codepoint.codepoint <= 0xFFFF)) {
+ res_offset[0] = (u16)codepoint.codepoint;
+ utf16_codepoint_size = 1;
+ } else if (codepoint.codepoint >= 0x10000 && codepoint.codepoint <= 0x10FFFF) {
+ res_offset[0] = (u16)(((codepoint.codepoint - 0x10000) >> 10) + 0xD800);
+ res_offset[1] = ((codepoint.codepoint - 0x10000) & 0x3FF) + 0xDC00;
+ utf16_codepoint_size = 2;
+ } else {
+ assert(false && "unreachable reached");
+ }
+
+ res_size += utf16_codepoint_size;
+ res_offset += utf16_codepoint_size;
+ }
+
+ assert(res_size >= 0);
+ cb_arena_pop(approx_size - res_size);
+ res.data = words;
+ res.length = res_size;
+ return res;
+}
+
+static CB_String8 cb_str8_from_cstr(const char *cstr)
+{
+ CB_String8 res = {0};