forked from lei.chen/myxce
introduce kv
This commit is contained in:
parent
48ea4a0205
commit
15fac3cda1
6 changed files with 504 additions and 4 deletions
8
src/flake.lock
generated
8
src/flake.lock
generated
|
|
@ -117,11 +117,11 @@
|
|||
"xbuild": "xbuild"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1770950940,
|
||||
"narHash": "sha256-pVnwAEaB6s2vIwkktL1xOP0pyV4VcPyfQYoIXKmv6Yk=",
|
||||
"lastModified": 1770966016,
|
||||
"narHash": "sha256-HZEy2nuM2g8anxKidaxv5hbDlV1+4yk18Dzre8fSAHE=",
|
||||
"ref": "master",
|
||||
"rev": "6f6bb5b4e0b706de2358de462a1fc4889f40c7a1",
|
||||
"revCount": 8,
|
||||
"rev": "e5f39839522dcfa7a66dc09a177ba89034659580",
|
||||
"revCount": 10,
|
||||
"type": "git",
|
||||
"url": "ssh://forgejo@gitea.shenrs.eu/rshen/librtti"
|
||||
},
|
||||
|
|
|
|||
12
src/include/kv.h
Normal file
12
src/include/kv.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#if !defined(_KV_H_)
|
||||
|
||||
#define _KV_H_ 1
|
||||
|
||||
#include <rtti.h>
|
||||
|
||||
typedef void (*kv_value_kill_fn_t)(void*);
|
||||
|
||||
extern typeinfo_t kvtab_int64_type;
|
||||
extern typeinfo_t kvtab_string_type;
|
||||
|
||||
#endif
|
||||
312
src/lib/kv.c
Normal file
312
src/lib/kv.c
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
#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;
|
||||
kv_value_kill_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);
|
||||
kv_value_kill_fn_t killer = va_arg(ap, kv_value_kill_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 } } };
|
||||
|
|
@ -83,6 +83,7 @@ libxce_src = [ gen_srcs[0],
|
|||
'helper.c',
|
||||
'resreq.c',
|
||||
'bitset.c',
|
||||
'kv.c',
|
||||
]
|
||||
|
||||
incdir = include_directories('../include')
|
||||
|
|
@ -135,6 +136,7 @@ libxce_test_src = ['testsuite/test.c',
|
|||
'testsuite/test_xvec.c',
|
||||
'testsuite/test_resreq.c',
|
||||
'testsuite/test_bitset.c',
|
||||
'testsuite/test_kv.c',
|
||||
]
|
||||
|
||||
libxce_test_deps = [libxce_deps, librtti_dep, unity_dep, libxce_dep]
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ extern void test_limit(void);
|
|||
extern void test_xvec(void);
|
||||
extern void test_resreq(void);
|
||||
extern void test_bitset(void);
|
||||
extern void test_kv(void);
|
||||
|
||||
void setUp(void) { return; }
|
||||
|
||||
|
|
@ -115,6 +116,7 @@ int main(int argc, char* argv[])
|
|||
TEST(test_xvec);
|
||||
TEST(test_resreq);
|
||||
TEST(test_bitset);
|
||||
TEST(test_kv);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
|
|
|
|||
172
src/lib/testsuite/test_kv.c
Normal file
172
src/lib/testsuite/test_kv.c
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
#include <errno.h>
|
||||
#include <rtti.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unity/unity.h>
|
||||
|
||||
#include "kv.h"
|
||||
|
||||
static void test_kv_int_create()
|
||||
{
|
||||
var tab = makeInstance(&kvtab_int64_type, 31, NULL);
|
||||
|
||||
TEST_ASSERT_TRUE(tab != NULL);
|
||||
|
||||
destroy(tab);
|
||||
}
|
||||
|
||||
static void test_kv_int1()
|
||||
{
|
||||
var tab = makeInstance(&kvtab_int64_type, 31, NULL);
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
TEST_ASSERT_TRUE(tab != NULL);
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
rc = key_add(tab, (void*)(long)i, (void*)(long)(i * i));
|
||||
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
void* v;
|
||||
|
||||
rc = key_find(tab, (void*)(long)i, &v);
|
||||
TEST_ASSERT_TRUE(rc > 0);
|
||||
|
||||
TEST_ASSERT_TRUE((int)(long)v == i * i);
|
||||
}
|
||||
|
||||
for (i = 100; i < 199; i++) {
|
||||
void* v = NULL;
|
||||
|
||||
rc = key_find(tab, (void*)(long)i, &v);
|
||||
|
||||
TEST_ASSERT_TRUE(rc == -ENOENT);
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
void* v;
|
||||
|
||||
rc = key_del(tab, (void*)(long)i);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
rc = key_find(tab, (void*)(long)i, &v);
|
||||
TEST_ASSERT_TRUE(rc == -ENOENT);
|
||||
}
|
||||
destroy(tab);
|
||||
}
|
||||
|
||||
static void my_free(void* p)
|
||||
{
|
||||
if (p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
static void test_kv_int2()
|
||||
{
|
||||
var tab = makeInstance(&kvtab_int64_type, 31, my_free);
|
||||
int i;
|
||||
int rc;
|
||||
char buf[128];
|
||||
|
||||
TEST_ASSERT_TRUE(tab != NULL);
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
char* p = NULL;
|
||||
|
||||
sprintf(buf, "value#%d", i);
|
||||
p = strdup(buf);
|
||||
|
||||
TEST_ASSERT_TRUE(p != NULL);
|
||||
rc = key_add(tab, (void*)(long)i, (void*)p);
|
||||
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
void* v;
|
||||
|
||||
rc = key_find(tab, (void*)(long)i, &v);
|
||||
TEST_ASSERT_TRUE(rc > 0);
|
||||
|
||||
sprintf(buf, "value#%d", i);
|
||||
TEST_ASSERT_TRUE(strcmp(buf, (char*)v) == 0);
|
||||
}
|
||||
|
||||
destroy(tab);
|
||||
}
|
||||
|
||||
static void test_kv_string1()
|
||||
{
|
||||
var tab = makeInstance(&kvtab_string_type, 31, NULL);
|
||||
int i;
|
||||
int rc;
|
||||
char buf[64];
|
||||
|
||||
TEST_ASSERT_TRUE(tab != NULL);
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
sprintf(buf, "key#%d", i);
|
||||
rc = key_add(tab, (void*)buf, (void*)(long)(i * i));
|
||||
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
void* v;
|
||||
|
||||
sprintf(buf, "key#%d", i);
|
||||
rc = key_find(tab, (void*)buf, &v);
|
||||
TEST_ASSERT_TRUE(rc > 0);
|
||||
|
||||
TEST_ASSERT_TRUE((int)(long)v == i * i);
|
||||
}
|
||||
|
||||
for (i = 100; i < 199; i++) {
|
||||
void* v = NULL;
|
||||
|
||||
sprintf(buf, "key#%d", i);
|
||||
rc = key_find(tab, (void*)buf, &v);
|
||||
|
||||
TEST_ASSERT_TRUE(rc == -ENOENT);
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
void* v;
|
||||
|
||||
sprintf(buf, "key#%d", i);
|
||||
rc = key_del(tab, (void*)buf);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
rc = key_find(tab, (void*)buf, &v);
|
||||
TEST_ASSERT_TRUE(rc == -ENOENT);
|
||||
}
|
||||
destroy(tab);
|
||||
}
|
||||
|
||||
static void test_kv_string_create()
|
||||
{
|
||||
var tab = makeInstance(&kvtab_string_type, 31, NULL);
|
||||
|
||||
TEST_ASSERT_TRUE(tab != NULL);
|
||||
|
||||
destroy(tab);
|
||||
}
|
||||
|
||||
void test_kv(void)
|
||||
{
|
||||
printf("\n>> kv test\n\n");
|
||||
|
||||
RUN_TEST(test_kv_int_create);
|
||||
RUN_TEST(test_kv_string_create);
|
||||
RUN_TEST(test_kv_int1);
|
||||
RUN_TEST(test_kv_int2);
|
||||
RUN_TEST(test_kv_string1);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue