From 95e975f514c709664638a36fce492d02e0e8336c Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 8 Sep 2010 04:57:43 +0000 Subject: [PATCH] added open-addressed hash table --- qse/include/qse/cmn/Makefile.am | 2 +- qse/include/qse/cmn/Makefile.in | 10 +- qse/include/qse/cmn/htb.h | 4 +- qse/include/qse/cmn/oht.h | 194 +++++++++++++++++++ qse/include/qse/cmn/sll.h | 8 +- qse/include/qse/cmn/xma.h | 9 +- qse/lib/cmn/Makefile.am | 2 +- qse/lib/cmn/Makefile.in | 9 +- qse/lib/cmn/oht.c | 322 ++++++++++++++++++++++++++++++++ qse/lib/cmn/xma.c | 28 +-- qse/samples/cmn/Makefile.am | 3 +- qse/samples/cmn/Makefile.in | 26 ++- qse/samples/cmn/oht.c | 127 +++++++++++++ qse/samples/cmn/xma.c | 35 ++-- 14 files changed, 719 insertions(+), 60 deletions(-) create mode 100644 qse/include/qse/cmn/oht.h create mode 100644 qse/lib/cmn/oht.c create mode 100644 qse/samples/cmn/oht.c diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index b0d5d5c3..e82e9166 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -1,7 +1,7 @@ pkgincludedir = $(includedir)/qse/cmn pkginclude_HEADERS = \ - mem.h xma.h fma.h chr.h str.h lda.h htb.h rbt.h \ + mem.h xma.h fma.h chr.h str.h lda.h oht.h htb.h rbt.h \ rex.h sll.h gdl.h dll.h opt.h tio.h \ fio.h pio.h sio.h time.h misc.h main.h stdio.h diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index 93c24dd9..b7b77324 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -52,8 +52,8 @@ CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = am__pkginclude_HEADERS_DIST = mem.h xma.h fma.h chr.h str.h lda.h \ - htb.h rbt.h rex.h sll.h gdl.h dll.h opt.h tio.h fio.h pio.h \ - sio.h time.h misc.h main.h stdio.h Mmgr.hpp StdMmgr.hpp \ + oht.h htb.h rbt.h rex.h sll.h gdl.h dll.h opt.h tio.h fio.h \ + pio.h sio.h time.h misc.h main.h stdio.h Mmgr.hpp StdMmgr.hpp \ Mmged.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ @@ -221,9 +221,9 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -pkginclude_HEADERS = mem.h xma.h fma.h chr.h str.h lda.h htb.h rbt.h \ - rex.h sll.h gdl.h dll.h opt.h tio.h fio.h pio.h sio.h time.h \ - misc.h main.h stdio.h $(am__append_1) +pkginclude_HEADERS = mem.h xma.h fma.h chr.h str.h lda.h oht.h htb.h \ + rbt.h rex.h sll.h gdl.h dll.h opt.h tio.h fio.h pio.h sio.h \ + time.h misc.h main.h stdio.h $(am__append_1) all: all-am .SUFFIXES: diff --git a/qse/include/qse/cmn/htb.h b/qse/include/qse/cmn/htb.h index 456efac8..8871486b 100644 --- a/qse/include/qse/cmn/htb.h +++ b/qse/include/qse/cmn/htb.h @@ -1,5 +1,5 @@ /* - * $Id: htb.h 354 2010-09-03 12:50:08Z hyunghwan.chung $ + * $Id: htb.h 355 2010-09-07 10:57:43Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -157,7 +157,7 @@ struct qse_htb_t qse_htb_sizer_t sizer; /**< bucket capacity recalculator */ qse_byte_t scale[2]; /**< length scale */ - qse_byte_t factor; /**< load factor */ + qse_byte_t factor; /**< load factor in percentage */ qse_byte_t filler0; qse_size_t size; diff --git a/qse/include/qse/cmn/oht.h b/qse/include/qse/cmn/oht.h new file mode 100644 index 00000000..22272f7f --- /dev/null +++ b/qse/include/qse/cmn/oht.h @@ -0,0 +1,194 @@ +/* + * $Id$ + * + Copyright 2006-2009 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope toht it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +/** @file + * This file provides the open-addressed hash table for fixed-size data. + */ +#ifndef _QSE_OHT_T_ +#define _QSE_OHT_T_ + +#include +#include + +#define QSE_OHT_INVALID_INDEX ((qse_size_t)-1) + +enum qse_oht_mark_t +{ + QSE_OHT_EMPTY = 0, + QSE_OHT_OCCUPIED = 1 /*, + QSE_OHT_DELETED = 2 */ +}; +typedef enum qse_oht_mark_t qse_oht_mark_t; + +enum qse_oht_walk_t +{ + QSE_OHT_WALK_STOP = 0, + QSE_OHT_WALK_FORWARD = 1, +}; +typedef enum qse_oht_walk_t qse_oht_walk_t; + +typedef struct qse_oht_t qse_oht_t; + +/** + * The qse_oht_comper_t type defines a key comparator that is called when + * the list needs to compare data. The comparator must return 0 if the data + * are the same and a non-zero integer otherwise. + */ +typedef int (*qse_oht_comper_t) ( + qse_oht_t* oht, /**< open-addressed hash table */ + const void* data1, /**< data pointer */ + const void* data2 /**< data pointer */ +); + +typedef void (*qse_oht_copier_t) ( + qse_oht_t* oht, + void* dst, + const void* src +); + +typedef qse_size_t (*qse_oht_hasher_t) ( + qse_oht_t* oht, + const void* data +); + +struct qse_oht_t +{ + QSE_DEFINE_COMMON_FIELDS(oht) + + struct + { + qse_size_t hard; + qse_size_t soft; + } capa; + qse_size_t size; + qse_size_t scale; + + qse_oht_hasher_t hasher; + qse_oht_comper_t comper; + qse_oht_copier_t copier; + + qse_oht_mark_t* mark; + void* data; +}; + +typedef qse_oht_walk_t (*qse_oht_walker_t) ( + qse_oht_t* oht, + void* data, + void* ctx +); + +#ifdef __cplusplus +extern "C" { +#endif + +QSE_DEFINE_COMMON_FUNCTIONS (oht) + +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 +); + +void qse_oht_close ( + qse_oht_t* 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 +); + +void qse_oht_fini ( + qse_oht_t* oht +); + +qse_oht_hasher_t qse_oht_gethasher ( + qse_oht_t* oht +); + +void qse_oht_sethasher ( + qse_oht_t* oht, + qse_oht_hasher_t hahser +); + +qse_oht_comper_t qse_oht_getcomper ( + qse_oht_t* oht +); + +void qse_oht_setcomper ( + qse_oht_t* oht, + qse_oht_comper_t hahser +); + +qse_oht_copier_t qse_oht_getcopier ( + qse_oht_t* oht +); + +void qse_oht_setcopier ( + qse_oht_t* oht, + qse_oht_copier_t hahser +); + +qse_size_t qse_oht_search ( + qse_oht_t* oht, + void* data +); + +qse_size_t qse_oht_insert ( + qse_oht_t* oht, + const void* data +); + +qse_size_t qse_oht_upsert ( + qse_oht_t* oht, + const void* data +); + +qse_size_t qse_oht_update ( + qse_oht_t* oht, + const void* data +); + +qse_size_t qse_oht_delete ( + qse_oht_t* oht, + const void* data +); + +void qse_oht_clear ( + qse_oht_t* oht +); + + +void qse_oht_walk ( + qse_oht_t* oht, /**< open-addressed hash table */ + qse_oht_walker_t walker, /**< walker function */ + void* ctx /**< context */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/include/qse/cmn/sll.h b/qse/include/qse/cmn/sll.h index 2611b02d..f262ef15 100644 --- a/qse/include/qse/cmn/sll.h +++ b/qse/include/qse/cmn/sll.h @@ -1,5 +1,5 @@ /* - * $Id: sll.h 354 2010-09-03 12:50:08Z hyunghwan.chung $ + * $Id: sll.h 355 2010-09-07 10:57:43Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -123,9 +123,9 @@ struct qse_sll_t */ struct qse_sll_node_t { - void* dptr; /* the pointer to data */ - qse_size_t dlen; /* the length of data */ - qse_sll_node_t* next; /* the pointer to the next node */ + qse_sll_node_t* next; /* point to the next node */ + void* dptr; /* data pointer */ + qse_size_t dlen; /* data length */ }; #define QSE_SLL_COPIER_SIMPLE ((qse_sll_copier_t)1) diff --git a/qse/include/qse/cmn/xma.h b/qse/include/qse/cmn/xma.h index 09c52906..46160c9e 100644 --- a/qse/include/qse/cmn/xma.h +++ b/qse/include/qse/cmn/xma.h @@ -46,7 +46,7 @@ * ptr2 = qse_xma_alloc (xma, 1000); // allocate a 1K block from the zone * ptr1 = qse_xma_realloc (xma, ptr1, 6000); // resize the 5K block to 6K. * - * qse_xma_dump (xma, qse_printf); // dump memory blocks + * qse_xma_dump (xma, qse_fprintf, QSE_STDOUT); // dump memory blocks * * // the following two lines are not actually needed as the allocator * // is closed after them. @@ -104,6 +104,8 @@ struct qse_xma_t #endif }; +typedef int (*qse_xma_dumper_t) (void* target, const qse_char_t* fmt,...); + #ifdef __cplusplus extern "C" { #endif @@ -189,8 +191,9 @@ void qse_xma_free ( * more statistical counters. */ void qse_xma_dump ( - qse_xma_t* xma, /**< memory allocator */ - int (*printf)(const qse_char_t* fmt,...) /**< output function */ + qse_xma_t* xma, /**< memory allocator */ + qse_xma_dumper_t dumper, /**< output function */ + void* target /**< first parameter to output function */ ); #ifdef __cplusplus diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am index bdcd37d9..1155d3ea 100644 --- a/qse/lib/cmn/Makefile.am +++ b/qse/lib/cmn/Makefile.am @@ -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 \ diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in index 517144ca..473a0c8c 100644 --- a/qse/lib/cmn/Makefile.in +++ b/qse/lib/cmn/Makefile.in @@ -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@ diff --git a/qse/lib/cmn/oht.c b/qse/lib/cmn/oht.c new file mode 100644 index 00000000..932db5d7 --- /dev/null +++ b/qse/lib/cmn/oht.c @@ -0,0 +1,322 @@ +#include +#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; + } + } +} diff --git a/qse/lib/cmn/xma.c b/qse/lib/cmn/xma.c index fe1113c0..b698b676 100644 --- a/qse/lib/cmn/xma.c +++ b/qse/lib/cmn/xma.c @@ -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("\n")); + dumper (target, QSE_T("\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); diff --git a/qse/samples/cmn/Makefile.am b/qse/samples/cmn/Makefile.am index afe80d3c..8570263f 100644 --- a/qse/samples/cmn/Makefile.am +++ b/qse/samples/cmn/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -DNDEBUG -bin_PROGRAMS = xma fma chr str sll dll lda htb rbt fio pio sio time main rex01 +bin_PROGRAMS = xma fma chr str sll dll lda oht htb rbt fio pio sio time main rex01 LDFLAGS = -L../../lib/cmn LDADD = -lqsecmn @@ -12,6 +12,7 @@ str_SOURCES = str.c sll_SOURCES = sll.c dll_SOURCES = dll.c lda_SOURCES = lda.c +oht_SOURCES = oht.c htb_SOURCES = htb.c rbt_SOURCES = rbt.c fio_SOURCES = fio.c diff --git a/qse/samples/cmn/Makefile.in b/qse/samples/cmn/Makefile.in index a90d27de..206afa57 100644 --- a/qse/samples/cmn/Makefile.in +++ b/qse/samples/cmn/Makefile.in @@ -35,9 +35,9 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = xma$(EXEEXT) fma$(EXEEXT) chr$(EXEEXT) str$(EXEEXT) \ - sll$(EXEEXT) dll$(EXEEXT) lda$(EXEEXT) htb$(EXEEXT) \ - rbt$(EXEEXT) fio$(EXEEXT) pio$(EXEEXT) sio$(EXEEXT) \ - time$(EXEEXT) main$(EXEEXT) rex01$(EXEEXT) + sll$(EXEEXT) dll$(EXEEXT) lda$(EXEEXT) oht$(EXEEXT) \ + htb$(EXEEXT) rbt$(EXEEXT) fio$(EXEEXT) pio$(EXEEXT) \ + sio$(EXEEXT) time$(EXEEXT) main$(EXEEXT) rex01$(EXEEXT) subdir = samples/cmn DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -82,6 +82,10 @@ am_main_OBJECTS = main.$(OBJEXT) main_OBJECTS = $(am_main_OBJECTS) main_LDADD = $(LDADD) main_DEPENDENCIES = +am_oht_OBJECTS = oht.$(OBJEXT) +oht_OBJECTS = $(am_oht_OBJECTS) +oht_LDADD = $(LDADD) +oht_DEPENDENCIES = am_pio_OBJECTS = pio.$(OBJEXT) pio_OBJECTS = $(am_pio_OBJECTS) pio_LDADD = $(LDADD) @@ -128,13 +132,14 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(chr_SOURCES) $(dll_SOURCES) $(fio_SOURCES) $(fma_SOURCES) \ - $(htb_SOURCES) $(lda_SOURCES) $(main_SOURCES) $(pio_SOURCES) \ - $(rbt_SOURCES) $(rex01_SOURCES) $(sio_SOURCES) $(sll_SOURCES) \ - $(str_SOURCES) $(time_SOURCES) $(xma_SOURCES) -DIST_SOURCES = $(chr_SOURCES) $(dll_SOURCES) $(fio_SOURCES) \ - $(fma_SOURCES) $(htb_SOURCES) $(lda_SOURCES) $(main_SOURCES) \ + $(htb_SOURCES) $(lda_SOURCES) $(main_SOURCES) $(oht_SOURCES) \ $(pio_SOURCES) $(rbt_SOURCES) $(rex01_SOURCES) $(sio_SOURCES) \ $(sll_SOURCES) $(str_SOURCES) $(time_SOURCES) $(xma_SOURCES) +DIST_SOURCES = $(chr_SOURCES) $(dll_SOURCES) $(fio_SOURCES) \ + $(fma_SOURCES) $(htb_SOURCES) $(lda_SOURCES) $(main_SOURCES) \ + $(oht_SOURCES) $(pio_SOURCES) $(rbt_SOURCES) $(rex01_SOURCES) \ + $(sio_SOURCES) $(sll_SOURCES) $(str_SOURCES) $(time_SOURCES) \ + $(xma_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -286,6 +291,7 @@ str_SOURCES = str.c sll_SOURCES = sll.c dll_SOURCES = dll.c lda_SOURCES = lda.c +oht_SOURCES = oht.c htb_SOURCES = htb.c rbt_SOURCES = rbt.c fio_SOURCES = fio.c @@ -392,6 +398,9 @@ lda$(EXEEXT): $(lda_OBJECTS) $(lda_DEPENDENCIES) main$(EXEEXT): $(main_OBJECTS) $(main_DEPENDENCIES) @rm -f main$(EXEEXT) $(LINK) $(main_OBJECTS) $(main_LDADD) $(LIBS) +oht$(EXEEXT): $(oht_OBJECTS) $(oht_DEPENDENCIES) + @rm -f oht$(EXEEXT) + $(LINK) $(oht_OBJECTS) $(oht_LDADD) $(LIBS) pio$(EXEEXT): $(pio_OBJECTS) $(pio_DEPENDENCIES) @rm -f pio$(EXEEXT) $(LINK) $(pio_OBJECTS) $(pio_LDADD) $(LIBS) @@ -430,6 +439,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oht.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rbt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rex01.Po@am__quote@ diff --git a/qse/samples/cmn/oht.c b/qse/samples/cmn/oht.c new file mode 100644 index 00000000..c5d6ebd9 --- /dev/null +++ b/qse/samples/cmn/oht.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include + + +#define R(f) \ + do { \ + qse_printf (QSE_T("== %s ==\n"), QSE_T(#f)); \ + if (f() == -1) return -1; \ + } while (0) + +typedef struct item_t item_t; +struct item_t +{ + long a; + long x; + long y; +}; + +static qse_oht_walk_t walk1 (qse_oht_t* oht, void* data, void* ctx) +{ + qse_printf (QSE_T("[%ld]\n"), *(long*)data); + return QSE_OHT_WALK_FORWARD; +} + +static qse_oht_walk_t walk2 (qse_oht_t* oht, void* data, void* ctx) +{ + item_t* item = (item_t*)data; + qse_printf (QSE_T("a [%ld] x [%ld] y [%ld]\n"), item->a, item->x, item->y); + return QSE_OHT_WALK_FORWARD; +} + +static qse_size_t hash (qse_oht_t* oht, void* data) +{ + item_t* item = (item_t*)data; + return item->a; +} + +static int comp (qse_oht_t* oht, void* data1, void* data2) +{ + return ((item_t*)data1)->a != ((item_t*)data2)->a; +} + +static int test1 () +{ + long x; + qse_oht_t* oht; + + oht = qse_oht_open (QSE_NULL, 0, QSE_SIZEOF(x), 10, 5); + if (oht == QSE_NULL) + { + qse_printf (QSE_T("failed to open a table\n")); + return -1; + } + + for (x = 9; x < 20; x++) + { + qse_printf (QSE_T("inserting %ld => %lu\n"), + x, (unsigned long)qse_oht_insert (oht, &x)); + } + + x = 10; + qse_printf (QSE_T("searching for %ld => %lu\n"), + x, (unsigned long)qse_oht_search (oht, &x)); + + x = 10; + qse_printf (QSE_T("deleting %ld => %lu\n"), + x, (unsigned long)qse_oht_delete (oht, &x)); + + x = 10; + qse_printf (QSE_T("searching for %ld => %lu\n"), + x, (unsigned long)qse_oht_search (oht, &x)); + + + qse_oht_walk (oht, walk1, QSE_NULL); + qse_oht_close (oht); + return 0; +} + +static int test2 () +{ + item_t x; + qse_oht_t* oht; + + oht = qse_oht_open (QSE_NULL, 0, QSE_SIZEOF(x), 10, 5); + if (oht == QSE_NULL) + { + qse_printf (QSE_T("failed to open a table\n")); + return -1; + } + + qse_oht_sethasher (oht, hash); + qse_oht_setcomper (oht, comp); + + for (x.a = 9; x.a < 20; x.a++) + { + x.x = x.a * 10; + x.y = x.a * 100; + qse_printf (QSE_T("inserting %ld => %lu\n"), + x.a, (unsigned long)qse_oht_insert (oht, &x)); + } + + x.a = 10; + qse_printf (QSE_T("searching for %ld => %lu\n"), + x.a, (unsigned long)qse_oht_search (oht, &x)); + + x.a = 10; + qse_printf (QSE_T("deleting %ld => %lu\n"), + x.a, (unsigned long)qse_oht_delete (oht, &x)); + + x.a = 10; + qse_printf (QSE_T("searching for %ld => %lu\n"), + x.a, (unsigned long)qse_oht_search (oht, &x)); + + + qse_oht_walk (oht, walk2, QSE_NULL); + qse_oht_close (oht); + return 0; +} + +int main () +{ + R (test1); + R (test2); + return 0; +} diff --git a/qse/samples/cmn/xma.c b/qse/samples/cmn/xma.c index 7b95d30e..82c765a7 100644 --- a/qse/samples/cmn/xma.c +++ b/qse/samples/cmn/xma.c @@ -27,10 +27,10 @@ static int test1 () //qse_xma_free (xma, ptr[2]); //qse_xma_free (xma, ptr[3]); - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_realloc (xma, ptr[0], 500); qse_xma_realloc (xma, ptr[3], 500); - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_close (xma); return 0; @@ -51,13 +51,13 @@ static int test2 () ptr[1] = qse_xma_alloc (xma, 1000); ptr[2] = qse_xma_alloc (xma, 3000); ptr[3] = qse_xma_alloc (xma, 1000); - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_free (xma, ptr[0]); qse_xma_free (xma, ptr[2]); - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_realloc (xma, ptr[1], 500); - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_close (xma); return 0; @@ -78,15 +78,15 @@ static int test3 () ptr[1] = qse_xma_alloc (xma, 1000); ptr[2] = qse_xma_alloc (xma, 3000); ptr[3] = qse_xma_alloc (xma, 1000); - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_free (xma, ptr[0]); qse_xma_free (xma, ptr[2]); - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); ptr[1] = qse_xma_realloc (xma, ptr[1], 3000); - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_free (xma, ptr[1]); - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_close (xma); return 0; @@ -140,20 +140,19 @@ static int test4 () x = qse_xma_alloc (xma, 10); y = qse_xma_alloc (xma, 40); } - qse_xma_dump (xma, qse_printf); + qse_xma_dump (xma, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_close (xma); return 0; } static int test5 () { - int i; void* ptr[100]; qse_mmgr_t xmammgr = { - qse_xma_alloc, - qse_xma_realloc, - qse_xma_free, + (qse_mmgr_alloc_t)qse_xma_alloc, + (qse_mmgr_realloc_t)qse_xma_realloc, + (qse_mmgr_free_t)qse_xma_free, QSE_NULL }; @@ -189,13 +188,15 @@ static int test5 () qse_xma_alloc (xma3, 8); qse_xma_realloc (xma3, ptr[0], 40000); - qse_xma_dump (xma3, qse_printf); - qse_xma_dump (xma2, qse_printf); - qse_xma_dump (xma1, qse_printf); + qse_xma_dump (xma3, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); + qse_xma_dump (xma2, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); + qse_xma_dump (xma1, (qse_xma_dumper_t)qse_fprintf, QSE_STDOUT); qse_xma_close (xma3); qse_xma_close (xma2); qse_xma_close (xma1); + + return 0; } int main ()