| 1 | #include	"dthdr.h" | 
|---|
| 2 |  | 
|---|
| 3 | /*	Ordered set/multiset | 
|---|
| 4 | **	dt:	dictionary being searched | 
|---|
| 5 | **	obj:	the object to look for. | 
|---|
| 6 | **	type:	search type. | 
|---|
| 7 | ** | 
|---|
| 8 | **      Written by Kiem-Phong Vo (5/25/96) | 
|---|
| 9 | */ | 
|---|
| 10 |  | 
|---|
| 11 | static void* dttree(Dt_t* dt, void* obj, int type) | 
|---|
| 12 | { | 
|---|
| 13 | Dtlink_t	*root, *t; | 
|---|
| 14 | int		cmp, lk, sz, ky; | 
|---|
| 15 | void		*o, *k, *key; | 
|---|
| 16 | Dtlink_t	*l, *r, *me = NULL, link; | 
|---|
| 17 | int		n, minp, turn[DT_MINP]; | 
|---|
| 18 | Dtcompar_f	cmpf; | 
|---|
| 19 | Dtdisc_t*	disc; | 
|---|
| 20 |  | 
|---|
| 21 | UNFLATTEN(dt); | 
|---|
| 22 | disc = dt->disc; _DTDSC(disc,ky,sz,lk,cmpf); | 
|---|
| 23 | dt->type &= ~DT_FOUND; | 
|---|
| 24 |  | 
|---|
| 25 | root = dt->data->here; | 
|---|
| 26 | if(!obj) | 
|---|
| 27 | {	if(!root || !(type&(DT_CLEAR|DT_FIRST|DT_LAST)) ) | 
|---|
| 28 | return NIL(void*); | 
|---|
| 29 |  | 
|---|
| 30 | if(type&DT_CLEAR) /* delete all objects */ | 
|---|
| 31 | {	if(disc->freef || disc->link < 0) | 
|---|
| 32 | {	do | 
|---|
| 33 | {	while((t = root->left) ) | 
|---|
| 34 | RROTATE(root,t); | 
|---|
| 35 | t = root->right; | 
|---|
| 36 | if(disc->freef) | 
|---|
| 37 | (*disc->freef)(dt,_DTOBJ(root,lk),disc); | 
|---|
| 38 | if(disc->link < 0) | 
|---|
| 39 | (*dt->memoryf)(dt,(void*)root,0,disc); | 
|---|
| 40 | } while((root = t) ); | 
|---|
| 41 | } | 
|---|
| 42 |  | 
|---|
| 43 | dt->data->size = 0; | 
|---|
| 44 | dt->data->here = NIL(Dtlink_t*); | 
|---|
| 45 | return NIL(void*); | 
|---|
| 46 | } | 
|---|
| 47 | else /* computing largest/smallest element */ | 
|---|
| 48 | {	if(type&DT_LAST) | 
|---|
| 49 | {	while((t = root->right) ) | 
|---|
| 50 | LROTATE(root,t); | 
|---|
| 51 | } | 
|---|
| 52 | else /* type&DT_FIRST */ | 
|---|
| 53 | {	while((t = root->left) ) | 
|---|
| 54 | RROTATE(root,t); | 
|---|
| 55 | } | 
|---|
| 56 |  | 
|---|
| 57 | dt->data->here = root; | 
|---|
| 58 | return _DTOBJ(root,lk); | 
|---|
| 59 | } | 
|---|
| 60 | } | 
|---|
| 61 |  | 
|---|
| 62 | /* note that link.right is LEFT tree and link.left is RIGHT tree */ | 
|---|
| 63 | l = r = &link; | 
|---|
| 64 |  | 
|---|
| 65 | /* allow apps to delete an object "actually" in the dictionary */ | 
|---|
| 66 | if(dt->meth->type == DT_OBAG && (type&(DT_DELETE|DT_DETACH)) ) | 
|---|
| 67 | {	key = _DTKEY(obj,ky,sz); | 
|---|
| 68 | for(o = dtsearch(dt,obj); o; o = dtnext(dt,o) ) | 
|---|
| 69 | {	k = _DTKEY(o,ky,sz); | 
|---|
| 70 | if(_DTCMP(dt,key,k,disc,cmpf,sz) != 0) | 
|---|
| 71 | break; | 
|---|
| 72 | if(o == obj) | 
|---|
| 73 | {	root = dt->data->here; | 
|---|
| 74 | l->right = root->left; | 
|---|
| 75 | r->left  = root->right; | 
|---|
| 76 | goto dt_delete; | 
|---|
| 77 | } | 
|---|
| 78 | } | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | if(type&(DT_MATCH|DT_SEARCH|DT_INSERT|DT_ATTACH)) | 
|---|
| 82 | {	key = (type&DT_MATCH) ? obj : _DTKEY(obj,ky,sz); | 
|---|
| 83 | if(root) | 
|---|
| 84 | goto do_search; | 
|---|
| 85 | } | 
|---|
| 86 | else if(type&DT_RENEW) | 
|---|
| 87 | {	me = (Dtlink_t*)obj; | 
|---|
| 88 | obj = _DTOBJ(me,lk); | 
|---|
| 89 | key = _DTKEY(obj,ky,sz); | 
|---|
| 90 | if(root) | 
|---|
| 91 | goto do_search; | 
|---|
| 92 | } | 
|---|
| 93 | else if(root && _DTOBJ(root,lk) != obj) | 
|---|
| 94 | {	key = _DTKEY(obj,ky,sz); | 
|---|
| 95 | do_search: | 
|---|
| 96 | if(dt->meth->type == DT_OSET && | 
|---|
| 97 | (minp = dt->data->minp) != 0 && (type&(DT_MATCH|DT_SEARCH)) ) | 
|---|
| 98 | {	/* simple search, note that minp should be even */ | 
|---|
| 99 | for(t = root, n = 0; n < minp; ++n) | 
|---|
| 100 | {	k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz); | 
|---|
| 101 | if((cmp = _DTCMP(dt,key,k,disc,cmpf,sz)) == 0) | 
|---|
| 102 | return _DTOBJ(t,lk); | 
|---|
| 103 | else | 
|---|
| 104 | {	turn[n] = cmp; | 
|---|
| 105 | if(!(t = cmp < 0 ? t->left : t->right) ) | 
|---|
| 106 | return NIL(void*); | 
|---|
| 107 | } | 
|---|
| 108 | } | 
|---|
| 109 |  | 
|---|
| 110 | /* exceed search length, top-down splay now */ | 
|---|
| 111 | for(n = 0; n < minp; n += 2) | 
|---|
| 112 | {	if(turn[n] < 0) | 
|---|
| 113 | {	t = root->left; | 
|---|
| 114 | if(turn[n+1] < 0) | 
|---|
| 115 | {	rrotate(root,t); | 
|---|
| 116 | rlink(r,t); | 
|---|
| 117 | root = t->left; | 
|---|
| 118 | } | 
|---|
| 119 | else | 
|---|
| 120 | {	llink(l,t); | 
|---|
| 121 | rlink(r,root); | 
|---|
| 122 | root = t->right; | 
|---|
| 123 | } | 
|---|
| 124 | } | 
|---|
| 125 | else | 
|---|
| 126 | {	t = root->right; | 
|---|
| 127 | if(turn[n+1] > 0) | 
|---|
| 128 | {	lrotate(root,t); | 
|---|
| 129 | llink(l,t); | 
|---|
| 130 | root = t->right; | 
|---|
| 131 | } | 
|---|
| 132 | else | 
|---|
| 133 | {	rlink(r,t); | 
|---|
| 134 | llink(l,root); | 
|---|
| 135 | root = t->left; | 
|---|
| 136 | } | 
|---|
| 137 | } | 
|---|
| 138 | } | 
|---|
| 139 | } | 
|---|
| 140 |  | 
|---|
| 141 | while(1) | 
|---|
| 142 | {	k = _DTOBJ(root,lk); k = _DTKEY(k,ky,sz); | 
|---|
| 143 | if((cmp = _DTCMP(dt,key,k,disc,cmpf,sz)) == 0) | 
|---|
| 144 | break; | 
|---|
| 145 | else if(cmp < 0) | 
|---|
| 146 | {	if((t = root->left) ) | 
|---|
| 147 | {	k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz); | 
|---|
| 148 | if((cmp = _DTCMP(dt,key,k,disc,cmpf,sz)) < 0) | 
|---|
| 149 | {	rrotate(root,t); | 
|---|
| 150 | rlink(r,t); | 
|---|
| 151 | if(!(root = t->left) ) | 
|---|
| 152 | break; | 
|---|
| 153 | } | 
|---|
| 154 | else if(cmp == 0) | 
|---|
| 155 | {	rlink(r,root); | 
|---|
| 156 | root = t; | 
|---|
| 157 | break; | 
|---|
| 158 | } | 
|---|
| 159 | else /* if(cmp > 0) */ | 
|---|
| 160 | {	llink(l,t); | 
|---|
| 161 | rlink(r,root); | 
|---|
| 162 | if(!(root = t->right) ) | 
|---|
| 163 | break; | 
|---|
| 164 | } | 
|---|
| 165 | } | 
|---|
| 166 | else | 
|---|
| 167 | {	rlink(r,root); | 
|---|
| 168 | root = NIL(Dtlink_t*); | 
|---|
| 169 | break; | 
|---|
| 170 | } | 
|---|
| 171 | } | 
|---|
| 172 | else /* if(cmp > 0) */ | 
|---|
| 173 | {	if((t = root->right) ) | 
|---|
| 174 | {	k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz); | 
|---|
| 175 | if((cmp = _DTCMP(dt,key,k,disc,cmpf,sz)) > 0) | 
|---|
| 176 | {	lrotate(root,t); | 
|---|
| 177 | llink(l,t); | 
|---|
| 178 | if(!(root = t->right) ) | 
|---|
| 179 | break; | 
|---|
| 180 | } | 
|---|
| 181 | else if(cmp == 0) | 
|---|
| 182 | {	llink(l,root); | 
|---|
| 183 | root = t; | 
|---|
| 184 | break; | 
|---|
| 185 | } | 
|---|
| 186 | else /* if(cmp < 0) */ | 
|---|
| 187 | {	rlink(r,t); | 
|---|
| 188 | llink(l,root); | 
|---|
| 189 | if(!(root = t->left) ) | 
|---|
| 190 | break; | 
|---|
| 191 | } | 
|---|
| 192 | } | 
|---|
| 193 | else | 
|---|
| 194 | {	llink(l,root); | 
|---|
| 195 | root = NIL(Dtlink_t*); | 
|---|
| 196 | break; | 
|---|
| 197 | } | 
|---|
| 198 | } | 
|---|
| 199 | } | 
|---|
| 200 | } | 
|---|
| 201 |  | 
|---|
| 202 | if(root) | 
|---|
| 203 | {	/* found it, now isolate it */ | 
|---|
| 204 | dt->type |= DT_FOUND; | 
|---|
| 205 | l->right = root->left; | 
|---|
| 206 | r->left = root->right; | 
|---|
| 207 |  | 
|---|
| 208 | if(type&(DT_SEARCH|DT_MATCH)) | 
|---|
| 209 | { has_root: | 
|---|
| 210 | root->left = link.right; | 
|---|
| 211 | root->right = link.left; | 
|---|
| 212 | if((dt->meth->type&DT_OBAG) && (type&(DT_SEARCH|DT_MATCH)) ) | 
|---|
| 213 | {	key = _DTOBJ(root,lk); key = _DTKEY(key,ky,sz); | 
|---|
| 214 | while((t = root->left) ) | 
|---|
| 215 | {	/* find max of left subtree */ | 
|---|
| 216 | while((r = t->right) ) | 
|---|
| 217 | LROTATE(t,r); | 
|---|
| 218 | root->left = t; | 
|---|
| 219 |  | 
|---|
| 220 | /* now see if it's in the same group */ | 
|---|
| 221 | k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz); | 
|---|
| 222 | if(_DTCMP(dt,key,k,disc,cmpf,sz) != 0) | 
|---|
| 223 | break; | 
|---|
| 224 | RROTATE(root,t); | 
|---|
| 225 | } | 
|---|
| 226 | } | 
|---|
| 227 | dt->data->here = root; | 
|---|
| 228 | return _DTOBJ(root,lk); | 
|---|
| 229 | } | 
|---|
| 230 | else if(type&DT_NEXT) | 
|---|
| 231 | {	root->left = link.right; | 
|---|
| 232 | root->right = NIL(Dtlink_t*); | 
|---|
| 233 | link.right = root; | 
|---|
| 234 | dt_next: | 
|---|
| 235 | if((root = link.left) ) | 
|---|
| 236 | {	while((t = root->left) ) | 
|---|
| 237 | RROTATE(root,t); | 
|---|
| 238 | link.left = root->right; | 
|---|
| 239 | goto has_root; | 
|---|
| 240 | } | 
|---|
| 241 | else	goto no_root; | 
|---|
| 242 | } | 
|---|
| 243 | else if(type&DT_PREV) | 
|---|
| 244 | {	root->right = link.left; | 
|---|
| 245 | root->left = NIL(Dtlink_t*); | 
|---|
| 246 | link.left = root; | 
|---|
| 247 | dt_prev: | 
|---|
| 248 | if((root = link.right) ) | 
|---|
| 249 | {	while((t = root->right) ) | 
|---|
| 250 | LROTATE(root,t); | 
|---|
| 251 | link.right = root->left; | 
|---|
| 252 | goto has_root; | 
|---|
| 253 | } | 
|---|
| 254 | else	goto no_root; | 
|---|
| 255 | } | 
|---|
| 256 | else if(type&(DT_DELETE|DT_DETACH)) | 
|---|
| 257 | {	/* taking an object out of the dictionary */ | 
|---|
| 258 | dt_delete: | 
|---|
| 259 | obj = _DTOBJ(root,lk); | 
|---|
| 260 | if(disc->freef && (type&DT_DELETE)) | 
|---|
| 261 | (*disc->freef)(dt,obj,disc); | 
|---|
| 262 | if(disc->link < 0) | 
|---|
| 263 | (*dt->memoryf)(dt,(void*)root,0,disc); | 
|---|
| 264 | if((dt->data->size -= 1) < 0) | 
|---|
| 265 | dt->data->size = -1; | 
|---|
| 266 | goto no_root; | 
|---|
| 267 | } | 
|---|
| 268 | else if(type&(DT_INSERT|DT_ATTACH)) | 
|---|
| 269 | {	if(dt->meth->type&DT_OSET) | 
|---|
| 270 | goto has_root; | 
|---|
| 271 | else | 
|---|
| 272 | {	root->left = NIL(Dtlink_t*); | 
|---|
| 273 | root->right = link.left; | 
|---|
| 274 | link.left = root; | 
|---|
| 275 | goto dt_insert; | 
|---|
| 276 | } | 
|---|
| 277 | } | 
|---|
| 278 | else if(type&DT_RENEW) /* a duplicate */ | 
|---|
| 279 | {	if(dt->meth->type&DT_OSET) | 
|---|
| 280 | {	if(disc->freef) | 
|---|
| 281 | (*disc->freef)(dt,obj,disc); | 
|---|
| 282 | if(disc->link < 0) | 
|---|
| 283 | (*dt->memoryf)(dt,(void*)me,0,disc); | 
|---|
| 284 | } | 
|---|
| 285 | else | 
|---|
| 286 | {	me->left = NIL(Dtlink_t*); | 
|---|
| 287 | me->right = link.left; | 
|---|
| 288 | link.left = me; | 
|---|
| 289 | dt->data->size += 1; | 
|---|
| 290 | } | 
|---|
| 291 | goto has_root; | 
|---|
| 292 | } | 
|---|
| 293 | } | 
|---|
| 294 | else | 
|---|
| 295 | {	/* not found, finish up LEFT and RIGHT trees */ | 
|---|
| 296 | r->left = NIL(Dtlink_t*); | 
|---|
| 297 | l->right = NIL(Dtlink_t*); | 
|---|
| 298 |  | 
|---|
| 299 | if(type&DT_NEXT) | 
|---|
| 300 | goto dt_next; | 
|---|
| 301 | else if(type&DT_PREV) | 
|---|
| 302 | goto dt_prev; | 
|---|
| 303 | else if(type&(DT_SEARCH|DT_MATCH)) | 
|---|
| 304 | { no_root: | 
|---|
| 305 | while((t = r->left) ) | 
|---|
| 306 | r = t; | 
|---|
| 307 | r->left = link.right; | 
|---|
| 308 | dt->data->here = link.left; | 
|---|
| 309 | return (type&DT_DELETE) ? obj : NIL(void*); | 
|---|
| 310 | } | 
|---|
| 311 | else if(type&(DT_INSERT|DT_ATTACH)) | 
|---|
| 312 | { dt_insert: | 
|---|
| 313 | if(disc->makef && (type&DT_INSERT)) | 
|---|
| 314 | obj = (*disc->makef)(dt,obj,disc); | 
|---|
| 315 | if(obj) | 
|---|
| 316 | {	if(lk >= 0) | 
|---|
| 317 | root = _DTLNK(obj,lk); | 
|---|
| 318 | else | 
|---|
| 319 | {	root = (Dtlink_t*)(*dt->memoryf) | 
|---|
| 320 | (dt,NIL(void*),sizeof(Dthold_t),disc); | 
|---|
| 321 | if(root) | 
|---|
| 322 | ((Dthold_t*)root)->obj = obj; | 
|---|
| 323 | else if(disc->makef && disc->freef && | 
|---|
| 324 | (type&DT_INSERT)) | 
|---|
| 325 | (*disc->freef)(dt,obj,disc); | 
|---|
| 326 | } | 
|---|
| 327 | } | 
|---|
| 328 | if(root) | 
|---|
| 329 | {	if(dt->data->size >= 0) | 
|---|
| 330 | dt->data->size += 1; | 
|---|
| 331 | goto has_root; | 
|---|
| 332 | } | 
|---|
| 333 | else	goto no_root; | 
|---|
| 334 | } | 
|---|
| 335 | else if(type&DT_RENEW) | 
|---|
| 336 | {	root = me; | 
|---|
| 337 | dt->data->size += 1; | 
|---|
| 338 | goto has_root; | 
|---|
| 339 | } | 
|---|
| 340 | else /*if(type&DT_DELETE)*/ | 
|---|
| 341 | {	obj = NIL(void*); | 
|---|
| 342 | goto no_root; | 
|---|
| 343 | } | 
|---|
| 344 | } | 
|---|
| 345 |  | 
|---|
| 346 | return NIL(void*); | 
|---|
| 347 | } | 
|---|
| 348 |  | 
|---|
| 349 | /* make this method available */ | 
|---|
| 350 | static Dtmethod_t	_Dtoset =  { dttree, DT_OSET }; | 
|---|
| 351 | static Dtmethod_t	_Dtobag =  { dttree, DT_OBAG }; | 
|---|
| 352 | Dtmethod_t* Dtoset = &_Dtoset; | 
|---|
| 353 | Dtmethod_t* Dtobag = &_Dtobag; | 
|---|
| 354 |  | 
|---|
| 355 | #ifndef KPVDEL /* backward compatibility - delete next time around */ | 
|---|
| 356 | Dtmethod_t		_Dttree = { dttree, DT_OSET }; | 
|---|
| 357 | Dtmethod_t* Dtorder = &_Dttree; | 
|---|
| 358 | Dtmethod_t* Dttree = &_Dttree; | 
|---|
| 359 | #endif | 
|---|
| 360 |  | 
|---|
| 361 | #ifdef NoF | 
|---|
| 362 | NoF(dttree) | 
|---|
| 363 | #endif | 
|---|
| 364 |  | 
|---|