add generic CX_HASH_KEY() macro default tip

Sun, 28 Sep 2025 22:32:42 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 28 Sep 2025 22:32:42 +0200
changeset 1402
6fa42f7e2624
parent 1401
a76249f50237

add generic CX_HASH_KEY() macro

relates to #731

src/cx/hash_key.h file | annotate | diff | comparison | revisions
tests/test_hash_key.c file | annotate | diff | comparison | revisions
--- a/src/cx/hash_key.h	Sat Sep 27 17:53:41 2025 +0200
+++ b/src/cx/hash_key.h	Sun Sep 28 22:32:42 2025 +0200
@@ -138,6 +138,24 @@
 CxHashKey cx_hash_key_str(const char *str);
 
 /**
+ * Computes a hash key from a string.
+ *
+ * Use this function when the string is represented
+ * as an unsigned char array.
+ *
+ * The string needs to be zero-terminated.
+ *
+ * @param str the string
+ * @return the hash key
+ */
+cx_attr_nodiscard
+cx_attr_cstr_arg(1)
+cx_attr_export
+static inline CxHashKey cx_hash_key_ustr(const unsigned char *str) {
+    return cx_hash_key_str((const char*)str);
+}
+
+/**
  * Computes a hash key from a byte array.
  *
  * @param bytes the array
@@ -185,6 +203,54 @@
 /**
  * Computes a hash key from a UCX string.
  *
+ * @param str the string
+ * @return the hash key
+ */
+cx_attr_nodiscard
+static inline CxHashKey cx_hash_key_mutstr(cxmutstr str) {
+    return cx_hash_key(str.ptr, str.length);
+}
+
+/**
+ * The identity function for the CX_HASH_KEY() macro.
+ * You should never need to use this manually.
+ *
+ * @param key the key
+ * @return a copy of the key
+ */
+cx_attr_nodiscard
+static inline CxHashKey cx_hash_key_identity(CxHashKey key) {
+    return key;
+}
+
+/**
+ * Creates a hash key from any of the supported types with implicit length.
+ *
+ * Does nothing when passing a CxHashkey.
+ *
+ * Supported types are UCX strings, zero-terminated C strings,
+ * and 32-bit or 64-bit unsigned integers.
+ *
+ * @param key the key data
+ * @returns the @c CxHashKey
+ */
+#define CX_HASH_KEY(key) _Generic((key), \
+        CxHashKey: cx_hash_key_identity, \
+        cxstring: cx_hash_key_cxstr, \
+        cxmutstr: cx_hash_key_mutstr, \
+        char*: cx_hash_key_str, \
+        const char*: cx_hash_key_str, \
+        unsigned char*: cx_hash_key_ustr, \
+        const unsigned char*: cx_hash_key_ustr, \
+        uint32_t: cx_hash_key_u32, \
+        uint64_t: cx_hash_key_u64) \
+        (key)
+
+
+/**
+ * Computes a hash key from a UCX string.
+ * Convenience macro that accepts both cxstring and cxmutstr.
+ * @deprecated use the CX_HASH_KEY() macro instead
  * @param str (@c cxstring or @c cxmutstr) the string
  * @return (@c CxHashKey) the hash key
  */
--- a/tests/test_hash_key.c	Sat Sep 27 17:53:41 2025 +0200
+++ b/tests/test_hash_key.c	Sun Sep 28 22:32:42 2025 +0200
@@ -41,14 +41,68 @@
     CxHashKey cxstr_key = cx_hash_key_cxstr(cx_str(str));
 
     CX_TEST_DO {
+        CX_TEST_ASSERT(bytes_key.hash == 1269566022);
         CX_TEST_ASSERT(str_key.hash == bytes_key.hash);
         CX_TEST_ASSERT(obj_key.hash == bytes_key.hash);
         CX_TEST_ASSERT(cxstr_key.hash == bytes_key.hash);
         CX_TEST_ASSERT(str_key.len == len);
+        CX_TEST_ASSERT(str_key.data == str);
         CX_TEST_ASSERT(cxstr_key.len == len);
+        CX_TEST_ASSERT(cxstr_key.data == str);
+        CX_TEST_ASSERT(obj_key.len == len);
+        CX_TEST_ASSERT(obj_key.data == str);
         CX_TEST_ASSERT(bytes_key.len == len);
+        CX_TEST_ASSERT(bytes_key.data == str);
+    }
+}
+
+CX_TEST(test_hash_key_int_functions) {
+    uint32_t a = 0xabc01337u;
+    uint64_t b = 0xabc0133747110815ull;
+
+    CxHashKey ak = cx_hash_key_u32(a);
+    CxHashKey bk = cx_hash_key_u64(b);
+
+    CX_TEST_DO {
+        CX_TEST_ASSERT(ak.data == NULL);
+        CX_TEST_ASSERT(ak.len == 0);
+        CX_TEST_ASSERT(ak.hash == 3897006249);
+        CX_TEST_ASSERT(bk.data == NULL);
+        CX_TEST_ASSERT(bk.len == 0);
+        CX_TEST_ASSERT(bk.hash == 17452435587688253422ull);
+    }
+}
+
+CX_TEST(test_hash_key_macro) {
+    const char *str = "my key";
+    size_t len = strlen(str);
+    uint32_t a = 0xabc01337u;
+    uint64_t b = 0xabc0133747110815ull;
+
+    CxHashKey str_key = CX_HASH_KEY(str);
+    CxHashKey bytes_key = CX_HASH_KEY((const unsigned char*)str);
+    CxHashKey mutstr_key = CX_HASH_KEY(cx_mutstr((char*)str));
+    CxHashKey cxstr_key = CX_HASH_KEY(cx_str(str));
+    CxHashKey ak = CX_HASH_KEY(a);
+    CxHashKey bk = CX_HASH_KEY(b);
+
+    CX_TEST_DO {
+        CX_TEST_ASSERT(bytes_key.hash == 1269566022);
+        CX_TEST_ASSERT(str_key.hash == bytes_key.hash);
+        CX_TEST_ASSERT(cxstr_key.hash == bytes_key.hash);
+        CX_TEST_ASSERT(mutstr_key.hash == bytes_key.hash);
+        CX_TEST_ASSERT(str_key.len == len);
+        CX_TEST_ASSERT(str_key.data == str);
+        CX_TEST_ASSERT(cxstr_key.len == len);
+        CX_TEST_ASSERT(cxstr_key.data == str);
         CX_TEST_ASSERT(bytes_key.len == len);
-        CX_TEST_ASSERT(str_key.data == str);
+        CX_TEST_ASSERT(bytes_key.data == str);
+        CX_TEST_ASSERT(ak.data == NULL);
+        CX_TEST_ASSERT(ak.len == 0);
+        CX_TEST_ASSERT(ak.hash == 3897006249);
+        CX_TEST_ASSERT(bk.data == NULL);
+        CX_TEST_ASSERT(bk.len == 0);
+        CX_TEST_ASSERT(bk.hash == 17452435587688253422ull);
     }
 }
 
@@ -90,6 +144,7 @@
     CxTestSuite *suite = cx_test_suite_new("hash_key");
 
     cx_test_register(suite, test_hash_key_functions);
+    cx_test_register(suite, test_hash_key_int_functions);
     cx_test_register(suite, test_hash_key_empty_string);
     cx_test_register(suite, test_hash_key_null);
 

mercurial