Some more work on hashing
This commit is contained in:
@ -58,6 +58,7 @@ cc_library(
|
|||||||
"float",
|
"float",
|
||||||
"format",
|
"format",
|
||||||
"functional",
|
"functional",
|
||||||
|
"hash",
|
||||||
"integers",
|
"integers",
|
||||||
"maybe_uninit",
|
"maybe_uninit",
|
||||||
"meta",
|
"meta",
|
||||||
|
27
asl/hash.hpp
27
asl/hash.hpp
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "asl/integers.hpp"
|
#include "asl/integers.hpp"
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/span.hpp"
|
||||||
|
|
||||||
namespace asl::city_hash
|
namespace asl::city_hash
|
||||||
{
|
{
|
||||||
@ -68,6 +68,15 @@ struct HashState
|
|||||||
constexpr HashState() = default;
|
constexpr HashState() = default;
|
||||||
explicit constexpr HashState(uint128_t s) : state{s} {}
|
explicit constexpr HashState(uint128_t s) : state{s} {}
|
||||||
|
|
||||||
|
static HashState combine_bytes(HashState h, span<const byte> bytes)
|
||||||
|
{
|
||||||
|
auto hashed = city_hash::CityHash128WithSeed(
|
||||||
|
reinterpret_cast<const char*>(bytes.data()),
|
||||||
|
static_cast<size_t>(bytes.size()),
|
||||||
|
h.state);
|
||||||
|
return HashState{hashed};
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr HashState combine(HashState h)
|
static constexpr HashState combine(HashState h)
|
||||||
{
|
{
|
||||||
return h;
|
return h;
|
||||||
@ -86,8 +95,20 @@ concept hashable = hashable_generic<T, HashState>;
|
|||||||
template<typename H, uniquely_represented T>
|
template<typename H, uniquely_represented T>
|
||||||
constexpr H AslHashValue(H h, const T& value)
|
constexpr H AslHashValue(H h, const T& value)
|
||||||
{
|
{
|
||||||
auto hashed = city_hash::CityHash128WithSeed(reinterpret_cast<const char*>(&value), size_of<T>, h.state);
|
return H::combine_bytes(h, as_bytes(span<const T>{&value, 1}));
|
||||||
return HashState{hashed};
|
}
|
||||||
|
|
||||||
|
template<typename H>
|
||||||
|
constexpr H AslHashValue(H h, bool value)
|
||||||
|
{
|
||||||
|
return AslHashValue(h, value ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<hashable T>
|
||||||
|
constexpr uint64_t hash_value(const T& value)
|
||||||
|
{
|
||||||
|
auto result = AslHashValue(HashState{}, value).state;
|
||||||
|
return city_hash::Hash128to64(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
@ -57,6 +57,12 @@ public:
|
|||||||
{
|
{
|
||||||
return as_string_view() == other;
|
return as_string_view() == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename H>
|
||||||
|
friend H AslHashValue(H h, const string& str)
|
||||||
|
{
|
||||||
|
return H::combine(h, str.as_string_view());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
string() -> string<>;
|
string() -> string<>;
|
||||||
|
@ -85,6 +85,12 @@ public:
|
|||||||
if (m_size != other.m_size) { return false; }
|
if (m_size != other.m_size) { return false; }
|
||||||
return memcmp(m_data, other.m_data, m_size) == 0;
|
return memcmp(m_data, other.m_data, m_size) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename H>
|
||||||
|
friend H AslHashValue(H h, string_view sv)
|
||||||
|
{
|
||||||
|
return H::combine(H::combine_bytes(h, as_bytes(sv.as_span())), sv.size());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
58
asl/tests/hash_tests.cpp
Normal file
58
asl/tests/hash_tests.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "asl/testing/testing.hpp"
|
||||||
|
#include "asl/hash.hpp"
|
||||||
|
#include "asl/string_view.hpp"
|
||||||
|
#include "asl/string.hpp"
|
||||||
|
|
||||||
|
static_assert(asl::hashable<uint8_t>);
|
||||||
|
static_assert(asl::hashable<uint16_t>);
|
||||||
|
static_assert(asl::hashable<uint32_t>);
|
||||||
|
static_assert(asl::hashable<uint64_t>);
|
||||||
|
static_assert(asl::hashable<uint128_t>);
|
||||||
|
|
||||||
|
static_assert(asl::hashable<int8_t>);
|
||||||
|
static_assert(asl::hashable<int16_t>);
|
||||||
|
static_assert(asl::hashable<int32_t>);
|
||||||
|
static_assert(asl::hashable<int64_t>);
|
||||||
|
|
||||||
|
ASL_TEST(integers)
|
||||||
|
{
|
||||||
|
uint64_t a = asl::hash_value<uint16_t>(45);
|
||||||
|
uint64_t b = asl::hash_value<uint16_t>(45);
|
||||||
|
uint64_t c = asl::hash_value<uint16_t>(46);
|
||||||
|
uint64_t d = asl::hash_value<uint32_t>(45);
|
||||||
|
|
||||||
|
ASL_TEST_EXPECT(a == b);
|
||||||
|
ASL_TEST_EXPECT(a != c);
|
||||||
|
ASL_TEST_EXPECT(a != d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(asl::hashable<bool>);
|
||||||
|
|
||||||
|
ASL_TEST(bool)
|
||||||
|
{
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value(true) == asl::hash_value(true));
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value(false) == asl::hash_value(false));
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value(true) != asl::hash_value(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(asl::hashable<asl::string_view>);
|
||||||
|
static_assert(asl::hashable<asl::string<>>);
|
||||||
|
|
||||||
|
ASL_TEST(strings)
|
||||||
|
{
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) == asl::hash_value("hello"_sv));
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) != asl::hash_value("hello "_sv));
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) != asl::hash_value("HELLO"_sv));
|
||||||
|
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value(asl::string("hello"_sv)) == asl::hash_value(asl::string("hello"_sv)));
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value(asl::string("hello"_sv)) != asl::hash_value(asl::string("hello "_sv)));
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value(asl::string("hello"_sv)) != asl::hash_value(asl::string("HELLO"_sv)));
|
||||||
|
|
||||||
|
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) == asl::hash_value(asl::string("hello"_sv)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Todo span, buffer (add combine_contiguous (optimize uniquely_represented))
|
||||||
|
// @Todo enum classes
|
||||||
|
// @Todo option (optimize uniquely_represented + has_niche)
|
||||||
|
// @Todo status, status_or
|
||||||
|
// @Todo box
|
Reference in New Issue
Block a user