summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2009-12-11 18:08:30 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2009-12-11 18:08:30 +0000
commit12172ff178b62b7c4d710ca1a54819a2b1d47a97 (patch)
tree87d9d04822cef0073db27fe1fa5bd11f0c4c86e3
parent3367e41278c26fbe6210a563451bdd238540f538 (diff)
thread-safe but lifetime-unsafe closures for passing closures around instead of sigc::slot, which is thread-unsafe but lifetime-safe (lifetime safe means that the slot is guaranteed to be safe to use no matter what the lifetime of the object to which it refers is)
git-svn-id: svn://localhost/ardour2/branches/3.0@6349 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--libs/pbd/pbd/closure.h120
1 files changed, 120 insertions, 0 deletions
diff --git a/libs/pbd/pbd/closure.h b/libs/pbd/pbd/closure.h
new file mode 100644
index 0000000000..f6c722a072
--- /dev/null
+++ b/libs/pbd/pbd/closure.h
@@ -0,0 +1,120 @@
+#ifndef __pbd_closure_h__
+#define __pbd_closure_h__
+
+#include <glib.h>
+#include <iostream>
+using std::cerr;
+
+namespace PBD {
+
+struct ClosureBaseImpl {
+ ClosureBaseImpl() { g_atomic_int_set (&_ref, 0); }
+
+ ClosureBaseImpl* ref() { g_atomic_int_inc (&_ref); return this; }
+ void unref() { if (g_atomic_int_dec_and_test (&_ref)) delete this; }
+
+ virtual void operator() () = 0;
+
+protected:
+ virtual ~ClosureBaseImpl() { cerr << "DBI @ " << this << " destroyed\n"; }
+
+private:
+ gint _ref;
+};
+
+struct Closure {
+ Closure () : impl (0) {}
+ Closure (ClosureBaseImpl* i) : impl (i->ref()) {}
+ Closure (const Closure& other) : impl (other.impl ? other.impl->ref() : 0) {}
+
+ Closure& operator= (const Closure& other) {
+ if (&other == this) {
+ return *this;
+ }
+ if (impl) {
+ impl->unref();
+ }
+ if (other.impl) {
+ impl = other.impl->ref();
+ } else {
+ impl = 0;
+ }
+ return *this;
+ }
+
+ virtual ~Closure () { if (impl) { impl->unref(); } }
+
+ /* will crash if impl is unset */
+ void operator() () { (*impl)(); }
+
+private:
+ ClosureBaseImpl* impl;
+};
+
+template<typename T>
+struct ClosureImpl0 : public ClosureBaseImpl {
+ ClosureImpl0 (T& obj, void (T::*m)())
+ : object (obj), method (m) {}
+ void operator() () { (object.*method)(); }
+ private:
+ T& object;
+ void (T::*method)();
+};
+
+template<typename T, typename A1>
+struct ClosureImpl1 : public ClosureBaseImpl
+{
+ ClosureImpl1 (T& obj, void (T::*m)(A1), A1 arg)
+ : object (obj), method (m), arg1 (arg) {}
+ void operator() () { (object.*method) (arg1); }
+
+ private:
+ T& object;
+ void (T::*method)(A1);
+ A1 arg1;
+};
+
+template<typename T, typename A1, typename A2>
+struct ClosureImpl2 : public ClosureBaseImpl
+{
+ ClosureImpl2 (T& obj, void (T::*m)( A1, A2), A1 arga, A2 argb)
+ : object (obj), method (m), arg1 (arga), arg2 (argb) {}
+ void operator() () { (object.*method) (arg1, arg2); }
+
+ private:
+ T& object;
+ void (T::*method)(A1, A2);
+ A1 arg1;
+ A2 arg2;
+};
+
+template<typename T, typename A1, typename A2, typename A3>
+struct ClosureImpl3 : public ClosureBaseImpl
+{
+ ClosureImpl3 (T& obj, void (T::*m)( A1, A2, A3), A1 arga, A2 argb, A3 argc)
+ : object (obj), method (m), arg1 (arga), arg2 (argb), arg3 (argc) {}
+ void operator() () { (object.*method) (arg1, arg2, arg3); }
+
+ private:
+ T& object;
+ void (T::*method)(A1, A2, A3);
+ A1 arg1;
+ A2 arg2;
+ A3 arg3;
+};
+
+template<typename T>
+Closure closure (T& t, void (T::*m)()) {return Closure (new ClosureImpl0<T> (t,m)); }
+
+template<typename T, typename A>
+Closure closure (T& t, void (T::*m)(A), A a) { return Closure (new ClosureImpl1<T,A>(t,m,a)); }
+
+template<typename T, typename A1, typename A2>
+Closure closure (T& t, void (T::*m)(A1,A2), A1 a1, A2 a2) { return Closure (new ClosureImpl2<T,A1,A2>(t,m, a1, a2)); }
+
+template<typename T, typename A1, typename A2, typename A3>
+Closure closure (T& t, void (T::*m)(A1, A2, A3), A1 a1, A2 a2, A3 a3) { return Closure (new ClosureImpl3<T,A1,A2,A3>(t,m , a1, a2, a3)); }
+
+}
+
+#endif /* __pbd_closure_h__ */