CVC3
|
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