context.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file context.cpp
00004  * 
00005  * Author: Clark Barrett
00006  * 
00007  * Created: Fri Jan 17 14:30:37 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 
00030 #include "context.h"
00031 
00032 
00033 using namespace CVCL;
00034 using namespace std;
00035 
00036 
00037 ///////////////////////////////////////////////////////////////////////////////
00038 // Scope methods                                                             //
00039 ///////////////////////////////////////////////////////////////////////////////
00040 
00041 
00042 void Scope::addToChain(ContextObjChain* obj)
00043 {
00044 //   TRACE("context verbose", "Scope::addToChain(", obj->name(), ")");
00045   if(d_restoreChain != NULL)
00046     d_restoreChain->d_restoreChainPrev = &obj->d_restoreChainNext;
00047   obj->d_restoreChainNext = d_restoreChain;
00048   obj->d_restoreChainPrev = &d_restoreChain;
00049   d_restoreChain = obj;
00050 }
00051 
00052 
00053 Scope::Scope(Context* context, Scope* prevScope)
00054   : d_context(context), d_prevScope(prevScope), d_restoreChain(NULL)
00055 {
00056   if (prevScope) d_level = prevScope->level() + 1;
00057   else d_level = 0;
00058   IF_DEBUG(d_delayDelete = false);
00059 }
00060 
00061 
00062 Scope::~Scope()
00063 {
00064 
00065   TRACE_MSG("context verbose", "~Scope() {");
00066   ContextObjChain* obj = d_restoreChain;
00067   // Now, delete restore chains queued up for deletion.
00068   IF_DEBUG(d_delayDelete=true);
00069 
00070   IF_DEBUG(
00071     if(debugger.trace("memory") && obj != NULL) {
00072       ostream& os = debugger.getOS();
00073       int n(0);
00074       ContextObjChain* tmp = obj;
00075       while(tmp != NULL) {
00076         tmp = tmp->d_restoreChainNext;
00077         n++;
00078       }
00079       os << "*** Warning: ~Scope(): found "<< n << " leaked objects "
00080          << "in scope " << d_level << ":" << endl;
00081       if(debugger.flag("memory leaks")) {
00082         tmp = obj;
00083         while(tmp != NULL) {
00084           os << tmp->name() << "\n";
00085           tmp = tmp->d_restoreChainNext;
00086         }
00087       }
00088       os << flush;
00089     }
00090   )
00091   // Now actually delete the chain
00092   TRACE_MSG("context verbose", "~Scope(): Deleting the chain");
00093   while (obj != NULL) {
00094     ContextObjChain* tmp = obj->d_restoreChainNext;
00095     // When called from ~ContextManager(), the master objects may
00096     // still point to this scope.  Disconnect them here.
00097     if(obj->d_master!=NULL && obj->d_master->d_scope == this)
00098       obj->d_master->d_scope = NULL;
00099     delete obj;
00100     obj = tmp;
00101   }
00102   TRACE_MSG("context verbose", "~Scope() => }");
00103 }
00104 
00105 
00106 void Scope::restore(void)
00107 {
00108   TRACE_MSG("context verbose", "Scope::restore() {");
00109   d_delayDelete=true;
00110   while (d_restoreChain != NULL) d_restoreChain = d_restoreChain->restore();
00111   d_delayDelete=false;
00112   TRACE_MSG("context verbose", "Scope::restore() }");
00113 }
00114 
00115 
00116 ///////////////////////////////////////////////////////////////////////////////
00117 // ContextObjChain methods                                                   //
00118 ///////////////////////////////////////////////////////////////////////////////
00119 
00120 
00121 ContextObjChain::ContextObjChain(ContextObj* data, ContextObj* master, 
00122                                  ContextObjChain* restore)
00123   : d_restoreChainNext(NULL), d_restoreChainPrev(NULL),
00124     d_restore(restore), d_data(data), d_master(master) { }
00125 
00126 
00127 ContextObjChain* ContextObjChain::restore(void)
00128 {
00129 //   TRACE("context verbose", "ContextObjChain::restore(", name(), ")");
00130   // Assign 'next' pointer only when the master object is restored,
00131   // since this may change our next pointer (master may have other
00132   // context objects removed).
00133   ContextObjChain* next;
00134   if(d_master==NULL) { // We are marked for deletion.  Do nothing.
00135     next = d_restoreChainNext;
00136   } else if(d_data == NULL) {
00137     d_master->setNull();
00138     Scope*& masterScope(d_master->d_scope);
00139     masterScope = d_master->d_scope->prevScope();
00140 //     DebugAssert(masterScope == masterScope->topScope(),"");
00141     DebugAssert(d_restore==NULL,"Expected NULL");
00142     next = d_restoreChainNext;
00143     masterScope->addToChain(this);
00144   }
00145   else {
00146     d_master->restoreData(d_data); // Data will be deleted in destructor
00147     d_master->d_scope = d_data->d_scope;
00148     d_master->d_restore = d_restore;
00149     next = d_restoreChainNext;
00150     delete this;
00151   }
00152   return next;
00153 }
00154 
00155 
00156 ContextObjChain::~ContextObjChain()
00157 {
00158 //   TRACE("context verbose", "~ContextObjChain(d_data=", name(), ")");
00159   if(d_data != NULL) delete d_data;
00160   // Disconnect the master object if it points to us; this may happen
00161   // within ~ContextManager() call.
00162   if(d_master!=NULL && d_master->d_restore == this)
00163     d_master->d_restore = NULL;
00164 }
00165 
00166 
00167 IF_DEBUG(
00168 std::string 
00169 ContextObjChain::name() const {
00170   if(d_master == NULL) return "Unknown";
00171   return d_master->name();
00172 }
00173 )
00174 
00175 ///////////////////////////////////////////////////////////////////////////////
00176 // ContextObj methods                                                        //
00177 ///////////////////////////////////////////////////////////////////////////////
00178 
00179 ContextObj::ContextObj(const ContextObj& co)
00180   : d_scope(co.d_scope), d_restore(co.d_restore) {
00181   IF_DEBUG(d_name=co.d_name);
00182   DebugAssert(co.d_active, "ContextObj["+co.name()+"] copy constructor");
00183   IF_DEBUG(d_active = co.d_active);
00184   TRACE("context verbose", "ContextObj()[", this, "]: copy constructor");
00185 }
00186 
00187 
00188 ContextObj& ContextObj::operator=(const ContextObj& co) {
00189   DebugAssert(false, "ContextObj::operator=(): shouldn't be called");
00190   return *this;
00191 }
00192 
00193 
00194 void ContextObj::update(int scope)
00195 {
00196 //   TRACE("context verbose", "update(", name(), ")");
00197 //   IF_DEBUG
00198 //     (static DebugTimer accum(debugger.timer("ContextObj::update time"));
00199 //      static DebugTimer tmpTimer(debugger.newTimer());
00200 //      static DebugCounter
00201 //        updateCalls(debugger.counter("ContextObject::update calls"));
00202 //      updateCalls++; debugger.setCurrentTime(tmpTimer));
00203   ContextObj* data = makeCopy();
00204   data->d_scope=d_scope;
00205   // The destructor of the copy should not destroy our older copies
00206   data->d_restore=NULL;
00207   IF_DEBUG(data->setName(name()+" [copy]"));
00208   ContextObjChain* obj = new ContextObjChain(data, this, d_restore);
00209   d_restore = obj;
00210   DebugAssert(scope < 0 || d_scope->level() < scope,
00211               "ContextObj::update(scope="+int2string(scope)
00212               +"): scope < d_scope->level() = "
00213               +int2string(d_scope->level()));
00214   d_scope = d_scope->topScope();
00215   if(scope >= 0) {
00216     // Fetch the specified scope
00217     for(int i=level(); i>scope; --i) {
00218       d_scope = d_scope->prevScope();
00219       DebugAssert(d_scope != NULL, "ContextObj::update["
00220                   +name()+"]: d_scope == NULL");
00221     }
00222   }
00223   d_scope->addToChain(obj);
00224 //   IF_DEBUG(debugger.setElapsed(tmpTimer); accum += tmpTimer);
00225 }
00226 
00227 // Create a new ContextObj.  The initial scope is set to the bottom
00228 // scope by default, to reduce the work of pop() (otherwise, if the
00229 // object is defined only on a very high scope, its scope will be
00230 // moved down with each pop).  If 'atBottomScope' == false, the
00231 // scope is set to the current scope.
00232 ContextObj::ContextObj(Context* context, bool atBottomScope)
00233   IF_DEBUG(: d_name("ContextObj"))
00234 {
00235   IF_DEBUG(d_active=true);
00236   DebugAssert(context != NULL, "NULL context pointer");
00237   if(atBottomScope) d_scope = context->bottomScope();
00238   else d_scope = context->topScope();
00239   d_restore = new ContextObjChain(NULL, this, NULL);
00240   d_scope->addToChain(d_restore);
00241   TRACE("context verbose", "ContextObj()[", this, "]");
00242 }
00243 
00244 
00245 ContextObj::~ContextObj()
00246 {
00247 //   TRACE("context verbose", "~ContextObj(", name(), ")");
00248   // Delete our restore copies
00249   TRACE("context verbose",
00250         string("~ContextObj(")+(d_scope && d_scope->d_delayDelete? "delayed" : "")+")[",
00251         this, "] {");
00252   DebugAssert(d_scope==NULL || !d_scope->d_delayDelete,
00253               "~ContextObj["+name()+"]");
00254   DebugAssert(d_active, "~ContextObj["+name()+"]");
00255   IF_DEBUG(d_active=false); 
00256 //   if(d_scope->d_delayDelete) {
00257 //     (d_scope->d_deleted).push_back(d_restore);
00258 //     // Mark the chain as "deleted"
00259 //     d_restore->d_master=NULL;
00260 //   } else {
00261   for(ContextObjChain* obj = d_restore; obj != NULL; ) {
00262     ContextObjChain* tmp = obj->d_restore;
00263     // Remove the object from the restore chain
00264     if(obj->d_restoreChainNext != NULL)
00265       obj->d_restoreChainNext->d_restoreChainPrev = obj->d_restoreChainPrev;
00266     *(obj->d_restoreChainPrev) = obj->d_restoreChainNext;
00267     // Delete the object and move to the next
00268     delete obj;
00269     obj = tmp;
00270   }
00271 //   }
00272   TRACE("context verbose", "~ContextObj()[", this, "] }");
00273 }
00274 
00275 
00276 ///////////////////////////////////////////////////////////////////////////////
00277 // Context methods                                                           //
00278 ///////////////////////////////////////////////////////////////////////////////
00279 
00280 
00281 Context::Context(ContextManager* cm, const string& name, int id)
00282   : d_cm(cm), d_name(name), d_id(id)
00283 {
00284   d_topScope = new Scope(this);
00285   d_bottomScope = d_topScope;
00286   TRACE("context", "*** [context] Creating new context: name = "
00287         + name + "id = ", id, "");
00288 }
00289 
00290 
00291 // Don't pop, just delete everything.  At this point, most of the
00292 // system is already destroyed, popping may be dangerous.
00293 Context::~Context()
00294 {
00295   // popto(0);
00296   Scope* top = d_topScope;
00297   while(top != NULL) {
00298     top = d_topScope->prevScope();
00299     delete d_topScope;
00300     d_topScope = top;
00301   }
00302   // Erase ourselves from the notify objects, so they don't call us
00303   for(vector<ContextNotifyObj*>::iterator i=d_notifyObjList.begin(),
00304         iend=d_notifyObjList.end(); i!=iend; ++i) {
00305     (*i)->d_context = NULL;
00306   }
00307   // Do not delete d_bottomScope, it's deleted with the last d_topScope.
00308 }
00309 
00310 
00311 void Context::pop()
00312 {
00313 //   IF_DEBUG
00314 //     (static DebugTimer accum(debugger.timer("Context::pop time"));
00315 //      static DebugTimer tmpTimer(debugger.newTimer());
00316 //      static DebugCounter calls(debugger.counter("Context::pop calls"));
00317 //      calls++; debugger.setCurrentTime(tmpTimer));
00318   Scope* top = d_topScope;
00319   TRACE("context", "*** [context] Popping scope from level ", level(), "...");
00320   DebugAssert(top->prevScope() != NULL,
00321               "Illegal to pop last scope off of stack.");
00322   // Notify before popping the scope
00323   for(vector<ContextNotifyObj*>::iterator i=d_notifyObjList.begin(),
00324         iend=d_notifyObjList.end(); i != iend; ++i)
00325     (*i)->notifyPre();
00326   // Pop the scope
00327   d_topScope = top->prevScope();
00328   top->restore();
00329   delete top;
00330   // Notify after the pop is done
00331   for(vector<ContextNotifyObj*>::iterator i=d_notifyObjList.begin(),
00332         iend=d_notifyObjList.end(); i != iend; ++i)
00333     (*i)->notify();
00334   TRACE("context", "*** [context] Popped scope to level ", level(), "}");
00335 //   IF_DEBUG(debugger.setElapsed(tmpTimer); accum += tmpTimer);
00336 }
00337 
00338 
00339 void Context::popto(int toLevel)
00340 {
00341   //TODO: more efficient implementation?
00342   // TRACE("context", "Context::popto(", toLevel, ") {");
00343   while (toLevel < topScope()->level()) pop();
00344   // TRACE("context", "Context::popto(", toLevel, ") => }");
00345 }
00346 
00347 
00348 void Context::deleteNotifyObj(ContextNotifyObj* obj) {
00349   size_t i(0), iend(d_notifyObjList.size());
00350   for(; i<iend && d_notifyObjList[i]!=obj; ++i);
00351   if(i<iend) { // Found obj; delete it from the vector
00352     d_notifyObjList[i]=d_notifyObjList.back();
00353     d_notifyObjList.pop_back();
00354   }
00355 }
00356 
00357 
00358 ///////////////////////////////////////////////////////////////////////////////
00359 // ContextManager methods                                                    //
00360 ///////////////////////////////////////////////////////////////////////////////
00361 
00362 
00363 ContextManager::ContextManager()
00364 {
00365   d_curContext = createContext("default");
00366 }
00367 
00368 
00369 ContextManager::~ContextManager()
00370 {
00371   while (d_contexts.size()) {
00372     delete d_contexts.back();
00373     d_contexts.pop_back();
00374   }
00375 }
00376 
00377 
00378 Context* ContextManager::createContext(const string& name)
00379 {
00380   d_contexts.push_back(new Context(this, name, d_contexts.size()));
00381   return d_contexts.back();
00382 }
00383 
00384 
00385 Context* ContextManager::switchContext(Context* context)
00386 {
00387   DebugAssert(false, "Multiple contexts not yet implemented");
00388   Context* old = d_curContext;
00389   DebugAssert(context && context == d_contexts[context->id()],
00390               "Unknown context");
00391   d_curContext = context;
00392   // TODO: Fix up all Context Objects
00393   return old;
00394 }

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