2017-05-10 21 views
1

私は8バイトのQByteArrayを持っており、その配列の特定のビットをチェックする必要がありますが、毎回同じビットではありません。その8バイト配列を構成する64ビットのいずれかにすることができます。パフォーマンスが優先です!QByteArrayの特定のビットを確認してください

私の現在の方法では、特定のバイトをその配列から取得してから、特定のハーフバイト(またはニブル)を取得し、QByteArray::number(x, 2)を使用して別のQByteArrayに変換し、最後にビットをチェックします。これはうまくいって、より良い方法が欲しい。

QBitArrayにロードすることを選択したので、特定のビットをすばやく簡単に取得できます。メモリ内の表現がQByteArrayまたはquint64と同じであると仮定したので、変換は受け入れられますが、変換は許可されません。

QByteArrayの特定のビット(0〜63)が1か0かどうかを確認するにはどうすればよいですか?

+0

質問に現在のコードを追加してください。私はビットの値を知るためにビット単位の演算子を使用していないのはなぜだろうかと思います。 http://stackoverflow.com/a/523737/2266412 –

+0

これは、私が生の 'QByteArray'ビットチェックを探しているところで' int'を受け付けるためです。まず、ビットがある特定のバイトを見つけてintに変換してから、そのメソッドを使用する必要があります。バイト位置とビット位置では、ロジックを把握する必要があります。パフォーマンスが関心事ですので、私はより直接的かつ迅速なものを求めています。 私は現在のコードを説明しましたが、私はそれをまったく使用するつもりはありません。それは面倒なので、私はそれを投稿することは全く利益がないとは思わない。 – mrg95

+0

あなたが話している "論理"は、現代のCPUでは些細なことです。あなたは本当にhttps:// godboltに向かうべきです。あなた自身のために見てください。 –

答えて

2

QBitArrayは、他のものに変換できるようには設計されていません。その内部表現は確かに内部的なものです。

あまりにも簡単です。現代のアーキテクチャはバレルシフタを使用しているので、シフトは安いです。

可能なビットからバイトへのマッピングはいくつかあります。したがって

 byte 0  byte 1  byte n-1 byte n 
LL - [] [89ABCDEF] ... 
LB - [] [FEDCBA98] ... 
BL -      ... [89ABCDEF] [] 
BB -      ... [FEDCBA98] [] 

::のは、それらのすべてをカバーしてみましょう

enum class BitMapping { LL, LB, BL, BB }; 

bool getBit1(const QByteArray & arr, int bit, BitMapping m) { 
    Q_ASSERT(arr.size() >= 8); 
    auto byte = (m == BitMapping::LL || m == BitMapping::LB) ? 
       bit/8 : (7 - bit/8); 
    bit = (m == BitMapping::LB || m == BitMapping::BB) ? 
     (bit%8) : (7 - (bit%8)); 
    return arr.at(byte) & (1<<bit); 
} 

私たちはプラットフォームが64ビット整数のための賢明なサポートを持っていると仮定した場合、我々はそれらを活用することができます

bool getBit2(const QByteArray & arr, int bit, BitMapping m) { 
    Q_ASSERT(arr.size() >= 8); 
    auto value = *reinterpret_cast<const quint64 *>(arr.data()); 
    if (m == BitMapping::LL || m == BitMapping::BL) 
     bit = (bit & 0x38) + 7 - (bit & 0x07); // reorder bits 
    if ((Q_BYTE_ORDER == Q_LITTLE_ENDIAN && (m == BitMapping::BL || m == BitMapping::BB)) || 
     (Q_BYTE_ORDER == Q_BIG_ENDIAN && (m == BitMapping::LL || m == BitMapping::LB))) 
     bit = (bit & 0x07) + 0x38 - (bit & 0x38); // reorder bytes 
    return value & (1<<bit); 
} 

どれでもまともなコンパイラは、上記のいずれかの実装を特殊化した場合にインライン展開します。

bool getBit(const QByteArray & arr, int bit) { 
    return getBit2(arr, bit, BitMapping::LB); 
} 

またLB場合の手でそれを特化することができます:Q_BYTE_ORDERチェックはコンパイル時の定数であり、何の実行時のオーバーヘッドが発生しないことを

bool getBit1(const QByteArray & arr, int bit) { 
    Q_ASSERT(arr.size() >= 8); 
    auto byte = bit/8; 
    bit = bit%8; 
    return arr.at(byte) & (1<<bit); 
} 

bool getBit2(const QByteArray & arr, int bit) { 
    Q_ASSERT(arr.size() >= 8); 
    auto value = *reinterpret_cast<const quint64 *>(arr.data()); 
    if (Q_BYTE_ORDER == Q_BIG_ENDIAN) 
     bit = (bit & 0x07) + 0x38 - (bit & 0x38); // reorder bytes 
    return value & (1<<bit); 
} 

注意。

getBit1およびgetBit2は、Qtが実行されるすべてのプラットフォームで移植可能です。getBit2は、getBit1より少し良いコードを生成します。 x86-64では、getBit2のビットツイイドコードは5命令になります。

mov $0x1,%eax 
shl %cl,%eax 
cltq 
test %rax,(%rdi) 
setne %al 
retq 
+0

LL、LBなどは何のために混乱していますか?明確にすることはできますか? – mrg95

+0

バイト配列内のビットの順序を表します。可能な順序は4つあります。それらはグラフィックで図示されています。不明な点は何ですか? –

+0

さて、初心者にとって、LとBが何を意味するのか。私はリトルとビッグを前提にしていますが、LLとLBの最初の8ビットが同じではないことに気づいたとき、私は混乱しました。 – mrg95

関連する問題