Actual source code: ALE_mem.hh

  1: #ifndef included_ALE_mem_hh
  2: #define included_ALE_mem_hh
  3: // This should be included indirectly -- only by including ALE.hh


  6: #include <memory>
  7: #include <typeinfo>
  8: #include <petsc.h>
  9: #include <ALE_log.hh>

 11: #ifdef ALE_HAVE_CXX_ABI
 12: #include <cxxabi.h>
 13: #endif

 15: namespace ALE {
 16:   template <class T>
 17:   static const char *getClassName() {
 18:     const std::type_info& id = typeid(T);
 19:     const char *id_name;

 21: #ifdef ALE_HAVE_CXX_ABI
 22:       // If the C++ ABI API is available, we can use it to demangle the class name provided by type_info.
 23:       // Here we assume the industry standard C++ ABI as described in http://www.codesourcery.com/cxx-abi/abi.html.
 24:       int   status;
 25:       char *id_name_demangled = abi::__cxa_demangle(id.name(), NULL, NULL, &status);

 27:       if (status != 0) {
 28:         id_name = id.name();
 29:       } else {
 30:         id_name = id_name_demangled;
 31:       }
 32: #else
 33:       id_name = id.name();
 34: #endif
 35:       return id_name;
 36:   };
 37:   template <class T>
 38:   static void restoreClassName(const char *id_name) {
 39: #ifdef ALE_HAVE_CXX_ABI
 40:     // Free the name malloc'ed by __cxa_demangle
 41:     free((char *) id_name);
 42: #endif
 43:   };

 45:   // This UNIVERSAL allocator class is static and provides allocation/deallocation services to all allocators defined below.
 46:   class universal_allocator {
 47:   public:
 48:     typedef std::size_t size_type;
 49:     static char*     allocate(const size_type& sz);
 50:     static void      deallocate(char *p, const size_type& sz);
 51:     static size_type max_size();
 52:   };

 54:   // This allocator implements create and del methods, that act roughly as new and delete in that they invoke a constructor/destructor
 55:   // in addition to memory allocation/deallocation.
 56:   // An additional (and potentially dangerous) feature allows an object of any type to be deleted so long as its size has been provided.
 57:   template <class T>
 58:   class polymorphic_allocator {
 59:   public:
 60:     typedef typename std::allocator<T> Alloc;
 61:     // A specific allocator -- alloc -- of type Alloc is used to define the correct types and implement methods
 62:     // that do not allocate/deallocate memory themselves -- the universal _alloc is used for that (and only that).
 63:     // The relative size sz is used to calculate the amount of memory to request from _alloc to satisfy a request to alloc.
 64:     typedef typename Alloc::size_type       size_type;
 65:     typedef typename Alloc::difference_type difference_type;
 66:     typedef typename Alloc::pointer         pointer;
 67:     typedef typename Alloc::const_pointer   const_pointer;
 68:     typedef typename Alloc::reference       reference;
 69:     typedef typename Alloc::const_reference const_reference;
 70:     typedef typename Alloc::value_type      value_type;

 72:     static Alloc alloc;                            // The underlying specific allocator
 73:     static typename Alloc::size_type sz;           // The size of T universal units of char

 75:     polymorphic_allocator()                                    {};
 76:     polymorphic_allocator(const polymorphic_allocator& a)      {};
 77:     template <class TT>
 78:     polymorphic_allocator(const polymorphic_allocator<TT>& aa){};
 79:     ~polymorphic_allocator() {};

 81:     // Reproducing the standard allocator interface
 82:     pointer       address(reference _x) const          { return alloc.address(_x);                                    };
 83:     const_pointer address(const_reference _x) const    { return alloc.address(_x);                                    };
 84:     T*            allocate(size_type _n)               { return (T*)universal_allocator::allocate(_n*sz);            };
 85:     void          deallocate(pointer _p, size_type _n) { universal_allocator::deallocate((char*)_p, _n*sz);           };
 86:     void          construct(pointer _p, const T& _val) { alloc.construct(_p, _val);                                   };
 87:     void          destroy(pointer _p)                  { alloc.destroy(_p);                                           };
 88:     size_type     max_size() const                     { return (size_type)floor(universal_allocator::max_size()/sz); };
 89:     // conversion typedef
 90:     template <class TT>
 91:     struct rebind { typedef polymorphic_allocator<TT> other;};
 92: 
 93:     T*  create(const T& _val = T());
 94:     void del(T* _p);
 95:     template<class TT> void del(TT* _p, size_type _sz);
 96:   };

 98:   template <class T>
 99:   typename polymorphic_allocator<T>::Alloc polymorphic_allocator<T>::alloc;

101:   //IMPORTANT: allocator 'sz' calculation takes place here
102:   template <class T>
103:   typename polymorphic_allocator<T>::size_type polymorphic_allocator<T>::sz =
104:     (typename polymorphic_allocator<T>::size_type)(ceil(sizeof(T)/sizeof(char)));

106:   template <class T>
107:   T* polymorphic_allocator<T>::create(const T& _val) {
108:     // First, allocate space for a single object
109:     T* _p = (T*)universal_allocator::allocate(sz);
110:     // Construct an object in the provided space using the provided initial value
111:     this->alloc.construct(_p,  _val);
112:     return _p;
113:   }

115:   template <class T>
116:   void polymorphic_allocator<T>::del(T* _p) {
117:     _p->~T();
118:     universal_allocator::deallocate((char*)_p, polymorphic_allocator<T>::sz);
119:   }

121:   template <class T> template <class TT>
122:   void polymorphic_allocator<T>::del(TT* _p, size_type _sz) {
123:     _p->~TT();
124:     universal_allocator::deallocate((char*)_p, _sz);
125:   }


128:   // An allocator all of whose events (allocation, deallocation, new, delete) are logged using ALE_log facilities.
129:   // O is true if this is an Obj allocator (that's the intended use, anyhow).
130:   template <class T, bool O = false>
131:   class logged_allocator : public polymorphic_allocator<T> {
132:   private:
133:     static bool        _log_initialized;
134:     static LogCookie   _cookie;
135:     static int         _allocate_event;
136:     static int         _deallocate_event;
137:     static int         _construct_event;
138:     static int         _destroy_event;
139:     static int         _create_event;
140:     static int         _del_event;
141:     //
142:     static void     __log_initialize();
143:     static LogEvent __log_event_register(const char *class_name, const char *event_name);
144: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
145:     // FIX: should PETSc memory logging machinery be wrapped by ALE_log like the rest of the logging stuff?
146:     PetscObject _petscObj; // this object is used to log memory in PETSc
147: #endif
148:     void __alloc_initialize();
149:     void __alloc_finalize();
150:   public:
151:     // Present the correct allocator interface
152:     typedef typename polymorphic_allocator<T>::size_type       size_type;
153:     typedef typename polymorphic_allocator<T>::difference_type difference_type;
154:     typedef typename polymorphic_allocator<T>::pointer         pointer;
155:     typedef typename polymorphic_allocator<T>::const_pointer   const_pointer;
156:     typedef typename polymorphic_allocator<T>::reference       reference;
157:     typedef typename polymorphic_allocator<T>::const_reference const_reference;
158:     typedef typename polymorphic_allocator<T>::value_type      value_type;
159:     //
160:     logged_allocator()                                   : polymorphic_allocator<T>()  {__log_initialize(); __alloc_initialize();};
161:     logged_allocator(const logged_allocator& a)          : polymorphic_allocator<T>(a) {__log_initialize(); __alloc_initialize();};
162:     template <class TT>
163:     logged_allocator(const logged_allocator<TT>& aa)    : polymorphic_allocator<T>(aa){__log_initialize(); __alloc_initialize();};
164:     ~logged_allocator() {__alloc_finalize();};
165:     // conversion typedef
166:     template <class TT>
167:     struct rebind { typedef logged_allocator<TT> other;};

169:     T*   allocate(size_type _n);
170:     void deallocate(T*  _p, size_type _n);
171:     void construct(T* _p, const T& _val);
172:     void destroy(T* _p);

174:     T*  create(const T& _val = T());
175:     void del(T*  _p);
176:     template <class TT> void del(TT* _p, size_type _sz);
177:   };

179:   template <class T, bool O>
180:   bool logged_allocator<T, O>::_log_initialized(false);
181:   template <class T, bool O>
182:   LogCookie logged_allocator<T,O>::_cookie(0);
183:   template <class T, bool O>
184:   int logged_allocator<T, O>::_allocate_event(0);
185:   template <class T, bool O>
186:   int logged_allocator<T, O>::_deallocate_event(0);
187:   template <class T, bool O>
188:   int logged_allocator<T, O>::_construct_event(0);
189:   template <class T, bool O>
190:   int logged_allocator<T, O>::_destroy_event(0);
191:   template <class T, bool O>
192:   int logged_allocator<T, O>::_create_event(0);
193:   template <class T, bool O>
194:   int logged_allocator<T, O>::_del_event(0);
195: 
196:   template <class T, bool O>
197:   void logged_allocator<T, O>::__log_initialize() {
198:     if(!logged_allocator::_log_initialized) {
199:       // First of all we make sure PETSc is initialized
200:       PetscTruth     flag;
201:       PetscErrorCode PetscInitialized(&flag); CHKERROR(ierr, "Error in PetscInitialized");
202:       if(!flag) {
203:         // I guess it would be nice to initialize PETSc here, but we'd need argv/argc here
204:         throw ALE::Exception("PETSc not initialized");
205:       }
206:       // Get a new cookie based on the class name
207:       const char *id_name = ALE::getClassName<T>();
208: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
209:       // Use id_name to register a cookie and events.
210:       logged_allocator::_cookie = LogCookieRegister(id_name);
211:       // Register the basic allocator methods' invocations as events; use the mangled class name.
212:       logged_allocator::_allocate_event   = logged_allocator::__log_event_register(id_name, "allocate");
213:       logged_allocator::_deallocate_event = logged_allocator::__log_event_register(id_name, "deallocate");
214:       logged_allocator::_construct_event  = logged_allocator::__log_event_register(id_name, "construct");
215:       logged_allocator::_destroy_event    = logged_allocator::__log_event_register(id_name, "destroy");
216:       logged_allocator::_create_event     = logged_allocator::__log_event_register(id_name, "create");
217:       logged_allocator::_del_event        = logged_allocator::__log_event_register(id_name, "del");
218: #endif
219:       ALE::restoreClassName<T>(id_name);
220:       logged_allocator::_log_initialized = true;
221:     }// if(!!logged_allocator::_log_initialized)
222:   }// logged_allocator<T,O>::__log_initialize()

224:   template <class T, bool O>
225:   void logged_allocator<T, O>::__alloc_initialize() {
226: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
227:     const char *id_name = ALE::getClassName<T>();
228:     PetscErrorCode PetscObjectCreateGeneric(PETSC_COMM_WORLD, logged_allocator::_cookie, id_name, &this->_petscObj);
229:     CHKERROR(ierr, "Failed in PetscObjectCreate");
230:     ALE::restoreClassName<T>(id_name);
231: #endif
232:   }// logged_allocator<T,O>::__alloc_initialize

234:   template <class T, bool O>
235:   void logged_allocator<T, O>::__alloc_finalize() {
236: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
237:     if (this->_petscObj) {
238:       PetscErrorCode PetscObjectDestroy(this->_petscObj);
239:       CHKERROR(ierr, "Failed in PetscObjectDestroy");
240:     }
241: #endif
242:   }// logged_allocator<T,O>::__alloc_finalize

244:   template <class T, bool O>
245:   LogEvent logged_allocator<T, O>::__log_event_register(const char *class_name, const char *event_name){
246:     // This routine assumes a cookie has been obtained.
247:     ostringstream txt;
248:     if(O) {
249:       txt << "Obj:";
250:     }
251: #ifdef ALE_LOGGING_VERBOSE
252:     txt << class_name;
253: #else
254:     txt << "<allocator>";
255: #endif
256:     txt << ":" << event_name;
257:     return LogEventRegister(logged_allocator::_cookie, txt.str().c_str());
258:   }

260:   template <class T, bool O>
261:   T*  logged_allocator<T, O>::allocate(size_type _n) {
262: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
263:     LogEventBegin(logged_allocator::_allocate_event);
264: #endif
265:     T* _p = polymorphic_allocator<T>::allocate(_n);
266: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
267:     PetscErrorCode PetscLogObjectMemory(this->_petscObj, _n*polymorphic_allocator<T>::sz);
268:     CHKERROR(ierr, "Error in PetscLogObjectMemory");
269:     LogEventEnd(logged_allocator::_allocate_event);
270: #endif
271:     return _p;
272:   }
273: 
274:   template <class T, bool O>
275:   void logged_allocator<T, O>::deallocate(T* _p, size_type _n) {
276: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
277:     LogEventBegin(logged_allocator::_deallocate_event);
278: #endif
279:     polymorphic_allocator<T>::deallocate(_p, _n);
280: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
281:     LogEventEnd(logged_allocator::_deallocate_event);
282: #endif
283:   }
284: 
285:   template <class T, bool O>
286:   void logged_allocator<T, O>::construct(T* _p, const T& _val) {
287: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
288:     LogEventBegin(logged_allocator::_construct_event);
289: #endif
290:     polymorphic_allocator<T>::construct(_p, _val);
291: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
292:     LogEventEnd(logged_allocator::_construct_event);
293: #endif
294:   }
295: 
296:   template <class T, bool O>
297:   void logged_allocator<T, O>::destroy(T* _p) {
298: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
299:     LogEventBegin(logged_allocator::_destroy_event);
300: #endif
301:     polymorphic_allocator<T>::destroy(_p);
302: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
303:     LogEventEnd(logged_allocator::_destroy_event);
304: #endif
305:   }
306: 
307:   template <class T, bool O>
308:   T* logged_allocator<T, O>::create(const T& _val) {
309: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
310:     LogEventBegin(logged_allocator::_create_event);
311: #endif
312:     T* _p = polymorphic_allocator<T>::create(_val);
313: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
314:     PetscErrorCode PetscLogObjectMemory(this->_petscObj, polymorphic_allocator<T>::sz);
315:     CHKERROR(ierr, "Error in PetscLogObjectMemory");
316:     LogEventEnd(logged_allocator::_create_event);
317: #endif
318:     return _p;
319:   }

321:   template <class T, bool O>
322:   void logged_allocator<T, O>::del(T* _p) {
323: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
324:     LogEventBegin(logged_allocator::_del_event);
325: #endif
326:     polymorphic_allocator<T>::del(_p);
327: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
328:     LogEventEnd(logged_allocator::_del_event);
329: #endif
330:   }

332:   template <class T, bool O> template <class TT>
333:   void logged_allocator<T, O>::del(TT* _p, size_type _sz) {
334: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
335:     LogEventBegin(logged_allocator::_del_event);
336: #endif
337:     polymorphic_allocator<T>::del(_p, _sz);
338: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
339:     LogEventEnd(logged_allocator::_del_event);
340: #endif
341:   }

343: #ifdef ALE_USE_LOGGING
344: #define ALE_ALLOCATOR ::ALE::logged_allocator
345: #else
346: #define ALE_ALLOCATOR ::ALE::polymorphic_allocator
347: #endif

349:   //
350:   // The following classes define smart pointer behavior.
351:   // They rely on allocators for memory pooling and logging (if logging is on).
352:   //

354:   // This is an Obj<X>-specific exception that is thrown when incompatible object conversion is attempted.
355:   class BadCast : public Exception {
356:   public:
357:     explicit BadCast(const string&        msg) : Exception(msg) {};
358:     explicit BadCast(const ostringstream& txt) : Exception(txt) {};
359:     //  It actually looks like passing txt as an argument to Exception(ostringstream) performs a copy of txt,
360:     //  which is disallowed due to the ostringstream constructor being private; must use a string constructor.
361:     BadCast(const BadCast& e)        : Exception(e) {};
362:   };

364:   // This is the main smart pointer class.
365:   template<class X>
366:   class Obj {
367:   public:
368:     // Types
369: #ifdef ALE_USE_LOGGING
370:     typedef logged_allocator<X,true>      Allocator;
371:     typedef logged_allocator<int,true>    Allocator_int;
372: #else
373:     typedef polymorphic_allocator<X>      Allocator;
374:     typedef polymorphic_allocator<int>    Allocator_int;
375: #endif
376:     typedef typename Allocator::size_type size_type;
377:   public:
378:     // These are intended to be private or at least protected
379:     // allocators
380:     Allocator_int         *int_allocator;
381:     Allocator             *allocator;
382:     //
383:     X*                     objPtr; // object pointer
384:     int*                   refCnt; // reference count
385:     size_type              sz;     // Size of underlying object (universal units) allocated with an allocator; indicates allocator use.
386:     // Constructor; this can be made private, if we move operator Obj<Y> outside this class definition and make it a friend.
387:     Obj(X *xx, int *refCnt, size_type sz);
388:   public:
389:     // Constructors & a destructor
390:     Obj() : objPtr((X *)NULL), refCnt((int*)NULL), sz(0) {this->createAllocators();};
391:     Obj(const X& x);
392:     Obj(X *xx);
393:     Obj(const Obj& obj);
394:     virtual ~Obj();

396:     // "Factory" methods
397:     Obj& create(const X& x = X());
398:     void destroy();
399:     void createAllocators();
400:     void destroyAllocators();
401:     void handleAllocators(const bool);

403:     // predicates & assertions
404:     bool isNull() const {return (this->objPtr == NULL);};
405:     void assertNull(bool flag) const { if(this->isNull() != flag){ throw(Exception("Null assertion failed"));}};

407:     // comparison operators
408:     bool operator==(const Obj& obj) { return (this->objPtr == obj.objPtr);};
409:     bool operator!=(const Obj& obj) { return (this->objPtr != obj.objPtr);};
410: 
411:     // assignment/conversion operators
412:     Obj& operator=(const Obj& obj);
413:     template <class Y> operator Obj<Y> const();
414:     template <class Y> Obj& operator=(const Obj<Y>& obj);

416:     // dereference operators
417:     X*   operator->() const {return objPtr;};
418: 
419:     // "exposure" methods: expose the underlying object or object pointer
420:     operator X*() {return objPtr;};
421:     X& operator*() {assertNull(false); return *objPtr;};
422:     operator X()  {assertNull(false); return *objPtr;};
423:     template<class Y> Obj& copy(const Obj<Y>& obj); // this operator will copy the underlying objects: USE WITH CAUTION
424: 

426:     // depricated methods/operators
427:     X* ptr() const     {return objPtr;};
428:     X* pointer() const {return objPtr;};
429:     X  obj() const     {assertNull(false); return *objPtr;};
430:     X  object() const  {assertNull(false); return *objPtr;};
431: 
432:   };// class Obj<X>

434:   // Constructors
435:   // New reference
436:   template <class X>
437:   Obj<X>::Obj(const X& x) {
438:     this->createAllocators();
439:     this->refCnt = NULL;
440:     this->create(x);
441:   }
442: 
443:   // Stolen reference
444:   template <class X>
445:   Obj<X>::Obj(X *xx){// such an object will be destroyed by calling 'delete' on its pointer
446:                      // (e.g., we assume the pointer was obtained with new)
447:     this->createAllocators();
448:     if (xx) {
449:       this->objPtr = xx;
450:       this->refCnt = this->int_allocator->create(1);
451:       //this->refCnt   = new int(1);
452:       this->sz = 0;
453:     } else {
454:       this->objPtr = NULL;
455:       this->refCnt = NULL;
456:       this->sz = 0;
457:     }
458:   }
459: 
460:   template <class X>
461:   Obj<X>::Obj(X *_xx, int *_refCnt, size_type _sz) {  // This is intended to be private.
462:     this->createAllocators();
463:     if (!_xx) {
464:       throw ALE::Exception("Making an Obj with a NULL objPtr");
465:     }
466:     this->objPtr = _xx;
467:     this->refCnt = _refCnt;  // we assume that all refCnt pointers are obtained using an int_allocator
468:     (*this->refCnt)++;
469:     this->sz = _sz;
470:     //if (!this->sz) {
471:     //  throw ALE::Exception("Making an Obj with zero size");
472:     //}
473:   }
474: 
475:   template <class X>
476:   Obj<X>::Obj(const Obj& obj) {
477:     this->createAllocators();
478:     this->objPtr = obj.objPtr;
479:     this->refCnt = obj.refCnt;
480:     if (obj.refCnt) {
481:       (*this->refCnt)++;
482:     }
483:     this->sz = obj.sz;
484:     //if (!this->sz) {
485:     //  throw ALE::Exception("Making an Obj with zero size");
486:     //}
487:   }

489:   // Destructor
490:   template <class X>
491:   Obj<X>::~Obj(){
492:     this->destroy();
493:     this->destroyAllocators();
494:   }

496:   template <class X>
497:   void Obj<X>::createAllocators() {
498:     this->handleAllocators(true);
499:   }

501:   template <class X>
502:   void Obj<X>::destroyAllocators() {
503:     this->handleAllocators(false);
504:   }

506:   template <class X>
507:   void Obj<X>::handleAllocators(const bool create) {
508:     static Allocator_int *s_int_allocator = NULL;
509:     static Allocator     *s_allocator     = NULL;
510:     static int            s_allocRefCnt   = 0;

512:     if (create) {
513:       if (s_allocRefCnt == 0) {
514:         s_int_allocator = new Allocator_int();
515:         s_allocator     = new Allocator();
516:       }
517:       s_allocRefCnt++;
518:       this->int_allocator = s_int_allocator;
519:       this->allocator     = s_allocator;
520:     } else {
521:       if (--s_allocRefCnt == 0) {
522:         delete int_allocator;
523:         delete allocator;
524:       }
525:       this->int_allocator = NULL;
526:       this->allocator     = NULL;
527:     }
528:   }

530:   template <class X>
531:   Obj<X>& Obj<X>::create(const X& x) {
532:     // Destroy the old state
533:     this->destroy();
534:     // Create the new state
535:     this->objPtr = this->allocator->create(x);
536:     this->refCnt = this->int_allocator->create(1);
537:     this->sz     = this->allocator->sz;
538:     if (!this->sz) {
539:       throw ALE::Exception("Making an Obj with zero size obtained from allocator");
540:     }
541:     return *this;
542:   }

544:   template <class X>
545:   void Obj<X>::destroy() {
546:     if(ALE::getVerbosity() > 3) {
547: #ifdef ALE_USE_DEBUGGING
548:       const char *id_name = ALE::getClassName<X>();

550:       printf("Obj<X>.destroy: Destroying Obj<%s>", id_name);
551:       if (!this->refCnt) {
552:         printf(" with no refCnt\n");
553:       } else {
554:         printf(" with refCnt %d\n", *this->refCnt);
555:       }
556:       ALE::restoreClassName<X>(id_name);
557: #endif
558:     }
559:     if (this->refCnt != NULL) {
560:       (*this->refCnt)--;
561:       if (*this->refCnt == 0) {
562:         // If  allocator has been used to create an objPtr, as indicated by 'sz', we use the allocator to delete objPtr, using 'sz'.
563:         if(this->sz != 0) {
564: #ifdef ALE_USE_DEBUGGING
565:           if(ALE::getVerbosity() > 3) {
566:             printf("  Calling deallocator on %p with size %d\n", this->objPtr, (int) this->sz);
567:           }
568: #endif
569:           this->allocator->del(this->objPtr, this->sz);
570:           this->sz = 0;
571:         }
572:         else { // otherwise we use 'delete'
573: #ifdef ALE_USE_DEBUGGING
574:           if(ALE::getVerbosity() > 3) {
575:             printf("  Calling delete on %p\n", this->objPtr);
576:           }
577: #endif
578:           if (!this->objPtr) {
579:             throw ALE::Exception("Trying to free NULL pointer");
580:           }
581:           delete this->objPtr;
582:         }
583:         // refCnt is always created/delete using the int_allocator.
584:         this->int_allocator->del(this->refCnt);
585:         this->objPtr = NULL;
586:         this->refCnt = NULL;
587:       }
588:     }
589:   }

591:   // assignment operator
592:   template <class X>
593:   Obj<X>& Obj<X>::operator=(const Obj<X>& obj) {
594:     if(this->objPtr == obj.objPtr) {return *this;}
595:     // Destroy 'this' Obj -- it will properly release the underlying object if the reference count is exhausted.
596:     if(this->objPtr) {
597:       this->destroy();
598:     }
599:     // Now copy the data from obj.
600:     this->objPtr = obj.objPtr;
601:     this->refCnt = obj.refCnt;
602:     if(this->refCnt!= NULL) {
603:       (*this->refCnt)++;
604:     }
605:     this->sz = obj.sz;
606:     return *this;
607:   }

609:   // conversion operator, preserves 'this'
610:   template<class X> template<class Y>
611:   Obj<X>::operator Obj<Y> const() {
612:     // We attempt to cast X* objPtr to Y* using dynamic_
613: #ifdef ALE_USE_DEBUGGING
614:     if(ALE::getVerbosity() > 1) {
615:       printf("Obj<X>::operator Obj<Y>: attempting a dynamic_cast on objPtr %p\n", this->objPtr);
616:     }
617: #endif
618:     Y* yObjPtr = dynamic_cast<Y*>(this->objPtr);
619:     // If the cast failed, throw an exception
620:     if(yObjPtr == NULL) {
621:       const char *Xname = ALE::getClassName<X>();
622:       const char *Yname = ALE::getClassName<Y>();
623:       std::string msg("Bad cast Obj<");
624:       msg += Xname;
625:       msg += "> --> Obj<";
626:       msg += Yname;
627:       msg += ">";
628:       ALE::restoreClassName<X>(Xname);
629:       ALE::restoreClassName<X>(Yname);
630:       throw BadCast(msg.c_str());
631:     }
632:     // Okay, we can proceed
633:     return Obj<Y>(yObjPtr, this->refCnt, this->sz);
634:   }

636:   // assignment-conversion operator
637:   template<class X> template<class Y>
638:   Obj<X>& Obj<X>::operator=(const Obj<Y>& obj) {
639:     // We attempt to cast Y* obj.objPtr to X* using dynamic_cast
640:     X* xObjPtr = dynamic_cast<X*>(obj.objPtr);
641:     // If the cast failed, throw an exception
642:     if(xObjPtr == NULL) {
643:       const char *Xname = ALE::getClassName<X>();
644:       const char *Yname = ALE::getClassName<Y>();
645:       std::string msg("Bad assignment cast Obj<");
646:       msg += Yname;
647:       msg += "> --> Obj<";
648:       msg += Xname;
649:       msg += ">";
650:       ALE::restoreClassName<X>(Xname);
651:       ALE::restoreClassName<X>(Yname);
652:       throw BadCast(msg.c_str());
653:     }
654:     // Okay, we can proceed with the assignment
655:     if(this->objPtr == obj.objPtr) {return *this;}
656:     // Destroy 'this' Obj -- it will properly release the underlying object if the reference count is exhausted.
657:     this->destroy();
658:     // Now copy the data from obj.
659:     this->objPtr = xObjPtr;
660:     this->refCnt = obj.refCnt;
661:     (*this->refCnt)++;
662:     this->sz = obj.sz;
663:     return *this;
664:   }
665: 
666:   // copy operator (USE WITH CAUTION)
667:   template<class X> template<class Y>
668:   Obj<X>& Obj<X>::copy(const Obj<Y>& obj) {
669:     if(this->isNull() || obj.isNull()) {
670:       throw(Exception("Copying to or from a null Obj"));
671:     }
672:     *(this->objPtr) = *(obj.objPtr);
673:     return *this;
674:   }


677: } // namespace ALE

679: #endif