滅入るんるん

何か書きます

【C#】Utf8String関連のデザイン動向

C#のStringが扱う文字コードはUTF-16ですが、UTF-8が広く使われるようになった現状ではUTF-8→UTF-16の変換コストなどがかかりパフォーマンス上の懸念点となっていました。 そこで最近のパフォーマンス改善の一環として、C#にUTF-8な文字列を扱えるようにしようという流れがcsharplangcorefxlabで起き、実際に作業が始まっているようです。

昔、個人的に作成していたCrossFormattedTextが設計的に古い(PCL)なため.NET Standardなものを作り直そうと考えているのですが、どうせならUTF-16,8両方に対応したいところです。
そういうわけもあり、Utf8String関連の動向を調べる機会があったので記事に書いておきます。(といっても英語詳しく読んでないので大した内容じゃないです……)

github.com

↑いちおう.NET Standard置き換えのプロトタイプ作ったので、API RequestとかあればIssue立てオナシャスm(__)m

デザインスペック

現在Corefxlabを見ると、Utf8Stringのデザインに関するIssueは2つあります。

github.com

github.com

実際の作業はあまり進んでないように見えるので今回はこの2つを眺めながら、どういった実装になるのか推測という感じになります。また、これ以外にもC#の言語的サポートに関してはcsharplangにIssueが立っています。

全般

このようなコアなことに関する記事を見る読者の皆様ならだいたい察しがついていることでしょうが、内部的にはReadOnlySpan<byte>ReadOnlyMemory<byte>のようにスライス可能な1バイト数値型を使いたいようです。

UTF-8 - Wikipedia

ところで、Wikipediaにも書いていますがUTF-8では1つの文字コードを表すのに8bit=1byteを複数用いて表現します。 この1byteの数値をCode unitという単位で表現します。これをC#側のほうでは(UTF-16なCode unitであるcharに合わせて)Char8という型を用意したいようですが、実態はbytesbyteになりそうです。

また、文字コードを表す単位としてCode pointScalar valueというのがあります。ここの説明がよくわからなかったのですが、どうやらCode pointは歴史的経緯のあるサロゲートコードの範囲を含めていて、Scalar valueは含めていないといったもののようです。そしてこのScalar valueUnicodeScalarという型として用意するようです。

もう1つ、厄介なことにUnicodeでは複数の文字を連結して1つの文字として扱う場合があります。人の絵文字とかのことですね。それはGraphemeと呼ばれるようですが、デザインスペック的にはサポートする予定はなさそうです。

UnicodeScalar

さきほど出たScalar valueを表すUnicodeScalar型ですが、こちらはUTF-8専用ではなくUTF-16の文字も表せるようにするようです。なので名前がUnicode Scalarなんでしょうね。

namespace System.Text
{
    public readonly struct UnicodeScalar
    {
        public int Utf16SequenceLength { get; } // 1 or 2
        public int Utf8SequenceLength { get; } // 1 ~ 4
        public int ToUtf16(Span<char> output);
        public int ToUtf8(Span<byte> output);
    }
}

Issueのほうからざっくりと抽出してみましたが、このUnicodeScalar型は面白くて、利用者側でSpanを作成し、そこに値を入れるToUtf16ToUtf8メソッドがあります。これを利用していくことになりますが、利用者側は当然、値の長さを知らないといけないので長さを取れるプロパティも実装するようです。

パフォーマンスのためにSpanを使うとこうなるのはしょうがないという感じですが、低レベルAPI感をとても感じます。

一応仮の実装はされているようなので、貼っておきます。

corefxlab/UnicodeScalar.cs at f691fc4b11238a806e9ae50cff6834e1df25ae1d · dotnet/corefxlab · GitHub

Utf8String, Utf8StringSegment

Utf8Stringの仕様策定の過程で、structがいいとかstructだとつらいとかどうのこうのがあったようですが、最終的にはUtf8String型はクラスとなるようです。
そこで、パフォーマンスのために構造体なUtf8StringSegmentも用意するようです。(どのような場面で使用されるかはよくわからなかった)

この2つの型ですが、API的にはStringと同じようなものを用意するようです。違う点で言うならばUnicodeScalar型の引数のあるAPIも用意する予定の点。前述の通りUnicodeScalarはUTF-16, UTF-8を表せる型なので既存のStringにもメソッドが追加されるのではという期待もできるのですが、どうなんでしょうかね。

おわりに

今回見てきたIssueですが、2つとも6月に立てられてからあまり話が進んでないようでした。Corefxlabには実際にutf8stringというブランチがあるのですがこちらも6月ぐらいからコミットがないようです。

最初に載せた自分の作業リポジトリもCorefxlabの動向次第な面があるので放置せざるを得ないのですが、UTF-16の呪縛から逃げれるかと思うと非常に楽しみなのでUtf8Stringが待ち遠しいです。