Make hash functions equality comparable.

This commit is contained in:
Matthias Vallentin 2013-07-22 18:03:55 +02:00
parent 9c2f57a9d9
commit eb64f5f961
3 changed files with 93 additions and 38 deletions

View file

@ -58,6 +58,7 @@
#define H3_H #define H3_H
#include <climits> #include <climits>
#include <cstring>
// The number of values representable by a byte. // The number of values representable by a byte.
#define H3_BYTE_RANGE (UCHAR_MAX+1) #define H3_BYTE_RANGE (UCHAR_MAX+1)
@ -112,6 +113,17 @@ public:
return result; return result;
} }
friend bool operator==(const H3& x, const H3& y)
{
return ! std::memcmp(x.byte_lookup, y.byte_lookup, N * H3_BYTE_RANGE);
}
friend bool operator!=(const H3& x, const H3& y)
{
return ! (x == y);
}
private: private:
T byte_lookup[N][H3_BYTE_RANGE]; T byte_lookup[N][H3_BYTE_RANGE];
}; };

View file

@ -8,56 +8,69 @@ Hasher::UHF::UHF(size_t seed, const std::string& extra)
} }
Hasher::digest Hasher::UHF::hash(const void* x, size_t n) const Hasher::digest Hasher::UHF::hash(const void* x, size_t n) const
{ {
assert(n <= UHASH_KEY_SIZE); assert(n <= UHASH_KEY_SIZE);
return n == 0 ? 0 : h_(x, n); return n == 0 ? 0 : h_(x, n);
} }
size_t Hasher::UHF::compute_seed(size_t seed, const std::string& extra) size_t Hasher::UHF::compute_seed(size_t seed, const std::string& extra)
{ {
u_char buf[SHA256_DIGEST_LENGTH]; u_char buf[SHA256_DIGEST_LENGTH];
SHA256_CTX ctx; SHA256_CTX ctx;
sha256_init(&ctx); sha256_init(&ctx);
if ( extra.empty() ) if ( extra.empty() )
{ {
unsigned int first_seed = initial_seed(); unsigned int first_seed = initial_seed();
sha256_update(&ctx, &first_seed, sizeof(first_seed)); sha256_update(&ctx, &first_seed, sizeof(first_seed));
} }
else else
{ {
sha256_update(&ctx, extra.c_str(), extra.size()); sha256_update(&ctx, extra.c_str(), extra.size());
}
sha256_update(&ctx, &seed, sizeof(seed));
sha256_final(&ctx, buf);
// Take the first sizeof(size_t) bytes as seed.
return *reinterpret_cast<size_t*>(buf);
} }
sha256_update(&ctx, &seed, sizeof(seed));
sha256_final(&ctx, buf);
// Take the first sizeof(size_t) bytes as seed.
return *reinterpret_cast<size_t*>(buf);
}
Hasher* Hasher::Create(size_t k, const std::string& name) Hasher* Hasher::Create(size_t k, const std::string& name)
{ {
return new DefaultHasher(k, name); return new DefaultHasher(k, name);
} }
Hasher::Hasher(size_t k, const std::string& name) Hasher::Hasher(size_t k, const std::string& name)
: k_(k), name_(name) : k_(k), name_(name)
{ {
} }
DefaultHasher::DefaultHasher(size_t k, const std::string& name) DefaultHasher::DefaultHasher(size_t k, const std::string& name)
: Hasher(k, name) : Hasher(k, name)
{ {
for ( size_t i = 0; i < k; ++i ) for ( size_t i = 0; i < k; ++i )
hash_functions_.push_back(UHF(i, name)); hash_functions_.push_back(UHF(i, name));
} }
Hasher::digest_vector DefaultHasher::Hash(const void* x, size_t n) const Hasher::digest_vector DefaultHasher::Hash(const void* x, size_t n) const
{ {
digest_vector h(K(), 0); digest_vector h(K(), 0);
for ( size_t i = 0; i < h.size(); ++i ) for ( size_t i = 0; i < h.size(); ++i )
h[i] = hash_functions_[i](x, n); h[i] = hash_functions_[i](x, n);
return h; return h;
} }
DefaultHasher* DefaultHasher::Clone() const
{
return new DefaultHasher(*this);
}
bool DefaultHasher::Equals(const Hasher* other) const /* final */
{
if ( typeid(*this) != typeid(*other) )
return false;
const DefaultHasher* o = static_cast<const DefaultHasher*>(other);
return hash_functions_ == o->hash_functions_;
}
DoubleHasher::DoubleHasher(size_t k, const std::string& name) DoubleHasher::DoubleHasher(size_t k, const std::string& name)
: Hasher(k, name), : Hasher(k, name),
@ -67,13 +80,25 @@ DoubleHasher::DoubleHasher(size_t k, const std::string& name)
} }
Hasher::digest_vector DoubleHasher::Hash(const void* x, size_t n) const Hasher::digest_vector DoubleHasher::Hash(const void* x, size_t n) const
{ {
digest h1 = h1_(x, n); digest h1 = h1_(x, n);
digest h2 = h2_(x, n); digest h2 = h2_(x, n);
digest_vector h(K(), 0); digest_vector h(K(), 0);
for ( size_t i = 0; i < h.size(); ++i ) for ( size_t i = 0; i < h.size(); ++i )
h[i] = h1 + i * h2; h[i] = h1 + i * h2;
return h; return h;
} }
DoubleHasher* DoubleHasher::Clone() const
{
return new DoubleHasher(*this);
}
bool DoubleHasher::Equals(const Hasher* other) const /* final */
{
if ( typeid(*this) != typeid(*other) )
return false;
const DoubleHasher* o = static_cast<const DoubleHasher*>(other);
return h1_ == o->h1_ && h2_ == o->h2_;
}

View file

@ -31,6 +31,10 @@ public:
virtual digest_vector Hash(const void* x, size_t n) const = 0; virtual digest_vector Hash(const void* x, size_t n) const = 0;
virtual Hasher* Clone() const = 0;
virtual bool Equals(const Hasher* other) const = 0;
size_t K() const { return k_; } size_t K() const { return k_; }
const std::string& Name() const { return name_; } const std::string& Name() const { return name_; }
@ -64,6 +68,16 @@ protected:
return hash(x, n); return hash(x, n);
} }
friend bool operator==(const UHF& x, const UHF& y)
{
return x.h_ == y.h_;
}
friend bool operator!=(const UHF& x, const UHF& y)
{
return ! (x == y);
}
digest hash(const void* x, size_t n) const; digest hash(const void* x, size_t n) const;
private: private:
@ -87,6 +101,8 @@ public:
DefaultHasher(size_t k, const std::string& name); DefaultHasher(size_t k, const std::string& name);
virtual digest_vector Hash(const void* x, size_t n) const /* final */; virtual digest_vector Hash(const void* x, size_t n) const /* final */;
virtual DefaultHasher* Clone() const /* final */;
virtual bool Equals(const Hasher* other) const /* final */;
private: private:
std::vector<UHF> hash_functions_; std::vector<UHF> hash_functions_;
@ -100,6 +116,8 @@ public:
DoubleHasher(size_t k, const std::string& name); DoubleHasher(size_t k, const std::string& name);
virtual digest_vector Hash(const void* x, size_t n) const /* final */; virtual digest_vector Hash(const void* x, size_t n) const /* final */;
virtual DoubleHasher* Clone() const /* final */;
virtual bool Equals(const Hasher* other) const /* final */;
private: private:
UHF h1_; UHF h1_;