From 8bd6650245d050e455cd4d26f6e59e7dd9b80392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Tue, 29 Mar 2016 11:47:23 +0200 Subject: array: allow arbitrarily sized array elements There exist two typical ways to use an array: 1) to hold pointers to externally allocated memory regions Use array_init(...) for initialization, an element has the size of a pointer. Use the functions suffixed with `_ptr' to manage your pointers. The cleanup function array_release_full must only be used with this type of array. 2) to hold arbitrary sized objects Use array_init_sized(...) to specify the size of a single element. Use the regular (i.e. without the `_ptr' suffix) functions to manage your objects. array_get will return a pointer to the object stored within the array. --- array.c | 52 +++++++++++++++++++++++++++++++++++++++++++++------- array.h | 35 ++++++++++++++++++++++++++++++----- vis-motions.c | 4 ++-- vis-text-objects.c | 4 ++-- vis.c | 2 ++ 5 files changed, 81 insertions(+), 16 deletions(-) diff --git a/array.c b/array.c index 7689b2e..315e18c 100644 --- a/array.c +++ b/array.c @@ -8,7 +8,12 @@ #define ARRAY_SIZE 16 void array_init(Array *arr) { + array_init_sized(arr, sizeof(void*)); +} + +void array_init_sized(Array *arr, size_t elem_size) { memset(arr, 0, sizeof *arr); + arr->elem_size = elem_size; } bool array_reserve(Array *arr, size_t count) { @@ -16,7 +21,7 @@ bool array_reserve(Array *arr, size_t count) { count = ARRAY_SIZE; if (arr->count < count) { count = MAX(count, arr->count*2); - void **items = realloc(arr->items, count * sizeof(void*)); + char *items = realloc(arr->items, count * arr->elem_size); if (!items) return false; arr->count = count; @@ -29,21 +34,21 @@ void array_release(Array *arr) { if (!arr) return; free(arr->items); - array_init(arr); + array_init_sized(arr, arr->elem_size); } void array_release_full(Array *arr) { if (!arr) return; for (size_t i = 0; i < arr->len; i++) - free(arr->items[i]); + free(array_get_ptr(arr, i)); array_release(arr); } void array_clear(Array *arr) { arr->len = 0; if (arr->items) - memset(arr->items, 0, arr->count * sizeof(void*)); + memset(arr->items, 0, arr->count * arr->elem_size); } void *array_get(Array *arr, size_t idx) { @@ -51,7 +56,16 @@ void *array_get(Array *arr, size_t idx) { errno = EINVAL; return NULL; } - return arr->items[idx]; + return arr->items + (idx * arr->elem_size); +} + +void *array_get_ptr(Array *arr, size_t idx) { + if (arr->elem_size != sizeof(void*)) { + errno = ENOTSUP; + return NULL; + } + void **ptr = array_get(arr, idx); + return ptr ? *ptr : NULL; } bool array_set(Array *arr, size_t idx, void *item) { @@ -59,14 +73,38 @@ bool array_set(Array *arr, size_t idx, void *item) { errno = EINVAL; return false; } - arr->items[idx] = item; + if (item) + memcpy(arr->items + (idx * arr->elem_size), item, arr->elem_size); + else + memset(arr->items + (idx * arr->elem_size), 0, arr->elem_size); return true; } +bool array_set_ptr(Array *arr, size_t idx, void *item) { + if (arr->elem_size != sizeof(void*)) { + errno = ENOTSUP; + return false; + } + return array_set(arr, idx, &item); +} + bool array_add(Array *arr, void *item) { if (!array_reserve(arr, arr->len+1)) return false; - arr->items[arr->len++] = item;; + if (!array_set(arr, arr->len++, item)) { + arr->len--; + return false; + } + return true; +} + +bool array_add_ptr(Array *arr, void *item) { + if (!array_reserve(arr, arr->len+1)) + return false; + if (!array_set_ptr(arr, arr->len++, item)) { + arr->len--; + return false; + } return true; } diff --git a/array.h b/array.h index 2d9c123..052bb50 100644 --- a/array.h +++ b/array.h @@ -4,14 +4,36 @@ #include #include -typedef struct { /* a dynamically growing array */ - void **items; /* NULL if empty */ - size_t len; /* number of currently stored items */ - size_t count; /* maximal capacity of the array */ +/* A dynamically growing array, there exist two typical ways to use it: + * + * 1) to hold pointers to externally allocated memory regions + * + * Use array_init(...) for initialization, an element has the + * size of a pointer. Use the functions suffixed with `_ptr' + * to manage your pointers. The cleanup function array_release_full + * must only be used with this type of array. + * + * 2) to hold arbitrary sized objects + * + * Use array_init_sized(...) to specify the size of a single + * element. Use the regular (i.e. without the `_ptr' suffix) + * functions to manage your objects. array_{add,set} will copy + * the object into the array, array_get will return a pointer + * to the object stored within the array. + */ +typedef struct { /* a dynamically growing array */ + char *items; /* NULL if empty */ + size_t elem_size; /* size of one array element */ + size_t len; /* number of currently stored items */ + size_t count; /* maximal capacity of the array */ } Array; -/* initalize a (stack allocated) Array instance */ +/* initalize an already allocated Array instance, storing pointers + * (elem_size == sizeof(void*)) */ void array_init(Array*); +/* initalize an already allocated Array instance, storing arbitrary + * sized objects */ +void array_init_sized(Array*, size_t elem_size); /* release/free the storage space used to hold items, reset size to zero */ void array_release(Array*); /* like above but also call free(3) for each stored pointer */ @@ -22,9 +44,12 @@ void array_clear(Array*); bool array_reserve(Array*, size_t count); /* get/set the i-th (zero based) element of the array */ void *array_get(Array*, size_t idx); +void *array_get_ptr(Array*, size_t idx); bool array_set(Array*, size_t idx, void *item); +bool array_set_ptr(Array*, size_t idx, void *item); /* add a new element to the end of the array */ bool array_add(Array*, void *item); +bool array_add_ptr(Array*, void *item); /* return the number of elements currently stored in the array */ size_t array_length(Array*); diff --git a/vis-motions.c b/vis-motions.c index 5bff026..3bb0b88 100644 --- a/vis-motions.c +++ b/vis-motions.c @@ -234,7 +234,7 @@ int vis_motion_register(Vis *vis, enum VisMotionType type, void *data, move->type = type; move->data = data; - if (array_add(&vis->motions, move)) + if (array_add_ptr(&vis->motions, move)) return VIS_MOVE_LAST + array_length(&vis->motions) - 1; free(move); return -1; @@ -322,7 +322,7 @@ bool vis_motion(Vis *vis, enum VisMotion motion, ...) { if (motion < LENGTH(vis_motions)) vis->action.movement = &vis_motions[motion]; else - vis->action.movement = array_get(&vis->motions, motion - VIS_MOVE_LAST); + vis->action.movement = array_get_ptr(&vis->motions, motion - VIS_MOVE_LAST); if (!vis->action.movement) goto err; diff --git a/vis-text-objects.c b/vis-text-objects.c index 962c22c..1b9f242 100644 --- a/vis-text-objects.c +++ b/vis-text-objects.c @@ -13,7 +13,7 @@ int vis_textobject_register(Vis *vis, int type, void *data, obj->type = type; obj->data = data; - if (array_add(&vis->textobjects, obj)) + if (array_add_ptr(&vis->textobjects, obj)) return LENGTH(vis_textobjects) + array_length(&vis->textobjects) - 1; free(obj); return -1; @@ -23,7 +23,7 @@ bool vis_textobject(Vis *vis, enum VisTextObject id) { if (id < LENGTH(vis_textobjects)) vis->action.textobj = &vis_textobjects[id]; else - vis->action.textobj = array_get(&vis->textobjects, id - LENGTH(vis_textobjects)); + vis->action.textobj = array_get_ptr(&vis->textobjects, id - LENGTH(vis_textobjects)); if (!vis->action.textobj) return false; action_do(vis, &vis->action); diff --git a/vis.c b/vis.c index 4ececaa..8dc8365 100644 --- a/vis.c +++ b/vis.c @@ -319,6 +319,8 @@ Vis *vis_new(Ui *ui, VisEvent *event) { vis->expandtab = false; vis->registers[VIS_REG_BLACKHOLE].type = REGISTER_BLACKHOLE; vis->registers[VIS_REG_CLIPBOARD].type = REGISTER_CLIPBOARD; + array_init(&vis->motions); + array_init(&vis->textobjects); action_reset(&vis->action); if (!(vis->command_file = file_new_internal(vis, NULL))) goto err; -- cgit v1.2.3