* Update comments
* Micro optimization
This commit is contained in:
1 parent
65e3f1049b
commit
b7f84236d3
1 file changed
+195
-157
+195
-157
@@ -120,27 +120,28 @@
|
||||
#define RBTREEI_GET_CHILD(x, n) ((x)->child[n])
|
||||
#define RBTREEI_SET_CHILD(x, n, y) ((x)->child[n] = (y))
|
||||
|
||||
// Color of a node of a Red/Black tree
|
||||
typedef enum {
|
||||
RBTREE_BLACK = 0, RBTREE_RED
|
||||
} rbtreei_color_e;
|
||||
|
||||
// General contact of a tree
|
||||
#define RBTREEI_CONTRACT(tree) do { \
|
||||
assert ((tree) != NULL); \
|
||||
assert ((tree)->node == NULL || RBTREEI_IS_BLACK((tree)->node)); \
|
||||
assert ((tree)->size != 0 || (tree)->node == NULL); \
|
||||
// General contact of a Read/Black tree
|
||||
#define RBTREEI_CONTRACT(tree) do { \
|
||||
assert ((tree) != NULL); \
|
||||
assert ((tree)->node == NULL || RBTREEI_IS_BLACK((tree)->node)); \
|
||||
assert ((tree)->size != 0 || (tree)->node == NULL); \
|
||||
} while (0)
|
||||
|
||||
// Contract of a node (doesn't check for equal depth in black)
|
||||
#define RBTREEI_CONTRACT_NODE(node) do { \
|
||||
assert((node) != NULL); \
|
||||
assert(RBTREEI_IS_BLACK(node) || RBTREEI_IS_RED(node)); \
|
||||
assert(RBTREEI_IS_BLACK(node) \
|
||||
|| (((node)->child[0] == NULL || RBTREEI_IS_BLACK(node->child[0])) \
|
||||
#define RBTREEI_CONTRACT_NODE(node) do { \
|
||||
assert((node) != NULL); \
|
||||
assert(RBTREEI_IS_BLACK(node) || RBTREEI_IS_RED(node)); \
|
||||
assert(RBTREEI_IS_BLACK(node) \
|
||||
|| (((node)->child[0] == NULL || RBTREEI_IS_BLACK(node->child[0])) \
|
||||
&& ((node)->child[1] == NULL || RBTREEI_IS_BLACK(node->child[1])))); \
|
||||
} while (0)
|
||||
|
||||
//TODO: UPDATE shall use a separate method than push
|
||||
//TODO: UPDATE method shall be a separate method than push method
|
||||
|
||||
/* Deferred evaluation for the rbtree definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
@@ -164,54 +165,69 @@ typedef enum {
|
||||
*/
|
||||
#define RBTREEI_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \
|
||||
\
|
||||
/* Node of Red/Black tree. \
|
||||
Each node has up to two child, a color (Red or black) \
|
||||
and the data stored in it */ \
|
||||
typedef struct M_C(name, _node_s) { \
|
||||
struct M_C(name, _node_s) *child[2]; \
|
||||
type data; \
|
||||
rbtreei_color_e color; \
|
||||
} node_t; \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
size_t size; \
|
||||
node_t *node; \
|
||||
/* Red/Black tree */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
size_t size; /* Number of elements in the tree */ \
|
||||
node_t *node; /* Root node of the tree */ \
|
||||
} tree_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
\
|
||||
/* Iterator on a tree. The iterator stores the full path to the \
|
||||
current node through all its parents and its depth */ \
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
node_t *stack[RBTREEI_MAX_STACK]; \
|
||||
int8_t which[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
/* Link with fast memory allocator if requested */ \
|
||||
M_IF_METHOD(MEMPOOL, oplist)( \
|
||||
/* Definition of the memory pool of this kind of node */ \
|
||||
MEMPOOL_DEF(M_C(name, _mempool), node_t) \
|
||||
/* Definition of the global variable used to reference this pool */ \
|
||||
M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \
|
||||
static inline node_t *M_C(name,_int_new)(void) { \
|
||||
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
|
||||
/* Allocator function */ \
|
||||
static inline node_t *M_C(name,_int_new)(void) { \
|
||||
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
|
||||
} \
|
||||
static inline void M_C(name,_int_del)(node_t *ptr) { \
|
||||
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
|
||||
/* Deallocator function */ \
|
||||
static inline void M_C(name,_int_del)(node_t *ptr) { \
|
||||
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
, /* No mempool allocation */ \
|
||||
\
|
||||
static inline node_t *M_C(name,_int_new)(void) { \
|
||||
/* Callic allocator function (common case) */ \
|
||||
static inline node_t *M_C(name,_int_new)(void) { \
|
||||
return M_CALL_NEW(oplist, node_t); \
|
||||
} \
|
||||
static inline void M_C(name,_int_del)(node_t *ptr) { \
|
||||
/* Callic deallocator function (common case) */ \
|
||||
static inline void M_C(name,_int_del)(node_t *ptr) { \
|
||||
M_CALL_DEL(oplist, ptr); \
|
||||
} ) \
|
||||
\
|
||||
\
|
||||
/* Check if the given oplist is compatible with the given type */ \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
/* Generate all functions */ \
|
||||
RBTREEI_DEF_P4(name, type, oplist, tree_t, node_t, it_t)
|
||||
|
||||
|
||||
#define RBTREEI_DEF_P4(name, type, oplist, tree_t, node_t, it_t) \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(tree_t tree) \
|
||||
M_C(name, _init)(tree_t tree) \
|
||||
{ \
|
||||
assert (tree != NULL); \
|
||||
tree->size = 0; \
|
||||
@@ -225,57 +241,70 @@ typedef enum {
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
node_t *stack[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt = 0; \
|
||||
/* If nothing (no node) nothing to clean: return */ \
|
||||
if (tree->node == NULL) return; \
|
||||
/* Parse all the tree */ \
|
||||
stack[cpt++] = tree->node; \
|
||||
while (cpt > 0) { \
|
||||
node_t *n = stack[cpt-1]; \
|
||||
/* Go down to the bottom left node that exists */ \
|
||||
while (true) { \
|
||||
RBTREEI_CONTRACT_NODE(n); \
|
||||
/* If there is a left child, get it */ \
|
||||
if (n->child[0] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
stack[cpt++] = n->child[0]; \
|
||||
n = n->child[0]; \
|
||||
stack[cpt-2]->child[0] = NULL; \
|
||||
/* If there is a right child, get it */ \
|
||||
} else if (n->child[1] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
stack[cpt++] = n->child[1]; \
|
||||
n = n->child[1]; \
|
||||
stack[cpt-2]->child[1] = NULL; \
|
||||
} else \
|
||||
/* No left nor right child, node can be deleted */ \
|
||||
} else { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
assert (n == stack[cpt - 1]); \
|
||||
/* Clear the bottom left node */ \
|
||||
M_CALL_CLEAR(oplist, n->data); \
|
||||
M_C(name,_int_del) (n); \
|
||||
M_C(name,_int_del) (n); \
|
||||
assert((stack[cpt-1] = NULL) == NULL); \
|
||||
/* Go up to the parent */ \
|
||||
cpt--; \
|
||||
} \
|
||||
/* Mark the root node as empty */ \
|
||||
tree->node = NULL; \
|
||||
tree->size = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(tree_t tree) \
|
||||
M_C(name, _clear)(tree_t tree) \
|
||||
{ \
|
||||
M_C(name, _clean)(tree); \
|
||||
/* Nothing more than clean the tree as everything is cleared */ \
|
||||
M_C(name, _clean)(tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push)(tree_t tree, type const data) \
|
||||
M_C(name, _push)(tree_t tree, type const data) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
node_t *tab[RBTREEI_MAX_STACK]; \
|
||||
int8_t which[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt = 0; \
|
||||
node_t *n = tree->node; \
|
||||
/* If nothing, create new node */ \
|
||||
/* If there is no root node, create a new node */ \
|
||||
if (n == NULL) { \
|
||||
n = M_C(name,_int_new)(); \
|
||||
n = M_C(name,_int_new)(); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (node_t)); \
|
||||
return; \
|
||||
} \
|
||||
/* Copy the data in the root node */ \
|
||||
M_CALL_INIT_SET(oplist, n->data, data); \
|
||||
/* Mark the root node as black */ \
|
||||
n->child[0] = n->child[1] = NULL; \
|
||||
RBTREEI_SET_BLACK (n); \
|
||||
tree->node = n; \
|
||||
@@ -284,46 +313,50 @@ typedef enum {
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
return; \
|
||||
} \
|
||||
/* Search for insertion point */ \
|
||||
/* Search for insertion point in the tree */ \
|
||||
tab[cpt] = n; \
|
||||
while (n != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE(n); \
|
||||
int cmp = M_CALL_CMP(oplist, n->data, data); \
|
||||
if (cmp == 0) { \
|
||||
/* key found ==> stop analysis */ \
|
||||
break; \
|
||||
} else if (cmp > 0) { \
|
||||
which[cpt++] = 0; \
|
||||
n = n->child[0]; \
|
||||
} else { \
|
||||
which[cpt++] = 1; \
|
||||
n = n->child[1]; \
|
||||
/* go left (if cmp > 0) or right (if cmp < 0) */ \
|
||||
int s = (cmp < 0); \
|
||||
which[cpt++] = s; \
|
||||
n = n->child[s]; \
|
||||
} \
|
||||
/* We cannot overflow the max depth of a tree */ \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
tab[cpt] = n; \
|
||||
} \
|
||||
/* If found, update the data (default is set) */ \
|
||||
if (n != NULL) { \
|
||||
/* FIXME: Use of SET method instead of UPDATE ? */ \
|
||||
M_IF_METHOD (UPDATE, oplist)(M_CALL_UPDATE(oplist, n->data, data) \
|
||||
, M_CALL_SET(oplist, n->data, data)); \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return; \
|
||||
} \
|
||||
/* Create new */ \
|
||||
n = M_C(name,_int_new)(); \
|
||||
/* Create new node to store the data */ \
|
||||
n = M_C(name,_int_new)(); \
|
||||
if (M_UNLIKELY (n == NULL) ) { \
|
||||
M_MEMORY_FULL (sizeof (node_t)); \
|
||||
return; \
|
||||
} \
|
||||
/* Copy the data and mark the node as red */ \
|
||||
M_CALL_INIT_SET(oplist, n->data, data); \
|
||||
n->child[0] = n->child[1] = NULL; \
|
||||
RBTREEI_SET_RED (n); \
|
||||
/* Add it in the iterator */ \
|
||||
assert (tab[cpt] == NULL); \
|
||||
tab[cpt] = n; \
|
||||
tree->size ++; \
|
||||
/* Add it in the tree */ \
|
||||
tree->size ++; \
|
||||
assert(tab[cpt-1]->child[0+which[cpt-1]] == NULL); \
|
||||
tab[cpt-1]->child[0+which[cpt-1]] = n; \
|
||||
/* Fix the tree */ \
|
||||
/* Fix the tree to still respect the red/back properties */ \
|
||||
while (cpt >= 2 \
|
||||
&& RBTREEI_IS_RED(tab[cpt-1]) \
|
||||
&& tab[cpt-2]->child[1-which[cpt-2]] != NULL \
|
||||
@@ -383,14 +416,15 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const tree_t tree) \
|
||||
M_C(name, _size)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return tree->size; \
|
||||
} \
|
||||
\
|
||||
/* Set the iterator to the first (child=0) or last (child=1) element */ \
|
||||
static inline void \
|
||||
M_C(name, _int_it)(it_t it, const tree_t tree, int child) \
|
||||
M_C(name, _int_it)(it_t it, const tree_t tree, int child) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
assert (it != NULL); \
|
||||
@@ -399,6 +433,7 @@ typedef enum {
|
||||
if (tree->node != NULL) { \
|
||||
it->which[cpt] = child; \
|
||||
node_t *n = it->stack[cpt++] = tree->node; \
|
||||
/* Go down the tree and fill in the iterator */ \
|
||||
while (n->child[child] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
n = n->child[child]; \
|
||||
@@ -411,47 +446,49 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const tree_t tree) \
|
||||
M_C(name, _it)(it_t it, const tree_t tree) \
|
||||
{ \
|
||||
M_C(name, _int_it)(it, tree, 0); \
|
||||
M_C(name, _int_it)(it, tree, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, const tree_t tree) \
|
||||
M_C(name, _it_last)(it_t it, const tree_t tree) \
|
||||
{ \
|
||||
M_C(name,_int_it)(it, tree, 1); \
|
||||
M_C(name,_int_it)(it, tree, 1); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const tree_t tree) \
|
||||
M_C(name, _it_end)(it_t it, const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
assert (it != NULL); \
|
||||
assert (it != NULL); \
|
||||
it->cpt = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t ref) \
|
||||
M_C(name, _it_set)(it_t it, const it_t ref) \
|
||||
{ \
|
||||
assert (it != NULL && ref != NULL); \
|
||||
*it = *ref; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->cpt == 0; \
|
||||
} \
|
||||
\
|
||||
/* Go to the next (child = 0)or previous element (child = 1) */ \
|
||||
static inline void \
|
||||
M_C(name, _int_next)(it_t it, int child) \
|
||||
M_C(name, _int_next)(it_t it, int child) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
assert (child == 0 || child == 1); \
|
||||
if (it->cpt == 0) return; \
|
||||
unsigned int cpt = it->cpt - 1; \
|
||||
node_t *n = it->stack[cpt]; \
|
||||
/* Get the other child */ \
|
||||
const int right = 1 ^ child; \
|
||||
if (n->child[right] != NULL && it->which[cpt] == child) { \
|
||||
/* Going right */ \
|
||||
@@ -476,19 +513,19 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _int_next)(it, 0); \
|
||||
M_C(name, _int_next)(it, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _int_next)(it, 1); \
|
||||
M_C(name, _int_next)(it, 1); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(const it_t it) \
|
||||
M_C(name, _ref)(const it_t it) \
|
||||
{ \
|
||||
assert(it != NULL && it->cpt > 0); \
|
||||
/* NOTE: partially unsafe if the user modify the order of the el */ \
|
||||
@@ -496,23 +533,22 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _ref)(it)); \
|
||||
return M_CONST_CAST(type, M_C(name, _ref)(it)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, \
|
||||
const it_t it2) \
|
||||
M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \
|
||||
{ \
|
||||
assert(it1 != NULL && it2 != NULL); \
|
||||
return it1->cpt == it2->cpt \
|
||||
&& it1->stack[it1->cpt-1] == it2->stack[it2->cpt-1]; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_from)(it_t it, \
|
||||
const tree_t tree, type const data) \
|
||||
M_C(name, _it_from)(it_t it, const tree_t tree, type const data) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
assert (it != NULL); \
|
||||
@@ -555,13 +591,13 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline bool M_ATTR_DEPRECATED \
|
||||
M_C(name, _it_to_p)(it_t it, type const data) \
|
||||
M_C(name, _it_to_p)(it_t it, type const data) \
|
||||
{ \
|
||||
return M_C(name, _it_until_p)(it, data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _min)(const tree_t tree) \
|
||||
M_C(name, _min)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
@@ -572,9 +608,9 @@ typedef enum {
|
||||
} \
|
||||
return &n->data; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _max)(const tree_t tree) \
|
||||
M_C(name, _max)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
@@ -585,82 +621,84 @@ typedef enum {
|
||||
} \
|
||||
return &n->data; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cmin)(const tree_t tree) \
|
||||
M_C(name, _cmin)(const tree_t tree) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _min)(tree)); \
|
||||
return M_CONST_CAST(type, M_C(name, _min)(tree)); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cmax)(const tree_t tree) \
|
||||
M_C(name, _cmax)(const tree_t tree) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _max)(tree)); \
|
||||
return M_CONST_CAST(type, M_C(name, _max)(tree)); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get)(const tree_t tree, type const data) \
|
||||
M_C(name, _get)(const tree_t tree, type const data) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
/* Go down the tree */ \
|
||||
while (n != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE (n); \
|
||||
int cmp = M_CALL_CMP(oplist, n->data, data); \
|
||||
if (cmp == 0) { \
|
||||
return &n->data; \
|
||||
} else if (cmp > 0) { \
|
||||
n = n->child[0]; \
|
||||
} else { \
|
||||
n = n->child[1]; \
|
||||
/* Go left (if cmp > 0) or right (if cmp < 0) */ \
|
||||
n = n->child[cmp < 0]; \
|
||||
} \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cget)(const tree_t tree, type const data) \
|
||||
M_C(name, _cget)(const tree_t tree, type const data) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \
|
||||
return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
/* Create a copy of the given node (recursively) */ \
|
||||
static inline node_t * \
|
||||
M_C(name, _int_copyn)(const node_t *o) \
|
||||
M_C(name, _int_copyn)(const node_t *o) \
|
||||
{ \
|
||||
if (o == NULL) return NULL; \
|
||||
node_t *n = M_C(name,_int_new)(); \
|
||||
node_t *n = M_C(name,_int_new)(); \
|
||||
if (M_UNLIKELY (n == NULL) ) { \
|
||||
M_MEMORY_FULL (sizeof (node_t)); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_CALL_INIT_SET(oplist, n->data, o->data); \
|
||||
n->child[0] = M_C(name, _int_copyn)(o->child[0]); \
|
||||
n->child[1] = M_C(name, _int_copyn)(o->child[1]); \
|
||||
n->child[0] = M_C(name, _int_copyn)(o->child[0]); \
|
||||
n->child[1] = M_C(name, _int_copyn)(o->child[1]); \
|
||||
RBTREEI_COPY_COLOR (n, o); \
|
||||
return n; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(tree_t tree, const tree_t ref) \
|
||||
M_C(name, _init_set)(tree_t tree, const tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
assert (tree != NULL && tree != ref); \
|
||||
tree->size = ref->size; \
|
||||
tree->node = M_C(name, _int_copyn)(ref->node); \
|
||||
/* Copy the root node recursively */ \
|
||||
tree->node = M_C(name, _int_copyn)(ref->node); \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(tree_t tree, const tree_t ref) \
|
||||
M_C(name, _set)(tree_t tree, const tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
if (tree == ref) return; \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_set)(tree, ref); \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_set)(tree, ref); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(tree_t tree, tree_t ref) \
|
||||
M_C(name, _init_move)(tree_t tree, tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
assert (tree != NULL && tree != ref); \
|
||||
@@ -672,18 +710,18 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(tree_t tree, tree_t ref) \
|
||||
M_C(name, _move)(tree_t tree, tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
assert (tree != ref); \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_move)(tree, ref); \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_move)(tree, ref); \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
|
||||
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree1); \
|
||||
RBTREEI_CONTRACT (tree2); \
|
||||
@@ -694,7 +732,7 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const tree_t tree) \
|
||||
M_C(name, _empty_p)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return tree->size == 0; \
|
||||
@@ -702,7 +740,7 @@ typedef enum {
|
||||
\
|
||||
/* Take care of the case n == NULL too */ \
|
||||
static inline bool \
|
||||
M_C(name, _int_is_black)(const node_t *n) \
|
||||
M_C(name, _int_is_black)(const node_t *n) \
|
||||
{ \
|
||||
return (n == NULL) ? true : RBTREEI_IS_BLACK(n); \
|
||||
} \
|
||||
@@ -714,7 +752,7 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline node_t * \
|
||||
M_C(name, _int_rotate)(node_t *pp, node_t *ppp, const bool right) \
|
||||
M_C(name, _int_rotate)(node_t *pp, node_t *ppp, const bool right) \
|
||||
{ \
|
||||
assert (pp != NULL && ppp != NULL); \
|
||||
bool left = !right; \
|
||||
@@ -729,12 +767,13 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
M_IF_DEBUG( \
|
||||
/* Compute the depth of a node */ \
|
||||
static size_t \
|
||||
M_C(name, _int_depth)(const node_t *n) \
|
||||
M_C(name, _int_depth)(const node_t *n) \
|
||||
{ \
|
||||
if (n == NULL) return 1; \
|
||||
return RBTREEI_IS_BLACK (n) \
|
||||
+ M_C(name, _int_depth)(n->child[0]); \
|
||||
+ M_C(name, _int_depth)(n->child[0]); \
|
||||
} \
|
||||
) \
|
||||
\
|
||||
@@ -752,8 +791,8 @@ typedef enum {
|
||||
tab[cpt] = n; \
|
||||
while (n != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE (n); \
|
||||
assert(M_C(name, _int_depth)(n->child[0]) \
|
||||
== M_C(name, _int_depth)(n->child[1])); \
|
||||
assert(M_C(name, _int_depth)(n->child[0]) \
|
||||
== M_C(name, _int_depth)(n->child[1])); \
|
||||
int cmp = M_CALL_CMP(oplist, n->data, key); \
|
||||
if (cmp == 0) { \
|
||||
break; \
|
||||
@@ -783,8 +822,8 @@ typedef enum {
|
||||
while (v != NULL) { \
|
||||
/* Always left node */ \
|
||||
RBTREEI_CONTRACT_NODE (v); \
|
||||
assert(M_C(name, _int_depth)(v->child[0]) \
|
||||
== M_C(name, _int_depth)(v->child[1])); \
|
||||
assert(M_C(name, _int_depth)(v->child[0]) \
|
||||
== M_C(name, _int_depth)(v->child[1])); \
|
||||
which[cpt++] = 0; \
|
||||
v = v->child[0]; \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
@@ -862,10 +901,10 @@ typedef enum {
|
||||
rbtreei_color_e p_color = RBTREEI_GET_COLOR (p); \
|
||||
if (childIsRight != nbChild) { \
|
||||
/* left-left or right-right case */ \
|
||||
p = M_C(name, _int_rotate) (p, tab[cpt-1], childIsRight); \
|
||||
p = M_C(name, _int_rotate) (p, tab[cpt-1], childIsRight); \
|
||||
} else { \
|
||||
s = M_C(name, _int_rotate) (s, p, childIsRight); \
|
||||
p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \
|
||||
s = M_C(name, _int_rotate) (s, p, childIsRight); \
|
||||
p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \
|
||||
} \
|
||||
RBTREEI_SET_COLOR(p, p_color); \
|
||||
assert(p->child[0] != NULL && p->child[1] != NULL); \
|
||||
@@ -906,22 +945,22 @@ typedef enum {
|
||||
structuraly different but functionnaly equal (you get this by \
|
||||
constructing the tree in a different way). We have to \
|
||||
compare the ordered value within the tree. */ \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
M_C(name, _it)(it2, t2); \
|
||||
while (!M_C(name, _end_p)(it1) \
|
||||
&& !M_C(name, _end_p)(it2)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
type const *ref2 = M_C(name, _cref)(it2); \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
M_C(name, _it)(it2, t2); \
|
||||
while (!M_C(name, _end_p)(it1) \
|
||||
&& !M_C(name, _end_p)(it2)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
type const *ref2 = M_C(name, _cref)(it2); \
|
||||
if (M_CALL_EQUAL(oplist, *ref1, *ref2) == false) \
|
||||
return false; \
|
||||
M_C(name, _next)(it1); \
|
||||
M_C(name, _next)(it2); \
|
||||
M_C(name, _next)(it1); \
|
||||
M_C(name, _next)(it2); \
|
||||
} \
|
||||
return M_C(name, _end_p)(it1) \
|
||||
&& M_C(name, _end_p)(it2); \
|
||||
return M_C(name, _end_p)(it1) \
|
||||
&& M_C(name, _end_p)(it2); \
|
||||
} \
|
||||
, /* NO EQUAL METHOD */ ) \
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(HASH, oplist)( \
|
||||
static inline size_t M_C(name,_hash)(const tree_t t1) { \
|
||||
RBTREEI_CONTRACT(t1); \
|
||||
@@ -929,57 +968,57 @@ typedef enum {
|
||||
/* NOTE: We can't compute the hash directly for the same reason \
|
||||
than for EQUAL operator. */ \
|
||||
it_t it1; \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
M_HASH_UP(hash, M_CALL_HASH(oplist, *ref1)); \
|
||||
M_C(name, _next)(it1); \
|
||||
M_C(name, _next)(it1); \
|
||||
} \
|
||||
return M_HASH_FINAL (hash); \
|
||||
return M_HASH_FINAL (hash); \
|
||||
} \
|
||||
, /* NO HASH METHOD */ ) \
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
tree_t const t1, bool append) { \
|
||||
tree_t const t1, bool append) { \
|
||||
RBTREEI_CONTRACT(t1); \
|
||||
assert(str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
/* NOTE: The print is really naive, and not really efficient */ \
|
||||
bool commaToPrint = false; \
|
||||
it_t it1; \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
if (commaToPrint) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
commaToPrint = true; \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
M_CALL_GET_STR(oplist, str, *ref1, true); \
|
||||
M_C(name, _next)(it1); \
|
||||
M_C(name, _next)(it1); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* NO GET_STR */ ) \
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(OUT_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, tree_t const rbtree) \
|
||||
M_C(name, _out_str)(FILE *file, tree_t const rbtree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(rbtree); \
|
||||
assert (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
fputc ('[', file); \
|
||||
it_t it; \
|
||||
bool commaToPrint = false; \
|
||||
for (M_C(name, _it)(it, rbtree) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
for (M_C(name, _it)(it, rbtree) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
if (commaToPrint) \
|
||||
fputc (M_GET_SEPARATOR oplist, file); \
|
||||
commaToPrint = true; \
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
M_CALL_OUT_STR(oplist, file, *item); \
|
||||
} \
|
||||
fputc (']', file); \
|
||||
fputc (']', file); \
|
||||
} \
|
||||
, /* no out_str */ ) \
|
||||
\
|
||||
@@ -1020,8 +1059,8 @@ typedef enum {
|
||||
{ \
|
||||
RBTREEI_CONTRACT(rbtree); \
|
||||
assert (file != NULL); \
|
||||
M_C(name,_clean)(rbtree); \
|
||||
int c = fgetc(file); \
|
||||
M_C(name,_clean)(rbtree); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
if (M_UNLIKELY (c == ']')) return true; \
|
||||
@@ -1032,37 +1071,36 @@ typedef enum {
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
do { c = fgetc(file); } while (isspace(c)); \
|
||||
if (b == false || c == EOF) break; \
|
||||
M_C(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
if (b == false || c == EOF) break; \
|
||||
M_C(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no in_str */ ) \
|
||||
\
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(OUT_SERIAL, oplist)( \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(t1); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
const M_C(name, _type_t) *item; \
|
||||
bool first_done = false; \
|
||||
it_t it; \
|
||||
ret = f->m_interface->write_array_start(local, f, t1->size); \
|
||||
ret = f->m_interface->write_array_start(local, f, t1->size); \
|
||||
for (M_C(name, _it)(it, t1) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
item = M_C(name, _cref)(it); \
|
||||
if (first_done) \
|
||||
ret |= f->m_interface->write_array_next(local, f); \
|
||||
ret |= f->m_interface->write_array_next(local, f); \
|
||||
ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \
|
||||
first_done = true; \
|
||||
} \
|
||||
ret |= f->m_interface->write_array_end(local, f); \
|
||||
ret |= f->m_interface->write_array_end(local, f); \
|
||||
return ret & M_SERIAL_FAIL; \
|
||||
} \
|
||||
, /* no OUT_SERIAL */ ) \
|
||||
@@ -1072,12 +1110,12 @@ typedef enum {
|
||||
M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(t1); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
size_t estimated_size = 0; \
|
||||
type key; \
|
||||
M_C(name,_clean)(t1); \
|
||||
type key; \
|
||||
M_C(name,_clean)(t1); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
M_CALL_INIT(oplist, key); \
|
||||
|
||||
Reference in new issue
Block a user