C#::バーター

前回(id:lord_hollow:20090825:p1)の続き。

BitConverterにbyte[]とオフセットを受け取って適当に書き換えてくれるメソッドがあればそれが速そうなんだけど。常識的に考えて、yield returnが遅いんだと思うし。

より、コンバータークラスを書いて試してみるテスト。とりあえず、float/byte/Int16/Int32の分だけ定義。TCP/IP通信用に使うので、政治的に正しくするためにネットワークバイトオーダー(ビッグエンディアン)にしてあります。

/// <summary>高速BitConverter(ネットワークバイトオーダー)</summary>
/// <remarks>C#3.0以前(C#2005)の場合、引数のthisを削れば使用可能</remarks>
public static class BitConverterEx {
  public static int SetBytes(this byte[] dt, int offset, float val) {
    var d = BitConverter.GetBytes(val).ToArray();
    dt[offset++] = dt[3];
    dt[offset++] = dt[2];
    dt[offset++] = dt[1];
    dt[offset++] = dt[0];
    return offset;
  }

  public static int SetBytes(this byte[] dt, int offset, int val){
    dt[offset++] = (byte)((val & 0xFF000000) >> 24);
    dt[offset++] = (byte)((val & 0xFF0000) >> 16);
    dt[offset++] = (byte)((val & 0xFF00) >> 8);
    dt[offset++] = (byte)(val & 0x00FF);
    return offset;
  }
  public static int SetBytes(this byte[] dt, int offset, short val){
    dt[offset++] = (byte)((val & 0xFF00) >> 8);
    dt[offset++] = (byte)(val & 0x00FF);
    return offset;
  }
  public static int SetBytes(this byte[] dt, int offset, byte val){
    dt[offset++] = val;
    return offset;
  }
}

使用例は以下のとおり。

stream = new byte[5];
int offset = 0;
offset = stream.SetBytes(offset, 25);
offset = stream.SetBytes(offset, (byte)26);

あるいは

stream = new byte[5];
int offset = 0;
offset = BitConverterEx.SetBytes(stream, offset, 25);
offset = BitConverterEx.SetBytes(stream, offset, (byte)26);

実行速度は、前回のConcatを使う方法に比べて8〜10倍高速ですねぇ。思った以上に速かったのですが、あらかじめ配列のサイズを手計算しないと駄目なのがネックかなあ。実際に使うためにはOutOfRange対策も入れなきゃダメだし、速度差は縮まるかな。
より高度には、上記streamを内部に隠蔽したPacketBuilderクラスを作るのが正しそう。