This is an automated email from the ASF dual-hosted git repository.

astitcher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git


The following commit(s) were added to refs/heads/main by this push:
     new 86281a4a7 PROTON-2888: [C++] Added std:hash specializations
86281a4a7 is described below

commit 86281a4a7c91bccde616e0d3524194f79a509a56
Author: Andrew Stitcher <[email protected]>
AuthorDate: Tue Apr 8 21:43:16 2025 -0400

    PROTON-2888: [C++] Added std:hash specializations
    
    This allows proton::uuid, proton::binary and proton::message_id to be
    used as keys in unordered std datastructures.
    
    Now we can use proton::binary as the key for std::unordered_map etc.
---
 cpp/include/proton/binary.hpp     |  8 ++++++++
 cpp/include/proton/message_id.hpp | 19 +++++++++++++++++++
 cpp/include/proton/uuid.hpp       |  8 ++++++++
 cpp/src/scalar_test.cpp           | 29 +++++++++++++++++++++++++++++
 cpp/src/tracing_opentelemetry.cpp |  8 --------
 5 files changed, 64 insertions(+), 8 deletions(-)

diff --git a/cpp/include/proton/binary.hpp b/cpp/include/proton/binary.hpp
index f7396f6b3..b01e40236 100644
--- a/cpp/include/proton/binary.hpp
+++ b/cpp/include/proton/binary.hpp
@@ -59,4 +59,12 @@ PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const 
binary&);
 
 } // proton
 
+/// Specialize std::hash so we can use proton::binary as a key for unordered 
datastructures
+template <> struct std::hash<proton::binary> {
+  std::size_t operator()(const proton::binary& k) const {
+      std::string s{k};
+      return std::hash<std::string>{}(s);
+  }
+};
+
 #endif // PROTON_BINARY_HPP
diff --git a/cpp/include/proton/message_id.hpp 
b/cpp/include/proton/message_id.hpp
index 2edcc2308..aacd35cdf 100644
--- a/cpp/include/proton/message_id.hpp
+++ b/cpp/include/proton/message_id.hpp
@@ -92,4 +92,23 @@ template<class T> T coerce(const message_id& x) { return 
internal::coerce<T>(x);
 
 } // proton
 
+/// Specialize std::hash so we can use proton::message_id as a key for 
unordered datastructures
+template <> struct std::hash<proton::message_id> {
+  std::size_t operator()(const proton::message_id& s) const {
+    std::size_t h;
+    auto type = s.type();
+    switch(type) {
+      case proton::ULONG:  h = 
std::hash<uint64_t>{}(proton::internal::get<uint64_t>(s)); break;
+      case proton::UUID:   h = 
std::hash<proton::uuid>{}(proton::internal::get<proton::uuid>(s)); break;
+      case proton::BINARY: h = 
std::hash<proton::binary>{}(proton::internal::get<proton::binary>(s)); break;
+      case proton::STRING: h = 
std::hash<std::string>{}(proton::internal::get<std::string>(s)); break;
+      default: throw proton::conversion_error("invalid message_id type 
"+type_name(s.type()));
+    }
+    auto type_hash = std::hash<proton::type_id>{}(type);
+    // Combine the two hashes - see https://stackoverflow.com/a/5889238
+    return h ^ (type_hash + 0x9e3779b9 + (h << 6) + (h >> 2));
+}
+
+};
+
 #endif // PROTON_MESSAGE_ID_HPP
diff --git a/cpp/include/proton/uuid.hpp b/cpp/include/proton/uuid.hpp
index a48712651..ce59a0db8 100644
--- a/cpp/include/proton/uuid.hpp
+++ b/cpp/include/proton/uuid.hpp
@@ -66,4 +66,12 @@ inline std::string to_string(const uuid& u) { return 
u.str(); }
 
 } // proton
 
+/// Specialize std::hash so we can use proton::uuid as a key for unordered 
datastructures
+template <> struct std::hash<proton::uuid> {
+  std::size_t operator()(const proton::uuid& k) const {
+      std::string s{k.begin(), k.end()};
+      return std::hash<std::string>{}(s);
+  };
+};
+
 #endif // PROTON_UUID_HPP
diff --git a/cpp/src/scalar_test.cpp b/cpp/src/scalar_test.cpp
index 54be0b974..9fcb53df0 100644
--- a/cpp/src/scalar_test.cpp
+++ b/cpp/src/scalar_test.cpp
@@ -56,6 +56,34 @@ void annotation_key_test() {
     ASSERT_EQUAL(scalar(symbol("foo")), annotation_key("foo"));
 }
 
+void hash_test() {
+    std::hash<binary> binary_hash;
+    ASSERT_EQUAL(binary_hash(binary("foo")), binary_hash(binary("foo")));
+    ASSERT(binary_hash(binary("foo")) != binary_hash(binary("bar")));
+
+    std::hash<uuid> uuid_hash;
+    auto u1 = uuid::random();
+    auto u2 = uuid::random();
+    ASSERT_EQUAL(uuid_hash(u1), uuid_hash(u1));
+    ASSERT(uuid_hash(u1) != uuid_hash(u2));
+
+    std::hash<message_id> message_id_hash;
+    ASSERT_EQUAL(message_id_hash(message_id("foo")), 
message_id_hash(message_id("foo")));
+    ASSERT(message_id_hash(message_id("foo")) != 
message_id_hash(message_id("bar")));
+    ASSERT_EQUAL(message_id_hash(message_id(23)), 
message_id_hash(message_id(23)));
+    ASSERT(message_id_hash(message_id(23)) != message_id_hash(message_id(24)));
+    ASSERT_EQUAL(message_id_hash(message_id(u1)), 
message_id_hash(message_id(u1)));
+    ASSERT(message_id_hash(message_id(u1)) != message_id_hash(message_id(u2)));
+    ASSERT_EQUAL(message_id_hash(message_id(binary("foo"))), 
message_id_hash(message_id(binary("foo"))));
+    ASSERT(message_id_hash(message_id(binary("foo"))) != 
message_id_hash(message_id(binary("bar"))));
+
+    binary b1{u1.begin(), u1.end()};
+    ASSERT(message_id_hash(message_id(b1)) != message_id_hash(message_id(u1)));
+    binary b23{23}; 
+    ASSERT(message_id_hash(message_id(b23)) != 
message_id_hash(message_id(23)));
+    
+}
+
 template <class T> T make(const char c) { T x; std::fill(x.begin(), x.end(), 
c); return x; }
 
 }
@@ -67,5 +95,6 @@ int main(int, char**) {
     RUN_TEST(failed, encode_decode_test());
     RUN_TEST(failed, message_id_test());
     RUN_TEST(failed, annotation_key_test());
+    RUN_TEST(failed, hash_test());
     return failed;
 }
diff --git a/cpp/src/tracing_opentelemetry.cpp 
b/cpp/src/tracing_opentelemetry.cpp
index e453f8381..a571fe8cb 100644
--- a/cpp/src/tracing_opentelemetry.cpp
+++ b/cpp/src/tracing_opentelemetry.cpp
@@ -55,14 +55,6 @@
 #include <string>
 #include <unordered_map>
 
-// Custom specialization of std::hash injected in namespace std for 
proton::binary as a key in tag_span i.e. an unordered_map.
-template <> struct std::hash<proton::binary> {
-    std::size_t operator()(const proton::binary& k) const {
-        std::string s(k[0], k.size());
-        return std::hash<std::string>{}(s);
-    }
-};
-
 namespace proton
 {
 namespace nostd = opentelemetry::nostd;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to