added qse_rbt_cbsert()

This commit is contained in:
hyung-hwan 2010-10-31 06:49:18 +00:00
parent d58631e70b
commit 1c82886941
9 changed files with 601 additions and 134 deletions

View File

@ -271,7 +271,7 @@ void* qse_fma_alloc (
* the @a size requested is not greater than the fixed block size of the memory * the @a size requested is not greater than the fixed block size of the memory
* allocator @a fma, it allocates a block of the fixed size; If the block * allocator @a fma, it allocates a block of the fixed size; If the block
* @a blk is not #QSE_NULL and the @a size requested is not greater than the * @a blk is not #QSE_NULL and the @a size requested is not greater than the
* fixed block size of the memory allocator @a fma, it returns the block @blk. * fixed block size of the memory allocator @a fma, it returns the block @a blk.
* *
* @return block pointer on success, #QSE_NULL on failure * @return block pointer on success, #QSE_NULL on failure
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* $Id: htb.h 365 2010-10-29 13:54:36Z hyunghwan.chung $ * $Id: htb.h 366 2010-10-30 12:49:18Z hyunghwan.chung $
* *
Copyright 2006-2009 Chung, Hyung-Hwan. Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE. This file is part of QSE.
@ -25,8 +25,44 @@
#include <qse/macros.h> #include <qse/macros.h>
/**@file /**@file
* A hash table maintains buckets for key/value pairs with the same key hash * This file provides a hash table encapsulated in the #qse_htb_t type that
* chained under the same bucket. * maintains buckets for key/value pairs with the same key hash chained under
* the same bucket. Its interface is very close to #qse_rbt_t.
*
* This sample code adds a series of keys and values and print them
* in the randome order.
* @code
* #include <qse/cmn/htb.h>
* #include <qse/cmn/mem.h>
* #include <qse/cmn/stdio.h>
*
* static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx)
* {
* qse_printf (QSE_T("key = %d, value = %d\n"),
* *(int*)QSE_HTB_KPTR(pair), *(int*)QSE_HTB_VPTR(pair));
* return QSE_HTB_WALK_FORWARD;
* }
*
* int main ()
* {
* qse_htb_t* s1;
* int i;
*
* s1 = qse_htb_open (QSE_MMGR_GETDFL(), 0, 30, 75, 1, 1); // error handling skipped
* qse_htb_setmancbs (s1, qse_htb_mancbs(QSE_HTB_MANCBS_INLINE_COPIERS));
*
* for (i = 0; i < 20; i++)
* {
* int x = i * 20;
* qse_htb_insert (s1, &i, QSE_SIZEOF(i), &x, QSE_SIZEOF(x)); // eror handling skipped
* }
*
* qse_htb_walk (s1, walk, QSE_NULL);
*
* qse_htb_close (s1);
* return 0;
* }
* @endcode
*/ */
typedef struct qse_htb_t qse_htb_t; typedef struct qse_htb_t qse_htb_t;
@ -132,6 +168,25 @@ typedef qse_htb_walk_t (*qse_htb_walker_t) (
void* ctx /**< pointer to user-defined data */ void* ctx /**< pointer to user-defined data */
); );
/**
* The qse_htb_cbserter_t type defines a callback function for qse_htb_cbsert().
* The qse_htb_cbserter() function calls it to allocate a new pair for the
* key pointed to by @a kptr of the length @a klen and the callback context
* @a ctx. The second parameter @a pair is passed the pointer to the existing
* pair for the key or #QSE_NULL in case of no existing key. The callback
* must return a pointer to a new or a reallocated pair. When reallocating the
* existing pair, this callback must destroy the existing pair and return the
* newly reallocated pair. It must return #QSE_NULL for failure.
*/
typedef qse_htb_pair_t* (*qse_htb_cbserter_t) (
qse_htb_t* htb, /**< hash table */
qse_htb_pair_t* pair, /**< pair pointer */
void* kptr, /**< key pointer */
qse_size_t klen, /**< key length */
void* ctx /**< callback context */
);
/** /**
* The qse_htb_pair_t type defines hash table pair. A pair is composed of a key * The qse_htb_pair_t type defines hash table pair. A pair is composed of a key
* and a value. It maintains pointers to the beginning of a key and a value * and a value. It maintains pointers to the beginning of a key and a value
@ -161,11 +216,19 @@ struct qse_htb_mancbs_t
qse_htb_hasher_t hasher; /**< key hasher */ qse_htb_hasher_t hasher; /**< key hasher */
}; };
/**
* The qse_htb_mancbs_kind_t type defines the type of predefined
* callback set for pair manipulation.
*/
enum qse_htb_mancbs_kind_t enum qse_htb_mancbs_kind_t
{ {
/** store the key and the value pointer */
QSE_HTB_MANCBS_DEFAULT, QSE_HTB_MANCBS_DEFAULT,
/** copy both key and value into the pair */
QSE_HTB_MANCBS_INLINE_COPIERS, QSE_HTB_MANCBS_INLINE_COPIERS,
/** copy the key into the pair but store the value pointer */
QSE_HTB_MANCBS_INLINE_KEY_COPIER, QSE_HTB_MANCBS_INLINE_KEY_COPIER,
/** copy the value into the pair but store the key pointer */
QSE_HTB_MANCBS_INLINE_VALUE_COPIER QSE_HTB_MANCBS_INLINE_VALUE_COPIER
}; };
@ -190,7 +253,17 @@ struct qse_htb_t
qse_htb_pair_t** bucket; qse_htb_pair_t** bucket;
}; };
/**
* The QSE_HTB_COPIER_SIMPLE macros defines a copier that remembers the
* pointer and length of data in a pair.
**/
#define QSE_HTB_COPIER_SIMPLE ((qse_htb_copier_t)1) #define QSE_HTB_COPIER_SIMPLE ((qse_htb_copier_t)1)
/**
* The QSE_HTB_COPIER_INLINE macros defines a copier that copies data into
* a pair.
**/
#define QSE_HTB_COPIER_INLINE ((qse_htb_copier_t)2) #define QSE_HTB_COPIER_INLINE ((qse_htb_copier_t)2)
#define QSE_HTB_COPIER_DEFAULT (QSE_HTB_COPIER_SIMPLE) #define QSE_HTB_COPIER_DEFAULT (QSE_HTB_COPIER_SIMPLE)
@ -227,6 +300,10 @@ extern "C" {
QSE_DEFINE_COMMON_FUNCTIONS (htb) QSE_DEFINE_COMMON_FUNCTIONS (htb)
/**
* The qse_htb_mancbs() functions returns a predefined callback set for
* pair manipulation.
*/
const qse_htb_mancbs_t* qse_htb_mancbs ( const qse_htb_mancbs_t* qse_htb_mancbs (
qse_htb_mancbs_kind_t kind qse_htb_mancbs_kind_t kind
); );
@ -380,24 +457,6 @@ qse_htb_pair_t* qse_htb_update (
qse_size_t vlen /**< value length */ qse_size_t vlen /**< value length */
); );
/**
* The qse_htb_cbserter_t type defines a callback function for qse_htb_cbsert().
* The qse_htb_cbserter() function calls it to allocate a new pair for the
* key pointed to by @a kptr of the length @a klen and the callback context
* @a ctx. The second parameter @a pair is passed the pointer to the existing
* pair for the key or #QSE_NULL in case of no existing key. The callback
* must return a pointer to a new or a reallocated pair. When reallocating the
* existing pair, this callback must destroy the existing pair and return the
* newly reallocated pair. It must return #QSE_NULL for failure.
*/
typedef qse_htb_pair_t* (*qse_htb_cbserter_t) (
qse_htb_t* htb, /**< hash table */
qse_htb_pair_t* pair, /**< pair pointer */
void* kptr, /**< key pointer */
qse_size_t klen, /**< key length */
void* ctx /**< callback context */
);
/** /**
* The qse_htb_cbsert() function inserts a key/value pair by delegating pair * The qse_htb_cbsert() function inserts a key/value pair by delegating pair
* allocation to a callback function. Depending on the callback function, * allocation to a callback function. Depending on the callback function,
@ -407,82 +466,82 @@ typedef qse_htb_pair_t* (*qse_htb_cbserter_t) (
* existing value delimited by a comma if the key is found. * existing value delimited by a comma if the key is found.
* *
* @code * @code
* qse_htb_walk_t print_map_pair (qse_htb_t* map, qse_htb_pair_t* pair, void* ctx) * qse_htb_walk_t print_map_pair (qse_htb_t* map, qse_htb_pair_t* pair, void* ctx)
* { * {
* qse_printf (QSE_T("%.*s[%d] => %.*s[%d]\n"), * qse_printf (QSE_T("%.*s[%d] => %.*s[%d]\n"),
* (int)QSE_HTB_KLEN(pair), QSE_HTB_KPTR(pair), (int)QSE_HTB_KLEN(pair), * (int)QSE_HTB_KLEN(pair), QSE_HTB_KPTR(pair), (int)QSE_HTB_KLEN(pair),
* (int)QSE_HTB_VLEN(pair), QSE_HTB_VPTR(pair), (int)QSE_HTB_VLEN(pair)); * (int)QSE_HTB_VLEN(pair), QSE_HTB_VPTR(pair), (int)QSE_HTB_VLEN(pair));
* return QSE_HTB_WALK_FORWARD; * return QSE_HTB_WALK_FORWARD;
* } * }
* *
* qse_htb_pair_t* cbserter ( * qse_htb_pair_t* cbserter (
* qse_htb_t* htb, qse_htb_pair_t* pair, * qse_htb_t* htb, qse_htb_pair_t* pair,
* void* kptr, qse_size_t klen, void* ctx) * void* kptr, qse_size_t klen, void* ctx)
* { * {
* qse_xstr_t* v = (qse_xstr_t*)ctx; * qse_xstr_t* v = (qse_xstr_t*)ctx;
* if (pair == QSE_NULL) * if (pair == QSE_NULL)
* { * {
* // no existing key for the key * // no existing key for the key
* return qse_htb_allocpair (htb, kptr, klen, v->ptr, v->len); * return qse_htb_allocpair (htb, kptr, klen, v->ptr, v->len);
* } * }
* else * else
* { * {
* // a pair with the key exists. * // a pair with the key exists.
* // in this sample, i will append the new value to the old value * // in this sample, i will append the new value to the old value
* // separated by a comma * // separated by a comma
* qse_htb_pair_t* new_pair; * qse_htb_pair_t* new_pair;
* qse_char_t comma = QSE_T(','); * qse_char_t comma = QSE_T(',');
* qse_byte_t* vptr; * qse_byte_t* vptr;
* *
* // allocate a new pair, but without filling the actual value. * // allocate a new pair, but without filling the actual value.
* // note vptr is given QSE_NULL for that purpose * // note vptr is given QSE_NULL for that purpose
* new_pair = qse_htb_allocpair ( * new_pair = qse_htb_allocpair (
* htb, kptr, klen, QSE_NULL, pair->vlen + 1 + v->len); * htb, kptr, klen, QSE_NULL, pair->vlen + 1 + v->len);
* if (new_pair == QSE_NULL) return QSE_NULL; * if (new_pair == QSE_NULL) return QSE_NULL;
* *
* // fill in the value space * // fill in the value space
* vptr = new_pair->vptr; * vptr = new_pair->vptr;
* qse_memcpy (vptr, pair->vptr, pair->vlen*QSE_SIZEOF(qse_char_t)); * qse_memcpy (vptr, pair->vptr, pair->vlen*QSE_SIZEOF(qse_char_t));
* vptr += pair->vlen*QSE_SIZEOF(qse_char_t); * vptr += pair->vlen*QSE_SIZEOF(qse_char_t);
* qse_memcpy (vptr, &comma, QSE_SIZEOF(qse_char_t)); * qse_memcpy (vptr, &comma, QSE_SIZEOF(qse_char_t));
* vptr += QSE_SIZEOF(qse_char_t); * vptr += QSE_SIZEOF(qse_char_t);
* qse_memcpy (vptr, v->ptr, v->len*QSE_SIZEOF(qse_char_t)); * qse_memcpy (vptr, v->ptr, v->len*QSE_SIZEOF(qse_char_t));
* *
* // this callback requires the old pair to be destroyed * // this callback requires the old pair to be destroyed
* qse_htb_freepair (htb, pair); * qse_htb_freepair (htb, pair);
* *
* // return the new pair * // return the new pair
* return new_pair; * return new_pair;
* } * }
* } * }
* *
* int main () * int main ()
* { * {
* qse_htb_t* s1; * qse_htb_t* s1;
* int i; * int i;
* qse_char_t* keys[] = { QSE_T("one"), QSE_T("two"), QSE_T("three") }; * qse_char_t* keys[] = { QSE_T("one"), QSE_T("two"), QSE_T("three") };
* qse_char_t* vals[] = { QSE_T("1"), QSE_T("2"), QSE_T("3"), QSE_T("4"), QSE_T("5") }; * qse_char_t* vals[] = { QSE_T("1"), QSE_T("2"), QSE_T("3"), QSE_T("4"), QSE_T("5") };
* *
* s1 = qse_htb_open ( * s1 = qse_htb_open (
* QSE_MMGR_GETDFL(), 0, 10, 70, * QSE_MMGR_GETDFL(), 0, 10, 70,
* QSE_SIZEOF(qse_char_t), QSE_SIZEOF(qse_char_t) * QSE_SIZEOF(qse_char_t), QSE_SIZEOF(qse_char_t)
* ); // note error check is skipped * ); // note error check is skipped
* qse_htb_setmancbs (s1, &mancbs1); * qse_htb_setmancbs (s1, &mancbs1);
* *
* for (i = 0; i < QSE_COUNTOF(vals); i++) * for (i = 0; i < QSE_COUNTOF(vals); i++)
* { * {
* qse_xstr_t ctx; * qse_xstr_t ctx;
* ctx.ptr = vals[i]; ctx.len = qse_strlen(vals[i]); * ctx.ptr = vals[i]; ctx.len = qse_strlen(vals[i]);
* qse_htb_cbsert (s1, * qse_htb_cbsert (s1,
* keys[i%QSE_COUNTOF(keys)], qse_strlen(keys[i%QSE_COUNTOF(keys)]), * keys[i%QSE_COUNTOF(keys)], qse_strlen(keys[i%QSE_COUNTOF(keys)]),
* cbserter, &ctx * cbserter, &ctx
* ); // note error check is skipped * ); // note error check is skipped
* } * }
* qse_htb_walk (s1, print_map_pair, QSE_NULL); * qse_htb_walk (s1, print_map_pair, QSE_NULL);
* *
* qse_htb_close (s1); * qse_htb_close (s1);
* return 0; * return 0;
* } * }
* @endcode * @endcode
*/ */
qse_htb_pair_t* qse_htb_cbsert ( qse_htb_pair_t* qse_htb_cbsert (

View File

@ -47,6 +47,7 @@
# define qse_map_ensert(map,kptr,klen,vptr,vlen) qse_htb_ensert(map,kptr,klen,vptr,vlen) # define qse_map_ensert(map,kptr,klen,vptr,vlen) qse_htb_ensert(map,kptr,klen,vptr,vlen)
# define qse_map_insert(map,kptr,klen,vptr,vlen) qse_htb_insert(map,kptr,klen,vptr,vlen) # define qse_map_insert(map,kptr,klen,vptr,vlen) qse_htb_insert(map,kptr,klen,vptr,vlen)
# define qse_map_update(map,kptr,klen,vptr,vlen) qse_htb_update(map,kptr,klen,vptr,vlen) # define qse_map_update(map,kptr,klen,vptr,vlen) qse_htb_update(map,kptr,klen,vptr,vlen)
# define qse_map_cbsert(map,kptr,klen,cb,ctx) qse_htb_cbsert(map,kptr,klen,cb,ctx)
# define qse_map_delete(map,kptr,klen) qse_htb_delete(map,kptr,klen) # define qse_map_delete(map,kptr,klen) qse_htb_delete(map,kptr,klen)
# define qse_map_clear(map) qse_htb_clear(map) # define qse_map_clear(map) qse_htb_clear(map)
# define qse_map_walk(map,walker,ctx) qse_htb_walk(map,walker,ctx) # define qse_map_walk(map,walker,ctx) qse_htb_walk(map,walker,ctx)
@ -59,6 +60,8 @@
# define qse_map_t qse_htb_t # define qse_map_t qse_htb_t
# define qse_map_pair_t qse_htb_pair_t # define qse_map_pair_t qse_htb_pair_t
# define qse_map_mancbs_t qse_htb_mancbs_t # define qse_map_mancbs_t qse_htb_mancbs_t
# define qse_map_cbserter_t qse_htb_cbserter_t
# define qse_map_walker_t qse_htb_walker_t
# define QSE_MAP_COPIER_SIMPLE QSE_HTB_COPIER_SIMPLE # define QSE_MAP_COPIER_SIMPLE QSE_HTB_COPIER_SIMPLE
# define QSE_MAP_COPIER_INLINE QSE_HTB_COPIER_INLINE # define QSE_MAP_COPIER_INLINE QSE_HTB_COPIER_INLINE
# define QSE_MAP_COPIER_DEFAULT QSE_HTB_COPIER_DEFAULT # define QSE_MAP_COPIER_DEFAULT QSE_HTB_COPIER_DEFAULT
@ -100,6 +103,7 @@
# define qse_map_ensert(map,kptr,klen,vptr,vlen) qse_rbt_ensert(map,kptr,klen,vptr,vlen) # define qse_map_ensert(map,kptr,klen,vptr,vlen) qse_rbt_ensert(map,kptr,klen,vptr,vlen)
# define qse_map_insert(map,kptr,klen,vptr,vlen) qse_rbt_insert(map,kptr,klen,vptr,vlen) # define qse_map_insert(map,kptr,klen,vptr,vlen) qse_rbt_insert(map,kptr,klen,vptr,vlen)
# define qse_map_update(map,kptr,klen,vptr,vlen) qse_rbt_update(map,kptr,klen,vptr,vlen) # define qse_map_update(map,kptr,klen,vptr,vlen) qse_rbt_update(map,kptr,klen,vptr,vlen)
# define qse_map_cbsert(map,kptr,klen,cb,ctx) qse_rbt_cbsert(map,kptr,klen,cb,ctx)
# define qse_map_delete(map,kptr,klen) qse_rbt_delete(map,kptr,klen) # define qse_map_delete(map,kptr,klen) qse_rbt_delete(map,kptr,klen)
# define qse_map_clear(map) qse_rbt_clear(map) # define qse_map_clear(map) qse_rbt_clear(map)
# define qse_map_walk(map,walker,ctx) qse_rbt_walk(map,walker,ctx) # define qse_map_walk(map,walker,ctx) qse_rbt_walk(map,walker,ctx)
@ -112,6 +116,8 @@
# define qse_map_t qse_rbt_t # define qse_map_t qse_rbt_t
# define qse_map_pair_t qse_rbt_pair_t # define qse_map_pair_t qse_rbt_pair_t
# define qse_map_mancbs_t qse_rbt_mancbs_t # define qse_map_mancbs_t qse_rbt_mancbs_t
# define qse_map_cbserter_t qse_rbt_cbserter_t
# define qse_map_walker_t qse_rbt_walker_t
# define QSE_MAP_COPIER_SIMPLE QSE_RBT_COPIER_SIMPLE # define QSE_MAP_COPIER_SIMPLE QSE_RBT_COPIER_SIMPLE
# define QSE_MAP_COPIER_INLINE QSE_RBT_COPIER_INLINE # define QSE_MAP_COPIER_INLINE QSE_RBT_COPIER_INLINE
# define QSE_MAP_COPIER_DEFAULT QSE_RBT_COPIER_DEFAULT # define QSE_MAP_COPIER_DEFAULT QSE_RBT_COPIER_DEFAULT

View File

@ -25,7 +25,44 @@
#include <qse/macros.h> #include <qse/macros.h>
/**@file /**@file
* A red-black tree is a self-balancing binary search tree. * This file provides a red-black tree encapsulated in the #qse_rbt_t type that
* implements a self-balancing binary search tree.Its interface is very close
* to #qse_htb_t.
*
* This sample code adds a series of keys and values and print them
* in descending key order.
* @code
* #include <qse/cmn/rbt.h>
* #include <qse/cmn/mem.h>
* #include <qse/cmn/stdio.h>
*
* static qse_rbt_walk_t walk (qse_rbt_t* rbt, qse_rbt_pair_t* pair, void* ctx)
* {
* qse_printf (QSE_T("key = %d, value = %d\n"),
* *(int*)QSE_RBT_KPTR(pair), *(int*)QSE_RBT_VPTR(pair));
* return QSE_RBT_WALK_FORWARD;
* }
*
* int main ()
* {
* qse_rbt_t* s1;
* int i;
*
* s1 = qse_rbt_open (QSE_MMGR_GETDFL(), 0, 1, 1); // error handling skipped
* qse_rbt_setmancbs (s1, qse_rbt_mancbs(QSE_RBT_MANCBS_INLINE_COPIERS));
*
* for (i = 0; i < 20; i++)
* {
* int x = i * 20;
* qse_rbt_insert (s1, &i, QSE_SIZEOF(i), &x, QSE_SIZEOF(x)); // eror handling skipped
* }
*
* qse_rbt_rwalk (s1, walk, QSE_NULL);
*
* qse_rbt_close (s1);
* return 0;
* }
* @endcode
*/ */
typedef struct qse_rbt_t qse_rbt_t; typedef struct qse_rbt_t qse_rbt_t;
@ -102,11 +139,29 @@ typedef void (*qse_rbt_keeper_t) (
* The qse_rbt_walker_t defines a pair visitor. * The qse_rbt_walker_t defines a pair visitor.
*/ */
typedef qse_rbt_walk_t (*qse_rbt_walker_t) ( typedef qse_rbt_walk_t (*qse_rbt_walker_t) (
qse_rbt_t* rbt, /**< rbt */ qse_rbt_t* rbt, /**< red-black tree */
qse_rbt_pair_t* pair, /**< pointer to a key/value pair */ qse_rbt_pair_t* pair, /**< pointer to a key/value pair */
void* ctx /**< pointer to user-defined data */ void* ctx /**< pointer to user-defined data */
); );
/**
* The qse_rbt_cbserter_t type defines a callback function for qse_rbt_cbsert().
* The qse_rbt_cbserter() function calls it to allocate a new pair for the
* key pointed to by @a kptr of the length @a klen and the callback context
* @a ctx. The second parameter @a pair is passed the pointer to the existing
* pair for the key or #QSE_NULL in case of no existing key. The callback
* must return a pointer to a new or a reallocated pair. When reallocating the
* existing pair, this callback must destroy the existing pair and return the
* newly reallocated pair. It must return #QSE_NULL for failure.
*/
typedef qse_rbt_pair_t* (*qse_rbt_cbserter_t) (
qse_rbt_t* rbt, /**< red-black tree */
qse_rbt_pair_t* pair, /**< pair pointer */
void* kptr, /**< key pointer */
qse_size_t klen, /**< key length */
void* ctx /**< callback context */
);
/** /**
* The qse_rbt_pair_t type defines red-black tree pair. A pair is composed * The qse_rbt_pair_t type defines red-black tree pair. A pair is composed
* of a key and a value. It maintains pointers to the beginning of a key and * of a key and a value. It maintains pointers to the beginning of a key and
@ -132,6 +187,10 @@ struct qse_rbt_pair_t
typedef struct qse_rbt_mancbs_t qse_rbt_mancbs_t; typedef struct qse_rbt_mancbs_t qse_rbt_mancbs_t;
/**
* The qse_rbt_mancbs_t type defines callback function sets for key/value
* pair manipulation.
*/
struct qse_rbt_mancbs_t struct qse_rbt_mancbs_t
{ {
qse_rbt_copier_t copier[2]; /**< key and value copier */ qse_rbt_copier_t copier[2]; /**< key and value copier */
@ -140,11 +199,19 @@ struct qse_rbt_mancbs_t
qse_rbt_keeper_t keeper; /**< value keeper */ qse_rbt_keeper_t keeper; /**< value keeper */
}; };
/**
* The qse_rbt_mancbs_kind_t type defines the type of predefined
* callback set for pair manipulation.
*/
enum qse_rbt_mancbs_kind_t enum qse_rbt_mancbs_kind_t
{ {
/** store the key and the value pointer */
QSE_RBT_MANCBS_DEFAULT, QSE_RBT_MANCBS_DEFAULT,
/** copy both key and value into the pair */
QSE_RBT_MANCBS_INLINE_COPIERS, QSE_RBT_MANCBS_INLINE_COPIERS,
/** copy the key into the pair but store the value pointer */
QSE_RBT_MANCBS_INLINE_KEY_COPIER, QSE_RBT_MANCBS_INLINE_KEY_COPIER,
/** copy the value into the pair but store the key pointer */
QSE_RBT_MANCBS_INLINE_VALUE_COPIER QSE_RBT_MANCBS_INLINE_VALUE_COPIER
}; };
@ -203,6 +270,10 @@ extern "C" {
QSE_DEFINE_COMMON_FUNCTIONS (rbt) QSE_DEFINE_COMMON_FUNCTIONS (rbt)
/**
* The qse_rbt_mancbs() functions returns a predefined callback set for
* pair manipulation.
*/
const qse_rbt_mancbs_t* qse_rbt_mancbs ( const qse_rbt_mancbs_t* qse_rbt_mancbs (
qse_rbt_mancbs_kind_t kind qse_rbt_mancbs_kind_t kind
); );
@ -251,7 +322,7 @@ const qse_rbt_mancbs_t* qse_rbt_getmancbs (
/** /**
* The qse_rbt_setmancbs() function sets internal manipulation callback * The qse_rbt_setmancbs() function sets internal manipulation callback
* functions for data construction, destruction, resizing, hashing, etc. * functions for data construction, destruction, comparison, etc.
*/ */
void qse_rbt_setmancbs ( void qse_rbt_setmancbs (
qse_rbt_t* rbt, /**< red-black tree */ qse_rbt_t* rbt, /**< red-black tree */
@ -335,6 +406,101 @@ qse_rbt_pair_t* qse_rbt_update (
qse_size_t vlen /**< value length */ qse_size_t vlen /**< value length */
); );
/**
* The qse_rbt_cbsert() function inserts a key/value pair by delegating pair
* allocation to a callback function. Depending on the callback function,
* it may behave like qse_rbt_insert(), qse_rbt_upsert(), qse_rbt_update(),
* qse_rbt_ensert(), or totally differently. The sample code below inserts
* a new pair if the key is not found and appends the new value to the
* existing value delimited by a comma if the key is found.
*
* @code
* qse_rbt_walk_t print_map_pair (qse_rbt_t* map, qse_rbt_pair_t* pair, void* ctx)
* {
* qse_printf (QSE_T("%.*s[%d] => %.*s[%d]\n"),
* (int)QSE_RBT_KLEN(pair), QSE_RBT_KPTR(pair), (int)QSE_RBT_KLEN(pair),
* (int)QSE_RBT_VLEN(pair), QSE_RBT_VPTR(pair), (int)QSE_RBT_VLEN(pair));
* return QSE_RBT_WALK_FORWARD;
* }
*
* qse_rbt_pair_t* cbserter (
* qse_rbt_t* rbt, qse_rbt_pair_t* pair,
* void* kptr, qse_size_t klen, void* ctx)
* {
* qse_xstr_t* v = (qse_xstr_t*)ctx;
* if (pair == QSE_NULL)
* {
* // no existing key for the key
* return qse_rbt_allocpair (rbt, kptr, klen, v->ptr, v->len);
* }
* else
* {
* // a pair with the key exists.
* // in this sample, i will append the new value to the old value
* // separated by a comma
* qse_rbt_pair_t* new_pair;
* qse_char_t comma = QSE_T(',');
* qse_byte_t* vptr;
*
* // allocate a new pair, but without filling the actual value.
* // note vptr is given QSE_NULL for that purpose
* new_pair = qse_rbt_allocpair (
* rbt, kptr, klen, QSE_NULL, pair->vlen + 1 + v->len);
* if (new_pair == QSE_NULL) return QSE_NULL;
*
* // fill in the value space
* vptr = new_pair->vptr;
* qse_memcpy (vptr, pair->vptr, pair->vlen*QSE_SIZEOF(qse_char_t));
* vptr += pair->vlen*QSE_SIZEOF(qse_char_t);
* qse_memcpy (vptr, &comma, QSE_SIZEOF(qse_char_t));
* vptr += QSE_SIZEOF(qse_char_t);
* qse_memcpy (vptr, v->ptr, v->len*QSE_SIZEOF(qse_char_t));
*
* // this callback requires the old pair to be destroyed
* qse_rbt_freepair (rbt, pair);
*
* // return the new pair
* return new_pair;
* }
* }
*
* int main ()
* {
* qse_rbt_t* s1;
* int i;
* qse_char_t* keys[] = { QSE_T("one"), QSE_T("two"), QSE_T("three") };
* qse_char_t* vals[] = { QSE_T("1"), QSE_T("2"), QSE_T("3"), QSE_T("4"), QSE_T("5") };
*
* s1 = qse_rbt_open (
* QSE_MMGR_GETDFL(), 0,
* QSE_SIZEOF(qse_char_t), QSE_SIZEOF(qse_char_t)
* ); // note error check is skipped
* qse_rbt_setmancbs (s1, &mancbs1);
*
* for (i = 0; i < QSE_COUNTOF(vals); i++)
* {
* qse_xstr_t ctx;
* ctx.ptr = vals[i]; ctx.len = qse_strlen(vals[i]);
* qse_rbt_cbsert (s1,
* keys[i%QSE_COUNTOF(keys)], qse_strlen(keys[i%QSE_COUNTOF(keys)]),
* cbserter, &ctx
* ); // note error check is skipped
* }
* qse_rbt_walk (s1, print_map_pair, QSE_NULL);
*
* qse_rbt_close (s1);
* return 0;
* }
* @endcode
*/
qse_rbt_pair_t* qse_rbt_cbsert (
qse_rbt_t* rbt, /**< red-black tree */
void* kptr, /**< key pointer */
qse_size_t klen, /**< key length */
qse_rbt_cbserter_t cbserter, /**< callback function */
void* ctx /**< callback context */
);
/** /**
* The qse_rbt_delete() function deletes a pair with a matching key * The qse_rbt_delete() function deletes a pair with a matching key
* @return 0 on success, -1 on failure * @return 0 on success, -1 on failure
@ -372,6 +538,39 @@ void qse_rbt_rwalk (
void* ctx /**< pointer to user-specific data */ void* ctx /**< pointer to user-specific data */
); );
/**
* The qse_rbt_allocpair() function allocates a pair for a key and a value
* given. But it does not chain the pair allocated into the red-black tree @a rbt.
* Use this function at your own risk.
*
* Take note of he following special behavior when the copier is
* #QSE_RBT_COPIER_INLINE.
* - If @a kptr is #QSE_NULL, the key space of the size @a klen is reserved but
* not propagated with any data.
* - If @a vptr is #QSE_NULL, the value space of the size @a vlen is reserved
* but not propagated with any data.
*/
qse_rbt_pair_t* qse_rbt_allocpair (
qse_rbt_t* rbt,
void* kptr,
qse_size_t klen,
void* vptr,
qse_size_t vlen
);
/**
* The qse_rbt_freepair() function destroys a pair. But it does not detach
* the pair destroyed from the red-black tree @a rbt. Use this function at your
* own risk.
*/
void qse_rbt_freepair (
qse_rbt_t* rbt,
qse_rbt_pair_t* pair
);
/**
* The qse_rbt_dflcomp() function defines the default key comparator.
*/
int qse_rbt_dflcomp ( int qse_rbt_dflcomp (
qse_rbt_t* rbt, qse_rbt_t* rbt,
const void* kptr1, const void* kptr1,

View File

@ -1,5 +1,5 @@
/* /*
* $Id: str.h 356 2010-09-07 12:29:25Z hyunghwan.chung $ * $Id: str.h 366 2010-10-30 12:49:18Z hyunghwan.chung $
* *
Copyright 2006-2009 Chung, Hyung-Hwan. Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE. This file is part of QSE.
@ -229,7 +229,7 @@ qse_size_t qse_strfcpy (
/** /**
* The qse_strfncpy() function formats a string by position. * The qse_strfncpy() function formats a string by position.
* It differs from qse_strfcpy() in that @str is an array of the * It differs from qse_strfcpy() in that @a str is an array of the
* #qse_cstr_t type. * #qse_cstr_t type.
* @sa qse_strfcpy, qse_strxfcpy, qse_strxfncpy * @sa qse_strfcpy, qse_strxfcpy, qse_strxfncpy
*/ */

View File

@ -140,7 +140,7 @@ void qse_xma_close (
* The qse_xma_init() initializes a memory allocator. If you have the qse_xma_t * The qse_xma_init() initializes a memory allocator. If you have the qse_xma_t
* structure statically declared or already allocated, you may pass the pointer * structure statically declared or already allocated, you may pass the pointer
* to this function instead of calling qse_xma_open(). It obtains a memory zone * to this function instead of calling qse_xma_open(). It obtains a memory zone
* of @a zonesize bytes with the memory manager @mmgr. Unlike qse_xma_open(), * of @a zonesize bytes with the memory manager @a mmgr. Unlike qse_xma_open(),
* it does not accept the extension size, thus not creating an extention area. * it does not accept the extension size, thus not creating an extention area.
* @return @a xma on success, #QSE_NULL on failure * @return @a xma on success, #QSE_NULL on failure
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* $Id: htb.c 365 2010-10-29 13:54:36Z hyunghwan.chung $ * $Id: htb.c 366 2010-10-30 12:49:18Z hyunghwan.chung $
* *
Copyright 2006-2009 Chung, Hyung-Hwan. Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE. This file is part of QSE.
@ -23,16 +23,18 @@
QSE_IMPLEMENT_COMMON_FUNCTIONS (htb) QSE_IMPLEMENT_COMMON_FUNCTIONS (htb)
#define htb_t qse_htb_t #define htb_t qse_htb_t
#define pair_t qse_htb_pair_t #define pair_t qse_htb_pair_t
#define copier_t qse_htb_copier_t #define copier_t qse_htb_copier_t
#define freeer_t qse_htb_freeer_t #define freeer_t qse_htb_freeer_t
#define hasher_t qse_htb_hasher_t #define hasher_t qse_htb_hasher_t
#define comper_t qse_htb_comper_t #define comper_t qse_htb_comper_t
#define keeper_t qse_htb_keeper_t #define keeper_t qse_htb_keeper_t
#define sizer_t qse_htb_sizer_t #define sizer_t qse_htb_sizer_t
#define walker_t qse_htb_walker_t #define walker_t qse_htb_walker_t
#define cbserter_t qse_htb_cbserter_t #define cbserter_t qse_htb_cbserter_t
#define mancbs_t qse_htb_mancbs_t
#define mancbs_kind_t qse_htb_mancbs_kind_t
#define KPTR(p) QSE_HTB_KPTR(p) #define KPTR(p) QSE_HTB_KPTR(p)
#define KLEN(p) QSE_HTB_KLEN(p) #define KLEN(p) QSE_HTB_KLEN(p)
@ -153,7 +155,7 @@ static QSE_INLINE pair_t* change_pair_val (
{ {
if (ovlen == vlen) if (ovlen == vlen)
{ {
QSE_MEMCPY (VPTR(pair), vptr, VTOB(htb,vlen)); if (vptr) QSE_MEMCPY (VPTR(pair), vptr, VTOB(htb,vlen));
} }
else else
{ {
@ -185,7 +187,7 @@ static QSE_INLINE pair_t* change_pair_val (
return pair; return pair;
} }
static qse_htb_mancbs_t mancbs[] = static mancbs_t mancbs[] =
{ {
{ {
{ {
@ -248,7 +250,7 @@ static qse_htb_mancbs_t mancbs[] =
} }
}; };
const qse_htb_mancbs_t* qse_htb_mancbs (qse_htb_mancbs_kind_t kind) const mancbs_t* qse_htb_mancbs (mancbs_kind_t kind)
{ {
return &mancbs[kind]; return &mancbs[kind];
}; };
@ -330,12 +332,12 @@ void qse_htb_fini (htb_t* htb)
QSE_MMGR_FREE (htb->mmgr, htb->bucket); QSE_MMGR_FREE (htb->mmgr, htb->bucket);
} }
const qse_htb_mancbs_t* qse_htb_getmancbs (htb_t* htb) const mancbs_t* qse_htb_getmancbs (htb_t* htb)
{ {
return htb->mancbs; return htb->mancbs;
} }
void qse_htb_setmancbs (htb_t* htb, const qse_htb_mancbs_t* mancbs) void qse_htb_setmancbs (htb_t* htb, const mancbs_t* mancbs)
{ {
QSE_ASSERT (mancbs != QSE_NULL); QSE_ASSERT (mancbs != QSE_NULL);
htb->mancbs = mancbs; htb->mancbs = mancbs;

View File

@ -23,14 +23,17 @@
QSE_IMPLEMENT_COMMON_FUNCTIONS (rbt) QSE_IMPLEMENT_COMMON_FUNCTIONS (rbt)
#define rbt_t qse_rbt_t #define rbt_t qse_rbt_t
#define pair_t qse_rbt_pair_t #define pair_t qse_rbt_pair_t
#define id_t qse_rbt_id_t #define id_t qse_rbt_id_t
#define copier_t qse_rbt_copier_t #define copier_t qse_rbt_copier_t
#define freeer_t qse_rbt_freeer_t #define freeer_t qse_rbt_freeer_t
#define comper_t qse_rbt_comper_t #define comper_t qse_rbt_comper_t
#define keeper_t qse_rbt_keeper_t #define keeper_t qse_rbt_keeper_t
#define walker_t qse_rbt_walker_t #define walker_t qse_rbt_walker_t
#define cbserter_t qse_rbt_cbserter_t
#define mancbs_t qse_rbt_mancbs_t
#define mancbs_kind_t qse_rbt_mancbs_kind_t
#define KPTR(p) QSE_RBT_KPTR(p) #define KPTR(p) QSE_RBT_KPTR(p)
#define KLEN(p) QSE_RBT_KLEN(p) #define KLEN(p) QSE_RBT_KLEN(p)
@ -134,7 +137,7 @@ QSE_INLINE void qse_rbt_freepair (rbt_t* rbt, pair_t* pair)
QSE_MMGR_FREE (rbt->mmgr, pair); QSE_MMGR_FREE (rbt->mmgr, pair);
} }
static qse_rbt_mancbs_t mancbs[] = static mancbs_t mancbs[] =
{ {
{ {
{ {
@ -189,7 +192,7 @@ static qse_rbt_mancbs_t mancbs[] =
} }
}; };
const qse_rbt_mancbs_t* qse_rbt_mancbs (qse_rbt_mancbs_kind_t kind) const mancbs_t* qse_rbt_mancbs (mancbs_kind_t kind)
{ {
return &mancbs[kind]; return &mancbs[kind];
}; };
@ -257,12 +260,12 @@ void qse_rbt_fini (rbt_t* rbt)
qse_rbt_clear (rbt); qse_rbt_clear (rbt);
} }
const qse_rbt_mancbs_t* qse_rbt_getmancbs (rbt_t* rbt) const mancbs_t* qse_rbt_getmancbs (rbt_t* rbt)
{ {
return rbt->mancbs; return rbt->mancbs;
} }
void qse_rbt_setmancbs (rbt_t* rbt, const qse_rbt_mancbs_t* mancbs) void qse_rbt_setmancbs (rbt_t* rbt, const mancbs_t* mancbs)
{ {
QSE_ASSERT (mancbs != QSE_NULL); QSE_ASSERT (mancbs != QSE_NULL);
rbt->mancbs = mancbs; rbt->mancbs = mancbs;
@ -450,7 +453,7 @@ static pair_t* change_pair_val (
{ {
if (ovlen == vlen) if (ovlen == vlen)
{ {
QSE_MEMCPY (VPTR(pair), vptr, VTOB(rbt,vlen)); if (vptr) QSE_MEMCPY (VPTR(pair), vptr, VTOB(rbt,vlen));
} }
else else
{ {
@ -597,6 +600,101 @@ pair_t* qse_rbt_update (
return insert (rbt, kptr, klen, vptr, vlen, UPDATE); return insert (rbt, kptr, klen, vptr, vlen, UPDATE);
} }
pair_t* qse_rbt_cbsert (
rbt_t* rbt, void* kptr, size_t klen, cbserter_t cbserter, void* ctx)
{
pair_t* xcur = rbt->root;
pair_t* xpar = QSE_NULL;
pair_t* xnew;
while (!IS_NIL(rbt,xcur))
{
int n = rbt->mancbs->comper (rbt, kptr, klen, xcur->kptr, xcur->klen);
if (n == 0)
{
/* back up the contents of the current pair
* in case it is reallocated */
pair_t tmp = *xcur;
/* call the callback function to manipulate the pair */
xnew = cbserter (rbt, xcur, kptr, klen, ctx);
if (xnew == QSE_NULL)
{
/* error returned by the callback function */
return QSE_NULL;
}
if (xnew != xcur)
{
/* the current pair has been reallocated, which implicitly
* means the previous contents were wiped out. so the contents
* backed up will be used for restoration/migration */
xnew->color = tmp.color;
xnew->left = tmp.left;
xnew->right = tmp.right;
xnew->parent = tmp.parent;
if (tmp.parent)
{
if (tmp.parent->left == xcur)
{
tmp.parent->left = xnew;
}
else
{
QSE_ASSERT (tmp.parent->right == xcur);
tmp.parent->right = xnew;
}
}
if (!IS_NIL(rbt,tmp.left)) tmp.left->parent = xnew;
if (!IS_NIL(rbt,tmp.right)) tmp.right->parent = xnew;
if (xcur == rbt->root) rbt->root = xnew;
}
return xnew;
}
xpar = xcur;
if (n > 0) xcur = xcur->right;
else /* if (n < 0) */ xcur = xcur->left;
}
xnew = cbserter (rbt, QSE_NULL, kptr, klen, ctx);
if (xnew == QSE_NULL) return QSE_NULL;
if (xpar == QSE_NULL)
{
/* the tree contains no pair */
QSE_ASSERT (rbt->root == &rbt->nil);
rbt->root = xnew;
}
else
{
/* perform normal binary insert */
int n = rbt->mancbs->comper (rbt, kptr, klen, xpar->kptr, xpar->klen);
if (n > 0)
{
QSE_ASSERT (xpar->right == &rbt->nil);
xpar->right = xnew;
}
else
{
QSE_ASSERT (xpar->left == &rbt->nil);
xpar->left = xnew;
}
xnew->parent = xpar;
adjust (rbt, xnew);
}
rbt->root->color = QSE_RBT_BLACK;
return xnew;
}
static void adjust_for_delete (rbt_t* rbt, pair_t* pair, pair_t* par) static void adjust_for_delete (rbt_t* rbt, pair_t* pair, pair_t* par)
{ {
while (pair != rbt->root && pair->color == QSE_RBT_BLACK) while (pair != rbt->root && pair->color == QSE_RBT_BLACK)

View File

@ -109,17 +109,120 @@ static int test2 ()
qse_printf (QSE_T("-------------------\n")); qse_printf (QSE_T("-------------------\n"));
qse_rbt_upsert (s1, QSE_T("hello"), 5, QSE_T("dr. gorilla"), 11); qse_rbt_upsert (s1, QSE_T("hello"), 5, QSE_T("dr. gorilla"), 11);
qse_rbt_upsert (s1, QSE_T("thinkpad"), 8, QSE_T("x61 rocks"), 9); qse_rbt_upsert (s1, QSE_T("thinkpad"), 8, QSE_T("x61 rocks on"), 13);
qse_rbt_ensert (s1, QSE_T("vista"), 5, QSE_T("microsoft"), 9); qse_rbt_ensert (s1, QSE_T("vista"), 5, QSE_T("microsoft"), 9);
qse_rbt_update (s1, QSE_T("world"), 5, QSE_T("baseball classic"), 16);
qse_rbt_rwalk (s1, walk2, QSE_NULL); qse_rbt_rwalk (s1, walk2, QSE_NULL);
qse_rbt_close (s1); qse_rbt_close (s1);
return 0; return 0;
} }
qse_rbt_walk_t print_map_pair (qse_rbt_t* map, qse_rbt_pair_t* pair, void* arg)
{
qse_printf (QSE_T("%.*s[%d] => %.*s[%d]\n"),
(int)QSE_RBT_KLEN(pair), QSE_RBT_KPTR(pair), (int)QSE_RBT_KLEN(pair),
(int)QSE_RBT_VLEN(pair), QSE_RBT_VPTR(pair), (int)QSE_RBT_VLEN(pair));
return QSE_RBT_WALK_FORWARD;
}
static qse_rbt_pair_t* test5_cbserter (
qse_rbt_t* rbt, qse_rbt_pair_t* pair,
void* kptr, qse_size_t klen, void* ctx)
{
qse_xstr_t* v = (qse_xstr_t*)ctx;
if (pair == QSE_NULL)
{
/* no existing key for the key */
return qse_rbt_allocpair (rbt, kptr, klen, v->ptr, v->len);
}
else
{
/* a pair with the key exists.
* in this sample, i will append the new value to the old value
* separated by a comma */
qse_rbt_pair_t* new_pair;
qse_char_t comma = QSE_T(',');
qse_byte_t* vptr;
/* allocate a new pair, but without filling the actual value.
* note vptr is given QSE_NULL for that purpose */
new_pair = qse_rbt_allocpair (
rbt, kptr, klen, QSE_NULL, pair->vlen + 1 + v->len);
if (new_pair == QSE_NULL) return QSE_NULL;
/* fill in the value space */
vptr = new_pair->vptr;
qse_memcpy (vptr, pair->vptr, pair->vlen*QSE_SIZEOF(qse_char_t));
vptr += pair->vlen*QSE_SIZEOF(qse_char_t);
qse_memcpy (vptr, &comma, QSE_SIZEOF(qse_char_t));
vptr += QSE_SIZEOF(qse_char_t);
qse_memcpy (vptr, v->ptr, v->len*QSE_SIZEOF(qse_char_t));
/* this callback requires the old pair to be destroyed */
qse_rbt_freepair (rbt, pair);
/* return the new pair */
return new_pair;
}
}
static int test5 ()
{
qse_rbt_t* s1;
int i;
qse_char_t* keys[] =
{
QSE_T("one"), QSE_T("two"), QSE_T("three")
};
qse_char_t* vals[] =
{
QSE_T("1"), QSE_T("2"), QSE_T("3"), QSE_T("4"), QSE_T("5"),
};
s1 = qse_rbt_open (QSE_MMGR_GETDFL(), 0,
QSE_SIZEOF(qse_char_t), QSE_SIZEOF(qse_char_t));
if (s1 == QSE_NULL)
{
qse_printf (QSE_T("cannot open a hash table\n"));
return -1;
}
qse_rbt_setmancbs (s1, qse_rbt_mancbs(QSE_RBT_MANCBS_INLINE_COPIERS));
for (i = 0; i < QSE_COUNTOF(vals); i++)
{
qse_xstr_t ctx;
qse_printf (QSE_T("setting a key [%s] and a value [%s]: "), keys[i%QSE_COUNTOF(keys)], vals[i]);
ctx.ptr = vals[i];
ctx.len = qse_strlen(vals[i]);
if (qse_rbt_cbsert (s1,
keys[i%QSE_COUNTOF(keys)],
qse_strlen(keys[i%QSE_COUNTOF(keys)]),
test5_cbserter, &ctx) == QSE_NULL)
{
qse_printf (QSE_T("[FAILED]\n"));
}
else
{
qse_printf (QSE_T("[OK]\n"));
}
}
qse_rbt_walk (s1, print_map_pair, QSE_NULL);
qse_rbt_close (s1);
return 0;
}
int main () int main ()
{ {
R (test1); R (test1);
R (test2); R (test2);
R (test5);
return 0; return 0;
} }