sdbm_hash for utils

This commit is contained in:
2018-11-17 11:00:02 +07:00
parent 1952d958e4
commit d61d647f48
3 changed files with 75 additions and 6 deletions

View File

@@ -69,3 +69,56 @@ namespace e2d
~noncopyable() = default;
};
}
namespace e2d { namespace utils
{
//
// sdbm_hash
//
namespace impl
{
// Inspired by:
// http://www.cse.yorku.ca/~oz/hash.html
template < typename Char >
u32 sdbm_hash_impl(u32 init, const Char* str) noexcept {
while ( Char c = *str++ ) {
init = c + (init << 6u) + (init << 16u) - init;
}
return init;
}
template < typename Char >
u32 sdbm_hash_impl(u32 init, const Char* begin, const Char* const end) noexcept {
while ( begin != end ) {
init = (*begin++) + (init << 6u) + (init << 16u) - init;
}
return init;
}
}
template < typename Char >
u32 sdbm_hash(const Char* str) noexcept {
E2D_ASSERT(str);
return impl::sdbm_hash_impl(0u, str);
}
template < typename Char >
u32 sdbm_hash(const Char* begin, const Char* const end) noexcept {
E2D_ASSERT(begin <= end);
return impl::sdbm_hash_impl(0u, begin, end);
}
template < typename Char >
u32 sdbm_hash(u32 init, const Char* str) noexcept {
E2D_ASSERT(str);
return impl::sdbm_hash_impl(init, str);
}
template < typename Char >
u32 sdbm_hash(u32 init, const Char* begin, const Char* const end) noexcept {
E2D_ASSERT(begin <= end);
return impl::sdbm_hash_impl(init, begin, end);
}
}}

View File

@@ -127,12 +127,7 @@ namespace e2d
template < typename Char >
u32 basic_string_hash<Char>::calculate_hash(basic_string_view<Char> str) noexcept {
// Inspired by:
// http://www.cse.yorku.ca/~oz/hash.html
u32 hash = 0;
for ( Char c : str ) {
hash = c + (hash << 6u) + (hash << 16u) - hash;
}
u32 hash = utils::sdbm_hash(str.cbegin(), str.cend());
debug_check_collisions(hash, str);
return hash;
}

View File

@@ -6,6 +6,27 @@
#define CATCH_CONFIG_MAIN
#include "_utils.hpp"
using namespace e2d;
TEST_CASE("utils") {
{
REQUIRE(utils::sdbm_hash("") == 0u);
REQUIRE(utils::sdbm_hash(1u, "") == 1u);
REQUIRE(utils::sdbm_hash<char>(nullptr, nullptr) == 0u);
REQUIRE(utils::sdbm_hash<char>(1u, nullptr, nullptr) == 1u);
const char* str1 = "hello";
const char* str2 = "hello";
REQUIRE(utils::sdbm_hash(str1) == utils::sdbm_hash(str2));
REQUIRE(utils::sdbm_hash(42u, str1) == utils::sdbm_hash(42u, str2));
REQUIRE(utils::sdbm_hash(
str1, str1 + std::strlen(str1)
) == utils::sdbm_hash(str2));
REQUIRE(utils::sdbm_hash(
42u, str1, str1 + std::strlen(str1)
) == utils::sdbm_hash(42u, str2));
}
}