diff options
Diffstat (limited to 'vmime/utility/smartPtr.hpp')
-rw-r--r-- | vmime/utility/smartPtr.hpp | 508 |
1 files changed, 444 insertions, 64 deletions
diff --git a/vmime/utility/smartPtr.hpp b/vmime/utility/smartPtr.hpp index 7b895629..65ea2ff6 100644 --- a/vmime/utility/smartPtr.hpp +++ b/vmime/utility/smartPtr.hpp @@ -21,6 +21,13 @@ #define VMIME_UTILITY_SMARTPTR_HPP_INCLUDED +#include <map> + + +// Forward reference to 'object' +namespace vmime { class object; } + + namespace vmime { namespace utility { @@ -47,116 +54,489 @@ public: }; -/** Smart auto-delete, referencable and copiable pointer. +/** Null reference. */ -template <class T> -class smart_ptr +class null_ref { private: - struct data + int foo; +}; + + +/** Strong reference (smart pointer). + */ + +template <class T> +class ref +{ +public: + + template <class U> friend class ref; + template <class U> 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() { 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; } + + 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 <class U> + ref <U> dynamicCast() const { - int refCount; - T* ptr; - }; + U* p = dynamic_cast <U*>(const_cast <T*>(m_ptr)); + if (!p) return ref <U>(); - data* m_data; + p->addStrong(); + ref <U> r; + r.m_ptr = p; - typedef std::map <T*, data*> MapType; - static MapType sm_map; + return r; + } -public: + // static_cast + template <class U> + ref <U> staticCast() const + { + U* p = static_cast <U*>(const_cast <T*>(m_ptr)); + if (!p) return ref <U>(); - smart_ptr() : m_data(NULL) { } - smart_ptr(T* const p) : m_data(NULL) { if (p) { attach(p); } } - smart_ptr(const smart_ptr& p) : m_data(NULL) { if (p.m_data) { attach(p); } } + p->addStrong(); - ~smart_ptr() { detach(); } + ref <U> r; + r.m_ptr = p; - smart_ptr& operator=(smart_ptr& p) + return r; + } + + // const_cast + template <class U> + ref <U> constCast() const { - attach(p); - return (*this); + U* p = const_cast <U*>(m_ptr); + if (!p) return ref <U>(); + + m_ptr->addStrong(); + + ref <U> r; + r.m_ptr = p; + + return r; } - smart_ptr& operator=(T* const p) + // Implicit downcast + template <class U> + operator ref <const U>() const { - if (!p) - detach(); - else - attach(p); + if (m_ptr) + m_ptr->addStrong(); + + ref <const U> r; + r.m_ptr = m_ptr; // will type check at compile-time (prevent from implicit upcast) - return (*this); + return r; } - operator T*() { return (m_data ? m_data->ptr : NULL); } - operator const T*() { return (m_data ? m_data->ptr : NULL); } + template <class U> + operator ref <U>() + { + if (m_ptr) + m_ptr->addStrong(); - T& operator *() { return (*(m_data->ptr)); } - T* operator ->() { return (m_data->ptr); } + ref <U> r; + r.m_ptr = m_ptr; // will type check at compile-time (prevent from implicit upcast) - const T* const ptr() const { return (m_data ? m_data->ptr : NULL); } - T* const ptr() { return (m_data ? m_data->ptr : NULL); } + return r; + } -private: + template <class U> + ref <T>& operator=(const ref <U>& other) + { + U* ptr = other.m_ptr; // will type check at compile-time (prevent from implicit upcast) + + if (ptr) + ptr->addStrong(); + + detach(); + + m_ptr = ptr; + + return *this; + } + + // Implicit non-const => const conversion + operator ref <const T>() const + { + if (m_ptr) + m_ptr->addStrong(); + + ref <const T> r; + r.m_ptr = m_ptr; + + return r; + } + + // 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; } + + /** 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 <T> fromPtr(T* const ptr) + { + if (ptr) + ptr->addStrong(); + + ref <T> r; + r.m_ptr = ptr; + + return r; + } + +protected: void detach() { - if (m_data) + if (m_ptr) { - if (m_data->refCount == 1) - { - typename MapType::iterator it = sm_map.find(m_data->ptr); - if (it != sm_map.end()) sm_map.erase(it); - - delete (m_data->ptr); - delete (m_data); - } - else - { - m_data->refCount--; - } - - m_data = NULL; + m_ptr->releaseStrong(); + m_ptr = 0; } } - void attach(T* const p) + template <class U> + void attach(U* const ptr) + { + if (ptr) + ptr->addStrong(); + + detach(); + + m_ptr = ptr; + } + + template <class U> + void attach(const ref <U>& r) + { + if (r.m_ptr) + r.m_ptr->addStrong(); + + detach(); + + m_ptr = r.m_ptr; + } + +private: + + T* m_ptr; +}; + + + +template <class T, class U> +bool operator==(const ref <T>& a, const ref <U>& b) +{ + return (a.get() == b.get()); +} + +template <class T, class U> +bool operator!=(const ref <T>& a, const ref <U>& b) +{ + return (a.get() != b.get()); +} + +template <class T> +bool operator==(const ref <T>& a, T* const p) +{ + return (a.get() == p); +} + +template <class T> +bool operator!=(const ref <T>& a, T* const p) +{ + return (a.get() != p); +} + +template <class T> +bool operator==(T* const p, const ref <T>& a) +{ + return (a.get() == p); +} + +template <class T> +bool operator!=(T* const p, const ref <T>& a) +{ + return (a.get() != p); +} + + + +/** Base class for weak references. + */ + +class weak_ref_base +{ + friend class vmime::object; // calls 'notifyObjectDestroyed' + +protected: + + weak_ref_base() { } + weak_ref_base(const weak_ref_base&) { } + virtual ~weak_ref_base() { } + + + virtual void notifyObjectDestroyed() = 0; +}; + + +/** Weak reference. + * Avoid circular references. + */ + +template <class T> +class weak_ref : public weak_ref_base +{ +public: + + template <class U> friend class weak_ref; + + + weak_ref() : m_ptr(0) { } + weak_ref(const ref <T>& r) : m_ptr(0) { attach(r); } + weak_ref(const weak_ref& r) : weak_ref_base(), m_ptr(0) { attach(r); } + weak_ref(const null_ref&) : m_ptr(0) { } + weak_ref(T* const p) : m_ptr(0) { attach(p); } + + ~weak_ref() { detach(); } + + + // Access to wrapped object + operator const T*() 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 <class U> + weak_ref <U> dynamicCast() const + { + U* p = dynamic_cast <U*>(const_cast <T*>(m_ptr)); + if (!p) return weak_ref <U>(); + + weak_ref <U> r; + + p->addWeak(&r); + + r.m_ptr = p; + + return r; + } + + // static_cast + template <class U> + weak_ref <U> staticCast() const + { + U* p = static_cast <U*>(const_cast <T*>(m_ptr)); + if (!p) return weak_ref <U>(); + + weak_ref <U> r; + + p->addWeak(&r); + + r.m_ptr = p; + + return r; + } + + // const_cast + template <class U> + weak_ref <U> constCast() const + { + U* p = const_cast <U*>(m_ptr); + if (!p) return weak_ref <U>(); + + weak_ref <U> r; + + p->addWeak(&r); + + r.m_ptr = p; + + return r; + } + + // Implicit downcast + template <class U> + operator weak_ref <const U>() + { + weak_ref <const U> r; + + if (m_ptr) + m_ptr->addWeak(&r); + + r.m_ptr = m_ptr; // will type check at compile-time (prevent from implicit upcast) + + return r; + } + + // Implicit downcast + template <class U> + operator weak_ref <U>() + { + weak_ref <U> r; + + if (m_ptr) + m_ptr->addWeak(&r); + + r.m_ptr = m_ptr; // will type check at compile-time (prevent from implicit upcast) + + return r; + } + + template <class U> + weak_ref <T>& operator=(const weak_ref <U>& other) { + U* ptr = other.m_ptr; // will type check at compile-time (prevent from implicit upcast) + + if (ptr) + ptr->addWeak(this); + detach(); - typename MapType::iterator it = sm_map.find(p); + m_ptr = ptr; + + return *this; + } + + // Implicit non-const => const conversion + operator weak_ref <const T>() const + { + weak_ref <const T> r; + + if (m_ptr) + m_ptr->addWeak(&r); + + r.m_ptr = m_ptr; + + return r; + } + + template <class U> + operator weak_ref <const U>() const + { + weak_ref <const U> r; + + if (m_ptr) + m_ptr->addWeak(&r); + + r.m_ptr = m_ptr; + + return r; + } + + // Copy + weak_ref& operator=(const weak_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; } + +private: - if (it != sm_map.end()) + void notifyObjectDestroyed() + { + m_ptr = 0; + } + + void detach() + { + if (m_ptr) { - (*it).second->refCount++; + m_ptr->releaseWeak(this); + m_ptr = 0; } - else - { - m_data = new data; - m_data->refCount = 1; - m_data->ptr = p; + } - sm_map.insert(typename MapType::value_type(p, m_data)); - } + void attach(const ref <T>& r) + { + if (r.m_ptr) + r.m_ptr->addWeak(this); + + detach(); + + m_ptr = r.m_ptr; } - void attach(const smart_ptr <T>& p) + void attach(const weak_ref& r) { - data* newData = p.m_data; - if (newData) newData->refCount++; + if (r.m_ptr) + r.m_ptr->addWeak(this); detach(); - m_data = newData; + m_ptr = r.m_ptr; } -}; + void attach(T* const p) + { + if (p) + p->addWeak(this); -template <class T> -typename smart_ptr <T>::MapType smart_ptr <T>::sm_map; + detach(); + + m_ptr = p; + } + + + T* m_ptr; +}; } // utility |