ucx/cx/map.h

changeset 101
7b3a3130be44
parent 77
5de33c2d94c6
--- a/ucx/cx/map.h	Thu Dec 12 20:01:43 2024 +0100
+++ b/ucx/cx/map.h	Mon Jan 06 22:22:55 2025 +0100
@@ -26,11 +26,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 /**
- * \file map.h
- * \brief Interface for map implementations.
- * \author Mike Becker
- * \author Olaf Wintermann
- * \copyright 2-Clause BSD License
+ * @file map.h
+ * @brief Interface for map implementations.
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ * @copyright 2-Clause BSD License
  */
 
 #ifndef UCX_MAP_H
@@ -89,19 +89,16 @@
     /**
      * Deallocates the entire memory.
      */
-    __attribute__((__nonnull__))
-    void (*destructor)(struct cx_map_s *map);
+    void (*deallocate)(struct cx_map_s *map);
 
     /**
      * Removes all elements.
      */
-    __attribute__((__nonnull__))
     void (*clear)(struct cx_map_s *map);
 
     /**
      * Add or overwrite an element.
      */
-    __attribute__((__nonnull__))
     int (*put)(
             CxMap *map,
             CxHashKey key,
@@ -111,7 +108,6 @@
     /**
      * Returns an element.
      */
-    __attribute__((__nonnull__, __warn_unused_result__))
     void *(*get)(
             const CxMap *map,
             CxHashKey key
@@ -119,18 +115,23 @@
 
     /**
      * Removes an element.
+     *
+     * Implementations SHALL check if @p targetbuf is set and copy the elements
+     * to the buffer without invoking any destructor.
+     * When @p targetbuf is not set, the destructors SHALL be invoked.
+     *
+     * The function SHALL return zero when the @p key was found and
+     * non-zero, otherwise. 
      */
-    __attribute__((__nonnull__))
-    void *(*remove)(
+    int (*remove)(
             CxMap *map,
             CxHashKey key,
-            bool destroy
+            void *targetbuf
     );
 
     /**
      * Creates an iterator for this map.
      */
-    __attribute__((__nonnull__, __warn_unused_result__))
     CxIterator (*iterator)(const CxMap *map, enum cx_map_iterator_type type);
 };
 
@@ -151,7 +152,10 @@
 /**
  * A shared instance of an empty map.
  *
- * Writing to that map is undefined.
+ * Writing to that map is not allowed.
+ *
+ * You can use this is a placeholder for initializing CxMap pointers
+ * for which you do not want to reserve memory right from the beginning.
  */
 extern CxMap *const cxEmptyMap;
 
@@ -164,7 +168,7 @@
  * @param map the map
  * @see cxMapStorePointers()
  */
-__attribute__((__nonnull__))
+cx_attr_nonnull
 static inline void cxMapStoreObjects(CxMap *map) {
     map->collection.store_pointer = false;
 }
@@ -181,7 +185,7 @@
  * @param map the map
  * @see cxMapStoreObjects()
  */
-__attribute__((__nonnull__))
+cx_attr_nonnull
 static inline void cxMapStorePointers(CxMap *map) {
     map->collection.store_pointer = true;
     map->collection.elem_size = sizeof(void *);
@@ -194,7 +198,7 @@
  * @return true, if this map is storing pointers
  * @see cxMapStorePointers()
  */
-__attribute__((__nonnull__))
+cx_attr_nonnull
 static inline bool cxMapIsStoringPointers(const CxMap *map) {
     return map->collection.store_pointer;
 }
@@ -202,20 +206,21 @@
 /**
  * Deallocates the memory of the specified map.
  *
- * @param map the map to be destroyed
+ * Also calls the content destructor functions for each element, if specified.
+ *
+ * @param map the map to be freed
  */
-__attribute__((__nonnull__))
-static inline void cxMapDestroy(CxMap *map) {
-    map->cl->destructor(map);
-}
+void cxMapFree(CxMap *map);
 
 
 /**
  * Clears a map by removing all elements.
  *
+ * Also calls the content destructor functions for each element, if specified.
+ *
  * @param map the map to be cleared
  */
-__attribute__((__nonnull__))
+cx_attr_nonnull
 static inline void cxMapClear(CxMap *map) {
     map->cl->clear(map);
 }
@@ -226,24 +231,22 @@
  * @param map the map
  * @return the number of stored elements
  */
-__attribute__((__nonnull__))
+cx_attr_nonnull
 static inline size_t cxMapSize(const CxMap *map) {
     return map->collection.size;
 }
 
-
-// TODO: set-like map operations (union, intersect, difference)
-
 /**
  * Creates a value iterator for a map.
  *
- * \note An iterator iterates over all elements successively. Therefore the order
+ * @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
  * @return an iterator for the currently stored values
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline CxIterator cxMapIteratorValues(const CxMap *map) {
     return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES);
 }
@@ -253,13 +256,14 @@
  *
  * The elements of the iterator are keys of type CxHashKey.
  *
- * \note An iterator iterates over all elements successively. Therefore the order
+ * @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
  * @return an iterator for the currently stored keys
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline CxIterator cxMapIteratorKeys(const CxMap *map) {
     return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS);
 }
@@ -269,7 +273,7 @@
  *
  * The elements of the iterator are key/value pairs of type CxMapEntry.
  *
- * \note An iterator iterates over all elements successively. Therefore the order
+ * @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
@@ -277,7 +281,8 @@
  * @see cxMapIteratorKeys()
  * @see cxMapIteratorValues()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline CxIterator cxMapIterator(const CxMap *map) {
     return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);
 }
@@ -286,13 +291,14 @@
 /**
  * Creates a mutating iterator over the values of a map.
  *
- * \note An iterator iterates over all elements successively. Therefore the order
+ * @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
  * @return an iterator for the currently stored values
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 CxIterator cxMapMutIteratorValues(CxMap *map);
 
 /**
@@ -300,13 +306,14 @@
  *
  * The elements of the iterator are keys of type CxHashKey.
  *
- * \note An iterator iterates over all elements successively. Therefore the order
+ * @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
  * @return an iterator for the currently stored keys
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 CxIterator cxMapMutIteratorKeys(CxMap *map);
 
 /**
@@ -314,7 +321,7 @@
  *
  * The elements of the iterator are key/value pairs of type CxMapEntry.
  *
- * \note An iterator iterates over all elements successively. Therefore the order
+ * @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
@@ -322,21 +329,13 @@
  * @see cxMapMutIteratorKeys()
  * @see cxMapMutIteratorValues()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 CxIterator cxMapMutIterator(CxMap *map);
 
 #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__))
+cx_attr_nonnull
 static inline int cxMapPut(
         CxMap *map,
         CxHashKey const &key,
@@ -345,16 +344,7 @@
     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__))
+cx_attr_nonnull
 static inline int cxMapPut(
         CxMap *map,
         cxstring const &key,
@@ -363,15 +353,7 @@
     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__))
+cx_attr_nonnull
 static inline int cxMapPut(
         CxMap *map,
         cxmutstr const &key,
@@ -380,15 +362,8 @@
     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__))
+cx_attr_nonnull
+cx_attr_cstr_arg(2)
 static inline int cxMapPut(
         CxMap *map,
         const char *key,
@@ -397,14 +372,8 @@
     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__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cxMapGet(
         const CxMap *map,
         CxHashKey const &key
@@ -412,14 +381,8 @@
     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__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cxMapGet(
         const CxMap *map,
         cxstring const &key
@@ -427,14 +390,8 @@
     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__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cxMapGet(
         const CxMap *map,
         cxmutstr const &key
@@ -442,14 +399,9 @@
     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__))
+cx_attr_nonnull
+cx_attr_nodiscard
+cx_attr_cstr_arg(2)
 static inline void *cxMapGet(
         const CxMap *map,
         const char *key
@@ -457,195 +409,86 @@
     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(
+cx_attr_nonnull
+static inline int cxMapRemove(
         CxMap *map,
         CxHashKey const &key
 ) {
-    (void) map->cl->remove(map, key, true);
+    return map->cl->remove(map, key, nullptr);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+static inline int cxMapRemove(
         CxMap *map,
         cxstring const &key
 ) {
-    (void) map->cl->remove(map, cx_hash_key_cxstr(key), true);
+    return map->cl->remove(map, cx_hash_key_cxstr(key), nullptr);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+static inline int cxMapRemove(
         CxMap *map,
         cxmutstr const &key
 ) {
-    (void) map->cl->remove(map, cx_hash_key_cxstr(key), true);
+    return map->cl->remove(map, cx_hash_key_cxstr(key), nullptr);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+cx_attr_cstr_arg(2)
+static inline int cxMapRemove(
         CxMap *map,
         const char *key
 ) {
-    (void) map->cl->remove(map, cx_hash_key_str(key), true);
+    return map->cl->remove(map, cx_hash_key_str(key), nullptr);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+cx_attr_access_w(3)
+static inline int cxMapRemoveAndGet(
         CxMap *map,
-        CxHashKey const &key
+        CxHashKey key,
+        void *targetbuf
 ) {
-    (void) map->cl->remove(map, key, false);
+    return map->cl->remove(map, key, targetbuf);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+cx_attr_access_w(3)
+static inline int cxMapRemoveAndGet(
         CxMap *map,
-        cxstring const &key
+        cxstring key,
+        void *targetbuf
 ) {
-    (void) map->cl->remove(map, cx_hash_key_cxstr(key), false);
+    return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+cx_attr_access_w(3)
+static inline int cxMapRemoveAndGet(
         CxMap *map,
-        cxmutstr const &key
+        cxmutstr key,
+        void *targetbuf
 ) {
-    (void) map->cl->remove(map, cx_hash_key_cxstr(key), false);
+    return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+cx_attr_access_w(3)
+cx_attr_cstr_arg(2)
+static inline int cxMapRemoveAndGet(
         CxMap *map,
-        const char *key
+        const char *key,
+        void *targetbuf
 ) {
-    (void) map->cl->remove(map, cx_hash_key_str(key), false);
+    return map->cl->remove(map, cx_hash_key_str(key), targetbuf);
 }
 
-
-
 #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
+ * @copydoc cxMapPut()
  */
-__attribute__((__nonnull__))
+cx_attr_nonnull
 static inline int cx_map_put(
         CxMap *map,
         CxHashKey key,
@@ -655,14 +498,9 @@
 }
 
 /**
- * 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
+ * @copydoc cxMapPut()
  */
-__attribute__((__nonnull__))
+cx_attr_nonnull
 static inline int cx_map_put_cxstr(
         CxMap *map,
         cxstring key,
@@ -672,14 +510,9 @@
 }
 
 /**
- * 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
+ * @copydoc cxMapPut()
  */
-__attribute__((__nonnull__))
+cx_attr_nonnull
 static inline int cx_map_put_mustr(
         CxMap *map,
         cxmutstr key,
@@ -689,14 +522,10 @@
 }
 
 /**
- * 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
+ * @copydoc cxMapPut()
  */
-__attribute__((__nonnull__))
+cx_attr_nonnull
+cx_attr_cstr_arg(2)
 static inline int cx_map_put_str(
         CxMap *map,
         const char *key,
@@ -708,10 +537,19 @@
 /**
  * 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
+ * A possible existing value will be overwritten.
+ *
+ * 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 (@c CxMap*) the map
+ * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key
+ * @param value (@c void*) the value
+ * @retval zero success
+ * @retval non-zero value on memory allocation failure
  */
 #define cxMapPut(map, key, value) _Generic((key), \
     CxHashKey: cx_map_put,                        \
@@ -722,13 +560,10 @@
     (map, key, value)
 
 /**
- * Retrieves a value by using a key.
- *
- * @param map the map
- * @param key the key
- * @return the value
+ * @copydoc cxMapGet()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cx_map_get(
         const CxMap *map,
         CxHashKey key
@@ -737,13 +572,10 @@
 }
 
 /**
- * Retrieves a value by using a key.
- *
- * @param map the map
- * @param key the key
- * @return the value
+ * @copydoc cxMapGet()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cx_map_get_cxstr(
         const CxMap *map,
         cxstring key
@@ -752,13 +584,10 @@
 }
 
 /**
- * Retrieves a value by using a key.
- *
- * @param map the map
- * @param key the key
- * @return the value
+ * @copydoc cxMapGet()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cx_map_get_mustr(
         const CxMap *map,
         cxmutstr key
@@ -767,13 +596,11 @@
 }
 
 /**
- * Retrieves a value by using a key.
- *
- * @param map the map
- * @param key the key
- * @return the value
+ * @copydoc cxMapGet()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
+cx_attr_cstr_arg(2)
 static inline void *cx_map_get_str(
         const CxMap *map,
         const char *key
@@ -784,9 +611,13 @@
 /**
  * Retrieves a value by using a key.
  *
- * @param map the map
- * @param key the key
- * @return the value
+ * 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 (@c CxMap*) the map
+ * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key
+ * @return (@c void*) the value
  */
 #define cxMapGet(map, key) _Generic((key), \
     CxHashKey: cx_map_get,                 \
@@ -797,74 +628,61 @@
     (map, key)
 
 /**
- * Removes a key/value-pair from the map by using the key.
- *
- * @param map the map
- * @param key the key
+ * @copydoc cxMapRemove()
  */
-__attribute__((__nonnull__))
-static inline void cx_map_remove(
+cx_attr_nonnull
+static inline int cx_map_remove(
         CxMap *map,
         CxHashKey key
 ) {
-    (void) map->cl->remove(map, key, true);
+    return map->cl->remove(map, key, NULL);
+}
+
+/**
+ * @copydoc cxMapRemove()
+ */
+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);
 }
 
 /**
- * Removes a key/value-pair from the map by using the key.
- *
- * @param map the map
- * @param key the key
+ * @copydoc cxMapRemove()
  */
-__attribute__((__nonnull__))
-static inline void cx_map_remove_cxstr(
+cx_attr_nonnull
+static inline int cx_map_remove_mustr(
         CxMap *map,
-        cxstring key
+        cxmutstr key
 ) {
-    (void) map->cl->remove(map, cx_hash_key_cxstr(key), true);
+    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);
 }
 
 /**
  * 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_mustr(
-        CxMap *map,
-        cxmutstr 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 destructors functions, if any, on the removed element.
  *
- * @param map the map
- * @param key the key
- */
-__attribute__((__nonnull__))
-static inline void cx_map_remove_str(
-        CxMap *map,
-        const char *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
+ * @param map (@c CxMap*) the map
+ * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key
+ * @retval zero success
+ * @retval non-zero the key was not found
+ * 
  * @see cxMapRemoveAndGet()
- * @see cxMapDetach()
  */
 #define cxMapRemove(map, key) _Generic((key), \
     CxHashKey: cx_map_remove,                 \
@@ -875,177 +693,85 @@
     (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
+ * @copydoc cxMapRemoveAndGet()
  */
-__attribute__((__nonnull__))
-static inline void cx_map_detach_cxstr(
+cx_attr_nonnull
+cx_attr_access_w(3)
+static inline int cx_map_remove_and_get(
         CxMap *map,
-        cxstring key
+        CxHashKey key,
+        void *targetbuf
 ) {
-    (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_mustr(
-        CxMap *map,
-        cxmutstr key
-) {
-    (void) map->cl->remove(map, cx_hash_key_cxstr(key), false);
+    return map->cl->remove(map, key, targetbuf);
 }
 
 /**
- * Detaches a key/value-pair from the map by using the key
- * without invoking the destructor.
- *
- * @param map the map
- * @param key the key
+ * @copydoc cxMapRemoveAndGet()
  */
-__attribute__((__nonnull__))
-static inline void cx_map_detach_str(
+cx_attr_nonnull
+cx_attr_access_w(3)
+static inline int cx_map_remove_and_get_cxstr(
         CxMap *map,
-        const char *key
+        cxstring key,
+        void *targetbuf
 ) {
-    (void) map->cl->remove(map, cx_hash_key_str(key), false);
+    return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf);
 }
 
 /**
- * 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()
+ * @copydoc cxMapRemoveAndGet()
  */
-#define cxMapDetach(map, key) _Generic((key), \
-    CxHashKey: cx_map_detach,                 \
-    cxstring: cx_map_detach_cxstr,            \
-    cxmutstr: cx_map_detach_mustr,            \
-    char*: cx_map_detach_str,                 \
-    const char*: cx_map_detach_str)           \
-    (map, 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);
+}
 
 /**
- * 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
+ * @copydoc cxMapRemoveAndGet()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
-static inline void *cx_map_remove_and_get(
+cx_attr_nonnull
+cx_attr_access_w(3)
+cx_attr_cstr_arg(2)
+static inline int cx_map_remove_and_get_str(
         CxMap *map,
-        CxHashKey key
+        const char *key,
+        void *targetbuf
 ) {
-    return map->cl->remove(map, key, !map->collection.store_pointer);
+    return map->cl->remove(map, cx_hash_key_str(key), targetbuf);
 }
 
 /**
  * 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->collection.store_pointer);
-}
-
-/**
- * Removes a key/value-pair from the map by using the key.
+ * This function will copy the contents of the removed element
+ * to the target buffer must be guaranteed to be large enough
+ * to hold the element (the map's element size).
+ * The destructor functions, if any, will @em not be called.
  *
- * @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_mustr(
-        CxMap *map,
-        cxmutstr key
-) {
-    return map->cl->remove(map, cx_hash_key_cxstr(key), !map->collection.store_pointer);
-}
-
-/**
- * Removes a key/value-pair from the map by using the key.
+ * If this map is storing pointers, the element is the pointer itself
+ * and not the object it points to.
  *
- * @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
+ * @param map (@c CxMap*) the map
+ * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) 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 cxMapStorePointers()
+ * @see cxMapRemove()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
-static inline void *cx_map_remove_and_get_str(
-        CxMap *map,
-        const char *key
-) {
-    return map->cl->remove(map, cx_hash_key_str(key), !map->collection.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), \
+#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)
+    (map, key, targetbuf)
 
 #endif // __cplusplus
 

mercurial