--- 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; +}