added open-addressed hash table
This commit is contained in:
@ -7,7 +7,7 @@ libqsecmn_la_SOURCES = \
|
||||
syscall.h mem.h \
|
||||
mem.c xma.c fma.c chr.c chr_cnv.c rex.c \
|
||||
str_bas.c str_cnv.c str_dyn.c str_utl.c \
|
||||
lda.c htb.c rbt.c sll.c gdl.c dll.c opt.c \
|
||||
lda.c oht.c htb.c rbt.c sll.c gdl.c dll.c opt.c \
|
||||
tio.c tio_get.c tio_put.c \
|
||||
fio.c pio.c sio.c \
|
||||
time.c \
|
||||
|
@ -75,9 +75,9 @@ LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
libqsecmn_la_DEPENDENCIES =
|
||||
am_libqsecmn_la_OBJECTS = mem.lo xma.lo fma.lo chr.lo chr_cnv.lo \
|
||||
rex.lo str_bas.lo str_cnv.lo str_dyn.lo str_utl.lo lda.lo \
|
||||
htb.lo rbt.lo sll.lo gdl.lo dll.lo opt.lo tio.lo tio_get.lo \
|
||||
tio_put.lo fio.lo pio.lo sio.lo time.lo misc.lo assert.lo \
|
||||
main.lo stdio.lo
|
||||
oht.lo htb.lo rbt.lo sll.lo gdl.lo dll.lo opt.lo tio.lo \
|
||||
tio_get.lo tio_put.lo fio.lo pio.lo sio.lo time.lo misc.lo \
|
||||
assert.lo main.lo stdio.lo
|
||||
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
|
||||
libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
@ -264,7 +264,7 @@ libqsecmn_la_SOURCES = \
|
||||
syscall.h mem.h \
|
||||
mem.c xma.c fma.c chr.c chr_cnv.c rex.c \
|
||||
str_bas.c str_cnv.c str_dyn.c str_utl.c \
|
||||
lda.c htb.c rbt.c sll.c gdl.c dll.c opt.c \
|
||||
lda.c oht.c htb.c rbt.c sll.c gdl.c dll.c opt.c \
|
||||
tio.c tio_get.c tio_put.c \
|
||||
fio.c pio.c sio.c \
|
||||
time.c \
|
||||
@ -369,6 +369,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oht.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pio.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rbt.Plo@am__quote@
|
||||
|
322
qse/lib/cmn/oht.c
Normal file
322
qse/lib/cmn/oht.c
Normal file
@ -0,0 +1,322 @@
|
||||
#include <qse/cmn/oht.h>
|
||||
#include "mem.h"
|
||||
|
||||
#define DATA_PTR(oht,index) \
|
||||
((void*)(((qse_byte_t*)(oht)->data) + ((index) * (oht)->scale)))
|
||||
|
||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (oht)
|
||||
|
||||
static QSE_INLINE_ALWAYS qse_size_t default_hasher (
|
||||
qse_oht_t* oht, const void* data)
|
||||
{
|
||||
size_t h = 5381;
|
||||
const qse_byte_t* p = (const qse_byte_t*)data;
|
||||
const qse_byte_t* bound = p + oht->scale;
|
||||
while (p < bound) h = ((h << 5) + h) + *p++;
|
||||
return h ;
|
||||
}
|
||||
|
||||
static QSE_INLINE_ALWAYS int default_comper (
|
||||
qse_oht_t* oht, const void* data1, const void* data2)
|
||||
{
|
||||
return QSE_MEMCMP(data1, data2, oht->scale);
|
||||
}
|
||||
|
||||
static QSE_INLINE_ALWAYS void default_copier (
|
||||
qse_oht_t* oht, void* dst, const void* src)
|
||||
{
|
||||
QSE_MEMCPY (dst, src, oht->scale);
|
||||
}
|
||||
|
||||
#define HASH_DATA(oht,data) \
|
||||
((oht)->hasher? (oht)->hasher ((oht), (data)): \
|
||||
default_hasher (oht, data))
|
||||
|
||||
#define COMP_DATA(oht,d1,d2) \
|
||||
((oht)->comper? (oht)->comper ((oht), (d1), (d2)): \
|
||||
QSE_MEMCMP ((d1), (d2), (oht)->scale))
|
||||
|
||||
#define COPY_DATA(oht,dst,src) \
|
||||
QSE_BLOCK ( \
|
||||
if ((oht)->copier) (oht)->copier ((oht), (dst), (src)); \
|
||||
else QSE_MEMCPY ((dst), (src), (oht)->scale); \
|
||||
)
|
||||
|
||||
qse_oht_t* qse_oht_open (
|
||||
qse_mmgr_t* mmgr, qse_size_t xtnsize,
|
||||
qse_size_t scale, qse_size_t capa, qse_size_t limit)
|
||||
{
|
||||
qse_oht_t* oht;
|
||||
|
||||
if (mmgr == QSE_NULL)
|
||||
{
|
||||
mmgr = QSE_MMGR_GETDFL();
|
||||
|
||||
QSE_ASSERTX (mmgr != QSE_NULL,
|
||||
"Set the memory manager with QSE_MMGR_SETDFL()");
|
||||
|
||||
if (mmgr == QSE_NULL) return QSE_NULL;
|
||||
}
|
||||
|
||||
oht = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_oht_t) + xtnsize);
|
||||
if (oht == QSE_NULL) return QSE_NULL;
|
||||
|
||||
if (qse_oht_init (oht, mmgr, scale, capa, limit) == QSE_NULL)
|
||||
{
|
||||
QSE_MMGR_FREE (mmgr, oht);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
return oht;
|
||||
}
|
||||
|
||||
void qse_oht_close (qse_oht_t* oht)
|
||||
{
|
||||
qse_oht_fini (oht);
|
||||
QSE_MMGR_FREE (oht->mmgr, oht);
|
||||
}
|
||||
|
||||
qse_oht_t* qse_oht_init (
|
||||
qse_oht_t* oht, qse_mmgr_t* mmgr,
|
||||
qse_size_t scale, qse_size_t capa, qse_size_t limit)
|
||||
{
|
||||
qse_size_t i;
|
||||
|
||||
if (scale <= 0) scale = 1;
|
||||
if (capa >= QSE_OHT_INVALID_INDEX - 1) capa = QSE_OHT_INVALID_INDEX - 1;
|
||||
if (limit > capa || limit <= 0) limit = capa;
|
||||
|
||||
QSE_MEMSET (oht, 0, QSE_SIZEOF(*oht));
|
||||
|
||||
oht->mmgr = mmgr;
|
||||
oht->capa.hard = capa;
|
||||
oht->capa.soft = limit;
|
||||
oht->scale = scale;
|
||||
oht->size = 0;
|
||||
|
||||
/*oht->hasher = default_hasher;
|
||||
oht->comper = default_comper;
|
||||
oht->copier = default_copier;*/
|
||||
|
||||
oht->mark = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_oht_mark_t) * capa);
|
||||
if (!oht->mark) return QSE_NULL;
|
||||
|
||||
oht->data = QSE_MMGR_ALLOC (mmgr, scale * capa);
|
||||
if (!oht->data)
|
||||
{
|
||||
QSE_MMGR_FREE (mmgr, oht->mark);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < capa; i++) oht->mark[i] = QSE_OHT_EMPTY;
|
||||
return oht;
|
||||
}
|
||||
|
||||
void qse_oht_fini (qse_oht_t* oht)
|
||||
{
|
||||
QSE_MMGR_FREE (oht->mmgr, oht->mark);
|
||||
QSE_MMGR_FREE (oht->mmgr, oht->data);
|
||||
oht->size = 0;
|
||||
}
|
||||
|
||||
qse_oht_hasher_t qse_oht_gethasher (qse_oht_t* oht)
|
||||
{
|
||||
return oht->hasher? oht->hasher: default_hasher;
|
||||
}
|
||||
|
||||
void qse_oht_sethasher (qse_oht_t* oht, qse_oht_hasher_t hasher)
|
||||
{
|
||||
oht->hasher = hasher;
|
||||
}
|
||||
|
||||
qse_oht_comper_t qse_oht_getcomper (qse_oht_t* oht)
|
||||
{
|
||||
return oht->comper? oht->comper: default_comper;
|
||||
}
|
||||
|
||||
void qse_oht_setcomper (qse_oht_t* oht, qse_oht_comper_t comper)
|
||||
{
|
||||
oht->comper = comper;
|
||||
}
|
||||
|
||||
qse_oht_copier_t qse_oht_getcopier (qse_oht_t* oht)
|
||||
{
|
||||
return oht->copier? oht->copier: default_copier;
|
||||
}
|
||||
|
||||
void qse_oht_setcopier (qse_oht_t* oht, qse_oht_copier_t copier)
|
||||
{
|
||||
oht->copier = copier;
|
||||
}
|
||||
|
||||
static QSE_INLINE qse_size_t search (
|
||||
qse_oht_t* oht, const void* data, qse_size_t hash)
|
||||
{
|
||||
qse_size_t i;
|
||||
|
||||
for (i = 0; i < oht->capa.hard; i++)
|
||||
{
|
||||
qse_size_t index = (hash + i) % oht->capa.hard;
|
||||
if (oht->mark[index] == QSE_OHT_EMPTY) break;
|
||||
if (oht->mark[index] == QSE_OHT_OCCUPIED)
|
||||
{
|
||||
if (COMP_DATA (oht, data, DATA_PTR(oht,index)) == 0)
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return QSE_OHT_INVALID_INDEX;
|
||||
}
|
||||
|
||||
qse_size_t qse_oht_search (qse_oht_t* oht, void* data)
|
||||
{
|
||||
qse_size_t i = search (oht, data, HASH_DATA(oht,data));
|
||||
if (i != QSE_OHT_INVALID_INDEX && data)
|
||||
COPY_DATA (oht, data, DATA_PTR(oht,i));
|
||||
return i;
|
||||
}
|
||||
|
||||
qse_size_t qse_oht_update (qse_oht_t* oht, const void* data)
|
||||
{
|
||||
qse_size_t i = search (oht, data, HASH_DATA(oht,data));
|
||||
if (i != QSE_OHT_INVALID_INDEX)
|
||||
COPY_DATA (oht, DATA_PTR(oht,i), data);
|
||||
return i;
|
||||
}
|
||||
|
||||
qse_size_t qse_oht_upsert (qse_oht_t* oht, const void* data)
|
||||
{
|
||||
qse_size_t i, hash = HASH_DATA (oht, data);
|
||||
|
||||
/* find the existing item */
|
||||
i = search (oht, data, hash);
|
||||
if (i != QSE_OHT_INVALID_INDEX)
|
||||
{
|
||||
COPY_DATA (oht, DATA_PTR(oht,i), data);
|
||||
return i;
|
||||
}
|
||||
|
||||
/* check if there is a free slot to insert data into */
|
||||
if (oht->size >= oht->capa.soft) return QSE_OHT_INVALID_INDEX;
|
||||
|
||||
/* get the unoccupied slot and insert the data into it.
|
||||
* iterate at most 'the number of items (oht->size)' times + 1. */
|
||||
for (i = 0; i <= oht->size; i++)
|
||||
{
|
||||
qse_size_t index = (hash + i) % oht->capa.hard;
|
||||
if (oht->mark[index] != QSE_OHT_OCCUPIED)
|
||||
{
|
||||
oht->mark[index] = QSE_OHT_OCCUPIED;
|
||||
COPY_DATA (oht, DATA_PTR(oht,index), data);
|
||||
oht->size++;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return QSE_OHT_INVALID_INDEX;
|
||||
}
|
||||
|
||||
qse_size_t qse_oht_insert (qse_oht_t* oht, const void* data)
|
||||
{
|
||||
qse_size_t i, hash;
|
||||
|
||||
/* check if there is a free slot to insert data into */
|
||||
if (oht->size >= oht->capa.soft) return QSE_OHT_INVALID_INDEX;
|
||||
|
||||
hash = HASH_DATA (oht, data);
|
||||
|
||||
/* check if the item already exits */
|
||||
i = search (oht, data, hash);
|
||||
if (i != QSE_OHT_INVALID_INDEX) return QSE_OHT_INVALID_INDEX;
|
||||
|
||||
/* get the unoccupied slot and insert the data into it.
|
||||
* iterate at most 'the number of items (oht->size)' times + 1. */
|
||||
for (i = 0; i <= oht->size; i++)
|
||||
{
|
||||
qse_size_t index = (hash + i) % oht->capa.hard;
|
||||
if (oht->mark[index] != QSE_OHT_OCCUPIED)
|
||||
{
|
||||
oht->mark[index] = QSE_OHT_OCCUPIED;
|
||||
COPY_DATA (oht, DATA_PTR(oht,index), data);
|
||||
oht->size++;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return QSE_OHT_INVALID_INDEX;
|
||||
}
|
||||
|
||||
qse_size_t qse_oht_delete (qse_oht_t* oht, const void* data)
|
||||
{
|
||||
#if 0
|
||||
qse_size_t index;
|
||||
|
||||
if (oht->size <= 0) return QSE_OHT_INVALID_INDEX;
|
||||
|
||||
index = search (oht, data, HASH_DATA(oht,data));
|
||||
if (index != QSE_OHT_INVALID_INDEX)
|
||||
{
|
||||
oht->mark[index] = QSE_OHT_DELETED;
|
||||
oht->size--;
|
||||
}
|
||||
|
||||
return index;
|
||||
#endif
|
||||
|
||||
qse_size_t index, i, x, y, z;
|
||||
|
||||
/* check if the oht is empty. if so, do nothing */
|
||||
if (oht->size <= 0) return QSE_OHT_INVALID_INDEX;
|
||||
|
||||
/* check if the item exists. otherwise, do nothing. */
|
||||
index = search (oht, data, HASH_DATA(oht,data));
|
||||
if (index == QSE_OHT_INVALID_INDEX) return QSE_OHT_INVALID_INDEX;
|
||||
|
||||
/* compact the cluster */
|
||||
for (i = 0, x = index, y = index; i < oht->size; i++)
|
||||
{
|
||||
y = (y + 1) % oht->capa.hard;
|
||||
|
||||
/* done if the slot at the current hash index is empty */
|
||||
if (oht->mark[y] == QSE_OHT_EMPTY) break;
|
||||
|
||||
/* get the natural hash index for the data in the slot at
|
||||
* the current hash index */
|
||||
z = HASH_DATA(oht,DATA_PTR(oht,y)) % oht->capa.hard;
|
||||
|
||||
/* move an element if necesary */
|
||||
if ((y > x && (z <= x || z > y)) ||
|
||||
(y < x && (z <= x && z > y)))
|
||||
{
|
||||
COPY_DATA (oht, DATA_PTR(oht,x), DATA_PTR(oht,y));
|
||||
x = y;
|
||||
}
|
||||
}
|
||||
|
||||
oht->mark[x] = QSE_OHT_EMPTY;
|
||||
oht->size--;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void qse_oht_clear (qse_oht_t* oht)
|
||||
{
|
||||
qse_size_t i;
|
||||
for (i = 0; i < oht->capa.hard; i++)
|
||||
oht->mark[i] = QSE_OHT_EMPTY;
|
||||
oht->size = 0;
|
||||
}
|
||||
|
||||
void qse_oht_walk (qse_oht_t* oht, qse_oht_walker_t walker, void* ctx)
|
||||
{
|
||||
qse_size_t i;
|
||||
|
||||
for (i = 0; i < oht->capa.hard; i++)
|
||||
{
|
||||
if (oht->mark[i] == QSE_OHT_OCCUPIED)
|
||||
{
|
||||
if (walker (oht, DATA_PTR(oht,i), ctx) == QSE_OHT_WALK_STOP)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -702,7 +702,7 @@ void qse_xma_free (qse_xma_t* xma, void* b)
|
||||
}
|
||||
}
|
||||
|
||||
void qse_xma_dump (qse_xma_t* xma, int (*printf)(const qse_char_t* fmt,...))
|
||||
void qse_xma_dump (qse_xma_t* xma, qse_xma_dumper_t dumper, void* target)
|
||||
{
|
||||
qse_xma_blk_t* tmp;
|
||||
unsigned long long fsum, asum;
|
||||
@ -710,19 +710,19 @@ void qse_xma_dump (qse_xma_t* xma, int (*printf)(const qse_char_t* fmt,...))
|
||||
unsigned long long isum;
|
||||
#endif
|
||||
|
||||
printf (QSE_T("<XMA DUMP>\n"));
|
||||
dumper (target, QSE_T("<XMA DUMP>\n"));
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
printf (QSE_T("== statistics ==\n"));
|
||||
printf (QSE_T("total = %llu\n"), (unsigned long long)xma->stat.total);
|
||||
printf (QSE_T("alloc = %llu\n"), (unsigned long long)xma->stat.alloc);
|
||||
printf (QSE_T("avail = %llu\n"), (unsigned long long)xma->stat.avail);
|
||||
dumper (target, QSE_T("== statistics ==\n"));
|
||||
dumper (target, QSE_T("total = %llu\n"), (unsigned long long)xma->stat.total);
|
||||
dumper (target, QSE_T("alloc = %llu\n"), (unsigned long long)xma->stat.alloc);
|
||||
dumper (target, QSE_T("avail = %llu\n"), (unsigned long long)xma->stat.avail);
|
||||
#endif
|
||||
|
||||
printf (QSE_T("== blocks ==\n"));
|
||||
printf (QSE_T(" size avail address\n"));
|
||||
dumper (target, QSE_T("== blocks ==\n"));
|
||||
dumper (target, QSE_T(" size avail address\n"));
|
||||
for (tmp = xma->head, fsum = 0, asum = 0; tmp; tmp = tmp->b.next)
|
||||
{
|
||||
printf (QSE_T(" %-18llu %-5d %p\n"), (unsigned long long)tmp->size, tmp->avail, tmp);
|
||||
dumper (target, QSE_T(" %-18llu %-5d %p\n"), (unsigned long long)tmp->size, tmp->avail, tmp);
|
||||
if (tmp->avail) fsum += tmp->size;
|
||||
else asum += tmp->size;
|
||||
}
|
||||
@ -731,12 +731,12 @@ void qse_xma_dump (qse_xma_t* xma, int (*printf)(const qse_char_t* fmt,...))
|
||||
isum = (xma->stat.nfree + xma->stat.nused) * HDRSIZE;
|
||||
#endif
|
||||
|
||||
printf (QSE_T("---------------------------------------\n"));
|
||||
printf (QSE_T("Allocated blocks: %18llu bytes\n"), asum);
|
||||
printf (QSE_T("Available blocks: %18llu bytes\n"), fsum);
|
||||
dumper (target, QSE_T("---------------------------------------\n"));
|
||||
dumper (target, QSE_T("Allocated blocks: %18llu bytes\n"), asum);
|
||||
dumper (target, QSE_T("Available blocks: %18llu bytes\n"), fsum);
|
||||
#ifdef QSE_XMA_ENABLE_STAT
|
||||
printf (QSE_T("Internal use : %18llu bytes\n"), isum);
|
||||
printf (QSE_T("Total : %18llu bytes\n"), asum + fsum + isum);
|
||||
dumper (target, QSE_T("Internal use : %18llu bytes\n"), isum);
|
||||
dumper (target, QSE_T("Total : %18llu bytes\n"), asum + fsum + isum);
|
||||
#endif
|
||||
|
||||
QSE_ASSERT (asum == xma->stat.alloc);
|
||||
|
Reference in New Issue
Block a user