--- a/ucx/map.c Sun Aug 31 14:39:13 2025 +0200 +++ b/ucx/map.c Sat Nov 08 23:06:11 2025 +0100 @@ -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) { @@ -51,7 +53,7 @@ cx_attr_unused enum cx_map_iterator_type type ) { CxMapIterator iter = {0}; - iter.map.c = map; + iter.map = (CxMap*) map; iter.base.valid = cx_empty_map_iter_valid; return iter; } @@ -84,25 +86,210 @@ // </editor-fold> -CxMapIterator cxMapMutIteratorValues(CxMap *map) { - CxMapIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_VALUES); - it.base.mutating = true; - return it; +void cxMapClear(CxMap *map) { + map->cl->clear(map); +} + +size_t cxMapSize(const CxMap *map) { + return map->collection.size; +} + +CxMapIterator cxMapIteratorValues(const CxMap *map) { + if (map == NULL) map = cxEmptyMap; + return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES); +} + +CxMapIterator cxMapIteratorKeys(const CxMap *map) { + if (map == NULL) map = cxEmptyMap; + return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS); } -CxMapIterator cxMapMutIteratorKeys(CxMap *map) { - CxMapIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_KEYS); - it.base.mutating = true; - return it; +CxMapIterator cxMapIterator(const CxMap *map) { + if (map == NULL) map = cxEmptyMap; + return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS); +} + +int cx_map_put(CxMap *map, CxHashKey key, void *value) { + return map->cl->put(map, key, value) == NULL; } -CxMapIterator cxMapMutIterator(CxMap *map) { - CxMapIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS); - it.base.mutating = true; - return it; +void *cx_map_emplace(CxMap *map, CxHashKey key) { + return map->cl->put(map, key, NULL); +} + +void *cx_map_get(const CxMap *map, CxHashKey key) { + return map->cl->get(map, key); +} + +int cx_map_remove(CxMap *map, CxHashKey key, void *targetbuf) { + return map->cl->remove(map, key, targetbuf); } void cxMapFree(CxMap *map) { if (map == NULL) return; map->cl->deallocate(map); } + +static void cx_map_remove_uninitialized_entry(CxMap *map, CxHashKey key) { + cx_destructor_func destr_bak = map->collection.simple_destructor; + cx_destructor_func2 destr2_bak = map->collection.advanced_destructor; + map->collection.simple_destructor = NULL; + map->collection.advanced_destructor = NULL; + cxMapRemove(map, key); + map->collection.simple_destructor = destr_bak; + map->collection.advanced_destructor = destr2_bak; +} + +int cxMapClone(CxMap *dst, const CxMap *src, cx_clone_func clone_func, + const CxAllocator *clone_allocator, void *data) { + if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; + CxMapIterator src_iter = cxMapIterator(src); + for (size_t i = 0; i < cxMapSize(src); i++) { + const CxMapEntry *entry = cxIteratorCurrent(src_iter); + void **dst_mem = cxMapEmplace(dst, *(entry->key)); + if (dst_mem == NULL) { + return 1; // LCOV_EXCL_LINE + } + void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; + void *dst_ptr = clone_func(target, entry->value, clone_allocator, data); + if (dst_ptr == NULL) { + cx_map_remove_uninitialized_entry(dst, *(entry->key)); + return 1; + } + if (cxCollectionStoresPointers(dst)) { + *dst_mem = dst_ptr; + } + cxIteratorNext(src_iter); + } + return 0; +} + +int cxMapDifference(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend, + cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) { + if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; + + CxMapIterator src_iter = cxMapIterator(minuend); + cx_foreach(const CxMapEntry *, entry, src_iter) { + if (cxMapContains(subtrahend, *entry->key)) { + continue; + } + void** dst_mem = cxMapEmplace(dst, *entry->key); + if (dst_mem == NULL) { + return 1; // LCOV_EXCL_LINE + } + void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; + void* dst_ptr = clone_func(target, entry->value, clone_allocator, data); + if (dst_ptr == NULL) { + cx_map_remove_uninitialized_entry(dst, *(entry->key)); + return 1; + } + if (cxCollectionStoresPointers(dst)) { + *dst_mem = dst_ptr; + } + } + return 0; +} + +int cxMapListDifference(CxMap *dst, const CxMap *src, const CxList *keys, + cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) { + if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; + + CxMapIterator src_iter = cxMapIterator(src); + cx_foreach(const CxMapEntry *, entry, src_iter) { + if (cxListContains(keys, entry->key)) { + continue; + } + void** dst_mem = cxMapEmplace(dst, *entry->key); + if (dst_mem == NULL) { + return 1; // LCOV_EXCL_LINE + } + void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; + void* dst_ptr = clone_func(target, entry->value, clone_allocator, data); + if (dst_ptr == NULL) { + cx_map_remove_uninitialized_entry(dst, *(entry->key)); + return 1; + } + if (cxCollectionStoresPointers(dst)) { + *dst_mem = dst_ptr; + } + } + return 0; +} + +int cxMapIntersection(CxMap *dst, const CxMap *src, const CxMap *other, + cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) { + if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; + + CxMapIterator src_iter = cxMapIterator(src); + cx_foreach(const CxMapEntry *, entry, src_iter) { + if (!cxMapContains(other, *entry->key)) { + continue; + } + void** dst_mem = cxMapEmplace(dst, *entry->key); + if (dst_mem == NULL) { + return 1; // LCOV_EXCL_LINE + } + void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; + void* dst_ptr = clone_func(target, entry->value, clone_allocator, data); + if (dst_ptr == NULL) { + cx_map_remove_uninitialized_entry(dst, *(entry->key)); + return 1; + } + if (cxCollectionStoresPointers(dst)) { + *dst_mem = dst_ptr; + } + } + return 0; +} + +int cxMapListIntersection(CxMap *dst, const CxMap *src, const CxList *keys, + cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) { + if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; + + CxMapIterator src_iter = cxMapIterator(src); + cx_foreach(const CxMapEntry *, entry, src_iter) { + if (!cxListContains(keys, entry->key)) { + continue; + } + void** dst_mem = cxMapEmplace(dst, *entry->key); + if (dst_mem == NULL) { + return 1; // LCOV_EXCL_LINE + } + void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; + void* dst_ptr = clone_func(target, entry->value, clone_allocator, data); + if (dst_ptr == NULL) { + cx_map_remove_uninitialized_entry(dst, *(entry->key)); + return 1; + } + if (cxCollectionStoresPointers(dst)) { + *dst_mem = dst_ptr; + } + } + return 0; +} + +int cxMapUnion(CxMap *dst, const CxMap *src, + cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) { + if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; + + CxMapIterator src_iter = cxMapIterator(src); + cx_foreach(const CxMapEntry *, entry, src_iter) { + if (cxMapContains(dst, *entry->key)) { + continue; + } + void** dst_mem = cxMapEmplace(dst, *entry->key); + if (dst_mem == NULL) { + return 1; // LCOV_EXCL_LINE + } + void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; + void* dst_ptr = clone_func(target, entry->value, clone_allocator, data); + if (dst_ptr == NULL) { + cx_map_remove_uninitialized_entry(dst, *(entry->key)); + return 1; + } + if (cxCollectionStoresPointers(dst)) { + *dst_mem = dst_ptr; + } + } + return 0; +}