constexpr hashed_string

This commit is contained in:
BlackMATov
2023-01-31 07:42:16 +07:00
parent 6a8aa13444
commit 14193a1434
3 changed files with 177 additions and 34 deletions

View File

@@ -531,6 +531,35 @@ namespace meta_hpp::detail
};
}
namespace meta_hpp::detail
{
template < std::size_t SizeBytes = sizeof(std::size_t) >
struct fnv1a_hash_traits;
template <>
struct fnv1a_hash_traits<4> { // NOLINT(*-magic-numbers)
using underlying_type = std::uint32_t;
static inline constexpr underlying_type prime{16777619U};
static inline constexpr underlying_type offset{2166136261U};
};
template <>
struct fnv1a_hash_traits<8> { // NOLINT(*-magic-numbers)
using underlying_type = std::uint64_t;
static inline constexpr underlying_type prime{1099511628211U};
static inline constexpr underlying_type offset{14695981039346656037U};
};
constexpr std::size_t fnv1a_hash(std::string_view str) noexcept {
std::size_t hash{fnv1a_hash_traits<>::offset};
for ( char ch : str ) {
hash ^= static_cast<std::size_t>(ch);
hash *= fnv1a_hash_traits<>::prime;
}
return hash;
}
}
namespace meta_hpp::detail
{
class hashed_string final {
@@ -544,40 +573,35 @@ namespace meta_hpp::detail
hashed_string& operator=(hashed_string&&) = default;
hashed_string& operator=(const hashed_string&) = default;
hashed_string(const char* str) noexcept
: hash_{std::hash<std::string_view>{}(str)} {}
constexpr hashed_string(const char* str) noexcept : hash_{fnv1a_hash(str)} {}
constexpr hashed_string(std::string_view str) noexcept : hash_{fnv1a_hash(str)} {}
constexpr hashed_string(const std::string& str) noexcept : hash_{fnv1a_hash(str)} {}
hashed_string(std::string_view str) noexcept
: hash_{std::hash<std::string_view>{}(str)} {}
hashed_string(const std::string& str) noexcept
: hash_{std::hash<std::string_view>{}(str)} {}
void swap(hashed_string& other) noexcept {
constexpr void swap(hashed_string& other) noexcept {
std::swap(hash_, other.hash_);
}
[[nodiscard]] std::size_t get_hash() const noexcept {
[[nodiscard]] constexpr std::size_t get_hash() const noexcept {
return hash_;
}
private:
std::size_t hash_{};
std::size_t hash_{fnv1a_hash("")};
};
inline void swap(hashed_string& l, hashed_string& r) noexcept {
constexpr void swap(hashed_string& l, hashed_string& r) noexcept {
l.swap(r);
}
[[nodiscard]] inline bool operator<(hashed_string l, hashed_string r) noexcept {
[[nodiscard]] constexpr bool operator<(hashed_string l, hashed_string r) noexcept {
return l.get_hash() < r.get_hash();
}
[[nodiscard]] inline bool operator==(hashed_string l, hashed_string r) noexcept {
[[nodiscard]] constexpr bool operator==(hashed_string l, hashed_string r) noexcept {
return l.get_hash() == r.get_hash();
}
[[nodiscard]] inline bool operator!=(hashed_string l, hashed_string r) noexcept {
return l.get_hash() == r.get_hash();
[[nodiscard]] constexpr bool operator!=(hashed_string l, hashed_string r) noexcept {
return l.get_hash() != r.get_hash();
}
}
@@ -585,7 +609,7 @@ namespace std
{
template <>
struct hash<meta_hpp::detail::hashed_string> {
size_t operator()(meta_hpp::detail::hashed_string hs) const noexcept {
constexpr size_t operator()(meta_hpp::detail::hashed_string hs) const noexcept {
return hs.get_hash();
}
};

View File

@@ -0,0 +1,95 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <meta.hpp/meta_all.hpp>
#include <doctest/doctest.h>
TEST_CASE("meta/meta_base/hashed_string") {
namespace meta = meta_hpp;
using meta::detail::hashed_string;
SUBCASE("ctor/0") {
constexpr hashed_string hs{};
static_assert(hs == hashed_string{""});
static_assert(hs.get_hash() == hashed_string{""}.get_hash());
CHECK(hs == hashed_string{std::string{}});
CHECK(hs == hashed_string{std::string_view{}});
}
SUBCASE("ctor/1") {
constexpr hashed_string hs{"hello"};
static_assert(hs.get_hash() == meta::detail::fnv1a_hash("hello"));
CHECK(hs == hashed_string{std::string{"hello"}});
CHECK(hs == hashed_string{std::string_view{"hello"}});
}
SUBCASE("copy_ctor") {
constexpr hashed_string hs{"hello"};
constexpr hashed_string hs2{hs};
static_assert(hs == hs2);
static_assert(hs.get_hash() == hs2.get_hash());
}
SUBCASE("move_ctor") {
constexpr hashed_string hs{"hello"};
constexpr hashed_string hs2{std::move(hs)};
static_assert(hs == hs2);
static_assert(hs.get_hash() == hs2.get_hash());
}
SUBCASE("operator=/copy") {
constexpr hashed_string hs{"hello"};
constexpr hashed_string hs2 = [&hs](){
hashed_string r;
r = hs;
return r;
}();
static_assert(hs == hs2);
static_assert(hs.get_hash() == hs2.get_hash());
}
SUBCASE("operator=/move") {
constexpr hashed_string hs{"hello"};
constexpr hashed_string hs2 = [&hs](){
hashed_string r;
r = std::move(hs);
return r;
}();
static_assert(hs == hs2);
static_assert(hs.get_hash() == hs2.get_hash());
}
SUBCASE("get_hash") {
constexpr hashed_string hs1{"hello"};
constexpr hashed_string hs2{"world"};
static_assert(hs1.get_hash() == hashed_string{"hello"}.get_hash());
static_assert(hs1.get_hash() != hs2.get_hash());
CHECK(std::hash<hashed_string>{}(hs1) == hs1.get_hash());
}
SUBCASE("operator<") {
constexpr hashed_string hs1{"hello"};
constexpr hashed_string hs2{"hello"};
static_assert(!(hs1 < hs2) && !(hs2 < hs1));
static_assert(hs1 < hashed_string{"world"} || hashed_string{"world"} < hs1);
}
SUBCASE("operator==") {
constexpr hashed_string hs1{"hello"};
static_assert(hs1 == hashed_string{"hello"});
static_assert(hs1 != hashed_string{"world"});
}
SUBCASE("swap") {
hashed_string hs1{"hello"};
hashed_string hs2{"world"};
swap(hs1, hs2);
CHECK(hs1 == hashed_string{"world"});
CHECK(hs2 == hashed_string{"hello"});
}
}