add implementations for map difference default tip

Sat, 25 Oct 2025 21:33:56 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 25 Oct 2025 21:33:56 +0200
changeset 1445
e8089a590b71
parent 1444
dd9dcbb39c2f

add implementations for map difference

relates to #746

docs/Writerside/topics/map.h.md file | annotate | diff | comparison | revisions
src/cx/map.h file | annotate | diff | comparison | revisions
src/map.c file | annotate | diff | comparison | revisions
--- a/docs/Writerside/topics/map.h.md	Sat Oct 25 21:12:59 2025 +0200
+++ b/docs/Writerside/topics/map.h.md	Sat Oct 25 21:33:56 2025 +0200
@@ -222,12 +222,17 @@
 
 void *cxMapGet(CxMap *map, KeyType key);
 
+bool cxMapContains(CxMap *map, KeyType key);
+
 size_t cxMapSize(const CxMap *map);
 ```
 
 With the function `cxMapGet()` you can retrieve a value stored under the specified `key`.
 If there is no such value, this function returns `NULL`.
 
+The function `cxMapContains()` returns `true` if the map contains an element with the specified `key`,
+and `false` otherwise.
+
 The function `cxMapSize()` returns how many key/value-pairs are currently stored in the map.
 
 ## Remove
--- a/src/cx/map.h	Sat Oct 25 21:12:59 2025 +0200
+++ b/src/cx/map.h	Sat Oct 25 21:33:56 2025 +0200
@@ -41,6 +41,11 @@
 #include "string.h"
 #include "hash_key.h"
 
+#ifndef UCX_LIST_H
+// forward-declare CxList
+typedef struct cx_list_s CxList;
+#endif
+
 #ifdef    __cplusplus
 extern "C" {
 #endif
@@ -404,12 +409,23 @@
  *
  * @param map (@c CxMap*) the map
  * @param key (any supported key type) the key
- * @return (@c void*) the value
+ * @return (@c void*) the value or @c NULL when no value with that @p key exists
  * @see CX_HASH_KEY()
  */
 #define cxMapGet(map, key) cx_map_get(map, CX_HASH_KEY(key))
 
 /**
+ * Checks if a map contains a specific key.
+ *
+ * @param map (@c CxMap*) the map
+ * @param key (any supported key type) the key
+ * @retval true if the key exists in the map
+ * @retval false if the key does not exist in the map
+ * @see CX_HASH_KEY()
+ */
+#define cxMapContains(map, key) (cxMapGet(map, key) != NULL)
+
+/**
  * Removes a key/value-pair from the map by using the key.
  *
  * Invokes the destructor functions, if any, on the removed element if and only if the
@@ -491,6 +507,15 @@
 CX_EXPORT int cxMapClone(CxMap *dst, const CxMap *src,
         cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
 
+
+cx_attr_nonnull_arg(1, 2, 3, 4)
+CX_EXPORT int cxMapDifference(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend,
+        cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+cx_attr_nonnull_arg(1, 2, 3, 4)
+CX_EXPORT int cxMapListDifference(CxMap *dst, const CxMap *src, const CxList *keys,
+        cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
 #ifdef    __cplusplus
 } // extern "C"
 #endif
--- a/src/map.c	Sat Oct 25 21:12:59 2025 +0200
+++ b/src/map.c	Sat Oct 25 21:33:56 2025 +0200
@@ -29,6 +29,8 @@
 #include "cx/map.h"
 #include <string.h>
 
+#include "cx/list.h"
+
 // <editor-fold desc="empty map implementation">
 
 static void cx_empty_map_noop(cx_attr_unused CxMap *map) {
@@ -172,3 +174,93 @@
     }
     return 0;
 }
+
+int cxMapDifference(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend,
+        cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
+    const bool map_was_not_empty = cxMapSize(dst) > 0;
+    CxMapIterator src_iter = cxMapIterator(minuend);
+    if (cxCollectionStoresPointers(dst)) {
+        cx_foreach(const CxMapEntry *, entry, src_iter) {
+            if (cxMapContains(subtrahend, *entry->key)) {
+                if (map_was_not_empty) {
+                    cxMapRemove(dst, *entry->key);
+                }
+            } else {
+                void** dst_mem = cxMapEmplace(dst, *entry->key);
+                if (dst_mem == NULL) {
+                    return 1;
+                }
+
+                void* dst_ptr = clone_func(NULL, entry->value, clone_allocator, data);
+                if (dst_ptr == NULL) {
+                    cx_map_remove_uninitialized_entry(dst, *(entry->key));
+                    return 1;
+                }
+                *dst_mem = dst_ptr;
+            }
+        }
+    } else {
+        cx_foreach(const CxMapEntry *, entry, src_iter) {
+            if (cxMapContains(subtrahend, *entry->key)) {
+                if (map_was_not_empty) {
+                    cxMapRemove(dst, *entry->key);
+                }
+            } else {
+                void* dst_mem = cxMapEmplace(dst, *entry->key);
+                if (dst_mem == NULL) {
+                    return 1;
+                }
+                if (NULL == clone_func(dst_mem, entry->value, clone_allocator, data)) {
+                    cx_map_remove_uninitialized_entry(dst, *entry->key);
+                    return 1;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+int cxMapListDifference(CxMap *dst, const CxMap *src, const CxList *keys,
+        cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
+    const bool map_was_not_empty = cxMapSize(dst) > 0;
+    CxMapIterator src_iter = cxMapIterator(src);
+    if (cxCollectionStoresPointers(dst)) {
+        cx_foreach(const CxMapEntry *, entry, src_iter) {
+            if (cxListContains(keys, entry->key)) {
+                if (map_was_not_empty) {
+                    cxMapRemove(dst, *entry->key);
+                }
+            } else {
+                void** dst_mem = cxMapEmplace(dst, *entry->key);
+                if (dst_mem == NULL) {
+                    return 1;
+                }
+
+                void* dst_ptr = clone_func(NULL, entry->value, clone_allocator, data);
+                if (dst_ptr == NULL) {
+                    cx_map_remove_uninitialized_entry(dst, *(entry->key));
+                    return 1;
+                }
+                *dst_mem = dst_ptr;
+            }
+        }
+    } else {
+        cx_foreach(const CxMapEntry *, entry, src_iter) {
+            if (cxListContains(keys, entry->key)) {
+                if (map_was_not_empty) {
+                    cxMapRemove(dst, *entry->key);
+                }
+            } else {
+                void* dst_mem = cxMapEmplace(dst, *entry->key);
+                if (dst_mem == NULL) {
+                    return 1;
+                }
+                if (NULL == clone_func(dst_mem, entry->value, clone_allocator, data)) {
+                    cx_map_remove_uninitialized_entry(dst, *entry->key);
+                    return 1;
+                }
+            }
+        }
+    }
+    return 0;
+}

mercurial