Advertisement
Guest User

Untitled

a guest
Mar 15th, 2015
264
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 9.52 KB | None | 0 0
  1. module d.gc.rbtree;
  2.  
  3. struct Node(N) {
  4. private:
  5.     Link!N[2] childs;
  6.    
  7.     @property
  8.     ref Link!N left() {
  9.         return childs[0];
  10.     }
  11.    
  12.     @property
  13.     ref Link!N right() {
  14.         return childs[1];
  15.     }
  16. }
  17.  
  18. void rb_print_tree(N)(N* root) {
  19.     Debug!N.print_tree(Link!N(root, Color.Black), 0);
  20. }
  21.  
  22. // Insert a new node in the tree.
  23. N* rb_insert(N)(N* root, N* n) {
  24.     // rbtree's depth is ln(n) which is at most 8 * size_t.sizeof.
  25.     // Each tree node that N.sizeof size, so we can remove ln(N.sizeof).
  26.     // But a branch can be at most 2* longer than the shortest one.
  27.     Path!N[16 * size_t.sizeof /+ -ln(N.sizeof)  +/] path = void;
  28.     auto stackp = &path[0]; // TODO: use .ptr when available.
  29.    
  30.     // Root is always black.
  31.     stackp.link = Link!N(root, Color.Black);
  32.    
  33.     while (!stackp.link.isLeaf()) {
  34.         auto link = stackp.link;
  35.         auto opcmp = n.opCmp(*link.node);
  36.         assert(opcmp != 0);
  37.        
  38.         auto cmp = stackp.cmp = opcmp > 0;
  39.        
  40.         stackp++;
  41.         stackp.link = link.childs[cmp];
  42.     }
  43.    
  44.     // The tree only has a root.
  45.     if (stackp is &path[0]) {
  46.         return n;
  47.     }
  48.    
  49.     // Inserted node is always red.
  50.     stackp.link = Link!N(n, Color.Red);
  51.     assert(stackp.link.isRed());
  52.    
  53.     // Now we found an insertion point, let's fix the tree.
  54.     for (stackp--; stackp !is (&path[0] - 1); stackp--) {
  55.         auto link = stackp.link;
  56.         auto cmp = stackp.cmp;
  57.        
  58.         auto child = link.childs[cmp] = stackp[1].link;
  59.         if (child.isBlack()) {
  60.             break;
  61.         }
  62.        
  63.         if (link.isRed()) {
  64.             continue;
  65.         }
  66.        
  67.         auto sibling = link.childs[!cmp];
  68.         if (sibling.isRed()) {
  69.             assert(link.isBlack());
  70.             assert(link.left.isRed() || link.right.isRed());
  71.            
  72.             /**
  73.              *     B          Br
  74.              *    / \   =>   / \
  75.              *   R   R      Rb  Rb
  76.              */
  77.             link.left = link.left.getAs(Color.Black);
  78.             link.right = link.right.getAs(Color.Black);
  79.             stackp.link = link.getAs(Color.Red);
  80.             continue;
  81.         }
  82.        
  83.         auto line = child.childs[cmp];
  84.         if (line.isBlack()) {
  85.             if (child.childs[!cmp].isBlack()) {
  86.                 // Our red child has 2 black child, we are good.
  87.                 break;
  88.             }
  89.            
  90.             /**
  91.              * We transform The zigzag case into the line case.
  92.              *
  93.              *                 B
  94.              *     B          / \
  95.              *    / \        B   R
  96.              *   B   R   =>       \
  97.              *      / \            R
  98.              *     R   B            \
  99.              *                       B
  100.              */
  101.             assert(child.childs[!cmp].isRed());
  102.             child = child.rotate(cmp);
  103.         }
  104.        
  105.         /**
  106.          *     B            Rb
  107.          *    / \          / \
  108.          *   B   R   =>   Br  R
  109.          *      / \      / \
  110.          *     B   R    B   B
  111.          */
  112.         link.childs[cmp] = child.getAs(Color.Black);
  113.         link = link.getAs(Color.Red);
  114.         stackp.link = link.rotate(!cmp);
  115.     }
  116.    
  117.     return path[0].link.node;
  118. }
  119.  
  120. // Remove a node from the tree.
  121. N* rb_remove(N)(N* root, N* n) {
  122.     // rbtree's depth is ln(n) which is at most 8 * size_t.sizeof.
  123.     // Each tree node that N.sizeof size, so we can remove ln(N.sizeof).
  124.     // But a branch can be at most 2* longer than the shortest one.
  125.     Path!N[16 * size_t.sizeof /+ -ln(N.sizeof)  +/] path = void;
  126.     auto stackp = &path[0]; // TODO: use .ptr when available.
  127.    
  128.     // Root is always black.
  129.     stackp.link = Link!N(root, Color.Black);
  130.    
  131.     while (true) {
  132.         auto opcmp = n.opCmp(*stackp.link.node);
  133.        
  134.         // We found our node !
  135.         if (opcmp == 0) {
  136.             break;
  137.         }
  138.        
  139.         auto link = stackp.link;
  140.         auto cmp = stackp.cmp = opcmp > 0;
  141.        
  142.         stackp++;
  143.         stackp.link = link.childs[cmp];
  144.        
  145.         assert(!stackp.link.isLeaf(), "Element not found in rbtree.");
  146.     }
  147.    
  148.     // Now we look for a succesor.
  149.     stackp.cmp = true;
  150.     auto removep = stackp;
  151.     auto removed = removep.link;
  152.    
  153.     assert(removep.link.node is n);
  154.    
  155.     stackp++;
  156.     stackp.link = removep.link.right;
  157.    
  158.     while(!stackp.link.isLeaf()) {
  159.         stackp.cmp = false;
  160.         auto link = stackp.link;
  161.        
  162.         stackp++;
  163.         stackp.link = link.left;
  164.     }
  165.    
  166.     stackp--;
  167.    
  168.     if (stackp is removep) {
  169.         // The node we remove has no successor.
  170.         stackp.link = stackp.link.left;
  171.     } else {
  172.         /**
  173.          * Swap node to be deleted with its successor
  174.          * but not the color, so we keep tree color
  175.          * constraint in place.
  176.          */
  177.         auto rcolor = removep.link.color;
  178.         removed = removed.getAs(stackp.link.color);
  179.        
  180.         auto link = stackp.link.getAs(rcolor);
  181.         stackp.link = link.right;
  182.        
  183.         link.left = removep.link.left;
  184.        
  185.         /**
  186.          * If the successor is the right child of the
  187.          * node we want to delete, this is incorrect.
  188.          * However, it doesn't matter, as it is going
  189.          * to be fixed during pruning.
  190.          */
  191.         link.right = removep.link.right;
  192.        
  193.         // NB: We don't clean the node to be removed.
  194.         // We simply splice it out.
  195.         removep.link = link;
  196.     }
  197.    
  198.     // If we are not at the root, fix the parent.
  199.     if (removep !is &path[0]) {
  200.         removep[-1].link.childs[removep[-1].cmp] = removep.link;
  201.     }
  202.    
  203.     // Removing red node require no fixup.
  204.     if (removed.isRed()) {
  205.         stackp[-1].link.childs[stackp[-1].cmp] = Link!N(null, Color.Black);
  206.         return path[0].link.node;
  207.     }
  208.    
  209.     for (stackp--; stackp !is (&path[0] - 1); stackp--) {
  210.         auto link = stackp.link;
  211.         auto cmp = stackp.cmp;
  212.        
  213.         auto child = stackp[1].link;
  214.         if (child.isRed()) {
  215.             // If the double black is on a red node, recolor.
  216.             link.childs[cmp] = child.getAs(Color.Black);
  217.             break;
  218.         }
  219.        
  220.         link.childs[cmp] = child;
  221.        
  222.         /**
  223.          * b = changed to black
  224.          * r = changed to red
  225.          * // = double black path
  226.          *
  227.          * We rotate and recolor to find ourselves in a case
  228.          * where sibling is black one level below. Because the
  229.          * new root will be red, zigzag case will bubble up
  230.          * with a red node, which is going to terminate.
  231.          *
  232.          *
  233.          *            Rb
  234.          *   B         \
  235.          *  / \\   =>   Br  <- new link
  236.          * R    B        \\
  237.          *                 B
  238.          */
  239.         auto sibling = link.childs[!cmp];
  240.         if (sibling.isRed()) {
  241.             assert(link.isBlack());
  242.            
  243.             link = link.getAs(Color.Red);
  244.             auto parent = link.rotate(cmp);
  245.             stackp.link = parent.getAs(Color.Black);
  246.            
  247.             // As we are going down one level, make sure we fix the parent.
  248.             if (stackp !is &path[0]) {
  249.                 stackp[-1].link.childs[stackp[-1].cmp] = stackp.link;
  250.             }
  251.            
  252.             stackp++;
  253.            
  254.             // Fake landing one level below.
  255.             // NB: We don't need to fake cmp.
  256.             stackp.link = link;
  257.             sibling = link.childs[!cmp];
  258.         }
  259.        
  260.         auto line = sibling.childs[!cmp];
  261.         if (line.isRed()) {
  262.             goto Line;
  263.         }
  264.        
  265.         if (sibling.childs[cmp].isBlack()) {
  266.             /**
  267.              * b = changed to black
  268.              * r = changed to red
  269.              * // = double black path
  270.              *
  271.              * We recolor the sibling to push the double
  272.              * black one level up.
  273.              *
  274.              *     X           (X)
  275.              *    / \\         / \
  276.              *   B    B  =>   Br  B
  277.              *  / \          / \
  278.              * B   B        B   B
  279.              */
  280.             link.childs[!cmp] = sibling.getAs(Color.Red);
  281.             continue;
  282.         }
  283.        
  284.         /**
  285.          * b = changed to black
  286.          * r = changed to red
  287.          * // = double black path
  288.          *
  289.          * We rotate the zigzag to be in the line case.
  290.          *
  291.          *                   X
  292.          *     X            / \\
  293.          *    / \\         Rb   B
  294.          *   B    B  =>   /
  295.          *  / \          Br
  296.          * B   R        /
  297.          *             B
  298.          */
  299.         line = sibling.getAs(Color.Red);
  300.         sibling = line.rotate(!cmp);
  301.         sibling = sibling.getAs(Color.Black);
  302.         link.childs[!cmp] = sibling;
  303.        
  304.         Line:
  305.         /**
  306.          * b = changed to black
  307.          * x = changed to x's original color
  308.          * // = double black path
  309.          *
  310.          *     X           Bx
  311.          *    / \\        / \
  312.          *   B    B  =>  Rb  Xb
  313.          *  / \             / \
  314.          * R   Y           Y   B
  315.          */
  316.         auto l = link.getAs(Color.Black);
  317.         l = l.rotate(cmp);
  318.         l.childs[!cmp] = line.getAs(Color.Black);
  319.        
  320.         // If we are the root, we are done.
  321.         if (stackp is &path[0]) {
  322.             return l.node;
  323.         }
  324.        
  325.         stackp[-1].link.childs[stackp[-1].cmp] = l.getAs(link.color);
  326.         break;
  327.     }
  328.    
  329.     return path[0].link.node;
  330. }
  331.  
  332. private:
  333.  
  334. struct Link(N) {
  335.     N* child;
  336.    
  337.     this(N* n, Color c) {
  338.         assert(c == Color.Black || n !is null);
  339.         child = cast(N*) ((cast(size_t) n) | c);
  340.     }
  341.    
  342.     auto getAs(Color c) const {
  343.         assert(c == Color.Black || node !is null);
  344.         return Link(node, c);
  345.     }
  346.    
  347.     @property
  348.     N* node() {
  349.         return cast(N*) ((cast(size_t) child) & ~0x01);
  350.     }
  351.    
  352.     @property
  353.     ref Link left() {
  354.         return node.node.left;
  355.     }
  356.    
  357.     @property
  358.     ref Link right() {
  359.         return node.node.right;
  360.     }
  361.    
  362.     @property
  363.     ref Link[2] childs() {
  364.         return node.node.childs;
  365.     }
  366.    
  367.     @property
  368.     Color color() const {
  369.         return cast(Color) ((cast(size_t) child) & 0x01);
  370.     }
  371.    
  372.     bool isRed() const {
  373.         return color == Color.Red;
  374.     }
  375.    
  376.     bool isBlack() const {
  377.         return color == Color.Black;
  378.     }
  379.    
  380.     bool isLeaf() const {
  381.         return child is null;
  382.     }
  383.    
  384.     // Rotate the tree and return the new root.
  385.     // The tree turn clockwize if cmp is true,
  386.     // counterclockwize if it is false.
  387.     auto rotate(bool cmp) {
  388.         auto x = childs[!cmp];
  389.         childs[!cmp] = x.childs[cmp];
  390.         x.childs[cmp] = this;
  391.         return x;
  392.     }
  393.    
  394.     // Rotate the tree and return the new root.
  395.     auto rotateLeft() {
  396.         auto r = right;
  397.         right = r.left;
  398.         r.left = this;
  399.         return r;
  400.     }
  401.    
  402.     // Rotate the tree and return the new root.
  403.     auto rotateRight() {
  404.         auto l = left;
  405.         left = l.right;
  406.         l.right = this;
  407.         return l;
  408.     }
  409. }
  410.  
  411. // TODO: make bool
  412. enum Color {
  413.     Black = 0,
  414.     Red = 1,
  415. }
  416.  
  417. struct Path(N) {
  418.     Link!N link;
  419.     bool cmp;
  420. }
  421.  
  422. template Debug(N) {
  423.  
  424. void print_tree(Link!N root, uint depth) {
  425.     foreach (i; 0 .. depth) {
  426.         printf("\t".ptr);
  427.     }
  428.    
  429.     if (root.isBlack()) {
  430.         printf("B %p\n".ptr, root.node);
  431.     } else {
  432.         assert(root.isRed());
  433.         printf("R %p\n".ptr, root.node);
  434.     }
  435.    
  436.     if (!root.isLeaf()) {
  437.         print_tree(root.right, depth + 1);
  438.         print_tree(root.left, depth + 1);
  439.     }
  440. }
  441.  
  442. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement