Sat, 25 Oct 2025 21:33:56 +0200
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; +}