mirror of
https://github.com/protobuf-c/protobuf-c.git
synced 2024-12-28 14:48:18 +08:00
git-svn-id: https://protobuf-c.googlecode.com/svn/trunk@112 00440858-1255-0410-a3e6-75ea37f81c3a
This commit is contained in:
parent
13a6f6f8e1
commit
73cb6e3023
981
src/google/protobuf-c/gskrbtreemacros.h
Normal file
981
src/google/protobuf-c/gskrbtreemacros.h
Normal file
@ -0,0 +1,981 @@
|
||||
#ifndef __GSK_RBTREE_MACROS_H_
|
||||
#define __GSK_RBTREE_MACROS_H_
|
||||
|
||||
/* Macros for construction of a red-black tree.
|
||||
* Like our other macro-based data-structures,
|
||||
* this doesn't allocate memory, and it doesn't
|
||||
* use any helper functions.
|
||||
*
|
||||
* It supports "invasive" tree structures,
|
||||
* for example, you can have nodes that are members
|
||||
* of two different trees.
|
||||
*
|
||||
* A rbtree is a tuple:
|
||||
* top
|
||||
* type*
|
||||
* is_red
|
||||
* set_is_red
|
||||
* parent
|
||||
* left
|
||||
* right
|
||||
* comparator
|
||||
* that should be defined by a macro like "GET_TREE()".
|
||||
* See tests/test-rbtree-macros.
|
||||
*
|
||||
* The methods are:
|
||||
* INSERT(tree, node, collision_node)
|
||||
* Try to insert 'node' into tree.
|
||||
* If an equivalent node exists,
|
||||
* return it in collision_node, and do nothing else.
|
||||
* Otherwise, node is added to the tree
|
||||
* (and collision_node is set to NULL).
|
||||
* REMOVE(tree, node)
|
||||
* Remove a node from the tree.
|
||||
* LOOKUP(tree, node, out)
|
||||
* Find a node in the tree.
|
||||
* Finds the node equivalent with
|
||||
* 'node', and returns it in 'out',
|
||||
* or sets out to NULL if no node exists.
|
||||
* LOOKUP_COMPARATOR(tree, key, key_comparator, out)
|
||||
* Find a node in the tree, based on a key
|
||||
* which may not be in the same format as the node.
|
||||
* FIRST(tree, out)
|
||||
* Set 'out' to the first node in the tree.
|
||||
* LAST(tree, out)
|
||||
* Set 'out' to the last node in the tree.
|
||||
* PREV(tree, cur, out)
|
||||
* Set 'out' to the previous node in the tree before cur.
|
||||
* NEXT(tree, cur, out)
|
||||
* Set 'out' to the next node in the tree after cur.
|
||||
* INFIMUM_COMPARATOR(tree, key, key_comparator, out)
|
||||
* Find the last node in the tree which is before or equal to 'key'.
|
||||
* SUPREMUM_COMPARATOR(tree, key, key_comparator, out)
|
||||
* Find the first node in the tree which is after or equal to 'key'.
|
||||
* INFIMUM(tree, key, out)
|
||||
* Find the last node in the tree which is before or equal to 'key'.
|
||||
* SUPREMUM(tree, key, out)
|
||||
* Find the first node in the tree which is after or equal to 'key'.
|
||||
*
|
||||
* XXX: how about rename INFIMUM, SUPREMUM as LOOKUP_LE, LOOKUP_GE * respectively?
|
||||
* That is, LOOKUP_LE returns the largest elt less-than-or-equal-to the key
|
||||
* and LOOKUP_GE returns the smallest elt greater-than-or-equal-to the key.
|
||||
* You can think of it as a lookup that allows "slip" in the direction indicated.
|
||||
* LOOKUP_LT and LOOKUP_GT would be natural methods too-- for lookups
|
||||
* that don't permit equality.
|
||||
*
|
||||
*
|
||||
* Occasionally, you may need the "RBCTREE", which has the is_red flag,
|
||||
* but also keeps a "count" field at every node telling the size of that subtree.
|
||||
* This then has all the methods of RBTREE, plus:
|
||||
* GET_BY_INDEX(tree, n, out)
|
||||
* Return the n-th element in the tree.
|
||||
* GET_BY_INDEX_UNCHECKED(tree, n, out)
|
||||
* Return the n-th element in the tree;
|
||||
* n MUST be less than or equal to the number of
|
||||
* nodes in the tree.
|
||||
* GET_NODE_INDEX(tree, node, n_out)
|
||||
* Sets n_out to the index of node in the tree.
|
||||
*
|
||||
* An rbctree is a tuple:
|
||||
* top
|
||||
* type*
|
||||
* is_red
|
||||
* set_is_red
|
||||
* get_count
|
||||
* set_count
|
||||
* parent
|
||||
* left
|
||||
* right
|
||||
* comparator
|
||||
*/
|
||||
|
||||
/*
|
||||
* By and large, the red-black tree algorithms used here are from
|
||||
* the classic text:
|
||||
* _Introduction to Algorithms_. Thomas Cormen, Charles Leiserson,
|
||||
* and Donald Rivest. MIT Press. 1990.
|
||||
* Citations appears as Algorithms:300 indicating page 300 (for example).
|
||||
* The "rbctree" is my name for this idea (daveb),
|
||||
* which i suspect has been thought of and implemented before.
|
||||
*/
|
||||
#define GSK_RBTREE_INSERT(tree, node, collision_node) \
|
||||
GSK_RBTREE_INSERT_(tree, node, collision_node)
|
||||
#define GSK_RBTREE_REMOVE(tree, node) \
|
||||
GSK_RBTREE_REMOVE_(tree, node)
|
||||
#define GSK_RBTREE_LOOKUP(tree, key, out) \
|
||||
GSK_RBTREE_LOOKUP_(tree, key, out)
|
||||
#define GSK_RBTREE_LOOKUP_COMPARATOR(tree, key, key_comparator, out) \
|
||||
GSK_RBTREE_LOOKUP_COMPARATOR_(tree, key, key_comparator, out)
|
||||
|
||||
#define GSK_RBTREE_FIRST(tree, out) \
|
||||
GSK_RBTREE_FIRST_(tree, out)
|
||||
#define GSK_RBTREE_LAST(tree, out) \
|
||||
GSK_RBTREE_LAST_(tree, out)
|
||||
#define GSK_RBTREE_NEXT(tree, in, out) \
|
||||
GSK_RBTREE_NEXT_(tree, in, out)
|
||||
#define GSK_RBTREE_PREV(tree, in, out) \
|
||||
GSK_RBTREE_PREV_(tree, in, out)
|
||||
|
||||
#define GSK_RBTREE_SUPREMUM(tree, key, out) \
|
||||
GSK_RBTREE_SUPREMUM_(tree, key, out)
|
||||
#define GSK_RBTREE_SUPREMUM_COMPARATOR(tree, key, key_comparator, out) \
|
||||
GSK_RBTREE_SUPREMUM_COMPARATOR_(tree, key, key_comparator, out)
|
||||
#define GSK_RBTREE_INFIMUM(tree, key, out) \
|
||||
GSK_RBTREE_INFIMUM_(tree, key, out)
|
||||
#define GSK_RBTREE_INFIMUM_COMPARATOR(tree, key, key_comparator, out) \
|
||||
GSK_RBTREE_INFIMUM_COMPARATOR_(tree, key, key_comparator, out)
|
||||
|
||||
#if 1
|
||||
#undef G_STMT_START
|
||||
#define G_STMT_START do
|
||||
#undef G_STMT_END
|
||||
#define G_STMT_END while(0)
|
||||
#endif
|
||||
|
||||
#define GSK_RBTREE_INSERT_(top,type,is_red,set_is_red,parent,left,right,comparator, node,collision_node) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_last = NULL; \
|
||||
type _gsk_at = (top); \
|
||||
gboolean _gsk_last_was_left = FALSE; \
|
||||
collision_node = NULL; \
|
||||
while (_gsk_at != NULL) \
|
||||
{ \
|
||||
int _gsk_compare_rv; \
|
||||
_gsk_last = _gsk_at; \
|
||||
comparator(_gsk_at, (node), _gsk_compare_rv); \
|
||||
if (_gsk_compare_rv > 0) \
|
||||
{ \
|
||||
_gsk_last_was_left = TRUE; \
|
||||
_gsk_at = _gsk_at->left; \
|
||||
} \
|
||||
else if (_gsk_compare_rv < 0) \
|
||||
{ \
|
||||
_gsk_last_was_left = FALSE; \
|
||||
_gsk_at = _gsk_at->right; \
|
||||
} \
|
||||
else \
|
||||
break; \
|
||||
} \
|
||||
if (_gsk_at != NULL) \
|
||||
{ \
|
||||
/* collision */ \
|
||||
collision_node = _gsk_at; \
|
||||
} \
|
||||
else if (_gsk_last == NULL) \
|
||||
{ \
|
||||
/* only node in tree */ \
|
||||
top = (node); \
|
||||
set_is_red ((node), 0); \
|
||||
(node)->left = (node)->right = (node)->parent = NULL; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
(node)->parent = _gsk_last; \
|
||||
(node)->left = (node)->right = NULL; \
|
||||
if (_gsk_last_was_left) \
|
||||
_gsk_last->left = (node); \
|
||||
else \
|
||||
_gsk_last->right = (node); \
|
||||
\
|
||||
/* fixup */ \
|
||||
_gsk_at = (node); \
|
||||
set_is_red (_gsk_at, 1); \
|
||||
while (top != _gsk_at && is_red(_gsk_at->parent)) \
|
||||
{ \
|
||||
if (_gsk_at->parent == _gsk_at->parent->parent->left) \
|
||||
{ \
|
||||
type _gsk_y = _gsk_at->parent->parent->right; \
|
||||
if (_gsk_y != NULL && is_red (_gsk_y)) \
|
||||
{ \
|
||||
set_is_red (_gsk_at->parent, 0); \
|
||||
set_is_red (_gsk_y, 0); \
|
||||
set_is_red (_gsk_at->parent->parent, 1); \
|
||||
_gsk_at = _gsk_at->parent->parent; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (_gsk_at == _gsk_at->parent->right) \
|
||||
{ \
|
||||
_gsk_at = _gsk_at->parent; \
|
||||
GSK_RBTREE_ROTATE_LEFT (top,type,parent,left,right, _gsk_at);\
|
||||
} \
|
||||
set_is_red(_gsk_at->parent, 0); \
|
||||
set_is_red(_gsk_at->parent->parent, 1); \
|
||||
GSK_RBTREE_ROTATE_RIGHT (top,type,parent,left,right, \
|
||||
_gsk_at->parent->parent); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
type _gsk_y = _gsk_at->parent->parent->left; \
|
||||
if (_gsk_y != NULL && is_red (_gsk_y)) \
|
||||
{ \
|
||||
set_is_red (_gsk_at->parent, 0); \
|
||||
set_is_red (_gsk_y, 0); \
|
||||
set_is_red (_gsk_at->parent->parent, 1); \
|
||||
_gsk_at = _gsk_at->parent->parent; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (_gsk_at == _gsk_at->parent->left) \
|
||||
{ \
|
||||
_gsk_at = _gsk_at->parent; \
|
||||
GSK_RBTREE_ROTATE_RIGHT (top,type,parent,left,right, \
|
||||
_gsk_at); \
|
||||
} \
|
||||
set_is_red(_gsk_at->parent, 0); \
|
||||
set_is_red(_gsk_at->parent->parent, 1); \
|
||||
GSK_RBTREE_ROTATE_LEFT (top,type,parent,left,right, \
|
||||
_gsk_at->parent->parent); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
set_is_red((top), 0); \
|
||||
} \
|
||||
}G_STMT_END
|
||||
|
||||
#define GSK_RBTREE_REMOVE_(top,type,is_red,set_is_red,parent,left,right,comparator, node) \
|
||||
/* Algorithms:273. */ \
|
||||
G_STMT_START{ \
|
||||
type _gsk_rb_del_z = (node); \
|
||||
type _gsk_rb_del_x; \
|
||||
type _gsk_rb_del_y; \
|
||||
type _gsk_rb_del_nullpar = NULL; /* Used to emulate sentinel nodes */ \
|
||||
gboolean _gsk_rb_del_fixup; \
|
||||
if (_gsk_rb_del_z->left == NULL || _gsk_rb_del_z->right == NULL) \
|
||||
_gsk_rb_del_y = _gsk_rb_del_z; \
|
||||
else \
|
||||
{ \
|
||||
GSK_RBTREE_NEXT_ (top,type,is_red,set_is_red,parent,left,right,comparator,\
|
||||
_gsk_rb_del_z, _gsk_rb_del_y); \
|
||||
} \
|
||||
_gsk_rb_del_x = _gsk_rb_del_y->left ? _gsk_rb_del_y->left \
|
||||
: _gsk_rb_del_y->right; \
|
||||
if (_gsk_rb_del_x) \
|
||||
_gsk_rb_del_x->parent = _gsk_rb_del_y->parent; \
|
||||
else \
|
||||
_gsk_rb_del_nullpar = _gsk_rb_del_y->parent; \
|
||||
if (!_gsk_rb_del_y->parent) \
|
||||
top = _gsk_rb_del_x; \
|
||||
else \
|
||||
{ \
|
||||
if (_gsk_rb_del_y == _gsk_rb_del_y->parent->left) \
|
||||
_gsk_rb_del_y->parent->left = _gsk_rb_del_x; \
|
||||
else \
|
||||
_gsk_rb_del_y->parent->right = _gsk_rb_del_x; \
|
||||
} \
|
||||
_gsk_rb_del_fixup = !is_red(_gsk_rb_del_y); \
|
||||
if (_gsk_rb_del_y != _gsk_rb_del_z) \
|
||||
{ \
|
||||
set_is_red(_gsk_rb_del_y, is_red(_gsk_rb_del_z)); \
|
||||
_gsk_rb_del_y->left = _gsk_rb_del_z->left; \
|
||||
_gsk_rb_del_y->right = _gsk_rb_del_z->right; \
|
||||
_gsk_rb_del_y->parent = _gsk_rb_del_z->parent; \
|
||||
if (_gsk_rb_del_y->parent) \
|
||||
{ \
|
||||
if (_gsk_rb_del_y->parent->left == _gsk_rb_del_z) \
|
||||
_gsk_rb_del_y->parent->left = _gsk_rb_del_y; \
|
||||
else \
|
||||
_gsk_rb_del_y->parent->right = _gsk_rb_del_y; \
|
||||
} \
|
||||
else \
|
||||
top = _gsk_rb_del_y; \
|
||||
\
|
||||
if (_gsk_rb_del_y->left) \
|
||||
_gsk_rb_del_y->left->parent = _gsk_rb_del_y; \
|
||||
if (_gsk_rb_del_y->right) \
|
||||
_gsk_rb_del_y->right->parent = _gsk_rb_del_y; \
|
||||
if (_gsk_rb_del_nullpar == _gsk_rb_del_z) \
|
||||
_gsk_rb_del_nullpar = _gsk_rb_del_y; \
|
||||
} \
|
||||
if (_gsk_rb_del_fixup) \
|
||||
{ \
|
||||
/* delete fixup (Algorithms, p 274) */ \
|
||||
while (_gsk_rb_del_x != top \
|
||||
&& !(_gsk_rb_del_x != NULL && is_red (_gsk_rb_del_x))) \
|
||||
{ \
|
||||
type _gsk_rb_del_xparent = _gsk_rb_del_x ? _gsk_rb_del_x->parent \
|
||||
: _gsk_rb_del_nullpar; \
|
||||
if (_gsk_rb_del_x == _gsk_rb_del_xparent->left) \
|
||||
{ \
|
||||
type _gsk_rb_del_w = _gsk_rb_del_xparent->right; \
|
||||
if (_gsk_rb_del_w != NULL && is_red (_gsk_rb_del_w)) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w, 0); \
|
||||
set_is_red (_gsk_rb_del_xparent, 1); \
|
||||
GSK_RBTREE_ROTATE_LEFT (top,type,parent,left,right, \
|
||||
_gsk_rb_del_xparent); \
|
||||
_gsk_rb_del_w = _gsk_rb_del_xparent->right; \
|
||||
} \
|
||||
if (!(_gsk_rb_del_w->left && is_red (_gsk_rb_del_w->left)) \
|
||||
&& !(_gsk_rb_del_w->right && is_red (_gsk_rb_del_w->right))) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w, 1); \
|
||||
_gsk_rb_del_x = _gsk_rb_del_xparent; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (!(_gsk_rb_del_w->right && is_red (_gsk_rb_del_w->right)))\
|
||||
{ \
|
||||
if (_gsk_rb_del_w->left) \
|
||||
set_is_red (_gsk_rb_del_w->left, 0); \
|
||||
set_is_red (_gsk_rb_del_w, 1); \
|
||||
GSK_RBTREE_ROTATE_RIGHT (top,type,parent,left,right, \
|
||||
_gsk_rb_del_w); \
|
||||
_gsk_rb_del_w = _gsk_rb_del_xparent->right; \
|
||||
} \
|
||||
set_is_red (_gsk_rb_del_w, is_red (_gsk_rb_del_xparent)); \
|
||||
set_is_red (_gsk_rb_del_xparent, 0); \
|
||||
set_is_red (_gsk_rb_del_w->right, 0); \
|
||||
GSK_RBTREE_ROTATE_LEFT (top,type,parent,left,right, \
|
||||
_gsk_rb_del_xparent); \
|
||||
_gsk_rb_del_x = top; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
type _gsk_rb_del_w = _gsk_rb_del_xparent->left; \
|
||||
if (_gsk_rb_del_w && is_red (_gsk_rb_del_w)) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w, 0); \
|
||||
set_is_red (_gsk_rb_del_xparent, 1); \
|
||||
GSK_RBTREE_ROTATE_RIGHT (top,type,parent,left,right, \
|
||||
_gsk_rb_del_xparent); \
|
||||
_gsk_rb_del_w = _gsk_rb_del_xparent->left; \
|
||||
} \
|
||||
if (!(_gsk_rb_del_w->right && is_red (_gsk_rb_del_w->right)) \
|
||||
&& !(_gsk_rb_del_w->left && is_red (_gsk_rb_del_w->left))) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w, 1); \
|
||||
_gsk_rb_del_x = _gsk_rb_del_xparent; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (!(_gsk_rb_del_w->left && is_red (_gsk_rb_del_w->left))) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w->right, 0); \
|
||||
set_is_red (_gsk_rb_del_w, 1); \
|
||||
GSK_RBTREE_ROTATE_LEFT (top,type,parent,left,right, \
|
||||
_gsk_rb_del_w); \
|
||||
_gsk_rb_del_w = _gsk_rb_del_xparent->left; \
|
||||
} \
|
||||
set_is_red (_gsk_rb_del_w, is_red (_gsk_rb_del_xparent)); \
|
||||
set_is_red (_gsk_rb_del_xparent, 0); \
|
||||
if (_gsk_rb_del_w->left) \
|
||||
set_is_red (_gsk_rb_del_w->left, 0); \
|
||||
GSK_RBTREE_ROTATE_RIGHT (top,type,parent,left,right, \
|
||||
_gsk_rb_del_xparent); \
|
||||
_gsk_rb_del_x = top; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (_gsk_rb_del_x != NULL) \
|
||||
set_is_red(_gsk_rb_del_x, 0); \
|
||||
} \
|
||||
_gsk_rb_del_z->left = NULL; \
|
||||
_gsk_rb_del_z->right = NULL; \
|
||||
_gsk_rb_del_z->parent = NULL; \
|
||||
}G_STMT_END
|
||||
|
||||
#define GSK_RBTREE_LOOKUP_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, \
|
||||
key,key_comparator,out) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_lookup_at = (top); \
|
||||
while (_gsk_lookup_at) \
|
||||
{ \
|
||||
int _gsk_compare_rv; \
|
||||
key_comparator(key,_gsk_lookup_at,_gsk_compare_rv); \
|
||||
if (_gsk_compare_rv < 0) \
|
||||
_gsk_lookup_at = _gsk_lookup_at->left; \
|
||||
else if (_gsk_compare_rv > 0) \
|
||||
_gsk_lookup_at = _gsk_lookup_at->right; \
|
||||
else \
|
||||
break; \
|
||||
} \
|
||||
out = _gsk_lookup_at; \
|
||||
}G_STMT_END
|
||||
/* see comments for 'SUPREMUM'; it is the same with the sense of the comparators
|
||||
* and left,right reversed. */
|
||||
#define GSK_RBTREE_INFIMUM_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, \
|
||||
key,key_comparator,out) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_lookup_at = (top); \
|
||||
type _gsk_lookup_rv = NULL; \
|
||||
while (_gsk_lookup_at) \
|
||||
{ \
|
||||
int _gsk_compare_rv; \
|
||||
key_comparator(key,_gsk_lookup_at,_gsk_compare_rv); \
|
||||
if (_gsk_compare_rv >= 0) \
|
||||
{ \
|
||||
_gsk_lookup_rv = _gsk_lookup_at; \
|
||||
_gsk_lookup_at = _gsk_lookup_at->right; \
|
||||
} \
|
||||
else \
|
||||
_gsk_lookup_at = _gsk_lookup_at->left; \
|
||||
} \
|
||||
out = _gsk_lookup_rv; \
|
||||
}G_STMT_END
|
||||
/* see introductory comments for a less mathematical
|
||||
* definition. but what 'supremum' computes is:
|
||||
* sup(tree, key) = min S(tree,key) or NULL if S(tree, key)
|
||||
* is empty, where S(tree,key) = { t | t \in tree && t >= key }.
|
||||
* The 'min' is determined by the 'comparator',
|
||||
* and the 't >= key' is determined by the 'key_comparator'.
|
||||
* But they must be consistent.
|
||||
*
|
||||
* so, here's a recursive description. suppose we wish to compute
|
||||
* the supremum sup(a, key), where 'a' is the node in the tree shown:
|
||||
* a
|
||||
* / \
|
||||
* b c
|
||||
* Is 'a >= key'? Then 'a' is in S(a, key),
|
||||
* and hence sup(a,key) exists. But a "better" supremum,
|
||||
* in terms of being the 'min' in the tree,
|
||||
* may lie in 'b'. Nothing better may lie in 'c', since it
|
||||
* is larger, and we are computing a minimum of S.
|
||||
*
|
||||
* But if 'a < key', then 'a' is not in S. hence 'b' and its children
|
||||
* are not in S. Hence sup(a) = sup(c), including the possibility that
|
||||
* sup(C) = NULL.
|
||||
*
|
||||
* Therefore,
|
||||
*
|
||||
* sup(b) if 'a >= key', and sub(b) exists, [case0]
|
||||
* sup(a) = a if 'a >= key', and sub(b) does not exist, [case1]
|
||||
* sup(c) if 'a < key' and sub(c) exists, [case2]
|
||||
* NULL if 'a < key' and sub(c) does not exist. [case3]
|
||||
*
|
||||
* the non-recursive algo follows once you realize that it's just
|
||||
* a tree descent, keeping track of the best candidate you've found.
|
||||
* TODO: there's got to be a better way to describe it.
|
||||
*/
|
||||
#define GSK_RBTREE_SUPREMUM_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, \
|
||||
key,key_comparator,out) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_lookup_at = (top); \
|
||||
type _gsk_lookup_rv = NULL; \
|
||||
while (_gsk_lookup_at) \
|
||||
{ \
|
||||
int _gsk_compare_rv; \
|
||||
key_comparator(key,_gsk_lookup_at,_gsk_compare_rv); \
|
||||
if (_gsk_compare_rv <= 0) \
|
||||
{ \
|
||||
_gsk_lookup_rv = _gsk_lookup_at; \
|
||||
_gsk_lookup_at = _gsk_lookup_at->left; \
|
||||
} \
|
||||
else \
|
||||
_gsk_lookup_at = _gsk_lookup_at->right; \
|
||||
} \
|
||||
out = _gsk_lookup_rv; \
|
||||
}G_STMT_END
|
||||
#define GSK_RBTREE_LOOKUP_(top,type,is_red,set_is_red,parent,left,right,comparator, key,out) \
|
||||
GSK_RBTREE_LOOKUP_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, key,comparator,out)
|
||||
#define GSK_RBTREE_SUPREMUM_(top,type,is_red,set_is_red,parent,left,right,comparator, key,out) \
|
||||
GSK_RBTREE_SUPREMUM_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, key,comparator,out)
|
||||
#define GSK_RBTREE_INFIMUM_(top,type,is_red,set_is_red,parent,left,right,comparator, key,out) \
|
||||
GSK_RBTREE_INFIMUM_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, key,comparator,out)
|
||||
|
||||
/* these macros don't need the is_red/set_is_red macros, nor the comparator,
|
||||
so omit them, to keep the lines a bit shorter. */
|
||||
#define GSK_RBTREE_ROTATE_RIGHT(top,type,parent,left,right, node) \
|
||||
GSK_RBTREE_ROTATE_LEFT(top,type,parent,right,left, node)
|
||||
#define GSK_RBTREE_ROTATE_LEFT(top,type,parent,left,right, node) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_rot_x = (node); \
|
||||
type _gsk_rot_y = _gsk_rot_x->right; \
|
||||
\
|
||||
_gsk_rot_x->right = _gsk_rot_y->left; \
|
||||
if (_gsk_rot_y->left) \
|
||||
_gsk_rot_y->left->parent = _gsk_rot_x; \
|
||||
_gsk_rot_y->parent = _gsk_rot_x->parent; \
|
||||
if (_gsk_rot_x->parent == NULL) \
|
||||
top = _gsk_rot_y; \
|
||||
else if (_gsk_rot_x == _gsk_rot_x->parent->left) \
|
||||
_gsk_rot_x->parent->left = _gsk_rot_y; \
|
||||
else \
|
||||
_gsk_rot_x->parent->right = _gsk_rot_y; \
|
||||
_gsk_rot_y->left = _gsk_rot_x; \
|
||||
_gsk_rot_x->parent = _gsk_rot_y; \
|
||||
}G_STMT_END
|
||||
|
||||
/* iteration */
|
||||
#define GSK_RBTREE_NEXT_(top,type,is_red,set_is_red,parent,left,right,comparator, in, out) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_next_at = (in); \
|
||||
g_assert (_gsk_next_at != NULL); \
|
||||
if (_gsk_next_at->right != NULL) \
|
||||
{ \
|
||||
_gsk_next_at = _gsk_next_at->right; \
|
||||
while (_gsk_next_at->left != NULL) \
|
||||
_gsk_next_at = _gsk_next_at->left; \
|
||||
out = _gsk_next_at; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
type _gsk_next_parent = (in)->parent; \
|
||||
while (_gsk_next_parent != NULL \
|
||||
&& _gsk_next_at == _gsk_next_parent->right) \
|
||||
{ \
|
||||
_gsk_next_at = _gsk_next_parent; \
|
||||
_gsk_next_parent = _gsk_next_parent->parent; \
|
||||
} \
|
||||
out = _gsk_next_parent; \
|
||||
} \
|
||||
}G_STMT_END
|
||||
|
||||
/* prev is just next with left/right child reversed. */
|
||||
#define GSK_RBTREE_PREV_(top,type,is_red,set_is_red,parent,left,right,comparator, in, out) \
|
||||
GSK_RBTREE_NEXT_(top,type,is_red,set_is_red,parent,right,left,comparator, in, out)
|
||||
|
||||
#define GSK_RBTREE_FIRST_(top,type,is_red,set_is_red,parent,left,right,comparator, out) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_first_at = (top); \
|
||||
if (_gsk_first_at != NULL) \
|
||||
while (_gsk_first_at->left != NULL) \
|
||||
_gsk_first_at = _gsk_first_at->left; \
|
||||
out = _gsk_first_at; \
|
||||
}G_STMT_END
|
||||
#define GSK_RBTREE_LAST_(top,type,is_red,set_is_red,parent,left,right,comparator, out) \
|
||||
GSK_RBTREE_FIRST_(top,type,is_red,set_is_red,parent,right,left,comparator, out)
|
||||
|
||||
/* --- RBC-Tree --- */
|
||||
#define GSK_RBCTREE_INSERT(tree, node, collision_node) \
|
||||
GSK_RBCTREE_INSERT_(tree, node, collision_node)
|
||||
#define GSK_RBCTREE_REMOVE(tree, node) \
|
||||
GSK_RBCTREE_REMOVE_(tree, node)
|
||||
#define GSK_RBCTREE_LOOKUP(tree, key, out) \
|
||||
GSK_RBCTREE_LOOKUP_(tree, key, out)
|
||||
#define GSK_RBCTREE_LOOKUP_COMPARATOR(tree, key, key_comparator, out) \
|
||||
GSK_RBCTREE_LOOKUP_COMPARATOR_(tree, key, key_comparator, out)
|
||||
|
||||
#define GSK_RBCTREE_FIRST(tree, out) \
|
||||
GSK_RBCTREE_FIRST_(tree, out)
|
||||
#define GSK_RBCTREE_LAST(tree, out) \
|
||||
GSK_RBCTREE_LAST_(tree, out)
|
||||
#define GSK_RBCTREE_NEXT(tree, in, out) \
|
||||
GSK_RBCTREE_NEXT_(tree, in, out)
|
||||
#define GSK_RBCTREE_PREV(tree, in, out) \
|
||||
GSK_RBCTREE_PREV_(tree, in, out)
|
||||
|
||||
#define GSK_RBCTREE_SUPREMUM(tree, key, out) \
|
||||
GSK_RBCTREE_SUPREMUM_(tree, key, out)
|
||||
#define GSK_RBCTREE_SUPREMUM_COMPARATOR(tree, key, key_comparator, out) \
|
||||
GSK_RBCTREE_SUPREMUM_COMPARATOR_(tree, key, key_comparator, out)
|
||||
#define GSK_RBCTREE_INFIMUM(tree, key, out) \
|
||||
GSK_RBCTREE_INFIMUM_(tree, key, out)
|
||||
#define GSK_RBCTREE_INFIMUM_COMPARATOR(tree, key, key_comparator, out) \
|
||||
GSK_RBCTREE_INFIMUM_COMPARATOR_(tree, key, key_comparator, out)
|
||||
|
||||
#define GSK_RBCTREE_GET_BY_INDEX(tree, index, out) \
|
||||
GSK_RBCTREE_GET_BY_INDEX_(tree, index, out)
|
||||
#define GSK_RBCTREE_GET_BY_INDEX_UNCHECKED(tree, index, out) \
|
||||
GSK_RBCTREE_GET_BY_INDEX_UNCHECKED_(tree, index, out)
|
||||
#define GSK_RBCTREE_GET_NODE_INDEX(tree, node, index_out) \
|
||||
GSK_RBCTREE_GET_NODE_INDEX_(tree, node, index_out)
|
||||
|
||||
#if 1
|
||||
#undef G_STMT_START
|
||||
#define G_STMT_START do
|
||||
#undef G_STMT_END
|
||||
#define G_STMT_END while(0)
|
||||
#endif
|
||||
|
||||
|
||||
#define GSK_RBCTREE_INSERT_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, node,collision_node) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_last = NULL; \
|
||||
type _gsk_at = (top); \
|
||||
gboolean _gsk_last_was_left = FALSE; \
|
||||
collision_node = NULL; \
|
||||
while (_gsk_at != NULL) \
|
||||
{ \
|
||||
int _gsk_compare_rv; \
|
||||
_gsk_last = _gsk_at; \
|
||||
comparator(_gsk_at, (node), _gsk_compare_rv); \
|
||||
if (_gsk_compare_rv > 0) \
|
||||
{ \
|
||||
_gsk_last_was_left = TRUE; \
|
||||
_gsk_at = _gsk_at->left; \
|
||||
} \
|
||||
else if (_gsk_compare_rv < 0) \
|
||||
{ \
|
||||
_gsk_last_was_left = FALSE; \
|
||||
_gsk_at = _gsk_at->right; \
|
||||
} \
|
||||
else \
|
||||
break; \
|
||||
} \
|
||||
if (_gsk_at != NULL) \
|
||||
{ \
|
||||
/* collision */ \
|
||||
collision_node = _gsk_at; \
|
||||
} \
|
||||
else if (_gsk_last == NULL) \
|
||||
{ \
|
||||
/* only node in tree */ \
|
||||
top = (node); \
|
||||
set_is_red ((node), 0); \
|
||||
(node)->left = (node)->right = (node)->parent = NULL; \
|
||||
set_count ((node), 1); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
(node)->parent = _gsk_last; \
|
||||
(node)->left = (node)->right = NULL; \
|
||||
if (_gsk_last_was_left) \
|
||||
_gsk_last->left = (node); \
|
||||
else \
|
||||
_gsk_last->right = (node); \
|
||||
\
|
||||
/* fixup counts */ \
|
||||
set_count ((node), 1); \
|
||||
for (_gsk_at = _gsk_last; _gsk_at; _gsk_at = _gsk_at->parent) \
|
||||
{ \
|
||||
guint _gsk_new_count = get_count(_gsk_at) + 1; \
|
||||
set_count(_gsk_at, _gsk_new_count); \
|
||||
} \
|
||||
\
|
||||
/* fixup */ \
|
||||
_gsk_at = (node); \
|
||||
set_is_red (_gsk_at, 1); \
|
||||
while (_gsk_at->parent != NULL && is_red(_gsk_at->parent)) \
|
||||
{ \
|
||||
if (_gsk_at->parent == _gsk_at->parent->parent->left) \
|
||||
{ \
|
||||
type _gsk_y = _gsk_at->parent->parent->right; \
|
||||
if (_gsk_y != NULL && is_red (_gsk_y)) \
|
||||
{ \
|
||||
set_is_red (_gsk_at->parent, 0); \
|
||||
set_is_red (_gsk_y, 0); \
|
||||
set_is_red (_gsk_at->parent->parent, 1); \
|
||||
_gsk_at = _gsk_at->parent->parent; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (_gsk_at == _gsk_at->parent->right) \
|
||||
{ \
|
||||
_gsk_at = _gsk_at->parent; \
|
||||
GSK_RBCTREE_ROTATE_LEFT (top,type,parent,left,right,get_count,set_count, _gsk_at);\
|
||||
} \
|
||||
set_is_red(_gsk_at->parent, 0); \
|
||||
set_is_red(_gsk_at->parent->parent, 1); \
|
||||
GSK_RBCTREE_ROTATE_RIGHT (top,type,parent,left,right,get_count,set_count,\
|
||||
_gsk_at->parent->parent); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
type _gsk_y = _gsk_at->parent->parent->left; \
|
||||
if (_gsk_y != NULL && is_red (_gsk_y)) \
|
||||
{ \
|
||||
set_is_red (_gsk_at->parent, 0); \
|
||||
set_is_red (_gsk_y, 0); \
|
||||
set_is_red (_gsk_at->parent->parent, 1); \
|
||||
_gsk_at = _gsk_at->parent->parent; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (_gsk_at == _gsk_at->parent->left) \
|
||||
{ \
|
||||
_gsk_at = _gsk_at->parent; \
|
||||
GSK_RBCTREE_ROTATE_RIGHT (top,type,parent,left,right,get_count,set_count,\
|
||||
_gsk_at); \
|
||||
} \
|
||||
set_is_red(_gsk_at->parent, 0); \
|
||||
set_is_red(_gsk_at->parent->parent, 1); \
|
||||
GSK_RBCTREE_ROTATE_LEFT (top,type,parent,left,right,get_count,set_count,\
|
||||
_gsk_at->parent->parent); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
set_is_red((top), 0); \
|
||||
} \
|
||||
}G_STMT_END
|
||||
|
||||
#define GSK_RBCTREE_REMOVE_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, node) \
|
||||
/* Algorithms:273. */ \
|
||||
G_STMT_START{ \
|
||||
type _gsk_rb_del_z = (node); \
|
||||
type _gsk_rb_del_x; \
|
||||
type _gsk_rb_del_y; \
|
||||
type _gsk_rb_del_nullpar = NULL; /* Used to emulate sentinel nodes */ \
|
||||
gboolean _gsk_rb_del_fixup; \
|
||||
if (_gsk_rb_del_z->left == NULL || _gsk_rb_del_z->right == NULL) \
|
||||
_gsk_rb_del_y = _gsk_rb_del_z; \
|
||||
else \
|
||||
{ \
|
||||
GSK_RBTREE_NEXT_ (top,type,is_red,set_is_red,parent,left,right,comparator,\
|
||||
_gsk_rb_del_z, _gsk_rb_del_y); \
|
||||
} \
|
||||
_gsk_rb_del_x = _gsk_rb_del_y->left ? _gsk_rb_del_y->left \
|
||||
: _gsk_rb_del_y->right; \
|
||||
if (_gsk_rb_del_x) \
|
||||
_gsk_rb_del_x->parent = _gsk_rb_del_y->parent; \
|
||||
else \
|
||||
_gsk_rb_del_nullpar = _gsk_rb_del_y->parent; \
|
||||
if (!_gsk_rb_del_y->parent) \
|
||||
top = _gsk_rb_del_x; \
|
||||
else \
|
||||
{ \
|
||||
if (_gsk_rb_del_y == _gsk_rb_del_y->parent->left) \
|
||||
_gsk_rb_del_y->parent->left = _gsk_rb_del_x; \
|
||||
else \
|
||||
_gsk_rb_del_y->parent->right = _gsk_rb_del_x; \
|
||||
_GSK_RBCTREE_FIX_COUNT_AND_UP(type,parent,left,right,get_count,set_count, _gsk_rb_del_y->parent);\
|
||||
} \
|
||||
_gsk_rb_del_fixup = !is_red(_gsk_rb_del_y); \
|
||||
if (_gsk_rb_del_y != _gsk_rb_del_z) \
|
||||
{ \
|
||||
set_is_red(_gsk_rb_del_y, is_red(_gsk_rb_del_z)); \
|
||||
_gsk_rb_del_y->left = _gsk_rb_del_z->left; \
|
||||
_gsk_rb_del_y->right = _gsk_rb_del_z->right; \
|
||||
_gsk_rb_del_y->parent = _gsk_rb_del_z->parent; \
|
||||
if (_gsk_rb_del_y->parent) \
|
||||
{ \
|
||||
if (_gsk_rb_del_y->parent->left == _gsk_rb_del_z) \
|
||||
_gsk_rb_del_y->parent->left = _gsk_rb_del_y; \
|
||||
else \
|
||||
_gsk_rb_del_y->parent->right = _gsk_rb_del_y; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
top = _gsk_rb_del_y; \
|
||||
} \
|
||||
/* TODO: look at pictures to see if "_AND_UP" is necessary */ \
|
||||
_GSK_RBCTREE_FIX_COUNT_AND_UP(type,parent,left,right,get_count,set_count, _gsk_rb_del_y);\
|
||||
\
|
||||
if (_gsk_rb_del_y->left) \
|
||||
_gsk_rb_del_y->left->parent = _gsk_rb_del_y; \
|
||||
if (_gsk_rb_del_y->right) \
|
||||
_gsk_rb_del_y->right->parent = _gsk_rb_del_y; \
|
||||
if (_gsk_rb_del_nullpar == _gsk_rb_del_z) \
|
||||
_gsk_rb_del_nullpar = _gsk_rb_del_y; \
|
||||
} \
|
||||
if (_gsk_rb_del_fixup) \
|
||||
{ \
|
||||
/* delete fixup (Algorithms, p 274) */ \
|
||||
while (_gsk_rb_del_x != top \
|
||||
&& !(_gsk_rb_del_x != NULL && is_red (_gsk_rb_del_x))) \
|
||||
{ \
|
||||
type _gsk_rb_del_xparent = _gsk_rb_del_x ? _gsk_rb_del_x->parent \
|
||||
: _gsk_rb_del_nullpar; \
|
||||
if (_gsk_rb_del_x == _gsk_rb_del_xparent->left) \
|
||||
{ \
|
||||
type _gsk_rb_del_w = _gsk_rb_del_xparent->right; \
|
||||
if (_gsk_rb_del_w != NULL && is_red (_gsk_rb_del_w)) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w, 0); \
|
||||
set_is_red (_gsk_rb_del_xparent, 1); \
|
||||
GSK_RBCTREE_ROTATE_LEFT (top,type,parent,left,right,get_count,set_count, \
|
||||
_gsk_rb_del_xparent); \
|
||||
_gsk_rb_del_w = _gsk_rb_del_xparent->right; \
|
||||
} \
|
||||
if (!(_gsk_rb_del_w->left && is_red (_gsk_rb_del_w->left)) \
|
||||
&& !(_gsk_rb_del_w->right && is_red (_gsk_rb_del_w->right))) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w, 1); \
|
||||
_gsk_rb_del_x = _gsk_rb_del_xparent; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (!(_gsk_rb_del_w->right && is_red (_gsk_rb_del_w->right)))\
|
||||
{ \
|
||||
if (_gsk_rb_del_w->left) \
|
||||
set_is_red (_gsk_rb_del_w->left, 0); \
|
||||
set_is_red (_gsk_rb_del_w, 1); \
|
||||
GSK_RBCTREE_ROTATE_RIGHT (top,type,parent,left,right,get_count,set_count, \
|
||||
_gsk_rb_del_w); \
|
||||
_gsk_rb_del_w = _gsk_rb_del_xparent->right; \
|
||||
} \
|
||||
set_is_red (_gsk_rb_del_w, is_red (_gsk_rb_del_xparent)); \
|
||||
set_is_red (_gsk_rb_del_xparent, 0); \
|
||||
set_is_red (_gsk_rb_del_w->right, 0); \
|
||||
GSK_RBCTREE_ROTATE_LEFT (top,type,parent,left,right,get_count,set_count, \
|
||||
_gsk_rb_del_xparent); \
|
||||
_gsk_rb_del_x = top; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
type _gsk_rb_del_w = _gsk_rb_del_xparent->left; \
|
||||
if (_gsk_rb_del_w && is_red (_gsk_rb_del_w)) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w, 0); \
|
||||
set_is_red (_gsk_rb_del_xparent, 1); \
|
||||
GSK_RBCTREE_ROTATE_RIGHT (top,type,parent,left,right,get_count,set_count, \
|
||||
_gsk_rb_del_xparent); \
|
||||
_gsk_rb_del_w = _gsk_rb_del_xparent->left; \
|
||||
} \
|
||||
if (!(_gsk_rb_del_w->right && is_red (_gsk_rb_del_w->right)) \
|
||||
&& !(_gsk_rb_del_w->left && is_red (_gsk_rb_del_w->left))) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w, 1); \
|
||||
_gsk_rb_del_x = _gsk_rb_del_xparent; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (!(_gsk_rb_del_w->left && is_red (_gsk_rb_del_w->left))) \
|
||||
{ \
|
||||
set_is_red (_gsk_rb_del_w->right, 0); \
|
||||
set_is_red (_gsk_rb_del_w, 1); \
|
||||
GSK_RBCTREE_ROTATE_LEFT (top,type,parent,left,right,get_count,set_count, \
|
||||
_gsk_rb_del_w); \
|
||||
_gsk_rb_del_w = _gsk_rb_del_xparent->left; \
|
||||
} \
|
||||
set_is_red (_gsk_rb_del_w, is_red (_gsk_rb_del_xparent)); \
|
||||
set_is_red (_gsk_rb_del_xparent, 0); \
|
||||
if (_gsk_rb_del_w->left) \
|
||||
set_is_red (_gsk_rb_del_w->left, 0); \
|
||||
GSK_RBCTREE_ROTATE_RIGHT (top,type,parent,left,right,get_count,set_count, \
|
||||
_gsk_rb_del_xparent); \
|
||||
_gsk_rb_del_x = top; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (_gsk_rb_del_x != NULL) \
|
||||
set_is_red(_gsk_rb_del_x, 0); \
|
||||
} \
|
||||
_gsk_rb_del_z->left = NULL; \
|
||||
_gsk_rb_del_z->right = NULL; \
|
||||
_gsk_rb_del_z->parent = NULL; \
|
||||
}G_STMT_END
|
||||
|
||||
#define GSK_RBCTREE_LOOKUP_COMPARATOR_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, \
|
||||
key,key_comparator,out) \
|
||||
GSK_RBTREE_LOOKUP_COMPARATOR_(top,type,is_red,set_count,parent,left,right,comparator, key,key_comparator,out)
|
||||
#define GSK_RBCTREE_INFIMUM_COMPARATOR_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, \
|
||||
key,key_comparator,out) \
|
||||
GSK_RBTREE_INFIMUM_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, key,key_comparator,out)
|
||||
#define GSK_RBCTREE_SUPREMUM_COMPARATOR_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, \
|
||||
key,key_comparator,out) \
|
||||
GSK_RBTREE_SUPREMUM_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, key,key_comparator,out)
|
||||
#define GSK_RBCTREE_LOOKUP_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, key,out) \
|
||||
GSK_RBTREE_LOOKUP_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, key,comparator,out)
|
||||
#define GSK_RBCTREE_SUPREMUM_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, key,out) \
|
||||
GSK_RBTREE_SUPREMUM_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, key,comparator,out)
|
||||
#define GSK_RBCTREE_INFIMUM_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, key,out) \
|
||||
GSK_RBTREE_INFIMUM_COMPARATOR_(top,type,is_red,set_is_red,parent,left,right,comparator, key,comparator,out)
|
||||
#define GSK_RBCTREE_NEXT_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, in, out) \
|
||||
GSK_RBTREE_NEXT_(top,type,is_red,set_is_red,parent,left,right,comparator, in, out)
|
||||
#define GSK_RBCTREE_PREV_(top,type,is_red,set_is_red,parent,left,right,comparator, in, out) \
|
||||
GSK_RBTREE_PREV_(top,type,is_red,set_is_red,parent,left,right,comparator, in, out)
|
||||
#define GSK_RBCTREE_FIRST_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, out) \
|
||||
GSK_RBTREE_FIRST_(top,type,is_red,set_is_red,parent,left,right,comparator, out)
|
||||
#define GSK_RBCTREE_LAST_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, out) \
|
||||
GSK_RBTREE_LAST_(top,type,is_red,set_is_red,parent,left,right,comparator, out)
|
||||
|
||||
#define GSK_RBCTREE_GET_BY_INDEX_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, index,out) \
|
||||
G_STMT_START{ \
|
||||
if (top == NULL || (index) >= get_count(top)) \
|
||||
out = NULL; \
|
||||
else \
|
||||
GSK_RBCTREE_GET_BY_INDEX_UNCHECKED_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, index,out);\
|
||||
}G_STMT_END
|
||||
#define GSK_RBCTREE_GET_BY_INDEX_UNCHECKED_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, index,out) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_at = (top); \
|
||||
guint _gsk_index = (index); \
|
||||
for (;;) \
|
||||
{ \
|
||||
guint _gsk_left_size = _gsk_at->left ? get_count(_gsk_at->left) : 0; \
|
||||
if (_gsk_index < _gsk_left_size) \
|
||||
_gsk_at = _gsk_at->left; \
|
||||
else if (_gsk_index == _gsk_left_size) \
|
||||
break; \
|
||||
else \
|
||||
{ \
|
||||
_gsk_index -= (_gsk_left_size + 1); \
|
||||
_gsk_at = _gsk_at->right; \
|
||||
} \
|
||||
} \
|
||||
out = _gsk_at; \
|
||||
}G_STMT_END
|
||||
|
||||
#define GSK_RBCTREE_GET_NODE_INDEX_(top,type,is_red,set_is_red,get_count,set_count,parent,left,right,comparator, node,index_out) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_at = (node); \
|
||||
guint _gsk_rv = _gsk_at->left ? get_count (_gsk_at->left) : 0; \
|
||||
while (_gsk_at->parent != NULL) \
|
||||
{ \
|
||||
if (_gsk_at->parent->left == _gsk_at) \
|
||||
; \
|
||||
else \
|
||||
{ \
|
||||
if (_gsk_at->parent->left) \
|
||||
_gsk_rv += get_count((_gsk_at->parent->left)); \
|
||||
_gsk_rv += 1; \
|
||||
} \
|
||||
_gsk_at = _gsk_at->parent; \
|
||||
} \
|
||||
index_out = _gsk_rv; \
|
||||
}G_STMT_END
|
||||
|
||||
#define GSK_RBCTREE_ROTATE_RIGHT(top,type,parent,left,right,get_count,set_count, node) \
|
||||
GSK_RBCTREE_ROTATE_LEFT(top,type,parent,right,left,get_count,set_count, node)
|
||||
#define GSK_RBCTREE_ROTATE_LEFT(top,type,parent,left,right,get_count,set_count, node) \
|
||||
G_STMT_START{ \
|
||||
type _gsk_rot_x = (node); \
|
||||
type _gsk_rot_y = _gsk_rot_x->right; \
|
||||
\
|
||||
_gsk_rot_x->right = _gsk_rot_y->left; \
|
||||
if (_gsk_rot_y->left) \
|
||||
_gsk_rot_y->left->parent = _gsk_rot_x; \
|
||||
_gsk_rot_y->parent = _gsk_rot_x->parent; \
|
||||
if (_gsk_rot_x->parent == NULL) \
|
||||
top = _gsk_rot_y; \
|
||||
else if (_gsk_rot_x == _gsk_rot_x->parent->left) \
|
||||
_gsk_rot_x->parent->left = _gsk_rot_y; \
|
||||
else \
|
||||
_gsk_rot_x->parent->right = _gsk_rot_y; \
|
||||
_gsk_rot_y->left = _gsk_rot_x; \
|
||||
_gsk_rot_x->parent = _gsk_rot_y; \
|
||||
\
|
||||
/* fixup counts. */ \
|
||||
/* to re-derive this here's what rotate_left(x) does pictorially: */ \
|
||||
/* x y */ \
|
||||
/* / \ / \ */ \
|
||||
/* a y == rotate_left(x) ==> x c */ \
|
||||
/* / \ / \ */ \
|
||||
/* b c a b */ \
|
||||
/* */ \
|
||||
/* so: n0 = get_count(x) (==a+b+c+2) */ \
|
||||
/* n1 = get_count(c) (c may be null) */ \
|
||||
/* n2 = n0 - n1 - 1; */ \
|
||||
/* set_count(x, n2) */ \
|
||||
/* set_count(y, n0) */ \
|
||||
/* c is _gsk_rot_y->right at this point */ \
|
||||
/* */ \
|
||||
/* equivalently: */ \
|
||||
/* y->count = x->count; */ \
|
||||
/* x->count -= c->count + 1 */ \
|
||||
{ \
|
||||
guint _gsk_rot_n0 = get_count(_gsk_rot_x); \
|
||||
guint _gsk_rot_n1 = _gsk_rot_y->right ? get_count(_gsk_rot_y->right) : 0; \
|
||||
guint _gsk_rot_n2 = _gsk_rot_n0 - _gsk_rot_n1 - 1; \
|
||||
set_count (_gsk_rot_x, _gsk_rot_n2); \
|
||||
set_count (_gsk_rot_y, _gsk_rot_n0); \
|
||||
} \
|
||||
}G_STMT_END
|
||||
|
||||
/* utility: recompute node's count, based on count of its children */
|
||||
#define _GSK_RBCTREE_FIX_COUNT(type,parent,left,right,get_count,set_count, node) \
|
||||
G_STMT_START{ \
|
||||
guint _gsk_fixcount_count = 1; \
|
||||
if ((node)->left != NULL) \
|
||||
_gsk_fixcount_count += get_count((node)->left); \
|
||||
if ((node)->right != NULL) \
|
||||
_gsk_fixcount_count += get_count((node)->right); \
|
||||
set_count((node), _gsk_fixcount_count); \
|
||||
}G_STMT_END
|
||||
|
||||
/* utility: recompute node's count, based on count of its children */
|
||||
#define _GSK_RBCTREE_FIX_COUNT_AND_UP(type,parent,left,right,get_count,set_count, node) \
|
||||
G_STMT_START{ \
|
||||
type _tmp_fix_count_up; \
|
||||
for (_tmp_fix_count_up = (node); \
|
||||
_tmp_fix_count_up != NULL; \
|
||||
_tmp_fix_count_up = _tmp_fix_count_up->parent) \
|
||||
_GSK_RBCTREE_FIX_COUNT (type,parent,left,right,get_count,set_count, _tmp_fix_count_up);\
|
||||
}G_STMT_END
|
||||
|
||||
#endif
|
@ -1,4 +1,5 @@
|
||||
#include "protobuf-c-dispatch.h"
|
||||
#include "gskrbtreemacros.h"
|
||||
|
||||
#define ALLOC_WITH_ALLOCATOR(allocator, size) ((allocator)->alloc ((allocator)->allocator_data, (size)))
|
||||
#define FREE_WITH_ALLOCATOR(allocator, ptr) ((allocator)->free ((allocator)->allocator_data, (ptr)))
|
||||
@ -8,7 +9,7 @@
|
||||
typedef struct _Callback Callback;
|
||||
struct _Callback
|
||||
{
|
||||
ProtobufC_DispatchCallback func;
|
||||
ProtobufCDispatchCallback func;
|
||||
void *data;
|
||||
};
|
||||
|
||||
@ -23,16 +24,50 @@ struct _FDMap
|
||||
typedef struct _RealDispatch RealDispatch;
|
||||
struct _RealDispatch
|
||||
{
|
||||
ProtobufC_Dispatch base;
|
||||
ProtobufCDispatch base;
|
||||
Callback *callbacks; /* parallels notifies_desired */
|
||||
size_t notifies_desired_alloced;
|
||||
size_t changes_alloced;
|
||||
FDMap *fd_map; /* map indexed by fd */
|
||||
size_t fd_map_size; /* number of elements of fd_map */
|
||||
|
||||
ProtobufCDispatchTimer *timer_tree;
|
||||
};
|
||||
|
||||
struct _ProtobufCDispatchTimer
|
||||
{
|
||||
/* the actual timeout time */
|
||||
unsigned long timeout_secs;
|
||||
unsigned timeout_usecs;
|
||||
|
||||
/* red-black tree stuff */
|
||||
ProtobufCDispatchTimer *left, *right, *parent;
|
||||
protobuf_c_boolean is_red;
|
||||
|
||||
/* user callback */
|
||||
ProtobufCDispatchTimerFunc func;
|
||||
void *func_data;
|
||||
};
|
||||
|
||||
/* Define the tree of timers, as per gskrbtreemacros.h */
|
||||
#define TIMER_GET_IS_RED(n) ((n)->is_red)
|
||||
#define TIMER_SET_IS_RED(n,v) ((n)->is_red = (v))
|
||||
#define TIMERS_COMPARE(a,b, rv) \
|
||||
if (a->timeout_secs < b->timeout_secs) rv = -1; \
|
||||
else if (a->timeout_secs > b->timeout_secs) rv = 1; \
|
||||
else if (a->timeout_usecs < b->timeout_usecs) rv = -1; \
|
||||
else if (a->timeout_usecs > b->timeout_usecs) rv = 1; \
|
||||
else if (a < b) rv = -1; \
|
||||
else if (a > b) rv = 1; \
|
||||
else rv = 0;
|
||||
#define GET_TIMER_TREE(d) \
|
||||
(d)->timer_tree, ProtobufCDispatchTimer *, \
|
||||
TIMER_GET_IS_RED, TIMER_SET_IS_RED, \
|
||||
parent, left, right, \
|
||||
TIMERS_COMPARE
|
||||
|
||||
/* Create or destroy a Dispatch */
|
||||
ProtobufC_Dispatch *protobuf_c_dispatch_new (void)
|
||||
ProtobufCDispatch *protobuf_c_dispatch_new (void)
|
||||
{
|
||||
RealDispatch *rv = ALLOC (sizeof (RealDispatch));
|
||||
rv->base.n_changes = 0;
|
||||
@ -48,7 +83,7 @@ ProtobufC_Dispatch *protobuf_c_dispatch_new (void)
|
||||
}
|
||||
|
||||
void
|
||||
protobuf_c_dispatch_free(ProtobufC_Dispatch *dispatch)
|
||||
protobuf_c_dispatch_free(ProtobufCDispatch *dispatch)
|
||||
{
|
||||
RealDispatch *d = (RealDispatch *) dispatch;
|
||||
FREE (d->base.notifies_desired);
|
||||
@ -152,10 +187,10 @@ deallocate_notify_desired_index (RealDispatch *d,
|
||||
|
||||
/* Registering file-descriptors to watch. */
|
||||
void
|
||||
protobuf_c_dispatch_watch_fd (ProtobufC_Dispatch *dispatch,
|
||||
protobuf_c_dispatch_watch_fd (ProtobufCDispatch *dispatch,
|
||||
int fd,
|
||||
unsigned events,
|
||||
ProtobufC_DispatchCallback callback,
|
||||
ProtobufCDispatchCallback callback,
|
||||
void *callback_data)
|
||||
{
|
||||
RealDispatch *d = (RealDispatch *) dispatch;
|
||||
@ -199,7 +234,7 @@ protobuf_c_dispatch_watch_fd (ProtobufC_Dispatch *dispatch,
|
||||
}
|
||||
|
||||
void
|
||||
protobuf_c_dispatch_close_fd (ProtobufC_Dispatch *dispatch,
|
||||
protobuf_c_dispatch_close_fd (ProtobufCDispatch *dispatch,
|
||||
int fd)
|
||||
{
|
||||
protobuf_c_dispatch_fd_closed (dispatch, fd);
|
||||
@ -207,7 +242,7 @@ protobuf_c_dispatch_close_fd (ProtobufC_Dispatch *dispatch,
|
||||
}
|
||||
|
||||
void
|
||||
protobuf_c_dispatch_fd_closed(ProtobufC_Dispatch *dispatch,
|
||||
protobuf_c_dispatch_fd_closed(ProtobufCDispatch *dispatch,
|
||||
int fd)
|
||||
{
|
||||
unsigned f = fd;
|
||||
@ -220,8 +255,16 @@ protobuf_c_dispatch_fd_closed(ProtobufC_Dispatch *dispatch,
|
||||
deallocate_notify_desired_index (d, f);
|
||||
}
|
||||
|
||||
static void
|
||||
free_timer (ProtobufCDispatchTimer *timer)
|
||||
{
|
||||
RealDispatch *d = timer->dispatch;
|
||||
timer->right = d->recycled_timeouts;
|
||||
d->recycled_timeouts = timer;
|
||||
}
|
||||
|
||||
void
|
||||
protobuf_c_dispatch_dispatch (ProtobufC_Dispatch *dispatch,
|
||||
protobuf_c_dispatch_dispatch (ProtobufCDispatch *dispatch,
|
||||
size_t n_notifies,
|
||||
ProtobufC_FDNotify *notifies)
|
||||
{
|
||||
@ -249,10 +292,42 @@ protobuf_c_dispatch_dispatch (ProtobufC_Dispatch *dispatch,
|
||||
d->callbacks[nd_ind].func (fd, events, d->callbacks[nd_ind].data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* handle timers */
|
||||
gettimeofday (&tv, NULL);
|
||||
while (d->timer_tree != NULL)
|
||||
{
|
||||
ProtobufCDispatchTimer *min_timer;
|
||||
GSK_RBTREE_FIRST (GET_TIMER_TREE (d), min_timer);
|
||||
if (min_timer.timeout_secs < tv.tv_secs
|
||||
|| (min_timer.timeout_secs == tv.tv_secs
|
||||
&& min_timer.timeout_usecs <= tv.tv_usecs))
|
||||
{
|
||||
ProtobufCDispatchTimerFunc func = min_timer->func;
|
||||
void *func_data = min_timer->func_data;
|
||||
GSK_RBTREE_REMOVE (GET_TIMER_TREE (d), min_timer);
|
||||
/* Set to NULL as a way to tell protobuf_c_dispatch_remove_timer()
|
||||
that we are in the middle of notifying */
|
||||
min_timer->func = NULL;
|
||||
min_timer->func_data = NULL;
|
||||
func (&d->base, func_data);
|
||||
free_timer (min_timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
d->base.has_timeout = 1;
|
||||
d->base.timeout_secs = min_timer->timeout_secs;
|
||||
d->base.timeout_usecs = min_timer->timeout_usecs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (d->timer_tree == NULL)
|
||||
d->base.has_timeout = 0;
|
||||
}
|
||||
|
||||
void
|
||||
protobuf_c_dispatch_clear_changes (ProtobufC_Dispatch *dispatch)
|
||||
protobuf_c_dispatch_clear_changes (ProtobufCDispatch *dispatch)
|
||||
{
|
||||
RealDispatch *d = (RealDispatch *) dispatch;
|
||||
unsigned i;
|
||||
@ -264,10 +339,8 @@ protobuf_c_dispatch_clear_changes (ProtobufC_Dispatch *dispatch)
|
||||
dispatch->n_changes = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
protobuf_c_dispatch_run (ProtobufC_Dispatch *dispatch,
|
||||
int timeout)
|
||||
protobuf_c_dispatch_run (ProtobufCDispatch *dispatch)
|
||||
{
|
||||
struct pollfd *fds;
|
||||
void *to_free = NULL;
|
||||
@ -319,3 +392,58 @@ protobuf_c_dispatch_run (ProtobufC_Dispatch *dispatch,
|
||||
if (to_free2)
|
||||
FREE (to_free2);
|
||||
}
|
||||
|
||||
ProtobufCDispatchTimer *
|
||||
protobuf_c_dispatch_add_timer(ProtobufCDispatch *dispatch,
|
||||
unsigned timeout_secs,
|
||||
unsigned timeout_usecs,
|
||||
ProtobufCDispatchTimerFunc func,
|
||||
void *func_data)
|
||||
{
|
||||
RealDispatch *d = (RealDispatch *) dispatch;
|
||||
protobuf_c_assert (func != NULL);
|
||||
if (d->recycled_timeouts != NULL)
|
||||
{
|
||||
rv = d->recycled_timeouts;
|
||||
d->recycled_timeouts = rv->right;
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = d->allocator->alloc (d->allocator, sizeof (ProtobufCDispatchTimer));
|
||||
}
|
||||
rv->timeout_secs = timeout_secs;
|
||||
rv->timeout_usecs = timeout_usecs;
|
||||
rv->func = func;
|
||||
rv->func_data = func_data;
|
||||
rv->dispatch = d;
|
||||
GSK_RBTREE_INSERT (GET_TIMER_TREE (d), rv, conflict);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void protobuf_c_dispatch_remove_timer (ProtobufCDispatchTimer *timer)
|
||||
{
|
||||
protobuf_c_boolean may_be_first;
|
||||
RealDispatch *d = timer->dispatch;
|
||||
|
||||
/* ignore mid-notify removal */
|
||||
if (timer->func == NULL)
|
||||
return;
|
||||
|
||||
may_be_first = d->base.timeout_usecs == timer->timeout_usecs
|
||||
&& d->base.timeout_secs == timer->timeout_secs;
|
||||
|
||||
GSK_RBTREE_REMOVE (GET_TIMER_TREE (d), timer);
|
||||
|
||||
if (may_be_first)
|
||||
{
|
||||
if (d->timer_tree == NULL)
|
||||
d->base.has_timeout = 0;
|
||||
else
|
||||
{
|
||||
ProtobufCDispatchTimer *min;
|
||||
GSK_RBTREE_FIRST (GET_TIMER_TREE (d), min);
|
||||
d->timeout_secs = min->timeout_secs;
|
||||
d->timeout_usecs = min->timeout_usecs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,27 +5,45 @@ typedef enum
|
||||
} ProtobufC_Events;
|
||||
|
||||
/* Create or destroy a Dispatch */
|
||||
ProtobufC_Dispatch *protobuf_c_dispatch_new (ProtobufCAllocator *allocator);
|
||||
void protobuf_c_dispatch_free(ProtobufC_Dispatch *dispatch);
|
||||
ProtobufCDispatch *protobuf_c_dispatch_new (ProtobufCAllocator *allocator);
|
||||
void protobuf_c_dispatch_free(ProtobufCDispatch *dispatch);
|
||||
|
||||
ProtobufCAllocator *protobuf_c_dispatch_peek_allocator (ProtobufC_Dispatch *);
|
||||
ProtobufCAllocator *protobuf_c_dispatch_peek_allocator (ProtobufCDispatch *);
|
||||
|
||||
typedef void (*ProtobufC_DispatchCallback) (int fd,
|
||||
typedef void (*ProtobufCDispatchCallback) (int fd,
|
||||
unsigned events,
|
||||
void *callback_data);
|
||||
|
||||
/* Registering file-descriptors to watch. */
|
||||
void protobuf_c_dispatch_watch_fd (ProtobufC_Dispatch *dispatch,
|
||||
void protobuf_c_dispatch_watch_fd (ProtobufCDispatch *dispatch,
|
||||
int fd,
|
||||
unsigned events,
|
||||
ProtobufC_DispatchCallback callback,
|
||||
ProtobufCDispatchCallback callback,
|
||||
void *callback_data);
|
||||
void protobuf_c_dispatch_close_fd (ProtobufC_Dispatch *dispatch,
|
||||
void protobuf_c_dispatch_close_fd (ProtobufCDispatch *dispatch,
|
||||
int fd);
|
||||
void protobuf_c_dispatch_fd_closed(ProtobufC_Dispatch *dispatch,
|
||||
void protobuf_c_dispatch_fd_closed(ProtobufCDispatch *dispatch,
|
||||
int fd);
|
||||
|
||||
/* Timers */
|
||||
typedef void (*ProtobufCDispatchTimerFunc) (ProtobufCDispatch *dispatch,
|
||||
void *func_data);
|
||||
ProtobufCDispatchTimer *
|
||||
protobuf_c_dispatch_add_timer(ProtobufCDispatch *dispatch,
|
||||
unsigned timeout_secs,
|
||||
unsigned timeout_usecs,
|
||||
ProtobufCDispatchTimerFunc func,
|
||||
void *func_data);
|
||||
void protobuf_c_dispatch_remove_timer (ProtobufCDispatchTimer *);
|
||||
|
||||
/* Idle functions */
|
||||
typedef void (*ProtobufCDispatchIdleFunc) (ProtobufCDispatch *dispatch,
|
||||
void *func_data);
|
||||
ProtobufCDispatchIdle *
|
||||
protobuf_c_dispatch_add_idle (ProtobufCDispatch *dispatch,
|
||||
ProtobufCDispatchIdleFunc func,
|
||||
void *func_data);
|
||||
void protobuf_c_dispatch_remove_idle (ProtobufCDispatchIdle *);
|
||||
|
||||
/* --- API for use in standalone application --- */
|
||||
/* Where you are happy just to run poll(2). */
|
||||
@ -34,15 +52,14 @@ void protobuf_c_dispatch_fd_closed(ProtobufC_Dispatch *dispatch,
|
||||
* Run one main-loop iteration, using poll(2) (or some system-level event system);
|
||||
* 'timeout' is in milliseconds, -1 for no timeout.
|
||||
*/
|
||||
void protobuf_c_dispatch_run (ProtobufC_Dispatch *dispatch,
|
||||
int timeout);
|
||||
void protobuf_c_dispatch_run (ProtobufCDispatch *dispatch);
|
||||
|
||||
|
||||
/* --- API for those who want to embed a dispatch into their own main-loop --- */
|
||||
void protobuf_c_dispatch_dispatch (ProtobufC_Dispatch *dispatch,
|
||||
void protobuf_c_dispatch_dispatch (ProtobufCDispatch *dispatch,
|
||||
size_t n_notifies,
|
||||
ProtobufC_FDNotify *notifies);
|
||||
void protobuf_c_dispatch_clear_changes (ProtobufC_Dispatch *);
|
||||
void protobuf_c_dispatch_clear_changes (ProtobufCDispatch *);
|
||||
|
||||
#ifdef WIN32
|
||||
typedef SOCKET ProtobufC_FD;
|
||||
@ -56,7 +73,7 @@ typedef struct {
|
||||
} ProtobufC_FDNotify;
|
||||
|
||||
|
||||
struct _ProtobufC_Dispatch
|
||||
struct _ProtobufCDispatch
|
||||
{
|
||||
/* changes to the events you are interested in. */
|
||||
size_t n_changes;
|
||||
@ -66,6 +83,15 @@ struct _ProtobufC_Dispatch
|
||||
size_t n_notifies_desired;
|
||||
ProtobufC_FDNotify *notifies_desired;
|
||||
|
||||
/* number of milliseconds to wait if no events occur */
|
||||
protobuf_c_boolean has_timeout;
|
||||
unsigned long timeout_secs;
|
||||
unsigned timeout_usecs;
|
||||
|
||||
/* true if there is an idle function, in which case polling with
|
||||
timeout 0 is appropriate */
|
||||
protobuf_c_boolean has_idle;
|
||||
|
||||
/* private data follows */
|
||||
};
|
||||
|
||||
|
@ -4,10 +4,12 @@ typedef struct _ProtobufC_RPC_Client ProtobufC_RPC_Client;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PROTOBUF_C_CLIENT_STATE_INIT,
|
||||
PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP,
|
||||
PROTOBUF_C_CLIENT_STATE_CONNECTING,
|
||||
PROTOBUF_C_CLIENT_STATE_CONNECTED,
|
||||
PROTOBUF_C_CLIENT_STATE_FAILED_WAITING
|
||||
PROTOBUF_C_CLIENT_STATE_FAILED_WAITING,
|
||||
PROTOBUF_C_CLIENT_STATE_FAILED /* if no autoretry */
|
||||
} ProtobufC_ClientState;
|
||||
|
||||
struct _ProtobufC_RPC_Client
|
||||
@ -21,36 +23,41 @@ struct _ProtobufC_RPC_Client
|
||||
char *name;
|
||||
ProtobufC_ClientState client_state;
|
||||
ProtobufC_FD fd;
|
||||
protobuf_c_boolean autoretry;
|
||||
unsigned autoretry_millis;
|
||||
union {
|
||||
struct {
|
||||
ProtobufCDispatch_Idle *idle;
|
||||
} init;
|
||||
struct {
|
||||
ProtobufCDispatch_Timer *timer;
|
||||
} failed_waiting;
|
||||
};
|
||||
};
|
||||
|
||||
void
|
||||
handle_init_idle (ProtobufCDispatch *
|
||||
|
||||
ProtobufCService *
|
||||
protobuf_c_rpc_client_new (ProtobufC_RPC_Options *options,
|
||||
const ProtobufCServiceDescriptor *descriptor)
|
||||
ProtobufCService *protobuf_c_rpc_client_new (ProtobufC_RPC_AddressType type,
|
||||
const char *name,
|
||||
const ProtobufCServiceDescriptor *descriptor,
|
||||
ProtobufCDispatch *dispatch);
|
||||
{
|
||||
ProtobufCAllocator *allocator = options->allocator;
|
||||
ProtobufCDispatch *dispatch = options->dispatch ? options->dispatch : protobuf_c_dispatch_default ();
|
||||
ProtobufC
|
||||
...
|
||||
ProtobufCAllocator *allocator = protobuf_c_dispatch_peek_allocator (dispatch);
|
||||
ProtobufC_RPC_Client *rv = allocator->alloc (allocator, sizeof (ProtobufC_RPC_Client));
|
||||
rv->base.descriptor = descriptor;
|
||||
rv->base.invoke = invoke_client_rpc;
|
||||
rv->base.destroy = destroy_client_rpc;
|
||||
protobuf_c_data_buffer_init (&rv->incoming);
|
||||
protobuf_c_data_buffer_init (&rv->outgoing);
|
||||
rv->allocator = allocator;
|
||||
rv->dispatch = dispatch;
|
||||
rv->address_type = type;
|
||||
rv->name = strcpy (allocator->alloc (allocator, strlen (name) + 1), name);
|
||||
rv->client_state = PROTOBUF_C_CLIENT_STATE_INIT;
|
||||
rv->fd = -1;
|
||||
rv->info.init = protobuf_c_dispatch_add_idle (dispatch, handle_init_idle, rv);
|
||||
return &rv->base;
|
||||
}
|
||||
-
|
||||
void protobuf_c_rpc_server_new (ProtobufC_RPC_Options *options,
|
||||
ProtobufCService *service);
|
||||
unsigned port,
|
||||
const ProtobufCServiceDescriptor *descriptor,
|
||||
ProtobufCAllocator *allocator,
|
||||
ProtobufCDispatch *dispatch);
|
||||
ProtobufCService *protobuf_c_rpc_client_new_local(const char *socket_name,
|
||||
const ProtobufCServiceDescriptor *descripto,
|
||||
ProtobufCAllocator *allocator,
|
||||
ProtobufCDispatch *dispatch);
|
||||
void protobuf_c_rpc_server_new_tcp (ProtobufCService *service,
|
||||
unsigned port,
|
||||
ProtobufCAllocator *allocator,
|
||||
ProtobufCDispatch *dispatch);
|
||||
void protobuf_c_rpc_server_new_local(ProtobufCService *service,
|
||||
const char *socket_nam,
|
||||
ProtobufCAllocator *allocator,
|
||||
ProtobufCDispatch *dispatch);
|
||||
|
||||
---
|
||||
|
Loading…
x
Reference in New Issue
Block a user