summaryrefslogtreecommitdiff
path: root/src/context
diff options
context:
space:
mode:
Diffstat (limited to 'src/context')
-rw-r--r--src/context/cdmap.h14
-rw-r--r--src/context/cdo.h38
-rw-r--r--src/context/context.cpp138
-rw-r--r--src/context/context.h168
-rw-r--r--src/context/context_mm.cpp3
5 files changed, 299 insertions, 62 deletions
diff --git a/src/context/cdmap.h b/src/context/cdmap.h
index d4de88daf..75f6eb2ae 100644
--- a/src/context/cdmap.h
+++ b/src/context/cdmap.h
@@ -71,6 +71,7 @@ class CDOmap : public ContextObj {
}
d_next->d_prev = d_prev;
d_prev->d_next = d_next;
+ Debug("gc") << "CDMap<> trash push_back " << this << std::endl;
d_map->d_trash.push_back(this);
} else {
d_data = p->d_data;
@@ -155,7 +156,7 @@ public:
CDMapData(Context* context) : ContextObj(context) {}
CDMapData(const ContextObj& co) : ContextObj(co) {}
- ~CDMapData() { destroy(); }
+ ~CDMapData() throw(AssertionException) { destroy(); }
};
/**
@@ -192,7 +193,7 @@ class CDMap : public ContextObj {
i != d_trash.end();
++i) {
Debug("gc") << "emptyTrash(): " << *i << std::endl;
- //(*i)->deleteSelf();
+ (*i)->deleteSelf();
}
d_trash.clear();
}
@@ -201,21 +202,26 @@ public:
CDMap(Context* context) :
ContextObj(context),
+ d_map(),
d_first(NULL),
d_context(context),
d_trash() {
}
~CDMap() throw(AssertionException) {
+ Debug("gc") << "cdmap " << this
+ << " disappearing, destroying..." << std::endl;
destroy();
+ Debug("gc") << "cdmap " << this
+ << " disappearing, done destroying" << std::endl;
for(typename table_type::iterator i = d_map.begin();
i != d_map.end();
++i) {
(*i).second->deleteSelf();
}
- //d_map.clear();
- Debug("gc") << "cdmap gone, emptying trash" << std::endl;
+ Debug("gc") << "cdmap " << this << " gone, emptying trash" << std::endl;
emptyTrash();
+ Debug("gc") << "done emptying trash for " << this << std::endl;
}
// The usual operators of map
diff --git a/src/context/cdo.h b/src/context/cdo.h
index e03156e8a..ead43b2e8 100644
--- a/src/context/cdo.h
+++ b/src/context/cdo.h
@@ -66,11 +66,26 @@ class CDO : public ContextObj {
CDO<T>& operator=(const CDO<T>& cdo);
public:
+
/**
* Main constructor - uses default constructor for T to create the initial
* value of d_data.
*/
- CDO(Context* context) : ContextObj(context) {}
+ CDO(Context* context) :
+ ContextObj(context) {
+ }
+
+ /**
+ * Main constructor - uses default constructor for T to create the
+ * initial value of d_data.
+ *
+ * This version takes an argument that specifies whether this CDO<>
+ * was itself allocated in context memory. If it was, it is linked
+ * with the current scope rather than scope 0.
+ */
+ CDO(bool allocatedInCMM, Context* context) :
+ ContextObj(allocatedInCMM, context) {
+ }
/**
* Constructor from object of type T. Creates a ContextObj and sets the data
@@ -78,7 +93,24 @@ public:
* current Scope. If the Scope is popped, the value will revert to whatever
* is assigned by the default constructor for T
*/
- CDO(Context* context, const T& data) : ContextObj(context) {
+ CDO(Context* context, const T& data) :
+ ContextObj(context) {
+ makeCurrent();
+ d_data = data;
+ }
+
+ /**
+ * Constructor from object of type T. Creates a ContextObj and sets the data
+ * to the given data value. Note that this value is only valid in the
+ * current Scope. If the Scope is popped, the value will revert to whatever
+ * is assigned by the default constructor for T.
+ *
+ * This version takes an argument that specifies whether this CDO<>
+ * was itself allocated in context memory. If it was, it is linked
+ * with the current scope rather than scope 0.
+ */
+ CDO(bool allocatedInCMM, Context* context, const T& data) :
+ ContextObj(allocatedInCMM, context) {
makeCurrent();
d_data = data;
}
@@ -86,7 +118,7 @@ public:
/**
* Destructor - call destroy() method
*/
- ~CDO() throw() { destroy(); }
+ ~CDO() throw(AssertionException) { destroy(); }
/**
* Set the data in the CDO. First call makeCurrent.
diff --git a/src/context/context.cpp b/src/context/context.cpp
index 05024430c..d371dc39a 100644
--- a/src/context/context.cpp
+++ b/src/context/context.cpp
@@ -10,9 +10,13 @@
** See the file COPYING in the top-level source directory for licensing
** information.
**
+ ** Implementation of base context operations.
**/
+#include <iostream>
+#include <vector>
+
#include "context/context.h"
#include "util/Assert.h"
@@ -54,7 +58,7 @@ Context::~Context() throw(AssertionException) {
void Context::push() {
- // FIXME: TRACE("pushpop", indentStr, "Push", " {");
+ Trace("pushpop") << std::string(2 * getLevel(), ' ') << "Push {" << std::endl;
// Create a new memory region
d_pCMM->push();
@@ -93,7 +97,7 @@ void Context::pop() {
pCNO = pCNO->d_pCNOnext;
}
- //FIXME: TRACE("pushpop", indentStr, "}", " Pop");
+ Trace("pushpop") << std::string(2 * getLevel(), ' ') << "} Pop" << std::endl;
}
@@ -124,16 +128,47 @@ void Context::addNotifyObjPost(ContextNotifyObj* pCNO) {
}
-void ContextObj::update() {
+void ContextObj::update() throw(AssertionException) {
+ Debug("context") << "before update(" << this << "):" << std::endl
+ << *getContext() << std::endl;
+
// Call save() to save the information in the current object
ContextObj* pContextObjSaved = save(d_pScope->getCMM());
+ Debug("context") << "in update(" << this << ") with restore "
+ << pContextObjSaved << ": waypoint 1" << std::endl
+ << *getContext() << std::endl;
+
// Check that base class data was saved
- Assert(pContextObjSaved->d_pContextObjNext == d_pContextObjNext &&
- pContextObjSaved->d_ppContextObjPrev == d_ppContextObjPrev &&
- pContextObjSaved->d_pContextObjRestore == d_pContextObjRestore &&
- pContextObjSaved->d_pScope == d_pScope,
- "save() did not properly copy information in base class");
+ Assert( ( pContextObjSaved->d_pContextObjNext == d_pContextObjNext &&
+ pContextObjSaved->d_ppContextObjPrev == d_ppContextObjPrev &&
+ pContextObjSaved->d_pContextObjRestore == d_pContextObjRestore &&
+ pContextObjSaved->d_pScope == d_pScope ),
+ "save() did not properly copy information in base class" );
+
+ // Link the "saved" object in place of this ContextObj in the scope
+ // we're moving it FROM.
+ Debug("context") << "in update(" << this
+ << "): next() == " << next() << std::endl;
+ if(next() != NULL) {
+ Debug("context") << "in update(" << this
+ << "): next()->prev() == " << next()->prev() << std::endl;
+ next()->prev() = &pContextObjSaved->next();
+ Debug("context") << "in update(" << this
+ << "): next()->prev() is now "
+ << next()->prev() << std::endl;
+ }
+ Debug("context") << "in update(" << this
+ << "): prev() == " << prev() << std::endl;
+ Debug("context") << "in update(" << this
+ << "): *prev() == " << *prev() << std::endl;
+ *prev() = pContextObjSaved;
+ Debug("context") << "in update(" << this
+ << "): *prev() is now " << *prev() << std::endl;
+
+ Debug("context") << "in update(" << this << ") with restore "
+ << pContextObjSaved << ": waypoint 3" << std::endl
+ << *getContext() << std::endl;
// Update Scope pointer to current top Scope
d_pScope = d_pScope->getContext()->getTopScope();
@@ -144,18 +179,27 @@ void ContextObj::update() {
// Insert object into the list of objects that need to be restored when this
// Scope is popped.
d_pScope->addToChain(this);
+
+ Debug("context") << "after update(" << this << ") with restore "
+ << pContextObjSaved << ":" << std::endl
+ << *getContext() << std::endl;
}
-ContextObj* ContextObj::restoreAndContinue() {
+ContextObj* ContextObj::restoreAndContinue() throw(AssertionException) {
// Variable to hold next object in list
ContextObj* pContextObjNext;
// Check the restore pointer. If NULL, this must be the bottom Scope
if(d_pContextObjRestore == NULL) {
- Assert(d_pScope == d_pScope->getContext()->getBottomScope(),
- "Expected bottom scope");
+ // might not be bottom scope, since objects allocated in context
+ // memory don't get linked to scope 0
+ //
+ // Assert(d_pScope == d_pScope->getContext()->getBottomScope(),
+ // "Expected bottom scope");
+
pContextObjNext = d_pContextObjNext;
+
// Nothing else to do
} else {
// Call restore to update the subclass data
@@ -169,13 +213,23 @@ ContextObj* ContextObj::restoreAndContinue() {
next() = d_pContextObjRestore->d_pContextObjNext;
prev() = d_pContextObjRestore->d_ppContextObjPrev;
d_pContextObjRestore = d_pContextObjRestore->d_pContextObjRestore;
+
+ // Re-link this ContextObj to the list in this scope
+ if(next() != NULL) {
+ next()->prev() = &next();
+ }
+ *prev() = this;
}
+
// Return the next object in the list
return pContextObjNext;
}
void ContextObj::destroy() throw(AssertionException) {
+ Debug("context") << "before destroy " << this
+ << " (level " << getLevel() << "):" << std::endl
+ << *getContext() << std::endl;
for(;;) {
// If valgrind reports invalid writes on the next few lines,
// here's a hint: make sure all classes derived from ContextObj in
@@ -184,12 +238,18 @@ void ContextObj::destroy() throw(AssertionException) {
if(next() != NULL) {
next()->prev() = prev();
}
- *(prev()) = next();
+ *prev() = next();
if(d_pContextObjRestore == NULL) {
break;
}
+ Debug("context") << "in destroy " << this << ", restore object is "
+ << d_pContextObjRestore << " at level "
+ << d_pContextObjRestore->getLevel() << ":" << std::endl
+ << *getContext() << std::endl;
restoreAndContinue();
}
+ Debug("context") << "after destroy " << this << ":" << std::endl
+ << *getContext() << std::endl;
}
@@ -198,11 +258,27 @@ ContextObj::ContextObj(Context* pContext) :
Assert(pContext != NULL, "NULL context pointer");
+ Debug("context") << "create new ContextObj(" << this << ")" << std::endl;
d_pScope = pContext->getBottomScope();
d_pScope->addToChain(this);
}
+ContextObj::ContextObj(bool allocatedInCMM, Context* pContext) :
+ d_pContextObjRestore(NULL) {
+
+ Assert(pContext != NULL, "NULL context pointer");
+
+ Debug("context") << "create new ContextObj(" << this << ")" << std::endl;
+ if(allocatedInCMM) {
+ d_pScope = pContext->getTopScope();
+ } else {
+ d_pScope = pContext->getBottomScope();
+ }
+ d_pScope->addToChain(this);
+}
+
+
ContextNotifyObj::ContextNotifyObj(Context* pContext, bool preNotify) {
if(preNotify) {
pContext->addNotifyObjPre(this);
@@ -217,8 +293,44 @@ ContextNotifyObj::~ContextNotifyObj() throw(AssertionException) {
d_pCNOnext->d_ppCNOprev = d_ppCNOprev;
}
if(d_ppCNOprev != NULL) {
- *(d_ppCNOprev) = d_pCNOnext;
+ *d_ppCNOprev = d_pCNOnext;
+ }
+}
+
+
+std::ostream& operator<<(std::ostream& out,
+ const Context& context) throw(AssertionException) {
+ const std::string separator(79, '-');
+
+ int level = context.d_scopeList.size() - 1;
+ typedef std::vector<Scope*>::const_reverse_iterator const_reverse_iterator;
+ for(const_reverse_iterator i = context.d_scopeList.rbegin();
+ i != context.d_scopeList.rend();
+ ++i, --level) {
+ Scope* pScope = *i;
+ Assert(pScope->getLevel() == level);
+ Assert(pScope->getContext() == &context);
+ out << separator << std::endl
+ << *pScope << std::endl;
+ }
+ return out << separator << std::endl;
+}
+
+
+std::ostream& operator<<(std::ostream& out,
+ const Scope& scope) throw(AssertionException) {
+ out << "Scope " << scope.d_level << ":";
+ ContextObj* pContextObj = scope.d_pContextObjList;
+ Assert(pContextObj == NULL ||
+ pContextObj->prev() == &scope.d_pContextObjList);
+ while(pContextObj != NULL) {
+ out << " <--> " << pContextObj;
+ Assert(pContextObj->d_pScope == &scope);
+ Assert(pContextObj->next() == NULL ||
+ pContextObj->next()->prev() == &pContextObj->next());
+ pContextObj = pContextObj->next();
}
+ return out << " --> NULL";
}
diff --git a/src/context/context.h b/src/context/context.h
index 0e2a9107f..ff650ce5d 100644
--- a/src/context/context.h
+++ b/src/context/context.h
@@ -18,13 +18,15 @@
#ifndef __CVC4__CONTEXT__CONTEXT_H
#define __CVC4__CONTEXT__CONTEXT_H
-#include "context/context_mm.h"
-#include "util/Assert.h"
-
+#include <iostream>
#include <cstdlib>
#include <cstring>
+#include <vector>
#include <new>
+#include "context/context_mm.h"
+#include "util/Assert.h"
+
namespace CVC4 {
namespace context {
@@ -33,6 +35,14 @@ class Scope;
class ContextObj;
class ContextNotifyObj;
+/** Pretty-printing of Contexts (for debugging) */
+std::ostream&
+operator<<(std::ostream&, const Context&) throw(AssertionException);
+
+/** Pretty-printing of Scopes (for debugging) */
+std::ostream&
+operator<<(std::ostream&, const Scope&) throw(AssertionException);
+
/**
* A Context encapsulates all of the dynamic state of the system. Its main
* methods are push() and pop(). A call to push() saves the current state,
@@ -78,6 +88,9 @@ class Context {
*/
ContextNotifyObj* d_pCNOpost;
+ friend std::ostream&
+ operator<<(std::ostream&, const Context&) throw(AssertionException);
+
public:
/**
* Constructor: create ContextMemoryManager and initial Scope
@@ -102,7 +115,7 @@ public:
/**
* Return the current Scope level.
*/
- int getLevel() const { return ((int)d_scopeList.size()) - 1; }
+ int getLevel() const { return d_scopeList.size() - 1; }
/**
* Return the ContextMemoryManager associated with the context.
@@ -176,13 +189,16 @@ class Scope {
*/
ContextObj* d_pContextObjList;
+ friend std::ostream&
+ operator<<(std::ostream&, const Scope&) throw(AssertionException);
+
public:
/**
* Constructor: Create a new Scope; set the level and the previous Scope
* if any.
*/
- Scope(Context* pContext, ContextMemoryManager* pCMM, int level) :
+ Scope(Context* pContext, ContextMemoryManager* pCMM, int level) throw() :
d_pContext(pContext),
d_pCMM(pCMM),
d_level(level),
@@ -193,38 +209,38 @@ public:
* Destructor: Restore all of the objects in ContextObjList. Defined inline
* below.
*/
- ~Scope() throw();
+ ~Scope() throw(AssertionException);
/**
* Get the Context for this Scope
*/
- Context* getContext() const { return d_pContext; }
+ Context* getContext() const throw() { return d_pContext; }
/**
* Get the ContextMemoryManager for this Scope
*/
- ContextMemoryManager* getCMM() const { return d_pCMM; }
+ ContextMemoryManager* getCMM() const throw() { return d_pCMM; }
/**
* Get the level of the current Scope
*/
- int getLevel() const { return d_level; }
+ int getLevel() const throw() { return d_level; }
/**
* Return true iff this Scope is the current top Scope
*/
- bool isCurrent() const { return this == d_pContext->getTopScope(); }
+ bool isCurrent() const throw() { return this == d_pContext->getTopScope(); }
/**
- * When a ContextObj object is modified for the first time in this Scope, it
- * should call this method to add itself to the list of objects that will
- * need to be restored. Defined inline below.
+ * When a ContextObj object is modified for the first time in this
+ * Scope, it should call this method to add itself to the list of
+ * objects that will need to be restored. Defined inline below.
*/
- void addToChain(ContextObj* pContextObj);
+ void addToChain(ContextObj* pContextObj) throw(AssertionException);
/**
- * Overload operator new for use with ContextMemoryManager to allow creation
- * of new Scope objects in the current memory region.
+ * Overload operator new for use with ContextMemoryManager to allow
+ * creation of new Scope objects in the current memory region.
*/
static void* operator new(size_t size, ContextMemoryManager* pCMM) {
return pCMM->newData(size);
@@ -232,9 +248,10 @@ public:
/**
* Overload operator delete for Scope objects allocated using
- * ContextMemoryManager. No need to do anything because memory is freed
- * automatically when the ContextMemoryManager pop() method is called.
- * Include both placement and standard delete for completeness.
+ * ContextMemoryManager. No need to do anything because memory is
+ * freed automatically when the ContextMemoryManager pop() method is
+ * called. Include both placement and standard delete for
+ * completeness.
*/
static void operator delete(void* pMem, ContextMemoryManager* pCMM) {}
static void operator delete(void* pMem) {}
@@ -245,9 +262,9 @@ public:
};/* class Scope */
/**
- * This is an abstract base class from which all objects that are context-dependent
- * should inherit. For any data structure that you want to have be
- * automatically backtracked, do the following:
+ * This is an abstract base class from which all objects that are
+ * context-dependent should inherit. For any data structure that you
+ * want to have be automatically backtracked, do the following:
* 1. Create a class for the data structure that inherits from ContextObj
* 2. Implement save()
* The role of save() is to create a new ContexObj object that contains
@@ -310,31 +327,34 @@ class ContextObj {
* does the necessary bookkeeping to ensure that object can be restored to
* its current state when restore is called.
*/
- void update();
+ void update() throw(AssertionException);
// The rest of the private methods are for the benefit of the Scope. We make
// Scope our friend so it is the only one that can use them.
friend class Scope;
+ friend std::ostream&
+ operator<<(std::ostream&, const Scope&) throw(AssertionException);
+
/**
* Return reference to next link in ContextObjList. Used by
* Scope::addToChain method.
*/
- ContextObj*& next() { return d_pContextObjNext; }
+ ContextObj*& next() throw() { return d_pContextObjNext; }
/**
* Return reference to prev link in ContextObjList. Used by
* Scope::addToChain method.
*/
- ContextObj**& prev() { return d_ppContextObjPrev; }
+ ContextObj**& prev() throw() { return d_ppContextObjPrev; }
/**
* This method is called by Scope during a pop: it does the necessary work to
* restore the object from its saved copy and then returns the next object in
* the list that needs to be restored.
*/
- ContextObj* restoreAndContinue();
+ ContextObj* restoreAndContinue() throw(AssertionException);
protected:
@@ -351,14 +371,10 @@ protected:
virtual void restore(ContextObj* pContextObjRestore) = 0;
/**
- * This method checks if the object has been modified in this Scope yet. If
- * not, it calls update().
+ * This method checks if the object has been modified in this Scope
+ * yet. If not, it calls update().
*/
- void makeCurrent() {
- if(!(d_pScope->isCurrent())) {
- update();
- }
- }
+ inline void makeCurrent() throw(AssertionException);
/**
* Should be called from sub-class destructor: calls restore until restored
@@ -369,9 +385,59 @@ protected:
*/
void destroy() throw(AssertionException);
+ /////
+ //
+ // These next four accessors return properties of the Scope to
+ // derived classes without giving them the Scope object directly.
+ //
+ /////
+
+ /**
+ * Get the Context with which this ContextObj was created. This is
+ * part of the protected interface, intended for derived classes to
+ * use if necessary.
+ */
+ Context* getContext() const throw() {
+ return d_pScope->getContext();
+ }
+
+ /**
+ * Get the ContextMemoryManager with which this ContextObj was
+ * created. This is part of the protected interface, intended for
+ * derived classes to use if necessary. If a ContextObj-derived
+ * class needs to allocate memory somewhere other than the save()
+ * member function (where it is explicitly given a
+ * ContextMemoryManager), it can use this accessor to get the memory
+ * manager.
+ */
+ ContextMemoryManager* getCMM() const throw() {
+ return d_pScope->getCMM();
+ }
+
+ /**
+ * Get the level associated to this ContextObj. Useful if a
+ * ContextObj-derived class needs to compare the level of its last
+ * update with another ContextObj.
+ */
+ int getLevel() const throw() {
+ return d_pScope->getLevel();
+ }
+
+ /**
+ * Returns true if the object is "current"-- that is, updated in the
+ * topmost contextual scope. Useful if a ContextObj-derived class
+ * needs to determine if it has been modified in the current scope.
+ * Note that it is always safe to call makeCurrent() without first
+ * checking if the object is current, so this function need not be
+ * used under normal circumstances.
+ */
+ bool isCurrent() const throw() {
+ return d_pScope->isCurrent();
+ }
+
/**
* operator new using ContextMemoryManager (common case used by
- * subclasses during save() ). No delete is required for memory
+ * subclasses during save()). No delete is required for memory
* allocated this way, since it is automatically released when the
* context is popped. Also note that allocations using this
* operator never have their destructor called, so any clean-up has
@@ -402,9 +468,17 @@ public:
ContextObj(Context* context);
/**
+ * Create a new ContextObj. This constructor takes an argument that
+ * specifies whether this ContextObj is itself allocated in context
+ * memory. If it is, it's invalid below the current scope level, so
+ * we don't put it in scope 0.
+ */
+ ContextObj(bool allocatedInCMM, Context* context);
+
+ /**
* Destructor does nothing: subclass must explicitly call destroy() instead.
*/
- virtual ~ContextObj() { Debug("contextgc") << "context obj dest" << std::endl; }
+ virtual ~ContextObj() {}
/**
* If you want to allocate a ContextObj object on the heap, use this
@@ -431,6 +505,7 @@ public:
* ContextMemoryManager as an argument.
*/
void deleteSelf() {
+ Debug("context") << "deleteSelf(" << this << ")" << std::endl;
this->~ContextObj();
::operator delete(this);
}
@@ -475,15 +550,16 @@ class ContextNotifyObj {
* Return reference to next link in ContextNotifyObj list. Used by
* Context::addNotifyObj methods.
*/
- ContextNotifyObj*& next() { return d_pCNOnext; }
+ ContextNotifyObj*& next() throw() { return d_pCNOnext; }
/**
* Return reference to prev link in ContextNotifyObj list. Used by
* Context::addNotifyObj methods.
*/
- ContextNotifyObj**& prev() { return d_ppCNOprev; }
+ ContextNotifyObj**& prev() throw() { return d_ppCNOprev; }
public:
+
/**
* Constructor for ContextNotifyObj. Parameters are the context to
* which this notify object will be added, and a flag which, if
@@ -504,11 +580,16 @@ public:
* implemented by the subclass.
*/
virtual void notify() = 0;
+
};/* class ContextNotifyObj */
-// Inline functions whose definitions had to be delayed:
+inline void ContextObj::makeCurrent() throw(AssertionException) {
+ if(!(d_pScope->isCurrent())) {
+ update();
+ }
+}
-inline Scope::~Scope() throw() {
+inline Scope::~Scope() throw(AssertionException) {
// Call restore() method on each ContextObj object in the list.
// Note that it is the responsibility of restore() to return the
// next item in the list.
@@ -517,9 +598,12 @@ inline Scope::~Scope() throw() {
}
}
-inline void Scope::addToChain(ContextObj* pContextObj) {
- if(d_pContextObjList != NULL)
- d_pContextObjList->prev() = &(pContextObj->next());
+inline void
+Scope::addToChain(ContextObj* pContextObj) throw(AssertionException) {
+ if(d_pContextObjList != NULL) {
+ d_pContextObjList->prev() = &pContextObj->next();
+ }
+
pContextObj->next() = d_pContextObjList;
pContextObj->prev() = &d_pContextObjList;
d_pContextObjList = pContextObj;
diff --git a/src/context/context_mm.cpp b/src/context/context_mm.cpp
index ab81c7486..b0b015681 100644
--- a/src/context/context_mm.cpp
+++ b/src/context/context_mm.cpp
@@ -85,6 +85,9 @@ void* ContextMemoryManager::newData(size_t size) {
AlwaysAssert(d_nextFree <= d_endChunk,
"Request is bigger than memory chunk size");
}
+ Debug("context") << "ContextMemoryManager::newData(" << size
+ << ") returning " << res << " at level "
+ << d_chunkList.size() << std::endl;
return res;
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback