added qse_raddic_addvendor(), qse_raddic_findvendorbyvalue(), qse_raddic_findvendorbyname()

This commit is contained in:
2017-12-08 08:12:24 +00:00
parent 5db7ddc770
commit 4266d8026c
18 changed files with 565 additions and 634 deletions

View File

@ -25,7 +25,7 @@
*/
/*
* hash.c Non-thread-safe split-ordered hash table.
* hash.c Non-thread-safe split-ordered hash table.
*
* The weird "reverse" function is based on an idea from
* "Split-Ordered Lists - Lock-free Resizable Hash Tables", with
@ -58,6 +58,7 @@
#include <qse/cmn/htl.h>
#include <qse/cmn/chr.h>
#include "mem-prv.h"
/*
@ -176,20 +177,19 @@ static qse_uint32_t parent_of (qse_uint32_t key)
}
static qse_htl_node_t *list_find (qse_htl_t* ht, qse_htl_node_t* head, qse_uint32_t reversed, const void* data)
static qse_htl_node_t* __list_find (qse_htl_t* ht, qse_htl_node_t* head, qse_uint32_t reversed, const void* data, qse_htl_comper_t comper)
{
qse_htl_node_t *cur;
if (!/*ht->*/comper) return QSE_NULL;
for (cur = head; cur != &ht->null; cur = cur->next)
{
if (cur->reversed == reversed)
{
if (ht->comper)
{
int cmp = ht->comper(ht, data, cur->data);
if (cmp > 0) break;
if (cmp < 0) continue;
}
int cmp = /*ht->*/comper(ht, data, cur->data);
if (cmp > 0) break;
if (cmp < 0) continue;
return cur;
}
if (cur->reversed > reversed) break;
@ -199,6 +199,11 @@ static qse_htl_node_t *list_find (qse_htl_t* ht, qse_htl_node_t* head, qse_uint3
}
QSE_INLINE static qse_htl_node_t *list_find (qse_htl_t* ht, qse_htl_node_t* head, qse_uint32_t reversed, const void* data)
{
return __list_find (ht, head, reversed, data, ht->comper);
}
/*
* Inserts a new entry into the list, in order.
*/
@ -254,7 +259,7 @@ static int list_delete (qse_htl_t* ht, qse_htl_node_t** head, qse_htl_node_t* no
/* ------------------------------------------------------------------------- */
static QSE_INLINE_ALWAYS qse_size_t default_hasher (qse_htl_t* htl, const void* data)
static QSE_INLINE_ALWAYS qse_uint32_t default_hasher (qse_htl_t* htl, const void* data)
{
#if 0
qse_size_t h = 5381;
@ -263,7 +268,7 @@ static QSE_INLINE_ALWAYS qse_size_t default_hasher (qse_htl_t* htl, const void*
while (p < bound) h = ((h << 5) + h) + *p++;
return h ;
#else
return qse_genhash (data, htl->keysize);
return qse_genhash32 (data, htl->keysize);
#endif
}
@ -426,7 +431,7 @@ static void fixup (qse_htl_t *ht, qse_uint32_t entry)
/*
* Grow the hash table.
*/
static void grow (qse_htl_t *ht)
static void grow (qse_htl_t*ht)
{
qse_htl_node_t **buckets;
@ -443,7 +448,7 @@ static void grow (qse_htl_t *ht)
ht->mask = ht->num_buckets - 1;
}
qse_htl_node_t *qse_htl_search (qse_htl_t* ht, void* data)
qse_htl_node_t *qse_htl_search (qse_htl_t* ht, const void* data)
{
qse_uint32_t key;
qse_uint32_t entry;
@ -457,6 +462,20 @@ qse_htl_node_t *qse_htl_search (qse_htl_t* ht, void* data)
return list_find(ht, ht->buckets[entry], reversed, data);
}
qse_htl_node_t *qse_htl_heterosearch (qse_htl_t* ht, const void* data, qse_htl_hasher_t hasher, qse_htl_comper_t comper)
{
qse_uint32_t key;
qse_uint32_t entry;
qse_uint32_t reversed;
key = /*ht->*/hasher(ht, data);
entry = key & ht->mask;
reversed = reverse(key);
if (!ht->buckets[entry]) fixup(ht, entry);
return __list_find(ht, ht->buckets[entry], reversed, data, comper);
}
/*
* Insert data.
*/
@ -564,7 +583,7 @@ qse_htl_node_t* qse_htl_ensert (qse_htl_t* ht, void* data)
qse_htl_node_t *node;
node = qse_htl_search(ht, data);
if (!node) return qse_htl_insert(ht, data);
if (!node) node = qse_htl_insert(ht, data);
return node;
}
@ -754,7 +773,7 @@ int qse_htl_info(qse_htl_t *ht)
/*
* Continue hashing data.
*/
QSE_INLINE qse_uint32_t qse_genhash_update (const void* data, qse_size_t size, qse_uint32_t hash)
QSE_INLINE qse_uint32_t qse_genhash32_update (const void* data, qse_size_t size, qse_uint32_t hash)
{
const qse_uint8_t *p = data;
const qse_uint8_t *q = p + size;
@ -785,15 +804,15 @@ QSE_INLINE qse_uint32_t qse_genhash_update (const void* data, qse_size_t size, q
return hash;
}
qse_uint32_t qse_genhash (const void *data, qse_size_t size)
qse_uint32_t qse_genhash32 (const void *data, qse_size_t size)
{
return qse_genhash_update (data, size, FNV_MAGIC_INIT);
return qse_genhash32_update (data, size, FNV_MAGIC_INIT);
}
/*
* Hash a C string, so we loop over it once.
*/
qse_uint32_t qse_mbshash (const qse_mchar_t* p)
qse_uint32_t qse_mbshash32 (const qse_mchar_t* p)
{
qse_uint32_t hash = FNV_MAGIC_INIT;
@ -806,25 +825,58 @@ qse_uint32_t qse_mbshash (const qse_mchar_t* p)
return hash;
}
qse_uint32_t qse_wcshash (const qse_wchar_t* p)
qse_uint32_t qse_wcshash32 (const qse_wchar_t* p)
{
qse_uint32_t hash = FNV_MAGIC_INIT;
while (*p)
{
#if (QSE_SIZEOF_WCHAR_T <= QSE_SIZEOF_UINT32_T)
#if (QSE_SIZEOF_WCHAR_T <= QSE_SIZEOF_UINT32_T)
hash ^= (qse_uint32_t)(*p);
hash *= FNV_MAGIC_PRIME;
#else
#else
hash = qse_genhash_update (*p, QSE_SIZEOF(*p), hash);
#endif
#endif
p++;
}
return hash;
}
qse_uint32_t qse_mbscasehash32 (const qse_mchar_t* p)
{
qse_uint32_t hash = FNV_MAGIC_INIT;
while (*p)
{
qse_mchar_t mc = *p++;
mc = QSE_TOMLOWER(mc);
hash ^= (qse_uint32_t)mc;
hash *= FNV_MAGIC_PRIME;
}
return hash;
}
qse_uint32_t qse_wcscasehash32 (const qse_wchar_t* p)
{
qse_uint32_t hash = FNV_MAGIC_INIT;
while (*p)
{
qse_wchar_t wc = *p++;
wc = QSE_TOWLOWER(wc);
#if (QSE_SIZEOF_WCHAR_T <= QSE_SIZEOF_UINT32_T)
hash ^= (qse_uint32_t)(wc);
hash *= FNV_MAGIC_PRIME;
#else
hash = qse_genhash_update (&wc, QSE_SIZEOF(wc), hash);
#endif
}
return hash;
}
#if 0
/*
@ -833,7 +885,7 @@ qse_uint32_t qse_wcshash (const qse_wchar_t* p)
*
* If you need a non-power-of-two hash, cope.
*/
qse_uint32_t qse_foldhash (qse_uint32_t hash, int bits)
qse_uint32_t qse_foldhash32 (qse_uint32_t hash, int bits)
{
int count;
qse_uint32_t result;

View File

@ -47,7 +47,7 @@
*/
#include <qse/rad/raddic.h>
#include <qse/cmn/rbt.h>
#include <qse/cmn/htl.h>
#include <qse/cmn/str.h>
#include "../cmn/mem-prv.h"
#include <qse/si/sio.h>
@ -56,12 +56,12 @@ struct qse_raddic_t
{
qse_mmgr_t* mmgr;
qse_rbt_t vendors_byname;
qse_rbt_t vendors_byvalue;
qse_rbt_t attributes_byname;
qse_rbt_t attributes_byvalue;
qse_rbt_t values_byvalue;
qse_rbt_t values_byname;
qse_htl_t vendors_byname;
qse_htl_t vendors_byvalue;
qse_htl_t attributes_byname;
qse_htl_t attributes_byvalue;
qse_htl_t values_byvalue;
qse_htl_t values_byname;
qse_raddic_attr_t *last_attr;
};
@ -94,82 +94,78 @@ static const name_id_t type_table[] =
{ QSE_NULL, 0 }
};
static int comp_xxx (const qse_rbt_t* rbt, const void* kptr, qse_size_t klen, const void* vptr, qse_size_t vlen)
static qse_uint32_t dict_vendor_name_hash (qse_htl_t* htl, const void *data)
{
return 0;
return qse_strcasehash32(((const qse_raddic_vendor_t*)data)->name);
}
static qse_rbt_style_t vendors_byname_style =
static int dict_vendor_name_cmp (qse_htl_t* htl, const void* one, const void* two)
{
{
QSE_RBT_COPIER_INLINE,
QSE_RBT_COPIER_DEFAULT
},
{
QSE_RBT_FREEER_DEFAULT,
QSE_RBT_FREEER_DEFAULT
},
comp_xxx,
QSE_RBT_KEEPER_DEFAULT,
};
const qse_raddic_vendor_t* a = one;
const qse_raddic_vendor_t* b = two;
return qse_strcasecmp(a->name, b->name);
}
static qse_rbt_style_t vendors_byvalue_style =
static void dict_vendor_name_free (qse_htl_t* htl, void* data)
{
{
QSE_RBT_COPIER_INLINE,
QSE_RBT_COPIER_DEFAULT
},
{
QSE_RBT_FREEER_DEFAULT,
QSE_RBT_FREEER_DEFAULT
},
QSE_RBT_COMPER_DEFAULT,
QSE_RBT_KEEPER_DEFAULT,
};
QSE_MMGR_FREE (htl->mmgr, data);
}
/*
static qse_rbt_style_t attr_by_name_style =
static qse_uint32_t dict_vendor_name_hetero_hash (qse_htl_t* htl, const void* one)
{
{
QSE_RBT_COPIER_INLINE,
QSE_RBT_COPIER_DEFAULT
},
{
QSE_RBT_FREEER_DEFAULT,
QSE_RBT_FREEER_DEFAULT
},
QSE_RBT_COMPER_DEFAULT,
QSE_RBT_KEEPER_DEFAULT,
QSE_RBT_SIZER_DEFAULT,
QSE_RBT_HASHER_DEFAULT
};
*/
return qse_strcasehash32((const qse_char_t*)one);
}
static int dict_vendor_name_hetero_cmp (qse_htl_t* htl, const void* one, const void* two)
{
const qse_raddic_vendor_t* b = two;
return qse_strcasecmp((const qse_char_t*)one, b->name);
}
static qse_uint32_t dict_vendor_value_hash (qse_htl_t* htl, const void* data)
{
const qse_raddic_vendor_t* v = (const qse_raddic_vendor_t*)data;
return qse_genhash32(&v->vendorpec, QSE_SIZEOF(v->vendorpec));
}
static int dict_vendor_value_cmp (qse_htl_t* htl, const void* one, const void* two)
{
const qse_raddic_vendor_t *a = one;
const qse_raddic_vendor_t *b = two;
return a->vendorpec - b->vendorpec;
}
int qse_raddic_init (qse_raddic_t* dic, qse_mmgr_t* mmgr)
{
QSE_MEMSET (dic, 0, QSE_SIZEOF(*dic));
dic->mmgr = mmgr;
qse_rbt_init (&dic->vendors_byname, mmgr, 1, 1);
qse_rbt_init (&dic->vendors_byvalue, mmgr, 1, 1);
qse_rbt_init (&dic->attributes_byname, mmgr, 1, 1);
qse_rbt_init (&dic->attributes_byvalue, mmgr, 1, 1);
qse_rbt_init (&dic->values_byname, mmgr, 1, 1);
qse_rbt_init (&dic->values_byvalue, mmgr, 1, 1);
qse_htl_init (&dic->vendors_byname, mmgr, 1);
qse_htl_init (&dic->vendors_byvalue, mmgr, 1);
qse_htl_init (&dic->attributes_byname, mmgr, 1);
qse_htl_init (&dic->attributes_byvalue, mmgr, 1);
qse_htl_init (&dic->values_byname, mmgr, 1);
qse_htl_init (&dic->values_byvalue, mmgr, 1);
qse_htl_sethasher (&dic->vendors_byname, dict_vendor_name_hash);
qse_htl_setcomper (&dic->vendors_byname, dict_vendor_name_cmp);
qse_htl_setfreeer (&dic->vendors_byname, dict_vendor_name_free);
qse_htl_sethasher (&dic->vendors_byvalue, dict_vendor_value_hash);
qse_htl_setcomper (&dic->vendors_byvalue, dict_vendor_value_cmp);
/* no freeer for dic->vendors_byvalue */
qse_rbt_setstyle (&dic->vendors_byname, &vendors_byname_style);
qse_rbt_setstyle (&dic->vendors_byvalue, &vendors_byvalue_style);
return 0;
}
void qse_raddic_fini (qse_raddic_t* dic)
{
qse_rbt_fini (&dic->vendors_byname);
qse_rbt_fini (&dic->vendors_byvalue);
qse_rbt_fini (&dic->attributes_byname);
qse_rbt_fini (&dic->attributes_byvalue);
qse_rbt_fini (&dic->values_byvalue);
qse_rbt_fini (&dic->values_byname);
qse_htl_fini (&dic->vendors_byname);
qse_htl_fini (&dic->vendors_byvalue);
qse_htl_fini (&dic->attributes_byname);
qse_htl_fini (&dic->attributes_byvalue);
qse_htl_fini (&dic->values_byvalue);
qse_htl_fini (&dic->values_byname);
}
qse_raddic_t* qse_raddic_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
@ -194,77 +190,66 @@ void qse_raddic_close (qse_raddic_t* dic)
{
qse_raddic_fini (dic);
QSE_MMGR_FREE (dic->mmgr, dic);
}
qse_raddic_vendor_t* qse_raddic_findvendorbyname (qse_raddic_t* dic, const qse_char_t* name)
{
qse_htl_node_t* np;
np = qse_htl_heterosearch (&dic->vendors_byname, name, dict_vendor_name_hetero_hash, dict_vendor_name_hetero_cmp);
if (!np) return QSE_NULL;
return (qse_raddic_vendor_t*)np->data;
}
#if 0
int qse_raddic_addvendor (qse_raddic_t* dic, const qse_char_t *name, int value)
/*
* Return the vendor struct based on the PEC.
*/
qse_raddic_vendor_t* qse_raddic_findvendorbyvalue (qse_raddic_t* dic, int vendorpec)
{
qse_htl_node_t* np;
qse_raddic_vendor_t dv;
dv.vendorpec = vendorpec;
np = qse_htl_search (&dic->vendors_byvalue, &dv);
if (!np) return QSE_NULL;
return (qse_raddic_vendor_t*)np->data;
}
qse_raddic_vendor_t* qse_raddic_addvendor (qse_raddic_t* dic, const qse_char_t* name, int value)
{
qse_size_t length;
qse_raddic_vendor_t* dv;
qse_htl_node_t* np;
if (value >= 65535)
{
//fr_strerror_printf("dict_addvendor: Cannot handle vendor ID larger than 65535");
return -1;
}
if (value >= 65535) return QSE_NULL;
/*if ((length = qse_strlen(name)) >= qse_raddic_vendor_t_MAX_NAME_LEN) {
fr_strerror_printf("dict_addvendor: vendor name too long");
return -1;
}*/
if ((dv = QSE_MMGR_ALLOC(dic->mmgr, QSE_SIZEOF(*dv) + (length * QSE_SIZEOF(*name)))) == QSE_NULL)
{
// fr_strerror_printf("dict_addvendor: out of memory");
return -1;
}
length = qse_strlen(name);
/* no +1 for the terminating null because dv->name is char[1] */
dv = QSE_MMGR_ALLOC(dic->mmgr, QSE_SIZEOF(*dv) + (length * QSE_SIZEOF(*name)));
if (dv == QSE_NULL) return QSE_NULL;
qse_strcpy(dv->name, name);
dv->vendorpec = value;
dv->vendorpec = value;
dv->type = dv->length = 1; /* defaults */
qse_rbt_insert (dic->vendors_byname,
if (!fr_hash_table_insert(vendors_byname, dv))
/* return an existing item or insert a new item */
np = qse_htl_ensert(&dic->vendors_byname, dv);
if (!np || np->data != dv)
{
qse_raddic_vendor_t *old_dv;
old_dv = fr_hash_table_finddata(vendors_byname, dv);
if (!old_dv) {
fr_strerror_printf("dict_addvendor: Failed inserting vendor name %s", name);
return -1;
}
if (old_dv->vendorpec != dv->vendorpec) {
fr_strerror_printf("dict_addvendor: Duplicate vendor name %s", name);
return -1;
}
/*
* Already inserted. Discard the duplicate entry.
*/
fr_pool_free(dv);
return 0;
/* insertion failure or existing item found */
QSE_MMGR_FREE (dic->mmgr, dv);
return QSE_NULL;
}
/*
* Insert the SAME pointer (not free'd when this table is
* deleted), into another table.
*
* We want this behaviour because we want OLD names for
* the attributes to be read from the configuration
* files, but when we're printing them, (and looking up
* by value) we want to use the NEW name.
*/
if (!fr_hash_table_replace(vendors_byvalue, dv)) {
fr_strerror_printf("dict_addvendor: Failed inserting vendor %s",
name);
return -1;
/* update indexing by value */
if (!qse_htl_upsert(&dic->vendors_byvalue, dv))
{
qse_htl_delete (&dic->vendors_byname, dv);
return QSE_NULL;
}
return 0;
return dv;
}
#endif
#if 0 // XXX
@ -357,33 +342,6 @@ qse_raddic_value_t *dict_valbyname(qse_raddic_t* dic, int attr, const char *name
*
* This is efficient only for small numbers of vendors.
*/
int dict_vendorbyname(const char *name)
{
qse_raddic_vendor_t *dv;
uint32_t buffer[(QSE_SIZEOF(*dv) + qse_raddic_vendor_t_MAX_NAME_LEN + 3)/4];
if (!name) return 0;
dv = (qse_raddic_vendor_t *) buffer;
strlcpy(dv->name, name, qse_raddic_vendor_t_MAX_NAME_LEN + 1);
dv = fr_hash_table_finddata(vendors_byname, dv);
if (!dv) return 0;
return dv->vendorpec;
}
/*
* Return the vendor struct based on the PEC.
*/
qse_raddic_vendor_t *dict_vendorbyvalue(int vendorpec)
{
qse_raddic_vendor_t dv;
dv.vendorpec = vendorpec;
return fr_hash_table_finddata(vendors_byvalue, &dv);
}
/*
* Add a value for an attribute to the dictionary.
@ -1021,32 +979,6 @@ static int dict_attr_value_cmp(const void *one, const void *two)
return a->attr - b->attr;
}
static uint32_t dict_vendor_name_hash(const void *data)
{
return dict_hashname(((const qse_raddic_vendor_t *)data)->name);
}
static int dict_vendor_name_cmp(const void *one, const void *two)
{
const qse_raddic_vendor_t *a = one;
const qse_raddic_vendor_t *b = two;
return qse_mbscasecmp(a->name, b->name);
}
static uint32_t dict_vendor_value_hash(const void *data)
{
return fr_hash(&(((const qse_raddic_vendor_t *)data)->vendorpec),
QSE_SIZEOF(((const qse_raddic_vendor_t *)data)->vendorpec));
}
static int dict_vendor_value_cmp(const void *one, const void *two)
{
const qse_raddic_vendor_t *a = one;
const qse_raddic_vendor_t *b = two;
return a->vendorpec - b->vendorpec;
}
static uint32_t dict_value_name_hash(const void *data)
{
@ -1236,14 +1168,6 @@ static void *fr_pool_alloc(size_t size)
return ptr;
}
static void fr_pool_free(UNUSED void *ptr)
{
/*
* Place-holder for later code.
*/
}
/*
* Free the dictionary_attributes and dictionary_values lists.
*/