1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
#ifndef _CONTAIN_
#define _CONTAIN_
/* Containers */
/* Splay tree backed associative map
*
* This works by cheating at inheritance in C. Create the structure you
* care about and put the *first* member as being a "splay". For instance:
*
* typedef struct {
* splay node;
* char *left;
* char *right;
* } foo_t;
*
* Create the map with:
* foo_t *foomap=NULL;
*
* You will also need a comparitor.
* int foomapcmp(const foo_t *a, const foo_t *b)
* {
* return strcmp(a->key,b->key);
* }
*
* Then to insert something into the map:
* foo_t node;
* node.key="a";
* node.value="apple";
* foomap=(foo_t *)splay_insert(
* (splay*)foomap,
* (splay_cmp_t)foomapcmp,
* (splay*)node
* );
*
* To search for something:
* struct foo_t node;
* node.key="a";
* foomap=(foo_t *)splay_find((splay*)foomap,
* (splay_cmp_t)foomapcmp,
* (splay*)node
* );
* printf("%s is for %s\n",foomap->key,foomap->value);
*
* Note the annoyingly copious amount of casts, and the fact that the return
* from splay_find is the top of the tree, and the result.
*/
typedef struct splay_node {
struct splay_node *left;
struct splay_node *right;
} splay;
typedef int (*splay_cmp_t)(const struct splay_node *, const struct splay_node *);
typedef void (*visitor_t)(const splay *tree,void *userdata);
splay *splay_search_tree(splay *tree, splay_cmp_t cmp, splay *node);
splay *splay_delete(splay *tree, splay_cmp_t cmp, splay *node);
void splay_purge(splay *tree);
splay *splay_insert(splay *tree, splay_cmp_t cmp, splay *node);
void splay_visit(const splay *tree, visitor_t pre,visitor_t inorder,visitor_t post,void *userdata);
/*
* Macros to wrap the splay tree to make it work a bit more like you expect.
*
* Map:
* MAP_CREATE(alphabet,char *,strcmp,char *)
* MAP_INSERT(alphabet,"a","apple")
* printf("a is for %s",MAP_FIND(alphabet,"a")->value);
*
* Set:
* SET_CREATE(afewofmyfavouritethings,char *,strcmp)
* SET_INSERT(afewofmyfavouritethings,"raindrops on roses");
* SET_INSERT(afewofmyfavouritethings,"whiskers on kittens");
* if (SET_CONTAINS(afewofmyfaovuritethings,"whiskers on kittens")) {
* printf("I like whiskers on kittens\n");
* } else {
* printf("Whiskers on kittens suck\n");
* }
*
*/
#define MAP_NODE(keytype,valuetype) \
struct { \
splay _map_node; \
keytype key; \
valuetype value; \
}
#define MAP(keytype,valuetype) \
struct { \
MAP_NODE(keytype,valuetype) *node; \
splay_cmp_t cmp; \
}
#define MAP_INIT(cmp) \
{ NULL, (splay_cmp_t)cmp }
#define CMP(name,keytype,exp) \
int name(splay *_map_a, splay *_map_b) { \
struct _map_t { \
splay _map_node; \
keytype key; \
}; \
keytype a = ((struct _map_t*)_map_a)->key; \
keytype b = ((struct _map_t*)_map_b)->key; \
return (exp); \
}
#define MAP_INSERT(name,vkey,vvalue) \
do { \
typeof((name).node) _node= \
malloc(sizeof(typeof(*(name).node))); \
*_node = (typeof(*(name).node)){{0,0},vkey,vvalue}; \
(name).node=(typeof((name).node))splay_insert( \
(splay *)(name).node, \
(name).cmp, \
(splay *)_node \
); \
} while(0);
#define MAP_FIND(name,vkey) \
({ \
typeof(*(name).node) _node; \
typeof((name).node) _ret; \
_node.key=vkey; \
(name).node=(typeof((name).node))splay_search_tree( \
(splay *)(name).node, \
(name).cmp, \
(splay *)&_node \
); \
if ((name).node \
&& (name).cmp((splay*)(name).node,(splay*)&_node)==0)\
_ret=(name).node; \
else \
_ret=NULL; \
_ret; \
})
#define MAP_VISITOR(name,keytype,valuetype) \
void name(MAP_NODE(keytype,valuetype) *node,void *userdata)
#define MAP_VISIT(name,pre,inorder,post,userdata) \
splay_visit((splay*)(name).node, \
(visitor_t)pre, \
(visitor_t)inorder, \
(visitor_t)post, \
userdata)
/* Sets ****************************************************************/
#define SET_CREATE(name,keytype,cmp) \
typedef struct { \
splay node; \
keytype key; \
} name ## _t; \
name ## _t *name = NULL; \
int name ## _cmp(const splay *a,const splay *b) { \
return cmp(((name ## _t*)a)->key,((name ## _t *)b)->key); \
}
#define SET_INSERT(name,vkey) \
do { \
name ## _t *_node=malloc(sizeof(name ## _t)); \
_node->key=vkey; \
name=(name ##_t*)splay_insert((splay *)name, \
(splay_cmp_t)name ## _cmp, \
(splay *)_node \
); \
} while(0);
#define SET_CONTAINS(name,vkey) \
({ \
name ## _t _node; \
_node.key=vkey; \
name=(name ##_t*)splay_search_tree( \
(splay *)name, \
(splay_cmp_t)name ## _cmp, \
(splay *)&_node \
); \
(name) && name ## _cmp((splay*)(name),(splay *)&_node)==0;\
})
#endif /* _CONTAIN_ */
|