enhanced the red-black tree
This commit is contained in:
parent
03c87a4f6a
commit
e187cd9dae
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: htb.h 328 2010-07-08 06:58:44Z hyunghwan.chung $
|
* $Id: htb.h 331 2010-07-13 11:18:30Z 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.
|
||||||
@ -52,8 +52,8 @@ typedef enum qse_htb_id_t qse_htb_id_t;
|
|||||||
*/
|
*/
|
||||||
typedef void* (*qse_htb_copier_t) (
|
typedef void* (*qse_htb_copier_t) (
|
||||||
qse_htb_t* htb /* hash table */,
|
qse_htb_t* htb /* hash table */,
|
||||||
void* dptr /* the pointer to a key or a value */,
|
void* dptr /* pointer to a key or a value */,
|
||||||
qse_size_t dlen /* the length of a key or a value */
|
qse_size_t dlen /* length of a key or a value */
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,15 +61,15 @@ typedef void* (*qse_htb_copier_t) (
|
|||||||
*/
|
*/
|
||||||
typedef void (*qse_htb_freeer_t) (
|
typedef void (*qse_htb_freeer_t) (
|
||||||
qse_htb_t* htb, /**< hash table */
|
qse_htb_t* htb, /**< hash table */
|
||||||
void* dptr, /**< the pointer to a key or a value */
|
void* dptr, /**< pointer to a key or a value */
|
||||||
qse_size_t dlen /**< the length of a key or a value */
|
qse_size_t dlen /**< length of a key or a value */
|
||||||
);
|
);
|
||||||
|
|
||||||
/* key hasher */
|
/* key hasher */
|
||||||
typedef qse_size_t (*qse_htb_hasher_t) (
|
typedef qse_size_t (*qse_htb_hasher_t) (
|
||||||
qse_htb_t* htb, /**< hash table */
|
qse_htb_t* htb, /**< hash table */
|
||||||
const void* kptr, /**< the pointer to a key */
|
const void* kptr, /**< pointer to a key */
|
||||||
qse_size_t klen /**< the length of a key in bytes */
|
qse_size_t klen /**< length of a key in bytes */
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,10 +82,10 @@ typedef qse_size_t (*qse_htb_hasher_t) (
|
|||||||
*/
|
*/
|
||||||
typedef int (*qse_htb_comper_t) (
|
typedef int (*qse_htb_comper_t) (
|
||||||
qse_htb_t* htb, /**< hash table */
|
qse_htb_t* htb, /**< hash table */
|
||||||
const void* kptr1, /**< the pointer to a key */
|
const void* kptr1, /**< pointer to a key */
|
||||||
qse_size_t klen1, /**< the length of a key */
|
qse_size_t klen1, /**< length of a key */
|
||||||
const void* kptr2, /**< the pointer to a key */
|
const void* kptr2, /**< pointer to a key */
|
||||||
qse_size_t klen2 /**< the length of a key */
|
qse_size_t klen2 /**< length of a key */
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,7 +101,7 @@ typedef void (*qse_htb_keeper_t) (
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The qse_htb_sizer_T type defines a bucket size claculator that is called
|
* The qse_htb_sizer_t type defines a bucket size claculator that is called
|
||||||
* when hash table should resize the bucket. The current bucket size +1 is passed
|
* when hash table should resize the bucket. The current bucket size +1 is passed
|
||||||
* as the hint.
|
* as the hint.
|
||||||
*/
|
*/
|
||||||
@ -123,15 +123,17 @@ typedef qse_htb_walk_t (*qse_htb_walker_t) (
|
|||||||
* 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
|
||||||
* plus their length. The length is scaled down with the scale factor
|
* plus their length. The length is scaled down with the scale factor
|
||||||
* specified in an owning htb. Use macros defined in the
|
* specified in an owning hash table.
|
||||||
*/
|
*/
|
||||||
struct qse_htb_pair_t
|
struct qse_htb_pair_t
|
||||||
{
|
{
|
||||||
void* kptr; /**< the pointer to a key */
|
void* kptr; /**< pointer to a key */
|
||||||
qse_size_t klen; /**< the length of a key */
|
qse_size_t klen; /**< length of a key */
|
||||||
void* vptr; /**< the pointer to a value */
|
void* vptr; /**< pointer to a value */
|
||||||
qse_size_t vlen; /**< the length of a value */
|
qse_size_t vlen; /**< length of a value */
|
||||||
qse_htb_pair_t* next; /**< the next pair under the same slot */
|
|
||||||
|
/* management information below */
|
||||||
|
qse_htb_pair_t* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,27 +164,16 @@ struct qse_htb_t
|
|||||||
#define QSE_HTB_COPIER_SIMPLE ((qse_htb_copier_t)1)
|
#define QSE_HTB_COPIER_SIMPLE ((qse_htb_copier_t)1)
|
||||||
#define QSE_HTB_COPIER_INLINE ((qse_htb_copier_t)2)
|
#define QSE_HTB_COPIER_INLINE ((qse_htb_copier_t)2)
|
||||||
|
|
||||||
/****m* Common/QSE_HTB_SIZE
|
/**
|
||||||
* NAME
|
* The QSE_HTB_SIZE() macro returns the number of pairs in a hash table.
|
||||||
* QSE_HTB_SIZE - get the number of pairs
|
|
||||||
* DESCRIPTION
|
|
||||||
* The QSE_HTB_SIZE() macro returns the number of pairs in hash table.
|
|
||||||
* SYNOPSIS
|
|
||||||
*/
|
*/
|
||||||
#define QSE_HTB_SIZE(m) ((m)->size)
|
#define QSE_HTB_SIZE(m) ((m)->size)
|
||||||
/*****/
|
|
||||||
|
|
||||||
/****m* Common/QSE_HTB_CAPA
|
/**
|
||||||
* NAME
|
* The QSE_HTB_CAPA() macro returns the maximum number of pairs that can be
|
||||||
* QSE_HTB_CAPA - get the capacity of hash table
|
* stored in a hash table without further reorganization.
|
||||||
*
|
|
||||||
* DESCRIPTION
|
|
||||||
* The QSE_HTB_CAPA() macro returns the maximum number of pairs hash table can hold.
|
|
||||||
*
|
|
||||||
* SYNOPSIS
|
|
||||||
*/
|
*/
|
||||||
#define QSE_HTB_CAPA(m) ((m)->capa)
|
#define QSE_HTB_CAPA(m) ((m)->capa)
|
||||||
/*****/
|
|
||||||
|
|
||||||
#define QSE_HTB_KCOPIER(m) ((m)->copier[QSE_HTB_KEY])
|
#define QSE_HTB_KCOPIER(m) ((m)->copier[QSE_HTB_KEY])
|
||||||
#define QSE_HTB_VCOPIER(m) ((m)->copier[QSE_HTB_VAL])
|
#define QSE_HTB_VCOPIER(m) ((m)->copier[QSE_HTB_VAL])
|
||||||
@ -285,14 +276,14 @@ int qse_htb_getscale (
|
|||||||
void qse_htb_setscale (
|
void qse_htb_setscale (
|
||||||
qse_htb_t* htb, /**< hash table */
|
qse_htb_t* htb, /**< hash table */
|
||||||
qse_htb_id_t id, /**< QSE_HTB_KEY or QSE_HTB_VAL */
|
qse_htb_id_t id, /**< QSE_HTB_KEY or QSE_HTB_VAL */
|
||||||
int scale /* scale factor in bytes */
|
int scale /**< scale factor in bytes */
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The qse_htb_getcopier() function gets a data copier.
|
* The qse_htb_getcopier() function gets a data copier.
|
||||||
*/
|
*/
|
||||||
qse_htb_copier_t qse_htb_getcopier (
|
qse_htb_copier_t qse_htb_getcopier (
|
||||||
qse_htb_t* htb,
|
qse_htb_t* htb, /**< hash table */
|
||||||
qse_htb_id_t id /**< QSE_HTB_KEY or QSE_HTB_VAL */
|
qse_htb_id_t id /**< QSE_HTB_KEY or QSE_HTB_VAL */
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -312,7 +303,7 @@ void qse_htb_setcopier (
|
|||||||
);
|
);
|
||||||
|
|
||||||
qse_htb_freeer_t qse_htb_getfreeer (
|
qse_htb_freeer_t qse_htb_getfreeer (
|
||||||
qse_htb_t* htb, /**< htb */
|
qse_htb_t* htb, /**< hash table */
|
||||||
qse_htb_id_t id /**< QSE_HTB_KEY or QSE_HTB_VAL */
|
qse_htb_id_t id /**< QSE_HTB_KEY or QSE_HTB_VAL */
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -326,7 +317,6 @@ void qse_htb_setfreeer (
|
|||||||
qse_htb_freeer_t freeer /**< an element freeer */
|
qse_htb_freeer_t freeer /**< an element freeer */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
qse_htb_hasher_t qse_htb_gethasher (
|
qse_htb_hasher_t qse_htb_gethasher (
|
||||||
qse_htb_t* htb
|
qse_htb_t* htb
|
||||||
);
|
);
|
||||||
|
@ -24,6 +24,17 @@
|
|||||||
#include <qse/types.h>
|
#include <qse/types.h>
|
||||||
#include <qse/macros.h>
|
#include <qse/macros.h>
|
||||||
|
|
||||||
|
/**@file
|
||||||
|
* A red-black tree is a self-balancing binary search tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* values that can be returned by qse_rbt_walker_t */
|
||||||
|
enum qse_rbt_walk_t
|
||||||
|
{
|
||||||
|
QSE_RBT_WALK_STOP = 0,
|
||||||
|
QSE_RBT_WALK_FORWARD = 1
|
||||||
|
};
|
||||||
|
|
||||||
enum qse_rbt_id_t
|
enum qse_rbt_id_t
|
||||||
{
|
{
|
||||||
QSE_RBT_KEY = 0,
|
QSE_RBT_KEY = 0,
|
||||||
@ -31,110 +42,381 @@ enum qse_rbt_id_t
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef struct qse_rbt_t qse_rbt_t;
|
typedef struct qse_rbt_t qse_rbt_t;
|
||||||
typedef struct qse_rbt_node_t qse_rbt_node_t;
|
typedef struct qse_rbt_pair_t qse_rbt_pair_t;
|
||||||
|
typedef enum qse_rbt_walk_t qse_rbt_walk_t;
|
||||||
typedef enum qse_rbt_id_t qse_rbt_id_t;
|
typedef enum qse_rbt_id_t qse_rbt_id_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_copier_t type defines a pair contruction callback.
|
||||||
|
*/
|
||||||
typedef void* (*qse_rbt_copier_t) (
|
typedef void* (*qse_rbt_copier_t) (
|
||||||
qse_rbt_t* rbt, /**< red-black tree */
|
qse_rbt_t* rbt /* red-black tree */,
|
||||||
void* dptr, /**< the pointer to a key or a value */
|
void* dptr /* pointer to a key or a value */,
|
||||||
qse_size_t dlen /**< the length of a key or a value */
|
qse_size_t dlen /* length of a key or a value */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_freeer_t defines a key/value destruction callback.
|
||||||
|
*/
|
||||||
typedef void (*qse_rbt_freeer_t) (
|
typedef void (*qse_rbt_freeer_t) (
|
||||||
qse_rbt_t* rbt, /**< red-black tree */
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
void* dptr, /**< the pointer to a key or a value */
|
void* dptr, /**< pointer to a key or a value */
|
||||||
qse_size_t dlen /**< the length of a key or a value */
|
qse_size_t dlen /**< length of a key or a value */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_comper_t type defines a key comparator that is called when
|
||||||
|
* the rbt needs to compare keys. A rbt is created with a default comparator
|
||||||
|
* which performs bitwise comparison between two keys.
|
||||||
|
*
|
||||||
|
* The comparator should return 0 if the keys are the same and a non-zero
|
||||||
|
* integer otherwise.
|
||||||
|
*/
|
||||||
typedef int (*qse_rbt_comper_t) (
|
typedef int (*qse_rbt_comper_t) (
|
||||||
qse_rbt_t* rbt, /**< red-black tree */
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
const void* kptr1, /**< the pointer to a key */
|
const void* kptr1, /**< key pointer */
|
||||||
qse_size_t klen1, /**< the length of a key */
|
qse_size_t klen1, /**< key length */
|
||||||
const void* kptr2, /**< the pointer to a key */
|
const void* kptr2, /**< key pointer */
|
||||||
qse_size_t klen2 /**< the length of a key */
|
qse_size_t klen2 /**< key length */
|
||||||
);
|
);
|
||||||
|
|
||||||
struct qse_rbt_node_t
|
/**
|
||||||
{
|
* The qse_rbt_keeper_t type defines a value keeper that is called when
|
||||||
int key;
|
* a value is retained in the context that it should be destroyed because
|
||||||
int value;
|
* it is identical to a new value. Two values are identical if their beginning
|
||||||
|
* pointers and their lengths are equal.
|
||||||
enum
|
*/
|
||||||
{
|
typedef void (*qse_rbt_keeper_t) (
|
||||||
QSE_RBT_RED,
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
QSE_RBT_BLACK
|
void* vptr, /**< value pointer */
|
||||||
} color;
|
qse_size_t vlen /**< value length */
|
||||||
|
);
|
||||||
qse_rbt_node_t* parent;
|
|
||||||
qse_rbt_node_t* child[2]; /* left and right */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct qse_rbt_t
|
|
||||||
{
|
|
||||||
QSE_DEFINE_COMMON_FIELDS (rbt)
|
|
||||||
|
|
||||||
qse_rbt_node_t nil; /**< internal nil node */
|
|
||||||
|
|
||||||
qse_byte_t scale[2]; /**< scale factor */
|
|
||||||
|
|
||||||
qse_rbt_copier_t copier[2];
|
|
||||||
qse_rbt_freeer_t freeer[2];
|
|
||||||
qse_rbt_comper_t comper;
|
|
||||||
|
|
||||||
qse_size_t size; /**< number of nodes */
|
|
||||||
qse_rbt_node_t* root;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum qse_rbt_walk_t
|
|
||||||
{
|
|
||||||
QSE_RBT_WALK_STOP = 0,
|
|
||||||
QSE_RBT_WALK_FORWARD = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum qse_rbt_walk_t qse_rbt_walk_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, /**< tree */
|
qse_rbt_t* rbt, /**< rbt */
|
||||||
qse_rbt_node_t* node, /**< pointer to a node */
|
qse_rbt_pair_t* pair, /**< pointer to a key/value pair */
|
||||||
void* ctx /**< pointer to user-defined context */
|
void* ctx /**< pointer to user-defined data */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* a value plus their length. The length is scaled down with the scale factor
|
||||||
|
* specified in an owning tree. Use macros defined in the
|
||||||
|
*/
|
||||||
|
struct qse_rbt_pair_t
|
||||||
|
{
|
||||||
|
void* kptr; /**< key pointer */
|
||||||
|
qse_size_t klen; /**< key length */
|
||||||
|
void* vptr; /**< value pointer */
|
||||||
|
qse_size_t vlen; /**< value length */
|
||||||
|
|
||||||
|
/* management information below */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
QSE_RBT_RED,
|
||||||
|
QSE_RBT_BLACK
|
||||||
|
} color;
|
||||||
|
qse_rbt_pair_t* parent;
|
||||||
|
qse_rbt_pair_t* child[2]; /* left and right */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_t type defines a red-black tree.
|
||||||
|
*/
|
||||||
|
struct qse_rbt_t
|
||||||
|
{
|
||||||
|
QSE_DEFINE_COMMON_FIELDS (rbt)
|
||||||
|
|
||||||
|
qse_rbt_copier_t copier[2];
|
||||||
|
qse_rbt_freeer_t freeer[2];
|
||||||
|
qse_rbt_comper_t comper; /**< key comparator */
|
||||||
|
qse_rbt_keeper_t keeper; /**< value keeper */
|
||||||
|
|
||||||
|
qse_byte_t scale[2]; /**< length scale */
|
||||||
|
qse_byte_t factor; /**< load factor */
|
||||||
|
qse_byte_t filler0;
|
||||||
|
|
||||||
|
qse_rbt_pair_t nil; /**< internal nil node */
|
||||||
|
|
||||||
|
qse_size_t size;
|
||||||
|
qse_rbt_pair_t* root;
|
||||||
|
};
|
||||||
|
|
||||||
#define QSE_RBT_COPIER_SIMPLE ((qse_rbt_copier_t)1)
|
#define QSE_RBT_COPIER_SIMPLE ((qse_rbt_copier_t)1)
|
||||||
#define QSE_RBT_COPIER_INLINE ((qse_rbt_copier_t)2)
|
#define QSE_RBT_COPIER_INLINE ((qse_rbt_copier_t)2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The QSE_RBT_SIZE() macro returns the number of pairs in red-black tree.
|
||||||
|
*/
|
||||||
|
#define QSE_RBT_SIZE(m) ((m)->size)
|
||||||
|
|
||||||
|
#define QSE_RBT_KCOPIER(m) ((m)->copier[QSE_RBT_KEY])
|
||||||
|
#define QSE_RBT_VCOPIER(m) ((m)->copier[QSE_RBT_VAL])
|
||||||
|
#define QSE_RBT_KFREEER(m) ((m)->freeer[QSE_RBT_KEY])
|
||||||
|
#define QSE_RBT_VFREEER(m) ((m)->freeer[QSE_RBT_VAL])
|
||||||
|
#define QSE_RBT_COMPER(m) ((m)->comper)
|
||||||
|
#define QSE_RBT_KEEPER(m) ((m)->keeper)
|
||||||
|
|
||||||
|
#define QSE_RBT_FACTOR(m) ((m)->factor)
|
||||||
|
#define QSE_RBT_KSCALE(m) ((m)->scale[QSE_RBT_KEY])
|
||||||
|
#define QSE_RBT_VSCALE(m) ((m)->scale[QSE_RBT_VAL])
|
||||||
|
|
||||||
|
#define QSE_RBT_KPTR(p) ((p)->kptr)
|
||||||
|
#define QSE_RBT_KLEN(p) ((p)->klen)
|
||||||
|
#define QSE_RBT_VPTR(p) ((p)->vptr)
|
||||||
|
#define QSE_RBT_VLEN(p) ((p)->vlen)
|
||||||
|
#define QSE_RBT_NEXT(p) ((p)->next)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
QSE_DEFINE_COMMON_FUNCTIONS (rbt)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_open() function creates a red-black tree.
|
||||||
|
* @return qse_rbt_t pointer on success, QSE_NULL on failure.
|
||||||
|
*/
|
||||||
qse_rbt_t* qse_rbt_open (
|
qse_rbt_t* qse_rbt_open (
|
||||||
qse_mmgr_t* mmgr, /**< memory manager */
|
qse_mmgr_t* mmgr, /**< memory manager */
|
||||||
qse_size_t ext /**< size of extension area in bytes */
|
qse_size_t ext /**< extension size in bytes */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_close() function destroys a red-black tree.
|
||||||
|
*/
|
||||||
void qse_rbt_close (
|
void qse_rbt_close (
|
||||||
qse_rbt_t* rbt /**< red-black tree */
|
qse_rbt_t* rbt /**< red-black tree */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_init() function initializes a red-black tree
|
||||||
|
*/
|
||||||
qse_rbt_t* qse_rbt_init (
|
qse_rbt_t* qse_rbt_init (
|
||||||
qse_rbt_t* rbt, /**< red-black tree */
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
qse_mmgr_t* mmgr /**< a memory manager */
|
qse_mmgr_t* mmgr /**< memory manager */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_fini() funtion finalizes a red-black tree
|
||||||
|
*/
|
||||||
void qse_rbt_fini (
|
void qse_rbt_fini (
|
||||||
qse_rbt_t* rbt /**< red-black tree */
|
qse_rbt_t* rbt /**< red-black tree */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_getsize() function gets the number of pairs in red-black tree.
|
||||||
|
*/
|
||||||
|
qse_size_t qse_rbt_getsize (
|
||||||
|
qse_rbt_t* rbt /**< red-black tree */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_getscale() function returns the scale factor
|
||||||
|
*/
|
||||||
|
int qse_rbt_getscale (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
qse_rbt_id_t id /**< QSE_RBT_KEY or QSE_RBT_VAL */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_setscale() function sets the scale factor of the length
|
||||||
|
* of a key and a value. A scale factor determines the actual length of
|
||||||
|
* a key and a value in bytes. A rbt is created with a scale factor of 1.
|
||||||
|
* The scale factor should be larger than 0 and less than 256.
|
||||||
|
* Note that it is a bad idea to change the scale factor while a red-black tree
|
||||||
|
* is not empty.
|
||||||
|
*/
|
||||||
|
void qse_rbt_setscale (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
qse_rbt_id_t id, /**< QSE_RBT_KEY or QSE_RBT_VAL */
|
||||||
|
int scale /**< scale factor in bytes */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_getcopier() function gets a data copier.
|
||||||
|
*/
|
||||||
|
qse_rbt_copier_t qse_rbt_getcopier (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
qse_rbt_id_t id /**< QSE_RBT_KEY or QSE_RBT_VAL */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_setcopier() function specifies how to clone an element.
|
||||||
|
* A special copier QSE_RBT_COPIER_INLINE is provided. This copier enables
|
||||||
|
* you to copy the data inline to the internal node. No freeer is invoked
|
||||||
|
* when the node is freeed.
|
||||||
|
*
|
||||||
|
* You may set the copier to QSE_NULL to perform no special operation
|
||||||
|
* when the data pointer is rememebered.
|
||||||
|
*/
|
||||||
|
void qse_rbt_setcopier (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
qse_rbt_id_t id, /**< QSE_RBT_KEY or QSE_RBT_VAL */
|
||||||
|
qse_rbt_copier_t copier /**< element copier */
|
||||||
|
);
|
||||||
|
|
||||||
|
qse_rbt_freeer_t qse_rbt_getfreeer (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
qse_rbt_id_t id /**< QSE_RBT_KEY or QSE_RBT_VAL */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_setfreeer() function specifies how to destroy an element.
|
||||||
|
* The @a freeer is called when a node containing the element is destroyed.
|
||||||
|
*/
|
||||||
|
void qse_rbt_setfreeer (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
qse_rbt_id_t id, /**< QSE_RBT_KEY or QSE_RBT_VAL */
|
||||||
|
qse_rbt_freeer_t freeer /**< an element freeer */
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_getcomper() function returns the key comparator.
|
||||||
|
*/
|
||||||
|
qse_rbt_comper_t qse_rbt_getcomper (
|
||||||
|
qse_rbt_t* rbt /**< red-black tree */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_setcomper() function changes the key comparator.
|
||||||
|
*/
|
||||||
|
void qse_rbt_setcomper (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
qse_rbt_comper_t comper /**< comparator function pointer */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_getkeeper() function returns the value retainer function
|
||||||
|
* that is called when you change the value of an existing key with the
|
||||||
|
* same value.
|
||||||
|
*/
|
||||||
|
qse_rbt_keeper_t qse_rbt_getkeeper (
|
||||||
|
qse_rbt_t* rbt
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_setkeeper() function changes the value retainer function.
|
||||||
|
*/
|
||||||
|
void qse_rbt_setkeeper (
|
||||||
|
qse_rbt_t* rbt,
|
||||||
|
qse_rbt_keeper_t keeper
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_search() function searches red-black tree to find a pair with a
|
||||||
|
* matching key. It returns the pointer to the pair found. If it fails
|
||||||
|
* to find one, it returns QSE_NULL.
|
||||||
|
* @return pointer to the pair with a maching key,
|
||||||
|
* or QSE_NULL if no match is found.
|
||||||
|
*/
|
||||||
|
qse_rbt_pair_t* qse_rbt_search (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
const void* kptr, /**< key pointer */
|
||||||
|
qse_size_t klen /**< the size of the key */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_upsert() function searches red-black tree for the pair with a
|
||||||
|
* matching key. If one is found, it updates the pair. Otherwise, it inserts
|
||||||
|
* a new pair with the key and value given. It returns the pointer to the
|
||||||
|
* pair updated or inserted.
|
||||||
|
* @return a pointer to the updated or inserted pair on success,
|
||||||
|
* QSE_NULL on failure.
|
||||||
|
*/
|
||||||
|
qse_rbt_pair_t* qse_rbt_upsert (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
void* kptr, /**< key pointer */
|
||||||
|
qse_size_t klen, /**< key length */
|
||||||
|
void* vptr, /**< value pointer */
|
||||||
|
qse_size_t vlen /**< value length */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_ensert() function inserts a new pair with the key and the value
|
||||||
|
* given. If there exists a pair with the key given, the function returns
|
||||||
|
* the pair containing the key.
|
||||||
|
* @return pointer to a pair on success, QSE_NULL on failure.
|
||||||
|
*/
|
||||||
|
qse_rbt_pair_t* qse_rbt_ensert (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
void* kptr, /**< key pointer */
|
||||||
|
qse_size_t klen, /**< key length */
|
||||||
|
void* vptr, /**< value pointer */
|
||||||
|
qse_size_t vlen /**< value length */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_insert() function inserts a new pair with the key and the value
|
||||||
|
* given. If there exists a pair with the key given, the function returns
|
||||||
|
* QSE_NULL without channging the value.
|
||||||
|
* @return pointer to the pair created on success, QSE_NULL on failure.
|
||||||
|
*/
|
||||||
|
qse_rbt_pair_t* qse_rbt_insert (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
void* kptr, /**< key pointer */
|
||||||
|
qse_size_t klen, /**< key length */
|
||||||
|
void* vptr, /**< value pointer */
|
||||||
|
qse_size_t vlen /**< value length */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_update() function updates the value of an existing pair
|
||||||
|
* with a matching key.
|
||||||
|
* @return pointer to the pair on success, QSE_NULL on no matching pair
|
||||||
|
*/
|
||||||
|
qse_rbt_pair_t* qse_rbt_update (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
void* kptr, /**< key pointer */
|
||||||
|
qse_size_t klen, /**< key length */
|
||||||
|
void* vptr, /**< value pointer */
|
||||||
|
qse_size_t vlen /**< value length */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_delete() function deletes a pair with a matching key
|
||||||
|
* @return 0 on success, -1 on failure
|
||||||
|
*/
|
||||||
|
int qse_rbt_delete (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
const void* kptr, /**< key pointer */
|
||||||
|
qse_size_t klen /**< key size */
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The qse_rbt_clear() function empties a red-black tree.
|
||||||
|
*/
|
||||||
void qse_rbt_clear (
|
void qse_rbt_clear (
|
||||||
qse_rbt_t* rbt /**< red-black tree */
|
qse_rbt_t* rbt /**< red-black tree */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_walk() function traverses a red-black tree in preorder
|
||||||
|
* from the leftmost child.
|
||||||
|
*/
|
||||||
|
void qse_rbt_walk (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
qse_rbt_walker_t walker, /**< pointer to the function for each pair */
|
||||||
|
void* ctx /**< pointer to user-specific data */
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_rbt_walk() function traverses a red-black tree in preorder
|
||||||
|
* from the rightmost child.
|
||||||
|
*/
|
||||||
|
void qse_rbt_rwalk (
|
||||||
|
qse_rbt_t* rbt, /**< red-black tree */
|
||||||
|
qse_rbt_walker_t walker, /**< pointer to the function for each pair */
|
||||||
|
void* ctx /**< pointer to user-specific data */
|
||||||
|
);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: htb.c 328 2010-07-08 06:58:44Z hyunghwan.chung $
|
* $Id: htb.c 331 2010-07-13 11:18:30Z 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.
|
||||||
@ -73,7 +73,7 @@ static size_t hash_key (htb_t* htb, const void* kptr, size_t klen)
|
|||||||
return h ;
|
return h ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int comp_key (htb_t* htb,
|
static QSE_INLINE int comp_key (htb_t* htb,
|
||||||
const void* kptr1, size_t klen1,
|
const void* kptr1, size_t klen1,
|
||||||
const void* kptr2, size_t klen2)
|
const void* kptr2, size_t klen2)
|
||||||
{
|
{
|
||||||
|
@ -21,34 +21,42 @@
|
|||||||
#include <qse/cmn/rbt.h>
|
#include <qse/cmn/rbt.h>
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
|
||||||
#define IS_NIL(rbt,x) ((x) == &((rbt)->nil))
|
|
||||||
|
|
||||||
#define KTOB(htb,len) ((len)*(htb)->scale[QSE_RBT_KEY])
|
|
||||||
|
|
||||||
#define LEFT 0
|
|
||||||
#define RIGHT 1
|
|
||||||
|
|
||||||
#define left child[LEFT]
|
|
||||||
#define right child[RIGHT]
|
|
||||||
|
|
||||||
#define rotate_left(rbt,pivot) rotate(rbt,pivot,1);
|
|
||||||
#define rotate_right(rbt,pivot) rotate(rbt,pivot,0);
|
|
||||||
|
|
||||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (rbt)
|
QSE_IMPLEMENT_COMMON_FUNCTIONS (rbt)
|
||||||
|
|
||||||
static QSE_INLINE void init_node (
|
#define rbt_t qse_rbt_t
|
||||||
qse_rbt_t* rbt, qse_rbt_node_t* node, int color,
|
#define pair_t qse_rbt_pair_t
|
||||||
int key, int value)
|
#define copier_t qse_rbt_copier_t
|
||||||
{
|
#define freeer_t qse_rbt_freeer_t
|
||||||
QSE_MEMSET (node, 0, QSE_SIZEOF(*node));
|
#define comper_t qse_rbt_comper_t
|
||||||
|
#define keeper_t qse_rbt_keeper_t
|
||||||
|
#define walker_t qse_rbt_walker_t
|
||||||
|
|
||||||
node->color = color;
|
#define KPTR(p) QSE_RBT_KPTR(p)
|
||||||
node->right = &rbt->nil;
|
#define KLEN(p) QSE_RBT_KLEN(p)
|
||||||
node->left = &rbt->nil;
|
#define VPTR(p) QSE_RBT_VPTR(p)
|
||||||
|
#define VLEN(p) QSE_RBT_VLEN(p)
|
||||||
|
|
||||||
node->key = key;
|
#define SIZEOF(x) QSE_SIZEOF(x)
|
||||||
node->value = value;
|
#define size_t qse_size_t
|
||||||
}
|
#define byte_t qse_byte_t
|
||||||
|
#define uint_t qse_uint_t
|
||||||
|
#define mmgr_t qse_mmgr_t
|
||||||
|
|
||||||
|
#define KTOB(rbt,len) ((len)*(rbt)->scale[QSE_RBT_KEY])
|
||||||
|
#define VTOB(rbt,len) ((len)*(rbt)->scale[QSE_RBT_VAL])
|
||||||
|
|
||||||
|
#define UPSERT 1
|
||||||
|
#define UPDATE 2
|
||||||
|
#define ENSERT 3
|
||||||
|
#define INSERT 4
|
||||||
|
|
||||||
|
#define IS_NIL(rbt,x) ((x) == &((rbt)->nil))
|
||||||
|
#define LEFT 0
|
||||||
|
#define RIGHT 1
|
||||||
|
#define left child[LEFT]
|
||||||
|
#define right child[RIGHT]
|
||||||
|
#define rotate_left(rbt,pivot) rotate(rbt,pivot,1);
|
||||||
|
#define rotate_right(rbt,pivot) rotate(rbt,pivot,0);
|
||||||
|
|
||||||
static QSE_INLINE int comp_key (
|
static QSE_INLINE int comp_key (
|
||||||
qse_rbt_t* rbt,
|
qse_rbt_t* rbt,
|
||||||
@ -74,9 +82,85 @@ static QSE_INLINE int comp_key (
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_rbt_t* qse_rbt_open (qse_mmgr_t* mmgr, qse_size_t ext)
|
static pair_t* alloc_pair (rbt_t* rbt,
|
||||||
|
void* kptr, size_t klen, void* vptr, size_t vlen)
|
||||||
{
|
{
|
||||||
qse_rbt_t* rbt;
|
pair_t* n;
|
||||||
|
|
||||||
|
copier_t kcop = rbt->copier[QSE_RBT_KEY];
|
||||||
|
copier_t vcop = rbt->copier[QSE_RBT_VAL];
|
||||||
|
|
||||||
|
size_t as = SIZEOF(pair_t);
|
||||||
|
if (kcop == QSE_RBT_COPIER_INLINE) as += KTOB(rbt,klen);
|
||||||
|
if (vcop == QSE_RBT_COPIER_INLINE) as += VTOB(rbt,vlen);
|
||||||
|
|
||||||
|
n = (pair_t*) QSE_MMGR_ALLOC (rbt->mmgr, as);
|
||||||
|
if (n == QSE_NULL) return QSE_NULL;
|
||||||
|
|
||||||
|
n->color = QSE_RBT_RED;
|
||||||
|
n->parent = QSE_NULL;
|
||||||
|
n->child[LEFT] = &rbt->nil;
|
||||||
|
n->child[RIGHT] = &rbt->nil;
|
||||||
|
|
||||||
|
KLEN(n) = klen;
|
||||||
|
if (kcop == QSE_RBT_COPIER_SIMPLE)
|
||||||
|
{
|
||||||
|
KPTR(n) = kptr;
|
||||||
|
}
|
||||||
|
else if (kcop == QSE_RBT_COPIER_INLINE)
|
||||||
|
{
|
||||||
|
KPTR(n) = n + 1;
|
||||||
|
QSE_MEMCPY (KPTR(n), kptr, KTOB(rbt,klen));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPTR(n) = kcop (rbt, kptr, klen);
|
||||||
|
if (KPTR(n) == QSE_NULL)
|
||||||
|
{
|
||||||
|
QSE_MMGR_FREE (rbt->mmgr, n);
|
||||||
|
return QSE_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VLEN(n) = vlen;
|
||||||
|
if (vcop == QSE_RBT_COPIER_SIMPLE)
|
||||||
|
{
|
||||||
|
VPTR(n) = vptr;
|
||||||
|
}
|
||||||
|
else if (vcop == QSE_RBT_COPIER_INLINE)
|
||||||
|
{
|
||||||
|
VPTR(n) = n + 1;
|
||||||
|
if (kcop == QSE_RBT_COPIER_INLINE)
|
||||||
|
VPTR(n) = (byte_t*)VPTR(n) + KTOB(rbt,klen);
|
||||||
|
QSE_MEMCPY (VPTR(n), vptr, VTOB(rbt,vlen));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VPTR(n) = vcop (rbt, vptr, vlen);
|
||||||
|
if (VPTR(n) != QSE_NULL)
|
||||||
|
{
|
||||||
|
if (rbt->freeer[QSE_RBT_KEY] != QSE_NULL)
|
||||||
|
rbt->freeer[QSE_RBT_KEY] (rbt, KPTR(n), KLEN(n));
|
||||||
|
QSE_MMGR_FREE (rbt->mmgr, n);
|
||||||
|
return QSE_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_pair (rbt_t* rbt, pair_t* pair)
|
||||||
|
{
|
||||||
|
if (rbt->freeer[QSE_RBT_KEY] != QSE_NULL)
|
||||||
|
rbt->freeer[QSE_RBT_KEY] (rbt, KPTR(pair), KLEN(pair));
|
||||||
|
if (rbt->freeer[QSE_RBT_VAL] != QSE_NULL)
|
||||||
|
rbt->freeer[QSE_RBT_VAL] (rbt, VPTR(pair), VLEN(pair));
|
||||||
|
QSE_MMGR_FREE (rbt->mmgr, pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
rbt_t* qse_rbt_open (mmgr_t* mmgr, size_t ext)
|
||||||
|
{
|
||||||
|
rbt_t* rbt;
|
||||||
|
|
||||||
if (mmgr == QSE_NULL)
|
if (mmgr == QSE_NULL)
|
||||||
{
|
{
|
||||||
@ -88,7 +172,7 @@ qse_rbt_t* qse_rbt_open (qse_mmgr_t* mmgr, qse_size_t ext)
|
|||||||
if (mmgr == QSE_NULL) return QSE_NULL;
|
if (mmgr == QSE_NULL) return QSE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rbt = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_rbt_t) + ext);
|
rbt = (rbt_t*) QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(rbt_t) + ext);
|
||||||
if (rbt == QSE_NULL) return QSE_NULL;
|
if (rbt == QSE_NULL) return QSE_NULL;
|
||||||
|
|
||||||
if (qse_rbt_init (rbt, mmgr) == QSE_NULL)
|
if (qse_rbt_init (rbt, mmgr) == QSE_NULL)
|
||||||
@ -100,179 +184,146 @@ qse_rbt_t* qse_rbt_open (qse_mmgr_t* mmgr, qse_size_t ext)
|
|||||||
return rbt;
|
return rbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qse_rbt_close (qse_rbt_t* rbt)
|
void qse_rbt_close (rbt_t* rbt)
|
||||||
{
|
{
|
||||||
qse_rbt_fini (rbt);
|
qse_rbt_fini (rbt);
|
||||||
QSE_MMGR_FREE (rbt->mmgr, rbt);
|
QSE_MMGR_FREE (rbt->mmgr, rbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_rbt_t* qse_rbt_init (qse_rbt_t* rbt, qse_mmgr_t* mmgr)
|
rbt_t* qse_rbt_init (rbt_t* rbt, mmgr_t* mmgr)
|
||||||
{
|
{
|
||||||
/* do not zero out the extension */
|
/* do not zero out the extension */
|
||||||
QSE_MEMSET (rbt, 0, QSE_SIZEOF(*rbt));
|
QSE_MEMSET (rbt, 0, SIZEOF(*rbt));
|
||||||
|
|
||||||
rbt->mmgr = mmgr;
|
rbt->mmgr = mmgr;
|
||||||
rbt->size = 0;
|
|
||||||
|
|
||||||
rbt->scale[QSE_RBT_KEY] = 1;
|
rbt->scale[QSE_RBT_KEY] = 1;
|
||||||
rbt->scale[QSE_RBT_VAL] = 1;
|
rbt->scale[QSE_RBT_VAL] = 1;
|
||||||
|
rbt->size = 0;
|
||||||
|
|
||||||
rbt->comper = comp_key;
|
rbt->comper = comp_key;
|
||||||
rbt->copier[QSE_RBT_KEY] = QSE_RBT_COPIER_SIMPLE;
|
rbt->copier[QSE_RBT_KEY] = QSE_RBT_COPIER_SIMPLE;
|
||||||
rbt->copier[QSE_RBT_VAL] = QSE_RBT_COPIER_SIMPLE;
|
rbt->copier[QSE_RBT_VAL] = QSE_RBT_COPIER_SIMPLE;
|
||||||
|
|
||||||
init_node (rbt, &rbt->nil, QSE_RBT_BLACK, 0, 0);
|
/*
|
||||||
|
rbt->freeer[QSE_RBT_KEY] = QSE_NULL;
|
||||||
|
rbt->freeer[QSE_RBT_VAL] = QSE_NULL;
|
||||||
|
rbt->keeper = QSE_NULL;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* self-initializing nil */
|
||||||
|
QSE_MEMSET(&rbt->nil, 0, QSE_SIZEOF(rbt->nil));
|
||||||
|
rbt->nil.color = QSE_RBT_BLACK;
|
||||||
|
rbt->nil.left = &rbt->nil;
|
||||||
|
rbt->nil.right = &rbt->nil;
|
||||||
|
|
||||||
|
/* root is set to nil initially */
|
||||||
rbt->root = &rbt->nil;
|
rbt->root = &rbt->nil;
|
||||||
|
|
||||||
return rbt;
|
return rbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qse_rbt_fini (qse_rbt_t* rbt)
|
void qse_rbt_fini (rbt_t* rbt)
|
||||||
{
|
{
|
||||||
qse_rbt_clear (rbt);
|
qse_rbt_clear (rbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_rbt_node_t* qse_rbt_search (qse_rbt_t* rbt, int key)
|
int qse_rbt_getscale (rbt_t* rbt, qse_rbt_id_t id)
|
||||||
{
|
{
|
||||||
/* TODO: enhance this. ues comper... etc */
|
QSE_ASSERTX (id == QSE_RBT_KEY || id == QSE_RBT_VAL,
|
||||||
|
"The ID should be either QSE_RBT_KEY or QSE_RBT_VAL");
|
||||||
|
return rbt->scale[id];
|
||||||
|
}
|
||||||
|
|
||||||
qse_rbt_node_t* node = rbt->root;
|
void qse_rbt_setscale (rbt_t* rbt, qse_rbt_id_t id, int scale)
|
||||||
|
|
||||||
while (!IS_NIL(rbt,node))
|
|
||||||
{
|
{
|
||||||
#if 0
|
QSE_ASSERTX (id == QSE_RBT_KEY || id == QSE_RBT_VAL,
|
||||||
int n = rbt->comper (rbt, kptr, klen, node->kptr, node->klen);
|
"The ID should be either QSE_RBT_KEY or QSE_RBT_VAL");
|
||||||
if (n == 0) return node;
|
|
||||||
|
|
||||||
if (n > 0) node = node->right;
|
QSE_ASSERTX (scale > 0 && scale <= QSE_TYPE_MAX(qse_byte_t),
|
||||||
else /* if (n < 0) */ node = node->left;
|
"The scale should be larger than 0 and less than or equal to the maximum value that the qse_byte_t type can hold");
|
||||||
#endif
|
|
||||||
if (key == node->key) return node;
|
|
||||||
|
|
||||||
if (key > node->key) node = node->right;
|
if (scale <= 0) scale = 1;
|
||||||
else /* if (key < node->key) */ node = node->left;
|
if (scale > QSE_TYPE_MAX(qse_byte_t)) scale = QSE_TYPE_MAX(qse_byte_t);
|
||||||
|
|
||||||
|
rbt->scale[id] = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
copier_t qse_rbt_getcopier (rbt_t* rbt, qse_rbt_id_t id)
|
||||||
|
{
|
||||||
|
QSE_ASSERTX (id == QSE_RBT_KEY || id == QSE_RBT_VAL,
|
||||||
|
"The ID should be either QSE_RBT_KEY or QSE_RBT_VAL");
|
||||||
|
return rbt->copier[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void qse_rbt_setcopier (rbt_t* rbt, qse_rbt_id_t id, copier_t copier)
|
||||||
|
{
|
||||||
|
QSE_ASSERTX (id == QSE_RBT_KEY || id == QSE_RBT_VAL,
|
||||||
|
"The ID should be either QSE_RBT_KEY or QSE_RBT_VAL");
|
||||||
|
if (copier == QSE_NULL) copier = QSE_RBT_COPIER_SIMPLE;
|
||||||
|
rbt->copier[id] = copier;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeer_t qse_rbt_getfreeer (rbt_t* rbt, qse_rbt_id_t id)
|
||||||
|
{
|
||||||
|
QSE_ASSERTX (id == QSE_RBT_KEY || id == QSE_RBT_VAL,
|
||||||
|
"The ID should be either QSE_RBT_KEY or QSE_RBT_VAL");
|
||||||
|
return rbt->freeer[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void qse_rbt_setfreeer (rbt_t* rbt, qse_rbt_id_t id, freeer_t freeer)
|
||||||
|
{
|
||||||
|
QSE_ASSERTX (id == QSE_RBT_KEY || id == QSE_RBT_VAL,
|
||||||
|
"The ID should be either QSE_RBT_KEY or QSE_RBT_VAL");
|
||||||
|
rbt->freeer[id] = freeer;
|
||||||
|
}
|
||||||
|
|
||||||
|
comper_t qse_rbt_getcomper (rbt_t* rbt)
|
||||||
|
{
|
||||||
|
return rbt->comper;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qse_rbt_setcomper (rbt_t* rbt, comper_t comper)
|
||||||
|
{
|
||||||
|
if (comper == QSE_NULL) comper = comp_key;
|
||||||
|
rbt->comper = comper;
|
||||||
|
}
|
||||||
|
|
||||||
|
keeper_t qse_rbt_getkeeper (rbt_t* rbt)
|
||||||
|
{
|
||||||
|
return rbt->keeper;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qse_rbt_setkeeper (rbt_t* rbt, keeper_t keeper)
|
||||||
|
{
|
||||||
|
rbt->keeper = keeper;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qse_rbt_getsize (rbt_t* rbt)
|
||||||
|
{
|
||||||
|
return rbt->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
pair_t* qse_rbt_search (rbt_t* rbt, const void* kptr, size_t klen)
|
||||||
|
{
|
||||||
|
pair_t* pair = rbt->root;
|
||||||
|
|
||||||
|
while (!IS_NIL(rbt,pair))
|
||||||
|
{
|
||||||
|
int n = rbt->comper (rbt, kptr, klen, pair->kptr, pair->klen);
|
||||||
|
if (n == 0) return pair;
|
||||||
|
|
||||||
|
if (n > 0) pair = pair->right;
|
||||||
|
else /* if (n < 0) */ pair = pair->left;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QSE_NULL;
|
return QSE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
static void rotate (qse_rbt_t* rbt, qse_rbt_pair_t* pivot, int leftwise)
|
||||||
static void rotate_left (qse_rbt_t* rbt, qse_rbt_node_t* pivot)
|
|
||||||
{
|
|
||||||
/* move the pivot node down to the poistion of the pivot's original
|
|
||||||
* left child(x). move the pivot's right child(y) to the pivot's original
|
|
||||||
* position. as 'c1' is between 'y' and 'pivot', move it to the right
|
|
||||||
* of the new pivot position.
|
|
||||||
*
|
|
||||||
* parent parent
|
|
||||||
* | | (left or right?) | |
|
|
||||||
* pivot y
|
|
||||||
* / \ / \
|
|
||||||
* x y =====> pivot c2
|
|
||||||
* / \ / \
|
|
||||||
* c1 c2 x c1
|
|
||||||
*
|
|
||||||
* the actual implementation here resolves the pivot's relationship to
|
|
||||||
* its parent by comparaing pointers as it is not known if the pivot node
|
|
||||||
* is the left child or the right child of its parent,
|
|
||||||
*/
|
|
||||||
|
|
||||||
qse_rbt_node_t* parent, * y, * c1;
|
|
||||||
|
|
||||||
QSE_ASSERT (pivot != QSE_NULL && pivot->right != QSE_NULL);
|
|
||||||
|
|
||||||
parent = pivot->parent;
|
|
||||||
y = pivot->right;
|
|
||||||
c1 = y->left;
|
|
||||||
|
|
||||||
y->parent = parent;
|
|
||||||
if (parent)
|
|
||||||
{
|
|
||||||
if (parent->left == pivot)
|
|
||||||
{
|
|
||||||
parent->left = y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QSE_ASSERT (parent->right == pivot);
|
|
||||||
parent->right = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QSE_ASSERT (rbt->root == pivot);
|
|
||||||
rbt->root = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
y->left = pivot;
|
|
||||||
if (!IS_NIL(rbt,pivot)) pivot->parent = y;
|
|
||||||
|
|
||||||
pivot->right = c1;
|
|
||||||
if (!IS_NIL(rbt,c1)) c1->parent = pivot;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rotate_right (qse_rbt_t* rbt, qse_rbt_node_t* pivot)
|
|
||||||
{
|
|
||||||
/* move the pivot node down to the poistion of the pivot's original
|
|
||||||
* right child(y). move the pivot's left child(x) to the pivot's original
|
|
||||||
* position. as 'c2' is between 'x' and 'pivot', move it to the left
|
|
||||||
* of the new pivot position.
|
|
||||||
*
|
|
||||||
* parent parent
|
|
||||||
* | | (left or right?) | |
|
|
||||||
* pivot x
|
|
||||||
* / \ / \
|
|
||||||
* x y =====> c1 pivot
|
|
||||||
* / \ / \
|
|
||||||
* c1 c2 c2 y
|
|
||||||
*
|
|
||||||
* the actual implementation here resolves the pivot's relationship to
|
|
||||||
* its parent by comparaing pointers as it is not known if the pivot node
|
|
||||||
* is the left child or the right child of its parent,
|
|
||||||
*/
|
|
||||||
|
|
||||||
qse_rbt_node_t* parent, * x, * c2;
|
|
||||||
|
|
||||||
QSE_ASSERT (pivot != QSE_NULL);
|
|
||||||
|
|
||||||
parent = pivot->parent;
|
|
||||||
x = pivot->left;
|
|
||||||
c2 = x->right;
|
|
||||||
|
|
||||||
x->parent = parent;
|
|
||||||
if (parent)
|
|
||||||
{
|
|
||||||
if (parent->left == pivot)
|
|
||||||
{
|
|
||||||
/* pivot is the left child of its parent */
|
|
||||||
parent->left = x;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* pivot is the right child of its parent */
|
|
||||||
QSE_ASSERT (parent->right == pivot);
|
|
||||||
parent->right = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* pivot is the root node */
|
|
||||||
QSE_ASSERT (rbt->root == pivot);
|
|
||||||
rbt->root = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
x->right = pivot;
|
|
||||||
if (!IS_NIL(rbt,pivot)) pivot->parent = x;
|
|
||||||
|
|
||||||
pivot->left = c2;
|
|
||||||
if (!IS_NIL(rbt,c2)) c2->parent = pivot;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void rotate (qse_rbt_t* rbt, qse_rbt_node_t* pivot, int leftwise)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* == leftwise rotation
|
* == leftwise rotation
|
||||||
* move the pivot node down to the poistion of the pivot's original
|
* move the pivot pair down to the poistion of the pivot's original
|
||||||
* left child(x). move the pivot's right child(y) to the pivot's original
|
* left child(x). move the pivot's right child(y) to the pivot's original
|
||||||
* position. as 'c1' is between 'y' and 'pivot', move it to the right
|
* position. as 'c1' is between 'y' and 'pivot', move it to the right
|
||||||
* of the new pivot position.
|
* of the new pivot position.
|
||||||
@ -285,7 +336,7 @@ static void rotate (qse_rbt_t* rbt, qse_rbt_node_t* pivot, int leftwise)
|
|||||||
* c1 c2 x c1
|
* c1 c2 x c1
|
||||||
*
|
*
|
||||||
* == rightwise rotation
|
* == rightwise rotation
|
||||||
* move the pivot node down to the poistion of the pivot's original
|
* move the pivot pair down to the poistion of the pivot's original
|
||||||
* right child(y). move the pivot's left child(x) to the pivot's original
|
* right child(y). move the pivot's left child(x) to the pivot's original
|
||||||
* position. as 'c2' is between 'x' and 'pivot', move it to the left
|
* position. as 'c2' is between 'x' and 'pivot', move it to the left
|
||||||
* of the new pivot position.
|
* of the new pivot position.
|
||||||
@ -300,11 +351,11 @@ static void rotate (qse_rbt_t* rbt, qse_rbt_node_t* pivot, int leftwise)
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* the actual implementation here resolves the pivot's relationship to
|
* the actual implementation here resolves the pivot's relationship to
|
||||||
* its parent by comparaing pointers as it is not known if the pivot node
|
* its parent by comparaing pointers as it is not known if the pivot pair
|
||||||
* is the left child or the right child of its parent,
|
* is the left child or the right child of its parent,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
qse_rbt_node_t* parent, * z, * c;
|
qse_rbt_pair_t* parent, * z, * c;
|
||||||
int cid1, cid2;
|
int cid1, cid2;
|
||||||
|
|
||||||
QSE_ASSERT (pivot != QSE_NULL);
|
QSE_ASSERT (pivot != QSE_NULL);
|
||||||
@ -352,14 +403,14 @@ static void rotate (qse_rbt_t* rbt, qse_rbt_node_t* pivot, int leftwise)
|
|||||||
if (!IS_NIL(rbt,c)) c->parent = pivot;
|
if (!IS_NIL(rbt,c)) c->parent = pivot;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adjust (qse_rbt_t* rbt, qse_rbt_node_t* node)
|
static void adjust (qse_rbt_t* rbt, qse_rbt_pair_t* pair)
|
||||||
{
|
{
|
||||||
while (node != rbt->root)
|
while (pair != rbt->root)
|
||||||
{
|
{
|
||||||
qse_rbt_node_t* tmp, * tmp2;
|
qse_rbt_pair_t* tmp, * tmp2;
|
||||||
int leftwise;
|
int leftwise;
|
||||||
|
|
||||||
qse_rbt_node_t* xpar = node->parent;
|
qse_rbt_pair_t* xpar = pair->parent;
|
||||||
if (xpar->color == QSE_RBT_BLACK) break;
|
if (xpar->color == QSE_RBT_BLACK) break;
|
||||||
|
|
||||||
QSE_ASSERT (xpar->parent != QSE_NULL);
|
QSE_ASSERT (xpar->parent != QSE_NULL);
|
||||||
@ -382,15 +433,15 @@ static void adjust (qse_rbt_t* rbt, qse_rbt_node_t* node)
|
|||||||
xpar->color = QSE_RBT_BLACK;
|
xpar->color = QSE_RBT_BLACK;
|
||||||
tmp->color = QSE_RBT_BLACK;
|
tmp->color = QSE_RBT_BLACK;
|
||||||
xpar->parent->color = QSE_RBT_RED;
|
xpar->parent->color = QSE_RBT_RED;
|
||||||
node = xpar->parent;
|
pair = xpar->parent;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (node == tmp2)
|
if (pair == tmp2)
|
||||||
{
|
{
|
||||||
node = xpar;
|
pair = xpar;
|
||||||
rotate (rbt, node, leftwise);
|
rotate (rbt, pair, leftwise);
|
||||||
xpar = node->parent;
|
xpar = pair->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
xpar->color = QSE_RBT_BLACK;
|
xpar->color = QSE_RBT_BLACK;
|
||||||
@ -400,60 +451,141 @@ static void adjust (qse_rbt_t* rbt, qse_rbt_node_t* node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_rbt_node_t* new_node (qse_rbt_t* rbt, int key, int value)
|
static pair_t* change_pair_val (
|
||||||
|
rbt_t* rbt, pair_t* pair, void* vptr, size_t vlen)
|
||||||
{
|
{
|
||||||
qse_rbt_node_t* node;
|
if (VPTR(pair) == vptr && VLEN(pair) == vlen)
|
||||||
|
{
|
||||||
|
/* if the old value and the new value are the same,
|
||||||
|
* it just calls the handler for this condition.
|
||||||
|
* No value replacement occurs. */
|
||||||
|
if (rbt->keeper != QSE_NULL)
|
||||||
|
{
|
||||||
|
rbt->keeper (rbt, vptr, vlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
copier_t vcop = rbt->copier[QSE_RBT_VAL];
|
||||||
|
void* ovptr = VPTR(pair);
|
||||||
|
size_t ovlen = VLEN(pair);
|
||||||
|
|
||||||
node = QSE_MMGR_ALLOC (rbt->mmgr, QSE_SIZEOF(*node));
|
/* place the new value according to the copier */
|
||||||
if (node == QSE_NULL) return QSE_NULL;
|
if (vcop == QSE_RBT_COPIER_SIMPLE)
|
||||||
|
{
|
||||||
|
VPTR(pair) = vptr;
|
||||||
|
VLEN(pair) = vlen;
|
||||||
|
}
|
||||||
|
else if (vcop == QSE_RBT_COPIER_INLINE)
|
||||||
|
{
|
||||||
|
if (ovlen == vlen)
|
||||||
|
{
|
||||||
|
QSE_MEMCPY (VPTR(pair), vptr, VTOB(rbt,vlen));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* need to reconstruct the pair */
|
||||||
|
pair_t* p = alloc_pair (rbt,
|
||||||
|
KPTR(pair), KLEN(pair),
|
||||||
|
vptr, vlen);
|
||||||
|
if (p == QSE_NULL) return QSE_NULL;
|
||||||
|
|
||||||
init_node (rbt, node, QSE_RBT_RED, key, value);
|
p->color = pair->color;
|
||||||
return node;
|
p->left = pair->left;
|
||||||
|
p->right = pair->right;
|
||||||
|
p->parent = pair->parent;
|
||||||
|
|
||||||
|
if (pair->parent)
|
||||||
|
{
|
||||||
|
if (pair->parent->left == pair)
|
||||||
|
{
|
||||||
|
pair->parent->left = p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QSE_ASSERT (parent->parent->right == pair);
|
||||||
|
pair->parent->right = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!IS_NIL(rbt,pair->left)) pair->left->parent = p;
|
||||||
|
if (!IS_NIL(rbt,pair->right)) pair->right->parent = p;
|
||||||
|
|
||||||
|
free_pair (rbt, pair);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
void* nvptr = vcop (rbt, vptr, vlen);
|
||||||
|
if (nvptr == QSE_NULL) return QSE_NULL;
|
||||||
|
VPTR(pair) = nvptr;
|
||||||
|
VLEN(pair) = vlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_node (qse_rbt_t* rbt, qse_rbt_node_t* node)
|
/* free up the old value */
|
||||||
|
if (rbt->freeer[QSE_RBT_VAL] != QSE_NULL)
|
||||||
{
|
{
|
||||||
/* TODO: call destructor... */
|
rbt->freeer[QSE_RBT_VAL] (rbt, ovptr, ovlen);
|
||||||
QSE_MMGR_FREE (rbt->mmgr, node);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_rbt_node_t* qse_rbt_insert (qse_rbt_t* rbt, int key, int value)
|
return pair;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pair_t* insert (
|
||||||
|
rbt_t* rbt, void* kptr, size_t klen, void* vptr, size_t vlen, int opt)
|
||||||
{
|
{
|
||||||
/* TODO: enhance this. ues comper... etc */
|
/* TODO: enhance this. ues comper... etc */
|
||||||
|
|
||||||
qse_rbt_node_t* xcur = rbt->root;
|
qse_rbt_pair_t* xcur = rbt->root;
|
||||||
qse_rbt_node_t* xpar = QSE_NULL;
|
qse_rbt_pair_t* xpar = QSE_NULL;
|
||||||
qse_rbt_node_t* xnew;
|
qse_rbt_pair_t* xnew;
|
||||||
|
|
||||||
while (!IS_NIL(rbt,xcur))
|
while (!IS_NIL(rbt,xcur))
|
||||||
{
|
{
|
||||||
if (key == xcur->key)
|
int n = rbt->comper (rbt, kptr, klen, xcur->kptr, xcur->klen);
|
||||||
|
if (n == 0)
|
||||||
{
|
{
|
||||||
/* TODO: handle various cases depending on insert types.
|
/* TODO: handle various cases depending on insert types.
|
||||||
* return error. update value. */
|
* return error. update value. */
|
||||||
xcur->value = value;
|
switch (opt)
|
||||||
|
{
|
||||||
|
case UPSERT:
|
||||||
|
case UPDATE:
|
||||||
|
return change_pair_val (rbt, xcur, vptr, vlen);
|
||||||
|
|
||||||
|
case ENSERT:
|
||||||
|
/* return existing pair */
|
||||||
return xcur;
|
return xcur;
|
||||||
|
|
||||||
|
case INSERT:
|
||||||
|
/* return failure */
|
||||||
|
return QSE_NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xpar = xcur;
|
xpar = xcur;
|
||||||
|
|
||||||
if (key > xcur->key) xcur = xcur->right;
|
if (n > 0) xcur = xcur->right;
|
||||||
else /* if (key < xcur->key) */ xcur = xcur->left;
|
else /* if (n < 0) */ xcur = xcur->left;
|
||||||
}
|
}
|
||||||
|
|
||||||
xnew = new_node (rbt, key, value);
|
if (opt == UPDATE) return QSE_NULL;
|
||||||
|
|
||||||
|
xnew = alloc_pair (rbt, kptr, klen, vptr, vlen);
|
||||||
if (xnew == QSE_NULL) return QSE_NULL;
|
if (xnew == QSE_NULL) return QSE_NULL;
|
||||||
|
|
||||||
if (xpar == QSE_NULL)
|
if (xpar == QSE_NULL)
|
||||||
{
|
{
|
||||||
/* the tree contains no node */
|
/* the tree contains no pair */
|
||||||
QSE_ASSERT (rbt->root == &rbt->nil);
|
QSE_ASSERT (rbt->root == &rbt->nil);
|
||||||
rbt->root = xnew;
|
rbt->root = xnew;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* perform normal binary insert */
|
/* perform normal binary insert */
|
||||||
if (key > xpar->key)
|
int n = rbt->comper (rbt, kptr, klen, xpar->kptr, xpar->klen);
|
||||||
|
if (n > 0)
|
||||||
{
|
{
|
||||||
QSE_ASSERT (xpar->right == &rbt->nil);
|
QSE_ASSERT (xpar->right == &rbt->nil);
|
||||||
xpar->right = xnew;
|
xpar->right = xnew;
|
||||||
@ -472,14 +604,39 @@ qse_rbt_node_t* qse_rbt_insert (qse_rbt_t* rbt, int key, int value)
|
|||||||
return xnew;
|
return xnew;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adjust_for_delete (
|
pair_t* qse_rbt_upsert (
|
||||||
qse_rbt_t* rbt, qse_rbt_node_t* node, qse_rbt_node_t* par)
|
rbt_t* rbt, void* kptr, size_t klen, void* vptr, size_t vlen)
|
||||||
{
|
{
|
||||||
while (node != rbt->root && node->color == QSE_RBT_BLACK)
|
return insert (rbt, kptr, klen, vptr, vlen, UPSERT);
|
||||||
{
|
}
|
||||||
qse_rbt_node_t* tmp;
|
|
||||||
|
|
||||||
if (node == par->left)
|
pair_t* qse_rbt_ensert (
|
||||||
|
rbt_t* rbt, void* kptr, size_t klen, void* vptr, size_t vlen)
|
||||||
|
{
|
||||||
|
return insert (rbt, kptr, klen, vptr, vlen, ENSERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
pair_t* qse_rbt_insert (
|
||||||
|
rbt_t* rbt, void* kptr, size_t klen, void* vptr, size_t vlen)
|
||||||
|
{
|
||||||
|
return insert (rbt, kptr, klen, vptr, vlen, INSERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pair_t* qse_rbt_update (
|
||||||
|
rbt_t* rbt, void* kptr, size_t klen, void* vptr, size_t vlen)
|
||||||
|
{
|
||||||
|
return insert (rbt, kptr, klen, vptr, vlen, UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adjust_for_delete (
|
||||||
|
qse_rbt_t* rbt, qse_rbt_pair_t* pair, qse_rbt_pair_t* par)
|
||||||
|
{
|
||||||
|
while (pair != rbt->root && pair->color == QSE_RBT_BLACK)
|
||||||
|
{
|
||||||
|
qse_rbt_pair_t* tmp;
|
||||||
|
|
||||||
|
if (pair == par->left)
|
||||||
{
|
{
|
||||||
tmp = par->right;
|
tmp = par->right;
|
||||||
if (tmp->color == QSE_RBT_RED)
|
if (tmp->color == QSE_RBT_RED)
|
||||||
@ -494,8 +651,8 @@ static void adjust_for_delete (
|
|||||||
tmp->right->color == QSE_RBT_BLACK)
|
tmp->right->color == QSE_RBT_BLACK)
|
||||||
{
|
{
|
||||||
if (!IS_NIL(rbt,tmp)) tmp->color = QSE_RBT_RED;
|
if (!IS_NIL(rbt,tmp)) tmp->color = QSE_RBT_RED;
|
||||||
node = par;
|
pair = par;
|
||||||
par = node->parent;
|
par = pair->parent;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -514,12 +671,12 @@ static void adjust_for_delete (
|
|||||||
tmp->right->color = QSE_RBT_BLACK;
|
tmp->right->color = QSE_RBT_BLACK;
|
||||||
|
|
||||||
rotate_left (rbt, par);
|
rotate_left (rbt, par);
|
||||||
node = rbt->root;
|
pair = rbt->root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QSE_ASSERT (node == par->right);
|
QSE_ASSERT (pair == par->right);
|
||||||
tmp = par->left;
|
tmp = par->left;
|
||||||
if (tmp->color == QSE_RBT_RED)
|
if (tmp->color == QSE_RBT_RED)
|
||||||
{
|
{
|
||||||
@ -533,8 +690,8 @@ static void adjust_for_delete (
|
|||||||
tmp->right->color == QSE_RBT_BLACK)
|
tmp->right->color == QSE_RBT_BLACK)
|
||||||
{
|
{
|
||||||
if (!IS_NIL(rbt,tmp)) tmp->color = QSE_RBT_RED;
|
if (!IS_NIL(rbt,tmp)) tmp->color = QSE_RBT_RED;
|
||||||
node = par;
|
pair = par;
|
||||||
par = node->parent;
|
par = pair->parent;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -552,28 +709,28 @@ static void adjust_for_delete (
|
|||||||
tmp->left->color = QSE_RBT_BLACK;
|
tmp->left->color = QSE_RBT_BLACK;
|
||||||
|
|
||||||
rotate_right (rbt, par);
|
rotate_right (rbt, par);
|
||||||
node = rbt->root;
|
pair = rbt->root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node->color = QSE_RBT_BLACK;
|
pair->color = QSE_RBT_BLACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete_node (qse_rbt_t* rbt, qse_rbt_node_t* node)
|
static void delete_pair (qse_rbt_t* rbt, qse_rbt_pair_t* pair)
|
||||||
{
|
{
|
||||||
qse_rbt_node_t* x, * y, * par;
|
qse_rbt_pair_t* x, * y, * par;
|
||||||
|
|
||||||
QSE_ASSERT (node && !IS_NIL(rbt,node));
|
QSE_ASSERT (pair && !IS_NIL(rbt,pair));
|
||||||
|
|
||||||
if (IS_NIL(rbt,node->left) || IS_NIL(rbt,node->right))
|
if (IS_NIL(rbt,pair->left) || IS_NIL(rbt,pair->right))
|
||||||
{
|
{
|
||||||
y = node;
|
y = pair;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* find a successor with NIL as a child */
|
/* find a successor with NIL as a child */
|
||||||
y = node->right;
|
y = pair->right;
|
||||||
while (!IS_NIL(rbt,y->left)) y = y->left;
|
while (!IS_NIL(rbt,y->left)) y = y->left;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,12 +751,12 @@ static void delete_node (qse_rbt_t* rbt, qse_rbt_node_t* node)
|
|||||||
rbt->root = x;
|
rbt->root = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y == node)
|
if (y == pair)
|
||||||
{
|
{
|
||||||
if (y->color == QSE_RBT_BLACK && !IS_NIL(rbt,x))
|
if (y->color == QSE_RBT_BLACK && !IS_NIL(rbt,x))
|
||||||
adjust_for_delete (rbt, x, par);
|
adjust_for_delete (rbt, x, par);
|
||||||
|
|
||||||
free_node (rbt, y);
|
free_pair (rbt, y);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -607,85 +764,133 @@ static void delete_node (qse_rbt_t* rbt, qse_rbt_node_t* node)
|
|||||||
adjust_for_delete (rbt, x, par);
|
adjust_for_delete (rbt, x, par);
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
if (node->parent)
|
if (pair->parent)
|
||||||
{
|
{
|
||||||
if (node->parent->left == node) node->parent->left = y;
|
if (pair->parent->left == pair) pair->parent->left = y;
|
||||||
if (node->parent->right == node) node->parent->right = y;
|
if (pair->parent->right == pair) pair->parent->right = y;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rbt->root = y;
|
rbt->root = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
y->parent = node->parent;
|
y->parent = pair->parent;
|
||||||
y->left = node->left;
|
y->left = pair->left;
|
||||||
y->right = node->right;
|
y->right = pair->right;
|
||||||
y->color = node->color;
|
y->color = pair->color;
|
||||||
|
|
||||||
if (node->left->parent == node) node->left->parent = y;
|
if (pair->left->parent == pair) pair->left->parent = y;
|
||||||
if (node->right->parent == node) node->right->parent = y;
|
if (pair->right->parent == pair) pair->right->parent = y;
|
||||||
#else
|
#else
|
||||||
*y = *node;
|
*y = *pair;
|
||||||
if (y->parent)
|
if (y->parent)
|
||||||
{
|
{
|
||||||
if (y->parent->left == node) y->parent->left = y;
|
if (y->parent->left == pair) y->parent->left = y;
|
||||||
if (y->parent->right == node) y->parent->right = y;
|
if (y->parent->right == pair) y->parent->right = y;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rbt->root = y;
|
rbt->root = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y->left->parent == node) y->left->parent = y;
|
if (y->left->parent == pair) y->left->parent = y;
|
||||||
if (y->right->parent == node) y->right->parent = y;
|
if (y->right->parent == pair) y->right->parent = y;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
free_node (rbt, node);
|
free_pair (rbt, pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: update tally */
|
rbt->size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qse_rbt_delete (qse_rbt_t* rbt, int key)
|
int qse_rbt_delete (qse_rbt_t* rbt, const void* kptr, size_t klen)
|
||||||
{
|
{
|
||||||
qse_rbt_node_t* node;
|
qse_rbt_pair_t* pair;
|
||||||
|
|
||||||
node = qse_rbt_search (rbt, key);
|
pair = qse_rbt_search (rbt, kptr, klen);
|
||||||
if (node == QSE_NULL) return -1;
|
if (pair == QSE_NULL) return -1;
|
||||||
|
|
||||||
delete_node (rbt, node);
|
delete_pair (rbt, pair);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qse_rbt_clear (qse_rbt_t* rbt)
|
void qse_rbt_clear (rbt_t* rbt)
|
||||||
{
|
{
|
||||||
/* TODO: improve this */
|
/* TODO: improve this */
|
||||||
while (!IS_NIL(rbt,rbt->root)) delete_node (rbt, rbt->root);
|
while (!IS_NIL(rbt,rbt->root)) delete_pair (rbt, rbt->root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_rbt_walk_t walk (
|
static QSE_INLINE void walk (rbt_t* rbt, walker_t walker, void* ctx, int l, int r)
|
||||||
qse_rbt_t* rbt, qse_rbt_walker_t walker,
|
|
||||||
void* ctx, qse_rbt_node_t* node)
|
|
||||||
{
|
{
|
||||||
if (!IS_NIL(rbt,node->left))
|
qse_rbt_pair_t* xcur = rbt->root;
|
||||||
|
qse_rbt_pair_t* prev = rbt->root->parent;
|
||||||
|
|
||||||
|
while (xcur && !IS_NIL(rbt,xcur))
|
||||||
{
|
{
|
||||||
if (walk (rbt, walker, ctx, node->left) == QSE_RBT_WALK_STOP)
|
if (prev == xcur->parent)
|
||||||
return QSE_RBT_WALK_STOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (walker (rbt, node, ctx) == QSE_RBT_WALK_STOP)
|
|
||||||
return QSE_RBT_WALK_STOP;
|
|
||||||
|
|
||||||
if (!IS_NIL(rbt,node->right))
|
|
||||||
{
|
{
|
||||||
if (walk (rbt, walker, ctx, node->right) == QSE_RBT_WALK_STOP)
|
/* the previous node is the parent of the current node.
|
||||||
return QSE_RBT_WALK_STOP;
|
* it indicates that we're going down to the child[l] */
|
||||||
}
|
if (!IS_NIL(rbt,xcur->child[l]))
|
||||||
|
|
||||||
return QSE_RBT_WALK_FORWARD;
|
|
||||||
}
|
|
||||||
|
|
||||||
void qse_rbt_walk (qse_rbt_t* rbt, qse_rbt_walker_t walker, void* ctx)
|
|
||||||
{
|
{
|
||||||
walk (rbt, walker, ctx, rbt->root);
|
/* go to the child[l] child */
|
||||||
|
prev = xcur;
|
||||||
|
xcur = xcur->child[l];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (walker (rbt, xcur, ctx) == QSE_RBT_WALK_STOP) break;
|
||||||
|
|
||||||
|
if (!IS_NIL(rbt,xcur->child[r]))
|
||||||
|
{
|
||||||
|
/* go down to the right node if exists */
|
||||||
|
prev = xcur;
|
||||||
|
xcur = xcur->child[r];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* otherwise, move up to the parent */
|
||||||
|
prev = xcur;
|
||||||
|
xcur = xcur->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (prev == xcur->child[l])
|
||||||
|
{
|
||||||
|
/* the left child has been already traversed */
|
||||||
|
|
||||||
|
if (walker (rbt, xcur, ctx) == QSE_RBT_WALK_STOP) break;
|
||||||
|
|
||||||
|
if (!IS_NIL(rbt,xcur->child[r]))
|
||||||
|
{
|
||||||
|
/* go down to the right node if it exists */
|
||||||
|
prev = xcur;
|
||||||
|
xcur = xcur->child[r];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* otherwise, move up to the parent */
|
||||||
|
prev = xcur;
|
||||||
|
xcur = xcur->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* both the left child and the right child have beem traversed */
|
||||||
|
QSE_ASSERT (prev == xcur->child[r]);
|
||||||
|
/* just move up to the parent */
|
||||||
|
prev = xcur;
|
||||||
|
xcur = xcur->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void qse_rbt_walk (rbt_t* rbt, walker_t walker, void* ctx)
|
||||||
|
{
|
||||||
|
walk (rbt, walker, ctx, LEFT, RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qse_rbt_rwalk (rbt_t* rbt, walker_t walker, void* ctx)
|
||||||
|
{
|
||||||
|
walk (rbt, walker, ctx, RIGHT, LEFT);
|
||||||
}
|
}
|
||||||
|
@ -11,22 +11,16 @@
|
|||||||
if (f() == -1) return -1; \
|
if (f() == -1) return -1; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static qse_rbt_walk_t walk (qse_rbt_t* rbt, qse_rbt_node_t* node, void* ctx)
|
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"), node->key, node->value);
|
qse_printf (QSE_T("key = %d, value = %d\n"),
|
||||||
|
*(int*)QSE_RBT_KPTR(pair), *(int*)QSE_RBT_VPTR(pair));
|
||||||
return QSE_RBT_WALK_FORWARD;
|
return QSE_RBT_WALK_FORWARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test1 ()
|
static int test1 ()
|
||||||
{
|
{
|
||||||
qse_rbt_t* s1;
|
qse_rbt_t* s1;
|
||||||
qse_char_t* x[] =
|
|
||||||
{
|
|
||||||
QSE_T("this is so good"),
|
|
||||||
QSE_T("what the fuck"),
|
|
||||||
QSE_T("do you like it?"),
|
|
||||||
QSE_T("oopsy!")
|
|
||||||
};
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
s1 = qse_rbt_open (QSE_MMGR_GETDFL(), 0);
|
s1 = qse_rbt_open (QSE_MMGR_GETDFL(), 0);
|
||||||
@ -36,52 +30,59 @@ static int test1 ()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qse_rbt_setcopier (s1, QSE_RBT_KEY, QSE_RBT_COPIER_INLINE);
|
||||||
|
qse_rbt_setcopier (s1, QSE_RBT_VAL, QSE_RBT_COPIER_INLINE);
|
||||||
|
/*
|
||||||
|
qse_rbt_setscale (s1, QSE_RBT_KEY, QSE_SIZEOF(int));
|
||||||
|
qse_rbt_setscale (s1, QSE_RBT_VAL, QSE_SIZEOF(int));
|
||||||
|
*/
|
||||||
/*
|
/*
|
||||||
qse_rbt_setcopier (s1, QSE_LDA_COPIER_INLINE);
|
|
||||||
qse_rbt_setkeeper (s1, keeper1);
|
qse_rbt_setkeeper (s1, keeper1);
|
||||||
qse_rbt_setscale (s1, QSE_SIZEOF(qse_char_t));
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i = 0; i < 20; i++)
|
for (i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
|
int x = i * 20;
|
||||||
qse_printf (QSE_T("inserting at %d\n"), i);
|
qse_printf (QSE_T("inserting at %d\n"), i);
|
||||||
qse_rbt_insert (s1, i, i * 20);
|
qse_rbt_insert (s1, &i, QSE_SIZEOF(i), &x, QSE_SIZEOF(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_rbt_walk (s1, walk, QSE_NULL);
|
qse_rbt_rwalk (s1, walk, QSE_NULL);
|
||||||
|
|
||||||
for (i = 0; i < 20; i += 2)
|
for (i = 0; i < 20; i += 2)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("deleting %d\n"), i);
|
qse_printf (QSE_T("deleting %d\n"), i);
|
||||||
qse_rbt_delete (s1, i);
|
qse_rbt_delete (s1, &i, QSE_SIZEOF(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_rbt_walk (s1, walk, QSE_NULL);
|
qse_rbt_rwalk (s1, walk, QSE_NULL);
|
||||||
|
|
||||||
for (i = 0; i < 20; i++)
|
for (i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
|
int x = i * 20;
|
||||||
qse_printf (QSE_T("inserting at %d\n"), i);
|
qse_printf (QSE_T("inserting at %d\n"), i);
|
||||||
qse_rbt_insert (s1, i, i * 20);
|
qse_rbt_insert (s1, &i, QSE_SIZEOF(i), &x, QSE_SIZEOF(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_rbt_walk (s1, walk, QSE_NULL);
|
qse_rbt_rwalk (s1, walk, QSE_NULL);
|
||||||
|
|
||||||
qse_rbt_clear (s1);
|
qse_rbt_clear (s1);
|
||||||
for (i = 20; i > 0; i--)
|
for (i = 20; i > 0; i--)
|
||||||
{
|
{
|
||||||
|
int x = i * 20;
|
||||||
qse_printf (QSE_T("inserting at %d\n"), i);
|
qse_printf (QSE_T("inserting at %d\n"), i);
|
||||||
qse_rbt_insert (s1, i, i * 20);
|
qse_rbt_insert (s1, &i, QSE_SIZEOF(i), &x, QSE_SIZEOF(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_rbt_walk (s1, walk, QSE_NULL);
|
qse_rbt_rwalk (s1, walk, QSE_NULL);
|
||||||
|
|
||||||
for (i = 0; i < 20; i += 3)
|
for (i = 0; i < 20; i += 3)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("deleting %d\n"), i);
|
qse_printf (QSE_T("deleting %d\n"), i);
|
||||||
qse_rbt_delete (s1, i);
|
qse_rbt_delete (s1, &i, QSE_SIZEOF(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_rbt_walk (s1, walk, QSE_NULL);
|
qse_rbt_rwalk (s1, walk, QSE_NULL);
|
||||||
|
|
||||||
qse_rbt_close (s1);
|
qse_rbt_close (s1);
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user