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

C#
このエントリーをはてなブックマークに追加

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

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

GitHub - MeilCli/SharedText: prototype project, remake of CrossFormattedText

prototype project, remake of CrossFormattedText. Contribute to MeilCli/SharedText development by creating an account on GitHub.

github.com

GitHub - MeilCli/SharedText: prototype project, remake of CrossFormattedText
Go to GitHub - MeilCli/SharedText: prototype project, remake of CrossFormattedText

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

デザインスペック

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

Scenarios and Design Philosophy - UTF-8 string support · Issue #2368 · dotnet/corefxlab

(This is a living document. Expect edits.) Scenarios High-performance networking stacks (This includes HttpClient, ASP.NET's Kestrel, and similar APIs.) High-performance networking stacks want to b...

github.com

Scenarios and Design Philosophy - UTF-8 string support · Issue #2368 · dotnet/corefxlab
Go to Scenarios and Design Philosophy - UTF-8 string support · Issue #2368 · dotnet/corefxlab

Utf8String design proposal · Issue #2350 · dotnet/corefxlab

Utf8String design discussion - last edited 14-Sep-19 Utf8String design overview Audience and scenarios Utf8String and related concepts are meant for modern internet-facing applications that need to...

github.com

Utf8String design proposal · Issue #2350 · dotnet/corefxlab
Go to Utf8String design proposal · Issue #2350 · dotnet/corefxlab

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

全般

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

UTF-8 - Wikipedia

ja.wikipedia.org

Go to 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/src/System.Text.Utf8/System/Text/UnicodeScalar.cs at f691fc4b11238a806e9ae50cff6834e1df25ae1d · dotnet/corefxlab

This repo is for experimentation and exploring new ideas that may or may not make it into the main corefx repo. - dotnet/corefxlab

github.com

corefxlab/src/System.Text.Utf8/System/Text/UnicodeScalar.cs at f691fc4b11238a806e9ae50cff6834e1df25ae1d · dotnet/corefxlab
Go to corefxlab/src/System.Text.Utf8/System/Text/UnicodeScalar.cs at f691fc4b11238a806e9ae50cff6834e1df25ae1d · dotnet/corefxlab

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が待ち遠しいです。