--- a/ucx/cx/map.h Sat Oct 04 14:54:25 2025 +0200 +++ b/ucx/cx/map.h Sun Oct 19 21:20:08 2025 +0200 @@ -185,8 +185,11 @@ /** * Add or overwrite an element. + * If the @p value is @c NULL, the implementation + * shall only allocate memory instead of adding an existing value to the map. + * Returns a pointer to the allocated memory or @c NULL if allocation fails. */ - int (*put)( + void *(*put)( CxMap *map, CxHashKey key, void *value @@ -227,7 +230,7 @@ * * Writing to that map is not allowed. * - * You can use this is a placeholder for initializing CxMap pointers + * You can use this as a placeholder for initializing CxMap pointers * for which you do not want to reserve memory right from the beginning. */ cx_attr_export @@ -277,50 +280,50 @@ * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored values */ -cx_attr_nonnull cx_attr_nodiscard static inline CxMapIterator cxMapIteratorValues(const CxMap *map) { + if (map == NULL) map = cxEmptyMap; return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES); } /** * Creates a key iterator for a map. * - * The elements of the iterator are keys of type CxHashKey and the pointer returned + * The elements of the iterator are keys of type CxHashKey, and the pointer returned * during iterator shall be treated as @c const @c CxHashKey* . * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored keys */ -cx_attr_nonnull cx_attr_nodiscard static inline CxMapIterator cxMapIteratorKeys(const CxMap *map) { + if (map == NULL) map = cxEmptyMap; return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS); } /** * Creates an iterator for a map. * - * The elements of the iterator are key/value pairs of type CxMapEntry and the pointer returned + * The elements of the iterator are key/value pairs of type CxMapEntry, and the pointer returned * during iterator shall be treated as @c const @c CxMapEntry* . * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored entries * @see cxMapIteratorKeys() * @see cxMapIteratorValues() */ -cx_attr_nonnull cx_attr_nodiscard static inline CxMapIterator cxMapIterator(const CxMap *map) { + if (map == NULL) map = cxEmptyMap; return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS); } @@ -335,10 +338,9 @@ * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored values */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_export CxMapIterator cxMapMutIteratorValues(CxMap *map); @@ -346,16 +348,15 @@ /** * Creates a mutating iterator over the keys of a map. * - * The elements of the iterator are keys of type CxHashKey and the pointer returned + * The elements of the iterator are keys of type CxHashKey, and the pointer returned * during iterator shall be treated as @c const @c CxHashKey* . * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored keys */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_export CxMapIterator cxMapMutIteratorKeys(CxMap *map); @@ -363,176 +364,40 @@ /** * Creates a mutating iterator for a map. * - * The elements of the iterator are key/value pairs of type CxMapEntry and the pointer returned + * The elements of the iterator are key/value pairs of type CxMapEntry, and the pointer returned * during iterator shall be treated as @c const @c CxMapEntry* . * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * - * @param map the map to create the iterator for + * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored entries * @see cxMapMutIteratorKeys() * @see cxMapMutIteratorValues() */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_export CxMapIterator cxMapMutIterator(CxMap *map); -#ifdef __cplusplus -} // end the extern "C" block here, because we want to start overloading -cx_attr_nonnull -static inline int cxMapPut( - CxMap *map, - CxHashKey const &key, - void *value -) { - return map->cl->put(map, key, value); -} - -cx_attr_nonnull -static inline int cxMapPut( - CxMap *map, - cxstring const &key, - void *value -) { - return map->cl->put(map, cx_hash_key_cxstr(key), value); -} - -cx_attr_nonnull -static inline int cxMapPut( - CxMap *map, - cxmutstr const &key, - void *value -) { - return map->cl->put(map, cx_hash_key_cxstr(key), value); -} - -cx_attr_nonnull -cx_attr_cstr_arg(2) -static inline int cxMapPut( - CxMap *map, - const char *key, - void *value -) { - return map->cl->put(map, cx_hash_key_str(key), value); -} - -cx_attr_nonnull -cx_attr_nodiscard -static inline void *cxMapGet( - const CxMap *map, - CxHashKey const &key -) { - return map->cl->get(map, key); -} - -cx_attr_nonnull -cx_attr_nodiscard -static inline void *cxMapGet( - const CxMap *map, - cxstring const &key -) { - return map->cl->get(map, cx_hash_key_cxstr(key)); -} - -cx_attr_nonnull -cx_attr_nodiscard -static inline void *cxMapGet( - const CxMap *map, - cxmutstr const &key -) { - return map->cl->get(map, cx_hash_key_cxstr(key)); -} - -cx_attr_nonnull -cx_attr_nodiscard -cx_attr_cstr_arg(2) -static inline void *cxMapGet( - const CxMap *map, - const char *key -) { - return map->cl->get(map, cx_hash_key_str(key)); -} - -cx_attr_nonnull -static inline int cxMapRemove( - CxMap *map, - CxHashKey const &key -) { - return map->cl->remove(map, key, nullptr); -} - -cx_attr_nonnull -static inline int cxMapRemove( - CxMap *map, - cxstring const &key -) { - return map->cl->remove(map, cx_hash_key_cxstr(key), nullptr); -} - -cx_attr_nonnull -static inline int cxMapRemove( - CxMap *map, - cxmutstr const &key -) { - return map->cl->remove(map, cx_hash_key_cxstr(key), nullptr); -} - -cx_attr_nonnull -cx_attr_cstr_arg(2) -static inline int cxMapRemove( - CxMap *map, - const char *key -) { - return map->cl->remove(map, cx_hash_key_str(key), nullptr); -} - -cx_attr_nonnull -cx_attr_access_w(3) -static inline int cxMapRemoveAndGet( - CxMap *map, - CxHashKey key, - void *targetbuf -) { - return map->cl->remove(map, key, targetbuf); -} - -cx_attr_nonnull -cx_attr_access_w(3) -static inline int cxMapRemoveAndGet( - CxMap *map, - cxstring key, - void *targetbuf -) { - return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf); -} - -cx_attr_nonnull -cx_attr_access_w(3) -static inline int cxMapRemoveAndGet( - CxMap *map, - cxmutstr key, - void *targetbuf -) { - return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf); -} - -cx_attr_nonnull -cx_attr_access_w(3) -cx_attr_cstr_arg(2) -static inline int cxMapRemoveAndGet( - CxMap *map, - const char *key, - void *targetbuf -) { - return map->cl->remove(map, cx_hash_key_str(key), targetbuf); -} - -#else // __cplusplus - /** - * @copydoc cxMapPut() + * Puts a key/value-pair into the map. + * + * A possible existing value will be overwritten. + * If destructor functions are specified, they are called for + * the overwritten element. + * + * If this map is storing pointers, the @p value pointer is written + * to the map. Otherwise, the memory is copied from @p value with + * memcpy(). + * + * The @p key is always copied. + * + * @param map the map + * @param key the key + * @param value the value + * @retval zero success + * @retval non-zero value on memory allocation failure + * @see cxMapPut() */ cx_attr_nonnull static inline int cx_map_put( @@ -540,44 +405,7 @@ CxHashKey key, void *value ) { - return map->cl->put(map, key, value); -} - -/** - * @copydoc cxMapPut() - */ -cx_attr_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); -} - -/** - * @copydoc cxMapPut() - */ -cx_attr_nonnull -static inline int cx_map_put_mustr( - CxMap *map, - cxmutstr key, - void *value -) { - return map->cl->put(map, cx_hash_key_cxstr(key), value); -} - -/** - * @copydoc cxMapPut() - */ -cx_attr_nonnull -cx_attr_cstr_arg(2) -static inline int cx_map_put_str( - CxMap *map, - const char *key, - void *value -) { - return map->cl->put(map, cx_hash_key_str(key), value); + return map->cl->put(map, key, value) == NULL; } /** @@ -594,21 +422,73 @@ * The @p key is always copied. * * @param map (@c CxMap*) the map - * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key + * @param key (any supported key type) the key * @param value (@c void*) the value * @retval zero success * @retval non-zero value on memory allocation failure + * @see CX_HASH_KEY() */ -#define cxMapPut(map, key, value) _Generic((key), \ - CxHashKey: cx_map_put, \ - cxstring: cx_map_put_cxstr, \ - cxmutstr: cx_map_put_mustr, \ - char*: cx_map_put_str, \ - const char*: cx_map_put_str) \ - (map, key, value) +#define cxMapPut(map, key, value) cx_map_put(map, CX_HASH_KEY(key), value) + +/** + * Allocates memory for a value in the map associated with the specified key. + * + * A possible existing value will be overwritten. + * If destructor functions are specified, they are called for + * the overwritten element. + * + * If the map is storing pointers, this function returns a @c void** pointer, + * meaning a pointer to that pointer. + * + * The @p key is always copied. + * + * @param map the map + * @param key the key + * @return the pointer to the allocated memory or @c NULL if allocation fails + * @retval zero success + * @retval non-zero value on memory allocation failure + * @see cxMapEmplace() + */ +cx_attr_nonnull +static inline void *cx_map_emplace( + CxMap *map, + CxHashKey key +) { + return map->cl->put(map, key, NULL); +} /** - * @copydoc cxMapGet() + * Allocates memory for a value in the map associated with the specified key. + * + * A possible existing value will be overwritten. + * If destructor functions are specified, they are called for + * the overwritten element. + * + * If the map is storing pointers, this function returns a @c void** pointer, + * meaning a pointer to that pointer. + * + * The @p key is always copied. + * + * @param map (@c CxMap*) the map + * @param key (any supported key type) the key + * @return the pointer to the allocated memory or @c NULL if allocation fails + * @retval zero success + * @retval non-zero value on memory allocation failure + * @see CX_HASH_KEY() + */ +#define cxMapEmplace(map, key) cx_map_emplace(map, CX_HASH_KEY(key)) + +/** + * Retrieves a value by using a key. + * + * If this map is storing pointers, the stored pointer is returned. + * Otherwise, a pointer to the element within the map's memory + * is returned (which is valid as long as the element stays in the map). + * + * @param map the map + * @param key the key + * @return the value + * @see cxMapGet() */ cx_attr_nonnull cx_attr_nodiscard @@ -620,43 +500,6 @@ } /** - * @copydoc cxMapGet() - */ -cx_attr_nonnull -cx_attr_nodiscard -static inline void *cx_map_get_cxstr( - const CxMap *map, - cxstring key -) { - return map->cl->get(map, cx_hash_key_cxstr(key)); -} - -/** - * @copydoc cxMapGet() - */ -cx_attr_nonnull -cx_attr_nodiscard -static inline void *cx_map_get_mustr( - const CxMap *map, - cxmutstr key -) { - return map->cl->get(map, cx_hash_key_cxstr(key)); -} - -/** - * @copydoc cxMapGet() - */ -cx_attr_nonnull -cx_attr_nodiscard -cx_attr_cstr_arg(2) -static inline void *cx_map_get_str( - const CxMap *map, - const char *key -) { - return map->cl->get(map, cx_hash_key_str(key)); -} - -/** * Retrieves a value by using a key. * * If this map is storing pointers, the stored pointer is returned. @@ -664,88 +507,29 @@ * is returned (which is valid as long as the element stays in the map). * * @param map (@c CxMap*) the map - * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key + * @param key (any supported key type) the key * @return (@c void*) the value - */ -#define cxMapGet(map, key) _Generic((key), \ - CxHashKey: cx_map_get, \ - cxstring: cx_map_get_cxstr, \ - cxmutstr: cx_map_get_mustr, \ - char*: cx_map_get_str, \ - const char*: cx_map_get_str) \ - (map, key) - -/** - * @copydoc cxMapRemove() - */ -cx_attr_nonnull -static inline int cx_map_remove( - CxMap *map, - CxHashKey key -) { - return map->cl->remove(map, key, NULL); -} - -/** - * @copydoc cxMapRemove() + * @see CX_HASH_KEY() */ -cx_attr_nonnull -static inline int cx_map_remove_cxstr( - CxMap *map, - cxstring key -) { - return map->cl->remove(map, cx_hash_key_cxstr(key), NULL); -} - -/** - * @copydoc cxMapRemove() - */ -cx_attr_nonnull -static inline int cx_map_remove_mustr( - CxMap *map, - cxmutstr key -) { - return map->cl->remove(map, cx_hash_key_cxstr(key), NULL); -} - -/** - * @copydoc cxMapRemove() - */ -cx_attr_nonnull -cx_attr_cstr_arg(2) -static inline int cx_map_remove_str( - CxMap *map, - const char *key -) { - return map->cl->remove(map, cx_hash_key_str(key), NULL); -} +#define cxMapGet(map, key) cx_map_get(map, CX_HASH_KEY(key)) /** * Removes a key/value-pair from the map by using the key. * - * Always invokes the destructors functions, if any, on the removed element. + * Invokes the destructor functions, if any, on the removed element if and only if the + * @p targetbuf is @c NULL. * - * @param map (@c CxMap*) the map - * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key + * @param map the map + * @param key the key + * @param targetbuf the optional buffer where the removed element shall be copied to * @retval zero success * @retval non-zero the key was not found - * + * + * @see cxMapRemove() * @see cxMapRemoveAndGet() */ -#define cxMapRemove(map, key) _Generic((key), \ - CxHashKey: cx_map_remove, \ - cxstring: cx_map_remove_cxstr, \ - cxmutstr: cx_map_remove_mustr, \ - char*: cx_map_remove_str, \ - const char*: cx_map_remove_str) \ - (map, key) - -/** - * @copydoc cxMapRemoveAndGet() - */ -cx_attr_nonnull -cx_attr_access_w(3) -static inline int cx_map_remove_and_get( +cx_attr_nonnull_arg(1) +static inline int cx_map_remove( CxMap *map, CxHashKey key, void *targetbuf @@ -754,44 +538,19 @@ } /** - * @copydoc cxMapRemoveAndGet() - */ -cx_attr_nonnull -cx_attr_access_w(3) -static inline int cx_map_remove_and_get_cxstr( - CxMap *map, - cxstring key, - void *targetbuf -) { - return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf); -} - -/** - * @copydoc cxMapRemoveAndGet() + * Removes a key/value-pair from the map by using the key. + * + * Always invokes the destructor functions, if any, on the removed element. + * + * @param map (@c CxMap*) the map + * @param key (any supported key type) the key + * @retval zero success + * @retval non-zero the key was not found + * + * @see cxMapRemoveAndGet() + * @see CX_HASH_KEY() */ -cx_attr_nonnull -cx_attr_access_w(3) -static inline int cx_map_remove_and_get_mustr( - CxMap *map, - cxmutstr key, - void *targetbuf -) { - return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf); -} - -/** - * @copydoc cxMapRemoveAndGet() - */ -cx_attr_nonnull -cx_attr_access_w(3) -cx_attr_cstr_arg(2) -static inline int cx_map_remove_and_get_str( - CxMap *map, - const char *key, - void *targetbuf -) { - return map->cl->remove(map, cx_hash_key_str(key), targetbuf); -} +#define cxMapRemove(map, key) cx_map_remove(map, CX_HASH_KEY(key), NULL) /** * Removes a key/value-pair from the map by using the key. @@ -805,21 +564,18 @@ * and not the object it points to. * * @param map (@c CxMap*) the map - * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key + * @param key (any supported key type) the key * @param targetbuf (@c void*) the buffer where the element shall be copied to * @retval zero success * @retval non-zero the key was not found * * @see cxMapRemove() + * @see CX_HASH_KEY() */ -#define cxMapRemoveAndGet(map, key, targetbuf) _Generic((key), \ - CxHashKey: cx_map_remove_and_get, \ - cxstring: cx_map_remove_and_get_cxstr, \ - cxmutstr: cx_map_remove_and_get_mustr, \ - char*: cx_map_remove_and_get_str, \ - const char*: cx_map_remove_and_get_str) \ - (map, key, targetbuf) +#define cxMapRemoveAndGet(map, key, targetbuf) cx_map_remove(map, CX_HASH_KEY(key), targetbuf) -#endif // __cplusplus +#ifdef __cplusplus +} // extern "C" +#endif #endif // UCX_MAP_H