myxce/src/lib/kv.c
2026-02-23 11:18:45 +08:00

492 lines
11 KiB
C

#include <errno.h>
#include <rtti.h>
#include <stdint.h>
#include <stdlib.h>
#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);
}