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

| ## Public API Reference

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

- File List
- File Members

# csutil/partialorder.h

Go to the documentation of this file.

    00001 /* -*- Mode: C++; c-basic-offset: 2 -*-
    00002    Copyright (C) 2005 by Adam D. Bradley <artdodge@cs.bu.edu>
    00003
    00004    This library is free software; you can redistribute it and/or
    00005    modify it under the terms of the GNU Lesser General Public
    00006    License as published by the Free Software Foundation; either
    00007    version 2 of the License, or (at your option) any later version.
    00008
    00009    This library is distributed in the hope that it will be useful,
    00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00012    Library General Public License for more details.
    00013
    00014    You should have received a copy of the GNU Library General Public
    00015    License along with this library; if not, write to the Free
    00016    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    00017 */
    00018
    00019 #ifndef __CS_UTIL_PO_H__
    00020 #define __CS_UTIL_PO_H__
    00021
    00026 #include "csextern.h"
    00027 #include "csutil/array.h"
    00028 #include "csutil/comparator.h"
    00029 #include "csutil/hash.h"
    00030 #include "csutil/list.h"
    00031 #include "csutil/ref.h"
    00032 #include "csutil/util.h"
    00033
    00034 #ifdef ADB_DEBUG
    00035 #include "csutil/eventhandlers.h"
    00036 #include <iostream>
    00037 #endif /* ADB_DEBUG */
    00038
    00051 template <class T>
    00052 class CS_CRYSTALSPACE_EXPORT csPartialOrder
    00053 {
    00054 protected:
    00055   class Node
    00056   {
    00057   public:
    00058     Node(const Node &other)
    00059       : self(other.self), output(other.output),
    00060         marked(other.marked),
    00061         pre(other.pre), post(other.post)
    00062     { }
    00063     Node(const T &id)
    00064       : self(id), output(false), marked(false),
    00065         pre(), post()
    00066     { }
    00067     const T self;
    00068     bool output;
    00069     bool marked;
    00070     csArray<size_t> pre;
    00071     csArray<size_t> post;
    00072   };
    00073   csArray<Node> Nodes;
    00074   csHash<size_t,const T> NodeMap;
    00075
    00076 public:
    00078   csPartialOrder ()
    00079     : Nodes (), NodeMap()
    00080   {
    00081     return;
    00082   }
    00083
    00085   csPartialOrder(const csPartialOrder &other)
    00086     : Nodes (other.Nodes), NodeMap (other.NodeMap)
    00087   {
    00088     return;
    00089   }
    00090
    00091 #ifdef ADB_DEBUG
    00092   // This code is particular to the csHandlerID scheduler.
    00093   void Dump (iObjectRegistry *objreg)
    00094   {
    00095     std::cerr << "Dumping PO Graph..." << std::endl;
    00096     for (size_t i=0 ; i<Nodes.Length() ; i++)
    00097     {
    00098       std::cerr << "  NODE: " << csEventHandlerRegistry::GetRegistry(objreg)->GetString(Nodes[i].self) << std::endl;
    00099       std::cerr << "    pre: ";
    00100       for (size_t j=0 ; j<Nodes[i].pre.Length() ; j++)
    00101       {
    00102         std::cerr << csEventHandlerRegistry::GetRegistry(objreg)->GetString(Nodes[Nodes[i].pre[j]].self) << " ";
    00103       }
    00104       std::cerr << std::endl << "    post: ";
    00105       for (size_t j=0 ; j<Nodes[i].post.Length() ; j++)
    00106       {
    00107         std::cerr << csEventHandlerRegistry::GetRegistry(objreg)->GetString(Nodes[Nodes[i].post[j]].self) << " ";
    00108       }
    00109       std::cerr << std::endl;
    00110     }
    00111     std::cerr << "End PO Graph, printing a solution..." << std::endl;
    00112     csList<const T> Solution;
    00113     Solve (Solution);
    00114     while (!Solution.IsEmpty ())
    00115     {
    00116       std::cerr << csEventHandlerRegistry::GetRegistry(objreg)->GetString(Solution.Front()) << " ";
    00117       Solution.PopFront();
    00118     }
    00119     std::cerr << std::endl << "Done." << std::endl << std::endl;
    00120   }
    00121 #endif /* ADB_DEBUG */
    00122
    00124   csPartialOrder(const csPartialOrder *other)
    00125     : Nodes (other->Nodes), NodeMap (other->NodeMap)
    00126   {
    00127     return;
    00128   }
    00129
    00131   void Add (const T& node)
    00132   {
    00133     SanityCheck();
    00134     if (NodeMap.Get(node, csArrayItemNotFound) == csArrayItemNotFound)
    00135     {
    00136       NodeMap.PutUnique(node, Nodes.Push(node));
    00137     }
    00138     SanityCheck();
    00139   }
    00140
    00142   bool Contains (const T& node)
    00143   {
    00144     return (NodeMap.Get(node, csArrayItemNotFound) != csArrayItemNotFound);
    00145   }
    00146
    00148   bool Contains (const T& pre, const T& post)
    00149   {
    00150     if (!Contains (pre) || !Contains (post))
    00151       return false;
    00152     size_t PreIdx = NodeMap.Get (pre, csArrayItemNotFound);
    00153     size_t PostIdx = NodeMap.Get (post, csArrayItemNotFound);
    00154     for (size_t i=0 ; i<Nodes[PreIdx].post.Length() ; i++)
    00155     {
    00156       if (Nodes[PreIdx].post[i] == PostIdx)
    00157       {
    00158         return true;
    00159       }
    00160     }
    00161     return false;
    00162   }
    00163
    00165   void Delete (const T& node)
    00166   {
    00167     SanityCheck();
    00168     size_t p = NodeMap.Get(node, csArrayItemNotFound);
    00169     CS_ASSERT(p!=csArrayItemNotFound);
    00170     CS_ASSERT(p < Nodes.Length());
    00171     // delete all posts pointing to node
    00172     for (size_t iter=0 ; iter<Nodes[p].pre.Length() ; iter++)
    00173     {
    00174       Nodes[Nodes[p].pre[iter]].post.Delete(p);
    00175     }
    00176     // delete node's pre's
    00177     Nodes[p].pre.DeleteAll();
    00178     // delete all pres pointing to node
    00179     for (size_t iter=0 ; iter<Nodes[p].post.Length() ; iter++)
    00180     {
    00181       Nodes[Nodes[p].post[iter]].pre.Delete(p);
    00182     }
    00183     // delete node's post's
    00184     Nodes[p].post.DeleteAll();
    00185     // delete node p, move the node at the end of the csArray into its place...
    00186     Nodes.DeleteIndexFast(p);
    00187
    00188     // update NodeMap accordingly by killing the lookup for the deleted node
    00189     // and updating the lookup for the node that moved into its place...
    00190     NodeMap.Delete(node, p);
    00191     if (Nodes.Length() > p)
    00192     {
    00193       // who got moved into "p"?
    00194       size_t moved = NodeMap.Get(Nodes[p].self, csArrayItemNotFound);
    00195       CS_ASSERT (moved != csArrayItemNotFound);
    00196
    00197       // change references to "moved" to reference "p"
    00198       for (size_t iter=0 ; iter<Nodes.Length() ; iter++)
    00199       {
    00200         for (size_t iter2=0 ; iter2<Nodes[iter].pre.Length() ; iter2++)
    00201         {
    00202           if (Nodes[iter].pre[iter2] == moved)
    00203             Nodes[iter].pre[iter2] = p;
    00204         }
    00205         for (size_t iter2=0 ; iter2<Nodes[iter].post.Length() ; iter2++)
    00206         {
    00207           if (Nodes[iter].post[iter2] == moved)
    00208             Nodes[iter].post[iter2] = p;
    00209         }
    00210       }
    00211       NodeMap.Delete(Nodes[p].self, moved);
    00212       NodeMap.PutUnique(Nodes[p].self, p);
    00213     }
    00214
    00215     SanityCheck();
    00216   }
    00217
    00224   bool AddOrder (const T& node1, const T& node2)
    00225   {
    00226     SanityCheck();
    00227     size_t n1 = NodeMap.Get(node1, csArrayItemNotFound);
    00228     size_t n2 = NodeMap.Get(node2, csArrayItemNotFound);
    00229     CS_ASSERT(n1 != csArrayItemNotFound);
    00230     CS_ASSERT(n2 != csArrayItemNotFound);
    00231
    00232     /* make the forward link "n1->n2" */
    00233     Nodes[n1].post.Push(n2);
    00234
    00235     if (InternalCycleTest(n1))
    00236     {
    00237       /* undo our mischief and report failure */
    00238       Nodes[n1].post.Pop();
    00239       return false;
    00240     }
    00241     else
    00242     {
    00243       /* make the paired pre link "n2<-n1" */
    00244       Nodes[n2].pre.Push(n1);
    00245       return true;
    00246     }
    00247     SanityCheck();
    00248   }
    00249
    00251   void DeleteOrder (const T& node1, const T& node2)
    00252   {
    00253     SanityCheck();
    00254     size_t n1 = NodeMap.Get(node1, csArrayItemNotFound);
    00255     size_t n2 = NodeMap.Get(node2, csArrayItemNotFound);
    00256     CS_ASSERT(n1 != csArrayItemNotFound);
    00257     CS_ASSERT(n2 != csArrayItemNotFound);
    00258     Nodes[n2].pre.DeleteFast(n1);
    00259     Nodes[n1].post.DeleteFast(n2);
    00260     SanityCheck();
    00261   }
    00262
    00264   size_t Size ()
    00265   {
    00266     return Nodes.Length();
    00267   }
    00268
    00270   const T GetByIndex(size_t i)
    00271   {
    00272     return Nodes[i].self;
    00273   }
    00274
    00279   void Solve (csList<const T> & result)
    00280   {
    00281     SanityCheck();
    00282     for (size_t iter=0 ; iter<Nodes.Length() ; iter++)
    00283     {
    00284       Nodes[iter].output = false;
    00285     }
    00286     result.DeleteAll();
    00287     bool done;
    00288     do
    00289     {
    00290       done = true;
    00291       for (size_t iter=0 ; iter<Nodes.Length() ; iter++)
    00292       {
    00293         if (Nodes[iter].output == false)
    00294         {
    00295           int canoutput = true;
    00296           for (size_t i2=0 ; i2<Nodes[iter].pre.Length() ; i2++)
    00297           {
    00298             if (!Nodes[Nodes[iter].pre[i2]].output)
    00299             {
    00300               canoutput = false;
    00301               break;
    00302             }
    00303           }
    00304           if (canoutput)
    00305           {
    00306             result.PushBack(Nodes[iter].self);
    00307             Nodes[iter].output = true;
    00308           }
    00309           else
    00310           {
    00311             done = false;
    00312           }
    00313         }
    00314       }
    00315     }
    00316     while (!done);
    00317     SanityCheck();
    00318   }
    00319
    00324   void Mark (const T& node)
    00325   {
    00326     size_t i = NodeMap.Get(node, csArrayItemNotFound);
    00327     CS_ASSERT(i != csArrayItemNotFound);
    00328     CS_ASSERT(i < Nodes.Length());
    00329     Nodes[i].marked = true;
    00330   }
    00331
    00335   bool IsMarked (const T& node)
    00336   {
    00337     size_t i = NodeMap.Get(node, csArrayItemNotFound);
    00338     CS_ASSERT(i != csArrayItemNotFound);
    00339     CS_ASSERT(i < Nodes.Length());
    00340     return Nodes[i].marked;
    00341   }
    00342
    00346   void ClearMark (const T& node)
    00347   {
    00348     size_t i = NodeMap.Get(node, csArrayItemNotFound);
    00349     CS_ASSERT(i != csArrayItemNotFound);
    00350     CS_ASSERT(i < Nodes.Length());
    00351     Nodes[i].marked = false;
    00352   }
    00353
    00357   void ClearMark ()
    00358   {
    00359     for (size_t i=0 ; i<Nodes.Length() ; i++)
    00360     {
    00361       Nodes[i].marked = false;
    00362     }
    00363   }
    00364
    00369   bool IsEnabled(const T& node)
    00370   {
    00371     size_t i = NodeMap.Get(node, csArrayItemNotFound);
    00372     CS_ASSERT(i != csArrayItemNotFound);
    00373     return InternalIsEnabled(i);
    00374   }
    00375
    00379   bool HasEnabled()
    00380   {
    00381     for (size_t i=0 ; i<Nodes.Length() ; i++)
    00382     {
    00383       if (InternalIsEnabled(i))
    00384         return true;
    00385     }
    00386     return false;
    00387   }
    00388
    00392   const T GetEnabled(T fail)
    00393   {
    00394     for (size_t i=0 ; i<Nodes.Length() ; i++)
    00395     {
    00396       if (InternalIsEnabled(i))
    00397         return Nodes[i].self;
    00398     }
    00399     return fail;
    00400   }
    00401
    00402 protected:
    00403   void SanityCheck ()
    00404   {
    00405 #ifdef CS_DEBUG
    00406     CS_ASSERT_MSG ("NodeMap has different size from Node list",
    00407                    NodeMap.GetSize() == Nodes.Length());
    00408     for (size_t i1=0; i1<Nodes.Length() ; i1++)
    00409     {
    00410       CS_ASSERT_MSG ("NodeMap names wrong location for node",
    00411                      NodeMap.Get(Nodes[i1].self, csArrayItemNotFound) == i1);
    00412       for (size_t i2=0 ; i2<Nodes[i1].pre.Length() ; i2++)
    00413       {
    00414         CS_ASSERT_MSG ("Node prefix index less than zero",
    00415                        Nodes[i1].pre[i2] >= 0);
    00416         CS_ASSERT_MSG ("Node prefix index larger than Nodes list",
    00417                        Nodes[i1].pre[i2] < Nodes.Length());
    00418         bool reciprocal_post_exists = false;
    00419         for (size_t i3=0 ; i3<Nodes[Nodes[i1].pre[i2]].post.Length() ; i3++)
    00420         {
    00421           if (Nodes[Nodes[i1].pre[i2]].post[i3] == i1)
    00422           {
    00423             reciprocal_post_exists = true;
    00424             break;
    00425           }
    00426         }
    00427         CS_ASSERT_MSG ("Node prefix does not have reciprocal postfix",
    00428                        reciprocal_post_exists);
    00429       }
    00430       for (size_t i2=0 ; i2<Nodes[i1].post.Length() ; i2++)
    00431       {
    00432         CS_ASSERT_MSG ("Node postfix index less than zero",
    00433                        Nodes[i1].post[i2] >= 0);
    00434         CS_ASSERT_MSG ("Node postfix index larger than Nodes list",
    00435                        Nodes[i1].post[i2] < Nodes.Length());
    00436         bool reciprocal_pre_exists = false;
    00437         for (size_t i3=0 ; i3<Nodes[Nodes[i1].post[i2]].pre.Length() ; i3++)
    00438         {
    00439           if (Nodes[Nodes[i1].post[i2]].pre[i3] == i1)
    00440           {
    00441             reciprocal_pre_exists = true;
    00442             break;
    00443           }
    00444         }
    00445         CS_ASSERT_MSG ("Node postfix does not have reciprocal prefix",
    00446                        reciprocal_pre_exists);
    00447       }
    00448     }
    00449     typename csHash<size_t,const T>::GlobalIterator iter =
    00450       NodeMap.GetIterator ();
    00451     while (iter.HasNext())
    00452     {
    00453       size_t idx = iter.Next();
    00454       CS_ASSERT_MSG ("NodeMap contains an index larger than Nodes list",
    00455                      idx < Nodes.Length());
    00456     }
    00457 #endif /* CS_DEBUG */
    00458   }
    00459
    00460   bool CycleTest(const T& node)
    00461   {
    00462     size_t n = NodeMap.Get(node, csArrayItemNotFound);
    00463     CS_ASSERT(n != csArrayItemNotFound);
    00464     return InternalCycleTest(n);
    00465   }
    00466
    00467   bool InternalIsEnabled(size_t i)
    00468   {
    00469     if (Nodes[i].marked)
    00470       return false;
    00471     for (size_t j=0 ; j<Nodes[i].pre.Length() ; j++)
    00472     {
    00473       if (!Nodes[Nodes[i].pre[j]].marked)
    00474         return false;
    00475     }
    00476     return true;
    00477   }
    00478
    00479   bool InternalCycleTest(size_t n1, size_t n2)
    00480   {
    00481     // n1 is the inserted node, see if n2 hits n1 again...
    00482     if (n1==n2)
    00483       return true;
    00484     for (size_t i=0 ; i<Nodes[n2].post.Length() ; i++)
    00485     {
    00486       if (InternalCycleTest(n1, Nodes[n2].post[i]))
    00487         return true;
    00488     }
    00489     return false;
    00490   }
    00491   bool InternalCycleTest(size_t n)
    00492   {
    00493     for (size_t i=0 ; i<Nodes[n].post.Length() ; i++)
    00494     {
    00495       if (InternalCycleTest(n, Nodes[n].post[i]))
    00496         return true;
    00497     }
    00498     return false;
    00499   }
    00500 };
    00501
    00502 #endif // __CS_UTIL_PO_H__