mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-14 19:41:29 +07:00
constexpr hashed_string
This commit is contained in:
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
95
develop/untests/meta_base/hashed_string_tests.cpp
Normal file
95
develop/untests/meta_base/hashed_string_tests.cpp
Normal 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"});
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,35 @@
|
||||
|
||||
#include "base.hpp"
|
||||
|
||||
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 {
|
||||
@@ -21,40 +50,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +86,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();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user