Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

src/DomainMap/DomainMap.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  *
00007  * Visit http://people.web.psi.ch/adelmann/ for more details
00008  *
00009  ***************************************************************************/
00010 
00011 #ifndef DOMAIN_MAP_H
00012 #define DOMAIN_MAP_H
00013 
00014 /***********************************************************************
00015 
00016 Steve Karmesin
00017 Dakota Scientific Software
00018 February 1996
00019 
00020 A DomainMap holds a bunch of Domains of type Key in such a way that you
00021 can quickly look up which Keys's touch a given one and an object 
00022 associated with that Key.
00023 
00024 Key must have the following operations defined:
00025 
00026 bool touches(const Key&, const Key&);
00027 Return true if the Keys touch, false if they don't.
00028 
00029 bool contains(const Key& l, const Key& r);
00030 Return true if l contains r, false otherwise.
00031 
00032 bool split(pair<const Key,const Key>&, const Key& k);
00033 Split one Key into two, and return a boolean for success.
00034 
00035 split and containes need to have the following properties for 
00036 consistent behavior:
00037 
00038 1. If Key A is split into A1 and A2, then 
00039    contains(A,A1)==true and contains(A,A2)==true.
00040 
00041 2. If Key A is split into A1 and A2, then there is no Key B 
00042    for which contains(A1,B) and contains(A2,B) are both true.
00043 
00044 3. If contains(A,B)==true and contains(B,C)==true then we must have
00045    contains(A,C)==true.
00046 
00047 Each Key is associated with a T. We enter those Ts into the
00048 DomainMap and later pull out the ones that touch a given Key.
00049 
00050 touches(const Key&) must do two things:
00051 1) It must be fast.
00052 2) It must be right.
00053 
00054 "Fast" means that it has to be at worst linear in the number of hits,
00055 times a log of the total number of elements in the Map.
00056 
00057 "Right" means that it has to find all of the elements that touch the
00058 given Key exactly once.
00059 
00060 This currently has very small subset of the capabilites of an STL map..
00061 It should gradually get expanded to include as many as make sense. 
00062 
00063 ***********************************************************************/
00064 
00065 // include files
00066 #include "Utility/Pooled.h"
00067 #include "Utility/PAssert.h"
00068 
00069 #ifdef IPPL_STDSTL
00070 
00071 #include <list>
00072 using std::list;
00073 #include <iterator>
00074 #ifndef __MWERKS__
00075                                 // using std::forward_iterator;
00076 #endif
00077 // Standard STL defines pair in Utility header
00078 #include <utility>
00079 using std::pair;
00080 
00081 #else
00082 
00083 #include <list.h>
00084 #include <iterator.h>
00085 #include <pair.h>
00086 
00087 #endif // IPPL_STDSTL
00088 
00089 #include <stddef.h>
00090 
00091 template < class Key, class T , class Touches, class Contains, class Split > 
00092 class DomainMap 
00093 {
00094 public:
00095     typedef DomainMap<Key,T,Touches,Contains,Split> DomainMap_t;
00096     typedef unsigned size_type;
00097     
00098     typedef Key key_type;
00099     typedef T   mapped_type;
00100     
00101     struct value_type {
00102         Key first;
00103         T   second;
00104         value_type() {}
00105         value_type(const Key& k, const T& t)
00106                 : first(k), 
00107                   second(t){
00108         }
00109     };
00110     
00111 
00112 private:
00113     // A class for the nodes of the tree.
00114     // Subclass from Pooled so that new and delete are fast.
00115     // Not visible from outside of DomainMap
00116     class Node : public Pooled<Node>
00117     {
00118     public: 
00119         typedef list<value_type> cont_type; // The type for the container
00120         Key MyDomain;                     // This Node's Domain.
00121         Node *Left,*Right;                // Make this a binary tree.
00122         Node *Parent;                     // Have this around for traversals.
00123         cont_type cont;                   // The values in this Node.
00124         
00125         // Construct with the domain and the parent.
00126         Node(const Key& d, Node* p=0) : MyDomain(d),Left(0),Right(0),Parent(p) {}
00127         // When you die take you children with you.
00128         ~Node() {
00129             if (Left ) delete Left;
00130             if (Right) delete Right;
00131         }
00132 
00133         // Insert a pair<Key,T> into the tree.
00134         // tjw: added noSplit flag 3/24/1998
00135         //mwerks      void insert(const value_type& d, bool noSplit=false);
00137         // Insert a T into the tree.
00138         // This isn't nearly as bad as it looks. It is just careful
00139         // to not build any nodes it doesn't have to, and to minimize
00140         // the number of times it calls split.  There is some duplicated
00141         // code here to keep the threading through the if statements smooth.
00142         void  insert(const value_type& d, bool noSplit=false) {
00143             TAU_TYPE_STRING(taustr, CT(*this) + " void (value_type)"); 
00144             TAU_PROFILE("DomainMap::Node::insert()", taustr, TAU_DOMAINMAP);
00145                 
00146             Key left_domain;            // When splitting a node, we'll need a spot
00147             Key right_domain;           // to store the left and right domains.
00148                 
00149             // ----------------------------------------------------------------------
00150             // tjw:
00151             // First, make sure that the domain isn't of total extent 1, which will
00152             // cause an assertion failure in split() functions like Index::split() in
00153             // the code below. For this special case, just insert straightaway. Use
00154             // the newly-added flag noSplit to request this; noSplit defaults to
00155             // false, so no existing code should break:
00156                 
00157             if (noSplit) {
00158                 cont.push_back(d);
00159                 return;
00160             }
00161                 
00162             // tjw.
00163             //-----------------------------------------------------------------------
00164                 
00165             if ( Left && Right ) {      
00166                 // If they both exist already the algorithm is simple.
00167                 if ( Contains::test(Left->MyDomain,d.first) )
00168                     Left->insert(d);
00169                 else if ( Contains::test(Right->MyDomain,d.first) )
00170                     Right->insert(d);
00171                 else
00172                     cont.push_back(d);
00173                     
00174             }
00175             else if ( Left==0 && Right==0 ) {
00176                 // If neither exist, split and check.
00177                 if ( Split::test(left_domain, right_domain, MyDomain) ) {
00178                     if ( Contains::test(left_domain, d.first) ) {
00179                         // It is on the left. Build it and go.
00180                         Left = new Node( left_domain, this );
00181                         Left->insert(d);
00182                     }
00183                     else if ( Contains::test(right_domain, d.first) ) {
00184                         // It is on the right. Build it and go.
00185                         Right = new Node( right_domain, this );
00186                         Right->insert(d);
00187                     }
00188                     else {
00189                         // It is not in either. Put it here.
00190                         cont.push_back(d);
00191                     }
00192                 }
00193                 else {
00194                     // Couldn't split. Put it here.
00195                     cont.push_back(d);
00196                 }
00197                     
00198             }
00199             else if ( Right ) {
00200                 // Only the one on the right exists already. Check it first.
00201                 if ( Contains::test(Right->MyDomain, d.first) ) {
00202                     // It is there, go down.
00203                     Right->insert(d);
00204                 }
00205                 else {
00206                     // Not on the right. Check the left.
00207                     Split::test(left_domain, right_domain, MyDomain);
00208                     if ( Contains::test(left_domain,d.first) ) {
00209                         // It is there. Build the left and drop into it.
00210                         Left = new Node( left_domain, this );
00211                         Left->insert(d);
00212                     }
00213                     else {
00214                         // Not there either. Keep it here.
00215                         cont.push_back(d);
00216                     }
00217                 }
00218                     
00219             }
00220             else if ( Left ) {
00221                 // Only the one on the left exists already. Check it first.
00222                 if ( Contains::test(Left->MyDomain, d.first) ) {
00223                     // It is there. Drop into it.
00224                     Left->insert(d);
00225                 }
00226                 else {
00227                     // It isn't on the left. Split to see if it is on the right.
00228                     Split::test(left_domain,right_domain,MyDomain);
00229                     if ( Contains::test(right_domain,d.first) ) {
00230                         // It is there. Build it and drop into it.
00231                         Right = new Node( right_domain, this );
00232                         Right->insert(d);
00233                     }
00234                     else {
00235                         // Not on the right either.  Keep it here.
00236                         cont.push_back(d);
00237                     }
00238                 }
00239             }
00240         }
00241         
00242     };
00243     
00244     friend class Node;
00245     
00246 public: 
00247     
00248     // forward declaration of const_iterator
00249     class const_iterator;
00250 
00251     // Forward iterator.
00252     // It could be bidirectional but I'm to lazy to add operator--().
00253     class iterator {
00254         friend class DomainMap<Key,T,Touches,Contains,Split>;
00255         friend class const_iterator;
00256 
00257     public:
00258 
00259         // Null ctor initializes p to zero so we can tell it is null.
00260         iterator() : p(0) { }
00261 
00262         // Create one with the two pointers it needs.
00263         iterator(Node *pp, typename Node::cont_type::iterator vv)
00264                 : p(pp), v(vv)
00265             {
00266             }
00267 
00268         // equality just tests each element.
00269         bool operator==(const iterator& rhs) const
00270             {
00271                 return (p==rhs.p)&&((p==0)||(v==rhs.v));
00272             }
00273         bool operator!=(const iterator& rhs) const
00274             {
00275                 return !(*this == rhs);
00276             }
00277 
00278         // Get the current one.
00279         value_type& operator*()
00280             {
00281                 PAssert(p != 0);
00282                 return *v;
00283             }
00284 
00285         // Increment the iterator.
00286         iterator& operator++() { op_pp(); return *this; }
00287 
00288         //mwerks private:
00289         //mwerks    void op_pp();
00291         // Increment an iterator.
00292         void op_pp()
00293             {
00294                 TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00295                 TAU_PROFILE("DomainMap::iterator::op_pp()", taustr, TAU_DOMAINMAP);
00296 
00297                 PAssert(p != 0);
00298                 // First try to increment inside this node.
00299                 if ( (++v) == p->cont.end() ) {
00300                     // If that one is at its end, go to the next node.
00301                     do {
00302                         // First look right.
00303                         if ( p->Right ) {
00304                             // If it is there, go there and then all the way left.
00305                             p = p->Right;
00306                             while ( p->Left )
00307                                 p = p->Left;
00308                         }
00309                         else {
00310                             // If there is no right, go up until you can go right.
00311                             Node *y = p->Parent; // DomainMap<Key,T,Touches,Contains,Split>::Node *y;
00312                             while (y && (p==y->Right)) {
00313                                 p = y;
00314                                 y = y->Parent;
00315                             }
00316                             p = y;
00317                         }
00318                         // If the node found has nothing in it, keep looking.
00319                     } while (p && ((v=p->cont.begin())==p->cont.end()));
00320                 }
00321             }
00322         Node *p;                                      // Which Node are we in.
00323         typename Node::cont_type::iterator v;     // Within that node where are we.
00324     };
00325 
00326     // const_iterator: like iterator, but does return by value
00327     class const_iterator {
00328         friend class DomainMap<Key,T,Touches,Contains,Split>;
00329 
00330     public:
00331         // Null ctor initializes p to zero so we can tell it is null.
00332         const_iterator() : p(0) {}
00333 
00334         // Create one with the two pointers it needs.
00335         const_iterator(Node *pp, typename Node::cont_type::iterator vv)
00336                 : p(pp), v(vv) {}
00337 
00338         // Create a const_iterator from an iterator
00339         const_iterator(const iterator& iter) : p(iter.p), v(iter.v) {}
00340 
00341         // equality just tests each element.
00342         bool operator==(const const_iterator& rhs) const
00343             {
00344                 return (p==rhs.p)&&((p==0)||(v==rhs.v));
00345             }
00346         bool operator!=(const const_iterator& rhs) const
00347             {
00348                 return !(*this == rhs);
00349             }
00350 
00351         // Get the current one.
00352         value_type operator*() const
00353             {
00354                 PAssert(p != 0);
00355                 return *v;
00356             }
00357 
00358         // Increment the iterator.
00359         const_iterator& operator++() { op_pp(); return *this; }
00360 
00361     private:
00362         //mwerks    void op_pp();
00364         // Increment a const_iterator.
00365         void op_pp()
00366             {
00367                 TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00368                 TAU_PROFILE("DomainMap::const_iterator::op_pp()", taustr, TAU_DOMAINMAP);
00369 
00370                 PAssert(p != 0);
00371                 // First try to increment inside this node.
00372                 if ( (++v) == p->cont.end() ) {
00373                     // If that one is at its end, go to the next node.
00374                     do {
00375                         // First look right.
00376                         if ( p->Right ) {
00377                             // If it is there, go there and then all the way left.
00378                             p = p->Right;
00379                             while ( p->Left )
00380                                 p = p->Left;
00381                         }
00382                         else {
00383                             // If there is no right, go up until you can go right.
00384                             // DomainMap<Key,T,Touches,Contains,Split>::Node *y = p->Parent;
00385                             Node *y = p->Parent;
00386                             while (y && (p==y->Right)) {
00387                                 p = y;
00388                                 y = y->Parent;
00389                             }
00390                             p = y;
00391                         }
00392                         // If the node found has nothing in it, keep looking.
00393                     } while (p && ((v=p->cont.begin())==p->cont.end()));
00394                 }
00395             }
00396         Node *p;                                     // Which Node are we in.
00397         typename Node::cont_type::iterator v;    // Within that node where are we.
00398     };
00399 
00400     // Touch iterator.
00401     // Given a Key find all those that touch it.
00402     class touch_iterator {
00403         friend class DomainMap<Key,T,Touches,Contains,Split>;
00404     public: 
00405 
00406         typedef forward_iterator_tag    iterator_category;
00407         typedef typename DomainMap_t::value_type value_type;
00408         typedef typename DomainMap_t::value_type *pointer;
00409         typedef typename DomainMap_t::value_type &reference;
00410         typedef ptrdiff_t               difference_type;
00411 
00412         // Null ctor initializes p to zero so we can tell it is null.
00413         touch_iterator() : p(0) { }
00414 
00415         // equality just tests each element.
00416         bool operator==(const touch_iterator& rhs) const
00417             {
00418                 return (p==rhs.p)&&((p==0)||(v==rhs.v));
00419             }
00420         bool operator!=(const touch_iterator& rhs) const
00421             {
00422                 return !(*this == rhs);
00423             }
00424 
00425         // Get the current one.
00426         value_type& operator*()
00427             {
00428                 PAssert(p != 0);
00429                 return *v;
00430             }
00431 
00432         value_type* operator->()
00433             {
00434                 PAssert(p != 0);
00435                 return &(*v);
00436             }
00437 
00438         // Convert to a regular iterator.
00439         operator iterator()
00440             {
00441                 return iterator(p,v);
00442             }
00443 
00444         // Increment the iterator.
00445         touch_iterator& operator++() { op_pp(); return *this; }
00446 
00447     private:
00448         //mwerks    void op_pp();
00450         // Increment a touch iterator.
00451         void op_pp()
00452             {
00453                 TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00454                 TAU_PROFILE("DomainMap::iterator::op_pp()", taustr, TAU_DOMAINMAP);
00455 
00456                 PAssert(p != 0);
00457 
00458                 // Try to find one inside this node.
00459                 while ( (++v) != p->cont.end() )
00460                     if ( Touches::test(TouchThis,(*v).first) )
00461                         return;                 // Found one!  Return it.
00462   
00463                 do {
00464                     // Not here. Look through the tree.
00465                     // First look right.
00466                      // DomainMap<Key,T,Touches,Contains,Split>::Node *y = p->Right;
00467                     Node *y = p->Right;
00468                     if ( y && Touches::test(TouchThis,y->MyDomain) ) {
00469                         // If it is there and we touch it, go there and then left.
00470                         p = y;
00471                         for (y=y->Left; y && Touches::test(TouchThis,y->MyDomain); y=y->Left )
00472                             p = y;
00473                     }
00474                     else {
00475                         // If there is no right, go up until you can go right.
00476                         // No need to test for touching on the way up because we
00477                         // would not be here if the parent didn't touch.
00478                         for (y=p->Parent; y && (p==y->Right); y=y->Parent) 
00479                             p = y;
00480                         p = y;
00481                     }
00482                     // Point to the beginning of the T's in this node.
00483                     if (p) {
00484                         for ( v = p->cont.begin() ; v != p->cont.end() ; ++v )
00485                             if ( Touches::test(TouchThis,(*v).first) )
00486                                 return;         // Found one!  Return it.
00487                     }
00488 
00489                 } while (p);
00490 
00491             }
00492         Node *p;                                      // Which Node are we in.
00493         typename Node::cont_type::iterator v;     // Within that node where are we.
00494         Key TouchThis;                        // The Key that is being touched.
00495     };
00496 
00497     // Create an DomainMap with a Key that has the bounding box
00498     // of the whole domain. It should be true that all of the Keys
00499     // inserted into the DomainMap are contained in the 
00500     // original Key.  This bounding box is enough to determine 
00501     // how the recursive bisection proceeds.
00502     DomainMap(const Key& d)
00503             : Root(new Node(d)), Size(0)
00504         {
00505         }
00506 
00507     DomainMap()
00508             : Root(0), Size(0)
00509         {
00510         }
00511 
00512     // Copy ctor and assign do deep copies.
00513     DomainMap( const DomainMap<Key,T,Touches,Contains,Split>& );
00514     void operator=(const DomainMap<Key,T,Touches,Contains,Split>& );
00515 
00516     // When you die take the tree with you.
00517     ~DomainMap() { delete Root; }
00518 
00519     // Iterators to count over all the elements.
00520     iterator begin()       { return Leftmost; }
00521     iterator end()         { return iterator(); }
00522     const_iterator begin() const { return const_iterator(Leftmost); }
00523     const_iterator end()   const { return const_iterator(); }
00524 
00525     // Add a pair<Key,T> to it.
00526     // tjw: added noSplit flag 3/24/1998
00527     void insert(const value_type& d, bool noSplit=false);
00528 
00529     // Find the range that touches a given T.
00530     pair<touch_iterator,touch_iterator> touch_range(const Key& t) const;
00531 
00532     // return how many we have.
00533     size_type size() const { return Size; }
00534 
00535 private: 
00536 
00537     friend class iterator;
00538     friend class const_iterator;
00539     friend class touch_iterator;
00540 
00541     Touches touches;
00542     Contains contains;
00543     Split split;
00544 
00545     Node* Root;
00546     iterator Leftmost;
00547     unsigned Size;
00548 
00549     // Add a pair<Key,T> to it without updating leftmost.
00550     void insert_noupdate(const value_type& d)
00551         {
00552             Root->insert(d);
00553             Size += 1;
00554         }
00555     // Reset the pointer to the first one.
00556     void update_leftmost();
00557 };
00558 
00560 
00561 #include "DomainMap/DomainMap.cpp"
00562 
00563 #endif // DOMAIN_MAP_H
00564 
00565 /***************************************************************************
00566  * $RCSfile: DomainMap.h,v $   $Author: adelmann $
00567  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:25 $
00568  * IPPL_VERSION_ID: $Id: DomainMap.h,v 1.1.1.1 2003/01/23 07:40:25 adelmann Exp $ 
00569  ***************************************************************************/

Generated on Fri Nov 2 01:25:55 2007 for IPPL by doxygen 1.3.5