Tom*_*ica 2 c++ qt qvariant stdhash
我需要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;
}
};
}
Run Code Online (Sandbox Code Playgroud)
显然,我不喜欢整件事switch.这是一个非常漫长而丑陋的代码,并且仅考虑基本类型.我宁愿制作为QVariant内部数据分配的内存数据的哈希值.或者,甚至更好 - 使用一些Qt的散列方法.
是否存在一种半可靠的方法来散列任何QVariant而不将其转换为原始类型?
*我知道复杂的物体可能隐藏在QVariant后面,但是这会导致碰撞的情况很少见,所以我不必关心.
给自己一个QByteArray+ QBuffer+ QDataStream来基本序列化QVariant到QByteArray.
然后简单地散列字节数组中的原始字节.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;
};
Run Code Online (Sandbox Code Playgroud)
它在评论中提到的速度非常快,并且它具有处理支持QDataStream序列化的每种类型的优点.对于自定义类型,您只需实现序列化,无需制作和维护巨型交换机.如果您已经实现了交换机版本,则可以进行比较.交换机本身有很多分支,而重用相同的字节数组对缓存非常友好,特别是如果你不使用很多字节,也就是说,你不是包含很长字符串或数组的散列变种.
此外,它优于半可靠,因为散列也包括变体类型,因此即使在实际数据可能是二进制相同的情况下,例如两个字节,值为255,而短值为65535,哈希将合并类型,使值不会发生碰撞.