src/ucx/cx/map.h

changeset 579
e10457d74fe1
parent 504
c094afcdfb27
--- a/src/ucx/cx/map.h	Mon Feb 10 17:44:51 2025 +0100
+++ b/src/ucx/cx/map.h	Sun Mar 02 18:10:52 2025 +0100
@@ -26,12 +26,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 /**
- * \file map.h
- * \brief Interface for map implementations.
- * \author Mike Becker
- * \author Olaf Wintermann
- * \version 3.0
- * \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
@@ -52,17 +51,37 @@
 /** Type for a map entry. */
 typedef struct cx_map_entry_s CxMapEntry;
 
+/** Type for a map iterator. */
+typedef struct cx_map_iterator_s CxMapIterator;
+
 /** Type for map class definitions. */
 typedef struct cx_map_class_s cx_map_class;
 
 /** Structure for the UCX map. */
 struct cx_map_s {
-    CX_COLLECTION_MEMBERS
+    /**
+     * Base attributes.
+     */
+    CX_COLLECTION_BASE;
     /** The map class definition. */
     cx_map_class *cl;
 };
 
 /**
+ * A map entry.
+ */
+struct cx_map_entry_s {
+    /**
+     * A pointer to the key.
+     */
+    const CxHashKey *key;
+    /**
+     * A pointer to the value.
+     */
+    void *value;
+};
+
+/**
  * The type of iterator for a map.
  */
 enum cx_map_iterator_type {
@@ -81,25 +100,92 @@
 };
 
 /**
+ * Internal iterator struct - use CxMapIterator.
+ */
+struct cx_map_iterator_s {
+    /**
+     * Inherited common data for all iterators.
+     */
+    CX_ITERATOR_BASE;
+
+    /**
+     * Handle for the source map.
+     */
+    union {
+        /**
+         * Access for mutating iterators.
+         */
+        CxMap *m;
+        /**
+         * Access for normal iterators.
+         */
+        const CxMap *c;
+    } map;
+
+    /**
+     * Handle for the current element.
+     *
+     * @attention Depends on the map implementation, do not assume a type (better: do not use!).
+     */
+    void *elem;
+
+    /**
+     * Reserved memory for a map entry.
+     *
+     * If a map implementation uses an incompatible layout, the iterator needs something
+     * to point to during iteration which @em is compatible.
+     */
+    CxMapEntry entry;
+
+    /**
+     * Field for storing the current slot number.
+     *
+     * (Used internally)
+     */
+    size_t slot;
+
+    /**
+     * Counts the elements successfully.
+     * It usually does not denote a stable index within the map as it would be for arrays.
+     */
+    size_t index;
+
+    /**
+     * The size of a value stored in this map.
+     */
+    size_t elem_size;
+
+    /**
+     * May contain the total number of elements, if known.
+     * Set to @c SIZE_MAX when the total number is unknown during iteration.
+     *
+     * @remark The UCX implementations of #CxMap always know the number of elements they store.
+     */
+    size_t elem_count;
+
+    /**
+     * The type of this iterator.
+     */
+    enum cx_map_iterator_type type;
+};
+
+/**
  * The class definition for arbitrary maps.
  */
 struct cx_map_class_s {
     /**
      * 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,
@@ -109,143 +195,122 @@
     /**
      * Returns an element.
      */
-    __attribute__((__nonnull__, __warn_unused_result__))
     void *(*get)(
-            CxMap const *map,
+            const CxMap *map,
             CxHashKey key
     );
 
     /**
      * 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)(CxMap const *map, enum cx_map_iterator_type type);
-};
-
-/**
- * A map entry.
- */
-struct cx_map_entry_s {
-    /**
-     * A pointer to the key.
-     */
-    CxHashKey const *key;
-    /**
-     * A pointer to the value.
-     */
-    void *value;
+    CxMapIterator (*iterator)(const CxMap *map, enum cx_map_iterator_type type);
 };
 
 /**
  * A shared instance of an empty map.
  *
- * Writing to that map is undefined.
- */
-extern CxMap *const cxEmptyMap;
-
-/**
- * Advises the map to store copies of the objects (default mode of operation).
+ * Writing to that map is not allowed.
  *
- * Retrieving objects from this map will yield pointers to the copies stored
- * within this list.
- *
- * @param map the map
- * @see cxMapStorePointers()
+ * You can use this is a placeholder for initializing CxMap pointers
+ * for which you do not want to reserve memory right from the beginning.
  */
-__attribute__((__nonnull__))
-static inline void cxMapStoreObjects(CxMap *map) {
-    map->store_pointer = false;
-}
-
-/**
- * Advises the map to only store pointers to the objects.
- *
- * Retrieving objects from this list will yield the original pointers stored.
- *
- * @note This function forcibly sets the element size to the size of a pointer.
- * Invoking this function on a non-empty map that already stores copies of
- * objects is undefined.
- *
- * @param map the map
- * @see cxMapStoreObjects()
- */
-__attribute__((__nonnull__))
-static inline void cxMapStorePointers(CxMap *map) {
-    map->store_pointer = true;
-    map->item_size = sizeof(void *);
-}
-
+cx_attr_export
+extern CxMap *const cxEmptyMap;
 
 /**
  * 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);
-}
+cx_attr_export
+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);
 }
 
-
-// TODO: set-like map operations (union, intersect, difference)
+/**
+ * Returns the number of elements in this map.
+ *
+ * @param map the map
+ * @return the number of stored elements
+ */
+cx_attr_nonnull
+static inline size_t cxMapSize(const CxMap *map) {
+    return map->collection.size;
+}
 
 /**
  * Creates a value iterator for a map.
  *
- * \note An iterator iterates over all elements successively. Therefore the order
+ * When the map is storing pointers, those pointers are returned.
+ * Otherwise, the iterator iterates over pointers to the memory within the map where the
+ * respective elements are stored.
+ *
+ * @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__))
-static inline CxIterator cxMapIteratorValues(CxMap const *map) {
+cx_attr_nonnull
+cx_attr_nodiscard
+static inline CxMapIterator cxMapIteratorValues(const CxMap *map) {
     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.
+ * 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
+ * @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__))
-static inline CxIterator cxMapIteratorKeys(CxMap const *map) {
+cx_attr_nonnull
+cx_attr_nodiscard
+static inline CxMapIterator cxMapIteratorKeys(const CxMap *map) {
     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.
+ * 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
+ * @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
@@ -253,8 +318,9 @@
  * @see cxMapIteratorKeys()
  * @see cxMapIteratorValues()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
-static inline CxIterator cxMapIterator(CxMap const *map) {
+cx_attr_nonnull
+cx_attr_nodiscard
+static inline CxMapIterator cxMapIterator(const CxMap *map) {
     return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);
 }
 
@@ -262,35 +328,45 @@
 /**
  * Creates a mutating iterator over the values of a map.
  *
- * \note An iterator iterates over all elements successively. Therefore the order
+ * When the map is storing pointers, those pointers are returned.
+ * Otherwise, the iterator iterates over pointers to the memory within the map where the
+ * respective elements are stored.
+ *
+ * @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__))
-CxMutIterator cxMapMutIteratorValues(CxMap *map);
+cx_attr_nonnull
+cx_attr_nodiscard
+cx_attr_export
+CxMapIterator cxMapMutIteratorValues(CxMap *map);
 
 /**
  * Creates a mutating iterator over the keys of a map.
  *
- * The elements of the iterator are keys of type CxHashKey.
+ * 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
+ * @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__))
-CxMutIterator cxMapMutIteratorKeys(CxMap *map);
+cx_attr_nonnull
+cx_attr_nodiscard
+cx_attr_export
+CxMapIterator cxMapMutIteratorKeys(CxMap *map);
 
 /**
  * Creates a mutating iterator for a map.
  *
- * The elements of the iterator are key/value pairs of type CxMapEntry.
+ * 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
+ * @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
@@ -298,21 +374,14 @@
  * @see cxMapMutIteratorKeys()
  * @see cxMapMutIteratorValues()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
-CxMutIterator cxMapMutIterator(CxMap *map);
+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
-
-/**
- * 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,
@@ -321,16 +390,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,
@@ -339,15 +399,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,
@@ -356,378 +408,133 @@
     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,
-        char const *key,
+        const char *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__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cxMapGet(
-        CxMap const *map,
+        const CxMap *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__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cxMapGet(
-        CxMap const *map,
+        const CxMap *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__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cxMapGet(
-        CxMap const *map,
+        const CxMap *map,
         cxmutstr 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__))
+cx_attr_nonnull
+cx_attr_nodiscard
+cx_attr_cstr_arg(2)
 static inline void *cxMapGet(
-        CxMap const *map,
-        char const *key
+        const CxMap *map,
+        const char *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(
+cx_attr_nonnull
+static inline int 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,
-        cxmutstr const &key
-) {
-    (void) map->cl->remove(map, cx_hash_key_cxstr(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(
-        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(
+cx_attr_nonnull
+static inline int cxMapRemove(
         CxMap *map,
         cxstring const &key
 ) {
-    (void) map->cl->remove(map, cx_hash_key_cxstr(key), false);
+    return map->cl->remove(map, cx_hash_key_cxstr(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
+static inline int cxMapRemove(
         CxMap *map,
         cxmutstr 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);
+    return map->cl->remove(map, cx_hash_key_cxstr(key), nullptr);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+cx_attr_cstr_arg(2)
+static inline int cxMapRemove(
         CxMap *map,
-        CxHashKey key
+        const char *key
 ) {
-    return map->cl->remove(map, key, !map->store_pointer);
+    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);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+cx_attr_access_w(3)
+static inline int cxMapRemoveAndGet(
         CxMap *map,
-        cxstring key
+        cxstring key,
+        void *targetbuf
 ) {
-    return map->cl->remove(map, cx_hash_key_cxstr(key), !map->store_pointer);
+    return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+cx_attr_access_w(3)
+static inline int cxMapRemoveAndGet(
         CxMap *map,
-        cxmutstr key
+        cxmutstr key,
+        void *targetbuf
 ) {
-    return map->cl->remove(map, cx_hash_key_cxstr(key), !map->store_pointer);
+    return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf);
 }
 
-/**
- * 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(
+cx_attr_nonnull
+cx_attr_access_w(3)
+cx_attr_cstr_arg(2)
+static inline int cxMapRemoveAndGet(
         CxMap *map,
-        char const *key
+        const char *key,
+        void *targetbuf
 ) {
-    return map->cl->remove(map, cx_hash_key_str(key), !map->store_pointer);
+    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,
@@ -737,14 +544,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,
@@ -754,14 +556,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,
@@ -771,17 +568,13 @@
 }
 
 /**
- * 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,
-        char const *key,
+        const char *key,
         void *value
 ) {
     return map->cl->put(map, cx_hash_key_str(key), value);
@@ -790,75 +583,75 @@
 /**
  * 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 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 (@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,                        \
     cxstring: cx_map_put_cxstr,                   \
     cxmutstr: cx_map_put_mustr,                   \
     char*: cx_map_put_str,                        \
-    char const*: cx_map_put_str)                  \
+    const 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
+ * @copydoc cxMapGet()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cx_map_get(
-        CxMap const *map,
+        const CxMap *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
+ * @copydoc cxMapGet()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cx_map_get_cxstr(
-        CxMap const *map,
+        const CxMap *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
+ * @copydoc cxMapGet()
  */
-__attribute__((__nonnull__, __warn_unused_result__))
+cx_attr_nonnull
+cx_attr_nodiscard
 static inline void *cx_map_get_mustr(
-        CxMap const *map,
+        const CxMap *map,
         cxmutstr 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
+ * @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(
-        CxMap const *map,
-        char const *key
+        const CxMap *map,
+        const char *key
 ) {
     return map->cl->get(map, cx_hash_key_str(key));
 }
@@ -866,268 +659,166 @@
 /**
  * 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,                 \
     cxstring: cx_map_get_cxstr,            \
     cxmutstr: cx_map_get_mustr,            \
     char*: cx_map_get_str,                 \
-    char const*: cx_map_get_str)           \
+    const 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
+ * @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,
-        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
+ * @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,                 \
     cxstring: cx_map_remove_cxstr,            \
     cxmutstr: cx_map_remove_mustr,            \
     char*: cx_map_remove_str,                 \
-    char const*: cx_map_remove_str)           \
+    const 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
+ * @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,
-        char const *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,                 \
-    char const*: 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->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->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, which 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->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
- */
-__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.
+ * @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
  *
- * 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()
+ * @see cxMapRemove()
  */
-#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,               \
-    char const*: cx_map_remove_and_get_str)         \
-    (map, key)
+    const char*: cx_map_remove_and_get_str)         \
+    (map, key, targetbuf)
 
 #endif // __cplusplus
 

mercurial