#pragma once
#include <cstdint>
#include <functional>
#include <unordered_set>
#include "common/exception/runtime.h"
#include "common/types/int128_t.h"
#include "common/types/interval_t.h"
#include "common/types/string_t.h"
#include "common/types/types.h"
#include "common/types/uint128_t.h"
namespace lbug {
namespace function {
constexpr const uint64_t NULL_HASH = UINT64_MAX;
inline common::hash_t murmurhash64(uint64_t x) {
x ^= x >> 32;
x *= 0xd6e8feb86659fd93U;
x ^= x >> 32;
x *= 0xd6e8feb86659fd93U;
x ^= x >> 32;
return x;
}
inline common::hash_t combineHashScalar(const common::hash_t a, const common::hash_t b) {
return (a * UINT64_C(0xbf58476d1ce4e5b9)) ^ b;
}
struct Hash {
template<class T>
static void operation(const T& , common::hash_t& ) {
throw common::RuntimeException(
"Hash type: " + std::string(typeid(T).name()) + " is not supported.");
}
template<class T>
static void operation(const T& key, bool isNull, common::hash_t& result) {
if (isNull) {
result = NULL_HASH;
return;
}
operation(key, result);
}
};
struct CombineHash {
static inline void operation(const common::hash_t& left, const common::hash_t& right,
common::hash_t& result) {
result = combineHashScalar(left, right);
}
};
template<>
inline void Hash::operation(const common::internalID_t& key, common::hash_t& result) {
result = murmurhash64(key.offset) ^ murmurhash64(key.tableID);
}
template<>
inline void Hash::operation(const bool& key, common::hash_t& result) {
result = murmurhash64(key);
}
template<>
inline void Hash::operation(const uint8_t& key, common::hash_t& result) {
result = murmurhash64(key);
}
template<>
inline void Hash::operation(const uint16_t& key, common::hash_t& result) {
result = murmurhash64(key);
}
template<>
inline void Hash::operation(const uint32_t& key, common::hash_t& result) {
result = murmurhash64(key);
}
template<>
inline void Hash::operation(const uint64_t& key, common::hash_t& result) {
result = murmurhash64(key);
}
template<>
inline void Hash::operation(const int64_t& key, common::hash_t& result) {
result = murmurhash64(key);
}
template<>
inline void Hash::operation(const int32_t& key, common::hash_t& result) {
result = murmurhash64(key);
}
template<>
inline void Hash::operation(const int16_t& key, common::hash_t& result) {
result = murmurhash64(key);
}
template<>
inline void Hash::operation(const int8_t& key, common::hash_t& result) {
result = murmurhash64(key);
}
template<>
inline void Hash::operation(const common::int128_t& key, common::hash_t& result) {
result = murmurhash64(key.low) ^ murmurhash64(key.high);
}
template<>
inline void Hash::operation(const common::uint128_t& key, common::hash_t& result) {
result = murmurhash64(key.low) ^ murmurhash64(key.high);
}
template<>
inline void Hash::operation(const double& key, common::hash_t& result) {
if (key == 0) {
result = murmurhash64(0);
} else {
result = murmurhash64(*reinterpret_cast<const uint64_t*>(&key));
}
}
template<>
inline void Hash::operation(const float& key, common::hash_t& result) {
if (key == 0) {
result = murmurhash64(0);
} else {
result = murmurhash64(*reinterpret_cast<const uint32_t*>(&key));
}
}
template<>
inline void Hash::operation(const std::string_view& key, common::hash_t& result) {
common::hash_t hashValue = 0;
auto data64 = reinterpret_cast<const uint64_t*>(key.data());
for (size_t i = 0u; i < key.size() / 8; i++) {
auto blockHash = lbug::function::murmurhash64(*(data64 + i));
hashValue = lbug::function::combineHashScalar(hashValue, blockHash);
}
uint64_t last = 0;
for (size_t i = 0u; i < key.size() % 8; i++) {
last |= static_cast<uint64_t>(key[key.size() / 8 * 8 + i]) << i * 8;
}
hashValue = lbug::function::combineHashScalar(hashValue, lbug::function::murmurhash64(last));
result = hashValue;
}
template<>
inline void Hash::operation(const std::string& key, common::hash_t& result) {
Hash::operation(std::string_view(key), result);
}
template<>
inline void Hash::operation(const common::string_t& key, common::hash_t& result) {
Hash::operation(key.getAsStringView(), result);
}
template<>
inline void Hash::operation(const common::interval_t& key, common::hash_t& result) {
result = combineHashScalar(murmurhash64(key.months),
combineHashScalar(murmurhash64(key.days), murmurhash64(key.micros)));
}
template<>
inline void Hash::operation(const std::unordered_set<std::string>& key, common::hash_t& result) {
for (auto&& s : key) {
result ^= std::hash<std::string>()(s);
}
}
struct InternalIDHasher {
std::size_t operator()(const common::internalID_t& internalID) const {
common::hash_t result = 0;
function::Hash::operation<common::internalID_t>(internalID, result);
return result;
}
};
} }