bring a generic interface to CxMap

Fri, 21 Apr 2023 19:50:43 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 21 Apr 2023 19:50:43 +0200
changeset 691
65baf7f45ac8
parent 690
2c2304622981
child 692
6ac92936cd44

bring a generic interface to CxMap

src/cx/hash_map.h file | annotate | diff | comparison | revisions
src/cx/map.h file | annotate | diff | comparison | revisions
src/hash_map.c file | annotate | diff | comparison | revisions
tests/CMakeLists.txt file | annotate | diff | comparison | revisions
tests/test_map.cpp file | annotate | diff | comparison | revisions
tests/test_map_generics.c file | annotate | diff | comparison | revisions
tests/test_map_generics.h file | annotate | diff | comparison | revisions
--- a/src/cx/hash_map.h	Fri Apr 21 18:38:18 2023 +0200
+++ b/src/cx/hash_map.h	Fri Apr 21 19:50:43 2023 +0200
@@ -84,7 +84,7 @@
  */
 __attribute__((__nonnull__, __warn_unused_result__))
 CxMap *cxHashMapCreate(
-        CxAllocator *allocator,
+        CxAllocator const *allocator,
         size_t itemsize,
         size_t buckets
 );
--- a/src/cx/map.h	Fri Apr 21 18:38:18 2023 +0200
+++ b/src/cx/map.h	Fri Apr 21 19:50:43 2023 +0200
@@ -39,6 +39,7 @@
 
 #include "common.h"
 #include "collection.h"
+#include "string.h"
 #include "hash_key.h"
 
 #ifdef    __cplusplus
@@ -211,108 +212,6 @@
     map->cl->clear(map);
 }
 
-/**
- * Puts a key/value-pair into the map.
- *
- * @param map the map
- * @param key the key
- * @param value the value
- * @return 0 on success, non-zero value on failure
- */
-__attribute__((__nonnull__))
-static inline int cxMapPut(
-        CxMap *map,
-        CxHashKey key,
-        void *value
-) {
-    return map->cl->put(map, key, value);
-}
-
-/**
- * Retrieves a value by using a key.
- *
- * @param map the map
- * @param key the key
- * @return the value
- */
-__attribute__((__nonnull__, __warn_unused_result__))
-static inline void *cxMapGet(
-        CxMap const *map,
-        CxHashKey key
-) {
-    return map->cl->get(map, key);
-}
-
-/**
- * Removes a key/value-pair from the map by using the key.
- *
- * Always invokes the destructor function, if any, on the removed element.
- * If this map is storing pointers and you just want to retrieve the pointer
- * without invoking the destructor, use cxMapRemoveAndGet().
- * If you just want to detach the element from the map without invoking the
- * destructor or returning the element, use cxMapDetach().
- *
- * @param map the map
- * @param key the key
- * @see cxMapRemoveAndGet()
- * @see cxMapDetach()
- */
-__attribute__((__nonnull__))
-static inline void cxMapRemove(
-        CxMap *map,
-        CxHashKey key
-) {
-    (void) map->cl->remove(map, key, true);
-}
-
-/**
- * Detaches a key/value-pair from the map by using the key
- * without invoking the destructor.
- *
- * In general, you should only use this function if the map does not own
- * the data and there is a valid reference to the data somewhere else
- * in the program. In all other cases it is preferable to use
- * cxMapRemove() or cxMapRemoveAndGet().
- *
- * @param map the map
- * @param key the key
- * @see cxMapRemove()
- * @see cxMapRemoveAndGet()
- */
-__attribute__((__nonnull__))
-static inline void cxMapDetach(
-        CxMap *map,
-        CxHashKey key
-) {
-    (void) map->cl->remove(map, key, false);
-}
-
-/**
- * Removes a key/value-pair from the map by using the key.
- *
- * This function can be used when the map is storing pointers,
- * in order to retrieve the pointer from the map without invoking
- * any destructor function. Sometimes you do not want the pointer
- * to be returned - in that case (instead of suppressing the "unused
- * result" warning) you can use cxMapDetach().
- *
- * If this map is not storing pointers, this function behaves like
- * cxMapRemove() and returns \c NULL.
- *
- * @param map the map
- * @param key the key
- * @return the stored pointer or \c NULL if either the key is not present
- * in the map or the map is not storing pointers
- * @see cxMapStorePointers()
- * @see cxMapDetach()
- */
-__attribute__((__nonnull__, __warn_unused_result__))
-static inline void *cxMapRemoveAndGet(
-        CxMap *map,
-        CxHashKey key
-) {
-    return map->cl->remove(map, key, !map->store_pointer);
-}
 
 // TODO: set-like map operations (union, intersect, difference)
 
@@ -413,8 +312,644 @@
     return map->cl->mut_iterator(map);
 }
 
-#ifdef    __cplusplus
+#ifdef __cplusplus
+} // end the extern "C" block here, because we want to start overloading
+
+/**
+ * Puts a key/value-pair into the map.
+ *
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @return 0 on success, non-zero value on failure
+ */
+__attribute__((__nonnull__))
+static inline int cxMapPut(
+        CxMap *map,
+        CxHashKey const &key,
+        void *value
+) {
+    return map->cl->put(map, key, value);
+}
+
+
+/**
+ * Puts a key/value-pair into the map.
+ *
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @return 0 on success, non-zero value on failure
+ */
+__attribute__((__nonnull__))
+static inline int cxMapPut(
+        CxMap *map,
+        cxstring const &key,
+        void *value
+) {
+    return map->cl->put(map, cx_hash_key_cxstr(key), value);
+}
+
+/**
+ * Puts a key/value-pair into the map.
+ *
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @return 0 on success, non-zero value on failure
+ */
+__attribute__((__nonnull__))
+static inline int cxMapPut(
+        CxMap *map,
+        char const *key,
+        void *value
+) {
+    return map->cl->put(map, cx_hash_key_str(key), value);
+}
+
+/**
+ * Retrieves a value by using a key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the value
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cxMapGet(
+        CxMap const *map,
+        CxHashKey const &key
+) {
+    return map->cl->get(map, key);
+}
+
+/**
+ * Retrieves a value by using a key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the value
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cxMapGet(
+        CxMap const *map,
+        cxstring const &key
+) {
+    return map->cl->get(map, cx_hash_key_cxstr(key));
+}
+
+/**
+ * Retrieves a value by using a key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the value
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cxMapGet(
+        CxMap const *map,
+        char const *key
+) {
+    return map->cl->get(map, cx_hash_key_str(key));
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * Always invokes the destructor function, if any, on the removed element.
+ * If this map is storing pointers and you just want to retrieve the pointer
+ * without invoking the destructor, use cxMapRemoveAndGet().
+ * If you just want to detach the element from the map without invoking the
+ * destructor or returning the element, use cxMapDetach().
+ *
+ * @param map the map
+ * @param key the key
+ * @see cxMapRemoveAndGet()
+ * @see cxMapDetach()
+ */
+__attribute__((__nonnull__))
+static inline void cxMapRemove(
+        CxMap *map,
+        CxHashKey const &key
+) {
+    (void) map->cl->remove(map, key, true);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * Always invokes the destructor function, if any, on the removed element.
+ * If this map is storing pointers and you just want to retrieve the pointer
+ * without invoking the destructor, use cxMapRemoveAndGet().
+ * If you just want to detach the element from the map without invoking the
+ * destructor or returning the element, use cxMapDetach().
+ *
+ * @param map the map
+ * @param key the key
+ * @see cxMapRemoveAndGet()
+ * @see cxMapDetach()
+ */
+__attribute__((__nonnull__))
+static inline void cxMapRemove(
+        CxMap *map,
+        cxstring const &key
+) {
+    (void) map->cl->remove(map, cx_hash_key_cxstr(key), true);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * Always invokes the destructor function, if any, on the removed element.
+ * If this map is storing pointers and you just want to retrieve the pointer
+ * without invoking the destructor, use cxMapRemoveAndGet().
+ * If you just want to detach the element from the map without invoking the
+ * destructor or returning the element, use cxMapDetach().
+ *
+ * @param map the map
+ * @param key the key
+ * @see cxMapRemoveAndGet()
+ * @see cxMapDetach()
+ */
+__attribute__((__nonnull__))
+static inline void cxMapRemove(
+        CxMap *map,
+        char const *key
+) {
+    (void) map->cl->remove(map, cx_hash_key_str(key), true);
+}
+
+/**
+ * Detaches a key/value-pair from the map by using the key
+ * without invoking the destructor.
+ *
+ * In general, you should only use this function if the map does not own
+ * the data and there is a valid reference to the data somewhere else
+ * in the program. In all other cases it is preferable to use
+ * cxMapRemove() or cxMapRemoveAndGet().
+ *
+ * @param map the map
+ * @param key the key
+ * @see cxMapRemove()
+ * @see cxMapRemoveAndGet()
+ */
+__attribute__((__nonnull__))
+static inline void cxMapDetach(
+        CxMap *map,
+        CxHashKey const &key
+) {
+    (void) map->cl->remove(map, key, false);
+}
+
+/**
+ * Detaches a key/value-pair from the map by using the key
+ * without invoking the destructor.
+ *
+ * In general, you should only use this function if the map does not own
+ * the data and there is a valid reference to the data somewhere else
+ * in the program. In all other cases it is preferable to use
+ * cxMapRemove() or cxMapRemoveAndGet().
+ *
+ * @param map the map
+ * @param key the key
+ * @see cxMapRemove()
+ * @see cxMapRemoveAndGet()
+ */
+__attribute__((__nonnull__))
+static inline void cxMapDetach(
+        CxMap *map,
+        cxstring const &key
+) {
+    (void) map->cl->remove(map, cx_hash_key_cxstr(key), false);
+}
+
+/**
+ * Detaches a key/value-pair from the map by using the key
+ * without invoking the destructor.
+ *
+ * In general, you should only use this function if the map does not own
+ * the data and there is a valid reference to the data somewhere else
+ * in the program. In all other cases it is preferable to use
+ * cxMapRemove() or cxMapRemoveAndGet().
+ *
+ * @param map the map
+ * @param key the key
+ * @see cxMapRemove()
+ * @see cxMapRemoveAndGet()
+ */
+__attribute__((__nonnull__))
+static inline void cxMapDetach(
+        CxMap *map,
+        char const *key
+) {
+    (void) map->cl->remove(map, cx_hash_key_str(key), false);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * This function can be used when the map is storing pointers,
+ * in order to retrieve the pointer from the map without invoking
+ * any destructor function. Sometimes you do not want the pointer
+ * to be returned - in that case (instead of suppressing the "unused
+ * result" warning) you can use cxMapDetach().
+ *
+ * If this map is not storing pointers, this function behaves like
+ * cxMapRemove() and returns \c NULL.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the stored pointer or \c NULL if either the key is not present
+ * in the map or the map is not storing pointers
+ * @see cxMapStorePointers()
+ * @see cxMapDetach()
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cxMapRemoveAndGet(
+        CxMap *map,
+        CxHashKey key
+) {
+    return map->cl->remove(map, key, !map->store_pointer);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * This function can be used when the map is storing pointers,
+ * in order to retrieve the pointer from the map without invoking
+ * any destructor function. Sometimes you do not want the pointer
+ * to be returned - in that case (instead of suppressing the "unused
+ * result" warning) you can use cxMapDetach().
+ *
+ * If this map is not storing pointers, this function behaves like
+ * cxMapRemove() and returns \c NULL.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the stored pointer or \c NULL if either the key is not present
+ * in the map or the map is not storing pointers
+ * @see cxMapStorePointers()
+ * @see cxMapDetach()
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cxMapRemoveAndGet(
+        CxMap *map,
+        cxstring key
+) {
+    return map->cl->remove(map, cx_hash_key_cxstr(key), !map->store_pointer);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * This function can be used when the map is storing pointers,
+ * in order to retrieve the pointer from the map without invoking
+ * any destructor function. Sometimes you do not want the pointer
+ * to be returned - in that case (instead of suppressing the "unused
+ * result" warning) you can use cxMapDetach().
+ *
+ * If this map is not storing pointers, this function behaves like
+ * cxMapRemove() and returns \c NULL.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the stored pointer or \c NULL if either the key is not present
+ * in the map or the map is not storing pointers
+ * @see cxMapStorePointers()
+ * @see cxMapDetach()
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cxMapRemoveAndGet(
+        CxMap *map,
+        char const *key
+) {
+    return map->cl->remove(map, cx_hash_key_str(key), !map->store_pointer);
 }
-#endif
+
+#else // __cplusplus
+
+/**
+ * Puts a key/value-pair into the map.
+ *
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @return 0 on success, non-zero value on failure
+ */
+__attribute__((__nonnull__))
+static inline int cx_map_put(
+        CxMap *map,
+        CxHashKey key,
+        void *value
+) {
+    return map->cl->put(map, key, value);
+}
+
+/**
+ * Puts a key/value-pair into the map.
+ *
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @return 0 on success, non-zero value on failure
+ */
+__attribute__((__nonnull__))
+static inline int cx_map_put_cxstr(
+        CxMap *map,
+        cxstring key,
+        void *value
+) {
+    return map->cl->put(map, cx_hash_key_cxstr(key), value);
+}
+
+/**
+ * Puts a key/value-pair into the map.
+ *
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @return 0 on success, non-zero value on failure
+ */
+__attribute__((__nonnull__))
+static inline int cx_map_put_str(
+        CxMap *map,
+        char const *key,
+        void *value
+) {
+    return map->cl->put(map, cx_hash_key_str(key), value);
+}
+
+/**
+ * Puts a key/value-pair into the map.
+ *
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @return 0 on success, non-zero value on failure
+ */
+#define cxMapPut(map, key, value) _Generic((key), \
+    CxHashKey: cx_map_put,                        \
+    cxstring: cx_map_put_cxstr,                   \
+    char*: cx_map_put_str)                        \
+    (map, key, value)
+
+/**
+ * Retrieves a value by using a key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the value
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cx_map_get(
+        CxMap const *map,
+        CxHashKey key
+) {
+    return map->cl->get(map, key);
+}
+
+/**
+ * Retrieves a value by using a key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the value
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cx_map_get_cxstr(
+        CxMap const *map,
+        cxstring key
+) {
+    return map->cl->get(map, cx_hash_key_cxstr(key));
+}
+
+/**
+ * Retrieves a value by using a key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the value
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cx_map_get_str(
+        CxMap const *map,
+        char const *key
+) {
+    return map->cl->get(map, cx_hash_key_str(key));
+}
+
+/**
+ * Retrieves a value by using a key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the value
+ */
+#define cxMapGet(map, key) _Generic((key), \
+    CxHashKey: cx_map_get,                 \
+    cxstring: cx_map_get_cxstr,            \
+    char*: cx_map_get_str)                 \
+    (map, key)
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * @param map the map
+ * @param key the key
+ */
+__attribute__((__nonnull__))
+static inline void cx_map_remove(
+        CxMap *map,
+        CxHashKey key
+) {
+    (void) map->cl->remove(map, key, true);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * @param map the map
+ * @param key the key
+ */
+__attribute__((__nonnull__))
+static inline void cx_map_remove_cxstr(
+        CxMap *map,
+        cxstring key
+) {
+    (void) map->cl->remove(map, cx_hash_key_cxstr(key), true);
+}
 
-#endif // UCX_MAP_H
\ No newline at end of file
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * @param map the map
+ * @param key the key
+ */
+__attribute__((__nonnull__))
+static inline void cx_map_remove_str(
+        CxMap *map,
+        char const *key
+) {
+    (void) map->cl->remove(map, cx_hash_key_str(key), true);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * Always invokes the destructor function, if any, on the removed element.
+ * If this map is storing pointers and you just want to retrieve the pointer
+ * without invoking the destructor, use cxMapRemoveAndGet().
+ * If you just want to detach the element from the map without invoking the
+ * destructor or returning the element, use cxMapDetach().
+ *
+ * @param map the map
+ * @param key the key
+ * @see cxMapRemoveAndGet()
+ * @see cxMapDetach()
+ */
+#define cxMapRemove(map, key) _Generic((key), \
+    CxHashKey: cx_map_remove,                 \
+    cxstring: cx_map_remove_cxstr,            \
+    char*: cx_map_remove_str)                 \
+    (map, key)
+
+/**
+ * Detaches a key/value-pair from the map by using the key
+ * without invoking the destructor.
+ *
+ * @param map the map
+ * @param key the key
+ */
+__attribute__((__nonnull__))
+static inline void cx_map_detach(
+        CxMap *map,
+        CxHashKey key
+) {
+    (void) map->cl->remove(map, key, false);
+}
+
+/**
+ * Detaches a key/value-pair from the map by using the key
+ * without invoking the destructor.
+ *
+ * @param map the map
+ * @param key the key
+ */
+__attribute__((__nonnull__))
+static inline void cx_map_detach_cxstr(
+        CxMap *map,
+        cxstring key
+) {
+    (void) map->cl->remove(map, cx_hash_key_cxstr(key), false);
+}
+
+/**
+ * Detaches a key/value-pair from the map by using the key
+ * without invoking the destructor.
+ *
+ * @param map the map
+ * @param key the key
+ */
+__attribute__((__nonnull__))
+static inline void cx_map_detach_str(
+        CxMap *map,
+        char const *key
+) {
+    (void) map->cl->remove(map, cx_hash_key_str(key), false);
+}
+
+/**
+ * Detaches a key/value-pair from the map by using the key
+ * without invoking the destructor.
+ *
+ * In general, you should only use this function if the map does not own
+ * the data and there is a valid reference to the data somewhere else
+ * in the program. In all other cases it is preferable to use
+ * cxMapRemove() or cxMapRemoveAndGet().
+ *
+ * @param map the map
+ * @param key the key
+ * @see cxMapRemove()
+ * @see cxMapRemoveAndGet()
+ */
+#define cxMapDetach(map, key) _Generic((key), \
+    CxHashKey: cx_map_detach,                 \
+    cxstring: cx_map_detach_cxstr,            \
+    char*: cx_map_detach_str)                 \
+    (map, key)
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the stored pointer or \c NULL if either the key is not present
+ * in the map or the map is not storing pointers
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cx_map_remove_and_get(
+        CxMap *map,
+        CxHashKey key
+) {
+    return map->cl->remove(map, key, !map->store_pointer);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the stored pointer or \c NULL if either the key is not present
+ * in the map or the map is not storing pointers
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cx_map_remove_and_get_cxstr(
+        CxMap *map,
+        cxstring key
+) {
+    return map->cl->remove(map, cx_hash_key_cxstr(key), !map->store_pointer);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the stored pointer or \c NULL if either the key is not present
+ * in the map or the map is not storing pointers
+ */
+__attribute__((__nonnull__, __warn_unused_result__))
+static inline void *cx_map_remove_and_get_str(
+        CxMap *map,
+        char const *key
+) {
+    return map->cl->remove(map, cx_hash_key_str(key), !map->store_pointer);
+}
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * This function can be used when the map is storing pointers,
+ * in order to retrieve the pointer from the map without invoking
+ * any destructor function. Sometimes you do not want the pointer
+ * to be returned - in that case (instead of suppressing the "unused
+ * result" warning) you can use cxMapDetach().
+ *
+ * If this map is not storing pointers, this function behaves like
+ * cxMapRemove() and returns \c NULL.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the stored pointer or \c NULL if either the key is not present
+ * in the map or the map is not storing pointers
+ * @see cxMapStorePointers()
+ * @see cxMapDetach()
+ */
+#define cxMapRemoveAndGet(map, key) _Generic((key), \
+    CxHashKey: cx_map_remove_and_get,               \
+    cxstring: cx_map_remove_and_get_cxstr,          \
+    char*: cx_map_remove_and_get_str)               \
+    (map, key)
+
+#endif // __cplusplus
+
+#endif // UCX_MAP_H
--- a/src/hash_map.c	Fri Apr 21 18:38:18 2023 +0200
+++ b/src/hash_map.c	Fri Apr 21 19:50:43 2023 +0200
@@ -419,7 +419,7 @@
 };
 
 CxMap *cxHashMapCreate(
-        CxAllocator *allocator,
+        CxAllocator const *allocator,
         size_t itemsize,
         size_t buckets
 ) {
--- a/tests/CMakeLists.txt	Fri Apr 21 18:38:18 2023 +0200
+++ b/tests/CMakeLists.txt	Fri Apr 21 19:50:43 2023 +0200
@@ -26,6 +26,7 @@
         test_tree.cpp
         test_hash_key.cpp
         test_map.cpp
+        test_map_generics.c
         test_basic_mempool.cpp
         test_printf.cpp
         selftest.cpp
--- a/tests/test_map.cpp	Fri Apr 21 18:38:18 2023 +0200
+++ b/tests/test_map.cpp	Fri Apr 21 19:50:43 2023 +0200
@@ -30,6 +30,7 @@
 #include "cx/utils.h"
 #include "cx/string.h"
 #include "util_allocator.h"
+#include "test_map_generics.h"
 
 #include <gtest/gtest.h>
 #include <unordered_map>
@@ -74,7 +75,7 @@
         auto keyiter = cxMapIteratorKeys(map);
         std::unordered_set<std::string> keys;
         cx_foreach(CxHashKey*, elem, keyiter) {
-            keys.insert(std::string(reinterpret_cast<char const*>(elem->data), elem->len));
+            keys.insert(std::string(reinterpret_cast<char const *>(elem->data), elem->len));
         }
         EXPECT_EQ(keyiter.index, map->size);
         ASSERT_EQ(keys.size(), map->size);
@@ -103,7 +104,8 @@
         auto pairiter = cxMapIterator(map);
         std::unordered_map<std::string, std::string> pairs;
         cx_foreach(CxMapEntry*, entry, pairiter) {
-            pairs[std::string(reinterpret_cast<char const*>(entry->key->data), entry->key->len)] = std::string((char *) entry->value);
+            pairs[std::string(reinterpret_cast<char const *>(entry->key->data), entry->key->len)] = std::string(
+                    (char *) entry->value);
         }
         EXPECT_EQ(pairiter.index, map->size);
         ASSERT_EQ(pairs.size(), refmap.size());
@@ -205,26 +207,26 @@
     CxTestingAllocator allocator;
     auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 4);
 
-    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
-    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
-    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
-    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
-    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
-    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
+    cxMapPut(map, "key 1", (void *) "val 1");
+    cxMapPut(map, "key 2", (void *) "val 2");
+    cxMapPut(map, "key 3", (void *) "val 3");
+    cxMapPut(map, "key 4", (void *) "val 4");
+    cxMapPut(map, "key 5", (void *) "val 5");
+    cxMapPut(map, "key 6", (void *) "val 6");
 
     auto iter = cxMapMutIterator(map);
     cx_foreach(CxMapEntry*, entry, iter) {
-        if (reinterpret_cast<char const*>(entry->key->data)[4] % 2 == 1) cxIteratorFlagRemoval(iter);
+        if (reinterpret_cast<char const *>(entry->key->data)[4] % 2 == 1) cxIteratorFlagRemoval(iter);
     }
     EXPECT_EQ(map->size, 3);
     EXPECT_EQ(iter.index, map->size);
 
-    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
-    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
-    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
-    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 4")), nullptr);
-    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 5")), nullptr);
-    EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 6")), nullptr);
+    EXPECT_EQ(cxMapGet(map, "key 1"), nullptr);
+    EXPECT_NE(cxMapGet(map, "key 2"), nullptr);
+    EXPECT_EQ(cxMapGet(map, "key 3"), nullptr);
+    EXPECT_NE(cxMapGet(map, "key 4"), nullptr);
+    EXPECT_EQ(cxMapGet(map, "key 5"), nullptr);
+    EXPECT_NE(cxMapGet(map, "key 6"), nullptr);
 
     cxMapDestroy(map);
     EXPECT_TRUE(allocator.verify());
@@ -234,12 +236,12 @@
     CxTestingAllocator allocator;
     auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 8);
 
-    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
-    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
-    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
-    cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4");
-    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
-    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
+    cxMapPut(map, "key 1", (void *) "val 1");
+    cxMapPut(map, "key 2", (void *) "val 2");
+    cxMapPut(map, "key 3", (void *) "val 3");
+    cxMapPut(map, "key 4", (void *) "val 4");
+    cxMapPut(map, "key 5", (void *) "val 5");
+    cxMapPut(map, "key 6", (void *) "val 6");
 
     // 6/8 does not exceed 0.75, therefore the function should not rehash
     int result = cxMapRehash(map);
@@ -254,32 +256,32 @@
     CxTestingAllocator allocator;
     auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 7);
 
-    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
-    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
-    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
-    cxMapPut(map, cx_hash_key_str("foo 4"), (void *) "val 4");
-    cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5");
-    cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6");
-    cxMapPut(map, cx_hash_key_str("bar 7"), (void *) "val 7");
-    cxMapPut(map, cx_hash_key_str("key 8"), (void *) "val 8");
-    cxMapPut(map, cx_hash_key_str("key 9"), (void *) "val 9");
-    cxMapPut(map, cx_hash_key_str("key 10"), (void *) "val 10");
+    cxMapPut(map, "key 1", (void *) "val 1");
+    cxMapPut(map, "key 2", (void *) "val 2");
+    cxMapPut(map, "key 3", (void *) "val 3");
+    cxMapPut(map, "foo 4", (void *) "val 4");
+    cxMapPut(map, "key 5", (void *) "val 5");
+    cxMapPut(map, "key 6", (void *) "val 6");
+    cxMapPut(map, "bar 7", (void *) "val 7");
+    cxMapPut(map, "key 8", (void *) "val 8");
+    cxMapPut(map, "key 9", (void *) "val 9");
+    cxMapPut(map, "key 10", (void *) "val 10");
 
     int result = cxMapRehash(map);
     EXPECT_EQ(result, 0);
     EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 25);
     EXPECT_EQ(map->size, 10);
 
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 1")), "val 1"), 0);
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 2")), "val 2"), 0);
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 3")), "val 3"), 0);
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("foo 4")), "val 4"), 0);
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 5")), "val 5"), 0);
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 6")), "val 6"), 0);
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("bar 7")), "val 7"), 0);
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 8")), "val 8"), 0);
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 9")), "val 9"), 0);
-    EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 10")), "val 10"), 0);
+    EXPECT_STREQ((char *) cxMapGet(map, "key 1"), "val 1");
+    EXPECT_STREQ((char *) cxMapGet(map, "key 2"), "val 2");
+    EXPECT_STREQ((char *) cxMapGet(map, "key 3"), "val 3");
+    EXPECT_STREQ((char *) cxMapGet(map, "foo 4"), "val 4");
+    EXPECT_STREQ((char *) cxMapGet(map, "key 5"), "val 5");
+    EXPECT_STREQ((char *) cxMapGet(map, "key 6"), "val 6");
+    EXPECT_STREQ((char *) cxMapGet(map, "bar 7"), "val 7");
+    EXPECT_STREQ((char *) cxMapGet(map, "key 8"), "val 8");
+    EXPECT_STREQ((char *) cxMapGet(map, "key 9"), "val 9");
+    EXPECT_STREQ((char *) cxMapGet(map, "key 10"), "val 10");
 
     cxMapDestroy(map);
     EXPECT_TRUE(allocator.verify());
@@ -289,18 +291,18 @@
     CxTestingAllocator allocator;
     auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 0);
 
-    cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1");
-    cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2");
-    cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3");
+    cxMapPut(map, "key 1", (void *) "val 1");
+    cxMapPut(map, "key 2", (void *) "val 2");
+    cxMapPut(map, "key 3", (void *) "val 3");
 
     EXPECT_EQ(map->size, 3);
 
     cxMapClear(map);
 
     EXPECT_EQ(map->size, 0);
-    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr);
-    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 2")), nullptr);
-    EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr);
+    EXPECT_EQ(cxMapGet(map, "key 1"), nullptr);
+    EXPECT_EQ(cxMapGet(map, "key 2"), nullptr);
+    EXPECT_EQ(cxMapGet(map, "key 3"), nullptr);
 
     cxMapDestroy(map);
     EXPECT_TRUE(allocator.verify());
@@ -319,22 +321,22 @@
     auto s5 = CX_STR("setup");
 
     // put them into the map
-    cxMapPut(map, cx_hash_key_str("s1"), &s1);
-    cxMapPut(map, cx_hash_key_str("s2"), &s2);
-    cxMapPut(map, cx_hash_key_str("s3"), &s3);
-    cxMapPut(map, cx_hash_key_str("s4"), &s4);
+    cxMapPut(map, "s1", &s1);
+    cxMapPut(map, "s2", &s2);
+    cxMapPut(map, "s3", &s3);
+    cxMapPut(map, "s4", &s4);
 
     // overwrite a value
-    cxMapPut(map, cx_hash_key_str("s1"), &s5);
+    cxMapPut(map, "s1", &s5);
 
     // look up a string
-    auto s3p = reinterpret_cast<cxstring *>(cxMapGet(map, cx_hash_key_str("s3")));
+    auto s3p = reinterpret_cast<cxstring *>(cxMapGet(map, "s3"));
     EXPECT_EQ(s3p->length, s3.length);
     EXPECT_EQ(s3p->ptr, s3.ptr);
     EXPECT_NE(s3p, &s3);
 
     // remove a string
-    cxMapRemove(map, cx_hash_key_str("s2"));
+    cxMapRemove(map, "s2");
 
     // iterate
     auto ref = std::vector{s5.ptr, s3.ptr, s4.ptr};
@@ -405,7 +407,7 @@
     {
         auto iter = cxMapMutIteratorKeys(map);
         cx_foreach(CxHashKey*, key, iter) {
-            if (reinterpret_cast<char const*>(key->data)[4] == '1') cxIteratorFlagRemoval(iter);
+            if (reinterpret_cast<char const *>(key->data)[4] == '1') cxIteratorFlagRemoval(iter);
         }
     }
     {
@@ -447,3 +449,26 @@
     verify_any_destructor(map);
     EXPECT_TRUE(allocator.verify());
 }
+
+TEST(CxHashMap, Generics) {
+    CxTestingAllocator allocator;
+    auto map = test_map_generics_step_1(&allocator);
+
+    EXPECT_EQ(map->size, 3);
+    EXPECT_STREQ((char *) cxMapGet(map, "test"), "test");
+    EXPECT_STREQ((char *) cxMapGet(map, "foo"), "bar");
+    EXPECT_STREQ((char *) cxMapGet(map, "hallo"), "welt");
+
+    test_map_generics_step_2(map);
+
+    EXPECT_EQ(map->size, 2);
+    EXPECT_STREQ((char *) cxMapGet(map, "key"), "value");
+    EXPECT_STREQ((char *) cxMapGet(map, "foo"), "bar");
+
+    test_map_generics_step_3(map);
+
+    EXPECT_EQ(map->size, 0);
+
+    cxMapDestroy(map);
+    EXPECT_TRUE(allocator.verify());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_map_generics.c	Fri Apr 21 19:50:43 2023 +0200
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "test_map_generics.h"
+#include "cx/hash_map.h"
+
+CxMap *test_map_generics_step_1(CxAllocator const * allocator) {
+    CxMap *map = cxHashMapCreate(allocator, sizeof(cxstring), 0);
+
+    cxMapPut(map, "test", "test");
+    cxMapPut(map, CX_STR("foo"), "bar");
+    cxMapPut(map, cx_str("hallo"), "welt");
+
+    return map;
+}
+
+void test_map_generics_step_2(CxMap *map) {
+    // note: we don't have a destructor here, so remove and detach are the same
+    cxMapRemove(map, cx_str("test"));
+    cxMapDetach(map, "hallo");
+    cxMapPut(map, cx_hash_key_str("key"), "value");
+}
+
+void test_map_generics_step_3(CxMap *map) {
+    void *r;
+    r = cxMapRemoveAndGet(map, "key");
+    r = cxMapRemoveAndGet(map, cx_str("foo"));
+    if (r != NULL) map->size = 47;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_map_generics.h	Fri Apr 21 19:50:43 2023 +0200
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCX_TEST_MAP_GENERICS_H
+#define UCX_TEST_MAP_GENERICS_H
+
+#include "cx/map.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CxMap *test_map_generics_step_1(CxAllocator const *);
+
+void test_map_generics_step_2(CxMap *);
+
+void test_map_generics_step_3(CxMap *);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //UCX_TEST_MAP_GENERICS_H

mercurial