|
|
1.1 ! root 1: /********************************************************************** ! 2: Memory management: malloc(), realloc(), free(). ! 3: ! 4: Kiem-Phong Vo, ulysses!kpv, ! 5: AT&T Bell Laboratories, MH5D102, 201-582-4869. ! 6: ! 7: The following #-parameters may be redefined: ! 8: SEGMENTED: if defined, memory requests are assumed to be ! 9: non-contiguous across calls of GETCORE's. ! 10: GETCORE: a function to get more core memory. If not SEGMENTED, ! 11: GETCORE(0) is assumed to return the next available ! 12: address. Default is 'sbrk'. ! 13: ERRCORE: the error code as returned by GETCORE. ! 14: Default is ((char *)(-1)). ! 15: CORESIZE: a desired unit (measured in bytes) to be used ! 16: with GETCORE. Default is (1024*ALIGN). ! 17: ! 18: This algorithm is based on a best fit strategy with lists of ! 19: free elts maintained in a self-adjusting binary tree. Each list ! 20: contains all elts of the same size. The tree is ordered by size. ! 21: For results on self-adjusting trees, see the paper: ! 22: Self-Adjusting Binary Trees, ! 23: DD Sleator & RE Tarjan, JACM 1985. ! 24: ! 25: The header of a block contains the size of the data part in bytes. ! 26: Since the size of a block is 0%4, the low two bits of the header ! 27: are free and used as follows: ! 28: ! 29: BIT0: 1 for busy (block is in use), 0 for free. ! 30: BIT1: if the block is busy, this bit is 1 if the ! 31: preceding block in contiguous memory is free. ! 32: Otherwise, it is always 0. ! 33: **********************************************************************/ ! 34: ! 35: /* debugging macros */ ! 36: #ifdef DEBUG ! 37: #define ASSERT(p) if(!(p))abort() ! 38: #define COUNT(n) n++ ! 39: static int nmalloc, nrealloc, nfree; ! 40: #else ! 41: #define ASSERT(p) ! 42: #define COUNT(n) ! 43: #endif /*DEBUG*/ ! 44: ! 45: /* function to copy data from one area to another */ ! 46: #ifdef SYSV ! 47: #define memcopy(to,fr,n) memcpy(to,fr,n) ! 48: #endif ! 49: ! 50: #ifdef BSD ! 51: #define memcopy(to,fr,n) bcopy(fr,to,n) ! 52: #endif ! 53: ! 54: #ifndef memcopy ! 55: static memcopy(to,fr,n) ! 56: register char *to, *fr; ! 57: register int n; ! 58: { ! 59: for(; n > 0; --n) ! 60: *to++ = *fr++; ! 61: } ! 62: #endif ! 63: ! 64: /* for conveniences */ ! 65: #define reg register ! 66: #define NULL (0) ! 67: #define WORDSIZE ((int)(sizeof(WORD))) ! 68: #define MINSIZE ((int)(sizeof(TREE)-sizeof(WORD))) ! 69: #define ROUND(s) if(s%WORDSIZE) s += (WORDSIZE - (s%WORDSIZE)) ! 70: ! 71: #ifdef DEBUG32 ! 72: /* The following definitions ease debugging ! 73: ** on a machine in which sizeof(pointer) == sizeof(int) == 4. ! 74: ** These definitions are not portable. ! 75: */ ! 76: #define ALIGN 4 ! 77: typedef int WORD; ! 78: typedef struct _t_ ! 79: { ! 80: unsigned int t_s; ! 81: struct _t_ *t_p; ! 82: struct _t_ *t_l; ! 83: struct _t_ *t_r; ! 84: struct _t_ *t_n; ! 85: struct _t_ *t_d; ! 86: } TREE; ! 87: #define SIZE(b) ((b)->t_s) ! 88: #define AFTER(b) ((b)->t_p) ! 89: #define PARENT(b) ((b)->t_p) ! 90: #define LEFT(b) ((b)->t_l) ! 91: #define RIGHT(b) ((b)->t_r) ! 92: #define LINKFOR(b) ((b)->t_n) ! 93: #define LINKBAK(b) ((b)->t_p) ! 94: ! 95: #else /* !DEBUG32 */ ! 96: /* The following definitions assume that "char *" has the largest size ! 97: ** among all pointer types. If this is not true, PTRSIZE should ! 98: ** be redefined to be the size of the largest pointer type (void * ?). ! 99: ** All of our allocations will be aligned on the least multiple of 4 ! 100: ** that is >= PTRSIZE. ! 101: */ ! 102: #define PTRSIZE ((int)(sizeof(char *))) ! 103: #define ALIGN (PTRSIZE%4 ? PTRSIZE+(4-(PTRSIZE%4)) : PTRSIZE) ! 104: ! 105: /* the proto-word */ ! 106: typedef union _w_ ! 107: { ! 108: unsigned int w_i; /* an int */ ! 109: struct _t_ *w_p; /* a pointer */ ! 110: char w_a[ALIGN]; /* to force alignment */ ! 111: } WORD; ! 112: ! 113: /* structure of a node in the free tree */ ! 114: typedef struct _t_ ! 115: { ! 116: WORD t_s; /* size of this element */ ! 117: WORD t_p; /* parent node */ ! 118: WORD t_l; /* left child */ ! 119: WORD t_r; /* right child */ ! 120: WORD t_n; /* next in link list */ ! 121: WORD t_d; /* dummy to reserve space for self-pointer */ ! 122: } TREE; ! 123: ! 124: /* usable # of bytes in the block */ ! 125: #define SIZE(b) (((b)->t_s).w_i) ! 126: ! 127: /* free tree pointers */ ! 128: #define PARENT(b) (((b)->t_p).w_p) ! 129: #define LEFT(b) (((b)->t_l).w_p) ! 130: #define RIGHT(b) (((b)->t_r).w_p) ! 131: ! 132: /* forward link in lists of small blocks */ ! 133: #define AFTER(b) (((b)->t_p).w_p) ! 134: ! 135: /* forward and backward links for lists in the tree */ ! 136: #define LINKFOR(b) (((b)->t_n).w_p) ! 137: #define LINKBAK(b) (((b)->t_p).w_p) ! 138: ! 139: #endif /* DEBUG32 */ ! 140: ! 141: /* set/test indicator if a block is in the tree or in a list */ ! 142: #define SETNOTREE(b) (LEFT(b) = (TREE *)(-1)) ! 143: #define ISNOTREE(b) (LEFT(b) == (TREE *)(-1)) ! 144: ! 145: /* functions to get information on a block */ ! 146: #define DATA(b) (((char *) (b)) + WORDSIZE) ! 147: #define BLOCK(d) ((TREE *) ((d) - WORDSIZE)) ! 148: #define SELFP(b) ((TREE **) (((char *) (b)) + SIZE(b))) ! 149: #define LAST(b) (*((TREE **) (((char *) (b)) - WORDSIZE))) ! 150: #define NEXT(b) ((TREE *) (((char *) (b)) + SIZE(b) + WORDSIZE)) ! 151: #define BOTTOM(b) ((DATA(b)+SIZE(b)+WORDSIZE) == Baddr) ! 152: ! 153: /* functions to set and test the lowest two bits of a word */ ! 154: #define BIT0 (01) /* ....01 */ ! 155: #define BIT1 (02) /* ...010 */ ! 156: #define BITS01 (03) /* ...011 */ ! 157: #define ISBIT0(w) ((w) & BIT0) ! 158: #define ISBIT1(w) ((w) & BIT1) ! 159: #define SETBIT0(w) ((w) |= BIT0) ! 160: #define SETBIT1(w) ((w) |= BIT1) ! 161: #define CLRBIT0(w) ((w) &= ~BIT0) ! 162: #define CLRBIT1(w) ((w) &= ~BIT1) ! 163: #define SETBITS01(w) ((w) |= BITS01) ! 164: #define CLRBITS01(w) ((w) &= ~BITS01) ! 165: ! 166: /* system call to get more core */ ! 167: #define GETCORE sbrk ! 168: #define ERRCORE ((char *)(-1)) ! 169: #define CORESIZE (1024*ALIGN) ! 170: ! 171: static TREE *Root, /* root of the free tree */ ! 172: *Bottom, /* the last free chunk in the arena */ ! 173: *_morecore(); /* function to get more core */ ! 174: ! 175: static char *Baddr; /* current high address of the arena */ ! 176: ! 177: char *GETCORE(), *malloc(), *realloc(); ! 178: ! 179: ! 180: /* ! 181: ** Allocation of small blocks ! 182: */ ! 183: ! 184: static TREE *List[MINSIZE/WORDSIZE]; /* lists of small blocks */ ! 185: ! 186: static char * _smalloc(size) ! 187: unsigned int size; ! 188: { ! 189: reg TREE *tp, *np; ! 190: reg int i, n; ! 191: ! 192: /* nothing to do */ ! 193: if(size == 0) ! 194: return NULL; ! 195: ! 196: /* list to use */ ! 197: i = size/WORDSIZE - 1; ! 198: ! 199: if(List[i] == NULL) ! 200: { ! 201: /* number of blocks to get at one time */ ! 202: #define NPS (WORDSIZE*8) ! 203: /**/ASSERT((size+WORDSIZE)*NPS >= MINSIZE); ! 204: ! 205: /* get NPS of these block types */ ! 206: if((List[i] = (TREE *) malloc((size+WORDSIZE)*NPS)) == NULL) ! 207: return NULL; ! 208: ! 209: /* make them into a link list */ ! 210: for(n = 0, np = List[i]; n < NPS; ++n) ! 211: { ! 212: tp = np; ! 213: SIZE(tp) = size; ! 214: np = NEXT(tp); ! 215: AFTER(tp) = np; ! 216: } ! 217: AFTER(tp) = NULL; ! 218: } ! 219: ! 220: /* allocate from the head of the queue */ ! 221: tp = List[i]; ! 222: List[i] = AFTER(tp); ! 223: SETBIT0(SIZE(tp)); ! 224: return DATA(tp); ! 225: } ! 226: ! 227: ! 228: ! 229: /* ! 230: ** malloc(). ! 231: */ ! 232: char * malloc(size) ! 233: unsigned int size; ! 234: { ! 235: reg int n; ! 236: reg TREE *tp, *sp; ! 237: ! 238: /**/ COUNT(nmalloc); ! 239: /**/ ASSERT(WORDSIZE == ALIGN); ! 240: ! 241: /* make sure that size is 0 mod ALIGN */ ! 242: ROUND(size); ! 243: ! 244: /* small blocks */ ! 245: if(size < MINSIZE) ! 246: return _smalloc(size); ! 247: ! 248: /* search for an elt of the right size */ ! 249: sp = NULL; ! 250: n = -1; ! 251: if(Root) ! 252: { ! 253: tp = Root; ! 254: while(1) ! 255: { ! 256: /* branch left */ ! 257: if(SIZE(tp) >= size) ! 258: { ! 259: if(n < 0 || n >= SIZE(tp)) ! 260: sp = tp, n = SIZE(tp); ! 261: if(LEFT(tp)) ! 262: tp = LEFT(tp); ! 263: else break; ! 264: } ! 265: else ! 266: { /* branch right */ ! 267: if(RIGHT(tp)) ! 268: tp = RIGHT(tp); ! 269: else break; ! 270: } ! 271: } ! 272: ! 273: if(sp) ! 274: { ! 275: t_delete(sp); ! 276: } ! 277: else if(tp != Root) ! 278: { ! 279: /* make the searched-to element the root */ ! 280: t_splay(tp); ! 281: Root = tp; ! 282: } ! 283: } ! 284: ! 285: /* if found none fitted in the tree */ ! 286: if(!sp) ! 287: { ! 288: if(Bottom && size <= SIZE(Bottom)) ! 289: sp = Bottom; ! 290: else sp = _morecore(size); ! 291: ! 292: /* no more memory */ ! 293: if(!sp) ! 294: return NULL; ! 295: } ! 296: ! 297: /* tell the forward neighbor that we're busy */ ! 298: CLRBIT1(SIZE(NEXT(sp))); /**/ ASSERT(ISBIT0(SIZE(NEXT(sp)))); ! 299: ! 300: /* if the leftover is enough for a new free piece */ ! 301: if((n = (SIZE(sp) - size) - WORDSIZE) >= MINSIZE) ! 302: { ! 303: SIZE(sp) = size; ! 304: tp = NEXT(sp); ! 305: SIZE(tp) = n|BIT0; ! 306: free(DATA(tp)); ! 307: } ! 308: else if(BOTTOM(sp)) ! 309: Bottom = NULL; ! 310: ! 311: /* return the allocated space */ ! 312: SETBIT0(SIZE(sp)); ! 313: return DATA(sp); ! 314: } ! 315: ! 316: ! 317: /* ! 318: ** realloc(). ! 319: ** If the block size is increasing, we try forward merging first. ! 320: ** This is not best-fit but it avoids some data recopying. ! 321: */ ! 322: char * realloc(old,size) ! 323: char *old; ! 324: unsigned int size; ! 325: { ! 326: reg TREE *tp, *np; ! 327: reg int n, ts; ! 328: reg char *new; ! 329: ! 330: /**/ COUNT(nrealloc); ! 331: ! 332: /* make sure that size is 0 mod ALIGN */ ! 333: ROUND(size); ! 334: ! 335: /* pointer to the block */ ! 336: tp = BLOCK(old); ! 337: ts = SIZE(tp); ! 338: ! 339: /* if the block was freed, data has been destroyed. */ ! 340: if(!ISBIT0(ts)) ! 341: return NULL; ! 342: ! 343: /* nothing to do */ ! 344: CLRBITS01(SIZE(tp)); ! 345: if(size == SIZE(tp)) ! 346: { ! 347: SIZE(tp) = ts; ! 348: return old; ! 349: } ! 350: ! 351: /* special cases involving small blocks */ ! 352: if(size < MINSIZE || SIZE(tp) < MINSIZE) ! 353: goto call_malloc; ! 354: ! 355: /* block is increasing in size, try merging the next block */ ! 356: if(size > SIZE(tp)) ! 357: { ! 358: np = NEXT(tp); ! 359: if(!ISBIT0(SIZE(np))) ! 360: { ! 361: /**/ ASSERT(SIZE(np) >= MINSIZE); ! 362: /**/ ASSERT(!ISBIT1(SIZE(np))); ! 363: SIZE(tp) += SIZE(np)+WORDSIZE; ! 364: if(np != Bottom) ! 365: t_delete(np); ! 366: else Bottom = NULL; ! 367: CLRBIT1(SIZE(NEXT(np))); ! 368: } ! 369: ! 370: #ifndef SEGMENTED ! 371: /* not enough & at TRUE end of memory, try extending core */ ! 372: if(size > SIZE(tp) && BOTTOM(tp) && GETCORE(0) == Baddr) ! 373: { ! 374: Bottom = tp; ! 375: _morecore(size); ! 376: } ! 377: #endif /*!SEGMENTED*/ ! 378: } ! 379: ! 380: /* got enough space to use */ ! 381: if(size <= SIZE(tp)) ! 382: { ! 383: if((n = (SIZE(tp) - size) - WORDSIZE) >= MINSIZE) ! 384: { ! 385: SIZE(tp) = size; ! 386: np = NEXT(tp); ! 387: SIZE(np) = n|BIT0; ! 388: free(DATA(np)); ! 389: } ! 390: else if(BOTTOM(tp)) ! 391: Bottom = NULL; ! 392: ! 393: /* the previous block may be free */ ! 394: if(ISBIT1(ts)) ! 395: SETBIT1(SIZE(tp)); ! 396: SETBIT0(SIZE(tp)); ! 397: return old; ! 398: } ! 399: ! 400: /* call malloc to get a new block */ ! 401: call_malloc: ! 402: SETBIT0(SIZE(tp)); ! 403: if(ISBIT1(ts)) ! 404: SETBIT1(SIZE(tp)); ! 405: if((new = malloc(size)) != NULL) ! 406: { ! 407: ts = SIZE(tp); ! 408: CLRBITS01(ts); ! 409: memcopy(new,old,ts < size ? ts : size); ! 410: } ! 411: free(old); ! 412: return new; ! 413: } ! 414: ! 415: ! 416: ! 417: /* ! 418: ** free(). ! 419: ** Coalescing of adjacent free blocks is done first. ! 420: ** Then, the new free block is leaf-inserted into the free tree ! 421: ** without splaying. This strategy does not guarantee the amortized ! 422: ** O(nlogn) behaviour for the insert/delete/find set of operations ! 423: ** on the tree. In practice, however, free is much more infrequent ! 424: ** than malloc/realloc and the tree searches performed by these ! 425: ** functions adequately keep the tree in balance. ! 426: */ ! 427: free(old) ! 428: char *old; ! 429: { ! 430: reg TREE *tp, *sp, *np; ! 431: reg int ts, size; ! 432: ! 433: /**/ COUNT(nfree); ! 434: ! 435: /* pointer to the block */ ! 436: tp = BLOCK(old); ! 437: ts = SIZE(tp); ! 438: if(!ISBIT0(ts)) ! 439: return -1; ! 440: CLRBITS01(SIZE(tp)); ! 441: ! 442: /* small block, put it in the right linked list */ ! 443: if(SIZE(tp) < MINSIZE) ! 444: { ! 445: ts = SIZE(tp)/WORDSIZE - 1; ! 446: AFTER(tp) = List[ts]; ! 447: List[ts] = tp; ! 448: return 0; ! 449: } ! 450: ! 451: /* see if coalescing with next block is warranted */ ! 452: np = NEXT(tp); ! 453: if(!ISBIT0(SIZE(np))) ! 454: { ! 455: if(np != Bottom) ! 456: t_delete(np); ! 457: SIZE(tp) += SIZE(np)+WORDSIZE; ! 458: } ! 459: ! 460: /* the same with the preceding block */ ! 461: if(ISBIT1(ts)) ! 462: { ! 463: np = LAST(tp); /**/ ASSERT(!ISBIT0(SIZE(np))); ! 464: /**/ ASSERT(np != Bottom); ! 465: t_delete(np); ! 466: SIZE(np) += SIZE(tp)+WORDSIZE; ! 467: tp = np; ! 468: } ! 469: ! 470: /* initialize tree info */ ! 471: PARENT(tp) = LEFT(tp) = RIGHT(tp) = LINKFOR(tp) = NULL; ! 472: ! 473: /* the last word of the block contains self's address */ ! 474: *(SELFP(tp)) = tp; ! 475: ! 476: /* set bottom block, or insert in the free tree */ ! 477: if(BOTTOM(tp)) ! 478: Bottom = tp; ! 479: else ! 480: { ! 481: /* search for the place to insert */ ! 482: if(Root) ! 483: { ! 484: size = SIZE(tp); ! 485: np = Root; ! 486: while(1) ! 487: { ! 488: if(SIZE(np) > size) ! 489: { ! 490: if(LEFT(np)) ! 491: np = LEFT(np); ! 492: else ! 493: { ! 494: LEFT(np) = tp; ! 495: PARENT(tp) = np; ! 496: break; ! 497: } ! 498: } ! 499: else if(SIZE(np) < size) ! 500: { ! 501: if(RIGHT(np)) ! 502: np = RIGHT(np); ! 503: else ! 504: { ! 505: RIGHT(np) = tp; ! 506: PARENT(tp) = np; ! 507: break; ! 508: } ! 509: } ! 510: else ! 511: { ! 512: if(sp = PARENT(np)) /* assignment = */ ! 513: { ! 514: if(np == LEFT(sp)) ! 515: LEFT(sp) = tp; ! 516: else RIGHT(sp) = tp; ! 517: PARENT(tp) = sp; ! 518: } ! 519: else Root = tp; ! 520: ! 521: /* insert to head of list */ ! 522: if(sp = LEFT(np)) /* assignment = */ ! 523: PARENT(sp) = tp; ! 524: LEFT(tp) = sp; ! 525: ! 526: if(sp = RIGHT(np)) /* assignment = */ ! 527: PARENT(sp) = tp; ! 528: RIGHT(tp) = sp; ! 529: ! 530: /* doubly link list */ ! 531: LINKFOR(tp) = np; ! 532: LINKBAK(np) = tp; ! 533: SETNOTREE(np); ! 534: ! 535: break; ! 536: } ! 537: } ! 538: } ! 539: else Root = tp; ! 540: } ! 541: ! 542: /* tell next block that this one is free */ ! 543: SETBIT1(SIZE(NEXT(tp))); /**/ ASSERT(ISBIT0(SIZE(NEXT(tp)))); ! 544: ! 545: return 0; ! 546: } ! 547: ! 548: ! 549: ! 550: /* ! 551: ** Get more core. Gaps in memory are noted as busy blocks. ! 552: */ ! 553: static TREE * _morecore(size) ! 554: unsigned int size; ! 555: { ! 556: reg TREE *tp; ! 557: reg int n; ! 558: reg char *addr; ! 559: ! 560: /* compute new amount of memory to get */ ! 561: tp = Bottom; ! 562: n = size + 2*WORDSIZE; ! 563: ! 564: #ifndef SEGMENTED ! 565: /* if not segmented memory, what we need may be smaller */ ! 566: if((addr = GETCORE(0)) == Baddr) ! 567: n = (size - (tp ? SIZE(tp) : 0)) + WORDSIZE; ! 568: #endif /*!SEGMENTED*/ ! 569: ! 570: /* get a multiple of CORESIZE */ ! 571: n = (n/CORESIZE + 1) * CORESIZE; ! 572: if((addr = GETCORE(n)) == ERRCORE) ! 573: return NULL; ! 574: ! 575: /* contiguous memory */ ! 576: if(addr == Baddr) ! 577: { ! 578: if(tp) ! 579: { ! 580: addr = ((char *)tp); ! 581: n += SIZE(tp) + 2*WORDSIZE; ! 582: } ! 583: else ! 584: { ! 585: addr = Baddr-WORDSIZE; ! 586: n += WORDSIZE; ! 587: } ! 588: } ! 589: ! 590: /* new bottom address */ ! 591: Baddr = addr + n; ! 592: ! 593: /* new bottom block */ ! 594: tp = ((TREE *) addr); ! 595: SIZE(tp) = n - 2*WORDSIZE; /**/ASSERT((SIZE(tp)%ALIGN) == 0); ! 596: ! 597: /* reserved the last word to head any noncontiguous memory */ ! 598: SETBIT0(SIZE(NEXT(tp))); ! 599: ! 600: /* non-contiguous memory, free old bottom block */ ! 601: if(Bottom && Bottom != tp) ! 602: { ! 603: SETBIT0(SIZE(Bottom)); ! 604: free(DATA(Bottom)); ! 605: } ! 606: ! 607: return tp; ! 608: } ! 609: ! 610: ! 611: ! 612: /* ! 613: ** Tree rotation functions (BU: bottom-up, TD: top-down) ! 614: */ ! 615: ! 616: #define LEFT1(x,y) if((RIGHT(x) = LEFT(y))) PARENT(RIGHT(x)) = x;\ ! 617: if((PARENT(y) = PARENT(x)))\ ! 618: if(LEFT(PARENT(x)) == x) LEFT(PARENT(y)) = y;\ ! 619: else RIGHT(PARENT(y)) = y;\ ! 620: LEFT(y) = x; PARENT(x) = y ! 621: ! 622: #define RIGHT1(x,y) if((LEFT(x) = RIGHT(y))) PARENT(LEFT(x)) = x;\ ! 623: if((PARENT(y) = PARENT(x)))\ ! 624: if(LEFT(PARENT(x)) == x) LEFT(PARENT(y)) = y;\ ! 625: else RIGHT(PARENT(y)) = y;\ ! 626: RIGHT(y) = x; PARENT(x) = y ! 627: ! 628: #define BULEFT2(x,y,z) if((RIGHT(x) = LEFT(y))) PARENT(RIGHT(x)) = x;\ ! 629: if((RIGHT(y) = LEFT(z))) PARENT(RIGHT(y)) = y;\ ! 630: if((PARENT(z) = PARENT(x)))\ ! 631: if(LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ ! 632: else RIGHT(PARENT(z)) = z;\ ! 633: LEFT(z) = y; PARENT(y) = z; LEFT(y) = x; PARENT(x) = y ! 634: ! 635: #define BURIGHT2(x,y,z) if((LEFT(x) = RIGHT(y))) PARENT(LEFT(x)) = x;\ ! 636: if((LEFT(y) = RIGHT(z))) PARENT(LEFT(y)) = y;\ ! 637: if((PARENT(z) = PARENT(x)))\ ! 638: if(LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ ! 639: else RIGHT(PARENT(z)) = z;\ ! 640: RIGHT(z) = y; PARENT(y) = z; RIGHT(y) = x; PARENT(x) = y ! 641: ! 642: #define TDLEFT2(x,y,z) if((RIGHT(y) = LEFT(z))) PARENT(RIGHT(y)) = y;\ ! 643: if((PARENT(z) = PARENT(x)))\ ! 644: if(LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ ! 645: else RIGHT(PARENT(z)) = z;\ ! 646: PARENT(x) = z; LEFT(z) = x; ! 647: ! 648: #define TDRIGHT2(x,y,z) if((LEFT(y) = RIGHT(z))) PARENT(LEFT(y)) = y;\ ! 649: if((PARENT(z) = PARENT(x)))\ ! 650: if(LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ ! 651: else RIGHT(PARENT(z)) = z;\ ! 652: PARENT(x) = z; RIGHT(z) = x; ! 653: ! 654: ! 655: ! 656: /* ! 657: ** Delete a tree element ! 658: */ ! 659: static t_delete(op) ! 660: TREE *op; ! 661: { ! 662: reg TREE *tp, *sp, *gp; ! 663: ! 664: /* if this is a non-tree node */ ! 665: if(ISNOTREE(op)) ! 666: { ! 667: tp = LINKBAK(op); ! 668: if(sp = LINKFOR(op)) /* assignment = */ ! 669: LINKBAK(sp) = tp; ! 670: LINKFOR(tp) = sp; ! 671: return; ! 672: } ! 673: ! 674: /* make op the root of the tree */ ! 675: if(PARENT(op)) ! 676: t_splay(op); ! 677: ! 678: /* if this is the start of a list */ ! 679: if(tp = LINKFOR(op)) /* assignment = */ ! 680: { ! 681: PARENT(tp) = NULL; ! 682: if(sp = LEFT(op)) /* assignment = */ ! 683: PARENT(sp) = tp; ! 684: LEFT(tp) = sp; ! 685: ! 686: if(sp = RIGHT(op)) /* assignment = */ ! 687: PARENT(sp) = tp; ! 688: RIGHT(tp) = sp; ! 689: ! 690: Root = tp; ! 691: return; ! 692: } ! 693: ! 694: /* if op has a non-null left subtree */ ! 695: if(tp = LEFT(op)) /* assignment = */ ! 696: { ! 697: PARENT(tp) = NULL; ! 698: ! 699: if(RIGHT(op)) ! 700: { ! 701: /* make the right-end of the left subtree its root */ ! 702: for(sp = RIGHT(tp); sp != NULL; sp = RIGHT(tp)) ! 703: { ! 704: if(gp = RIGHT(sp)) /* assignment = */ ! 705: { ! 706: TDLEFT2(tp,sp,gp); ! 707: tp = gp; ! 708: } ! 709: else ! 710: { ! 711: LEFT1(tp,sp); ! 712: tp = sp; ! 713: } ! 714: } ! 715: ! 716: /* hook the right subtree of op to the above elt */ ! 717: RIGHT(tp) = RIGHT(op); ! 718: PARENT(RIGHT(tp)) = tp; ! 719: } ! 720: } ! 721: ! 722: /* no left subtree */ ! 723: else if(tp = RIGHT(op)) /* assignment = */ ! 724: PARENT(tp) = NULL; ! 725: ! 726: Root = tp; ! 727: } ! 728: ! 729: ! 730: ! 731: /* ! 732: ** Bottom up splaying (simple version). ! 733: ** The basic idea is to roughly cut in half the ! 734: ** path from Root to tp and make tp the new root. ! 735: */ ! 736: static t_splay(tp) ! 737: reg TREE *tp; ! 738: { ! 739: reg TREE *pp, *gp; ! 740: ! 741: /* iterate until tp is the root */ ! 742: for(pp = PARENT(tp); pp != NULL; pp = PARENT(tp)) ! 743: { ! 744: /* grandparent of tp */ ! 745: gp = PARENT(pp); ! 746: ! 747: /* x is a left child */ ! 748: if(LEFT(pp) == tp) ! 749: { ! 750: if(gp && LEFT(gp) == pp) ! 751: { ! 752: BURIGHT2(gp,pp,tp); ! 753: } ! 754: else ! 755: { ! 756: RIGHT1(pp,tp); ! 757: } ! 758: } ! 759: else ! 760: { /**/ ASSERT(RIGHT(pp) == tp); ! 761: if(gp && RIGHT(gp) == pp) ! 762: { ! 763: BULEFT2(gp,pp,tp); ! 764: } ! 765: else ! 766: { ! 767: LEFT1(pp,tp); ! 768: } ! 769: } ! 770: } ! 771: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.