C++では容量削減のためにビットフィールドが多用されました。これをC#でどのように表すべきか、答えのない問題に悩んでいます。
背景:C++のビットフィールド
C++のビットフィールドは以下の形式で表されます。組み込み整数のビット演算の糖衣構文です。
// unsignedはunsigned intの略記。C#のuintです。 union struct1 { struct { unsigned bit0_1 : 2; unsigned bit2_6 : 5; unsigned bit7_32 : 25; }; unsigned ui; }; int wmain() { const auto sizeof_struct1 = sizeof(struct1); // 8 = sizeof(unsigned int) struct1 s1; s1.bit0_1 = 0b10; s1.bit2_6 = 0b10101; s1.bit7_32 = 100; // ビットフィールドの上に書いた要素から下位ビットに配置されます。 auto i1 = s1.ui; // 0x00003256 = 0b001100100_10101_10 return 0; }
ビットフィールドにより、C++ではCPUID
命令の結果や組み込み整数中のビットデータを容易に扱えます。
知る限り、C#にはビットフィールドに関する言語仕様や構造体・クラスはありません。なので自作する選択肢があります。
C#のビットフィールドを考える。
自作ビットフィールドの選択肢として次を考えています。使い方次第なので正解はありません。
関数か構造体かクラスか?
- 組み込み整数やタプルを使えば関数でも構造体やクラスでも実現可能。関数指向かオブジェクト指向かで使い分ければ良さそう。
構造体かクラスか?
- イミュータブルなら構造体、ミュータブルならクラスが良さそう。
- 最近は
ref var
による構造体の参照も使えるが、既定の書き方では単にコピーされるので省メモリと速度を追求しなければクラスの方が良さそう。 - クラスにはGC稼働と小さな余剰バイトのコストはある。ただし短期間にプロパティとして使う程度なら無視できそう。
ビット範囲の情報(開始位置と終了位置)を残すか?
- 設計思想次第。プログラマー向けのツールを作るなら残しても良さそう。ビットフィールドを簡単に使いたいなら残さなくても良さそう。
開始位置でオフセット前の値を返すか、オフセット後の値を返すか?
設計思想次第。関数でも構造体・クラスでも両方あるいは両機能用意しても良いかも。
結論
指向と目的次第でどの選択肢もありだと思いました。今回はC#的なオブジェクト指向にのっとり、構造体とクラスでイミュータブル版とミュータブル版を作ってみようと思っています。