#include #include #include #include #include "bitset.h" #include "mylock.h" #include "utils.h" #include "zarray.h" int zarray_init(zarray_t* array, int delta, zarray_item_killer_t killer) { if ((array == NULL) || (delta <= 0)) { return -EINVAL; } mylock_init(&(array->lock)); array->delta = delta; array->data = NULL; array->killer = killer; array->count = 0; array->caps = 0; array->pos = 0; return 0; } static int zarray_ensure_items(zarray_t* array, int mincap) { int nc, i; void* p; if (mincap < array->caps) { return 1; } nc = mincap; if (nc < array->caps + array->delta) { nc = array->caps + array->delta; } p = (void*)realloc(array->data, nc * sizeof(void*)); if (p == NULL) { return -ENOMEM; } array->data = p; for (i = array->caps; i < nc; i++) { array->data[i] = NULL; } /* this will make we can get next free * location quickly */ array->pos = array->caps; array->caps = nc; return 1; } int zarray_store(zarray_t* array, void* data) { int rc, i; if (array == NULL) { return -EINVAL; } mylock_lock(&(array->lock)); rc = zarray_ensure_items(array, array->count + 1); if (rc >= 0) { int idx; rc = -ENOMEM; idx = array->pos; for (i = 0; i < array->caps; i++) { if (array->data[idx] == NULL) { array->data[idx] = data; array->count++; rc = idx; break; } idx++; if (idx >= array->caps) { idx = 0; } } if (rc >= 0) { array->pos = (rc + 1) % array->caps; } } mylock_unlock(&(array->lock)); return rc; } int zarray_clear(zarray_t* array, int idx) { if (array == NULL) { return -EINVAL; } if ((idx < 0) || (idx >= array->caps)) { return -EINVAL; } mylock_lock(&(array->lock)); array->data[idx] = NULL; mylock_unlock(&(array->lock)); return 0; } void zarray_fini(zarray_t* array) { if (array == NULL) { return; } if (array->data != NULL) { int i; if (array->killer != NULL) { for (i = 0; i < array->caps; i++) { if (array->data[i] != NULL) { void* ptr = array->data[i]; array->data[i] = NULL; (array->killer)(ptr); } } } free(array->data); array->data = NULL; } } int zarray_iter_ex(zarray_t* array, zarray_iter_skip_fn_t skipfn, xlist_t* l, void* arg) { int i, j; if ((array == NULL) || (l == NULL)) { return -EINVAL; } mylock_lock(&(array->lock)); for (j = 0; j < l->count; j++) { zarray_iter_fn_t f = (zarray_iter_fn_t)l->data[j]; if (f == NULL) { continue; } for (i = 0; i < array->caps; i++) { if (skipfn != NULL) { if (skipfn(array->data[i])) { continue; } } else if (array->data[i] == NULL) { continue; } (*f)(arg, array->data[i]); } } mylock_unlock(&(array->lock)); return 0; } int zarray_iter(zarray_t* array, zarray_iter_fn_t f, void* arg) { int rc; xlist_t l; if ((array == NULL) || (f == NULL)) { return -EINVAL; } xlist_init(&l, 2); xlist_store(&l, f); rc = zarray_iter_ex(array, NULL, &l, arg); xlist_fini(&l); return rc; } void* zarray_find(zarray_t* array, zarray_find_cond_fn_t fn, ...) { int i; va_list ap; void* data = NULL; if ((array == NULL) || (fn == NULL)) { errno = EINVAL; return NULL; } va_start(ap, fn); mylock_lock(&(array->lock)); for (i = 0; i < array->caps; i++) { va_list ap1; int rc; va_copy(ap1, ap); rc = fn(array->data[i], ap1); va_end(ap1); if (rc) { data = array->data[i]; break; } } mylock_unlock(&(array->lock)); va_end(ap); return data; } int zarray_del(zarray_t* array, int idx) { void* ptr = NULL; if (array == NULL) { return -EINVAL; } if (idx < 0) { return -EINVAL; } if (idx >= array->caps) { return 0; } mylock_lock(&(array->lock)); ptr = array->data[idx]; array->data[idx] = NULL; if (ptr != NULL) { array->count--; } /* idx will be a usable position */ array->pos = idx; mylock_unlock(&(array->lock)); if (array->killer != NULL) { if (ptr != NULL) { (array->killer)(ptr); } } return 0; } int zarray_put_ex(zarray_t* array, int count, int* idxs, void** data) { int i, maxid; int rc = 0; if ((array == NULL) || (count <= 0) || (idxs == NULL) || (data == NULL)) { return -EINVAL; } maxid = 0; for (i = 0; i < count; i++) { if (idxs[i] < 0) { return -EINVAL; } if (idxs[i] > maxid) { maxid = idxs[i]; } } mylock_lock(&(array->lock)); rc = zarray_ensure_items(array, maxid + 1); if (rc >= 0) { for (i = 0; i < count; i++) { int idx = idxs[i]; void* ptr = array->data[idx]; array->data[idx] = data[i]; if (ptr != NULL) { if (array->killer != NULL) { array->killer(ptr); } } else { array->count++; } } } mylock_unlock(&(array->lock)); return 0; } int zarray_put(zarray_t* array, int idx, void* data) { int idxs[] = { idx }; void* datas[] = { data }; return zarray_put_ex(array, 1, &idxs[0], &datas[0]); } int zarray_get_ex(zarray_t* array, int count, int* idxs, void** data) { int i; if ((array == NULL) || (count <= 0) || (idxs == NULL) || (data == NULL)) { return -EINVAL; } mylock_lock(&(array->lock)); for (i = 0; i < count; i++) { int idx = idxs[i]; if (idx >= array->caps) { data[i] = NULL; } else { data[i] = array->data[idx]; } } mylock_unlock(&(array->lock)); return 0; } void* zarray_get(zarray_t* array, int idx) { int idxs[] = { idx }; void* datas[] = { NULL }; int rc = 0; rc = zarray_get_ex(array, 1, &idxs[0], &datas[0]); if (rc < 0) { SET_ERROR(-rc); return NULL; } return datas[0]; } typedef struct { mylock_t lock; } xzarray_private_t; typedef struct { unsigned int inuse : 1; void* data; } xzarray_item_t; typedef struct { int count; size_t caps; size_t delta; int pos; xzarray_item_t* data; destroy_fn_t killer; } xzarray_t; static size_t xzarray_datasize(va_list ap) { size_t sz = sizeof(xzarray_t); return sz; } static int xzarray_init(meta_obj_t* obj, va_list ap) { xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(obj); xzarray_t* a = RTTI_OBJ_TO_DATA(xzarray_t, obj); xzarray_params_t* params = va_arg(ap, xzarray_params_t*); if ((params == NULL) || (params->delta < 1)) { return -EINVAL; } a->count = 0; a->caps = 0; a->delta = params->delta; a->data = NULL; a->pos = 0; a->killer = params->datakiller; mylock_init(&(priv->lock)); return 1; } static void xzarray_destroy(meta_obj_t* obj) { xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(obj); xzarray_t* a = RTTI_OBJ_TO_DATA(xzarray_t, obj); int i; for (i = 0; i < a->caps; i++) { if (a->data[i].inuse) { if (a->killer != NULL) { a->killer(a->data[i].data); } } } FREEUP(a->data); mylock_fini(&(priv->lock)); } static int xzarray_ensure_items(xzarray_t* array, int mincap) { int nc, i; void* p; if (mincap < array->caps) { return 1; } nc = mincap; if (nc < array->caps + array->delta) { nc = array->caps + array->delta; } p = (xzarray_item_t*)realloc(array->data, nc * sizeof(xzarray_item_t)); if (p == NULL) { return -ENOMEM; } array->data = p; for (i = array->caps; i < nc; i++) { array->data[i].inuse = 0; array->data[i].data = NULL; } /* this will make we can get next free * location quickly */ if (array->data[array->pos].inuse) { array->pos = array->caps; } array->caps = nc; return 1; } static int xzarray_store(meta_obj_t* obj, void* data) { xzarray_t* a = RTTI_OBJ_TO_DATA(xzarray_t, obj); xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(obj); int rc = 0; rc = xzarray_ensure_items(a, a->count + 1); if (rc >= 0) { int idx, i; rc = -ENOMEM; idx = a->pos; for (i = 0; i < a->caps; i++) { if (a->data[idx].inuse == 0) { a->data[idx].inuse = 1; a->data[idx].data = data; a->count++; rc = idx; break; } idx++; if (idx >= a->caps) { idx = 0; } } if (rc >= 0) { a->pos = (rc + 1) % a->caps; } } return rc; } static int xzarray_get_vec(meta_obj_t* obj, int count, int* idxs, void** data) { xzarray_t* a = RTTI_OBJ_TO_DATA(xzarray_t, obj); xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(obj); int i; int rc = 0; if ((count <= 0) || (idxs == NULL) || (data == NULL)) { return -EINVAL; } for (i = 0; i < count; i++) { int idx = idxs[i]; if ((idx >= a->caps) || (a->data[idx].inuse == 0)) { rc = -ENOENT; break; } } if (rc == 0) { for (i = 0; i < count; i++) { int idx = idxs[i]; data[i] = a->data[idx].data; } } return rc; } static int xzarray_get(meta_obj_t* obj, int idx, void** data) { int idxs[] = { idx }; return xzarray_get_vec(obj, 1, (int*)&idxs[0], data); } static int xzarray_put_vec(meta_obj_t* obj, int count, int* idxs, void** data) { xzarray_t* a = RTTI_OBJ_TO_DATA(xzarray_t, obj); xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(obj); int i, rc, maxid; if ((count < 1) || (idxs == NULL) || (data == NULL)) { return -EINVAL; } maxid = 0; rc = 0; for (i = 0; i < count; i++) { if (idxs[i] < 0) { rc = -EINVAL; break; } if (maxid < idxs[i]) { maxid = idxs[i]; } } if (rc >= 0) { rc = xzarray_ensure_items(a, maxid + 1); } if (rc >= 0) { for (i = 0; i < count; i++) { int idx = idxs[i]; if (a->data[idx].inuse == 1) { if (a->killer != NULL) { a->killer(a->data[idx].data); } } a->data[idx].data = data[i]; a->data[idx].inuse = 1; } } return rc; } static int xzarray_put(meta_obj_t* obj, int idx, void* data) { int idxs[] = { idx }; void* datas[] = { data }; return xzarray_put_vec(obj, 1, &(idxs[0]), &(datas[0])); } static int xzarray_clear(meta_obj_t* obj, int idx) { xzarray_t* a = RTTI_OBJ_TO_DATA(xzarray_t, obj); xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(obj); int rc = -EINVAL; if (idx < a->caps) { rc = 0; if (a->data[idx].inuse) { if (a->killer != NULL) { a->killer(a->data[idx].data); } } a->data[idx].inuse = 0; a->data[idx].data = NULL; a->pos = idx; /* we can find the available idx next time */ } return rc; } static int xzarray_make_iter(iterator_t* iter, va_list ap) { xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(iter->obj); iter->data = (void*)(long)0; return RTTI_ITER_OK; } static int xzarray_iter_next(iterator_t* iter, void** data) { xzarray_t* a = RTTI_OBJ_TO_DATA(xzarray_t, iter->obj); int i; for (i = (int)(long)iter->data; i < a->caps; i++) { if (a->data[i].inuse) { *data = a->data[i].data; iter->data = (void*)(long)(i + 1); return RTTI_ITER_OK; } } return RTTI_ITER_NO_DATA; } static int xzarray_iter_reset(iterator_t* iter) { iter->data = (void*)(long)0; return RTTI_ITER_OK; } static int xzarray_lock(meta_obj_t* obj, uint64_t option) { xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(obj); return mylock_lock(&(priv->lock)); } static void xzarray_unlock(meta_obj_t* obj) { xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(obj); mylock_unlock(&(priv->lock)); return; } static void xzarray_iter_destroy(iterator_t* iter) { xzarray_private_t* priv = (xzarray_private_t*)RTTI_OBJ_TO_PRIV(iter->obj); return; } typeinfo_t xzarray_type = { .name = "xzarray", .privateSize = sizeof(xzarray_private_t), .dataSize = (datasize_fn_t)xzarray_datasize, .init = (obj_init_fn_t)xzarray_init, .destroy = (obj_destroy_fn_t)xzarray_destroy, .interfaces = { .varray = &(intf_varray_t) { .vstore = (vstore_fn_t)xzarray_store, .vget = (vget_fn_t)xzarray_get, .vget_vec = (vget_vec_fn_t)xzarray_get_vec, .vput = (vput_fn_t)xzarray_put, .vput_vec = (vput_vec_fn_t)xzarray_put_vec, .vclear = (vclear_fn_t)xzarray_clear }, .iter = &(intf_iterator_t) { .make = (iter_make_fn_t)xzarray_make_iter, .next = (iter_next_fn_t)xzarray_iter_next, .reset = (iter_reset_fn_t)xzarray_iter_reset, .destroy = (iter_destroy_fn_t)xzarray_iter_destroy }, .lock = &(intf_lock_t) { .lock = (lock_fn_t)xzarray_lock, .unlock = (unlock_fn_t)xzarray_unlock } } };