Sun, 28 Sep 2025 22:32:42 +0200
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);