added another new hash table implementation based on fr
This commit is contained in:
parent
02f3adf134
commit
5db7ddc770
@ -380,7 +380,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
@ -619,7 +618,7 @@ distdir: $(DISTFILES)
|
||||
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|
||||
|| chmod -R a+r "$(distdir)"
|
||||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
@ -645,7 +644,7 @@ dist-shar: distdir
|
||||
@echo WARNING: "Support for shar distribution archives is" \
|
||||
"deprecated." >&2
|
||||
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
@ -663,7 +662,7 @@ dist dist-all:
|
||||
distcheck: dist
|
||||
case '$(DIST_ARCHIVES)' in \
|
||||
*.tar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
|
||||
eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.lz*) \
|
||||
@ -673,7 +672,7 @@ distcheck: dist
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
|
||||
eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
|
@ -355,7 +355,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -362,7 +362,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -388,7 +388,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -353,7 +353,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -353,7 +353,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
14
qse/configure
vendored
14
qse/configure
vendored
@ -821,7 +821,6 @@ infodir
|
||||
docdir
|
||||
oldincludedir
|
||||
includedir
|
||||
runstatedir
|
||||
localstatedir
|
||||
sharedstatedir
|
||||
sysconfdir
|
||||
@ -924,7 +923,6 @@ datadir='${datarootdir}'
|
||||
sysconfdir='${prefix}/etc'
|
||||
sharedstatedir='${prefix}/com'
|
||||
localstatedir='${prefix}/var'
|
||||
runstatedir='${localstatedir}/run'
|
||||
includedir='${prefix}/include'
|
||||
oldincludedir='/usr/include'
|
||||
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
|
||||
@ -1177,15 +1175,6 @@ do
|
||||
| -silent | --silent | --silen | --sile | --sil)
|
||||
silent=yes ;;
|
||||
|
||||
-runstatedir | --runstatedir | --runstatedi | --runstated \
|
||||
| --runstate | --runstat | --runsta | --runst | --runs \
|
||||
| --run | --ru | --r)
|
||||
ac_prev=runstatedir ;;
|
||||
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
|
||||
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
|
||||
| --run=* | --ru=* | --r=*)
|
||||
runstatedir=$ac_optarg ;;
|
||||
|
||||
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
|
||||
ac_prev=sbindir ;;
|
||||
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
||||
@ -1323,7 +1312,7 @@ fi
|
||||
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
|
||||
datadir sysconfdir sharedstatedir localstatedir includedir \
|
||||
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
|
||||
libdir localedir mandir runstatedir
|
||||
libdir localedir mandir
|
||||
do
|
||||
eval ac_val=\$$ac_var
|
||||
# Remove trailing slashes.
|
||||
@ -1476,7 +1465,6 @@ Fine tuning of the installation directories:
|
||||
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
|
||||
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
|
||||
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
|
||||
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
|
||||
--libdir=DIR object code libraries [EPREFIX/lib]
|
||||
--includedir=DIR C header files [PREFIX/include]
|
||||
--oldincludedir=DIR C header files for non-gcc [/usr/include]
|
||||
|
@ -298,7 +298,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -356,7 +356,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -396,7 +396,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -347,7 +347,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -12,6 +12,7 @@ pkginclude_HEADERS = \
|
||||
fmt.h \
|
||||
gdl.h \
|
||||
htb.h \
|
||||
htl.h \
|
||||
hton.h \
|
||||
hwad.h \
|
||||
ipad.h \
|
||||
|
@ -133,13 +133,13 @@ am__can_run_installinfo = \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__pkginclude_HEADERS_DIST = alg.h arr.h chr.h cp949.h cp950.h dll.h \
|
||||
env.h fma.h fmt.h gdl.h htb.h hton.h hwad.h ipad.h main.h \
|
||||
map.h mb8.h mbwc.h mem.h oht.h opt.h path.h pma.h rbt.h rex.h \
|
||||
sll.h slmb.h str.h time.h tmr.h tre.h uni.h uri.h utf8.h xma.h \
|
||||
Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp ScopedPtr.hpp \
|
||||
SharedPtr.hpp StrBase.hpp String.hpp Mpool.hpp Association.hpp \
|
||||
LinkedList.hpp HashList.hpp HashTable.hpp RedBlackTree.hpp \
|
||||
RedBlackTable.hpp Array.hpp BinaryHeap.hpp
|
||||
env.h fma.h fmt.h gdl.h htb.h htl.h hton.h hwad.h ipad.h \
|
||||
main.h map.h mb8.h mbwc.h mem.h oht.h opt.h path.h pma.h rbt.h \
|
||||
rex.h sll.h slmb.h str.h time.h tmr.h tre.h uni.h uri.h utf8.h \
|
||||
xma.h Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \
|
||||
ScopedPtr.hpp SharedPtr.hpp StrBase.hpp String.hpp Mpool.hpp \
|
||||
Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp \
|
||||
RedBlackTree.hpp RedBlackTable.hpp Array.hpp BinaryHeap.hpp
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
@ -361,7 +361,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
@ -373,9 +372,9 @@ top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
pkginclude_HEADERS = alg.h arr.h chr.h cp949.h cp950.h dll.h env.h \
|
||||
fma.h fmt.h gdl.h htb.h hton.h hwad.h ipad.h main.h map.h \
|
||||
mb8.h mbwc.h mem.h oht.h opt.h path.h pma.h rbt.h rex.h sll.h \
|
||||
slmb.h str.h time.h tmr.h tre.h uni.h uri.h utf8.h xma.h \
|
||||
fma.h fmt.h gdl.h htb.h htl.h hton.h hwad.h ipad.h main.h \
|
||||
map.h mb8.h mbwc.h mem.h oht.h opt.h path.h pma.h rbt.h rex.h \
|
||||
sll.h slmb.h str.h time.h tmr.h tre.h uni.h uri.h utf8.h xma.h \
|
||||
$(am__append_1)
|
||||
all: all-am
|
||||
|
||||
|
302
qse/include/qse/cmn/htl.h
Normal file
302
qse/include/qse/cmn/htl.h
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QSE_HTL_T_
|
||||
#define _QSE_HTL_T_
|
||||
|
||||
/** \file
|
||||
* This file provides the hash table for fixed-size data.
|
||||
*/
|
||||
|
||||
#include <qse/types.h>
|
||||
#include <qse/macros.h>
|
||||
|
||||
/**
|
||||
* The #qse_htl_walk_t type defines walking directions.
|
||||
*/
|
||||
enum qse_htl_walk_t
|
||||
{
|
||||
QSE_HTL_WALK_STOP = 0,
|
||||
QSE_HTL_WALK_FORWARD = 1,
|
||||
};
|
||||
typedef enum qse_htl_walk_t qse_htl_walk_t;
|
||||
|
||||
typedef struct qse_htl_t qse_htl_t;
|
||||
typedef struct qse_htl_node_t qse_htl_node_t;
|
||||
|
||||
/**
|
||||
* The #qse_htl_hasher_t type defines a data hasher function.
|
||||
*/
|
||||
typedef qse_size_t (*qse_htl_hasher_t) (
|
||||
qse_htl_t* htl,
|
||||
const void* data
|
||||
);
|
||||
|
||||
/**
|
||||
* The #qse_htl_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_htl_comper_t) (
|
||||
qse_htl_t* htl, /**< hash table */
|
||||
const void* data1, /**< data pointer */
|
||||
const void* data2 /**< data pointer */
|
||||
);
|
||||
|
||||
/**
|
||||
* The #qse_htl_feeeer_t type defines a data deallocation function.
|
||||
*/
|
||||
typedef void (*qse_htl_freeer_t) (
|
||||
qse_htl_t* htl,
|
||||
void* data
|
||||
);
|
||||
|
||||
/**
|
||||
* The #qse_htl_copier_t type defines a data copier function.
|
||||
*/
|
||||
typedef void* (*qse_htl_copier_t) (
|
||||
qse_htl_t* htl,
|
||||
void* data
|
||||
);
|
||||
|
||||
/**
|
||||
* The #qse_htl_walker_t function defines a callback function
|
||||
* for qse_htl_walk().
|
||||
*/
|
||||
typedef qse_htl_walk_t (*qse_htl_walker_t) (
|
||||
qse_htl_t* htl,
|
||||
void* data,
|
||||
void* ctx
|
||||
);
|
||||
|
||||
struct qse_htl_node_t
|
||||
{
|
||||
struct qse_htl_node_t* next;
|
||||
qse_uint32_t reversed;
|
||||
qse_uint32_t key;
|
||||
void* data;
|
||||
};
|
||||
|
||||
struct qse_htl_t
|
||||
{
|
||||
qse_mmgr_t* mmgr;
|
||||
|
||||
int keysize; /* default key size */
|
||||
|
||||
int num_elements;
|
||||
int num_buckets; /* power of 2 */
|
||||
int next_grow;
|
||||
int mask;
|
||||
|
||||
qse_htl_hasher_t hasher;
|
||||
qse_htl_comper_t comper;
|
||||
qse_htl_freeer_t freeer;
|
||||
qse_htl_copier_t copier;
|
||||
|
||||
qse_htl_node_t null;
|
||||
qse_htl_node_t** buckets;
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The qse_htl_open() function creates an hash table.
|
||||
*/
|
||||
QSE_EXPORT qse_htl_t* qse_htl_open (
|
||||
qse_mmgr_t* mmgr,
|
||||
qse_size_t xtnsize,
|
||||
int scale
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_close() function destroys an hash table.
|
||||
*/
|
||||
QSE_EXPORT void qse_htl_close (
|
||||
qse_htl_t* htl /**< hash table */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_open() function initializes an hash table.
|
||||
*/
|
||||
QSE_EXPORT int qse_htl_init (
|
||||
qse_htl_t* htl,
|
||||
qse_mmgr_t* mmgr,
|
||||
int scale
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_close() function finalizes an hash table.
|
||||
*/
|
||||
QSE_EXPORT void qse_htl_fini (
|
||||
qse_htl_t* htl /**< hash table */
|
||||
);
|
||||
|
||||
|
||||
#if defined(QSE_HAVE_INLINE)
|
||||
static QSE_INLINE qse_mmgr_t* qse_htl_getmmgr (qse_htl_t* htl) { return (htl)->mmgr; }
|
||||
#else
|
||||
#define qse_htl_getmmgr(htl) ((htl)->mmgr))
|
||||
#endif
|
||||
|
||||
#if defined(QSE_HAVE_INLINE)
|
||||
static QSE_INLINE void* qse_htl_getxtn (qse_htl_t* htl) { return QSE_XTN(htl); }
|
||||
#else
|
||||
#define qse_htl_getxtn(htl) (QSE_XTN(htl))
|
||||
#endif
|
||||
|
||||
#if defined(QSE_HAVE_INLINE)
|
||||
static QSE_INLINE int qse_htl_getsize (qse_htl_t* htl) { return htl->num_elements; }
|
||||
#else
|
||||
#define qse_htl_getsize(htl) ((htl)->num_elements)
|
||||
#endif
|
||||
|
||||
#if defined(QSE_HAVE_INLINE)
|
||||
static QSE_INLINE qse_htl_hasher_t qse_htl_gethasher (qse_htl_t* htl) { return htl->hasher; }
|
||||
static QSE_INLINE qse_htl_comper_t qse_htl_getcomper (qse_htl_t* htl) { return htl->comper; }
|
||||
static QSE_INLINE qse_htl_freeer_t qse_htl_getfreeer (qse_htl_t* htl) { return htl->freeer; }
|
||||
|
||||
static QSE_INLINE void qse_htl_sethasher (qse_htl_t* htl, qse_htl_hasher_t _hasher) { htl->hasher = _hasher; }
|
||||
static QSE_INLINE void qse_htl_setcomper (qse_htl_t* htl, qse_htl_comper_t _comper) { htl->comper = _comper; }
|
||||
static QSE_INLINE void qse_htl_setfreeer (qse_htl_t* htl, qse_htl_freeer_t _freeer) { htl->freeer = _freeer; }
|
||||
static QSE_INLINE void qse_htl_setcopier (qse_htl_t* htl, qse_htl_copier_t _copier) { htl->copier = _copier; }
|
||||
#else
|
||||
#define qse_htl_gethasher(htl) ((htl)->hasher)
|
||||
#define qse_htl_getcomper(htl) ((htl)->comper)
|
||||
#define qse_htl_getfreeer(htl) ((htl)->freeer)
|
||||
|
||||
#define qse_htl_sethasher(htl,_hahser) ((htl)->hasher = _hasher)
|
||||
#define qse_htl_setcomper(htl,_comper) ((htl)->comper = _comper)
|
||||
#define qse_htl_setfreeer(htl,_freeer) ((htl)->freeer = _freeer)
|
||||
#define qse_htl_setcopier(htl,_copier) ((htl)->copier = _copier)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The qse_htl_search() function searches a hash table to find a
|
||||
* matching datum. It returns the index to the slot of an internal array
|
||||
* where the matching datum is found.
|
||||
* \return slot index if a match if found,
|
||||
* #QSE_HTL_NIL if no match is found.
|
||||
*/
|
||||
QSE_EXPORT qse_htl_node_t* qse_htl_search (
|
||||
qse_htl_t* htl, /**< hash table */
|
||||
void* data /**< data pointer */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_insert() function inserts a new datum. It fails if it finds
|
||||
* an existing datum.
|
||||
* \return slot index where the new datum is inserted on success,
|
||||
* #QSE_HTL_NIL on failure.
|
||||
*/
|
||||
QSE_EXPORT qse_htl_node_t* qse_htl_insert (
|
||||
qse_htl_t* htl, /**< hash table */
|
||||
void* data /**< data pointer */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_upsert() function inserts a new datum if it finds no matching
|
||||
* datum or updates an exsting datum if finds a matching datum.
|
||||
* \return slot index where the datum is inserted or updated.
|
||||
*/
|
||||
QSE_EXPORT qse_htl_node_t* qse_htl_upsert (
|
||||
qse_htl_t* htl, /**< hash table */
|
||||
void* data /**< data pointer */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_update() function updates an existing datum. It fails if it finds
|
||||
* no existing datum.
|
||||
* \return slot index where an existing datum is updated on success,
|
||||
* #QSE_HTL_NIL on failure.
|
||||
*/
|
||||
QSE_EXPORT qse_htl_node_t* qse_htl_update (
|
||||
qse_htl_t* htl, /**< hash table */
|
||||
void* data /**< data pointer */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_ensert() function inserts a new item if one is not found.
|
||||
* It returns an existing item otherwise.
|
||||
*/
|
||||
QSE_EXPORT qse_htl_node_t* qse_htl_ensert (
|
||||
qse_htl_t* htl, /**< hash table */
|
||||
void* data /**< data pointer */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_delete() function deletes an existing datum. It fails if it finds
|
||||
* no existing datum.
|
||||
* \return 0 on success, -1 on failure
|
||||
*/
|
||||
QSE_EXPORT int qse_htl_delete (
|
||||
qse_htl_t* htl, /**< hash table */
|
||||
void* data /**< data pointer */
|
||||
);
|
||||
|
||||
QSE_EXPORT void* qse_htl_yank (
|
||||
qse_htl_t* ht,
|
||||
void* data
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_clear() functions deletes all data items.
|
||||
*/
|
||||
QSE_EXPORT void qse_htl_clear (
|
||||
qse_htl_t* htl /**< hash table */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_htl_walk() function executes the callback function @a walker for
|
||||
* each valid data item.
|
||||
*/
|
||||
QSE_EXPORT void qse_htl_walk (
|
||||
qse_htl_t* htl, /**< hash table */
|
||||
qse_htl_walker_t walker, /**< callback function */
|
||||
void* ctx /**< context */
|
||||
);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
QSE_EXPORT qse_uint32_t qse_genhash_update (const void* data, qse_size_t size, qse_uint32_t hash);
|
||||
QSE_EXPORT qse_uint32_t qse_genhash (const void *data, qse_size_t size);
|
||||
/*qse_uint32_t qse_foldhash (qse_uint32_t hash, int bits);*/
|
||||
|
||||
QSE_EXPORT qse_uint32_t qse_mbshash (const qse_mchar_t* p);
|
||||
QSE_EXPORT qse_uint32_t qse_wcshash (const qse_wchar_t* p);
|
||||
|
||||
#if defined(QSE_CHAR_IS_WCHAR)
|
||||
# define qse_strhash(x) qse_wcshash (x)
|
||||
#else
|
||||
# define qse_strhash(x) qse_mbshash (x)
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -345,7 +345,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -345,7 +345,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -345,7 +345,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -46,16 +46,52 @@
|
||||
#define QSE_RAD_ATTR_TYPE_COMBO_IP 13
|
||||
#define QSE_RAD_ATTR_TYPE_TLV 14
|
||||
|
||||
struct qse_raddic_attr_flags_t
|
||||
{
|
||||
unsigned int addport : 1; /* add NAS-Port to IP address */
|
||||
unsigned int has_tag : 1; /* tagged attribute */
|
||||
unsigned int do_xlat : 1; /* strvalue is dynamic */
|
||||
unsigned int unknown_attr : 1; /* not in dictionary */
|
||||
unsigned int array : 1; /* pack multiples into 1 attr */
|
||||
unsigned int has_value : 1; /* has a value */
|
||||
unsigned int has_value_alias : 1; /* has a value alias */
|
||||
unsigned int has_tlv : 1; /* has sub attributes */
|
||||
unsigned int is_tlv : 1; /* is a sub attribute */
|
||||
unsigned int encoded : 1; /* has been put into packet */
|
||||
qse_int8_t tag; /* tag for tunneled attributes */
|
||||
qse_uint8_t encrypt; /* encryption method */
|
||||
};
|
||||
typedef struct qse_raddic_attr_flags_t qse_raddic_attr_flags_t;
|
||||
|
||||
struct qse_raddic_attr_t
|
||||
{
|
||||
int attr;
|
||||
int type;
|
||||
int vendor;
|
||||
/* ATTR_FLAGS flags;*/
|
||||
char name[1];
|
||||
qse_raddic_attr_flags_t flags;
|
||||
qse_char_t name[1];
|
||||
};
|
||||
typedef struct qse_raddic_attr_t qse_raddic_attr_t;
|
||||
|
||||
|
||||
struct qse_raddic_value_t
|
||||
{
|
||||
int attr;
|
||||
int value;
|
||||
qse_char_t name[1];
|
||||
};
|
||||
typedef struct qse_raddic_value_t qse_raddic_value_t;
|
||||
|
||||
struct qse_raddic_vendor_t
|
||||
{
|
||||
int vendorpec;
|
||||
int type;
|
||||
int length;
|
||||
int flags;
|
||||
qse_char_t name[1];
|
||||
};
|
||||
typedef struct qse_raddic_vendor_t qse_raddic_vendor_t;
|
||||
|
||||
typedef struct qse_raddic_t qse_raddic_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
@ -347,7 +347,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -29,25 +29,39 @@
|
||||
|
||||
#include <qse/Types.hpp>
|
||||
#include <qse/Uncopyable.hpp>
|
||||
#include <qse/cmn/Mmged.hpp>
|
||||
|
||||
/////////////////////////////////
|
||||
QSE_BEGIN_NAMESPACE(QSE)
|
||||
/////////////////////////////////
|
||||
|
||||
class AppRoot: QSE::Uncopyable
|
||||
class AppRoot: Uncopyable, public Types, public Mmged
|
||||
{
|
||||
public:
|
||||
AppRoot (): _root_only (false) {}
|
||||
AppRoot (Mmgr* mmgr): Mmged(mmgr), _root_only(false) {}
|
||||
virtual ~AppRoot () {}
|
||||
|
||||
int daemonize (bool chdir_to_root = true, int fork_count = 1) QSE_CPP_NOEXCEPT;
|
||||
|
||||
static int chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT;
|
||||
static int chroot (const qse_mchar_t* mpath) QSE_CPP_NOEXCEPT;
|
||||
int chroot (const qse_mchar_t* mpath) QSE_CPP_NOEXCEPT;
|
||||
int chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT;
|
||||
|
||||
#if 0
|
||||
int switchUser (uid_t uid, gid_t gid, bool permanently) QSE_CPP_NOEXCEPT;
|
||||
int restoreUser () QSE_CPP_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool _root_only;
|
||||
#if 0
|
||||
uid_t saved_uid;
|
||||
gid_t saved_gid;
|
||||
gid_t saved_groups[NGROUPS_MAX];
|
||||
qse_size_t saved_ngroups;
|
||||
|
||||
void on_signal () QSE_CPP_NOEXCEPT;
|
||||
void on_signal () QSE_CPP_NOEXCEPT;
|
||||
#endif
|
||||
};
|
||||
|
||||
/////////////////////////////////
|
||||
|
@ -354,7 +354,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -278,6 +278,18 @@ QSE_EXPORT void qse_log_fini (
|
||||
qse_log_t* log
|
||||
);
|
||||
|
||||
#if defined(QSE_HAVE_INLINE)
|
||||
static QSE_INLINE qse_mmgr_t* qse_log_getmmgr (qse_log_t* log) { return (log)->mmgr; }
|
||||
#else
|
||||
#define qse_log_getmmgr(log) ((log)->mmgr))
|
||||
#endif
|
||||
|
||||
#if defined(QSE_HAVE_INLINE)
|
||||
static QSE_INLINE void* qse_log_getxtn (qse_log_t* log) { return QSE_XTN(log); }
|
||||
#else
|
||||
#define qse_log_getxtn(log) (QSE_XTN(log))
|
||||
#endif
|
||||
|
||||
QSE_EXPORT void qse_log_setident (
|
||||
qse_log_t* log,
|
||||
const qse_char_t* ident
|
||||
|
@ -345,7 +345,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -390,7 +390,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -546,7 +546,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -43,6 +43,7 @@ libqsecmn_la_SOURCES = \
|
||||
env.c \
|
||||
gdl.c \
|
||||
htb.c \
|
||||
htl.c \
|
||||
fma.c \
|
||||
fmt-intmax.c \
|
||||
fmt-out.c \
|
||||
|
@ -143,8 +143,8 @@ am__DEPENDENCIES_1 =
|
||||
libqsecmn_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
|
||||
$(am__DEPENDENCIES_1)
|
||||
am__libqsecmn_la_SOURCES_DIST = alg-base64.c alg-rand.c alg-search.c \
|
||||
alg-sort.c arr.c assert.c chr.c dll.c env.c gdl.c htb.c fma.c \
|
||||
fmt-intmax.c fmt-out.c hton.c hwad.c ipad.c main.c mb8.c \
|
||||
alg-sort.c arr.c assert.c chr.c dll.c env.c gdl.c htb.c htl.c \
|
||||
fma.c fmt-intmax.c fmt-out.c hton.c hwad.c ipad.c main.c mb8.c \
|
||||
mbwc.c mbwc-str.c mem.c oht.c opt.c path-base.c path-canon.c \
|
||||
path-core.c path-merge.c pma.c rbt.c rex.c sll.c slmb.c \
|
||||
str-beg.c str-cat.c str-chr.c str-cnv.c str-cmp.c str-cpy.c \
|
||||
@ -159,19 +159,19 @@ am__libqsecmn_la_SOURCES_DIST = alg-base64.c alg-rand.c alg-search.c \
|
||||
@ENABLE_XCMGRS_TRUE@am__objects_2 = cp949.lo cp950.lo
|
||||
am_libqsecmn_la_OBJECTS = alg-base64.lo alg-rand.lo alg-search.lo \
|
||||
alg-sort.lo arr.lo assert.lo chr.lo dll.lo env.lo gdl.lo \
|
||||
htb.lo fma.lo fmt-intmax.lo fmt-out.lo hton.lo hwad.lo ipad.lo \
|
||||
main.lo mb8.lo mbwc.lo mbwc-str.lo mem.lo oht.lo opt.lo \
|
||||
path-base.lo path-canon.lo path-core.lo path-merge.lo pma.lo \
|
||||
rbt.lo rex.lo sll.lo slmb.lo str-beg.lo str-cat.lo str-chr.lo \
|
||||
str-cnv.lo str-cmp.lo str-cpy.lo str-del.lo str-dup.lo \
|
||||
str-dyn.lo str-end.lo str-excl.lo str-fcpy.lo str-fmt.lo \
|
||||
str-fnmat.lo str-incl.lo str-join.lo str-len.lo str-pac.lo \
|
||||
str-pbrk.lo str-put.lo str-rev.lo str-rot.lo str-set.lo \
|
||||
str-spl.lo str-spn.lo str-str.lo str-subst.lo str-tok.lo \
|
||||
str-trm.lo str-word.lo time.lo tmr.lo tre.lo tre-ast.lo \
|
||||
tre-compile.lo tre-match-bt.lo tre-match-pa.lo tre-parse.lo \
|
||||
tre-stack.lo uri.lo utf8.lo xma.lo $(am__objects_1) \
|
||||
$(am__objects_2)
|
||||
htb.lo htl.lo fma.lo fmt-intmax.lo fmt-out.lo hton.lo hwad.lo \
|
||||
ipad.lo main.lo mb8.lo mbwc.lo mbwc-str.lo mem.lo oht.lo \
|
||||
opt.lo path-base.lo path-canon.lo path-core.lo path-merge.lo \
|
||||
pma.lo rbt.lo rex.lo sll.lo slmb.lo str-beg.lo str-cat.lo \
|
||||
str-chr.lo str-cnv.lo str-cmp.lo str-cpy.lo str-del.lo \
|
||||
str-dup.lo str-dyn.lo str-end.lo str-excl.lo str-fcpy.lo \
|
||||
str-fmt.lo str-fnmat.lo str-incl.lo str-join.lo str-len.lo \
|
||||
str-pac.lo str-pbrk.lo str-put.lo str-rev.lo str-rot.lo \
|
||||
str-set.lo str-spl.lo str-spn.lo str-str.lo str-subst.lo \
|
||||
str-tok.lo str-trm.lo str-word.lo time.lo tmr.lo tre.lo \
|
||||
tre-ast.lo tre-compile.lo tre-match-bt.lo tre-match-pa.lo \
|
||||
tre-parse.lo tre-stack.lo uri.lo utf8.lo xma.lo \
|
||||
$(am__objects_1) $(am__objects_2)
|
||||
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
@ -443,7 +443,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
@ -486,7 +485,7 @@ noinst_HEADERS = \
|
||||
va_copy.h
|
||||
|
||||
libqsecmn_la_SOURCES = alg-base64.c alg-rand.c alg-search.c alg-sort.c \
|
||||
arr.c assert.c chr.c dll.c env.c gdl.c htb.c fma.c \
|
||||
arr.c assert.c chr.c dll.c env.c gdl.c htb.c htl.c fma.c \
|
||||
fmt-intmax.c fmt-out.c hton.c hwad.c ipad.c main.c mb8.c \
|
||||
mbwc.c mbwc-str.c mem.c oht.c opt.c path-base.c path-canon.c \
|
||||
path-core.c path-merge.c pma.c rbt.c rex.c sll.c slmb.c \
|
||||
@ -608,6 +607,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt-out.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdl.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htl.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hton.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwad.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipad.Plo@am__quote@
|
||||
|
856
qse/lib/cmn/htl.c
Normal file
856
qse/lib/cmn/htl.c
Normal file
@ -0,0 +1,856 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
* modifications so that they're not lock-free. :(
|
||||
*
|
||||
* However, the split-order idea allows a fast & easy splitting of the
|
||||
* hash bucket chain when the hash table is resized. Without it, we'd
|
||||
* have to check & update the pointers for every node in the buck chain,
|
||||
* rather than being able to move 1/2 of the entries in the chain with
|
||||
* one update.
|
||||
*
|
||||
* Version: $Id$
|
||||
*
|
||||
* This library 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 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that 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 this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* Copyright 2005,2006 The FreeRADIUS server project
|
||||
*/
|
||||
|
||||
|
||||
#include <qse/cmn/htl.h>
|
||||
#include "mem-prv.h"
|
||||
|
||||
/*
|
||||
* A reasonable number of buckets to start off with.
|
||||
* Should be a power of two.
|
||||
*/
|
||||
#define QSE_HTL_NUM_BUCKETS (64)
|
||||
|
||||
|
||||
/*
|
||||
* perl -e 'foreach $i (0..255) {$r = 0; foreach $j (0 .. 7 ) { if (($i & ( 1<< $j)) != 0) { $r |= (1 << (7 - $j));}} print $r, ", ";if (($i & 7) == 7) {print "\n";}}'
|
||||
*/
|
||||
static const qse_uint8_t reversed_byte[256] =
|
||||
{
|
||||
0, 128, 64, 192, 32, 160, 96, 224,
|
||||
16, 144, 80, 208, 48, 176, 112, 240,
|
||||
8, 136, 72, 200, 40, 168, 104, 232,
|
||||
24, 152, 88, 216, 56, 184, 120, 248,
|
||||
4, 132, 68, 196, 36, 164, 100, 228,
|
||||
20, 148, 84, 212, 52, 180, 116, 244,
|
||||
12, 140, 76, 204, 44, 172, 108, 236,
|
||||
28, 156, 92, 220, 60, 188, 124, 252,
|
||||
2, 130, 66, 194, 34, 162, 98, 226,
|
||||
18, 146, 82, 210, 50, 178, 114, 242,
|
||||
10, 138, 74, 202, 42, 170, 106, 234,
|
||||
26, 154, 90, 218, 58, 186, 122, 250,
|
||||
6, 134, 70, 198, 38, 166, 102, 230,
|
||||
22, 150, 86, 214, 54, 182, 118, 246,
|
||||
14, 142, 78, 206, 46, 174, 110, 238,
|
||||
30, 158, 94, 222, 62, 190, 126, 254,
|
||||
1, 129, 65, 193, 33, 161, 97, 225,
|
||||
17, 145, 81, 209, 49, 177, 113, 241,
|
||||
9, 137, 73, 201, 41, 169, 105, 233,
|
||||
25, 153, 89, 217, 57, 185, 121, 249,
|
||||
5, 133, 69, 197, 37, 165, 101, 229,
|
||||
21, 149, 85, 213, 53, 181, 117, 245,
|
||||
13, 141, 77, 205, 45, 173, 109, 237,
|
||||
29, 157, 93, 221, 61, 189, 125, 253,
|
||||
3, 131, 67, 195, 35, 163, 99, 227,
|
||||
19, 147, 83, 211, 51, 179, 115, 243,
|
||||
11, 139, 75, 203, 43, 171, 107, 235,
|
||||
27, 155, 91, 219, 59, 187, 123, 251,
|
||||
7, 135, 71, 199, 39, 167, 103, 231,
|
||||
23, 151, 87, 215, 55, 183, 119, 247,
|
||||
15, 143, 79, 207, 47, 175, 111, 239,
|
||||
31, 159, 95, 223, 63, 191, 127, 255
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* perl -e 'foreach $i (0..255) {$r = 0;foreach $j (0 .. 7) { $r = $i & (1 << (7 - $j)); last if ($r)} print $i & ~($r), ", ";if (($i & 7) == 7) {print "\n";}}'
|
||||
*/
|
||||
static qse_uint8_t parent_byte[256] =
|
||||
{
|
||||
0, 0, 0, 1, 0, 1, 2, 3,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103,
|
||||
104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Reverse a key.
|
||||
*/
|
||||
static qse_uint32_t reverse (qse_uint32_t key)
|
||||
{
|
||||
return ((reversed_byte[key & 0xff] << 24) |
|
||||
(reversed_byte[(key >> 8) & 0xff] << 16) |
|
||||
(reversed_byte[(key >> 16) & 0xff] << 8) |
|
||||
(reversed_byte[(key >> 24) & 0xff]));
|
||||
}
|
||||
|
||||
/*
|
||||
* Take the parent by discarding the highest bit that is set.
|
||||
*/
|
||||
static qse_uint32_t parent_of (qse_uint32_t key)
|
||||
{
|
||||
if (key > 0x00ffffff)
|
||||
return (key & 0x00ffffff) | (parent_byte[key >> 24] << 24);
|
||||
|
||||
if (key > 0x0000ffff)
|
||||
return (key & 0x0000ffff) | (parent_byte[key >> 16] << 16);
|
||||
|
||||
if (key > 0x000000ff)
|
||||
return (key & 0x000000ff) | (parent_byte[key >> 8] << 8);
|
||||
|
||||
return parent_byte[key];
|
||||
}
|
||||
|
||||
|
||||
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_node_t *cur;
|
||||
|
||||
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;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
if (cur->reversed > reversed) break;
|
||||
}
|
||||
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Inserts a new entry into the list, in order.
|
||||
*/
|
||||
static int list_insert (qse_htl_t* ht, qse_htl_node_t** head, qse_htl_node_t* node)
|
||||
{
|
||||
qse_htl_node_t **last, *cur;
|
||||
|
||||
last = head;
|
||||
|
||||
for (cur = *head; cur != &ht->null; cur = cur->next)
|
||||
{
|
||||
if (cur->reversed > node->reversed) break;
|
||||
last = &(cur->next);
|
||||
|
||||
if (cur->reversed == node->reversed)
|
||||
{
|
||||
if (ht->comper)
|
||||
{
|
||||
int cmp = ht->comper(ht, node->data, cur->data);
|
||||
if (cmp > 0) break;
|
||||
if (cmp < 0) continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
node->next = *last;
|
||||
*last = node;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete an entry from the list.
|
||||
*/
|
||||
static int list_delete (qse_htl_t* ht, qse_htl_node_t** head, qse_htl_node_t* node)
|
||||
{
|
||||
qse_htl_node_t **last, *cur;
|
||||
|
||||
last = head;
|
||||
|
||||
for (cur = *head; cur != &ht->null; cur = cur->next)
|
||||
{
|
||||
if (cur == node) break;
|
||||
last = &(cur->next);
|
||||
}
|
||||
|
||||
*last = node->next;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
static QSE_INLINE_ALWAYS qse_size_t default_hasher (qse_htl_t* htl, const void* data)
|
||||
{
|
||||
#if 0
|
||||
qse_size_t h = 5381;
|
||||
const qse_byte_t* p = (const qse_byte_t*)data;
|
||||
const qse_byte_t* bound = p + htl->keysize;
|
||||
while (p < bound) h = ((h << 5) + h) + *p++;
|
||||
return h ;
|
||||
#else
|
||||
return qse_genhash (data, htl->keysize);
|
||||
#endif
|
||||
}
|
||||
|
||||
static QSE_INLINE_ALWAYS int default_comper (qse_htl_t* htl, const void* data1, const void* data2)
|
||||
{
|
||||
return QSE_MEMCMP(data1, data2, htl->keysize);
|
||||
}
|
||||
|
||||
qse_htl_t* qse_htl_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, int keysize)
|
||||
{
|
||||
qse_htl_t* htl;
|
||||
|
||||
htl = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_htl_t) + xtnsize);
|
||||
if (htl == QSE_NULL) return QSE_NULL;
|
||||
|
||||
if (qse_htl_init (htl, mmgr, keysize) <= -1)
|
||||
{
|
||||
QSE_MMGR_FREE (mmgr, htl);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
QSE_MEMSET (htl + 1, 0, xtnsize);
|
||||
return htl;
|
||||
}
|
||||
|
||||
void qse_htl_close (qse_htl_t* htl)
|
||||
{
|
||||
qse_htl_fini (htl);
|
||||
QSE_MMGR_FREE (htl->mmgr, htl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the table.
|
||||
*
|
||||
* Memory usage in bytes is (20/3) * number of entries.
|
||||
*/
|
||||
int qse_htl_init (qse_htl_t* ht, qse_mmgr_t* mmgr, int keysize)
|
||||
{
|
||||
QSE_MEMSET (ht, 0, sizeof(*ht));
|
||||
ht->mmgr = mmgr;
|
||||
ht->keysize = keysize;
|
||||
|
||||
ht->hasher = default_hasher;
|
||||
ht->comper = default_comper;
|
||||
ht->freeer = QSE_NULL;
|
||||
ht->copier = QSE_NULL;
|
||||
ht->num_buckets = QSE_HTL_NUM_BUCKETS;
|
||||
ht->mask = ht->num_buckets - 1;
|
||||
|
||||
/*
|
||||
* Have a default load factor of 2.5. In practice this
|
||||
* means that the average load will hit 3 before the
|
||||
* table grows.
|
||||
*/
|
||||
ht->next_grow = (ht->num_buckets << 1) + (ht->num_buckets >> 1);
|
||||
|
||||
ht->buckets = QSE_MMGR_ALLOC (ht->mmgr, QSE_SIZEOF(*ht->buckets) * ht->num_buckets);
|
||||
if (!ht->buckets) return -1;
|
||||
|
||||
QSE_MEMSET (ht->buckets, 0, sizeof(*ht->buckets) * ht->num_buckets);
|
||||
|
||||
ht->null.reversed = ~0;
|
||||
ht->null.key = ~0;
|
||||
ht->null.next = &ht->null;
|
||||
|
||||
ht->buckets[0] = &ht->null;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qse_htl_fini (qse_htl_t* ht)
|
||||
{
|
||||
int i;
|
||||
qse_htl_node_t *node, *next;
|
||||
|
||||
/*
|
||||
* Walk over the buckets, freeing them all.
|
||||
*/
|
||||
for (i = 0; i < ht->num_buckets; i++)
|
||||
{
|
||||
if (ht->buckets[i])
|
||||
{
|
||||
for (node = ht->buckets[i]; node != &ht->null; node = next)
|
||||
{
|
||||
next = node->next;
|
||||
|
||||
if (!node->data) continue; /* dummy entry */
|
||||
|
||||
if (ht->freeer) ht->freeer (ht, node->data);
|
||||
QSE_MMGR_FREE (ht->mmgr, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QSE_MMGR_FREE (ht->mmgr, ht->buckets);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* If the current bucket is uninitialized, initialize it
|
||||
* by recursively copying information from the parent.
|
||||
*
|
||||
* We may have a situation where entry E is a parent to 2 other
|
||||
* entries E' and E". If we split E into E and E', then the
|
||||
* nodes meant for E" end up in E or E', either of which is
|
||||
* wrong. To solve that problem, we walk down the whole chain,
|
||||
* inserting the elements into the correct place.
|
||||
*/
|
||||
static void fixup (qse_htl_t *ht, qse_uint32_t entry)
|
||||
{
|
||||
qse_uint32_t parent_entry;
|
||||
qse_htl_node_t** last, * cur;
|
||||
qse_uint32_t thiss;
|
||||
|
||||
parent_entry = parent_of(entry);
|
||||
|
||||
/* parent_entry == entry if and only if entry == 0 */
|
||||
|
||||
if (!ht->buckets[parent_entry])
|
||||
{
|
||||
fixup(ht, parent_entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep walking down cur, trying to find entries that
|
||||
* don't belong here any more. There may be multiple
|
||||
* ones, so we can't have a naive algorithm...
|
||||
*/
|
||||
last = &ht->buckets[parent_entry];
|
||||
thiss = parent_entry;
|
||||
|
||||
for (cur = *last; cur != &ht->null; cur = cur->next)
|
||||
{
|
||||
qse_uint32_t real_entry;
|
||||
|
||||
real_entry = cur->key & ht->mask;
|
||||
if (real_entry != thiss)
|
||||
{ /* ht->buckets[real_entry] == QSE_NULL */
|
||||
*last = &ht->null;
|
||||
ht->buckets[real_entry] = cur;
|
||||
thiss = real_entry;
|
||||
}
|
||||
|
||||
last = &(cur->next);
|
||||
}
|
||||
|
||||
/*
|
||||
* We may NOT have initialized this bucket, so do it now.
|
||||
*/
|
||||
if (!ht->buckets[entry]) ht->buckets[entry] = &ht->null;
|
||||
}
|
||||
|
||||
/*
|
||||
* This should be a power of two. Changing it to 4 doesn't seem
|
||||
* to make any difference.
|
||||
*/
|
||||
#define GROW_FACTOR (2)
|
||||
|
||||
/*
|
||||
* Grow the hash table.
|
||||
*/
|
||||
static void grow (qse_htl_t *ht)
|
||||
{
|
||||
qse_htl_node_t **buckets;
|
||||
|
||||
buckets = QSE_MMGR_ALLOC (ht->mmgr, QSE_SIZEOF(*buckets) * GROW_FACTOR * ht->num_buckets);
|
||||
if (!buckets) return;
|
||||
|
||||
QSE_MEMCPY (buckets, ht->buckets, QSE_SIZEOF(*buckets) * ht->num_buckets);
|
||||
QSE_MEMSET (&buckets[ht->num_buckets], 0, QSE_SIZEOF(*buckets) * ht->num_buckets);
|
||||
|
||||
QSE_MMGR_FREE (ht->mmgr, ht->buckets);
|
||||
ht->buckets = buckets;
|
||||
ht->num_buckets *= GROW_FACTOR;
|
||||
ht->next_grow *= GROW_FACTOR;
|
||||
ht->mask = ht->num_buckets - 1;
|
||||
}
|
||||
|
||||
qse_htl_node_t *qse_htl_search (qse_htl_t* ht, void* data)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert data.
|
||||
*/
|
||||
qse_htl_node_t* qse_htl_insert (qse_htl_t* ht, void* data)
|
||||
{
|
||||
qse_uint32_t key;
|
||||
qse_uint32_t entry;
|
||||
qse_uint32_t reversed;
|
||||
qse_htl_node_t *node;
|
||||
|
||||
key = ht->hasher(ht, data);
|
||||
entry = key & ht->mask;
|
||||
reversed = reverse(key);
|
||||
|
||||
if (!ht->buckets[entry]) fixup(ht, entry);
|
||||
|
||||
/*
|
||||
* If we try to do our own memory allocation here, the
|
||||
* speedup is only ~15% or so, which isn't worth it.
|
||||
*/
|
||||
node = QSE_MMGR_ALLOC(ht->mmgr, QSE_SIZEOF(*node));
|
||||
if (!node) return QSE_NULL;
|
||||
QSE_MEMSET (node, 0, QSE_SIZEOF(*node));
|
||||
|
||||
node->next = &ht->null;
|
||||
node->reversed = reversed;
|
||||
node->key = key;
|
||||
|
||||
if (ht->copier)
|
||||
{
|
||||
node->data = ht->copier (ht, data);
|
||||
if (!node->data)
|
||||
{
|
||||
QSE_MMGR_FREE (ht->mmgr, node);
|
||||
return QSE_NULL;
|
||||
}
|
||||
}
|
||||
else node->data = data;
|
||||
|
||||
/* already in the table, can't insert it */
|
||||
if (!list_insert(ht, &ht->buckets[entry], node))
|
||||
{
|
||||
if (ht->freeer) ht->freeer (ht, node->data);
|
||||
QSE_MMGR_FREE (ht->mmgr, node);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the load factor, and grow the table if
|
||||
* necessary.
|
||||
*/
|
||||
ht->num_elements++;
|
||||
if (ht->num_elements >= ht->next_grow) grow(ht);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace old data with new data, OR insert if there is no old.
|
||||
*/
|
||||
qse_htl_node_t* qse_htl_upsert (qse_htl_t* ht, void* data)
|
||||
{
|
||||
qse_htl_node_t *node;
|
||||
void* datap;
|
||||
|
||||
node = qse_htl_search(ht, data);
|
||||
if (!node) return qse_htl_insert(ht, data);
|
||||
|
||||
if (ht->copier)
|
||||
{
|
||||
datap = ht->copier (ht, data);
|
||||
if (!datap) return QSE_NULL;
|
||||
}
|
||||
else datap = data;
|
||||
|
||||
if (ht->freeer) ht->freeer(ht, node->data);
|
||||
node->data = datap;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
qse_htl_node_t* qse_htl_update (qse_htl_t* ht, void* data)
|
||||
{
|
||||
qse_htl_node_t *node;
|
||||
void* datap;
|
||||
|
||||
node = qse_htl_search(ht, data);
|
||||
if (!node) return QSE_NULL;
|
||||
|
||||
if (ht->copier)
|
||||
{
|
||||
datap = ht->copier (ht, data);
|
||||
if (!datap) return QSE_NULL;
|
||||
}
|
||||
else datap = data;
|
||||
|
||||
if (ht->freeer) ht->freeer(ht, node->data);
|
||||
node->data = datap;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* Yank an entry from the hash table, without freeing the data.
|
||||
*/
|
||||
void* qse_htl_yank (qse_htl_t* ht, void* data)
|
||||
{
|
||||
qse_uint32_t key;
|
||||
qse_uint32_t entry;
|
||||
qse_uint32_t reversed;
|
||||
void *old;
|
||||
qse_htl_node_t* node;
|
||||
|
||||
if (!ht) return QSE_NULL;
|
||||
|
||||
key = ht->hasher(ht, data);
|
||||
entry = key & ht->mask;
|
||||
reversed = reverse(key);
|
||||
|
||||
if (!ht->buckets[entry]) fixup(ht, entry);
|
||||
|
||||
node = list_find(ht, ht->buckets[entry], reversed, data);
|
||||
if (!node) return QSE_NULL;
|
||||
|
||||
list_delete(ht, &ht->buckets[entry], node);
|
||||
ht->num_elements--;
|
||||
|
||||
old = node->data;
|
||||
QSE_MMGR_FREE (ht->mmgr, node);
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a piece of data from the hash table.
|
||||
*/
|
||||
int qse_htl_delete(qse_htl_t *ht, void* data)
|
||||
{
|
||||
void* old;
|
||||
|
||||
old = qse_htl_yank(ht, data);
|
||||
if (!old) return -1;
|
||||
|
||||
if (ht->freeer) ht->freeer(ht, old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk over the nodes, allowing deletes & inserts to happen.
|
||||
*/
|
||||
void qse_htl_walk (qse_htl_t *ht, qse_htl_walker_t walker, void *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ht->num_buckets - 1; i >= 0; i--)
|
||||
{
|
||||
qse_htl_node_t* node, * next;
|
||||
|
||||
/*
|
||||
* Ensure that the current bucket is filled.
|
||||
*/
|
||||
if (!ht->buckets[i]) fixup(ht, i);
|
||||
|
||||
for (node = ht->buckets[i]; node != &ht->null; node = next)
|
||||
{
|
||||
next = node->next;
|
||||
if (walker(ht, node->data, ctx) == QSE_HTL_WALK_STOP) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Find data from a template
|
||||
*/
|
||||
void *qse_htl_finddata(qse_htl_t *ht, const void *data)
|
||||
{
|
||||
qse_htl_node_t *node;
|
||||
|
||||
node = qse_htl_find(ht, data);
|
||||
if (!node) return NULL;
|
||||
|
||||
return node->data;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TESTING
|
||||
/*
|
||||
* Show what the hash table is doing.
|
||||
*/
|
||||
int qse_htl_info(qse_htl_t *ht)
|
||||
{
|
||||
int i, a, collisions, uninitialized;
|
||||
int array[256];
|
||||
|
||||
if (!ht) return 0;
|
||||
|
||||
uninitialized = collisions = 0;
|
||||
memset(array, 0, sizeof(array));
|
||||
|
||||
for (i = 0; i < ht->num_buckets; i++) {
|
||||
qse_uint32_t key;
|
||||
int load;
|
||||
qse_htl_node_t *node, *next;
|
||||
|
||||
/*
|
||||
* If we haven't inserted or looked up an entry
|
||||
* in a bucket, it's uninitialized.
|
||||
*/
|
||||
if (!ht->buckets[i]) {
|
||||
uninitialized++;
|
||||
continue;
|
||||
}
|
||||
|
||||
load = 0;
|
||||
key = ~0;
|
||||
for (node = ht->buckets[i]; node != &ht->null; node = next) {
|
||||
if (node->reversed == key) {
|
||||
collisions++;
|
||||
} else {
|
||||
key = node->reversed;
|
||||
}
|
||||
next = node->next;
|
||||
load++;
|
||||
}
|
||||
|
||||
if (load > 255) load = 255;
|
||||
array[load]++;
|
||||
}
|
||||
|
||||
printf("HASH TABLE %p\tbuckets: %d\t(%d uninitialized)\n", ht,
|
||||
ht->num_buckets, uninitialized);
|
||||
printf("\tnum entries %d\thash collisions %d\n",
|
||||
ht->num_elements, collisions);
|
||||
|
||||
a = 0;
|
||||
for (i = 1; i < 256; i++) {
|
||||
if (!array[i]) continue;
|
||||
printf("%d\t%d\n", i, array[i]);
|
||||
|
||||
/*
|
||||
* Since the entries are ordered, the lookup cost
|
||||
* for any one element in a chain is (on average)
|
||||
* the cost of walking half of the chain.
|
||||
*/
|
||||
if (i > 1) {
|
||||
a += array[i] * i;
|
||||
}
|
||||
}
|
||||
a /= 2;
|
||||
a += array[1];
|
||||
|
||||
printf("\texpected lookup cost = %d/%d or %f\n\n",
|
||||
ht->num_elements, a,
|
||||
(float) ht->num_elements / (float) a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#define FNV_MAGIC_INIT (0x811c9dc5)
|
||||
#define FNV_MAGIC_PRIME (0x01000193)
|
||||
|
||||
/*
|
||||
* A fast hash function. For details, see:
|
||||
*
|
||||
* http://www.isthe.com/chongo/tech/comp/fnv/
|
||||
*
|
||||
* Which also includes public domain source. We've re-written
|
||||
* it here for our purposes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Continue hashing data.
|
||||
*/
|
||||
QSE_INLINE qse_uint32_t qse_genhash_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;
|
||||
|
||||
/*
|
||||
* FNV-1 hash each octet in the buffer
|
||||
*/
|
||||
while (p != q)
|
||||
{
|
||||
/*
|
||||
* XOR the 8-bit quantity into the bottom of
|
||||
* the hash.
|
||||
*/
|
||||
hash ^= (qse_uint32_t) (*p++);
|
||||
|
||||
/*
|
||||
* Multiple by 32-bit magic FNV prime, mod 2^32
|
||||
*/
|
||||
hash *= FNV_MAGIC_PRIME;
|
||||
#if 0
|
||||
/*
|
||||
* Potential optimization.
|
||||
*/
|
||||
hash += (hash<<1) + (hash<<4) + (hash<<7) + (hash<<8) + (hash<<24);
|
||||
#endif
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
qse_uint32_t qse_genhash (const void *data, qse_size_t size)
|
||||
{
|
||||
return qse_genhash_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 hash = FNV_MAGIC_INIT;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
hash ^= (qse_uint32_t) (*p++);
|
||||
hash *= FNV_MAGIC_PRIME;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
qse_uint32_t qse_wcshash (const qse_wchar_t* p)
|
||||
{
|
||||
|
||||
qse_uint32_t hash = FNV_MAGIC_INIT;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
#if (QSE_SIZEOF_WCHAR_T <= QSE_SIZEOF_UINT32_T)
|
||||
hash ^= (qse_uint32_t)(*p);
|
||||
hash *= FNV_MAGIC_PRIME;
|
||||
#else
|
||||
hash = qse_genhash_update (*p, QSE_SIZEOF(*p), hash);
|
||||
#endif
|
||||
p++;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Return a "folded" hash, where the lower "bits" are the
|
||||
* hash, and the upper bits are zero.
|
||||
*
|
||||
* If you need a non-power-of-two hash, cope.
|
||||
*/
|
||||
qse_uint32_t qse_foldhash (qse_uint32_t hash, int bits)
|
||||
{
|
||||
int count;
|
||||
qse_uint32_t result;
|
||||
|
||||
if ((bits <= 0) || (bits >= 32)) return hash;
|
||||
|
||||
result = hash;
|
||||
|
||||
/*
|
||||
* Never use the same bits twice in an xor.
|
||||
*/
|
||||
for (count = 0; count < 32; count += bits)
|
||||
{
|
||||
hash >>= bits;
|
||||
result ^= hash;
|
||||
}
|
||||
|
||||
return result & (((qse_uint32_t) (1 << bits)) - 1);
|
||||
}
|
||||
#endif
|
@ -377,7 +377,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -384,7 +384,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -377,7 +377,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
1093
qse/lib/rad/raddic.c
1093
qse/lib/rad/raddic.c
File diff suppressed because it is too large
Load Diff
@ -408,7 +408,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -26,9 +26,8 @@
|
||||
|
||||
#include <qse/si/AppRoot.hpp>
|
||||
#include <qse/si/sinfo.h>
|
||||
#include <qse/cmn/mem.h>
|
||||
#include <qse/cmn/mbwc.h>
|
||||
#include "../cmn/syscall.h"
|
||||
#include <qse/cmn/mbwc.h>
|
||||
|
||||
/////////////////////////////////
|
||||
QSE_BEGIN_NAMESPACE(QSE)
|
||||
@ -42,7 +41,6 @@ int AppRoot::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT
|
||||
{
|
||||
if (fork_count >= 2)
|
||||
{
|
||||
struct sigaction sa;
|
||||
int n = QSE_FORK();
|
||||
if (n == -1) return -1;
|
||||
if (n != 0) QSE_EXIT(0);
|
||||
@ -103,64 +101,53 @@ int AppRoot::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int AppRoot::switchUser () QSE_CPP_NOEXCEPT
|
||||
{
|
||||
struct passwd* pw;
|
||||
|
||||
pw = getpwnam (username);
|
||||
if (!pw)
|
||||
|
||||
|
||||
if (QSE_SETGID(pw->pw_gid) == -1)
|
||||
{
|
||||
}
|
||||
|
||||
QSE_SETEGID(gid);
|
||||
QSE_SETUID(uid);
|
||||
QSE_SETEUID(uid);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int AppRoot::chroot (const qse_mchar_t* mpath) QSE_CPP_NOEXCEPT
|
||||
{
|
||||
int orgdirfd;
|
||||
|
||||
orgdirfd = QSE_OPEN (".", O_RDONLY, 0);
|
||||
if (orgdirfd == -1) return -1;
|
||||
|
||||
if (QSE_CHDIR(mpath) == -1) return -1;
|
||||
if (QSE_CHROOT(mpath) == -1)
|
||||
{
|
||||
QSE_FCHDIR (orgdirfd);
|
||||
QSE_CLOSE (orgdirfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
QSE_CLOSE (orgdirfd);
|
||||
QSE_CHROOT ("/");
|
||||
|
||||
return 0;
|
||||
return QSE_CHROOT (mpath);
|
||||
}
|
||||
|
||||
int AppRoot::chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT
|
||||
{
|
||||
qse_mchar_t* mpath;
|
||||
|
||||
mpath = qse_wcstombsdup (wpath, QSE_NULL, QSE_MMGR_GETDFL());
|
||||
mpath = qse_wcstombsdup (wpath, QSE_NULL, this->getMmgr());
|
||||
if (!mpath) return -1;
|
||||
|
||||
int n = AppRoot::chroot ((const qse_mchar_t*)mpath);
|
||||
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), mpath);
|
||||
this->getMmgr()->dispose (mpath);
|
||||
return n;
|
||||
}
|
||||
|
||||
void AppRoot::on_signal () QSE_CPP_NOEXCEPT
|
||||
#if 0
|
||||
int AppRoot::switchPrivilege (int gid, int uid, bool permanently)
|
||||
{
|
||||
gid = QSE_GETGID();
|
||||
uid = QSE_GETUID();
|
||||
|
||||
this->saved_egid = QSE_GETEGID();
|
||||
this->saved_euid = QSE_GETEUID();
|
||||
this->saved_ngroups = getgroups (QSE_COUNTOF(this->saved_groups), this->saved_groups);
|
||||
|
||||
if (this->saved_euid == 0) setgrops (1, gid);
|
||||
|
||||
setegid (gid);
|
||||
//setregid (-1, gid);
|
||||
|
||||
if (uid != this->saved_euid)
|
||||
{
|
||||
seteuid (uid);
|
||||
//setreuid (-1, uid);
|
||||
}
|
||||
}
|
||||
|
||||
int AppRoot::restorePrivilege ()
|
||||
{
|
||||
if (QSE_GETEUID() != this->saved_euid) seteuid (this->saved_euid);
|
||||
if (QSE_GETEGID() != this->saved_egid) setegid (this->saved_egid);
|
||||
if (this->saved_euid == 0) setgroups (this->saved_ngroups, this->saved_groups);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
int main ()
|
||||
@ -168,8 +155,10 @@ int main ()
|
||||
AppRoot app;
|
||||
|
||||
app.daemonize();
|
||||
app.switchUser ("nobody", "nobody");
|
||||
app.switchUser (10, 20);
|
||||
app.chuser ();
|
||||
app.chgroup ();
|
||||
app.chroot ();
|
||||
|
||||
app.catchSignal (SIGINT, xxxxx);
|
||||
app.catchSignal (SIGTERM, xxx);
|
||||
|
||||
|
@ -423,7 +423,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -377,7 +377,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -356,7 +356,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -298,7 +298,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -300,7 +300,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -356,7 +356,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -480,7 +480,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -15,6 +15,7 @@ bin_PROGRAMS = \
|
||||
fmt01 \
|
||||
fmt02 \
|
||||
htb01 \
|
||||
htl01 \
|
||||
ipad01 \
|
||||
main01 \
|
||||
main02 \
|
||||
|
@ -90,11 +90,12 @@ build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
bin_PROGRAMS = arr01$(EXEEXT) chr01$(EXEEXT) dll$(EXEEXT) \
|
||||
env01$(EXEEXT) fma$(EXEEXT) fmt01$(EXEEXT) fmt02$(EXEEXT) \
|
||||
htb01$(EXEEXT) ipad01$(EXEEXT) main01$(EXEEXT) main02$(EXEEXT) \
|
||||
mbwc01$(EXEEXT) mbwc02$(EXEEXT) oht$(EXEEXT) path01$(EXEEXT) \
|
||||
pma$(EXEEXT) rex01$(EXEEXT) rbt01$(EXEEXT) sll$(EXEEXT) \
|
||||
slmb01$(EXEEXT) str01$(EXEEXT) str02$(EXEEXT) time$(EXEEXT) \
|
||||
tre01$(EXEEXT) uri01$(EXEEXT) xma$(EXEEXT) $(am__EXEEXT_1)
|
||||
htb01$(EXEEXT) htl01$(EXEEXT) ipad01$(EXEEXT) main01$(EXEEXT) \
|
||||
main02$(EXEEXT) mbwc01$(EXEEXT) mbwc02$(EXEEXT) oht$(EXEEXT) \
|
||||
path01$(EXEEXT) pma$(EXEEXT) rex01$(EXEEXT) rbt01$(EXEEXT) \
|
||||
sll$(EXEEXT) slmb01$(EXEEXT) str01$(EXEEXT) str02$(EXEEXT) \
|
||||
time$(EXEEXT) tre01$(EXEEXT) uri01$(EXEEXT) xma$(EXEEXT) \
|
||||
$(am__EXEEXT_1)
|
||||
@WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS)
|
||||
|
||||
#bin_PROGRAMS += rex02
|
||||
@ -188,6 +189,10 @@ am__htb02_SOURCES_DIST = htb02.cpp
|
||||
@ENABLE_CXX_TRUE@am_htb02_OBJECTS = htb02.$(OBJEXT)
|
||||
htb02_OBJECTS = $(am_htb02_OBJECTS)
|
||||
@ENABLE_CXX_TRUE@htb02_DEPENDENCIES = $(am__DEPENDENCIES_3)
|
||||
htl01_SOURCES = htl01.c
|
||||
htl01_OBJECTS = htl01.$(OBJEXT)
|
||||
htl01_LDADD = $(LDADD)
|
||||
htl01_DEPENDENCIES = $(am__DEPENDENCIES_2)
|
||||
am_ipad01_OBJECTS = ipad01.$(OBJEXT)
|
||||
ipad01_OBJECTS = $(am_ipad01_OBJECTS)
|
||||
ipad01_LDADD = $(LDADD)
|
||||
@ -332,7 +337,7 @@ SOURCES = $(arr01_SOURCES) $(arr02_SOURCES) $(arr03_SOURCES) \
|
||||
$(bh01_SOURCES) $(bh02_SOURCES) $(chr01_SOURCES) \
|
||||
$(dll_SOURCES) $(env01_SOURCES) $(fma_SOURCES) \
|
||||
$(fmt01_SOURCES) $(fmt02_SOURCES) $(hl01_SOURCES) \
|
||||
$(htb01_SOURCES) $(htb02_SOURCES) $(ipad01_SOURCES) \
|
||||
$(htb01_SOURCES) $(htb02_SOURCES) htl01.c $(ipad01_SOURCES) \
|
||||
$(main01_SOURCES) $(main02_SOURCES) $(mbwc01_SOURCES) \
|
||||
$(mbwc02_SOURCES) $(oht_SOURCES) $(path01_SOURCES) \
|
||||
$(pma_SOURCES) $(rbt01_SOURCES) $(rbt02_SOURCES) \
|
||||
@ -345,10 +350,10 @@ DIST_SOURCES = $(arr01_SOURCES) $(am__arr02_SOURCES_DIST) \
|
||||
$(am__bh02_SOURCES_DIST) $(chr01_SOURCES) $(dll_SOURCES) \
|
||||
$(env01_SOURCES) $(fma_SOURCES) $(fmt01_SOURCES) \
|
||||
$(fmt02_SOURCES) $(am__hl01_SOURCES_DIST) $(htb01_SOURCES) \
|
||||
$(am__htb02_SOURCES_DIST) $(ipad01_SOURCES) $(main01_SOURCES) \
|
||||
$(main02_SOURCES) $(mbwc01_SOURCES) $(mbwc02_SOURCES) \
|
||||
$(oht_SOURCES) $(path01_SOURCES) $(pma_SOURCES) \
|
||||
$(rbt01_SOURCES) $(am__rbt02_SOURCES_DIST) \
|
||||
$(am__htb02_SOURCES_DIST) htl01.c $(ipad01_SOURCES) \
|
||||
$(main01_SOURCES) $(main02_SOURCES) $(mbwc01_SOURCES) \
|
||||
$(mbwc02_SOURCES) $(oht_SOURCES) $(path01_SOURCES) \
|
||||
$(pma_SOURCES) $(rbt01_SOURCES) $(am__rbt02_SOURCES_DIST) \
|
||||
$(am__rbt03_SOURCES_DIST) $(rex01_SOURCES) $(sll_SOURCES) \
|
||||
$(slmb01_SOURCES) $(am__sp01_SOURCES_DIST) \
|
||||
$(am__sp02_SOURCES_DIST) $(str01_SOURCES) \
|
||||
@ -550,7 +555,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
@ -754,6 +758,10 @@ htb02$(EXEEXT): $(htb02_OBJECTS) $(htb02_DEPENDENCIES) $(EXTRA_htb02_DEPENDENCIE
|
||||
@rm -f htb02$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(htb02_OBJECTS) $(htb02_LDADD) $(LIBS)
|
||||
|
||||
htl01$(EXEEXT): $(htl01_OBJECTS) $(htl01_DEPENDENCIES) $(EXTRA_htl01_DEPENDENCIES)
|
||||
@rm -f htl01$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(htl01_OBJECTS) $(htl01_LDADD) $(LIBS)
|
||||
|
||||
ipad01$(EXEEXT): $(ipad01_OBJECTS) $(ipad01_DEPENDENCIES) $(EXTRA_ipad01_DEPENDENCIES)
|
||||
@rm -f ipad01$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(ipad01_OBJECTS) $(ipad01_LDADD) $(LIBS)
|
||||
@ -862,6 +870,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hl01.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb01.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb02.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htl01.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipad01.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main01.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main02.Po@am__quote@
|
||||
|
209
qse/samples/cmn/htl01.c
Normal file
209
qse/samples/cmn/htl01.c
Normal file
@ -0,0 +1,209 @@
|
||||
#include <qse/cmn/mem.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/htl.h>
|
||||
#include <qse/si/sio.h>
|
||||
|
||||
#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_htl_walk_t walk1 (qse_htl_t* htl, void* data, void* ctx)
|
||||
{
|
||||
qse_printf (QSE_T("[%ld]\n"), *(long*)data);
|
||||
return QSE_HTL_WALK_FORWARD;
|
||||
}
|
||||
|
||||
static qse_htl_walk_t walk2 (qse_htl_t* htl, 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_HTL_WALK_FORWARD;
|
||||
}
|
||||
|
||||
static qse_size_t hash_item (qse_htl_t* htl, const void* data)
|
||||
{
|
||||
item_t* item = (item_t*)data;
|
||||
//return item->a + 123445;
|
||||
return qse_genhash (&item->a, QSE_SIZEOF(item->a));
|
||||
}
|
||||
|
||||
static int comp_item (qse_htl_t* htl, const void* data1, const void* data2)
|
||||
{
|
||||
return ((item_t*)data1)->a != ((item_t*)data2)->a;
|
||||
}
|
||||
|
||||
static void* copy_item (qse_htl_t* htl, void* data)
|
||||
{
|
||||
item_t* x = (item_t*)QSE_MMGR_ALLOC (htl->mmgr, QSE_SIZEOF(item_t));
|
||||
if (x) *x = *(item_t*)data;
|
||||
return x;
|
||||
}
|
||||
|
||||
static void free_item (qse_htl_t* htl, void* data)
|
||||
{
|
||||
QSE_MMGR_FREE (htl->mmgr, data);
|
||||
}
|
||||
|
||||
static void* copy_long (qse_htl_t* htl, void* data)
|
||||
{
|
||||
long* x = (long*)QSE_MMGR_ALLOC (htl->mmgr, QSE_SIZEOF(long));
|
||||
if (x) *x = *(long*)data;
|
||||
return x;
|
||||
}
|
||||
|
||||
static void free_long (qse_htl_t* htl, void* data)
|
||||
{
|
||||
QSE_MMGR_FREE (htl->mmgr, data);
|
||||
}
|
||||
|
||||
static int test1 ()
|
||||
{
|
||||
long x;
|
||||
qse_htl_t* htl;
|
||||
qse_htl_node_t* np;
|
||||
|
||||
htl = qse_htl_open (QSE_MMGR_GETDFL(), 0, QSE_SIZEOF(x));
|
||||
if (htl == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("failed to open a table\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
qse_htl_setcopier (htl, copy_long);
|
||||
qse_htl_setfreeer (htl, free_long);
|
||||
|
||||
for (x = 9; x < 20; x++)
|
||||
{
|
||||
if (qse_htl_insert(htl, &x))
|
||||
{
|
||||
qse_printf (QSE_T("SUCCESS: inserted %ld\n"), x);
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_printf (QSE_T("FAILURE: failed to insert %ld\n"), x);
|
||||
}
|
||||
}
|
||||
|
||||
x = 10;
|
||||
if ((np = qse_htl_search(htl, &x)))
|
||||
{
|
||||
qse_printf (QSE_T("SUCCESS: found %ld\n"), *(long*)np->data);
|
||||
QSE_ASSERT (*(long*)np->data == x);
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_printf (QSE_T("FAILURE: failed to found %ld\n"), x);
|
||||
}
|
||||
|
||||
x = 10;
|
||||
if (qse_htl_delete(htl, &x) == 0)
|
||||
{
|
||||
qse_printf (QSE_T("SUCCESS: deleted %ld\n"), x);
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_printf (QSE_T("FAILURE: failed to delete %ld\n"), x);
|
||||
}
|
||||
|
||||
x = 10;
|
||||
qse_printf (QSE_T("searching for %ld\n"), x);
|
||||
np = qse_htl_search(htl, &x);
|
||||
QSE_ASSERT (np == QSE_NULL);
|
||||
if (np)
|
||||
{
|
||||
qse_printf (QSE_T("FAILURE: found something that must not be found - %ld\n"), x);
|
||||
}
|
||||
|
||||
qse_printf (QSE_T("total %lu items\n"), (unsigned long)qse_htl_getsize(htl));
|
||||
qse_htl_walk (htl, walk1, QSE_NULL);
|
||||
qse_htl_close (htl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test2 ()
|
||||
{
|
||||
item_t x;
|
||||
qse_htl_t* htl;
|
||||
qse_htl_node_t* np;
|
||||
|
||||
htl = qse_htl_open (QSE_MMGR_GETDFL(), 0, QSE_SIZEOF(x));
|
||||
if (htl == QSE_NULL)
|
||||
{
|
||||
qse_printf (QSE_T("failed to open a table\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
qse_htl_sethasher (htl, hash_item);
|
||||
qse_htl_setcomper (htl, comp_item);
|
||||
qse_htl_setcopier (htl, copy_item);
|
||||
qse_htl_setfreeer (htl, free_item);
|
||||
|
||||
for (x.a = 9; x.a < 20; x.a++)
|
||||
{
|
||||
x.x = x.a * 10;
|
||||
x.y = x.a * 100;
|
||||
|
||||
if (qse_htl_insert(htl, &x))
|
||||
{
|
||||
qse_printf (QSE_T("SUCCESS: inserted %ld\n"), x.a);
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_printf (QSE_T("FAILURE: failed to insert %ld\n"), x.a);
|
||||
}
|
||||
}
|
||||
|
||||
x.a = 10;
|
||||
if ((np = qse_htl_search(htl, &x)))
|
||||
{
|
||||
qse_printf (QSE_T("SUCCESS: found %ld\n"), *(long*)np->data);
|
||||
QSE_ASSERT (*(long*)np->data == x.a);
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_printf (QSE_T("FAILURE: failed to found %ld\n"), x.a);
|
||||
}
|
||||
|
||||
x.a = 10;
|
||||
if (qse_htl_delete(htl, &x) == 0)
|
||||
{
|
||||
qse_printf (QSE_T("SUCCESS: deleted %ld\n"), x.a);
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_printf (QSE_T("FAILURE: failed to delete %ld\n"), x.a);
|
||||
}
|
||||
|
||||
x.a = 10;
|
||||
qse_printf (QSE_T("searching for %ld\n"), x.a);
|
||||
np = qse_htl_search(htl, &x);
|
||||
QSE_ASSERT (np == QSE_NULL);
|
||||
if (np)
|
||||
{
|
||||
qse_printf (QSE_T("FAILURE: found something that must not be found - %ld\n"), x.a);
|
||||
}
|
||||
|
||||
qse_printf (QSE_T("total %lu items\n"), (unsigned long)qse_htl_getsize(htl));
|
||||
qse_htl_walk (htl, walk2, QSE_NULL);
|
||||
qse_htl_close (htl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
qse_open_stdsios ();
|
||||
R (test1);
|
||||
R (test2);
|
||||
qse_close_stdsios ();
|
||||
return 0;
|
||||
}
|
@ -351,7 +351,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -352,7 +352,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -391,7 +391,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -433,7 +433,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -298,7 +298,6 @@ pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
Loading…
x
Reference in New Issue
Block a user