aboutsummaryrefslogtreecommitdiffstats
path: root/vmime/utility/smartPtr.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'vmime/utility/smartPtr.hpp')
-rw-r--r--vmime/utility/smartPtr.hpp508
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