3

QList<QVariant>のキーとして使用する必要がありますstd::unordered_map。これの目的は、一意のキー列にインデックスを作成することにより、データ テーブルの検索を最適化することです。

だから私はこのコードを作りました。完全ではありませんが、テーブル キー列で発生するいくつかの基本的なデータ型を示します。

#include <unordered_map>
#include <string>
//std::hash
#include <functional>
//std::size_t
#include <cstddef>
// Hashing method for QVariantList
namespace std {
    template <>
    struct hash<QList<QVariant>>
    {
        std::size_t operator()(const QList<QVariant>& k) const
        {
            using std::size_t;
            using std::hash;
            using std::string;
            size_t hash_num = 0;
            Q_FOREACH(var, k) {
                // Make hash of the primitive value of the QVariant
                switch(var.type()) {
                    case QVariant::String : {
                        hash_num = hash_num^hash<string>(var.toString().toStdString());
                        break;
                    }
                    case QVariant::Char :
                    case QVariant::ULongLong :
                    case QVariant::UInt :
                    case QVariant::LongLong :
                    case QVariant::Int : {
                        hash_num = hash_num^hash<long long>(var.toLongLong());
                        break;
                    }
                    case QVariant::Double : {
                        hash_num = hash_num^hash<double>(var.toDouble());
                        break;
                    }
                }
            }
            return hash_num;
        }
    };
}

明らかに、私はすべてが好きではありませんswitch。これは非常に長く醜いコードであり、基本的な型しか説明していません。QVariantの内部データに割り当てられたメモリ データのハッシュを作成したいと思います。または、さらに良い - Qt のハッシュ方法を使用します。

QVariant をプリミティブ型に変換せずにハッシュする半信頼できる*方法はありますか?

*複雑なオブジェクトが QVariant の背後に隠れている可能性があることは理解していますが、これが衝突につながるケースは非常にまれであるため、気にする必要はありません。

4

1 に答える 1

8

QByteArray++を取得して、基本的にs をにシリアル化しQBufferます。QDataStreamQVariantQByteArray

次に、バイト配列内の生のバイトを単純にハッシュします。Qt はすでにqHash関数を実装してQByteArrayいるので、準備は完了です。

QByteArray再割り当てを回避するために十分な事前割り当てバイトで同じものを再利用することにより、効率を最大化できます。VariantHasherすべてをクラスでラップし、単にseek(0)新しいハッシュの前にバッファーをラップし、全体ではpos()なくバイト数のみをハッシュすることができます。

class QVariantHasher {
  public:
    QVariantHasher() : buff(&bb), ds(&buff) {
      bb.reserve(1000);
      buff.open(QIODevice::WriteOnly);
    }
    uint hash(const QVariant & v) {
      buff.seek(0);
      ds << v;
      return qHashBits(bb.constData(), buff.pos());
    }
  private:
    QByteArray bb;
    QBuffer buff;
    QDataStream ds;
};

コメントで述べたように非常に高速であり、QDataStreamシリアライゼーションをサポートするすべてのタイプで動作するという利点があります。カスタム型の場合、シリアル化を実装するだけで済み、巨大なスイッチを作成して維持する必要はありません。すでにスイッチ バージョンが実装されている場合は、比較を行うと興味深いでしょう。スイッチ自体は多くの分岐を伴いますが、同じバイト配列を再利用することは非常にキャッシュ フレンドリーです。特に、多くのバイトを使用しない場合、つまり、非常に長い文字列または配列を含むバリアントをハッシュしていない場合はなおさらです。

また、ハッシュにはバリアント型も含まれるため、半信頼性よりも優れています。したがって、実際のデータがバイナリ同一である可能性がある場合でも、たとえば、値が 255 の 2 バイトと値が 65535 の short の場合、ハッシュは値が衝突しないように型を組み込みます。

于 2016-12-14T14:52:49.130 に答える