#include #include #include #include #include "kv.h" #include "utils.h" typedef struct kvent_ kvent_t; struct kvent_ { kvent_t* next; void* key; void* value; }; typedef struct { uint32_t nslots; destroy_fn_t val_killer; kvent_t** slots; } kvtab_t; static size_t kvtab_datasize(va_list ap) { size_t sz = sizeof(kvtab_t); return sz; } static int kvtab_init(meta_obj_t* obj, va_list ap) { kvtab_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_t, obj); uint32_t nslots = va_arg(ap, uint32_t); destroy_fn_t killer = va_arg(ap, destroy_fn_t); if (nslots <= 1) { return -EINVAL; } kvtab->slots = (kvent_t**)calloc(nslots, sizeof(*(kvtab->slots))); if (kvtab->slots == NULL) { return -ENOMEM; } kvtab->nslots = nslots; kvtab->val_killer = killer; return 1; } static void kvtab_int64_destroy(meta_obj_t* obj) { kvtab_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_t, obj); int i; for (i = 0; i < kvtab->nslots; i++) { kvent_t* e = NULL; while ((e = kvtab->slots[i]) != NULL) { kvtab->slots[i] = e->next; e->next = NULL; if (kvtab->val_killer != NULL) { kvtab->val_killer(e->value); } FREEUP(e); } } FREEUP(kvtab->slots); } static kvent_t* kvtab_int64_get(kvtab_t* t, uint64_t key) { uint32_t hc; kvent_t* e = NULL; hc = hash_block((char*)&key, sizeof(key)) % t->nslots; e = t->slots[hc]; while (e != NULL) { if (((uint64_t)(long)e->key) == key) { break; } e = e->next; } return e; } static int kvtab_int64_add(meta_obj_t* obj, void* key, void* value) { kvtab_t* t = RTTI_OBJ_TO_DATA(kvtab_t, obj); kvent_t* e = NULL; uint32_t hc; uint64_t keyint; e = kvtab_int64_get(t, (uint64_t)(long)key); if (e != NULL) { return -EEXIST; } e = (kvent_t*)calloc(1, sizeof(*e)); if (e == NULL) { return -ENOMEM; } e->key = key; e->value = value; keyint = (uint64_t)(long)key; hc = hash_block((char*)&keyint, sizeof(keyint)) % t->nslots; e->next = t->slots[hc]; t->slots[hc] = e; return 1; } static int kvtab_int64_del(meta_obj_t* obj, void* key) { uint64_t keyint = (uint64_t)(long)key; kvtab_t* t = RTTI_OBJ_TO_DATA(kvtab_t, obj); kvent_t** e = NULL; uint32_t hc; hc = hash_block((char*)&keyint, sizeof(keyint)) % t->nslots; e = &(t->slots[hc]); while ((*e) != NULL) { if ((uint64_t)(long)(*e)->key == keyint) { kvent_t* e1 = *e; *e = e1->next; if (t->val_killer != NULL) { t->val_killer(e1->value); } FREEUP(e1); return 1; } e = &((*e)->next); } return 0; } static int kvtab_int64_find(meta_obj_t* obj, void* key, void** value) { uint64_t keyint = (uint64_t)(long)key; kvtab_t* t = RTTI_OBJ_TO_DATA(kvtab_t, obj); kvent_t* e = NULL; if (value == NULL) { return -EINVAL; } e = kvtab_int64_get(t, keyint); if (e == NULL) { return -ENOENT; } *value = e->value; return 1; } static void kvtab_string_destroy(meta_obj_t* obj) { kvtab_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_t, obj); int i; for (i = 0; i < kvtab->nslots; i++) { kvent_t* e = NULL; while ((e = kvtab->slots[i]) != NULL) { kvtab->slots[i] = e->next; e->next = NULL; FREEUP(e->key); if (kvtab->val_killer != NULL) { kvtab->val_killer(e->value); } FREEUP(e); } } FREEUP(kvtab->slots); } static kvent_t* kvtab_string_get(kvtab_t* t, char* key) { uint32_t hc; kvent_t* e = NULL; hc = hash_string(key) % t->nslots; e = t->slots[hc]; while (e != NULL) { if (strcmp((char*)e->key, key) == 0) { break; } e = e->next; } return e; } static int kvtab_string_add(meta_obj_t* obj, void* key, void* value) { kvtab_t* t = RTTI_OBJ_TO_DATA(kvtab_t, obj); kvent_t* e = NULL; uint32_t hc; e = kvtab_string_get(t, (char*)key); if (e != NULL) { return -EEXIST; } e = (kvent_t*)calloc(1, sizeof(*e)); if (e == NULL) { return -ENOMEM; } e->key = strdup((char*)key); if (e->key == NULL) { FREEUP(e); return -ENOMEM; } e->value = value; hc = hash_string((char*)key) % t->nslots; e->next = t->slots[hc]; t->slots[hc] = e; return 1; } static int kvtab_string_del(meta_obj_t* obj, void* key) { kvtab_t* t = RTTI_OBJ_TO_DATA(kvtab_t, obj); kvent_t** e = NULL; uint32_t hc; hc = hash_string((char*)key) % t->nslots; e = &(t->slots[hc]); while ((*e) != NULL) { if (strcmp((char*)(*e)->key, (char*)key) == 0) { kvent_t* e1 = *e; *e = e1->next; FREEUP(e1->key); if (t->val_killer != NULL) { t->val_killer(e1->value); } FREEUP(e1); return 1; } e = &((*e)->next); } return 0; } static int kvtab_string_find(meta_obj_t* obj, void* key, void** value) { kvtab_t* t = RTTI_OBJ_TO_DATA(kvtab_t, obj); kvent_t* e = NULL; if (value == NULL) { return -EINVAL; } e = kvtab_string_get(t, (char*)key); if (e == NULL) { return -ENOENT; } *value = e->value; return 1; } typeinfo_t kvtab_int64_type = { .name = "kvtab_int", .privateSize = 0, .dataSize = (datasize_fn_t)kvtab_datasize, .init = (obj_init_fn_t)kvtab_init, .destroy = (obj_destroy_fn_t)kvtab_int64_destroy, .interfaces = { .kv = &(intf_kv_t) { .add_key = (key_add_fn_t)kvtab_int64_add, .del_key = (key_del_fn_t)kvtab_int64_del, .find_key = (key_find_fn_t)kvtab_int64_find } } }; typeinfo_t kvtab_string_type = { .name = "kvtab_int", .privateSize = 0, .dataSize = (datasize_fn_t)kvtab_datasize, .init = (obj_init_fn_t)kvtab_init, .destroy = (obj_destroy_fn_t)kvtab_string_destroy, .interfaces = { .kv = &(intf_kv_t) { .add_key = (key_add_fn_t)kvtab_string_add, .del_key = (key_del_fn_t)kvtab_string_del, .find_key = (key_find_fn_t)kvtab_string_find } } }; typedef struct { uint32_t nslots; size_t keylen; destroy_fn_t val_killer; comp_fn_t cmp; kvent_t** slots; } kvtab_generic_t; static size_t kvtab_generic_datasize(va_list ap) { size_t sz = sizeof(kvtab_generic_t); return sz; } static int kvtab_generic_init(meta_obj_t* obj, va_list ap) { uint32_t nslots = va_arg(ap, uint32_t); destroy_fn_t killer = va_arg(ap, destroy_fn_t); size_t keylen = va_arg(ap, size_t); comp_fn_t cmp = va_arg(ap, comp_fn_t); kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); if (nslots <= 1) { return -EINVAL; } kvtab->slots = (kvent_t**)calloc(nslots, sizeof(*(kvtab->slots))); if (kvtab->slots == NULL) { return -EINVAL; } kvtab->nslots = nslots; kvtab->val_killer = killer; kvtab->cmp = cmp; kvtab->keylen = keylen; return 1; } static void kvtab_generic_destroy(meta_obj_t* obj) { kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); int i; for (i = 0; i < kvtab->nslots; i++) { kvent_t* e = NULL; while ((e = kvtab->slots[i]) != NULL) { kvtab->slots[i] = e->next; e->next = NULL; FREEUP(e->key); if (kvtab->val_killer != NULL) { kvtab->val_killer(e->value); } FREEUP(e); } } FREEUP(kvtab->slots); return; } static kvent_t* kvtab_generic_get(kvtab_generic_t* kvtab, void* key) { uint32_t hc; kvent_t* e = NULL; hc = hash_block((char*)key, kvtab->keylen) % kvtab->nslots; e = kvtab->slots[hc]; while (e != NULL) { if (kvtab->cmp(e->key, key, kvtab->keylen) == 0) { break; } e = e->next; } return e; } static int kvtab_generic_add(meta_obj_t* obj, void* key, void* value) { kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); kvent_t* e = NULL; uint32_t hc; e = kvtab_generic_get(kvtab, key); if (e != NULL) { return -EEXIST; } e = (kvent_t*)calloc(1, sizeof(*e)); if (e == NULL) { return -ENOMEM; } e->key = (void*)calloc(1, kvtab->keylen); if (e->key == NULL) { FREEUP(e); return -ENOMEM; } memcpy(e->key, key, kvtab->keylen); e->value = value; hc = hash_block((char*)key, kvtab->keylen) % kvtab->nslots; e->next = kvtab->slots[hc]; kvtab->slots[hc] = e; return 1; } static int kvtab_generic_del(meta_obj_t* obj, void* key) { kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); kvent_t** e = NULL; uint32_t hc; hc = hash_block((char*)key, kvtab->keylen) % kvtab->nslots; e = &(kvtab->slots[hc]); while ((*e) != NULL) { if (kvtab->cmp((*e)->key, key, kvtab->keylen) == 0) { kvent_t* e1 = *e; *e = e1->next; FREEUP(e1->key); if (kvtab->val_killer != NULL) { kvtab->val_killer(e1->value); } FREEUP(e1); return 1; } e = &((*e)->next); } return 0; } static int kvtab_generic_find(meta_obj_t* obj, void* key, void** value) { kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); kvent_t* e = NULL; if (value == NULL) { return -EINVAL; } e = kvtab_generic_get(kvtab, key); if (e == NULL) { return -ENOENT; } *value = e->value; return 1; } typeinfo_t kvtab_generic_type = { .name = "kvtab_generic", .privateSize = 0, .dataSize = (datasize_fn_t)kvtab_generic_datasize, .init = (obj_init_fn_t)kvtab_generic_init, .destroy = (obj_destroy_fn_t)kvtab_generic_destroy, .interfaces = { .kv = &(intf_kv_t) { .add_key = (key_add_fn_t)kvtab_generic_add, .del_key = (key_del_fn_t)kvtab_generic_del, .find_key = (key_find_fn_t)kvtab_generic_find } } }; int key_cmp_default(void* k1, void* k2, size_t len) { return memcmp(k1, k2, len); }