template Endian (Type) { ubyte shift; ubyte size = Type.sizeof - 1; static this () { while (size >> shift) shift++; } Type[] big (ubyte[] data) { Type[] result; result.length |= (data.length + size) >> shift; foreach (uint x; 0 .. data.length) result[x >> shift] |= (Type.min | data[x]) << ((size ^ (size & x)) << 3); return result; } Type[] little (ubyte[] data) { Type[] result; result.length |= (data.length + size) >> shift; foreach (uint x; 0 .. data.length) result[x >> shift] |= (Type.min | data[x]) << ((size & x) << 3); return result; } ubyte[] big (Type[] data) { ubyte[] result; result.length |= data.length << shift; foreach (uint x; 0 .. result.length) result[x] |= ubyte.max & (data[x >> shift] >> ((size ^ (size & x)) << 3)); return result; } ubyte[] little (Type[] data) { ubyte[] result; result.length |= data.length << shift; foreach (uint x; 0 .. result.length) result[x] |= ubyte.max & (data[x >> shift] >> ((size & x) << 3)); return result; } }
バイトオーダーとは、2バイト以上のサイズを持ったデータ(型)に格納する際、上位と下位バイトのどちらからビットを立てていくかというもの。
上位バイトからは「ビッグエンディアン」、下位バイトからは「リトルエンディアン」と呼ばれます。
上位バイトとはビット列の左側1byte、下位バイトとはビット列の右側1byteことです。
例えば 00011000 という1byteのデータは、
short型のビッグエンディアンに変換した場合 00011000 00000000 となり、
short型のリトルエンディアンに変換した場合 00000000 00011000 となります。
そして変換のサンプルコード。
元データに変換する際、元データのサイズが変換されているデータ型のサイズで割り切れない場合はその分0で埋められます。import std.stdio; /* この辺に template Endian ... */ void main () { alias Endian!(uint) endian; ubyte[] data = cast(ubyte[])("abcdefghijklnmopqrstuvwxyz"); uint[] big = endian.big(data); // uint型のビッグエンディアンに変換 uint[] little = endian.little(data); // uint型のリトルエンディアンに変換 writeln(data); writeln(big); writeln(little); writeln(endian.big(big)); // uint型のビッグエンディアンをubyte型(元データ)に変換 writeln(endian.little(little)); // uint型のリトルエンディアンをubyte型(元データ)に変換 }
リトルエンディアンの場合は普通に cast 使った方が速いかもですが、自己満足で。
0 件のコメント:
コメントを投稿