Bug 1403444 - Expand rb_remove. r?njn draft
authorMike Hommey <mh+mozilla@glandium.org>
Tue, 26 Sep 2017 17:13:53 +0900
changeset 670932 75f0993111f55b862f6ac0ac6c81ca159462b249
parent 670931 a665a0c7d9be7aa8212691079c0845b92fc5757c
child 670933 1f0294ddab99fc047da936f8d5ce17e6c03d5217
push id81767
push userbmo:mh+mozilla@glandium.org
push dateWed, 27 Sep 2017 06:43:40 +0000
reviewersnjn
bugs1403444
milestone58.0a1
Bug 1403444 - Expand rb_remove. r?njn At the same time, simplify the expanded code to better fit in the template.
memory/build/rb.h
--- a/memory/build/rb.h
+++ b/memory/build/rb.h
@@ -221,186 +221,16 @@ public:
         rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t);                 \
         a_field(r_node).SetRight(rbp_mrr_t);                                   \
       } else {                                                                 \
         rbp_rotate_left(a_type, a_field, (a_node), (r_node));                  \
       }                                                                        \
     }                                                                          \
   } while (0)
 
-#define rb_remove(a_type, a_field, a_cmp, a_tree, a_node)                      \
-  do {                                                                         \
-    a_type rbp_r_s;                                                            \
-    a_type *rbp_r_p, *rbp_r_c, *rbp_r_xp, *rbp_r_t, *rbp_r_u;                  \
-    int rbp_r_cmp;                                                             \
-    a_field(&rbp_r_s).SetLeft((a_tree)->rbt_root);                             \
-    a_field(&rbp_r_s).SetRight(&(a_tree)->rbt_nil);                            \
-    a_field(&rbp_r_s).SetColor(NodeColor::Black);                              \
-    rbp_r_p = &rbp_r_s;                                                        \
-    rbp_r_c = (a_tree)->rbt_root;                                              \
-    rbp_r_xp = &(a_tree)->rbt_nil;                                             \
-    /* Iterate down the tree, but always transform 2-nodes to 3- or   */       \
-    /* 4-nodes in order to maintain the invariant that the current    */       \
-    /* node is not a 2-node.  This allows simple deletion once a leaf */       \
-    /* is reached.  Handle the root specially though, since there may */       \
-    /* be no way to convert it from a 2-node to a 3-node.             */       \
-    rbp_r_cmp = (a_cmp)((a_node), rbp_r_c);                                    \
-    if (rbp_r_cmp < 0) {                                                       \
-      rbp_r_t = a_field(rbp_r_c).Left();                                       \
-      rbp_r_u = a_field(rbp_r_t).Left();                                       \
-      if (a_field(rbp_r_t).IsBlack() && a_field(rbp_r_u).IsBlack()) {          \
-        /* Apply standard transform to prepare for left move.     */           \
-        rbp_move_red_left(a_type, a_field, rbp_r_c, rbp_r_t);                  \
-        a_field(rbp_r_t).SetColor(NodeColor::Black);                           \
-        a_field(rbp_r_p).SetLeft(rbp_r_t);                                     \
-        rbp_r_c = rbp_r_t;                                                     \
-      } else {                                                                 \
-        /* Move left.                                             */           \
-        rbp_r_p = rbp_r_c;                                                     \
-        rbp_r_c = a_field(rbp_r_c).Left();                                     \
-      }                                                                        \
-    } else {                                                                   \
-      if (rbp_r_cmp == 0) {                                                    \
-        MOZ_ASSERT((a_node) == rbp_r_c);                                       \
-        if (a_field(rbp_r_c).Right() == &(a_tree)->rbt_nil) {                  \
-          /* Delete root node (which is also a leaf node).      */             \
-          if (a_field(rbp_r_c).Left() != &(a_tree)->rbt_nil) {                 \
-            rbp_lean_right(a_type, a_field, rbp_r_c, rbp_r_t);                 \
-            a_field(rbp_r_t).SetRight(&(a_tree)->rbt_nil);                     \
-          } else {                                                             \
-            rbp_r_t = &(a_tree)->rbt_nil;                                      \
-          }                                                                    \
-          a_field(rbp_r_p).SetLeft(rbp_r_t);                                   \
-        } else {                                                               \
-          /* This is the node we want to delete, but we will    */             \
-          /* instead swap it with its successor and delete the  */             \
-          /* successor.  Record enough information to do the    */             \
-          /* swap later.  rbp_r_xp is the a_node's parent.      */             \
-          rbp_r_xp = rbp_r_p;                                                  \
-          rbp_r_cmp = 1; /* Note that deletion is incomplete.   */             \
-        }                                                                      \
-      }                                                                        \
-      if (rbp_r_cmp == 1) {                                                    \
-        if (a_field(a_field(a_field(rbp_r_c).Right()).Left()).IsBlack()) {     \
-          rbp_r_t = a_field(rbp_r_c).Left();                                   \
-          if (a_field(rbp_r_t).IsRed()) {                                      \
-            /* Standard transform.                            */               \
-            rbp_move_red_right(a_type, a_field, rbp_r_c, rbp_r_t);             \
-          } else {                                                             \
-            /* Root-specific transform.                       */               \
-            a_field(rbp_r_c).SetColor(NodeColor::Red);                         \
-            rbp_r_u = a_field(rbp_r_t).Left();                                 \
-            if (a_field(rbp_r_u).IsRed()) {                                    \
-              a_field(rbp_r_u).SetColor(NodeColor::Black);                     \
-              rbp_rotate_right(a_type, a_field, rbp_r_c, rbp_r_t);             \
-              rbp_rotate_left(a_type, a_field, rbp_r_c, rbp_r_u);              \
-              a_field(rbp_r_t).SetRight(rbp_r_u);                              \
-            } else {                                                           \
-              a_field(rbp_r_t).SetColor(NodeColor::Red);                       \
-              rbp_rotate_left(a_type, a_field, rbp_r_c, rbp_r_t);              \
-            }                                                                  \
-          }                                                                    \
-          a_field(rbp_r_p).SetLeft(rbp_r_t);                                   \
-          rbp_r_c = rbp_r_t;                                                   \
-        } else {                                                               \
-          /* Move right.                                        */             \
-          rbp_r_p = rbp_r_c;                                                   \
-          rbp_r_c = a_field(rbp_r_c).Right();                                  \
-        }                                                                      \
-      }                                                                        \
-    }                                                                          \
-    if (rbp_r_cmp != 0) {                                                      \
-      while (true) {                                                           \
-        MOZ_ASSERT(rbp_r_p != &(a_tree)->rbt_nil);                             \
-        rbp_r_cmp = (a_cmp)((a_node), rbp_r_c);                                \
-        if (rbp_r_cmp < 0) {                                                   \
-          rbp_r_t = a_field(rbp_r_c).Left();                                   \
-          if (rbp_r_t == &(a_tree)->rbt_nil) {                                 \
-            /* rbp_r_c now refers to the successor node to    */               \
-            /* relocate, and rbp_r_xp/a_node refer to the     */               \
-            /* context for the relocation.                    */               \
-            if (a_field(rbp_r_xp).Left() == (a_node)) {                        \
-              a_field(rbp_r_xp).SetLeft(rbp_r_c);                              \
-            } else {                                                           \
-              MOZ_ASSERT(a_field(rbp_r_xp).Right() == (a_node));               \
-              a_field(rbp_r_xp).SetRight(rbp_r_c);                             \
-            }                                                                  \
-            a_field(rbp_r_c).SetLeft(a_field(a_node).Left());                  \
-            a_field(rbp_r_c).SetRight(a_field(a_node).Right());                \
-            a_field(rbp_r_c).SetColor(a_field(a_node).Color());                \
-            if (a_field(rbp_r_p).Left() == rbp_r_c) {                          \
-              a_field(rbp_r_p).SetLeft(&(a_tree)->rbt_nil);                    \
-            } else {                                                           \
-              MOZ_ASSERT(a_field(rbp_r_p).Right() == rbp_r_c);                 \
-              a_field(rbp_r_p).SetRight(&(a_tree)->rbt_nil);                   \
-            }                                                                  \
-            break;                                                             \
-          }                                                                    \
-          rbp_r_u = a_field(rbp_r_t).Left();                                   \
-          if (a_field(rbp_r_t).IsBlack() && a_field(rbp_r_u).IsBlack()) {      \
-            rbp_move_red_left(a_type, a_field, rbp_r_c, rbp_r_t);              \
-            if (a_field(rbp_r_p).Left() == rbp_r_c) {                          \
-              a_field(rbp_r_p).SetLeft(rbp_r_t);                               \
-            } else {                                                           \
-              a_field(rbp_r_p).SetRight(rbp_r_t);                              \
-            }                                                                  \
-            rbp_r_c = rbp_r_t;                                                 \
-          } else {                                                             \
-            rbp_r_p = rbp_r_c;                                                 \
-            rbp_r_c = a_field(rbp_r_c).Left();                                 \
-          }                                                                    \
-        } else {                                                               \
-          /* Check whether to delete this node (it has to be    */             \
-          /* the correct node and a leaf node).                 */             \
-          if (rbp_r_cmp == 0) {                                                \
-            MOZ_ASSERT((a_node) == rbp_r_c);                                   \
-            if (a_field(rbp_r_c).Right() == &(a_tree)->rbt_nil) {              \
-              /* Delete leaf node.                          */                 \
-              if (a_field(rbp_r_c).Left() != &(a_tree)->rbt_nil) {             \
-                rbp_lean_right(a_type, a_field, rbp_r_c, rbp_r_t);             \
-                a_field(rbp_r_t).SetRight(&(a_tree)->rbt_nil);                 \
-              } else {                                                         \
-                rbp_r_t = &(a_tree)->rbt_nil;                                  \
-              }                                                                \
-              if (a_field(rbp_r_p).Left() == rbp_r_c) {                        \
-                a_field(rbp_r_p).SetLeft(rbp_r_t);                             \
-              } else {                                                         \
-                a_field(rbp_r_p).SetRight(rbp_r_t);                            \
-              }                                                                \
-              break;                                                           \
-            } else {                                                           \
-              /* This is the node we want to delete, but we */                 \
-              /* will instead swap it with its successor    */                 \
-              /* and delete the successor.  Record enough   */                 \
-              /* information to do the swap later.          */                 \
-              /* rbp_r_xp is a_node's parent.               */                 \
-              rbp_r_xp = rbp_r_p;                                              \
-            }                                                                  \
-          }                                                                    \
-          rbp_r_t = a_field(rbp_r_c).Right();                                  \
-          rbp_r_u = a_field(rbp_r_t).Left();                                   \
-          if (a_field(rbp_r_u).IsBlack()) {                                    \
-            rbp_move_red_right(a_type, a_field, rbp_r_c, rbp_r_t);             \
-            if (a_field(rbp_r_p).Left() == rbp_r_c) {                          \
-              a_field(rbp_r_p).SetLeft(rbp_r_t);                               \
-            } else {                                                           \
-              a_field(rbp_r_p).SetRight(rbp_r_t);                              \
-            }                                                                  \
-            rbp_r_c = rbp_r_t;                                                 \
-          } else {                                                             \
-            rbp_r_p = rbp_r_c;                                                 \
-            rbp_r_c = a_field(rbp_r_c).Right();                                \
-          }                                                                    \
-        }                                                                      \
-      }                                                                        \
-    }                                                                          \
-    /* Update root.                                                   */       \
-    (a_tree)->rbt_root = a_field(&rbp_r_s).Left();                             \
-  } while (0)
-
 /* Tree structure. */
 template<typename T, typename Trait>
 struct RedBlackTree
 {
   T* rbt_root;
   T rbt_nil;
 
   void Init()
@@ -598,17 +428,189 @@ struct RedBlackTree
     }
     /* Update the root and make sure that it is black. */
     rbt_root = Trait::GetTreeNode(&rbp_i_s).Left();
     Trait::GetTreeNode(rbt_root).SetColor(NodeColor::Black);
   }
 
   void Remove(T* aNode)
   {
-    rb_remove(T, Trait::GetTreeNode, Trait::Compare, this, aNode);
+    T rbp_r_s;
+    T *rbp_r_p, *rbp_r_c, *rbp_r_xp, *rbp_r_t, *rbp_r_u;
+    int rbp_r_cmp;
+    Trait::GetTreeNode(&rbp_r_s).SetLeft(rbt_root);
+    Trait::GetTreeNode(&rbp_r_s).SetRight(&rbt_nil);
+    Trait::GetTreeNode(&rbp_r_s).SetColor(NodeColor::Black);
+    rbp_r_p = &rbp_r_s;
+    rbp_r_c = rbt_root;
+    rbp_r_xp = &rbt_nil;
+    /* Iterate down the tree, but always transform 2-nodes to 3- or
+     * 4-nodes in order to maintain the invariant that the current
+     * node is not a 2-node. This allows simple deletion once a leaf
+     * is reached. Handle the root specially though, since there may
+     * be no way to convert it from a 2-node to a 3-node. */
+    rbp_r_cmp = Trait::Compare(aNode, rbp_r_c);
+    if (rbp_r_cmp < 0) {
+      rbp_r_t = Trait::GetTreeNode(rbp_r_c).Left();
+      rbp_r_u = Trait::GetTreeNode(rbp_r_t).Left();
+      if (Trait::GetTreeNode(rbp_r_t).IsBlack() &&
+          Trait::GetTreeNode(rbp_r_u).IsBlack()) {
+        /* Apply standard transform to prepare for left move. */
+        rbp_move_red_left(T, Trait::GetTreeNode, rbp_r_c, rbp_r_t);
+        Trait::GetTreeNode(rbp_r_t).SetColor(NodeColor::Black);
+        Trait::GetTreeNode(rbp_r_p).SetLeft(rbp_r_t);
+        rbp_r_c = rbp_r_t;
+      } else {
+        /* Move left. */
+        rbp_r_p = rbp_r_c;
+        rbp_r_c = Trait::GetTreeNode(rbp_r_c).Left();
+      }
+    } else {
+      if (rbp_r_cmp == 0) {
+        MOZ_ASSERT(aNode == rbp_r_c);
+        if (Trait::GetTreeNode(rbp_r_c).Right() == &rbt_nil) {
+          /* Delete root node (which is also a leaf node). */
+          if (Trait::GetTreeNode(rbp_r_c).Left() != &rbt_nil) {
+            rbp_lean_right(T, Trait::GetTreeNode, rbp_r_c, rbp_r_t);
+            Trait::GetTreeNode(rbp_r_t).SetRight(&rbt_nil);
+          } else {
+            rbp_r_t = &rbt_nil;
+          }
+          Trait::GetTreeNode(rbp_r_p).SetLeft(rbp_r_t);
+        } else {
+          /* This is the node we want to delete, but we will
+           * instead swap it with its successor and delete the
+           * successor. Record enough information to do the
+           * swap later. rbp_r_xp is the aNode's parent. */
+          rbp_r_xp = rbp_r_p;
+          rbp_r_cmp = 1; /* Note that deletion is incomplete. */
+        }
+      }
+      if (rbp_r_cmp == 1) {
+        if (Trait::GetTreeNode(
+              Trait::GetTreeNode(Trait::GetTreeNode(rbp_r_c).Right()).Left())
+              .IsBlack()) {
+          rbp_r_t = Trait::GetTreeNode(rbp_r_c).Left();
+          if (Trait::GetTreeNode(rbp_r_t).IsRed()) {
+            /* Standard transform. */
+            rbp_move_red_right(T, Trait::GetTreeNode, rbp_r_c, rbp_r_t);
+          } else {
+            /* Root-specific transform. */
+            Trait::GetTreeNode(rbp_r_c).SetColor(NodeColor::Red);
+            rbp_r_u = Trait::GetTreeNode(rbp_r_t).Left();
+            if (Trait::GetTreeNode(rbp_r_u).IsRed()) {
+              Trait::GetTreeNode(rbp_r_u).SetColor(NodeColor::Black);
+              rbp_rotate_right(T, Trait::GetTreeNode, rbp_r_c, rbp_r_t);
+              rbp_rotate_left(T, Trait::GetTreeNode, rbp_r_c, rbp_r_u);
+              Trait::GetTreeNode(rbp_r_t).SetRight(rbp_r_u);
+            } else {
+              Trait::GetTreeNode(rbp_r_t).SetColor(NodeColor::Red);
+              rbp_rotate_left(T, Trait::GetTreeNode, rbp_r_c, rbp_r_t);
+            }
+          }
+          Trait::GetTreeNode(rbp_r_p).SetLeft(rbp_r_t);
+          rbp_r_c = rbp_r_t;
+        } else {
+          /* Move right. */
+          rbp_r_p = rbp_r_c;
+          rbp_r_c = Trait::GetTreeNode(rbp_r_c).Right();
+        }
+      }
+    }
+    if (rbp_r_cmp != 0) {
+      while (true) {
+        MOZ_ASSERT(rbp_r_p != &rbt_nil);
+        rbp_r_cmp = Trait::Compare(aNode, rbp_r_c);
+        if (rbp_r_cmp < 0) {
+          rbp_r_t = Trait::GetTreeNode(rbp_r_c).Left();
+          if (rbp_r_t == &rbt_nil) {
+            /* rbp_r_c now refers to the successor node to
+             * relocate, and rbp_r_xp/aNode refer to the
+             * context for the relocation. */
+            if (Trait::GetTreeNode(rbp_r_xp).Left() == (aNode)) {
+              Trait::GetTreeNode(rbp_r_xp).SetLeft(rbp_r_c);
+            } else {
+              MOZ_ASSERT(Trait::GetTreeNode(rbp_r_xp).Right() == (aNode));
+              Trait::GetTreeNode(rbp_r_xp).SetRight(rbp_r_c);
+            }
+            Trait::GetTreeNode(rbp_r_c).SetLeft(
+              Trait::GetTreeNode(aNode).Left());
+            Trait::GetTreeNode(rbp_r_c).SetRight(
+              Trait::GetTreeNode(aNode).Right());
+            Trait::GetTreeNode(rbp_r_c).SetColor(
+              Trait::GetTreeNode(aNode).Color());
+            if (Trait::GetTreeNode(rbp_r_p).Left() == rbp_r_c) {
+              Trait::GetTreeNode(rbp_r_p).SetLeft(&rbt_nil);
+            } else {
+              MOZ_ASSERT(Trait::GetTreeNode(rbp_r_p).Right() == rbp_r_c);
+              Trait::GetTreeNode(rbp_r_p).SetRight(&rbt_nil);
+            }
+            break;
+          }
+          rbp_r_u = Trait::GetTreeNode(rbp_r_t).Left();
+          if (Trait::GetTreeNode(rbp_r_t).IsBlack() &&
+              Trait::GetTreeNode(rbp_r_u).IsBlack()) {
+            rbp_move_red_left(T, Trait::GetTreeNode, rbp_r_c, rbp_r_t);
+            if (Trait::GetTreeNode(rbp_r_p).Left() == rbp_r_c) {
+              Trait::GetTreeNode(rbp_r_p).SetLeft(rbp_r_t);
+            } else {
+              Trait::GetTreeNode(rbp_r_p).SetRight(rbp_r_t);
+            }
+            rbp_r_c = rbp_r_t;
+          } else {
+            rbp_r_p = rbp_r_c;
+            rbp_r_c = Trait::GetTreeNode(rbp_r_c).Left();
+          }
+        } else {
+          /* Check whether to delete this node (it has to be
+           * the correct node and a leaf node). */
+          if (rbp_r_cmp == 0) {
+            MOZ_ASSERT(aNode == rbp_r_c);
+            if (Trait::GetTreeNode(rbp_r_c).Right() == &rbt_nil) {
+              /* Delete leaf node. */
+              if (Trait::GetTreeNode(rbp_r_c).Left() != &rbt_nil) {
+                rbp_lean_right(T, Trait::GetTreeNode, rbp_r_c, rbp_r_t);
+                Trait::GetTreeNode(rbp_r_t).SetRight(&rbt_nil);
+              } else {
+                rbp_r_t = &rbt_nil;
+              }
+              if (Trait::GetTreeNode(rbp_r_p).Left() == rbp_r_c) {
+                Trait::GetTreeNode(rbp_r_p).SetLeft(rbp_r_t);
+              } else {
+                Trait::GetTreeNode(rbp_r_p).SetRight(rbp_r_t);
+              }
+              break;
+            } else {
+              /* This is the node we want to delete, but we
+               * will instead swap it with its successor
+               * and delete the successor. Record enough
+               * information to do the swap later.
+               * rbp_r_xp is aNode's parent. */
+              rbp_r_xp = rbp_r_p;
+            }
+          }
+          rbp_r_t = Trait::GetTreeNode(rbp_r_c).Right();
+          rbp_r_u = Trait::GetTreeNode(rbp_r_t).Left();
+          if (Trait::GetTreeNode(rbp_r_u).IsBlack()) {
+            rbp_move_red_right(T, Trait::GetTreeNode, rbp_r_c, rbp_r_t);
+            if (Trait::GetTreeNode(rbp_r_p).Left() == rbp_r_c) {
+              Trait::GetTreeNode(rbp_r_p).SetLeft(rbp_r_t);
+            } else {
+              Trait::GetTreeNode(rbp_r_p).SetRight(rbp_r_t);
+            }
+            rbp_r_c = rbp_r_t;
+          } else {
+            rbp_r_p = rbp_r_c;
+            rbp_r_c = Trait::GetTreeNode(rbp_r_c).Right();
+          }
+        }
+      }
+    }
+    /* Update root. */
+    rbt_root = Trait::GetTreeNode(&rbp_r_s).Left();
   }
 };
 
 /*
  * The iterators simulate recursion via an array of pointers that store the
  * current path.  This is critical to performance, since a series of calls to
  * rb_{next,prev}() would require time proportional to (n lg n), whereas this
  * implementation only requires time proportional to (n).