const iterators
[ardour.git] / libs / pbd / pbd / signals.py
index e5ea09ae2e9cc8e6e830a08352f3a25cb4013327..9495b70f89365bca18bad35b42fb09744e66a090 100644 (file)
 # than this if you want to read the code!
 #
 
+from __future__ import print_function
 import sys
 
 if len(sys.argv) < 2:
-    print 'Syntax: %s <path>' % sys.argv[0]
+    print('Syntax: %s <path>' % sys.argv[0])
     sys.exit(1)
 
 f = open(sys.argv[1], 'w')
 
-print >>f,"/** THIS FILE IS AUTOGENERATED by signals.py: CHANGES WILL BE LOST */\n\n"
+print("/** THIS FILE IS AUTOGENERATED by signals.py: CHANGES WILL BE LOST */\n", file=f)
 
 # Produce a comma-separated string from a list of substrings,
 # giving an optional prefix to each substring
@@ -66,47 +67,57 @@ def signal(f, n, v):
     for a in An:
         an.append(a.lower())
 
+    # If the template is fully specialized, use of typename SomeTypedef::iterator is illegal
+    # in c++03 (should use just SomeTypedef::iterator) [although use of typename is ok in c++0x]
+    # http://stackoverflow.com/questions/6076015/typename-outside-of-template
+    if n == 0 and v:
+        typename = ""
+    else:
+        typename = "typename "
+
+    if v:
+        print("/** A signal with %d parameters (specialisation for a void return) */" % n, file=f)
+    else:
+        print("/** A signal with %d parameters */" % n, file=f)
     if v:
-        print >>f,"template <%s>" % comma_separated(An, "typename ")
-        print >>f,"class Signal%d<%s> : public SignalBase" % (n, comma_separated(["void"] + An))
+        print("template <%s>" % comma_separated(An, "typename "), file=f)
+        print("class Signal%d<%s> : public SignalBase" % (n, comma_separated(["void"] + An)), file=f)
     else:
-        print >>f,"template <%s>" % comma_separated(["R"] + An + ["C = OptionalLastValue<R> "], "typename ")
-        print >>f,"class Signal%d : public SignalBase" % n
+        print("template <%s>" % comma_separated(["R"] + An + ["C = OptionalLastValue<R> "], "typename "), file=f)
+        print("class Signal%d : public SignalBase" % n, file=f)
 
-    print >>f,"{"
-    print >>f,"public:"
-    print >>f,""
+    print("{", file=f)
+    print("public:", file=f)
+    print("", file=f)
     if v:
-        print >>f,"\ttypedef boost::function<void(%s)> slot_function_type;" % comma_separated(An)
-        print >>f,"\ttypedef void result_type;"
+        print("\ttypedef boost::function<void(%s)> slot_function_type;" % comma_separated(An), file=f)
+        print("\ttypedef void result_type;", file=f)
     else:
-        print >>f,"\ttypedef boost::function<R(%s)> slot_function_type;" % comma_separated(An)
-        print >>f,"\ttypedef boost::optional<R> result_type;"
+        print("\ttypedef boost::function<R(%s)> slot_function_type;" % comma_separated(An), file=f)
+        print("\ttypedef boost::optional<R> result_type;", file=f)
 
-    print >>f,""
+    print("", file=f)
 
-    print >>f,"private:"
+    print("private:", file=f)
 
-    print >>f,"""
+    print("""
+       /** The slots that this signal will call on emission */
        typedef std::map<boost::shared_ptr<Connection>, slot_function_type> Slots;
        Slots _slots;
-"""
-
-    print >>f,"public:"
-    print >>f,""
-    print >>f,"\t~Signal%d () {" % n,
-
-    print >>f,"""
-               boost::mutex::scoped_lock lm (_mutex);
-#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))                                                                      
-                for (typename Slots::iterator i = _slots.begin(); i != _slots.end(); ++i) {                                                 
-#else                                                                                                                             
-                for (Slots::iterator i = _slots.begin(); i != _slots.end(); ++i) {                                                          
-#endif                                                                                                                               
-                       i->first->signal_going_away ();
-               }
-       }
-"""
+""", file=f)
+
+    print("public:", file=f)
+    print("", file=f)
+    print("\t~Signal%d () {" % n, file=f)
+
+    print("\t\tGlib::Threads::Mutex::Lock lm (_mutex);", file=f)
+    print("\t\t/* Tell our connection objects that we are going away, so they don't try to call us */", file=f)
+    print("\t\tfor (%sSlots::const_iterator i = _slots.begin(); i != _slots.end(); ++i) {" % typename, file=f)
+
+    print("\t\t\ti->first->signal_going_away ();", file=f)
+    print("\t\t}", file=f)
+    print("\t}", file=f)
+    print("", file=f)
 
     if n == 0:
         p = ""
@@ -115,12 +126,11 @@ def signal(f, n, v):
         p = ", %s" % comma_separated(Anan)
         q = ", %s" % comma_separated(an)
     
-    print >>f,"\tstatic void compositor (typename boost::function<void(%s)> f, EventLoop* event_loop, EventLoop::InvalidationRecord* ir%s) {" % (comma_separated(An), p)
-    print >>f,"\t\tevent_loop->call_slot (ir, boost::bind (f%s));" % q
-    print >>f,"\t}"
-
-    print >>f,"""
+    print("\tstatic void compositor (%sboost::function<void(%s)> f, EventLoop* event_loop, EventLoop::InvalidationRecord* ir%s) {" % (typename, comma_separated(An), p), file=f)
+    print("\t\tevent_loop->call_slot (ir, boost::bind (f%s));" % q, file=f)
+    print("\t}", file=f)
 
+    print("""
        /** Arrange for @a slot to be executed whenever this signal is emitted. 
            Store the connection that represents this arrangement in @a c.
 
@@ -176,7 +186,7 @@ def signal(f, n, v):
                if (ir) {
                        ir->event_loop = event_loop;
                }
-"""
+""", file=f)
     u = []
     for i in range(0, n):
         u.append("_%d" % (i + 1))
@@ -186,15 +196,15 @@ def signal(f, n, v):
     else:
         p = ", %s" % comma_separated(u)
 
-    print >>f,"\t\tclist.add_connection (_connect (boost::bind (&compositor, slot, event_loop, ir%s)));" % p
+    print("\t\tclist.add_connection (_connect (boost::bind (&compositor, slot, event_loop, ir%s)));" % p, file=f)
 
-    print >>f,"""
+    print("""
        }
 
        /** See notes for the ScopedConnectionList variant of this function. This
-       * differs in that it stores the connection to the signal in a single
-       * ScopedConnection rather than a ScopedConnectionList.
-       */
+        *  differs in that it stores the connection to the signal in a single
+        *  ScopedConnection rather than a ScopedConnectionList.
+        */
 
        void connect (ScopedConnection& c, 
                      PBD::EventLoop::InvalidationRecord* ir, 
@@ -204,94 +214,97 @@ def signal(f, n, v):
                if (ir) {
                        ir->event_loop = event_loop;
                }
-"""
-    print >>f,"\t\tc = _connect (boost::bind (&compositor, slot, event_loop, ir%s));" % p
-    print >>f,"\t}"
+""", file=f)
+    print("\t\tc = _connect (boost::bind (&compositor, slot, event_loop, ir%s));" % p, file=f)
+    print("\t}", file=f)
 
-    print >>f,"""
+    print("""
        /** Emit this signal. This will cause all slots connected to it be executed
            in the order that they were connected (cross-thread issues may alter
            the precise execution time of cross-thread slots).
        */
-"""
+""", file=f)
 
     if v:
-        print >>f,"\tvoid operator() (%s)" % comma_separated(Anan)
+        print("\tvoid operator() (%s)" % comma_separated(Anan), file=f)
     else:
-        print >>f,"\ttypename C::result_type operator() (%s)" % comma_separated(Anan)
-    print >>f,"\t{"
-    print >>f,"\t\tSlots s;"
-    print >>f,"\t\t{"
-    print >>f,"\t\t\tboost::mutex::scoped_lock lm (_mutex);"
-    print >>f,"\t\t\ts = _slots;"
-    print >>f,"\t\t}"
+        print("\ttypename C::result_type operator() (%s)" % comma_separated(Anan), file=f)
+    print("\t{", file=f)
+    print("\t\t/* First, take a copy of our list of slots as it is now */", file=f)
+    print("", file=f)
+    print("\t\tSlots s;", file=f)
+    print("\t\t{", file=f)
+    print("\t\t\tGlib::Threads::Mutex::Lock lm (_mutex);", file=f)
+    print("\t\t\ts = _slots;", file=f)
+    print("\t\t}", file=f)
+    print("", file=f)
     if not v:
-        print >>f,"\t\tstd::list<R> r;"
-    if n == 0 and v:
-        print >>f,"""
-#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))                                                                      
-                for (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {                                                 
-#else                                                                                                                             
-                for (Slots::iterator i = s.begin(); i != s.end(); ++i) {                                                          
-#endif                                                                                                                               
-"""
-    else:
-        print >>f,"\t\tfor (typename Slots::iterator i = s.begin(); i != s.end(); ++i) {"
-
-    print >>f,"""
+        print("\t\tstd::list<R> r;", file=f)
+    print("\t\tfor (%sSlots::const_iterator i = s.begin(); i != s.end(); ++i) {" % typename, file=f)
+    print("""
+                       /* We may have just called a slot, and this may have resulted in
+                          disconnection of other slots from us.  The list copy means that
+                          this won't cause any problems with invalidated iterators, but we
+                          must check to see if the slot we are about to call is still on the list.
+                       */
                        bool still_there = false;
                        {
-                               boost::mutex::scoped_lock lm (_mutex);
+                               Glib::Threads::Mutex::Lock lm (_mutex);
                                still_there = _slots.find (i->first) != _slots.end ();
                        }
 
-                       if (still_there) {"""
+                       if (still_there) {""", file=f)
     if v:
-        print >>f,"\t\t\t\t(i->second)(%s);" % comma_separated(an)
+        print("\t\t\t\t(i->second)(%s);" % comma_separated(an), file=f)
     else:
-        print >>f,"\t\t\t\tr.push_back ((i->second)(%s));" % comma_separated(an)
-    print >>f,"\t\t\t}"
-    print >>f,"\t\t}"
+        print("\t\t\t\tr.push_back ((i->second)(%s));" % comma_separated(an), file=f)
+    print("\t\t\t}", file=f)
+    print("\t\t}", file=f)
+    print("", file=f)
     if not v:
-        print >>f,"\t\tC c;"
-        print >>f,"\t\treturn c (r.begin(), r.end());"
-    print >>f,"\t}"
+        print("\t\t/* Call our combiner to do whatever is required to the result values */", file=f)
+        print("\t\tC c;", file=f)
+        print("\t\treturn c (r.begin(), r.end());", file=f)
+    print("\t}", file=f)
 
-    print >>f,"""
+    print("""
        bool empty () {
-               boost::mutex::scoped_lock lm (_mutex);
+               Glib::Threads::Mutex::Lock lm (_mutex);
                return _slots.empty ();
        }
-"""
+""", file=f)
 
     if v:
         tp = comma_separated(["void"] + An)
     else:
         tp = comma_separated(["R"] + An + ["C"])
 
-    print >>f,""
-    print >>f,"private:"
-    print >>f,""
-    print >>f,"\tfriend class Connection;"
+    print("private:", file=f)
+    print("", file=f)
+    print("\tfriend class Connection;", file=f)
 
-    print >>f,"""
+    print("""
        boost::shared_ptr<Connection> _connect (slot_function_type f)
        {
+#ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
+                if (_debug_connection) {
+                        PBD::stacktrace (std::cerr, 10);
+                }
+#endif
                boost::shared_ptr<Connection> c (new Connection (this));
-               boost::mutex::scoped_lock lm (_mutex);
+               Glib::Threads::Mutex::Lock lm (_mutex);
                _slots[c] = f;
                return c;
-       }
-"""
+       }""", file=f)
 
-    print >>f,"""
+    print("""
        void disconnect (boost::shared_ptr<Connection> c)
        {
-               boost::mutex::scoped_lock lm (_mutex);
+               Glib::Threads::Mutex::Lock lm (_mutex);
                _slots.erase (c);
        }
 };    
-"""
+""", file=f)
 
 for i in range(0, 6):
     signal(f, i, False)