diff --git a/core/anomap.c b/core/anomap.c index 760c8ad0..c605a400 100644 --- a/core/anomap.c +++ b/core/anomap.c @@ -81,7 +81,6 @@ static const struct anomap_lock null_lock = { static unsigned anomap_has_locks = #if !defined ANOMAP_NATIVE_LOCKS || ANOMAP_NATIVE_LOCKS == NATIVE_LOCK_NONE 0; - static const struct anomap_lock lock_functions = null_lock; #else anomap_use_lock; @@ -288,9 +287,13 @@ anomap_init(struct anomap *map, map->cmp = cmp; map->keys.size = key_size; map->vals.size = val_size; +#if !defined ANOMAP_NATIVE_LOCKS || ANOMAP_NATIVE_LOCKS == NATIVE_LOCK_NONE + map->lock.functions = &null_lock; +#else map->lock.functions = options & anomap_use_lock ? &lock_functions : &null_lock; +#endif if ((map->lock.lock = map->lock.functions->create())) return true; @@ -324,6 +327,65 @@ anomap_destroy(struct anomap *map) { free(map); } +struct anomap * +anomap_clone(struct anomap *map, anomap_clone_options options) { + if (options) return NULL; + struct anomap *clone = malloc(sizeof *clone); + struct { + void *ptrs[16]; + size_t len; + } cleanup = { 0 }; + if (!clone) return NULL; + + LOCK_R_ACQUIRE; + memcpy(clone, map, sizeof *clone); + clone->free_on_cleanup = true; + + if (!(clone->lock.lock = clone->lock.functions->create())) + goto lock_create_fail; + +#define CLONE_ARRAY(ARRAY, SIZE) \ + do { \ + if ((clone->ARRAY.arr = malloc(SIZE))) { \ + memcpy(clone->ARRAY.arr, map->ARRAY.arr, SIZE); \ + cleanup.ptrs[cleanup.len++] = clone->ARRAY.arr; \ + } else goto array_copy_fail; \ + } while (0) + + if (clone->map.len) { + CLONE_ARRAY(map, clone->map.cap * sizeof *clone->map.arr); + CLONE_ARRAY(keys, clone->keys.cap * clone->keys.size); + if (clone->vals.size) + CLONE_ARRAY(vals, clone->vals.cap * clone->vals.size); + if (clone->options & anomap_preserve_order) + CLONE_ARRAY(order, clone->order.cap * sizeof *clone->order.arr); + } + + LOCK_R_RELEASE; + return clone; + + array_copy_fail: + while (cleanup.len) + free(cleanup.ptrs[--cleanup.len]); + clone->lock.functions->destroy(clone->lock.lock); + lock_create_fail: + LOCK_R_RELEASE; + free(clone); + return NULL; +} + +void +anomap_move(struct anomap *dest, bool free_on_destroy, struct anomap *map) { + LOCK_W_ACQUIRE; + memcpy(dest, map, sizeof *dest); + bool free_map = map->free_on_cleanup; + dest->free_on_cleanup = free_on_destroy; + memset(map, 0, sizeof *map); + if (free_map) free(map); + map = dest; + LOCK_W_RELEASE; +} + void anomap_set_on_item_changed( struct anomap *map, anomap_on_item_changed *on_changed, void *data) diff --git a/core/anomap.h b/core/anomap.h index 073147a2..a56422e0 100644 --- a/core/anomap.h +++ b/core/anomap.h @@ -61,6 +61,14 @@ struct anomap *anomap_create(size_t key_size, size_t val_size, anomap_options options); void anomap_destroy(struct anomap *map); +typedef enum { +#define ANOMAP_CLONE_OPTIONS_NONE anomap_clone_options_none + anomap_clone_options_none, +} anomap_clone_options; + +struct anomap *anomap_clone(struct anomap *map, anomap_clone_options options); +void anomap_move(struct anomap *dest, bool free_on_destroy, struct anomap *map); + struct anomap_item_changed { struct anomap *map; void *data;