// // VMime library (http://www.vmime.org) // Copyright (C) 2002-2006 Vincent Richard // // 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. // // Linking this library statically or dynamically with other modules is making // a combined work based on this library. Thus, the terms and conditions of // the GNU General Public License cover the whole combination. // #ifndef VMIME_UTILITY_SMARTPTR_HPP_INCLUDED #define VMIME_UTILITY_SMARTPTR_HPP_INCLUDED #include // Forward reference to 'object' namespace vmime { class object; } namespace vmime { namespace utility { /** Simple auto-delete pointer. */ template class auto_ptr { private: T* const m_ptr; public: auto_ptr(T* const ptr) : m_ptr(ptr) { } ~auto_ptr() { delete (m_ptr); } operator T*() { return (m_ptr); } T* const operator ->() { return (m_ptr); } T& operator *() { return (*m_ptr); } }; /** Reference counter for shared pointers. */ class refCounter { public: refCounter(const long initialValue); ~refCounter(); const long increment(); const long decrement(); const long compareExchange(const long compare, const long exchangeWith); operator long() const; private: long m_value; }; /** Manage the life cycle of an object. */ class refManager { public: refManager(object* obj); ~refManager(); /** Add a strong reference to the managed object. */ const bool addStrong(); /** Release a strong reference to the managed object. * If it is the last reference, the object is destroyed. */ void releaseStrong(); /** Add a weak reference to the managed object. */ void addWeak(); /** Release a weak reference to the managed object. * If it is the last weak reference, the manager is destroyed. */ void releaseWeak(); /** Return a raw pointer to the managed object. * * @return pointer to the managed object */ object* getObject(); /** Return the number of strong refs to this object. * For debugging purposes only. * * @return strong reference count */ const long getStrongRefCount() const; /** Return the number of weak refs to this object. * For debugging purposes only. * * @return weak reference count */ const long getWeakRefCount() const; private: void deleteManager(); void deleteObject(); object* m_object; refCounter m_strongCount; refCounter m_weakCount; }; /** Null reference. */ class null_ref { private: int foo; }; template class weak_ref; /** Shared ownership (strong reference to an object). */ template class ref { public: template friend class ref; template friend class weak_ref; ref() : m_ptr(0) { } ref(const ref& r) : m_ptr(0) { attach(r); } ref(const null_ref&) : m_ptr(0) { } virtual ~ref() throw() { detach(); } // Allow creating NULL ref (NULL casts to anything*) ref(class null_pointer*) : m_ptr(0) { } // Access to wrapped object // operator const T*() const { return m_ptr; } operator const void*() const { return m_ptr; } T& operator *() { return *m_ptr; } const T& operator *() const { return *m_ptr; } T* operator ->() { return m_ptr; } const T* operator ->() const { return m_ptr; } const T* const get() const { return m_ptr; } T* const get() { return m_ptr; } // dynamic_cast template ref dynamicCast() const { U* p = dynamic_cast (const_cast (m_ptr)); if (!p) return ref (); if (m_ptr) m_ptr->getRefManager()->addStrong(); return ref ::fromPtrImpl(p); } // static_cast template ref staticCast() const { U* p = static_cast (const_cast (m_ptr)); if (!p) return ref (); if (m_ptr) m_ptr->getRefManager()->addStrong(); return ref ::fromPtrImpl(p); } // const_cast template ref constCast() const { U* p = const_cast (m_ptr); if (!p) return ref (); if (m_ptr) m_ptr->getRefManager()->addStrong(); return ref ::fromPtrImpl(p); } // Implicit downcast template operator ref () const { if (m_ptr) m_ptr->getRefManager()->addStrong(); ref r; r.m_ptr = m_ptr; // will type check at compile-time (prevent from implicit upcast) return r; } template operator ref () { if (m_ptr) m_ptr->getRefManager()->addStrong(); ref r; r.m_ptr = m_ptr; // will type check at compile-time (prevent from implicit upcast) return r; } template ref & operator=(const ref & other) { U* ptr = other.m_ptr; // will type check at compile-time (prevent from implicit upcast) if (ptr) ptr->getRefManager()->addStrong(); detach(); m_ptr = ptr; return *this; } // Implicit non-const => const conversion operator ref () const { if (m_ptr) m_ptr->getRefManager()->addStrong(); return ref ::fromPtrImpl(m_ptr); } // Copy ref& operator=(const ref& p) { attach(p); return *this; } // NULL-pointer comparison bool operator==(const class null_pointer*) const { return m_ptr == 0; } bool operator!=(const class null_pointer*) const { return m_ptr != 0; } bool operator==(const null_ref&) const { return m_ptr == 0; } bool operator!=(const null_ref&) const { return m_ptr != 0; } /** Create a ref<> from a raw pointer. * * WARNING: you should use this function only if you know what * you are doing. In general, you should create ref objects using * vmime::create(). * * When this function returns, the pointer is owned by the ref, * you should not attempt to delete it manually. * * @param ptr raw pointer to encapsulate * @return a ref which encapsulates the specified raw pointer */ static ref fromPtr(T* const ptr) { return ref ::fromPtrImpl(ptr); } static ref fromPtrConst(const T* const ptr) { return ref ::fromPtrImpl(ptr); } static ref fromWeak(weak_ref wr) { refManager* mgr = wr.getManager(); if (mgr && mgr->addStrong()) return ref ::fromPtrImpl(dynamic_cast (mgr->getObject())); else return ref (); } static ref fromWeakConst(weak_ref wr) { refManager* mgr = wr.getManager(); if (mgr && mgr->addStrong()) return ref ::fromPtrImpl(dynamic_cast (mgr->getObject())); else return ref (); } protected: template static ref fromPtrImpl(U* ptr) { ref r; r.m_ptr = ptr; return r; } void detach() { if (m_ptr) { m_ptr->getRefManager()->releaseStrong(); m_ptr = 0; } } template void attach(U* const ptr) { if (ptr) ptr->getRefManager()->addStrong(); detach(); m_ptr = ptr; } template void attach(const ref & r) { if (r.m_ptr) r.m_ptr->getRefManager()->addStrong(); detach(); m_ptr = r.m_ptr; } private: T* m_ptr; }; template bool operator==(const ref & a, const ref & b) { return (a.get() == b.get()); } template bool operator!=(const ref & a, const ref & b) { return (a.get() != b.get()); } template bool operator==(const ref & a, T* const p) { return (a.get() == p); } template bool operator!=(const ref & a, T* const p) { return (a.get() != p); } template bool operator==(T* const p, const ref & a) { return (a.get() == p); } template bool operator!=(T* const p, const ref & a) { return (a.get() != p); } template bool operator==(const null_ref&, const ref & r) { return (r.get() == 0); } template bool operator!=(const null_ref&, const ref & r) { return (r.get() != 0); } /** Weak reference. * Avoid circular references. */ template class weak_ref { public: template friend class weak_ref; weak_ref() : m_mgr(0) { } weak_ref(const ref & r) : m_mgr(0) { attach(r); } weak_ref(const weak_ref& r) : m_mgr(0) { attach(r); } weak_ref(const null_ref&) : m_mgr(0) { } weak_ref(class null_pointer*) : m_mgr(0) { } ~weak_ref() { detach(); } /** Return the manager for the object. * * @return pointer to the object which manages the object * or NULL if the weak reference points to nothing */ refManager* getManager() { return m_mgr; } /** Try to acquire a strong reference to the object (const version). * * @return strong reference or null reference if the * object is not available anymore */ ref acquire() const { return ref ::fromWeakConst(*this); } /** Try to acquire a strong reference to the object. * * @return strong reference or null reference if the * object is not available anymore */ ref acquire() { return ref ::fromWeak(*this); } // Implicit non-const => const conversion operator weak_ref () const { if (m_mgr) m_mgr->addWeak(); weak_ref r; r.m_mgr = m_mgr; return r; } template operator weak_ref () const { if (m_mgr) m_mgr->addWeak(); weak_ref r; r.m_mgr = m_mgr; return r; } // Copy weak_ref& operator=(const weak_ref& p) { attach(p); return *this; } private: void detach() { if (m_mgr) { m_mgr->releaseWeak(); m_mgr = 0; } } void attach(const ref & r) { if (r.m_ptr) r.m_ptr->getRefManager()->addWeak(); detach(); if (r.m_ptr) m_mgr = r.m_ptr->getRefManager(); else m_mgr = 0; } void attach(const weak_ref& r) { if (r.m_mgr) r.m_mgr->addWeak(); detach(); m_mgr = r.m_mgr; } refManager* m_mgr; }; } // utility } // vmime #endif // VMIME_UTILITY_SMARTPTR_HPP_INCLUDED