/***********************************************************************/ /* FUNCTION: Treepredecessor */ /**/ /* INPUTS: tree is the tree in question, and x is the node we want the */ /* the predecessor of. */ /**/ /* OUTPUT: This function returns the predecessor of x or NULL if no */ /* predecessor exists. */ /**/ /* Modifies Input: none */ /**/ /* Note: uses the algorithm in _Introduction_To_Algorithms_ */ /***********************************************************************/ chunk_header *TreePredecessor(heap_header *tree, int tree_idx, chunk_header *x) { chunk_header *y; chunk_header *nil = tree->nil; chunk_header *root = (tree_idx == 0) ? tree->root_free_chunk : tree->root_used_chunk; if (nil != (y = x->left)) { /* assignment to y is intentional */ while (y->right != nil) { /* returns the maximum of the left subtree of x */ y = y->right; } return(y); } else { y = x->parent; while (x == y->left) { if (y == root) { return(nil); } x = y; y = y->parent; } return(y); } }
/***********************************************************************/ /* FUNCTION: TreeSuccessor */ /**/ /* INPUTS: tree is the tree in question, and x is the node we want the */ /* the successor of. */ /**/ /* OUTPUT: This function returns the successor of x or NULL if no */ /* successor exists. */ /**/ /* Modifies Input: none */ /**/ /* Note: uses the algorithm in _Introduction_To_Algorithms_ */ /***********************************************************************/ chunk_header *TreeSuccessor(heap_header *tree, int tree_idx, chunk_header *x) { chunk_header *y; chunk_header *nil = tree->nil; chunk_header *root = (tree_idx == 0) ? tree->root_free_chunk : tree->root_used_chunk; if (nil != (y = x->right)) { /* assignment to y is intentional */ while (y->left != nil) { /* returns the minium of the right subtree of x */ y = y->left; } return(y); } else { y = x->parent; while (x == y->right) { /* sentinel used instead of checking for nil */ x = y; y = y->parent; } if (y == root) { return(nil); } return(y); } }
/***********************************************************************/ /* FUNCTION: TreeInsertHelp */ /**/ /* INPUTS: tree is the tree to insert into and z is the node to insert */ /**/ /* OUTPUT: none */ /**/ /* Modifies Input: tree, z */ /**/ /* EFFECTS: Inserts z into the tree as if it were a regular binary tree */ /* using the algorithm described in _Introduction_To_Algorithms_ */ /* by Cormen et al. This funciton is only intended to be called */ /* by the RBTreeInsert function and not by the user */ /***********************************************************************/ void TreeInsertHelp(heap_header *tree, int tree_idx, chunk_header *z) { /* This function should only be called by InsertRBTree (see above) */ chunk_header *x; chunk_header *y; chunk_header *nil = tree->nil; chunk_header *root = (tree_idx == 0) ? tree->root_free_chunk : tree->root_used_chunk; #if DEBUG_TREE Formatter.Write("TreeInsertHelp: tree: ", Program.arch.DebugOutput); Formatter.Write((ulong)tree, "X", Program.arch.DebugOutput); Formatter.Write(", tree_idx: ", Program.arch.DebugOutput); Formatter.Write((ulong)tree_idx, "X", Program.arch.DebugOutput); Formatter.Write(", z: ", Program.arch.DebugOutput); Formatter.Write((ulong)z, "X", Program.arch.DebugOutput); Formatter.Write(", nil: ", Program.arch.DebugOutput); Formatter.Write((ulong)nil, "X", Program.arch.DebugOutput); Formatter.Write(", root: ", Program.arch.DebugOutput); Formatter.Write((ulong)root, "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); #endif z->left = z->right = nil; y = root; x = root->left; while (x != nil) { #if DEBUG_TREE Formatter.Write("x: ", Program.arch.DebugOutput); Formatter.Write((ulong)x, "X", Program.arch.DebugOutput); Formatter.Write(", y: ", Program.arch.DebugOutput); Formatter.Write((ulong)y, "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); #endif y = x; if (1 == Compare(x, z, tree_idx)) { /* x.key > z.key */ x = x->left; } else { /* x,key <= z.key */ x = x->right; } } z->parent = y; if ((y == root) || (1 == Compare(y, z, tree_idx))) { /* y.key > z.key */ y->left = z; } else { y->right = z; } }
/***********************************************************************/ /* FUNCTION: LeftRotate */ /**/ /* INPUTS: This takes a tree so that it can access the appropriate */ /* root and nil pointers, and the node to rotate on. */ /**/ /* OUTPUT: None */ /**/ /* Modifies Input: tree, x */ /**/ /* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ /* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ /* makes the parent of x be to the left of x, x the parent of */ /* its parent before the rotation and fixes other pointers */ /* accordingly. */ /***********************************************************************/ void LeftRotate(heap_header *tree, int tree_idx, chunk_header *x) { chunk_header *y; chunk_header *nil = tree->nil; /* I originally wrote this function to use the sentinel for */ /* nil to avoid checking for nil. However this introduces a */ /* very subtle bug because sometimes this function modifies */ /* the parent pointer of nil. This can be a problem if a */ /* function which calls LeftRotate also uses the nil sentinel */ /* and expects the nil sentinel's parent pointer to be unchanged */ /* after calling this function. For example, when RBDeleteFixUP */ /* calls LeftRotate it expects the parent pointer of nil to be */ /* unchanged. */ y = x->right; x->right = y->left; if (y->left != nil) { y->left->parent = x; /* used to use sentinel here */ } /* and do an unconditional assignment instead of testing for nil */ y->parent = x->parent; /* instead of checking if x->parent is the root as in the book, we */ /* count on the root sentinel to implicitly take care of this case */ if (x == x->parent->left) { x->parent->left = y; } else { x->parent->right = y; } y->left = x; x->parent = y; }
chunk_header *search(heap_header *tree, int tree_idx, int pattern, byte *x) { /* Return the chunk that matches the given pattern value: * * 0) smallest value larger than or equal to (in-order successor of x) * 1) largest value smaller than or equal to (in-order predecessor of x) */ /* First we do an 'pseudo-insert' on the new value and determine its would-be * parent and whether it would be the left or right child of that parent */ chunk_header *parent = null; int child_idx = 0; /* 0 = left child, 1 = right child */ chunk_header *root = (tree_idx == 0) ? tree->root_free_chunk : tree->root_used_chunk; chunk_header *nil = tree->nil; root = root->left; chunk_header *src = root; while (src != nil) { /*Formatter.Write("gengc: search: src: ", Program.arch.DebugOutput); * Formatter.Write((ulong)src, "X", Program.arch.DebugOutput); * Formatter.Write(", parent: ", Program.arch.DebugOutput); * Formatter.Write((ulong)src->parent, "X", Program.arch.DebugOutput); * Formatter.Write(", left: ", Program.arch.DebugOutput); * Formatter.Write((ulong)src->left, "X", Program.arch.DebugOutput); * Formatter.Write(", right: ", Program.arch.DebugOutput); * Formatter.Write((ulong)src->right, "X", Program.arch.DebugOutput); * Formatter.WriteLine(Program.arch.DebugOutput);*/ if (src == null) { Formatter.WriteLine("gengc: search: error: src is null", Program.arch.DebugOutput); Formatter.Write("gengc: tree_idx: ", Program.arch.DebugOutput); Formatter.Write((ulong)tree_idx, Program.arch.DebugOutput); Formatter.Write(", pattern: ", Program.arch.DebugOutput); Formatter.Write((ulong)pattern, Program.arch.DebugOutput); Formatter.Write(", root: ", Program.arch.DebugOutput); Formatter.Write((ulong)root, "X", Program.arch.DebugOutput); Formatter.Write(", nil: ", Program.arch.DebugOutput); Formatter.Write((ulong)nil, "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); while (true) { ; } } byte *node_val; if (tree_idx == 0) { /* free tree, sorted by length */ node_val = src->length; } else { /* used tree, sorted by address */ node_val = (byte *)src; } if (node_val == x) { /* We've found an exact match - return it */ return(src); } if (x > node_val) { /* search to the right */ parent = src; child_idx = 1; src = src->right; } else { /* search to the left */ parent = src; child_idx = 0; src = src->left; } } /* Now we have a leaf node, and know which child of its parent it is * * Look for either the in-order predecessor or successor depending on the * value of 'pattern' * * To do this, for successor we travel up until we find a node that is a * left child, then take its parent. * * For predecessor, we travel up until we find a node that is the right child * of its parent, then take its parent */ while (pattern != child_idx) { /* go up the tree */ chunk_header *cur_node = parent; parent = parent->parent; if (parent == nil) { /* Couldn't find a block of the appropriate size */ return(null); } /* determine whether cur_node is the left or right child of parent */ if (cur_node == parent->left) { child_idx = 0; } else { child_idx = 1; } } return(parent); }
public void Init(void *start, void *end) { sm_sizes = new int[] { 8, 16, 24, 32, 48, 64, 80, 96, 128, 192, 256, 384, 512, 1024, 2048 }; /* sm_total_counts must be a multiple of 8 */ sm_total_counts = new int[] { 512, 256, 160, 128, 80, 64, 48, 40, 32, 16, 8, 8, 8, 8, 8 }; /* Check we have enough space for our structures */ if (((byte *)end - (byte *)start) < 0x100000) { throw new Exception("Not enough heap space provided"); } /* Sanity check */ if (sm_sizes.Length != sm_total_counts.Length) { throw new Exception("sm_sizes and sm_total_counts are not of the same length"); } heap_start = start; heap_end = end; /* Allocate the header structure */ hdr = (heap_header *)start; hdr->used_chunks = 0; hdr->free_chunks = 0; Formatter.Write("gengc: hdr = ", Program.arch.DebugOutput); Formatter.Write((ulong)hdr, "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); /* Start chunks 1 page in */ byte *cur_ptr = (byte *)start + 0x1000; /* Allocate the nil chunk */ chunk_header *nil = (chunk_header *)cur_ptr; cur_ptr += sizeof(chunk_header); nil->parent = nil; nil->left = nil; nil->right = nil; nil->red = 0; nil->flags = 0; nil->length = (byte *)0; hdr->nil = nil; /* Allocate the used tree root chunk */ chunk_header *root_u = (chunk_header *)(cur_ptr); cur_ptr += sizeof(chunk_header); root_u->parent = nil; root_u->left = nil; root_u->right = nil; root_u->red = 0; root_u->length = (byte *)0; root_u->flags = 0; hdr->root_used_chunk = root_u; /* Allocate the free tree root chunk */ chunk_header *root_f = (chunk_header *)(cur_ptr); cur_ptr += sizeof(chunk_header); root_f->parent = nil; root_f->left = nil; root_f->right = nil; root_f->red = 0; root_f->length = (byte *)0; root_f->flags = 0; hdr->root_free_chunk = root_f; /* Allocate the first chunk */ chunk_header *c = (chunk_header *)(cur_ptr); c->length = (byte *)((byte *)end - (byte *)c - sizeof(chunk_header)); c->flags = 1 << 4; // large object c->lock_object = 0; /* Add the first chunk to the tree */ RBTreeInsert(hdr, 0, c); hdr->lo_size = sm_sizes[sm_sizes.Length - 1]; /* Allocate an array for the array of next free sm arrays */ for (int i = 0; i < sm_sizes.Length; i++) { *get_sma_ptr(i) = null; *get_sm_free_ptr(i) = 0; } ready = 1; }
/***********************************************************************/ /* FUNCTION: RBDelete */ /**/ /* INPUTS: tree is the tree to delete node z from */ /**/ /* OUTPUT: none */ /**/ /* EFFECT: Deletes z from tree and frees the key and info of z */ /* using DestoryKey and DestoryInfo. Then calls */ /* RBDeleteFixUp to restore red-black properties */ /**/ /* Modifies Input: tree, z */ /**/ /* The algorithm from this function is from _Introduction_To_Algorithms_ */ /***********************************************************************/ void RBDelete(heap_header *tree, int tree_idx, chunk_header *z) { chunk_header *y; chunk_header *x; chunk_header *nil = tree->nil; chunk_header *root = (tree_idx == 0) ? tree->root_free_chunk : tree->root_used_chunk; /* Remove from the count */ if (tree_idx == 0) { tree->free_chunks--; } else { tree->used_chunks--; } y = ((z->left == nil) || (z->right == nil)) ? z : TreeSuccessor(tree, tree_idx, z); x = (y->left == nil) ? y->right : y->left; if (root == (x->parent = y->parent)) { /* assignment of y->p to x->p is intentional */ root->left = x; } else { if (y == y->parent->left) { y->parent->left = x; } else { y->parent->right = x; } } if (y != z) { /* y should not be nil in this case */ /* y is the node to splice out and x is its child */ if (y->red == 0) { RBDeleteFixUp(tree, tree_idx, x); } //tree->DestroyKey(z->key); //tree->DestroyInfo(z->info); y->left = z->left; y->right = z->right; y->parent = z->parent; y->red = z->red; z->left->parent = z->right->parent = y; if (z == z->parent->left) { z->parent->left = y; } else { z->parent->right = y; } //free(z); } else { //tree->DestroyKey(y->key); //tree->DestroyInfo(y->info); if (y->red == 0) { RBDeleteFixUp(tree, tree_idx, x); } //free(y); } }
/***********************************************************************/ /* FUNCTION: RBDeleteFixUp */ /**/ /* INPUTS: tree is the tree to fix and x is the child of the spliced */ /* out node in RBTreeDelete. */ /**/ /* OUTPUT: none */ /**/ /* EFFECT: Performs rotations and changes colors to restore red-black */ /* properties after a node is deleted */ /**/ /* Modifies Input: tree, x */ /**/ /* The algorithm from this function is from _Introduction_To_Algorithms_ */ /***********************************************************************/ void RBDeleteFixUp(heap_header *tree, int tree_idx, chunk_header *x) { chunk_header *root = (tree_idx == 0) ? tree->root_free_chunk : tree->root_used_chunk; root = root->left; chunk_header *w; while ((x->red == 0) && (root != x)) { if (x == x->parent->left) { w = x->parent->right; if (w->red == 1) { w->red = 0; x->parent->red = 1; LeftRotate(tree, tree_idx, x->parent); w = x->parent->right; } if ((w->right->red == 0) && (w->left->red == 0)) { w->red = 1; x = x->parent; } else { if (w->right->red == 0) { w->left->red = 0; w->red = 1; RightRotate(tree, tree_idx, w); w = x->parent->right; } w->red = x->parent->red; x->parent->red = 0; w->right->red = 0; LeftRotate(tree, tree_idx, x->parent); x = root; /* this is to exit while loop */ } } else { /* the code below is has left and right switched from above */ w = x->parent->left; if (w->red == 1) { w->red = 0; x->parent->red = 1; RightRotate(tree, tree_idx, x->parent); w = x->parent->left; } if ((w->right->red == 0) && (w->left->red == 0)) { w->red = 1; x = x->parent; } else { if (w->left->red == 0) { w->right->red = 0; w->red = 1; LeftRotate(tree, tree_idx, w); w = x->parent->left; } w->red = x->parent->red; x->parent->red = 0; w->left->red = 0; RightRotate(tree, tree_idx, x->parent); x = root; /* this is to exit while loop */ } } } x->red = 0; }
/* Before calling Insert RBTree the node x should have its key set */ /***********************************************************************/ /* FUNCTION: RBTreeInsert */ /**/ /* INPUTS: tree is the red-black tree to insert a node which has a key */ /* pointed to by key and info pointed to by info. */ /**/ /* OUTPUT: This function returns a pointer to the newly inserted node */ /* which is guarunteed to be valid until this node is deleted. */ /* What this means is if another data structure stores this */ /* pointer then the tree does not need to be searched when this */ /* is to be deleted. */ /**/ /* Modifies Input: tree */ /**/ /* EFFECTS: Creates a node node which contains the appropriate key and */ /* info pointers and inserts it into the tree. */ /***********************************************************************/ chunk_header *RBTreeInsert(heap_header *tree, int tree_idx, chunk_header *val) { chunk_header *y; chunk_header *x = val; chunk_header *newNode; chunk_header *root = (tree_idx == 0) ? tree->root_free_chunk : tree->root_used_chunk; /* Add to the count */ if (tree_idx == 0) { tree->free_chunks++; } else { tree->used_chunks++; } TreeInsertHelp(tree, tree_idx, x); newNode = x; x->red = 1; while (x->parent->red == 1) { /* use sentinel instead of checking for root */ if (x->parent == x->parent->parent->left) { y = x->parent->parent->right; if (y->red == 1) { x->parent->red = 0; y->red = 0; x->parent->parent->red = 1; x = x->parent->parent; } else { if (x == x->parent->right) { x = x->parent; LeftRotate(tree, tree_idx, x); } x->parent->red = 0; x->parent->parent->red = 1; RightRotate(tree, tree_idx, x->parent->parent); } } else { /* case for x->parent == x->parent->parent->right */ y = x->parent->parent->left; if (y->red == 1) { x->parent->red = 0; y->red = 0; x->parent->parent->red = 1; x = x->parent->parent; } else { if (x == x->parent->left) { x = x->parent; RightRotate(tree, tree_idx, x); } x->parent->red = 0; x->parent->parent->red = 1; LeftRotate(tree, tree_idx, x->parent->parent); } } } root->left->red = 0; return(newNode); }