#include #include #include #include #include #include #include "htab.h" #include "kv.h" #include "mylock.h" #include "utils.h" #include "xstring.h" static struct { mylock_t lock; var xstr_table; } xstring_table; typedef struct { atomic_ulong refcount; uint32_t hashcode; size_t len; } xstring_private_t; static typeinfo_t xstring_type; static void xstring_destroy(meta_obj_t*); static void my_xstring_killer(var s) { if (s == NULL) { return; } destroy_(s, (obj_destroy_fn_t)xstring_destroy); } int xstring_table_init(int nslots) { kv_params_t params = { .nslots = nslots, .keyops = &string_key_ops, .datakiller = my_xstring_killer }; if (nslots <= 1) { return -EINVAL; } mylock_init(&(xstring_table.lock)); xstring_table.xstr_table = makeInstance(&kvtab_type, ¶ms); if (xstring_table.xstr_table == NULL) { return -errno; } return 0; } void xstring_table_fini() { destroy(xstring_table.xstr_table); mylock_fini(&(xstring_table.lock)); } static size_t xstring_datasize(va_list ap) { char* src = va_arg(ap, char*); return strlen(src) + 1; } static int xstring_init(meta_obj_t* obj, va_list ap) { char* src = va_arg(ap, char*); char* dest = RTTI_OBJ_TO_DATA(char, obj); xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); if (src == NULL) { src = ""; } strcpy(dest, src); priv->refcount = 1; priv->hashcode = hash_string(src); priv->len = strlen(src); return 1; } static void xstring_destroy(meta_obj_t* obj) { xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); memset(priv, 0x0, sizeof(*priv)); return; } static int xstring_reference(meta_obj_t* obj) { xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); atomic_fetch_add(&(priv->refcount), 1); return 0; } static void xstring_dereference(meta_obj_t* obj) { xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); char* v = RTTI_OBJ_TO_DATA(char, obj); uint64_t count; count = atomic_fetch_sub(&(priv->refcount), 1); if (count == 1) { mylock_lock(&(xstring_table.lock)); key_del(xstring_table.xstr_table, v); mylock_unlock(&(xstring_table.lock)); } return; } static int32_t xstring_hash(meta_obj_t* obj) { xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); return priv->hashcode; } static int64_t xstring_length(meta_obj_t* obj) { xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); return priv->len; } char* makeString(char* s) { var string; int rc; if (s == NULL) { errno = EINVAL; return NULL; } mylock_lock(&(xstring_table.lock)); rc = key_find(xstring_table.xstr_table, (void*)s, (void**)&string); if (rc > 0) { /* add reference */ reference(string); } mylock_unlock(&(xstring_table.lock)); if (rc > 0) { return (char*)string; } string = makeInstance(&xstring_type, s); if (string == NULL) { return NULL; } mylock_lock(&(xstring_table.lock)); rc = key_add(xstring_table.xstr_table, (void*)s, string); mylock_unlock(&(xstring_table.lock)); if (rc < 0) { destroy_(string, (obj_destroy_fn_t)xstring_destroy); string = NULL; errno = -rc; } return (char*)string; } static typeinfo_t xstring_type = { .name = "xstring", .privateSize = sizeof(xstring_private_t), .dataSize = (datasize_fn_t)xstring_datasize, .init = (obj_init_fn_t)xstring_init, .destroy = (obj_destroy_fn_t)NULL, /* to disable destroy() */ .interfaces = { .reference = &(intf_reference_t) { .reference = (reference_fn_t)xstring_reference, .dereference = (dereference_fn_t)xstring_dereference }, .hash = &(intf_hash_t) { .hash = (hash_fn_t)xstring_hash }, .length = &(intf_length_t) { .length = (length_fn_t)xstring_length } } };