/* 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 3 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, see . * */ #ifndef COMMON_PTR_H #define COMMON_PTR_H #include "common/scummsys.h" #include "common/noncopyable.h" #include "common/safe-bool.h" #include "common/types.h" /* For nullptr_t */ #include namespace Common { /** * @defgroup common_ptr Pointers * @ingroup common * * @brief API and templates for pointers. * @{ */ class BasePtrTrackerInternal { public: typedef int RefValue; BasePtrTrackerInternal() : _weakRefCount(1), _strongRefCount(1) {} virtual ~BasePtrTrackerInternal() {} void incWeak() { _weakRefCount++; } void decWeak() { if (--_weakRefCount == 0) delete this; } void incStrong() { _strongRefCount++; } void decStrong() { if (--_strongRefCount == 0) { destructObject(); decWeak(); } } bool isAlive() const { return _strongRefCount > 0; } RefValue getStrongCount() const { return _strongRefCount; } protected: virtual void destructObject() = 0; private: RefValue _weakRefCount; // Weak ref count + 1 if object ref count > 0 RefValue _strongRefCount; }; template class BasePtrTrackerImpl : public BasePtrTrackerInternal { public: BasePtrTrackerImpl(T *ptr) : _ptr(ptr) {} protected: void destructObject() override { STATIC_ASSERT(sizeof(T) > 0, SharedPtr_cannot_delete_incomplete_type); delete _ptr; } T *_ptr; }; template class BasePtrTrackerDeletionImpl : public BasePtrTrackerInternal { public: BasePtrTrackerDeletionImpl(T *ptr, DL d) : _ptr(ptr), _deleter(d) {} private: void destructObject() override { _deleter(_ptr); } T *_ptr; DL _deleter; }; template class WeakPtr; /** * 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. Comparison between a SharedPtr object and * a plain pointer is only possible via SharedPtr::get. */ template class SharedPtr : public SafeBool > { template friend class WeakPtr; template friend class SharedPtr; public: // Invariant: If _tracker is non-null, then the object is alive typedef T *PointerType; typedef T &ReferenceType; typedef BasePtrTrackerInternal::RefValue RefValue; SharedPtr() : _pointer(nullptr), _tracker(nullptr) { } SharedPtr(std::nullptr_t) : _pointer(nullptr), _tracker(nullptr) { } ~SharedPtr() { if (_tracker) _tracker->decStrong(); } template explicit SharedPtr(T2 *p) : _pointer(p), _tracker(p ? (new BasePtrTrackerImpl(p)) : nullptr) { } template SharedPtr(T2 *p, DL d) : _pointer(p), _tracker(p ? (new BasePtrTrackerDeletionImpl(p, d)) : nullptr) { } SharedPtr(const SharedPtr &r) : _pointer(r._pointer), _tracker(r._tracker) { if (_tracker) _tracker->incStrong(); } template SharedPtr(const SharedPtr &r) : _pointer(r._pointer), _tracker(r._tracker) { if (_tracker) _tracker->incStrong(); } template explicit SharedPtr(const WeakPtr &r) : _pointer(nullptr), _tracker(nullptr) { if (r._tracker && r._tracker->isAlive()) { _pointer = r._pointer; _tracker = r._tracker; _tracker->incStrong(); } } SharedPtr &operator=(const SharedPtr &r) { reset(r); return *this; } template SharedPtr &operator=(const SharedPtr &r) { reset(r); return *this; } T &operator*() const { assert(_pointer); return *_pointer; } T *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 */ PointerType get() const { return _pointer; } template bool operator==(const SharedPtr &r) const { return _pointer == r.get(); } template bool operator!=(const SharedPtr &r) const { return _pointer != r.get(); } bool operator==(std::nullptr_t) const { return _pointer == nullptr; } bool operator!=(std::nullptr_t) const { return _pointer != nullptr; } /** * Implicit conversion operator to bool for convenience, to make * checks like "if (sharedPtr) ..." possible. */ bool operator_bool() const { return _pointer != nullptr; } /** * Returns the number of strong references to the object. */ int refCount() const { if (_tracker == nullptr) return 0; return _tracker->getStrongCount(); } /** * Checks if the object is the only object refering * to the assigned pointer. This should just be used for * debugging purposes. */ bool unique() const { return refCount() == 1; } /** * Resets the object to a NULL pointer. */ void reset() { if (_tracker) _tracker->decStrong(); _tracker = nullptr; _pointer = nullptr; } /** * Resets the object to the specified shared pointer */ template void reset(const SharedPtr &r) { BasePtrTrackerInternal *oldTracker = _tracker; _pointer = r._pointer; _tracker = r._tracker; if (_tracker) _tracker->incStrong(); if (oldTracker) oldTracker->decStrong(); } /** * Resets the object to the specified weak pointer */ template void reset(const WeakPtr &r) { BasePtrTrackerInternal *oldTracker = _tracker; if (r._tracker && r._tracker->isAlive()) { _tracker = r._tracker; _pointer = r._pointer; _tracker->incStrong(); } else { _tracker = nullptr; _pointer = nullptr; } if (oldTracker) oldTracker->decStrong(); } /** * Resets the object to the specified pointer */ void reset(T *ptr) { if (_tracker) _tracker->decStrong(); _pointer = ptr; _tracker = new BasePtrTrackerImpl(ptr); } /** * Performs the equivalent of static_cast to a new pointer type */ template SharedPtr staticCast() const { return SharedPtr(static_cast(_pointer), _tracker); } /** * Performs the equivalent of dynamic_cast to a new pointer type */ template SharedPtr dynamicCast() const { return SharedPtr(dynamic_cast(_pointer), _tracker); } /** * Performs the equivalent of const_cast to a new pointer type */ template SharedPtr constCast() const { return SharedPtr(const_cast(_pointer), _tracker); } /** * Performs the equivalent of const_cast to a new pointer type */ template SharedPtr reinterpretCast() const { return SharedPtr(reinterpret_cast(_pointer), _tracker); } private: SharedPtr(T *pointer, BasePtrTrackerInternal *tracker) : _pointer(pointer), _tracker(tracker) { if (tracker) tracker->incStrong(); } T *_pointer; BasePtrTrackerInternal *_tracker; }; /** * Implements a smart pointer that holds a non-owning ("weak") refrence to * a pointer. It needs to be converted to a SharedPtr to access it. */ template class WeakPtr { template friend class WeakPtr; template friend class SharedPtr; public: WeakPtr() : _pointer(nullptr), _tracker(nullptr) { } WeakPtr(std::nullptr_t) : _pointer(nullptr), _tracker(nullptr) { } WeakPtr(const WeakPtr &r) : _pointer(r._pointer), _tracker(r._tracker) { if (_tracker) _tracker->incWeak(); } ~WeakPtr() { if (_tracker) _tracker->decWeak(); } template WeakPtr(const WeakPtr &r) : _pointer(r._pointer), _tracker(r._tracker) { if (_tracker) _tracker->incWeak(); } template WeakPtr(const SharedPtr &r) : _pointer(r._pointer), _tracker(r._tracker) { if (_tracker) _tracker->incWeak(); } /** * Performs the equivalent of static_cast to a new pointer type */ template WeakPtr staticCast() const { return WeakPtr(expired() ? nullptr : static_cast(_pointer), _tracker); } /** * Performs the equivalent of dynamic_cast to a new pointer type */ template WeakPtr dynamicCast() const { return WeakPtr(expired() ? nullptr : dynamic_cast(_pointer), _tracker); } /** * Performs the equivalent of const_cast to a new pointer type */ template WeakPtr constCast() const { return WeakPtr(expired() ? nullptr : const_cast(_pointer), _tracker); } /** * Performs the equivalent of const_cast to a new pointer type */ template WeakPtr reinterpretCast() const { return WeakPtr(expired() ? nullptr : reinterpret_cast(_pointer), _tracker); } /** * Creates a SharedPtr that manages the referenced object */ SharedPtr lock() const { return SharedPtr(*this); } /** * Returns the number of strong references to the object. */ int refCount() const { if (_tracker == nullptr) return 0; return _tracker->getStrongCount(); } /** * Returns whether the referenced object isn't valid */ bool expired() const { return _tracker == nullptr || _tracker->getStrongCount() == 0; } /** * Returns whether this precedes another weak pointer in owner-based order */ template bool owner_before(const WeakPtr& other) const { return _tracker < other._tracker; } /** * Returns whether this precedes a shared pointer in owner-based order */ template bool owner_before(const SharedPtr &other) const { return _tracker < other._tracker; } WeakPtr &operator=(const WeakPtr &r) { reset(r); return *this; } template WeakPtr &operator=(const WeakPtr &r) { reset(r); return *this; } template WeakPtr &operator=(const SharedPtr &r) { reset(r); return *this; } /** * Resets the object to a NULL pointer. */ void reset() { if (_tracker) _tracker->decWeak(); _tracker = nullptr; _pointer = nullptr; } /** * Resets the object to the specified shared pointer */ template void reset(const SharedPtr &r) { BasePtrTrackerInternal *oldTracker = _tracker; _pointer = r._pointer; _tracker = r._tracker; if (_tracker) _tracker->incWeak(); if (oldTracker) oldTracker->decWeak(); } /** * Resets the object to the specified weak pointer */ template void reset(const WeakPtr &r) { BasePtrTrackerInternal *oldTracker = _tracker; _pointer = r._pointer; _tracker = r._tracker; if (_tracker) _tracker->incWeak(); if (oldTracker) oldTracker->decWeak(); } private: WeakPtr(T *pointer, BasePtrTrackerInternal *tracker) : _pointer(pointer), _tracker(tracker) { if (tracker) tracker->incWeak(); } T *_pointer; BasePtrTrackerInternal *_tracker; }; template struct DefaultDeleter { inline void operator()(T *object) { STATIC_ASSERT(sizeof(T) > 0, cannot_delete_incomplete_type); delete object; } }; template > class ScopedPtr : private NonCopyable, public SafeBool > { public: typedef T ValueType; typedef T *PointerType; typedef T &ReferenceType; explicit ScopedPtr(PointerType o = nullptr) : _pointer(o) {} ScopedPtr(std::nullptr_t) : _pointer(nullptr) {} /** * Move constructor */ template ScopedPtr(ScopedPtr &&o) : _pointer(o._pointer) { o._pointer = nullptr; } ReferenceType operator*() const { return *_pointer; } PointerType operator->() const { return _pointer; } /** * Implicit conversion operator to bool for convenience, to make * checks like "if (scopedPtr) ..." possible. */ bool operator_bool() const { return _pointer != nullptr; } ~ScopedPtr() { DL()(_pointer); } /** * Resets the pointer with the new value. Old object will be destroyed */ void reset(PointerType o = nullptr) { DL()(_pointer); _pointer = o; } /** * Affectation with nullptr */ ScopedPtr &operator=(std::nullptr_t) { reset(nullptr); } /** * Replaces the ScopedPtr with another scoped ScopedPtr. */ template ScopedPtr &operator=(ScopedPtr &&other) { PointerType oldPointer = _pointer; _pointer = other._pointer; other._pointer = nullptr; DL()(oldPointer); return *this; } /** * Returns the plain pointer value. * * @return the pointer the ScopedPtr manages */ PointerType get() const { return _pointer; } /** * Returns the plain pointer value and releases ScopedPtr. * After release() call you need to delete object yourself * * @return the pointer the ScopedPtr manages */ PointerType release() { PointerType r = _pointer; _pointer = nullptr; return r; } private: PointerType _pointer; }; template > class DisposablePtr : private NonCopyable, public SafeBool > { public: typedef T ValueType; typedef T *PointerType; typedef T &ReferenceType; explicit DisposablePtr(PointerType o, DisposeAfterUse::Flag dispose) : _pointer(o), _dispose(dispose) {} ~DisposablePtr() { if (_dispose) DL()(_pointer); } ReferenceType operator*() const { return *_pointer; } PointerType operator->() const { return _pointer; } /** * Implicit conversion operator to bool for convenience, to make * checks like "if (scopedPtr) ..." possible. */ bool operator_bool() const { return _pointer != nullptr; } /** * Resets the pointer with the new value. Old object will be destroyed */ void reset(PointerType o, DisposeAfterUse::Flag dispose) { if (_dispose) DL()(_pointer); _pointer = o; _dispose = dispose; } /** * Clears the pointer. Old object will be destroyed */ void reset() { reset(nullptr, DisposeAfterUse::NO); } /** * Clears the pointer without destroying the old object. */ void disownPtr() { _pointer = nullptr; _dispose = DisposeAfterUse::NO; } /** * Returns the plain pointer value. * * @return the pointer the DisposablePtr manages */ PointerType get() const { return _pointer; } /** * Returns the pointer's dispose flag. */ DisposeAfterUse::Flag getDispose() const { return _dispose; } private: PointerType _pointer; DisposeAfterUse::Flag _dispose; }; /** @} */ } // End of namespace Common #endif