]> git.lyx.org Git - lyx.git/blobdiff - boost/libs/signals/src/signal_base.cpp
make sure to dist pch.h and mark PCH_FILE as a built file
[lyx.git] / boost / libs / signals / src / signal_base.cpp
index ccdd0cf2a69f9a9df65a1bbd88ecf73665ae4192..e1f9bd7df96c7ba9453579b0085319b6d2f7c83d 100644 (file)
@@ -1,27 +1,25 @@
 // Boost.Signals library
-//
-// Copyright (C) 2001 Doug Gregor (gregod@cs.rpi.edu)
-//
-// Permission to copy, use, sell and distribute this software is granted
-// provided this copyright notice appears in all copies.
-// Permission to modify the code and to distribute modified code is granted
-// provided this copyright notice appears in all copies, and a notice
-// that the code was modified is included with the copyright notice.
-//
-// This software is provided "as is" without express or implied warranty,
-// and with no claim as to its suitability for any purpose.
+
+// Copyright Douglas Gregor 2001-2004. Use, modification and
+// distribution is subject to the Boost Software License, Version
+// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
 // For more information, see http://www.boost.org
 
+#define BOOST_SIGNALS_SOURCE
+
 #include <boost/signals/detail/signal_base.hpp>
 #include <cassert>
 
 namespace boost {
   namespace BOOST_SIGNALS_NAMESPACE {
     namespace detail {
-      signal_base_impl::signal_base_impl(const compare_type& comp) : 
-       call_depth(0),
-       slots_(comp)
+      signal_base_impl::signal_base_impl(const compare_type& comp,
+                                         const any& combiner)
+        : call_depth(0),
+          slots_(comp),
+          combiner_(combiner)
       {
         flags.delayed_disconnect = false;
         flags.clearing = false;
@@ -40,12 +38,12 @@ namespace boost {
         if (flags.clearing)
           return;
 
-       if (call_depth == 0) {
+        if (call_depth == 0) {
           // Clearing the slot list will disconnect all slots automatically
-         temporarily_set_clearing set_clearing(this);
-         slots_.clear();
-       }
-       else {
+          temporarily_set_clearing set_clearing(this);
+          slots_.clear();
+        }
+        else {
           // We can't actually remove elements from the slot list because there
           // are still iterators into the slot list that must not be
           // invalidated by this operation. So just disconnect each slot
@@ -53,91 +51,52 @@ namespace boost {
           // reach zero, the call list will be cleared.
           flags.delayed_disconnect = true;
           temporarily_set_clearing set_clearing(this);
-         for (slot_iterator i = slots_.begin(); i != slots_.end(); ++i) {
-           i->second.first.disconnect();
-         }
-       }
+          for (iterator i = slots_.begin(); i != slots_.end(); ++i) {
+            i->first.disconnect();
+          }
+        }
       }
 
-      connection 
+      connection
       signal_base_impl::
-        connect_slot(const any& slot,
+        connect_slot(const any& slot_,
                      const any& name,
-                     const std::vector<const trackable*>& bound_objects)
+                     shared_ptr<slot_base::data_t> data,
+                     connect_position at)
       {
-        // Allocate storage for a new basic_connection object to represent the
-        // connection
-        basic_connection* con = new basic_connection();
-
-        // Create a new connection handle object and place the basic_connection
-        // object we just created under its control. Note that the "reset"
-        // routine will delete con if allocation throws.
-        connection slot_connection;
-        slot_connection.reset(con);
+        // Transfer the burden of ownership to a local, scoped
+        // connection.
+        data->watch_bound_objects.set_controlling(false);
+        scoped_connection safe_connection(data->watch_bound_objects);
 
         // Allocate storage for an iterator that will hold the point of
         // insertion of the slot into the list. This is used to later remove
         // the slot when it is disconnected.
-        std::auto_ptr<slot_iterator> saved_iter(new slot_iterator());
+        std::auto_ptr<iterator> saved_iter(new iterator);
 
-        // Add the slot to the list. 
+        // Add the slot to the list.
+        iterator pos = 
+          slots_.insert(name, data->watch_bound_objects, slot_, at);
 
-        slot_iterator pos = 
-          slots_.insert(stored_slot_type(name,
-                                        connection_slot_pair(slot_connection,
-                                                             slot)));
-
-        // Make the copy of the connection in the list disconnect when it is
-        // destroyed
-        pos->second.first.set_controlling();
-
-        // The assignment operation here absolutely must not throw, which 
-        // intuitively makes sense (because any container's insert method 
+        // The assignment operation here absolutely must not throw, which
+        // intuitively makes sense (because any container's insert method
         // becomes impossible to use in an exception-safe manner without this
         // assumption), but doesn't appear to be mentioned in the standard.
         *saved_iter = pos;
-        
+
         // Fill out the connection object appropriately. None of these
         // operations can throw
-        con->signal = this;
-        con->signal_data = saved_iter.release();
-        con->signal_disconnect = &signal_base_impl::slot_disconnected;       
-        
-        // If an exception is thrown the connection will automatically be 
-        // disconnected. 
-        scoped_connection safe_connection = slot_connection;
-        
-        // Connect each of the bound objects
-        for(std::vector<const trackable*>::const_iterator i = 
-              bound_objects.begin();
-            i != bound_objects.end(); 
-            ++i) {
-          // Notify the object that the signal is connecting to it by passing
-          // it a copy of the connection. If the connection
-          // should throw, the scoped connection safe_connection will
-          // disconnect the connection completely.
-          bound_object binding;
-          (*i)->signal_connected(slot_connection, binding);
-
-          // This will notify the bound object that the connection just made
-          // should be disconnected if an exception is thrown before the
-          // end of this iteration
-          auto_disconnect_bound_object disconnector(binding);
-
-          // Add the binding to the list of bindings for the connection.
-          con->bound_objects.push_back(binding);
-
-          // The connection object now knows about the bound object, so if an
-          // exception is thrown later the connection object will notify the
-          // bound object of the disconnection automatically
-          disconnector.release();
-        }
-
-        // No exceptions will be thrown past this point, and we must not
-        // disconnect the connection now
-        safe_connection.release();
+        data->watch_bound_objects.get_connection()->signal = this;
+        data->watch_bound_objects.get_connection()->signal_data = 
+          saved_iter.release();
+        data->watch_bound_objects.get_connection()->signal_disconnect = 
+          &signal_base_impl::slot_disconnected;
 
-        return slot_connection;
+        // Make the copy of the connection in the list disconnect when it is
+        // destroyed. The local, scoped connection is then released
+        // because ownership has been transferred.
+        pos->first.set_controlling();
+        return safe_connection.release();
       }
 
       bool signal_base_impl::empty() const
@@ -145,35 +104,37 @@ namespace boost {
         // Disconnected slots may still be in the list of slots if
         //   a) this is called while slots are being invoked (call_depth > 0)
         //   b) an exception was thrown in remove_disconnected_slots
-        for (slot_iterator i = slots_.begin(); i != slots_.end(); ++i) {
-          if (i->second.first.connected())
+        for (iterator i = slots_.begin(); i != slots_.end(); ++i) {
+          if (i->first.connected())
             return false;
         }
 
         return true;
       }
 
-      void signal_base_impl::disconnect(const any& group)
+      std::size_t signal_base_impl::num_slots() const
       {
-        std::pair<slot_iterator, slot_iterator> group_slots = 
-          slots_.equal_range(group);
-        while (group_slots.first != group_slots.second) {
-          slot_iterator next = group_slots.first;
-          ++next;
-
-          group_slots.first->second.first.disconnect();
-          group_slots.first = next;
+        // Disconnected slots may still be in the list of slots if
+        //   a) this is called while slots are being invoked (call_depth > 0)
+        //   b) an exception was thrown in remove_disconnected_slots
+        std::size_t count = 0;
+        for (iterator i = slots_.begin(); i != slots_.end(); ++i) {
+          if (i->first.connected())
+            ++count;
         }
+        return count;
       }
 
+      void signal_base_impl::disconnect(const any& group)
+      { slots_.disconnect(group); }
+
       void signal_base_impl::slot_disconnected(void* obj, void* data)
       {
         signal_base_impl* self = reinterpret_cast<signal_base_impl*>(obj);
 
         // We won't need the slot iterator after this
-        std::auto_ptr<slot_iterator> slot(
-                                      reinterpret_cast<slot_iterator*>(data));
-    
+        std::auto_ptr<iterator> slot(reinterpret_cast<iterator*>(data));
+
         // If we're flags.clearing, we don't bother updating the list of slots
         if (!self->flags.clearing) {
           // If we're in a call, note the fact that a slot has been deleted so
@@ -189,19 +150,11 @@ namespace boost {
       }
 
       void signal_base_impl::remove_disconnected_slots() const
-      {
-        // Remove any disconnected slots
-        for (slot_iterator i = slots_.begin(); i != slots_.end(); /* none */) {
-          if (!i->second.first.connected())
-            slots_.erase(i++);
-          else
-            ++i;
-        }
-      }
+      { slots_.remove_disconnected_slots(); }
 
       call_notification::
         call_notification(const shared_ptr<signal_base_impl>& b) :
-         impl(b)
+          impl(b)
       {
         // A call will be made, so increment the call depth as a notification
         impl->call_depth++;
@@ -213,24 +166,24 @@ namespace boost {
 
         // If the call depth is zero and we have some slots that have been
         // disconnected during the calls, remove those slots from the list
-        if (impl->call_depth == 0 && 
-           impl->flags.delayed_disconnect) {
+        if (impl->call_depth == 0 &&
+            impl->flags.delayed_disconnect) {
           impl->remove_disconnected_slots();
           impl->flags.delayed_disconnect = false;
         }
       }
 
-      signal_base::~signal_base()
-      {
-      }
+    signal_base::signal_base(const compare_type& comp, const any& combiner)
+      : impl()
+    {
+      impl.reset(new signal_base_impl(comp, combiner));
+    }
+
+    signal_base::~signal_base()
+    {
+    }
+
     } // namespace detail
   } // namespace BOOST_SIGNALS_NAMESPACE
 } // namespace boost
 
-#ifndef BOOST_MSVC
-// Explicit instantiations to keep in the library
-template class boost::function2<bool, boost::any, boost::any>;
-template class std::multimap<boost::any, 
-                             boost::BOOST_SIGNALS_NAMESPACE::detail::connection_slot_pair, 
-                             boost::function2<bool, boost::any, boost::any> >;
-#endif