Crystal Space: csutil/redblacktree.h Source File (Crystal Space Public API Reference)

| ## Public API Reference

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# csutil/redblacktree.h

Go to the documentation of this file.

    00001 /*
    00002     Copyright (C) 2005 by Jorrit Tyberghein
    00003               (C) 2005 by Frank Richter
    00004
    00005     This library is free software; you can redistribute it and/or
    00006     modify it under the terms of the GNU Library General Public
    00007     License as published by the Free Software Foundation; either
    00008     version 2 of the License, or (at your option) any later version.
    00009
    00010     This library is distributed in the hope that it will be useful,
    00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013     Library General Public License for more details.
    00014
    00015     You should have received a copy of the GNU Library General Public
    00016     License along with this library; if not, write to the Free
    00017     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    00018 */
    00019
    00020 #ifndef __CS_UTIL_REDBLACKTREE_H__
    00021 #define __CS_UTIL_REDBLACKTREE_H__
    00022
    00023 #include "csutil/blockallocator.h"
    00024 #include "csutil/comparator.h"
    00025
    00026 // hack: work around problems caused by #defining 'new'
    00027 #if defined(CS_EXTENSIVE_MEMDEBUG) || defined(CS_MEMORY_TRACKER)
    00028 # undef new
    00029 #endif
    00030 #include <new>
    00031
    00046 template <typename K>
    00047 class csRedBlackTree
    00048 {
    00049 protected:
    00050   enum NodeColor { Black = 0, Red = 1 };
    00052   struct Node
    00053   {
    00054   private:
    00056     Node* parent;
    00057   public:
    00058     Node* left;
    00059     Node* right;
    00060     uint8 key[sizeof(K)];
    00061
    00062     Node() : parent(0) {}
    00063     ~Node() { ((K*)&key)->~K(); }
    00064     inline Node* GetParent() const
    00065     { return (Node*)((uintptr_t)parent & (uintptr_t)~1); }
    00066     void SetParent(Node* p)
    00067     { parent = (Node*)(((uintptr_t)p & (uintptr_t)~1) | (uint)GetColor()); }
    00068     NodeColor GetColor() const
    00069     { // Expression split over two statements to pacify some broken gcc's which
    00070       // barf saying "can't convert Node* to NodeColor".
    00071       uintptr_t const v = ((uintptr_t)parent & 1);
    00072       return (NodeColor)v;
    00073     }
    00074     void SetColor (NodeColor color)
    00075     { parent = (Node*)(((uintptr_t)parent & (uintptr_t)~1) | (uint)color); }
    00076   };
    00077   csBlockAllocator<Node, CS::Memory::AllocatorAlign<2> > nodeAlloc;
    00078
    00079   Node* root;
    00080
    00082   Node* RecursiveInsert (Node* parent, Node*& node, const K& key)
    00083   {
    00084     if (node == 0)
    00085     {
    00086       node = nodeAlloc.Alloc();
    00087       node->SetParent (parent);
    00088       node->left = node->right = 0;
    00089       new ((K*)&node->key) K (key);
    00090       node->SetColor (Red);
    00091       return node;
    00092     }
    00093     else
    00094     {
    00095       int r = csComparator<K, K>::Compare (key, *((K*)&node->key));
    00096       if (r == 0)
    00097         return 0;
    00098       else if (r < 0)
    00099         return RecursiveInsert (node, node->left, key);
    00100       else
    00101         return RecursiveInsert (node, node->right, key);
    00102     }
    00103   }
    00105   void RotateLeft (Node* pivot)
    00106   {
    00107     Node* pivotReplace = pivot->right;
    00108     pivot->right = pivotReplace->left;
    00109     if (pivotReplace->left != 0) pivotReplace->left->SetParent (pivot);
    00110     pivotReplace->SetParent (pivot->GetParent());
    00111     if (pivot->GetParent() == 0)
    00112       root = pivotReplace;
    00113     else
    00114     {
    00115       if (pivot == pivot->GetParent()->left)
    00116         pivot->GetParent()->left = pivotReplace;
    00117       else
    00118         pivot->GetParent()->right = pivotReplace;
    00119     }
    00120     pivotReplace->left = pivot;
    00121     pivot->SetParent (pivotReplace);
    00122   }
    00124   void RotateRight (Node* pivot)
    00125   {
    00126     Node* pivotReplace = pivot->left;
    00127     pivot->left = pivotReplace->right;
    00128     pivotReplace->right->SetParent (pivot);
    00129     pivotReplace->SetParent (pivot->GetParent());
    00130     if (pivot->GetParent() == 0)
    00131       root = pivotReplace;
    00132     else
    00133     {
    00134       if (pivot == pivot->GetParent()->left)
    00135         pivot->GetParent()->left = pivotReplace;
    00136       else
    00137         pivot->GetParent()->right = pivotReplace;
    00138     }
    00139     pivotReplace->right = pivot;
    00140     pivot->SetParent (pivotReplace);
    00141   }
    00143   bool IsBlack (Node* node) const
    00144   { return (node == 0) || (node->GetColor() == Black); }
    00146   bool IsRed (Node* node) const
    00147   { return (node != 0) && (node->GetColor() == Red); }
    00149   void InsertFixup (Node* node)
    00150   {
    00151     Node* p;
    00152     while (((p = node->GetParent()) != 0) && IsRed (p))
    00153     {
    00154       Node* pp = p->GetParent();
    00155       if (pp == 0) break;
    00156       if (p == pp->left)
    00157       {
    00158         Node* y = pp->right;
    00159         if (IsRed (y))
    00160         {
    00161           // Uncle of 'node' is red
    00162           p->SetColor (Black);
    00163           y->SetColor (Black);
    00164           pp->SetColor (Red);
    00165           node = pp;
    00166         }
    00167         else
    00168         {
    00169           if (node == p->right)
    00170           {
    00171             // Uncle of 'node' is black, node is right child
    00172             node = p;
    00173             RotateLeft (node);
    00174           }
    00175           // Uncle of 'node' is black, node is left child
    00176           p->SetColor (Black);
    00177           pp->SetColor (Red);
    00178           RotateRight (pp);
    00179         }
    00180       }
    00181       else
    00182       {
    00183         Node* y = pp->left;
    00184         if (IsRed (y))
    00185         {
    00186           // Uncle of 'node' is red
    00187           p->SetColor (Black);
    00188           y->SetColor (Black);
    00189           pp->SetColor (Red);
    00190           node = pp;
    00191         }
    00192         else
    00193         {
    00194           if (node == p->left)
    00195           {
    00196             // Uncle of 'node' is black, node is left child
    00197             node = p;
    00198             RotateRight (node);
    00199           }
    00200           // Uncle of 'node' is black, node is right child
    00201           p->SetColor (Black);
    00202           pp->SetColor (Red);
    00203           RotateLeft (pp);
    00204         }
    00205       }
    00206     }
    00207     root->SetColor (Black);
    00208   }
    00210   void DeleteNode (Node* node)
    00211   {
    00212     Node* y; // Node we will replace 'node' with
    00213     if ((node->left == 0) || (node->right == 0))
    00214       y = node;
    00215     else
    00216       y = Successor (node);
    00217     Node* x;
    00218     if (y->left != 0)
    00219       x = y->left;
    00220     else
    00221       x = y->right;
    00222     if (x != 0) x->SetParent (y->GetParent());
    00223     if (y->GetParent() == 0)
    00224       root = x;
    00225     else
    00226     {
    00227       if (y == y->GetParent()->left)
    00228         y->GetParent()->left = x;
    00229       else
    00230         y->GetParent()->right = x;
    00231     }
    00232     if (y != node)
    00233     {
    00234       // Copy key
    00235       ((K*)&node->key)->~K();
    00236       new ((K*)&node->key) K (*((K*)&y->key));
    00237     }
    00238     if (y->GetColor() == Black)
    00239       DeleteFixup (node);
    00240     nodeAlloc.Free (y);
    00241   }
    00243   void DeleteFixup (Node* node)
    00244   {
    00245     while ((node != root) && IsBlack (node))
    00246     {
    00247       Node* p = node->GetParent();
    00248       if (node == p->left)
    00249       {
    00250         Node* w = p->right;
    00251         if (IsRed (w))
    00252         {
    00253           w->SetColor (Black);
    00254           p->SetColor (Red);
    00255           RotateLeft (p);
    00256           w = p->right;
    00257         }
    00258         if (IsBlack (w->left) && IsBlack (w->right))
    00259         {
    00260           w->SetColor (Red);
    00261           node = p;
    00262         }
    00263         else
    00264         {
    00265           if (IsBlack (w->right))
    00266           {
    00267             w->left->SetColor (Red);
    00268             w->SetColor (Red);
    00269             RotateRight (w);
    00270             w = p->right;
    00271           }
    00272           w->SetColor (p->GetColor ());
    00273           p->SetColor (Black);
    00274           w->right->SetColor (Black);
    00275           RotateLeft (p);
    00276           node = root;
    00277         }
    00278       }
    00279       else
    00280       {
    00281         Node* w = p->left;
    00282         if (IsRed (w))
    00283         {
    00284           w->SetColor (Black);
    00285           p->SetColor (Red);
    00286           RotateRight (p);
    00287           w = p->left;
    00288         }
    00289         if (IsBlack (w->left) && IsBlack (w->right))
    00290         {
    00291           w->SetColor (Red);
    00292           node = p;
    00293         }
    00294         else
    00295         {
    00296           if (IsBlack (w->left))
    00297           {
    00298             w->right->SetColor (Red);
    00299             w->SetColor (Red);
    00300             RotateLeft (w);
    00301             w = p->left;
    00302           }
    00303           w->SetColor (p->GetColor ());
    00304           p->SetColor (Black);
    00305           w->left->SetColor (Black);
    00306           RotateRight (p);
    00307           node = root;
    00308         }
    00309       }
    00310     }
    00311     node->SetColor (Black);
    00312   }
    00314   Node* LocateNode (Node* node, const K& key) const
    00315   {
    00316     if (node == 0) return 0;
    00317
    00318     int r = csComparator<K, K>::Compare (key, node->key);
    00319     if (r == 0)
    00320       return node;
    00321     else if (r < 0)
    00322       return LocateNode (node->left, key);
    00323     else
    00324       return LocateNode (node->right, key);
    00325   }
    00327   Node* Successor (Node* node) const
    00328   {
    00329     Node* succ;
    00330     if (node->right != 0)
    00331     {
    00332       succ = node->right;
    00333       while (succ->left != 0) succ = succ->left;
    00334       return succ;
    00335     }
    00336     Node* y = node->GetParent();
    00337     while ((y != 0) && (node == y->right))
    00338     {
    00339       node = y;
    00340       y = y->GetParent();
    00341     }
    00342     return y;
    00343   }
    00345
    00346   template<typename K2>
    00347   const K* RecursiveFind (Node* node, const K2& other) const
    00348   {
    00349     if (node == 0) return 0;
    00350     int r = csComparator<K2, K>::Compare (other, *((K*)&node->key));
    00351     if (r == 0)
    00352       return ((K*)&node->key);
    00353     else if (r < 0)
    00354       return RecursiveFind (node->left, other);
    00355     else
    00356       return RecursiveFind (node->right, other);
    00357   }
    00358   template<typename K2>
    00359   K* RecursiveFind (Node* node, const K2& other)
    00360   {
    00361     if (node == 0) return 0;
    00362     int r = csComparator<K2, K>::Compare (other, *((K*)&node->key));
    00363     if (r == 0)
    00364       return ((K*)&node->key);
    00365     else if (r < 0)
    00366       return RecursiveFind (node->left, other);
    00367     else
    00368       return RecursiveFind (node->right, other);
    00369   }
    00370   template<typename K2>
    00371   const K& RecursiveFind (Node* node, const K2& other, const K& fallback) const
    00372   {
    00373     if (node == 0) return fallback;
    00374     int r = csComparator<K2, K>::Compare (other, *((K*)&node->key));
    00375     if (r == 0)
    00376       return *((K*)&node->key);
    00377     else if (r < 0)
    00378       return RecursiveFind (node->left, other);
    00379     else
    00380       return RecursiveFind (node->right, other);
    00381   }
    00382   template<typename K2>
    00383   K& RecursiveFind (Node* node, const K2& other, K& fallback)
    00384   {
    00385     if (node == 0) return fallback;
    00386     int r = csComparator<K2, K>::Compare (other, *((K*)&node->key));
    00387     if (r == 0)
    00388       return *((K*)&node->key);
    00389     else if (r < 0)
    00390       return RecursiveFind (node->left, other);
    00391     else
    00392       return RecursiveFind (node->right, other);
    00393   }
    00395
    00396   template <typename CB>
    00397   void RecursiveTraverseInOrder (Node* node, CB& callback) const
    00398   {
    00399     if (node->left != 0) RecursiveTraverseInOrder (node->left, callback);
    00400     callback.Process (*((K*)&node->key));
    00401     if (node->right != 0) RecursiveTraverseInOrder (node->right, callback);
    00402   }
    00403
    00405
    00406   template<typename K2>
    00407   K* Find (const K2& other)
    00408   {
    00409     return RecursiveFind (root, other);
    00410   }
    00411   template<typename K2>
    00412   K& Find (const K2& other, K& fallback)
    00413   {
    00414     return RecursiveFind (root, other, fallback);
    00415   }
    00417
    00419   void RecursiveCopy (Node*& to, Node* parent, const Node* from)
    00420   {
    00421     if (from == 0)
    00422     {
    00423       to = 0;
    00424       return;
    00425     }
    00426     to = nodeAlloc.Alloc();
    00427     to->SetParent (parent);
    00428     to->SetColor (from->GetColor());
    00429     new ((K*)&to->key) K (*((K*)&from->key));
    00430     RecursiveCopy (to->left, to, from->left);
    00431     RecursiveCopy (to->right, to, from->right);
    00432   }
    00433 public:
    00439   csRedBlackTree (size_t allocatorBlockSize = 4096) :
    00440     nodeAlloc (allocatorBlockSize / sizeof(Node)), root(0) { }
    00441   csRedBlackTree (const csRedBlackTree& other) :
    00442     nodeAlloc (other.nodeAlloc.GetBlockElements())
    00443   {
    00444     RecursiveCopy (root, 0, other.root);
    00445   }
    00446
    00452   const K* Insert (const K& key)
    00453   {
    00454     Node* n = RecursiveInsert (0, root, key);
    00455     if (n == 0) return 0;
    00456     InsertFixup (n);
    00457     return (K*)&n->key;
    00458   }
    00464   bool Delete (const K& key)
    00465   {
    00466     Node* n = LocateNode (root, key);
    00467     if (n == 0) return false;
    00468     DeleteNode (n);
    00469     return true;
    00470   }
    00472   bool In (const K& key) const
    00473   {
    00474     return (LocateNode (root, key) != 0);
    00475   }
    00481   bool Contains (const K& key) const { return In (key); }
    00482
    00484
    00485   template<typename K2>
    00486   const K* Find (const K2& other) const
    00487   {
    00488     return RecursiveFind (root, other);
    00489   }
    00490   template<typename K2>
    00491   const K& Find (const K2& other, const K& fallback) const
    00492   {
    00493     return RecursiveFind (root, other, fallback);
    00494   }
    00496
    00498   void DeleteAll()
    00499   {
    00500     nodeAlloc.Empty();
    00501     root = 0;
    00502   }
    00504   void Empty() { DeleteAll(); }
    00506   bool IsEmpty() const { return (root == 0); }
    00507
    00509
    00510   template <typename CB>
    00511   void TraverseInOrder (CB& callback) const
    00512   {
    00513     if (root != 0) RecursiveTraverseInOrder (root, callback);
    00514   }
    00516 };
    00517
    00522 template <typename K, typename T>
    00523 class csRedBlackTreePayload
    00524 {
    00525   K key;
    00526   T value;
    00527 public:
    00528   csRedBlackTreePayload (const K& k, const T& v) : key(k), value(v) {}
    00529   csRedBlackTreePayload (const csRedBlackTreePayload& other) :
    00530     key(other.key), value(other.value) {}
    00531
    00532   const K& GetKey() const { return key; }
    00533   const T& GetValue() const { return value; }
    00534   T& GetValue() { return value; }
    00535   bool operator < (const csRedBlackTreePayload& other) const
    00536   {
    00537     return (csComparator<K, K>::Compare (key, other.key) < 0);
    00538   }
    00539   bool operator < (const K& other) const
    00540   {
    00541     return (csComparator<K, K>::Compare (key, other) < 0);
    00542   }
    00543   friend bool operator < (const K& k1, const csRedBlackTreePayload& k2)
    00544   {
    00545     return (csComparator<K, K>::Compare (k1, k2.key) < 0);
    00546   }
    00547   operator const T&() const { return value; }
    00548   operator T&() { return value; }
    00549 };
    00550
    00555 template <typename K, typename T>
    00556 class csRedBlackTreeMap : protected csRedBlackTree<csRedBlackTreePayload<K, T> >
    00557 {
    00558   typedef csRedBlackTree<csRedBlackTreePayload<K, T> > supahclass;
    00559
    00560   template<typename CB>
    00561   class TraverseCB
    00562   {
    00563     CB callback;
    00564   public:
    00565     TraverseCB (const CB& callback) : callback(callback) {}
    00566     void Process (csRedBlackTreePayload<K, T>& value)
    00567     {
    00568       callback.Process (value.GetKey(), value.GetValue());
    00569     }
    00570   };
    00571 public:
    00577   T* Put (const K& key, const T &value)
    00578   {
    00579     csRedBlackTreePayload<K, T>* payload = (csRedBlackTreePayload<K, T>*)
    00580       Insert (csRedBlackTreePayload<K, T>(key, value));
    00581     return (payload != 0) ? &payload->GetValue() :  0;
    00582   }
    00588   bool Delete (const K& key)
    00589   {
    00590     csRedBlackTreePayload<K, T>* payload = Find (key);
    00591     if (payload == 0) return false;
    00592     return supahclass::Delete (*payload);
    00593   }
    00595
    00599   const T* GetElementPointer (const K& key) const
    00600   {
    00601     csRedBlackTreePayload<K, T>* payload = Find (key);
    00602     if (payload == 0) return 0;
    00603     return &payload->GetValue();
    00604   }
    00605   T* GetElementPointer (const K& key)
    00606   {
    00607     csRedBlackTreePayload<K, T>* payload = Find (key);
    00608     if (payload == 0) return 0;
    00609     return &payload->GetValue();
    00610   }
    00612
    00614
    00617   const T& Get (const K& key, const T& fallback) const
    00618   {
    00619     csRedBlackTreePayload<K, T>* payload = Find (key);
    00620     if (payload == 0) return fallback;
    00621     return payload->GetValue();
    00622   }
    00623   T& Get (const K& key, T& fallback)
    00624   {
    00625     csRedBlackTreePayload<K, T>* payload = Find (key);
    00626     if (payload == 0) return fallback;
    00627     return payload->GetValue();
    00628   }
    00630
    00631   void DeleteAll() { supahclass::Empty(); }
    00633   void Empty() { DeleteAll(); }
    00635   bool IsEmpty() const { return supahclass::IsEmpty(); }
    00636
    00638
    00639   template <typename CB>
    00640   void TraverseInOrder (CB& callback) const
    00641   {
    00642     TraverseCB<CB> traverser (callback);
    00643     supahclass::TraverseInOrder (traverser);
    00644   }
    00646 };
    00647
    00650 #if defined(CS_EXTENSIVE_MEMDEBUG) || defined(CS_MEMORY_TRACKER)
    00651 # define new CS_EXTENSIVE_MEMDEBUG_NEW
    00652 #endif
    00653
    00654 #endif // __CS_UTIL_REDBLACKTREE_H__