C++でC風ライブラリを作る(UTF-16からUTF-8への変換編2)

高木です。おはようございます。
前回はctrtomb関数のchar16_t型版の仕様を考えました。
 今回は、その仕様に基づいた実装を行っていきます。
 
あまり能書きが長いのは嫌になってきますので、早速コードを掲載することにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76  | namespace cloverfield {   using mbstate_t = std::uint32_t;   inline std::size_t ctrtomb(char* s, char16_t c16, mbstate_t* ps)   {     if (ps == nullptr)     {       thread_local mbstate_t ts{};       ps = &ts;     }     if (s == nullptr)     {       static char buf[mb_len_max];       s = buf;       c16 = 0;     }     std::size_t result = -1;     char32_t c32 = c16;     if ((c16 & 0xfc00) == 0xd800)     {       *ps = c16;       return 0;     }     else if ((c16 & 0xfc00) == 0xdc00)     {       if ((*ps & 0xfc00) != 0xd800)         goto illegal_sequence;       c32 = ((*ps & 0x3ff) << 10 | c16 & 0x3ff) + 0x10000;     }     if (c32 == 0)     {       s[0] = '\0';       result = 1;     }     else if (c32 < 0x80)     {       *s = static_cast<char>(c32);       result = 1;     }     else if (c32 < 0x800)     {       s[0] = static_cast<char>(0xc0 | (c32 >> 6));       s[1] = static_cast<char>(0x80 | (c32 & 0x3f));       result = 2;     }     else if (c32 < 0x10000)     {       s[0] = static_cast<char>(0xe0 | (c32 >> 12));       s[1] = static_cast<char>(0x80 | ((c32 >> 6) & 0x3f));       s[2] = static_cast<char>(0x80 | (c32 & 0x3f));       result = 3;     }     else if (c32 < 0x110000)     {       s[0] = static_cast<char>(0xf0 | (c32 >> 18));       s[1] = static_cast<char>(0x80 | ((c32 >> 12) & 0x3f));       s[2] = static_cast<char>(0x80 | ((c32 >> 6) & 0x3f));       s[3] = static_cast<char>(0x80 | (c32 & 0x3f));       result = 4;     }     else     {       goto illegal_sequence;     }     *ps = c32;     return result; illegal_sequence:     *ps = -1;     throw std::invalid_argument("cloverfield::ctrtomb");   } }  | 
ちょっと乱雑になってしまいましたが、こんな感じでどうでしょうか?
 UTF-32からUTF-8への変換部分については、別の関数にして流用可能にしたほうがいいかもしれませんね。
今回はいったんここまでにして、次回、ctrtomb関数を実装する際にその対応を行うことにしましょう。

