From 5565183495fd55394bbae8f15830ea715c3cb45c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 15 Jan 2026 17:39:17 -0500 Subject: [PATCH] xo-objectd2: + DString.hash() + utest --- xo-object2/include/xo/object2/DString.hpp | 15 ++++++++++++ xo-object2/utest/DString.test.cpp | 29 +++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/xo-object2/include/xo/object2/DString.hpp b/xo-object2/include/xo/object2/DString.hpp index da891e7f..fb236721 100644 --- a/xo-object2/include/xo/object2/DString.hpp +++ b/xo-object2/include/xo/object2/DString.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include //#include @@ -169,6 +170,11 @@ namespace xo { **/ static int compare(const DString & lhs, const DString & rhs) noexcept; + /** compute hash of string contents **/ + std::size_t hash() const noexcept { + return std::hash{}(std::string_view(chars_, size_)); + } + // TODO - behave like std::string, to the extent feasible // insert // insert_range @@ -273,4 +279,13 @@ namespace xo { } /*namespace scm*/ } /*namespace xo*/ +namespace std { + template <> + struct hash { + std::size_t operator()(const xo::scm::DString & x) const noexcept { + return x.hash(); + } + }; +} /*namespace std*/ + /* end DString.hpp */ diff --git a/xo-object2/utest/DString.test.cpp b/xo-object2/utest/DString.test.cpp index 19ade045..21f33bd8 100644 --- a/xo-object2/utest/DString.test.cpp +++ b/xo-object2/utest/DString.test.cpp @@ -358,6 +358,35 @@ namespace xo { REQUIRE(*apple1 >= *apple2); REQUIRE_FALSE(*apple1 >= *banana); } + + TEST_CASE("DString-hash", "[object2][DString]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + + DString * s1 = DString::from_cstr(alloc, "hello"); + DString * s2 = DString::from_cstr(alloc, "hello"); + DString * s3 = DString::from_cstr(alloc, "world"); + DString * empty1 = DString::empty(alloc, 16); + DString * empty2 = DString::empty(alloc, 32); + + // same content produces same hash + REQUIRE(s1->hash() == s2->hash()); + + // empty strings have same hash + REQUIRE(empty1->hash() == empty2->hash()); + + // different content produces different hash (not guaranteed, but highly likely) + REQUIRE(s1->hash() != s3->hash()); + + // std::hash specialization works + std::hash hasher; + REQUIRE(hasher(*s1) == s1->hash()); + REQUIRE(hasher(*s2) == s2->hash()); + REQUIRE(hasher(*s1) == hasher(*s2)); + } } /*namespace ut*/ } /*namespace xo*/