context.h

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file context.h
00004  * 
00005  * Author: Clark Barrett
00006  * 
00007  * Created: Tue Dec 31 19:07:38 2002
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 
00030 #ifndef _cvcl__include__context_h_
00031 #define _cvcl__include__context_h_
00032 
00033 #include <string>
00034 #include <vector>
00035 #include "debug.h"
00036 
00037 
00038 namespace CVCL {
00039 
00040 /****************************************************************************/
00041 /*! \defgroup Context Context Management
00042  *  \ingroup BuildingBlocks
00043  * Infrastructure for backtrackable data structures.
00044  * @{
00045  */
00046 /****************************************************************************/
00047 
00048 class Context;
00049 class ContextManager;
00050 class ContextNotifyObj;
00051 class ContextObj;
00052 class ContextObjChain;
00053 
00054 /****************************************************************************/
00055 /*! 
00056  * Author: Clark Barrett
00057  *
00058  * Created: Thu Feb 13 00:19:15 2003
00059  *
00060  * A scope encapsulates the portion of a context which has changed
00061  * since the last call to push().  Thus, when pop() is called,
00062  * everything in this scope is restored to its previous state.
00063  */
00064  /****************************************************************************/
00065 
00066 class Scope {
00067   friend class ContextObj;
00068   friend class ContextObjChain;
00069   friend class CDFlags;
00070   //! Context that created this scope
00071   Context* d_context;
00072 
00073   //! Previous scope in this context
00074   Scope* d_prevScope;
00075 
00076   //! Scope level
00077   int d_level;
00078 
00079   /*! @brief Linked list of objects which are "current" in this scope,
00080     and thus need to be restored when the scope is deleted */
00081   ContextObjChain* d_restoreChain;
00082 
00083   //! Deleted ContextObj's (queued up for deletion during restore())
00084   std::vector<ContextObjChain*> d_deleted;
00085 
00086   //! Set while inside restore() or ~Scope() methods
00087   bool d_delayDelete;
00088 
00089   //! Called by ContextObj when created
00090   void addToChain(ContextObjChain* obj);
00091 
00092 public:
00093   //! Constructor
00094   Scope(Context* context, Scope* prevScope = NULL);
00095   //! Delete the scope (only free up memory, do not call restore())
00096   ~Scope();
00097 
00098   //! Access functions
00099   Scope* prevScope() const { return d_prevScope; }
00100   int level(void) const { return d_level; }
00101   bool isCurrent(void) const;
00102   Scope* topScope() const;
00103 
00104   //! Restore all the values
00105   void restore(void);
00106 };
00107 
00108 ///////////////////////////////////////////////////////////////////////////////
00109 //                                                                           //
00110 // Class: ContextObjChain                                                    //
00111 // Author: Sergey Berezin                                                    //
00112 // Created: Wed Mar 12 11:25:22 2003                                         //
00113 
00114 /*! Description: An element of a doubly linked list holding a copy of
00115  * ContextObj in a scope.  It is made separate from ContextObj to keep
00116  * the list pointers valid in all scopes at all times, so that the
00117  * object can be easily removed from the list when the master
00118  * ContextObj is destroyed. */
00119 ///////////////////////////////////////////////////////////////////////////////
00120 class ContextObjChain {
00121 friend class Scope;
00122 friend class ContextObj;
00123 friend class CDFlags;
00124 private:
00125   //! Next link in chain
00126   ContextObjChain* d_restoreChainNext;
00127 
00128   /*! @brief Pointer to the pointer of the previous object which
00129   points to us.  This makes a doubly-linked list for easy element
00130   deletion */
00131   ContextObjChain** d_restoreChainPrev;
00132 
00133   //! Pointer to the previous copy which belongs to the same master
00134   ContextObjChain* d_restore;
00135 
00136   //! Pointer to copy of master to be restored when restore() is called
00137   ContextObj* d_data;
00138 
00139   //! Pointer to the master object
00140   ContextObj* d_master;
00141 
00142   //! Private constructor (only friends can use it)
00143   ContextObjChain(ContextObj* data, ContextObj* master, 
00144                   ContextObjChain* restore);
00145 
00146   //! Restore from d_data to d_master
00147   ContextObjChain* restore(void);
00148 public:
00149   //! Destructor
00150   ~ContextObjChain();
00151   IF_DEBUG(std::string name() const;);
00152 };
00153 
00154 ///////////////////////////////////////////////////////////////////////////////
00155 //                                                                           //
00156 // Class: ContextObj                                                         //
00157 // Author: Clark Barrett                                                     //
00158 // Created: Thu Feb 13 00:21:13 2003                                         //
00159 
00160 /*!  Description: This is a generic class from which all objects that
00161  * are context-dependent should inherit.  Subclasses need to implement
00162  * makeCopy, restoreData, and setNull.
00163  */
00164 ///////////////////////////////////////////////////////////////////////////////
00165 class ContextObj {
00166 friend class Scope;
00167 friend class ContextObjChain;
00168 friend class CDFlags;
00169 private:
00170   //! Last scope in which this object was modified.
00171   Scope* d_scope;
00172 
00173   /*! @brief The list of values on previous scopes; our destructor
00174    *  should clean up those. */
00175   ContextObjChain* d_restore;
00176 
00177   IF_DEBUG(std::string d_name);
00178   IF_DEBUG(bool d_active);
00179 
00180   //! Update on the given scope, on the current scope if 'scope' == 0
00181   void update(int scope = -1);
00182 
00183 protected:
00184   //! Copy constructor (defined mainly for debugging purposes)
00185   ContextObj(const ContextObj& co);
00186   //! Assignment operator (defined mainly for debugging purposes)
00187   ContextObj& operator=(const ContextObj& co);
00188   /*! @brief Make a copy of the current object so it can be restored
00189    * to its current state */
00190   virtual ContextObj* makeCopy(void) = 0;
00191 
00192   //! Restore the current object from the given data
00193   virtual void restoreData(ContextObj* data) {
00194     FatalAssert(false, 
00195                 "ContextObj::restoreData(): call in the base abstract class");
00196   }
00197 
00198   //! Set the current object to be invalid
00199   virtual void setNull(void) = 0;
00200 
00201   //! Return our name (for debugging)
00202   IF_DEBUG(virtual std::string name() const { return d_name; });
00203 
00204 public:
00205   //! Create a new ContextObj.
00206   /*!
00207    * The initial scope is set to the bottom scope by default, to
00208    * reduce the work of pop() (otherwise, if the object is defined
00209    * only on a very high scope, its scope will be moved down with each
00210    * pop).  If 'atBottomScope' == false, the scope is set to the
00211    * current scope. 
00212    */
00213   ContextObj(Context* context, bool atBottomScope = true);
00214   virtual ~ContextObj();
00215 
00216   int level() const { return (d_scope==NULL)? 0 : d_scope->level(); }
00217   bool isCurrent(int scope = -1) const {
00218     if(scope >= 0) return d_scope->level() == scope;
00219     else return d_scope->isCurrent();
00220   }
00221   void makeCurrent(int scope = -1) { if (!isCurrent(scope)) update(scope); }
00222   IF_DEBUG(void setName(const std::string& name) { d_name=name; });
00223 };
00224 
00225 ///////////////////////////////////////////////////////////////////////////////
00226 //                                                                           //
00227 // Class: Context                                                            //
00228 // Author: Clark Barrett                                                     //
00229 // Created: Thu Feb 13 00:24:59 2003                                         //
00230 /*!
00231  * Encapsulates the general notion of stack-based saving and restoring
00232  * of a database.
00233  */
00234 ///////////////////////////////////////////////////////////////////////////////
00235 class Context {
00236   //! Context Manager
00237   ContextManager* d_cm;
00238 
00239   //! Name of context
00240   std::string d_name;
00241 
00242   //! Context ID
00243   int d_id;
00244 
00245   //! Pointer to top and bottom scopes of context
00246   Scope* d_topScope;
00247   Scope* d_bottomScope;
00248 
00249   //! List of objects to notify with every pop
00250   std::vector<ContextNotifyObj*> d_notifyObjList;
00251 
00252 public:
00253   Context(ContextManager* cm, const std::string& name, int id);
00254   ~Context();
00255 
00256   //! Access methods
00257   ContextManager* getCM() const { return d_cm; }
00258   const std::string& name() const { return d_name; }
00259   int id() const { return d_id; }
00260   Scope* topScope() const { return d_topScope; }
00261   Scope* bottomScope() const { return d_bottomScope; }
00262   int level() const { return d_topScope->level(); }
00263 
00264   // TODO: use custom memory manager
00265   void push() {
00266     d_topScope = new Scope(this, d_topScope);
00267     TRACE("context", "*** [context] Pushing scope to level ", level(), " {");
00268     IF_DEBUG(DebugCounter maxLevel(debugger.counter("max scope level")));
00269     IF_DEBUG(if(maxLevel<level()) maxLevel=level());
00270   }
00271   void pop();
00272   void popto(int toLevel);
00273   void addNotifyObj(ContextNotifyObj* obj) { d_notifyObjList.push_back(obj); }
00274   void deleteNotifyObj(ContextNotifyObj* obj);
00275 };
00276 
00277 // Have to define after Context class
00278 inline bool Scope::isCurrent(void) const
00279   { return this == d_context->topScope(); }
00280 
00281 inline Scope* Scope::topScope() const { return d_context->topScope(); }
00282 
00283 /****************************************************************************/
00284 //! Manager for multiple contexts.  Also holds current context.
00285 /*!
00286  * Author: Clark Barrett
00287  *
00288  * Created: Thu Feb 13 00:26:29 2003
00289  */
00290 /****************************************************************************/
00291 
00292 class ContextManager {
00293   Context* d_curContext;
00294   std::vector<Context*> d_contexts;
00295 
00296 public:
00297   ContextManager();
00298   ~ContextManager();
00299 
00300   void push() { d_curContext->push(); }
00301   void pop() { d_curContext->pop(); }
00302   void popto(int toLevel) { d_curContext->popto(toLevel); }
00303   int scopeLevel() { return d_curContext->level(); }
00304   Context* createContext(const std::string& name="");
00305   Context* getCurrentContext() { return d_curContext; }
00306   Context* switchContext(Context* context);
00307 };
00308 
00309 /****************************************************************************/
00310 /*! Author: Clark Barrett                                                     
00311  *
00312  * Created: Sat Feb 22 16:21:47 2003                                         
00313  *
00314  * Lightweight version of ContextObj: objects are simply notified
00315  * every time there's a pop. notifyPre() is called right before the
00316  * context is restored, and notify() is called after the context is
00317  * restored.
00318  */
00319 /****************************************************************************/
00320  
00321 class ContextNotifyObj {
00322   friend class Context;
00323 protected:
00324   Context* d_context;
00325 public:
00326   ContextNotifyObj(Context* context): d_context(context)
00327     { context->addNotifyObj(this); }
00328   virtual ~ContextNotifyObj() {
00329     // If we are being deleted before the context, remove ourselves
00330     // from the notify list.  However, if the context is deleted
00331     // before we are, then our d_context will be cleared from ~Context()
00332     if(d_context!=NULL) d_context->deleteNotifyObj(this);
00333   }
00334   virtual void notifyPre(void) {}
00335   virtual void notify(void) {}
00336 };
00337 
00338 /*@}*/  // end of group Context
00339 
00340 }
00341 
00342 #endif

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