« Android Studio 2.2 + cmake で上位ディレクトリを C++ の基準とする | メイン | デフォルトフォントの選択 »

2016年11月21日

吉里吉里Z 開発:: Windows版/Android版文字の取り扱い

    

吉里吉里Z 内部では UTF-16 で処理され、wchar_t を使用している。
wchar_t は、Windows では 16bit だが、Android では 32bit になる。
この差をどのように取り扱うか検討する必要がある。

1. wchar_t で統一し、ファイルのやり取りなどの部分のみ環境固有にする。
2. char16_t で統一し、Win32 API などに受け渡す時はキャストする。
3. Windows は wchar_t、他は char16_t にする。

1.の場合
wchar_t で統一すると文字サイズが異なるためファイルの読み書きなどで互換性がなくなる。
動作自体はほぼ問題なく動く。
ただ、ファイル読み書きで互換性がないのは困るので、環境に応じて処理を分ける必要がある。
Windows 基準で作られているので、Android は別実装になる。
また、Java と文字列をやり取りする場合、jchar は 16bit のため毎回変換が必要になる。

2.の場合
C++11 以降 wchar_t は非推奨となっていて、Unicode 用の char16_t や char32_t が使えるようになっている。
char16_t で統一してしまえばすっきりする。
ただ、文字列処理関数として char16_t のものは少ないので、別途準備する必要がある。
Win32 API では、文字列を wchar_t* で受け渡すものがあり、これは char16_t だとキャストしないといけない。
キャストの場合ミスがあると実行時に問題となって表れるので、避けられるのなら避けたい。

3.の場合
キャストの問題を避けるために Windows は wchar_t 、Android は char16_t にする方法。
char16_t なので文字列処理関数を準備する必要があるのは 2の場合と同じ。
実装上のミスはキャストと比較してコンパイル時にわかりやすいのでやや安心。
環境によって定義が異なるのがややすっきりしない。

方法とメリットデメリットはこんなところ。
今回は、3番を選択した。
実装は――
tjs_char を環境によって wchar_t か char16_t として定義して、内部では tjs_char で統一。
tjs_string を環境によって std::wstring か std::u16string として定義して、内部では tjs_string で統一。
文字列定数は、TJS_W を環境によってマクロで L""か u"" として定義して、内部では TJS_W で統一(単一文字も同じ)。
とした。
また、文字列処理関数は主に bionic からコピーし、tjs_char として書き換えた。
文字列処理関数を自前で持つことで SIMD 化を行いやすくもなった(ランタイムで既に SIMD 化されていたりもするので速度低下している部分もあると考えられるが)。


投稿者 Takenori : 2016年11月21日 02:24




comments powered by Disqus
Total : Today : Yesterday : なかのひと