/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $URL$ * $Id$ */ #ifndef COMMON_PTR_H #define COMMON_PTR_H #include "common/scummsys.h" namespace Common { class SharedPtrDeletionInternal { public: virtual ~SharedPtrDeletionInternal() {} }; template class SharedPtrDeletionImpl : public SharedPtrDeletionInternal { public: SharedPtrDeletionImpl(T *ptr) : _ptr(ptr) {} ~SharedPtrDeletionImpl() { // Checks if the supplied type is not just a plain // forward definition, taken from boost::checked_delete // This makes the user really aware what he tries to do // when using this with an incomplete type. typedef char completeCheck[sizeof(T) ? 1 : -1]; (void)sizeof(completeCheck); delete _ptr; } private: T *_ptr; }; template class SharedPtrDeletionDeleterImpl : public SharedPtrDeletionInternal { public: SharedPtrDeletionDeleterImpl(T *ptr, D d) : _ptr(ptr), _deleter(d) {} ~SharedPtrDeletionDeleterImpl() { _deleter(_ptr); } private: T *_ptr; D _deleter; }; /** * A simple shared pointer implementation modelled after boost. * * This object keeps track of the assigned pointer and automatically * frees it when no more SharedPtr references to it exist. * * To achieve that the object implements an internal reference counting. * Thus you should try to avoid using the plain pointer after assigning * it to a SharedPtr object for the first time. If you still use the * plain pointer be sure you do not delete it on your own. You may also * not use the plain pointer to create a new SharedPtr object, since that * would result in a double deletion of the pointer sooner or later. * * Example creation: * Common::SharedPtr pointer(new int(1)); * would create a pointer to int. Later on usage via *pointer is the same * as for a normal pointer. If you need to access the plain pointer value * itself later on use the get method. The class also supplies a operator * ->, which does the same as the -> operator on a normal pointer. * * Be sure you are using new to initialize the pointer you want to manage. * If you do not use new for allocating, you have to supply a deleter as * second parameter when creating a SharedPtr object. The deleter has to * implement operator() which takes the pointer it should free as argument. * * Note that you have to specify the type itself not the pointer type as * template parameter. * * When creating a SharedPtr object from a normal pointer you need a real * definition of the type you want SharedPtr to manage, a simple forward * definition is not enough. * * The class has implicit upcast support, so if you got a class B derived * from class A, you can assign a pointer to B without any problems to a * SharedPtr object with template parameter A. The very same applies to * assignment of a SharedPtr object to a SharedPtr object. * * There are also operators != and == to compare two SharedPtr objects * with compatible pointers. Comparision between a SharedPtr object and * a plain pointer is just possible via SharedPtr::get. */ template class SharedPtr { #if !((__GNUC__ == 2) && (__GNUC_MINOR__ >= 95)) template friend class SharedPtr; #endif public: typedef int RefValue; typedef T ValueType; typedef T *Pointer; SharedPtr() : _refCount(0), _deletion(0), _pointer(0) {} template explicit SharedPtr(T2 *p) : _refCount(new RefValue(1)), _deletion(new SharedPtrDeletionImpl(p)), _pointer(p) {} template SharedPtr(T2 *p, D d) : _refCount(new RefValue(1)), _deletion(new SharedPtrDeletionDeleterImpl(p, d)), _pointer(p) {} SharedPtr(const SharedPtr &r) : _refCount(r._refCount), _deletion(r._deletion), _pointer(r._pointer) { if (_refCount) ++(*_refCount); } template SharedPtr(const SharedPtr &r) : _refCount(r._refCount), _deletion(r._deletion), _pointer(r._pointer) { if (_refCount) ++(*_refCount); } ~SharedPtr() { decRef(); } SharedPtr &operator =(const SharedPtr &r) { if (r._refCount) ++(*r._refCount); decRef(); _refCount = r._refCount; _deletion = r._deletion; _pointer = r._pointer; return *this; } template SharedPtr &operator =(const SharedPtr &r) { if (r._refCount) ++(*r._refCount); decRef(); _refCount = r._refCount; _deletion = r._deletion; _pointer = r._pointer; return *this; } ValueType &operator *() const { assert(_pointer); return *_pointer; } Pointer operator ->() const { assert(_pointer); return _pointer; } /** * Returns the plain pointer value. Be sure you know what you * do if you are continuing to use that pointer. * * @return the pointer the SharedPtr object manages */ Pointer get() const { return _pointer; } /** * Implicit conversion operator to bool for convenience, to make * checks like "if (sharePtr) ..." possible. */ operator bool() const { return _pointer != 0; } /** * Checks if the SharedPtr object is the only object refering * to the assigned pointer. This should just be used for * debugging purposes. */ bool unique() const { return refCount() == 1; } /** * Returns the number of references to the assigned pointer. * This should just be used for debugging purposes. */ RefValue refCount() const { return _refCount ? *_refCount : 0; } private: void decRef() { if (_refCount) { --(*_refCount); if (!*_refCount) { delete _refCount; delete _deletion; _deletion = 0; _refCount = 0; _pointer = 0; } } } RefValue *_refCount; SharedPtrDeletionInternal *_deletion; T *_pointer; }; } // end of namespace Common template bool operator ==(const Common::SharedPtr &l, const Common::SharedPtr &r) { return l.get() == r.get(); } template bool operator !=(const Common::SharedPtr &l, const Common::SharedPtr &r) { return l.get() != r.get(); } #endif