cdmap.h

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file cdmap.h
00004  * 
00005  * Author: Sergey Berezin
00006  * 
00007  * Created: Thu May 15 15:55:09 2003
00008  *
00009  * <hr>
00010  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00011  * Junior University and by New York University. 
00012  *
00013  * License to use, copy, modify, sell and/or distribute this software
00014  * and its documentation for any purpose is hereby granted without
00015  * royalty, subject to the terms and conditions defined in the \ref
00016  * LICENSE file provided with this distribution.  In particular:
00017  *
00018  * - The above copyright notice and this permission notice must appear
00019  * in all copies of the software and related documentation.
00020  *
00021  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00022  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00023  * 
00024  * <hr>
00025  * 
00026  */
00027 /*****************************************************************************/
00028 
00029 #ifndef _cvcl__include__cdmap_h_
00030 #define _cvcl__include__cdmap_h_
00031 
00032 #include <iterator>
00033 #include "context.h"
00034 
00035 namespace CVCL {
00036 
00037 ///////////////////////////////////////////////////////////////////////////////
00038 //                                                                           //
00039 // Class: CDMap (Context Dependent Map)                                      //
00040 // Author: Sergey Berezin                                                    //
00041 // Created: Thu May 15 15:55:09 2003                                         //
00042 // Description: Generic templated class for a map which must be saved        //
00043 //              and restored as contexts are pushed and popped.  Requires    //
00044 //              that operator= be defined for the data class, and            //
00045 //              operator== for the key class.   In addition, a hash<Key>     //
00046 //              template specialization must be defined, or a hash class     //
00047 //              explicitly provided in the template.                         //
00048 //                                                                           //
00049 ///////////////////////////////////////////////////////////////////////////////
00050 
00051 // Auxiliary class: almost the same as CDO (see cdo.h), but on
00052 // setNull() call it erases itself from the map.
00053 
00054 template <class Key, class Data, class HashFcn = std::hash<Key> > class CDMap;
00055 
00056 template <class Key, class Data, class HashFcn = std::hash<Key> >
00057 class CDOmap :public ContextObj {
00058   Key d_key;
00059   Data d_data;
00060   bool d_inMap; // whether the data must be in the map
00061   CDMap<Key, Data, HashFcn>* d_cdmap;
00062 
00063   // Doubly-linked list for keeping track of elements in order of insertion
00064   CDOmap<Key, Data, HashFcn>* d_prev;
00065   CDOmap<Key, Data, HashFcn>* d_next;
00066 
00067   virtual ContextObj* makeCopy(void) { return new CDOmap<Key, Data, HashFcn>(*this); }
00068 
00069   virtual void restoreData(ContextObj* data) {
00070     CDOmap<Key, Data, HashFcn>* p((CDOmap<Key, Data, HashFcn>*)data);
00071     if(p->d_inMap) { d_data = p->d_data; d_inMap = true; }
00072     else setNull();
00073   }
00074   virtual void setNull(void) {
00075     // Erase itself from the map and put itself into trash.  We cannot
00076     // "delete this" here, because it will break context operations in
00077     // a non-trivial way.
00078     if(d_cdmap->d_map.count(d_key) > 0) {
00079       d_cdmap->d_map.erase(d_key);
00080       d_cdmap->d_trash.push_back(this);
00081     }
00082     d_prev->d_next = d_next;
00083     d_next->d_prev = d_prev;
00084     if (d_cdmap->d_first == this) {
00085       d_cdmap->d_first = d_next;
00086       if (d_next == this) {
00087         d_cdmap->d_first = NULL;
00088       }
00089     }
00090   }
00091 
00092 public:
00093   CDOmap(Context* context, CDMap<Key, Data, HashFcn>* cdmap,
00094          const Key& key, const Data& data, int scope = -1)
00095     : ContextObj(context, true /* use bottom scope */),
00096     d_key(key), d_inMap(false), d_cdmap(cdmap) {
00097     set(data, scope);
00098     IF_DEBUG(setName("CDOmap"));
00099     CDOmap<Key, Data, HashFcn>*& first = d_cdmap->d_first;
00100     if (first == NULL) {
00101       first = d_next = d_prev = this;
00102     }
00103     else {
00104       d_prev = first->d_prev;
00105       d_next = first;
00106       d_prev->d_next = first->d_prev = this;
00107     }
00108   }
00109   ~CDOmap() {}
00110   void set(const Data& data, int scope=-1) {
00111     makeCurrent(scope); d_data = data; d_inMap = true;
00112   }
00113   const Key& getKey() const { return d_key; }
00114   const Data& get() const { return d_data; }
00115   operator Data() { return get(); }
00116   CDOmap<Key, Data, HashFcn>& operator=(const Data& data) { set(data); return *this; }
00117   CDOmap<Key, Data, HashFcn>* next() const {
00118     if (d_next == d_cdmap->d_first) return NULL;
00119     else return d_next;
00120   }
00121 }; // end of class CDOmap
00122 
00123 // Dummy subclass of ContextObj to serve as our data class
00124 class CDMapData : public ContextObj {
00125   ContextObj* makeCopy(void) { return new CDMapData(*this); }
00126   void restoreData(ContextObj* data) { }
00127   void setNull(void) { }
00128  public:
00129   CDMapData(Context* context): ContextObj(context) { }
00130   CDMapData(const ContextObj& co): ContextObj(co) { }
00131 };
00132 
00133 // The actual class CDMap
00134 template <class Key, class Data, class HashFcn>
00135 class CDMap: public ContextObj {
00136   friend class CDOmap<Key, Data, HashFcn>;
00137  private:
00138   std::hash_map<Key,CDOmap<Key, Data, HashFcn>*> d_map;
00139   // The vector of CDOmap objects to be destroyed
00140   std::vector<CDOmap<Key, Data, HashFcn>*> d_trash;
00141   CDOmap<Key, Data, HashFcn>* d_first;
00142   Context* d_context;
00143   
00144   // Nothing to save; the elements take care of themselves
00145   virtual ContextObj* makeCopy(void) { return new CDMapData(*this); }
00146   // Similarly, nothing to restore
00147   virtual void restoreData(ContextObj* data) { }
00148   
00149   // Destroy stale CDOmap objects from trash
00150   void emptyTrash() {
00151     for(typename std::vector<CDOmap<Key, Data, HashFcn>*>::iterator
00152           i=d_trash.begin(), iend=d_trash.end(); i!=iend; ++i)
00153       delete *i;
00154     d_trash.clear();
00155   }
00156 
00157   virtual void setNull(void) {
00158     // Delete all the elements and clear the map
00159     for(typename std::hash_map<Key,CDOmap<Key, Data, HashFcn>*>::iterator
00160           i=d_map.begin(), iend=d_map.end();
00161         i!=iend; ++i) delete (*i).second;
00162     d_map.clear();
00163     emptyTrash();
00164   }
00165 public:
00166   CDMap(Context* context, int scope = -1)
00167     : ContextObj(context), d_first(NULL), d_context(context) {
00168     IF_DEBUG(setName("CDMap"));     
00169   }
00170   ~CDMap() { setNull(); }
00171   // The usual operators of map
00172   size_t size() const { return d_map.size(); }
00173   size_t count(const Key& k) const { return d_map.count(k); }
00174 
00175   // If a key is not present, a new object is created and inserted
00176   CDOmap<Key, Data, HashFcn>& operator[](const Key& k) {
00177     emptyTrash();
00178     typename std::hash_map<Key,CDOmap<Key, Data, HashFcn>*>::iterator i(d_map.find(k));
00179     CDOmap<Key, Data, HashFcn>* obj;
00180     if(i == d_map.end()) { // Create new object
00181       obj = new CDOmap<Key, Data, HashFcn>(d_context, this, k, Data());
00182       d_map[k] = obj;
00183     } else {
00184       obj = (*i).second;
00185     }
00186     return *obj;
00187   }
00188 
00189   void insert(const Key& k, const Data& d, int scope = -1) {
00190     emptyTrash();
00191     typename std::hash_map<Key,CDOmap<Key, Data, HashFcn>*>::iterator i(d_map.find(k));
00192     if(i == d_map.end()) { // Create new object
00193       CDOmap<Key, Data, HashFcn>*
00194         obj(new CDOmap<Key, Data, HashFcn>(d_context, this, k, d, scope));
00195       d_map[k] = obj;
00196     } else {
00197       (*i).second->set(d, scope);
00198     }
00199   }
00200   // FIXME: no erase(), too much hassle to implement efficiently...
00201 
00202   // Iterator for CDMap: points to pair<const Key, CDOMap<Key, Data, HashFcn>&>;
00203   // in most cases, this will be functionally similar to pair<const Key,Data>.
00204   class iterator : public std::iterator<std::input_iterator_tag,std::pair<const Key, Data>,std::ptrdiff_t> {
00205     private:
00206       // Private members
00207       typename std::hash_map<Key,CDOmap<Key, Data, HashFcn>*>::const_iterator d_it;
00208     public:
00209       // Constructor from std::hash_map
00210       iterator(const typename std::hash_map<Key,CDOmap<Key, Data, HashFcn>*>::const_iterator& i)
00211       : d_it(i) { }
00212       // Copy constructor
00213       iterator(const iterator& i): d_it(i.d_it) { }
00214       // Default constructor
00215       iterator() { }
00216       // (Dis)equality
00217       bool operator==(const iterator& i) const {
00218         return d_it == i.d_it;
00219       }
00220       bool operator!=(const iterator& i) const {
00221         return d_it != i.d_it;
00222       }
00223       // Dereference operators.
00224       std::pair<const Key, Data> operator*() const {
00225         const std::pair<const Key, CDOmap<Key, Data, HashFcn>*>& p(*d_it);
00226         return std::pair<const Key, Data>(p.first, *p.second);
00227       }
00228       // Who needs an operator->() for maps anyway?...
00229       // It'd be nice, but not possible by design.
00230       //std::pair<const Key,Data>* operator->() const {
00231       //  return &(operator*());
00232       //}
00233       
00234 
00235       // Prefix and postfix increment
00236       iterator& operator++() { ++d_it; return *this; }
00237       // Postfix increment: requires a Proxy object to hold the
00238       // intermediate value for dereferencing
00239       class Proxy {
00240         const std::pair<const Key, Data>* d_pair;
00241       public:
00242         Proxy(const std::pair<const Key, Data>& p): d_pair(&p) { }
00243         std::pair<const Key, Data>& operator*() { return *d_pair; }
00244       };
00245       // Actual postfix increment: returns Proxy with the old value.
00246       // Now, an expression like *i++ will return the current *i, and
00247       // then advance the iterator.  However, don't try to use Proxy for
00248       // anything else.
00249       Proxy operator++(int) {
00250         Proxy e(*(*this));
00251         ++(*this);
00252         return e;
00253       }
00254   };
00255 
00256   iterator begin() const { return iterator(d_map.begin()); }
00257   iterator end() const { return iterator(d_map.end()); }
00258 
00259   class orderedIterator {
00260       const CDOmap<Key, Data, HashFcn>* d_it;
00261     public:
00262       orderedIterator(const CDOmap<Key, Data, HashFcn>* p): d_it(p) {}
00263       orderedIterator(const orderedIterator& i): d_it(i.d_it) { }
00264       // Default constructor
00265       orderedIterator() { }
00266       // (Dis)equality
00267       bool operator==(const orderedIterator& i) const {
00268         return d_it == i.d_it;
00269       }
00270       bool operator!=(const orderedIterator& i) const {
00271         return d_it != i.d_it;
00272       }
00273       // Dereference operators.
00274       std::pair<const Key, Data> operator*() const {
00275         return std::pair<const Key, Data>(d_it->getKey(), d_it->get());
00276       }
00277 
00278       // Prefix and postfix increment
00279       orderedIterator& operator++() { d_it = d_it->next(); return *this; }
00280       // Postfix increment: requires a Proxy object to hold the
00281       // intermediate value for dereferencing
00282       class Proxy {
00283         const std::pair<const Key, Data>* d_pair;
00284       public:
00285         Proxy(const std::pair<const Key, Data>& p): d_pair(&p) { }
00286         std::pair<const Key, Data>& operator*() { return *d_pair; }
00287       };
00288       // Actual postfix increment: returns Proxy with the old value.
00289       // Now, an expression like *i++ will return the current *i, and
00290       // then advance the orderedIterator.  However, don't try to use Proxy for
00291       // anything else.
00292       Proxy operator++(int) {
00293         Proxy e(*(*this));
00294         ++(*this);
00295         return e;
00296       }
00297   };
00298 
00299   orderedIterator orderedBegin() const { return orderedIterator(d_first); }
00300   orderedIterator orderedEnd() const { return orderedIterator(NULL); }
00301 
00302   iterator find(const Key& k) const { return iterator(d_map.find(k)); }
00303 
00304 }; // end of class CDMap
00305 
00306 
00307 }
00308 
00309 #endif

Generated on Thu Apr 13 16:57:29 2006 for CVC Lite by  doxygen 1.4.4