Skip to content

Commit

Permalink
feat(anomap): add anomap_clone and anomap_move, and NULL cmp
Browse files Browse the repository at this point in the history
  • Loading branch information
Anotra committed Feb 26, 2024
1 parent 8bbbd4c commit b136042
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 17 deletions.
107 changes: 90 additions & 17 deletions core/anomap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -280,17 +279,21 @@ anomap_init(struct anomap *map,
int (*cmp)(const void *, const void *),
anomap_options options)
{
if (!map || !key_size || !cmp || (options & ~ANOMAP_ALLOWED_OPTIONS))
if (!map || !key_size || (options & ~ANOMAP_ALLOWED_OPTIONS))
return false;
memset(map, 0, sizeof *map);
map->free_on_cleanup = false;
map->options = options;
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;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -394,24 +456,35 @@ anomap_index_of_no_lock(struct anomap *map, void *key, size_t *position) {
int result;

if (0 == map->map.len) goto on_empty;
result = map->cmp(key, keys + key_size * map->map.arr[map->map.len - 1]);
if (0 == result) return *position = map->map.len - 1, true;

# define BINARY_SEARCH(cmp_operator) \
if (result cmp_operator 0) \
return *position = map->map.len, false; \
while (lo < hi) { \
mid = lo + (hi - lo) / 2; \
result = map->cmp(key, keys + key_size * map->map.arr[mid]); \
if (result == 0) return *position = mid, true; \
if (result cmp_operator 0) lo = mid + 1; \
else hi = mid; \
}
const size_t last_item = map->map.arr[map->map.len - 1];
result = map->cmp
? map->cmp(key, keys + key_size * last_item)
: memcmp(key, keys + key_size * last_item, key_size);
if (0 == result) return *position = last_item, true;

# define BSEARCH(cmp_operator, cmp_func, ...) \
do { \
if (result cmp_operator 0) \
return *position = map->map.len, false; \
while (lo < hi) { \
mid = lo + (hi - lo) / 2; \
result = cmp_func(__VA_ARGS__); \
if (result == 0) return *position = mid, true; \
if (result cmp_operator 0) lo = mid + 1; \
else hi = mid; \
} \
} while (0)

if (map->options & anomap_reverse_order) {
BINARY_SEARCH(<);
if (map->cmp)
BSEARCH(<, map->cmp, key, keys + key_size * map->map.arr[mid]);
else
BSEARCH(<, memcmp, key, keys + key_size * map->map.arr[mid], key_size);
} else {
BINARY_SEARCH(>);
if (map->cmp)
BSEARCH(>, map->cmp, key, keys + key_size * map->map.arr[mid]);
else
BSEARCH(>, memcmp, key, keys + key_size * map->map.arr[mid], key_size);
}

# undef BINARY_SEARCH
Expand Down
8 changes: 8 additions & 0 deletions core/anomap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit b136042

Please sign in to comment.