CVC3

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  *
00011  * License to use, copy, modify, sell and/or distribute this software
00012  * and its documentation for any purpose is hereby granted without
00013  * royalty, subject to the terms and conditions defined in the \ref
00014  * LICENSE file provided with this distribution.
00015  *
00016  * <hr>
00017  *
00018  */
00019 /*****************************************************************************/
00020 
00021 
00022 #ifndef _cvc3__include__context_h_
00023 #define _cvc3__include__context_h_
00024 
00025 #include <string>
00026 #include <vector>
00027 #include <stdlib.h>
00028 #include "debug.h"
00029 #include "memory_manager_context.h"
00030 #include "os.h"
00031 
00032 namespace CVC3 {
00033 
00034 /****************************************************************************/
00035 /*! \defgroup Context Context Management
00036  *  \ingroup BuildingBlocks
00037  * Infrastructure for backtrackable data structures.
00038  * @{
00039  */
00040 /****************************************************************************/
00041 
00042 class Context;
00043 class ContextManager;
00044 class ContextNotifyObj;
00045 class ContextObj;
00046 class ContextObjChain;
00047 
00048 /****************************************************************************/
00049 /*!
00050  * Author: Clark Barrett
00051  *
00052  * Created: Thu Feb 13 00:19:15 2003
00053  *
00054  * A scope encapsulates the portion of a context which has changed
00055  * since the last call to push().  Thus, when pop() is called,
00056  * everything in this scope is restored to its previous state.
00057  */
00058  /****************************************************************************/
00059 
00060 class Scope {
00061   friend class ContextObj;
00062   friend class ContextObjChain;
00063   friend class CDFlags;
00064   //! Context that created this scope
00065   Context* d_context;
00066 
00067   //! Memory manager for this scope
00068   ContextMemoryManager* d_cmm;
00069 
00070   //! Previous scope in this context
00071   Scope* d_prevScope;
00072 
00073   //! Scope level
00074   int d_level;
00075 
00076   /*! @brief Linked list of objects which are "current" in this scope,
00077     and thus need to be restored when the scope is deleted */
00078   ContextObjChain* d_restoreChain;
00079 
00080   //! Called by ContextObj when created
00081   void addToChain(ContextObjChain* obj);
00082 
00083 public:
00084   //! Constructor
00085   Scope(Context* context, ContextMemoryManager* cmm,
00086         Scope* prevScope = NULL)
00087     : d_context(context), d_cmm(cmm), d_prevScope(prevScope),
00088       d_restoreChain(NULL)
00089     { if (prevScope) d_level = prevScope->level() + 1; else d_level = 0; }
00090   //! Destructor
00091   ~Scope() {}
00092 
00093   //! Access functions
00094   Scope* prevScope() const { return d_prevScope; }
00095   int level(void) const { return d_level; }
00096   bool isCurrent(void) const;
00097   Scope* topScope() const;
00098   Context* getContext() const { return d_context; }
00099   ContextMemoryManager* getCMM() const { return d_cmm; }
00100 
00101   void* operator new(size_t size, MemoryManager* mm)
00102     { return mm->newData(size); }
00103   void operator delete(void* pMem, MemoryManager* mm) {
00104     mm->deleteData(pMem);
00105   }
00106   void operator delete(void*) { }
00107 
00108   //! Restore all the values
00109   void restore(void);
00110 
00111   //! Called by ~ContextManager
00112   void finalize(void);
00113 
00114   //! Check for memory leaks
00115   void check(void);
00116 
00117   //! Compute memory used
00118   unsigned long getMemory(int verbosity);
00119 };
00120 
00121 ///////////////////////////////////////////////////////////////////////////////
00122 //                                                                           //
00123 // Class: ContextObjChain                //
00124 // Author: Sergey Berezin                                                    //
00125 // Created: Wed Mar 12 11:25:22 2003               //
00126 
00127 /*! Description: An element of a doubly linked list holding a copy of
00128  * ContextObj in a scope.  It is made separate from ContextObj to keep
00129  * the list pointers valid in all scopes at all times, so that the
00130  * object can be easily removed from the list when the master
00131  * ContextObj is destroyed. */
00132 ///////////////////////////////////////////////////////////////////////////////
00133 class ContextObjChain {
00134 friend class Scope;
00135 friend class ContextObj;
00136 friend class CDFlags;
00137 private:
00138   //! Next link in chain
00139   ContextObjChain* d_restoreChainNext;
00140 
00141   /*! @brief Pointer to the pointer of the previous object which
00142   points to us.  This makes a doubly-linked list for easy element
00143   deletion */
00144   ContextObjChain** d_restoreChainPrev;
00145 
00146   //! Pointer to the previous copy which belongs to the same master
00147   ContextObjChain* d_restore;
00148 
00149   //! Pointer to copy of master to be restored when restore() is called
00150   ContextObj* d_data;
00151 
00152   //! Pointer to the master object
00153   ContextObj* d_master;
00154 
00155   //! Private constructor (only friends can use it)
00156   ContextObjChain(ContextObj* data, ContextObj* master,
00157       ContextObjChain* restore)
00158     : d_restoreChainNext(NULL), d_restoreChainPrev(NULL),
00159       d_restore(restore), d_data(data), d_master(master)
00160   { }
00161 
00162   //! Restore from d_data to d_master
00163   ContextObjChain* restore(void);
00164 public:
00165   //! Destructor
00166   ~ContextObjChain() {}
00167 
00168   void* operator new(size_t size, MemoryManager* mm) {
00169     return mm->newData(size);
00170   }
00171   void operator delete(void* pMem, MemoryManager* mm) {
00172     mm->deleteData(pMem);
00173   }
00174 
00175   void operator delete(void*) { }
00176 
00177   // If you use this operator, you have to call free yourself when the memory
00178   // is freed.
00179   void* operator new(size_t size, bool b) {
00180     return malloc(size);
00181   }
00182   void operator delete(void* pMem, bool b) {
00183     free(pMem);
00184   }
00185 
00186   IF_DEBUG(std::string name() const;)
00187 };
00188 
00189 ///////////////////////////////////////////////////////////////////////////////
00190 //                                                                           //
00191 // Class: ContextObj                   //
00192 // Author: Clark Barrett                                                     //
00193 // Created: Thu Feb 13 00:21:13 2003               //
00194 
00195 /*!  Description: This is a generic class from which all objects that
00196  * are context-dependent should inherit.  Subclasses need to implement
00197  * makeCopy, restoreData, and setNull.
00198  */
00199 ///////////////////////////////////////////////////////////////////////////////
00200 class CVC_DLL ContextObj {
00201 friend class Scope;
00202 friend class ContextObjChain;
00203 friend class CDFlags;
00204 private:
00205   //! Last scope in which this object was modified.
00206   Scope* d_scope;
00207 
00208   /*! @brief The list of values on previous scopes; our destructor
00209    *  should clean up those. */
00210   ContextObjChain* d_restore;
00211 
00212   IF_DEBUG(std::string d_name;)
00213   IF_DEBUG(bool d_active;)
00214 
00215   //! Update on the given scope, on the current scope if 'scope' == -1
00216   void update(int scope = -1);
00217 
00218 protected:
00219   //! Copy constructor (defined mainly for debugging purposes)
00220   ContextObj(const ContextObj& co)
00221     : d_scope(co.d_scope), d_restore(co.d_restore) {
00222     IF_DEBUG(d_name=co.d_name;)
00223     DebugAssert(co.d_active, "ContextObj["+co.name()+"] copy constructor");
00224     IF_DEBUG(d_active = co.d_active;)
00225     //    TRACE("context verbose", "ContextObj()[", this, "]: copy constructor");
00226   }
00227 
00228   //! Assignment operator (defined mainly for debugging purposes)
00229   ContextObj& operator=(const ContextObj& co) {
00230     DebugAssert(false, "ContextObj::operator=(): shouldn't be called");
00231     return *this;
00232   }
00233 
00234   /*! @brief Make a copy of the current object so it can be restored
00235    * to its current state */
00236   virtual ContextObj* makeCopy(ContextMemoryManager* cmm) = 0;
00237 
00238   //! Restore the current object from the given data
00239   virtual void restoreData(ContextObj* data) {
00240     FatalAssert(false,
00241                 "ContextObj::restoreData(): call in the base abstract class");
00242   }
00243 
00244   const ContextObj* getRestore() {
00245     return d_restore ? d_restore->d_data : NULL;
00246   }
00247 
00248   //! Set the current object to be invalid
00249   virtual void setNull(void) = 0;
00250 
00251   //! Return our name (for debugging)
00252   IF_DEBUG(virtual std::string name() const { return d_name; })
00253 
00254   //! Get context memory manager
00255   ContextMemoryManager* getCMM() { return d_scope->getCMM(); }
00256 
00257 public:
00258   //! Create a new ContextObj.
00259   /*!
00260    * The initial scope is set to the bottom scope by default, to
00261    * reduce the work of pop() (otherwise, if the object is defined
00262    * only on a very high scope, its scope will be moved down with each
00263    * pop).  If 'atBottomScope' == false, the scope is set to the
00264    * current scope.
00265    */
00266   ContextObj(Context* context);
00267   virtual ~ContextObj();
00268 
00269   int level() const { return (d_scope==NULL)? 0 : d_scope->level(); }
00270   bool isCurrent(int scope = -1) const {
00271     if(scope >= 0) return d_scope->level() == scope;
00272     else return d_scope->isCurrent();
00273   }
00274   void makeCurrent(int scope = -1) { if (!isCurrent(scope)) update(scope); }
00275   IF_DEBUG(void setName(const std::string& name) { d_name=name; })
00276 
00277   void* operator new(size_t size, MemoryManager* mm) {
00278     return mm->newData(size);
00279   }
00280   void operator delete(void* pMem, MemoryManager* mm) {
00281     mm->deleteData(pMem);
00282   }
00283 
00284   // If you use this operator, you have to call free yourself when the memory
00285   // is freed.
00286   void* operator new(size_t size, bool b) {
00287     return malloc(size);
00288   }
00289   void operator delete(void* pMem, bool b) {
00290     free(pMem);
00291   }
00292 
00293   void operator delete(void*) { }
00294 };
00295 
00296 ///////////////////////////////////////////////////////////////////////////////
00297 //                                                                           //
00298 // Class: Context                  //
00299 // Author: Clark Barrett                                                     //
00300 // Created: Thu Feb 13 00:24:59 2003               //
00301 /*!
00302  * Encapsulates the general notion of stack-based saving and restoring
00303  * of a database.
00304  */
00305 ///////////////////////////////////////////////////////////////////////////////
00306 class CVC_DLL Context {
00307   //! Context Manager
00308   ContextManager* d_cm;
00309 
00310   //! Name of context
00311   std::string d_name;
00312 
00313   //! Context ID
00314   int d_id;
00315 
00316   //! Pointer to top and bottom scopes of context
00317   Scope* d_topScope;
00318   Scope* d_bottomScope;
00319 
00320   //! List of objects to notify with every pop
00321   std::vector<ContextNotifyObj*> d_notifyObjList;
00322 
00323   //! Stack of free ContextMemoryManager's
00324   std::vector<ContextMemoryManager*> d_cmmStack;
00325 
00326 public:
00327   Context(ContextManager* cm, const std::string& name, int id);
00328   ~Context();
00329 
00330   //! Access methods
00331   ContextManager* getCM() const { return d_cm; }
00332   const std::string& name() const { return d_name; }
00333   int id() const { return d_id; }
00334   Scope* topScope() const { return d_topScope; }
00335   Scope* bottomScope() const { return d_bottomScope; }
00336   int level() const { return d_topScope->level(); }
00337 
00338   void push();
00339   void pop();
00340   void popto(int toLevel);
00341   void addNotifyObj(ContextNotifyObj* obj) { d_notifyObjList.push_back(obj); }
00342   void deleteNotifyObj(ContextNotifyObj* obj);
00343   unsigned long getMemory(int verbosity);
00344 };
00345 
00346 // Have to define after Context class
00347 inline bool Scope::isCurrent(void) const
00348   { return this == d_context->topScope(); }
00349 
00350 inline void Scope::addToChain(ContextObjChain* obj) {
00351   if(d_restoreChain != NULL)
00352     d_restoreChain->d_restoreChainPrev = &(obj->d_restoreChainNext);
00353   obj->d_restoreChainNext = d_restoreChain;
00354   obj->d_restoreChainPrev = &d_restoreChain;
00355   d_restoreChain = obj;
00356 }
00357 
00358 inline Scope* Scope::topScope() const { return d_context->topScope(); }
00359 
00360 inline void Scope::restore(void) {
00361   //  TRACE_MSG("context verbose", "Scope::restore() {");
00362   while (d_restoreChain != NULL) d_restoreChain = d_restoreChain->restore();
00363   //  TRACE_MSG("context verbose", "Scope::restore() }");
00364 }
00365 
00366 // Create a new ContextObj.  The initial scope is set to the bottom
00367 // scope by default, to reduce the work of pop() (otherwise, if the
00368 // object is defined only on a very high scope, its scope will be
00369 // moved down with each pop).  If 'atBottomScope' == false, the
00370 // scope is set to the current scope.
00371 inline ContextObj::ContextObj(Context* context)
00372   IF_DEBUG(: d_name("ContextObj"))
00373 {
00374   IF_DEBUG(d_active=true;)
00375   DebugAssert(context != NULL, "NULL context pointer");
00376   d_scope = context->bottomScope();
00377   d_restore = new(true) ContextObjChain(NULL, this, NULL);
00378   d_scope->addToChain(d_restore);
00379   //  if (atBottomScope) d_scope->addSpecialObject(d_restore);
00380   //  TRACE("context verbose", "ContextObj()[", this, "]");
00381 }
00382 
00383 
00384 /****************************************************************************/
00385 //! Manager for multiple contexts.  Also holds current context.
00386 /*!
00387  * Author: Clark Barrett
00388  *
00389  * Created: Thu Feb 13 00:26:29 2003
00390  */
00391 /****************************************************************************/
00392 
00393 class ContextManager {
00394   Context* d_curContext;
00395   std::vector<Context*> d_contexts;
00396 
00397 public:
00398   ContextManager();
00399   ~ContextManager();
00400 
00401   void push() { d_curContext->push(); }
00402   void pop() { d_curContext->pop(); }
00403   void popto(int toLevel) { d_curContext->popto(toLevel); }
00404   int scopeLevel() { return d_curContext->level(); }
00405   Context* createContext(const std::string& name="");
00406   Context* getCurrentContext() { return d_curContext; }
00407   Context* switchContext(Context* context);
00408   unsigned long getMemory(int verbosity);
00409 };
00410 
00411 /****************************************************************************/
00412 /*! Author: Clark Barrett
00413  *
00414  * Created: Sat Feb 22 16:21:47 2003
00415  *
00416  * Lightweight version of ContextObj: objects are simply notified
00417  * every time there's a pop. notifyPre() is called right before the
00418  * context is restored, and notify() is called after the context is
00419  * restored.
00420  */
00421 /****************************************************************************/
00422 
00423 class ContextNotifyObj {
00424   friend class Context;
00425 protected:
00426   Context* d_context;
00427 public:
00428   ContextNotifyObj(Context* context): d_context(context)
00429     { context->addNotifyObj(this); }
00430   virtual ~ContextNotifyObj() {
00431     // If we are being deleted before the context, remove ourselves
00432     // from the notify list.  However, if the context is deleted
00433     // before we are, then our d_context will be cleared from ~Context()
00434     if(d_context!=NULL) d_context->deleteNotifyObj(this);
00435   }
00436   virtual void notifyPre(void) {}
00437   virtual void notify(void) {}
00438   virtual unsigned long getMemory(int verbosity) { return sizeof(ContextNotifyObj); }
00439 };
00440 
00441 /*@}*/  // end of group Context
00442 
00443 }
00444 
00445 #endif