diff options
Diffstat (limited to 'nx-X11/util/memleak/fmalloc.c')
-rw-r--r-- | nx-X11/util/memleak/fmalloc.c | 1256 |
1 files changed, 0 insertions, 1256 deletions
diff --git a/nx-X11/util/memleak/fmalloc.c b/nx-X11/util/memleak/fmalloc.c deleted file mode 100644 index bce5c4388..000000000 --- a/nx-X11/util/memleak/fmalloc.c +++ /dev/null @@ -1,1256 +0,0 @@ -/* - * $Xorg: fmalloc.c,v 1.5 2001/02/09 02:06:19 xorgcvs Exp $ - * -Copyright 1992, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - * - * Author: Keith Packard, MIT X Consortium - */ - -/* $XFree86: xc/util/memleak/fmalloc.c,v 3.12 2001/02/16 13:24:10 eich Exp $ */ - - -/* - * Leak tracing allocator -- using C lib malloc/free, tracks - * all allocations. When requested, performs a garbage-collection - * style mark/sweep on static memory (data and stack), locating - * objects referenced therein. Recursively marks objects. - * Sweeps through all allocations, warning of possible violations - * (unreferenced allocated, referenced freed etc). - */ - -#include <stdio.h> - -extern char **environ; -extern xf86DriverList; -extern etext; -extern _etext; -extern __data_start; -extern _end; - -#ifndef TOP_OF_DATA -#define TOP_OF_DATA 0 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - -#ifdef X_NOT_POSIX -#define NO_ATEXIT -#endif - -typedef unsigned long mem; -typedef unsigned int magic; - -#ifdef HAS_GET_RETURN_ADDRESS -#define MAX_RETURN_STACK 16 -#endif - -#define MAX_FREED_MEMORY (1*1024*1024) - -#define ACTIVE_HEAD_MAGIC 0xff1111ff -#define ACTIVE_TAIL_MAGIC 0xee2222ee -#define ACTIVE_DATA_MAGIC 0xdd3333dd -#define FREED_HEAD_MAGIC 0xcc4444cc -#define FREED_TAIL_MAGIC 0xbb5555bb -#define FREED_DATA_MAGIC 0xcc6666cc - -/* - * the marked fields in each head have two bits - one indicating - * references to the head of the block, and one indicating references - * to the middle of the block - */ -#define UNREFERENCED 0 -#define REFERENCED_HEAD 1 -#define REFERENCED_MIDDLE 2 - -typedef struct _head { - struct _head *left, *right; - struct _head *next; - int balance; -#ifdef HAS_GET_RETURN_ADDRESS - mem returnStack[MAX_RETURN_STACK]; -#endif - mem *from; - mem *fromReturnStack; - unsigned long allocTime; - unsigned long freeTime; - int size; - int desiredsize; - int actualSize; - int marked; - magic headMagic; -} HeadRec, *HeadPtr; - -typedef struct _tail { - magic tailMagic; - magic tailPad; -} TailRec, *TailPtr; - -#define Header(p) ((HeadPtr) (((char *) (p)) - sizeof (HeadRec))) -#define DataForHead(h) ((mem *) ((h) + 1)) -#define Tailer(p) ((TailPtr) (((char *) (p)) + Header(p)->size)) -#define TailForHead(h) (Tailer(DataForHead(h))) -#define RoundSize (sizeof (mem)) -#define RoundUp(s) (((s) + RoundSize - 1) & ~(RoundSize - 1)) -#define TotalSize(s) ((s) + sizeof (HeadRec) + sizeof (TailRec)) -#define CheckInit() if (!endOfStaticMemory) endOfStaticMemory = sbrk(0) -#define BlockContains(h,p) (DataForHead(h) <= (p) && (p) < (mem *) TailForHead(h)) - -typedef HeadRec tree; -typedef mem *tree_data; - -#define COMPARE_ADDR(a,b,op) (((mem) (a)) op ((mem) (b))) -#define COMPARE(a,b,op,s) ((!s) ? \ - COMPARE_ADDR(a,b,op) :\ - (((a)->actualSize op (b)->actualSize) || \ - ((a)->actualSize == (b)->actualSize && \ - COMPARE_ADDR(a,b,op)))) - - -#define LESS_THAN(a,b,s) COMPARE(a,b,<,s) -#define GREATER_THAN(a,b,s) COMPARE(a,b,>,s) - -#define SEARCH(top,result,p) for (result = top; result;) {\ - if ((mem *) (p) < DataForHead(result)) \ - result = result->left; \ - else if ((mem *) TailForHead(result) < (mem *) (p)) \ - result = result->right; \ - else \ - break; \ -} - - -static tree *activeMemory, *freedMemory, *deadMemory; - -static mem *endOfStaticMemory = (mem *) TOP_OF_DATA; -static mem *highestAllocatedMemory; - -static int freedMemoryTotal; -static int freedMemoryCount; -static int activeMemoryTotal; -static int activeMemoryCount; -static int deadMemoryTotal; -static int unreferencedAllocatedTotal; -static int unreferencedAllocatedCount; - -int FindLeakWarnMiddlePointers = 0; -unsigned long FindLeakAllocBreakpoint = ~0; -unsigned long FindLeakFreeBreakpoint = ~0; -unsigned long FindLeakTime; -int FindLeakCheckAlways = 0; -int FindLeakValidateAlways = 0; -int FindPrintAllocations = 0; - -static void MarkActiveBlock (); -static int tree_insert (), tree_delete (); -void CheckMemory (); -char *malloc (), *realloc (), *calloc (); -void free (); -extern char *sbrk (); - -#ifdef HAS_GET_RETURN_ADDRESS -static void -PrintReturnStack (m, ra) - char *m; - mem *ra; -{ - int i; - - fprintf (stderr, " %s:", m); - for (i = 0; i < MAX_RETURN_STACK && ra[i]; i++) - fprintf (stderr, " 0x%lx", ra[i]); - fprintf (stderr, "\n"); -} -#endif - -static void -MemError (s, h, ourRet) - char *s; - HeadPtr h; - int ourRet; -{ - mem *ra; - int i; - - if (h) - { - fprintf (stderr, "%s 0x%08lx (size %d) (from 0x%lx) ", - s, DataForHead(h), h->desiredsize, h->from); -#ifdef HAS_GET_RETURN_ADDRESS - if (h->fromReturnStack) - PrintReturnStack ("\nallocated at", h->fromReturnStack); - else - fprintf(stderr,"\n"); - PrintReturnStack ("Saved return stack", h->returnStack); -#else - fprintf(stderr,"\n"); -#endif - } - else - fprintf (stderr, "%s\n", s); -#ifdef HAS_GET_RETURN_ADDRESS - if (ourRet) - { - mem returnStack[MAX_RETURN_STACK]; - - getStackTrace (returnStack, MAX_RETURN_STACK); - PrintReturnStack ("Current return stack", returnStack); - } -#endif -} - -static void -MarkMemoryRegion (low, high) - mem *low, *high; -{ - mem **start = (mem **) low, **end = (mem **) high; - mem *p; - - while (start < end) { - p = *start; - if (endOfStaticMemory <= p && p < highestAllocatedMemory) - MarkActiveBlock (p, (mem *) start); - start++; - } -} - -static void -MarkActiveBlock (p, from) - mem *p, *from; -{ - HeadPtr h, hh; - int marked; - int oldMarked; - - SEARCH(activeMemory, h, p) - if (h) { - marked = REFERENCED_HEAD; - if (p != DataForHead(h)) - marked = REFERENCED_MIDDLE; - oldMarked = h->marked; - if (!(oldMarked & marked)) - { - h->marked |= marked; - h->from = from; -#ifdef HAS_GET_RETURN_ADDRESS - SEARCH(activeMemory, hh, h->from) - if (hh) - h->fromReturnStack = hh->returnStack; -#endif - if (!oldMarked) - MarkMemoryRegion (DataForHead(h), (mem *) TailForHead(h)); - } - return; - } - SEARCH(freedMemory, h, p) - if (h) - { - marked = REFERENCED_HEAD; - if (p != DataForHead(h)) - marked = REFERENCED_MIDDLE; - if (!(h->marked & marked)) - { - h->marked |= marked; - h->from = from; -#ifdef HAS_GET_RETURN_ADDRESS - SEARCH(activeMemory, hh, h->from) - if (hh) - h->fromReturnStack = hh->returnStack; -#endif - } - return; - } -} - -static void -ClearTree (t) - tree *t; -{ - if (!t) - return; - ClearTree (t->left); - t->marked = 0; - t->from = 0; - ClearTree (t->right); -} - -static void -SweepActiveTree (t) - tree *t; -{ - if (!t) - return; - SweepActiveTree (t->left); - if (!t->marked) { - unreferencedAllocatedTotal += t->desiredsize; - unreferencedAllocatedCount++; - MemError ("Unreferenced allocated", t, FALSE); - } - else if (!(t->marked & REFERENCED_HEAD)) - MemError ("Referenced allocated middle", t, FALSE); - SweepActiveTree (t->right); -} - -/* - * run a thread through the tree at the same time - * - the thread runs - * - * root -> left_child ... -> right_child ... -> null - */ - -static tree * -SweepFreedTree (t) - tree *t; -{ - tree *left_last, *right_last; - - if (!t) - return 0; - - left_last = SweepFreedTree (t->left); - if (t->marked) - { - if (t->marked & REFERENCED_HEAD) - MemError ("Referenced freed base", t, FALSE); - else if (FindLeakWarnMiddlePointers) - MemError ("Referenced freed middle", t, FALSE); - } - right_last = SweepFreedTree (t->right); - - if (t->left) - t->next = t->left; - else - t->next = t->right; - if (left_last) - left_last->next = t->right; - if (!right_last) - right_last = left_last; - if (!right_last) - right_last = t; - return right_last; -} - -static void -SweepFreedMemory () -{ - tree *t, *n; - int count, shouldCount; - - (void) SweepFreedTree (freedMemory); - count = 0; - shouldCount = freedMemoryCount; - for (t = freedMemory; t; t = n) { - n = t->next; - count++; - if (!t->marked) - { - (void) tree_delete (&freedMemory, t, FALSE); - freedMemoryTotal -= t->desiredsize; - freedMemoryCount--; - tree_insert (&deadMemory, t, TRUE); - } - } - if (count != shouldCount) - abort (); -} - -static void -ValidateTree (head, headMagic, tailMagic, bodyMagic, mesg) - tree *head; - mem headMagic, tailMagic, bodyMagic; - char *mesg; -{ - TailPtr tail; - magic *p; - int i; - - if (!head) - return; - ValidateTree (head->left, headMagic, tailMagic, bodyMagic, mesg); - tail = TailForHead (head); - if (head->headMagic != headMagic) - MemError (mesg, head, FALSE); - if (tail->tailMagic != tailMagic) - MemError (mesg, head, FALSE); - if (bodyMagic) { - i = head->size / sizeof (magic); - p = (magic *) DataForHead(head); - while (i--) { - if (*p++ != bodyMagic) - { - MemError (mesg, head, FALSE); - break; - } - } - } - ValidateTree (head->right, headMagic, tailMagic, bodyMagic, mesg); -} - -static void -ValidateActiveMemory () -{ - ValidateTree (activeMemory, ACTIVE_HEAD_MAGIC, ACTIVE_TAIL_MAGIC, - 0, "Store outside of active memory"); -} - -static void -ValidateFreedMemory () -{ - ValidateTree (freedMemory, FREED_HEAD_MAGIC, FREED_TAIL_MAGIC, - FREED_DATA_MAGIC, "Store into freed memory"); -} - -static void -AddActiveBlock (h) - HeadPtr h; -{ - TailPtr t = TailForHead(h); - magic *p; - int i; - - tree_insert (&activeMemory, h, FALSE); - if ((mem *) t > highestAllocatedMemory) - highestAllocatedMemory = (mem *) t; - - /* - * Breakpoint position - assign FindLeakAllocBreakpoint with - * debugger and set a breakpoint in the conditional clause below - */ - if (FindLeakTime == FindLeakAllocBreakpoint) - h->headMagic = ACTIVE_HEAD_MAGIC; /* set breakpoint here */ - - h->allocTime = FindLeakTime++; - - h->headMagic = ACTIVE_HEAD_MAGIC; - t->tailMagic = ACTIVE_TAIL_MAGIC; - i = h->size / sizeof (magic); - p = (magic *) DataForHead(h); - while (i--) - *p++ = ACTIVE_DATA_MAGIC; - activeMemoryTotal += h->desiredsize; - activeMemoryCount++; -} - -static void -RemoveActiveBlock (h) - HeadPtr h; -{ - activeMemoryTotal -= h->desiredsize; - activeMemoryCount--; - tree_delete (&activeMemory, h, FALSE); -} - -static void -AddFreedBlock (h) - HeadPtr h; -{ - TailPtr t = TailForHead(h); - int i; - magic *p; - - tree_insert (&freedMemory, h, FALSE); - - /* - * Breakpoint position - assign FindLeakFreeBreakpoint with - * debugger and set a breakpoint in the conditional clause below - */ - if (FindLeakTime == FindLeakFreeBreakpoint) - h->headMagic = FREED_HEAD_MAGIC; /* set breakpoint here */ - - h->freeTime = FindLeakTime++; - - h->headMagic = FREED_HEAD_MAGIC; - t->tailMagic = FREED_TAIL_MAGIC; - i = h->size / sizeof (magic); - p = (magic *) DataForHead(h); - while (i--) - *p++ = FREED_DATA_MAGIC; - freedMemoryTotal += h->desiredsize; - freedMemoryCount++; - /* GC if we've got piles of unused memory */ - if (freedMemoryTotal - deadMemoryTotal >= MAX_FREED_MEMORY) - CheckMemory (); -} -#if 0 -static void -WarnReferencedRange(rangeStart,rangeEnd,from,to) - mem *rangeStart; - mem *rangeEnd; - mem *from; - mem *to; -{ - mem *range = rangeStart; - - while ( range < rangeEnd) { - if ((mem *)*range >= from && (mem *)*range <= to) - fprintf(stderr, "0x%lx still points into newly allocated range\n", - (unsigned long) range); - range++; - } -} - -static void -WarnReferencedTree(head, from, to) - tree *head; - char *from; - char *to; -{ - if (!head) return; - WarnReferencedTree(head->right,from,to); - WarnReferencedRange(DataForHead(head),TailForHead(head),from,to); - WarnReferencedTree(head->left,from,to); -} - -static void -WarnReferenced(from, to) - char *from; - char *to; -{ - mem foo; - - foo = 1; - WarnReferencedTree(activeMemory,from,to); - WarnReferencedRange(BOTTOM_OF_DATA, endOfStaticMemory,from,to); - WarnReferencedRange(&foo, TOP_OF_STACK,from,to); -} -#endif -/* - * Entry points: - * - * CheckMemory () -- Verifies heap - * malloc (size) -- Allocates memory - * free (old) -- Deallocates memory - * realloc (old, size) -- Allocate, copy, free - * calloc (num, size_per) -- Allocate and zero - */ - -void -CheckMemory () -{ -#if 0 - mem foo; - - unreferencedAllocatedTotal = 0; - unreferencedAllocatedCount = 0; - foo = 1; - fprintf (stderr, "\nCheckMemory\n"); - fprintf (stderr, "Static Memory Area: 0x%lx to 0x%lx\n", - BOTTOM_OF_DATA, endOfStaticMemory); - fprintf (stderr, "%d bytes active memory in %d allocations\n", - activeMemoryTotal, activeMemoryCount); - fprintf (stderr, "%d bytes freed memory held from %d allocations\n", - freedMemoryTotal, freedMemoryCount); - ValidateActiveMemory (); - ValidateFreedMemory (); - ClearTree (activeMemory); - ClearTree (freedMemory); - MarkMemoryRegion (BOTTOM_OF_DATA, endOfStaticMemory); - MarkMemoryRegion (&foo, TOP_OF_STACK); - SweepActiveTree (activeMemory); - SweepFreedMemory (); - fprintf (stderr, "%d bytes freed memory still held from %d allocations\n", - freedMemoryTotal, freedMemoryCount); - fprintf (stderr, - "%d bytes of allocated memory not referenced from %d allocations\n", - unreferencedAllocatedTotal,unreferencedAllocatedCount); - deadMemoryTotal = freedMemoryTotal; - fprintf (stderr, "CheckMemory done\n"); -#endif -} - -/* - * Allocator interface -- malloc and free (others in separate files) - */ - -#define CORE_CHUNK 16384 - -static char *core; -static unsigned core_left; -static unsigned total_core_used; - -static char * -morecore (size) - unsigned size; -{ - unsigned alloc_size; - char *alloc, *newcore; - - if (core_left < size) - { - alloc_size = (size + CORE_CHUNK - 1) & ~(CORE_CHUNK-1); - newcore = sbrk (alloc_size); - if (((long) newcore) == -1) - return 0; - core = newcore; - core_left = alloc_size; - total_core_used += alloc_size; - } - alloc = core; - core += size; - core_left -= size; - return alloc; -} - -char * -malloc (desiredsize) - unsigned desiredsize; -{ - char *ret; - unsigned size; - unsigned totalsize; - HeadPtr h; - - if (!endOfStaticMemory) - endOfStaticMemory = (mem *) sbrk(0); - if (FindLeakCheckAlways) - CheckMemory (); - else if (FindLeakValidateAlways) - { - ValidateActiveMemory (); - ValidateFreedMemory (); - } - size = RoundUp(desiredsize); - totalsize = TotalSize (size); - - h = deadMemory; - while (h) - { - if (h->actualSize == size) - break; - else if (h->actualSize < size) - h = h->right; - else { - if (!h->left) - break; - h = h->left; - } - } - if (h) - { - tree_delete (&deadMemory, h, TRUE); - } - else - { - h = (HeadPtr) morecore (totalsize); - if (!h) - return NULL; - h->actualSize = size; - } - h->desiredsize = desiredsize; - h->size = size; -#ifdef HAS_GET_RETURN_ADDRESS - getStackTrace (h->returnStack, MAX_RETURN_STACK); -#endif - AddActiveBlock (h); - ret = (char *) DataForHead(h); - if (FindPrintAllocations) { - fprintf(stderr,"Allocated %i bytes at 0x%lx\n",desiredsize,ret); -#ifdef HAS_GET_RETURN_ADDRESS - PrintReturnStack ("at",h->returnStack); -#endif - } - return ret; -} - -void -free (p) - char *p; -{ - HeadPtr h; - static int beenHere; - -#ifndef NO_ATEXIT - /* do it at free instead of malloc to avoid recursion? */ - if (!beenHere) - { - beenHere = TRUE; - atexit (CheckMemory); - } -#endif - if (!p) - { - MemError ("Freeing NULL", (HeadPtr) 0, TRUE); - return; - } - SEARCH (activeMemory, h, p); - if (!h) - { - SEARCH(freedMemory, h, p); - if (h) - MemError ("Freeing something twice", h, TRUE); - else - MemError ("Freeing something never allocated", h, TRUE); - return; - } - if (DataForHead(h) != (mem *) p) - { - MemError ("Freeing pointer to middle of allocated block", h, TRUE); - return; - } - if (h->headMagic != ACTIVE_HEAD_MAGIC || - TailForHead(h)->tailMagic != ACTIVE_TAIL_MAGIC) - MemError ("Freeing corrupted data", h, TRUE); - RemoveActiveBlock (h); -#ifdef HAS_GET_RETURN_ADDRESS - getStackTrace (h->returnStack, MAX_RETURN_STACK); -#endif - AddFreedBlock (h); - if (FindLeakCheckAlways) - CheckMemory (); - else if (FindLeakValidateAlways) - { - ValidateActiveMemory (); - ValidateFreedMemory (); - } - if (FindPrintAllocations) { - fprintf(stderr,"Freed at: 0x%lx\n",p); - PrintReturnStack ("at",h->returnStack); - } - -} - -char * -realloc (old, desiredsize) - char *old; - unsigned desiredsize; -{ - char *new; - HeadPtr h, fh; - int copysize; - - new = malloc (desiredsize); - if (!new) - return NULL; - if (!old) - return new; - SEARCH(activeMemory, h, old); - if (!h) - { - SEARCH(freedMemory, fh, old); - if (fh) - MemError ("Reallocing from freed data", fh, TRUE); - else - MemError ("Reallocing from something not allocated", h, TRUE); - } - else - { - if (DataForHead(h) != (mem *) old) - { - MemError ("Reallocing from pointer to middle of allocated block", h, TRUE); - } - else - { - if (h->headMagic != ACTIVE_HEAD_MAGIC || - TailForHead(h)->tailMagic != ACTIVE_TAIL_MAGIC) - MemError ("Reallocing corrupted data", h, TRUE); - copysize = desiredsize; - if (h->desiredsize < desiredsize) - copysize = h->desiredsize; -#ifdef SVR4 - memmove (new, old, copysize); -#else - bcopy (old, new, copysize); -#endif - RemoveActiveBlock (h); -#ifdef HAS_GET_RETURN_ADDRESS - getStackTrace (h->returnStack, MAX_RETURN_STACK); -#endif - AddFreedBlock (h); - } - } - if (FindPrintAllocations) { - fprintf(stderr,"Freed at: 0x%lx\n",old); - fprintf(stderr,"Reallocated: %i bytes at: 0x%lx\n",desiredsize,new); -#ifdef HAS_GET_RETURN_ADDRESS - PrintReturnStack ("at", h->returnStack); -#endif - } - return new; -} - -char * -calloc (num, size) - unsigned num, size; -{ - char *ret; - - size *= num; - ret = malloc (size); - if (!ret) - return NULL; -#ifdef SVR4 - memset (ret, 0, size); -#else - bzero (ret, size); -#endif - return ret; -} - -/* - * Semi-Balanced trees (avl). This only contains two - * routines - insert and delete. Searching is - * reserved for the client to write. - */ - -static rebalance_right (), rebalance_left (); - -/* - * insert a new node - * - * this routine returns non-zero if the tree has grown - * taller - */ - -static int -tree_insert (treep, new, bySize) -tree **treep; -tree *new; -int bySize; -{ - if (!(*treep)) { - (*treep) = new; - (*treep)->left = 0; - (*treep)->right = 0; - (*treep)->balance = 0; - return 1; - } else { - if (LESS_THAN (*treep, new, bySize)) { - if (tree_insert (&((*treep)->right), new, bySize)) - switch (++(*treep)->balance) { - case 0: - return 0; - case 1: - return 1; - case 2: - (void) rebalance_right (treep); - } - return 0; - } else if (GREATER_THAN(*treep, new, bySize)) { - if (tree_insert (&((*treep)->left), new, bySize)) - switch (--(*treep)->balance) { - case 0: - return 0; - case -1: - return 1; - case -2: - (void) rebalance_left (treep); - } - return 0; - } else { - return 0; - } - } - /*NOTREACHED*/ -} - -/* - * delete a node from a tree - * - * this routine return non-zero if the tree has been shortened - */ - -static int -tree_delete (treep, old, bySize) -tree **treep; -tree *old; -int bySize; -{ - tree *to_be_deleted; - tree *replacement; - tree *replacement_parent; - int replacement_direction; - int delete_direction; - tree *swap_temp; - int balance_temp; - - if (!*treep) - /* node not found */ - return 0; - if (LESS_THAN(*treep, old, bySize)) { - if (tree_delete (&(*treep)->right, old, bySize)) - /* - * check the balance factors - * Note that the conditions are - * inverted from the insertion case - */ - switch (--(*treep)->balance) { - case 0: - return 1; - case -1: - return 0; - case -2: - return rebalance_left (treep); - } - return 0; - } else if (GREATER_THAN(*treep, old, bySize)) { - if (tree_delete (&(*treep)->left, old, bySize)) - switch (++(*treep)->balance) { - case 0: - return 1; - case 1: - return 0; - case 2: - return rebalance_right (treep); - } - return 0; - } else { - to_be_deleted = *treep; - /* - * find an empty down pointer (if any) - * and rehook the tree - */ - if (!to_be_deleted->right) { - (*treep) = to_be_deleted->left; - return 1; - } else if (!to_be_deleted->left) { - (*treep) = to_be_deleted->right; - return 1; - } else { - /* - * if both down pointers are full, then - * move a node from the bottom of the tree up here. - * - * This builds an incorrect tree -- the replacement - * node and the to_be_deleted node will not - * be in correct order. This doesn't matter as - * the to_be_deleted node will obviously not leave - * this routine alive. - */ - /* - * if the tree is left heavy, then go left - * else go right - */ - replacement_parent = to_be_deleted; - if (to_be_deleted->balance == -1) { - delete_direction = -1; - replacement_direction = -1; - replacement = to_be_deleted->left; - while (replacement->right) { - replacement_parent = replacement; - replacement_direction = 1; - replacement = replacement->right; - } - } else { - delete_direction = 1; - replacement_direction = 1; - replacement = to_be_deleted->right; - while (replacement->left) { - replacement_parent = replacement; - replacement_direction = -1; - replacement = replacement->left; - } - } - /* - * swap the replacement node into - * the tree where the node is to be removed - * - * this would be faster if only the data - * element was swapped -- but that - * won't work for findleak. The alternate - * code would be: - data_temp = to_be_deleted->data; - to _be_deleted->data = replacement->data; - replacement->data = data_temp; - */ - swap_temp = to_be_deleted->left; - to_be_deleted->left = replacement->left; - replacement->left = swap_temp; - swap_temp = to_be_deleted->right; - to_be_deleted->right = replacement->right; - replacement->right = swap_temp; - balance_temp = to_be_deleted->balance; - to_be_deleted->balance = replacement->balance; - replacement->balance = balance_temp; - /* - * if the replacement node is directly below - * the to-be-removed node, hook the to_be_deleted - * node below it (instead of below itself!) - */ - if (replacement_parent == to_be_deleted) - replacement_parent = replacement; - if (replacement_direction == -1) - replacement_parent->left = to_be_deleted; - else - replacement_parent->right = to_be_deleted; - (*treep) = replacement; - /* - * delete the node from the sub-tree - */ - if (delete_direction == -1) { - if (tree_delete (&(*treep)->left, old, bySize)) { - switch (++(*treep)->balance) { - case 2: - abort (); - case 1: - return 0; - case 0: - return 1; - } - } - return 0; - } else { - if (tree_delete (&(*treep)->right, old, bySize)) { - switch (--(*treep)->balance) { - case -2: - abort (); - case -1: - return 0; - case 0: - return 1; - } - } - return 0; - } - } - } - /*NOTREACHED*/ -} - -/* - * two routines to rebalance the tree. - * - * rebalance_right -- the right sub-tree is too long - * rebalance_left -- the left sub-tree is too long - * - * These routines are the heart of avl trees, I've tried - * to make their operation reasonably clear with comments, - * but some study will be necessary to understand the - * algorithm. - * - * these routines return non-zero if the resultant - * tree is shorter than the un-balanced version. This - * is only of interest to the delete routine as the - * balance after insertion can never actually shorten - * the tree. - */ - -static -rebalance_right (treep) -tree **treep; -{ - tree *temp; - /* - * rebalance the tree - */ - if ((*treep)->right->balance == -1) { - /* - * double whammy -- the inner sub-sub tree - * is longer than the outer sub-sub tree - * - * this is the "double rotation" from - * knuth. Scheme: replace the tree top node - * with the inner sub-tree top node and - * adjust the maze of pointers and balance - * factors accordingly. - */ - temp = (*treep)->right->left; - (*treep)->right->left = temp->right; - temp->right = (*treep)->right; - switch (temp->balance) { - case -1: - temp->right->balance = 1; - (*treep)->balance = 0; - break; - case 0: - temp->right->balance = 0; - (*treep)->balance = 0; - break; - case 1: - temp->right->balance = 0; - (*treep)->balance = -1; - break; - } - temp->balance = 0; - (*treep)->right = temp->left; - temp->left = (*treep); - (*treep) = temp; - return 1; - } else { - /* - * a simple single rotation - * - * Scheme: replace the tree top node - * with the sub-tree top node - */ - temp = (*treep)->right->left; - (*treep)->right->left = (*treep); - (*treep) = (*treep)->right; - (*treep)->left->right = temp; - /* - * only two possible configurations -- - * if the right sub-tree was balanced, then - * *both* sides of it were longer than the - * left side, so the resultant tree will - * have a long leg (the left inner leg being - * the same length as the right leg) - */ - if ((*treep)->balance == 0) { - (*treep)->balance = -1; - (*treep)->left->balance = 1; - return 0; - } else { - (*treep)->balance = 0; - (*treep)->left->balance = 0; - return 1; - } - } -} - -static -rebalance_left (treep) -tree **treep; -{ - tree *temp; - /* - * rebalance the tree - */ - if ((*treep)->left->balance == 1) { - /* - * double whammy -- the inner sub-sub tree - * is longer than the outer sub-sub tree - * - * this is the "double rotation" from - * knuth. Scheme: replace the tree top node - * with the inner sub-tree top node and - * adjust the maze of pointers and balance - * factors accordingly. - */ - temp = (*treep)->left->right; - (*treep)->left->right = temp->left; - temp->left = (*treep)->left; - switch (temp->balance) { - case 1: - temp->left->balance = -1; - (*treep)->balance = 0; - break; - case 0: - temp->left->balance = 0; - (*treep)->balance = 0; - break; - case -1: - temp->left->balance = 0; - (*treep)->balance = 1; - break; - } - temp->balance = 0; - (*treep)->left = temp->right; - temp->right = (*treep); - (*treep) = temp; - return 1; - } else { - /* - * a simple single rotation - * - * Scheme: replace the tree top node - * with the sub-tree top node - */ - temp = (*treep)->left->right; - (*treep)->left->right = (*treep); - (*treep) = (*treep)->left; - (*treep)->right->left = temp; - /* - * only two possible configurations -- - * if the left sub-tree was balanced, then - * *both* sides of it were longer than the - * right side, so the resultant tree will - * have a long leg (the right inner leg being - * the same length as the left leg) - */ - if ((*treep)->balance == 0) { - (*treep)->balance = 1; - (*treep)->right->balance = -1; - return 0; - } else { - (*treep)->balance = 0; - (*treep)->right->balance = 0; - return 1; - } - } -} - -#ifdef DEBUG - -static -depth (treep) -tree *treep; -{ - int ldepth, rdepth; - - if (!treep) - return 0; - ldepth = depth (treep->left); - rdepth = depth (treep->right); - if (ldepth > rdepth) - return ldepth + 1; - return rdepth + 1; -} - -static tree * -left_most (treep) -tree *treep; -{ - while (treep && treep->left) - treep = treep->left; - return treep; -} - -static tree * -right_most (treep) -tree *treep; -{ - while (treep && treep->right) - treep = treep->right; - return treep; -} - -tree_verify (treep) -tree *treep; -{ - tree_data left_data, right_data; - - if (!treep) - return 1; - if (treep->left) - left_data = right_most (treep->left)->data; - else - left_data = treep->data - 1; - if (treep->right) - right_data = left_most (treep->right)->data; - else - right_data = treep->data + 1; - if (treep->data < left_data || treep->data > right_data) { - abort (); - return 0; - } - if (treep->balance != depth (treep->right) - depth (treep->left)) { - abort (); - return 0; - } - return tree_verify (treep->left) && tree_verify (treep->right); -} - -#endif |