You can subscribe to this list here.
| 2005 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(89) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2006 |
Jan
(208) |
Feb
(76) |
Mar
(55) |
Apr
(74) |
May
(43) |
Jun
(116) |
Jul
(109) |
Aug
(46) |
Sep
(36) |
Oct
(106) |
Nov
(159) |
Dec
(128) |
| 2007 |
Jan
(54) |
Feb
(225) |
Mar
(200) |
Apr
(229) |
May
(7) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
Update of /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/doc In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv2126 Modified Files: design.xml faq.xml introduction.xml rationale.xml signals.xml tests.xml tutorial.xml Log Message: Updated documentation. Index: tutorial.xml =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/doc/tutorial.xml,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- tutorial.xml 5 Mar 2007 19:54:28 -0000 1.1 +++ tutorial.xml 6 Mar 2007 21:51:55 -0000 1.2 @@ -681,7 +681,7 @@ <para>Slots can be temporarily "blocked", meaning that they will be ignored when the signal is invoked but have not been disconnected. A -<class>boost::signals::shared_connection_block</class> object will +<classname>boost::signals::shared_connection_block</classname> object will temporarily block a slot. The connection is unblocked by either destroying or calling <methodname alt="shared_connection_block::unblock">unblock</methodname> @@ -861,6 +861,14 @@ <classname alt="slotN">slot</classname> constructor is passed more than one argument, it will automatically pass all the arguments to <code>bind</code> and use the returned function object.</para> +<para>One limitation of using <code>shared_ptr</code> for tracking is that +an object cannot setup tracking of itself in its constructor. However, it is +possible to set up tracking in a post-constructor. In a post-constructor, +a <code>shared_ptr</code> to <code>this</code> can be obtained by using +<classname>enable_shared_from_this</classname>. You may also find +<functionname>deconstruct_ptr</functionname> useful as a simple +post-constructor/pre-destructor framework for your classes. +</para> </section> <section><title>When can disconnections occur? (Intermediate)</title> @@ -873,7 +881,7 @@ <code>scoped_connection</code>'s destructor.</para></listitem> <listitem><para>An object tracked by the slot is destroyed.</para></listitem> -<listitem><para>A slot throws an <class>boost::expired_slot</class> exception. +<listitem><para>A slot throws an <classname>boost::expired_slot</classname> exception. </para></listitem> <listitem><para>The signal is destroyed.</para></listitem></itemizedlist> <para>These events can occur at any time without disrupting a signal's Index: introduction.xml =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/doc/introduction.xml,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- introduction.xml 5 Mar 2007 19:54:28 -0000 1.1 +++ introduction.xml 6 Mar 2007 21:51:55 -0000 1.2 @@ -4,12 +4,6 @@ <section last-revision="$Date$"> <title>Introduction</title> -<para>This documentation describes a thread-safe variant of the -official Boost.Signals library. There have been some changes to -the interface to support thread-safety, mostly with respect to -automatic connection management. -</para> - <para>The Boost.Signals library is an implementation of a managed signals and slots system. Signals represent callbacks with multiple targets, and are also called publishers or events in similar @@ -18,7 +12,7 @@ are called when the signal is "emitted."</para> <para>Signals and slots are managed, in that signals and slots (or, -more properly, objects that occur as part of the slots) track all +more properly, objects that occur as part of the slots) can track connections and are capable of automatically disconnecting signal/slot connections when either is destroyed. This enables the user to make signal/slot connections without expending a great effort to manage the @@ -31,4 +25,13 @@ user to specify the manner in which multiple return values are combined.</para> +<para>This documentation describes a thread-safe variant of the +official Boost.Signals library. There have been some changes to +the interface to support thread-safety, mostly with respect to +automatic connection management. This implementation was written by +Frank Mori Hess. Acknowledgements are also due to Timmo Stange, Peter +Dimov, and Gottlob Frege for ideas and feedback, and to Douglas Gregor +for the original version of Boost.Signals this effort was based on. +</para> + </section> \ No newline at end of file |
|
From: Frank M. H. <fm...@us...> - 2007-03-06 21:47:10
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv32424 Modified Files: postconstructible.hpp predestructible.hpp deconstruct_ptr.hpp Log Message: Added BOOST_ABI_PREFIX/SUFFIX and made some minor tweaks to deconstruct_ptr.hpp. Index: predestructible.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/predestructible.hpp,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- predestructible.hpp 3 Mar 2007 16:46:29 -0000 1.3 +++ predestructible.hpp 6 Mar 2007 21:47:07 -0000 1.4 @@ -12,6 +12,10 @@ #ifndef BOOST_PREDESTRUCTIBLE_HEADER #define BOOST_PREDESTRUCTIBLE_HEADER +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + namespace boost { class predestructible @@ -23,4 +27,9 @@ virtual ~predestructible() {} }; } + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + #endif Index: deconstruct_ptr.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/deconstruct_ptr.hpp,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- deconstruct_ptr.hpp 23 Feb 2007 14:38:13 -0000 1.4 +++ deconstruct_ptr.hpp 6 Mar 2007 21:47:07 -0000 1.5 @@ -16,6 +16,10 @@ #include <boost/predestructible.hpp> #include <boost/shared_ptr.hpp> +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + namespace boost { namespace deconstruct_detail @@ -32,16 +36,16 @@ template<typename T> class predestructing_deleter { public: - void operator()(T *ptr) + void operator()(const T *ptr) const { m_predestruct(ptr); checked_delete(ptr); } private: - void m_predestruct(...) + static void m_predestruct(...) { } - void m_predestruct(const boost::predestructible *ptr) + static void m_predestruct(const boost::predestructible *ptr) { boost::predestructible *nonconst_ptr = const_cast<boost::predestructible*>(ptr); nonconst_ptr->predestruct(); @@ -65,4 +69,9 @@ return shared; } } + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + #endif Index: postconstructible.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/postconstructible.hpp,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- postconstructible.hpp 7 Feb 2007 18:14:48 -0000 1.2 +++ postconstructible.hpp 6 Mar 2007 21:47:06 -0000 1.3 @@ -12,6 +12,9 @@ #ifndef BOOST_POSTCONSTRUCTIBLE_HEADER #define BOOST_POSTCONSTRUCTIBLE_HEADER +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif namespace boost { @@ -31,4 +34,9 @@ virtual void postconstruct() {} }; } + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + #endif |
|
From: Frank M. H. <fm...@us...> - 2007-03-06 18:18:36
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv13063 Modified Files: last_value.hpp Log Message: tweaked no_slots_error exception. Index: last_value.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/last_value.hpp,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- last_value.hpp 5 Mar 2007 15:10:54 -0000 1.4 +++ last_value.hpp 6 Mar 2007 18:18:30 -0000 1.5 @@ -19,11 +19,10 @@ class expired_slot; // no_slots_error is thrown when we are unable to generate a return value // due to no slots being connected to the signal. - class no_slots_error: public std::runtime_error + class no_slots_error: public std::exception { public: - no_slots_error(const std::string &description): std::runtime_error(description) - {} + virtual const char* what() {return "boost::no_slots_error";} }; namespace last_value_detail { template<typename T> |
|
From: Frank M. H. <fm...@us...> - 2007-03-06 18:17:37
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv12645/thread_safe_signals Modified Files: connection.hpp Log Message: Added some missing BOOST_ABI_PREFIX/BOOST_ABI_SUFFIX Index: connection.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/connection.hpp,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- connection.hpp 5 Mar 2007 15:34:36 -0000 1.25 +++ connection.hpp 6 Mar 2007 18:17:30 -0000 1.26 @@ -32,6 +32,10 @@ #include <boost/weak_ptr.hpp> #include <vector> +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + namespace boost { namespace signalslib @@ -209,4 +213,8 @@ } } +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + #endif // _EPG_SIGNALS_CONNECTION_H |
|
From: Frank M. H. <fm...@us...> - 2007-03-06 18:17:34
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv12645 Modified Files: thread_safe_signal.hpp Log Message: Added some missing BOOST_ABI_PREFIX/BOOST_ABI_SUFFIX Index: thread_safe_signal.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signal.hpp,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- thread_safe_signal.hpp 2 Mar 2007 16:00:38 -0000 1.17 +++ thread_safe_signal.hpp 6 Mar 2007 18:17:30 -0000 1.18 @@ -32,6 +32,7 @@ #include <algorithm> #include <boost/assert.hpp> +#include <boost/config.hpp> #include <boost/function.hpp> #include <boost/last_value.hpp> #include <boost/preprocessor/arithmetic.hpp> @@ -49,9 +50,12 @@ #include <boost/thread_safe_signals/shared_connection_block.hpp> #include <boost/thread_safe_signals/single_threaded.hpp> #include <boost/thread_safe_signals/slot.hpp> -#include <boost/thread_safe_signals/track.hpp> #include <functional> +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + #define BOOST_PP_ITERATION_LIMITS (0, BOOST_SIGNALS_MAX_ARGS) #define BOOST_PP_FILENAME_1 <boost/thread_safe_signals/detail/signal_template.hpp> #include BOOST_PP_ITERATE() @@ -81,4 +85,8 @@ }; } +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + #endif // _THREAD_SAFE_SIGNAL_HPP |
|
From: Frank M. H. <fm...@us...> - 2007-03-06 18:17:32
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv12645/thread_safe_signals/detail Modified Files: slot_groups.hpp Log Message: Added some missing BOOST_ABI_PREFIX/BOOST_ABI_SUFFIX Index: slot_groups.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/slot_groups.hpp,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- slot_groups.hpp 1 Mar 2007 18:57:35 -0000 1.14 +++ slot_groups.hpp 6 Mar 2007 18:17:31 -0000 1.15 @@ -10,16 +10,16 @@ #ifndef BOOST_TSS_SLOT_GROUPS_HEADER #define BOOST_TSS_SLOT_GROUPS_HEADER -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - #include <boost/thread_safe_signals/connection.hpp> #include <boost/optional.hpp> #include <list> #include <map> #include <utility> +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + namespace boost { namespace signalslib { namespace detail { |
|
From: Frank M. H. <fm...@us...> - 2007-03-06 16:59:34
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv11756/thread_safe_signals/detail Modified Files: signal_template.hpp slot_template.hpp Log Message: Added use of BOOST_STATIC_CONSTANT. Index: signal_template.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/signal_template.hpp,v retrieving revision 1.43 retrieving revision 1.44 diff -u -d -r1.43 -r1.44 --- signal_template.hpp 5 Mar 2007 14:52:46 -0000 1.43 +++ signal_template.hpp 6 Mar 2007 16:59:30 -0000 1.44 @@ -414,7 +414,7 @@ typedef arg1_type first_argument_type; typedef arg2_type second_argument_type; #endif - static const int arity = BOOST_SIGNALS_NUM_ARGS; + BOOST_STATIC_CONSTANT(int, arity = BOOST_SIGNALS_NUM_ARGS); BOOST_SIGNAL_CLASS_NAME(const combiner_type &combiner = combiner_type(), const group_compare_type &group_compare = group_compare_type()): Index: slot_template.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/slot_template.hpp,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- slot_template.hpp 5 Mar 2007 21:08:38 -0000 1.9 +++ slot_template.hpp 6 Mar 2007 16:59:33 -0000 1.10 @@ -42,7 +42,7 @@ typedef arg1_type first_argument_type; typedef arg2_type second_argument_type; #endif - static const int arity = BOOST_SIGNALS_NUM_ARGS; + BOOST_STATIC_CONSTANT(int, arity = BOOST_SIGNALS_NUM_ARGS); template<typename F> BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)(const F& f): _slot_function(signalslib::detail::get_invocable_slot(f, signalslib::detail::tag_type(f))) |
|
From: Frank M. H. <fm...@us...> - 2007-03-06 16:58:32
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv11342/thread_safe_signals Modified Files: shared_connection_block.hpp Log Message: Added shared_connection_block::blocking() query. Index: shared_connection_block.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/shared_connection_block.hpp,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- shared_connection_block.hpp 5 Mar 2007 15:34:36 -0000 1.2 +++ shared_connection_block.hpp 6 Mar 2007 16:58:30 -0000 1.3 @@ -42,6 +42,10 @@ { _blocker.reset(); } + bool blocking() const + { + return _blocker != 0; + } private: boost::weak_ptr<detail::ConnectionBodyBase> _weakConnectionBody; shared_ptr<void> _blocker; |
|
From: Jan G. <jan...@us...> - 2007-03-06 00:05:05
|
Update of /cvsroot/boost-sandbox/boost-sandbox/libs/circular_buffer/test In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv8179/libs/circular_buffer/test Modified Files: space_optimized_test.cpp test.hpp Log Message: Iterator invalidation made more explicit. Index: space_optimized_test.cpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/libs/circular_buffer/test/space_optimized_test.cpp,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- space_optimized_test.cpp 18 Feb 2007 23:03:27 -0000 1.11 +++ space_optimized_test.cpp 6 Mar 2007 00:03:46 -0000 1.12 @@ -6,8 +6,6 @@ // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_CB_TEST - #include "test.hpp" #define CB_CONTAINER circular_buffer_space_optimized Index: test.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/libs/circular_buffer/test/test.hpp,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- test.hpp 18 Dec 2006 01:30:29 -0000 1.13 +++ test.hpp 6 Mar 2007 00:03:46 -0000 1.14 @@ -13,6 +13,8 @@ #pragma once #endif +#define BOOST_CB_TEST + #include <boost/circular_buffer.hpp> #include <boost/test/included/unit_test_framework.hpp> #include <boost/iterator.hpp> |
|
From: Jan G. <jan...@us...> - 2007-03-06 00:05:04
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/circular_buffer In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv8179/boost/circular_buffer Modified Files: base.hpp debug.hpp details.hpp Log Message: Iterator invalidation made more explicit. Index: base.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/circular_buffer/base.hpp,v retrieving revision 1.81 retrieving revision 1.82 diff -u -d -r1.81 -r1.82 --- base.hpp 26 Feb 2007 22:37:08 -0000 1.81 +++ base.hpp 6 Mar 2007 00:03:46 -0000 1.82 @@ -60,7 +60,11 @@ http://www.boost.org/libs/circular_buffer/doc/circular_buffer.html */ template <class T, class Alloc> -class circular_buffer : public cb_details::iterator_registry { +class circular_buffer +#if BOOST_CB_ENABLE_DEBUG +: public cb_details::debug_iterator_registry +#endif // #if BOOST_CB_ENABLE_DEBUG +{ // Requirements BOOST_CLASS_REQUIRE(T, boost, SGIAssignableConcept); @@ -654,7 +658,7 @@ m_first = m_buff; m_last = add(m_buff, size()); #if BOOST_CB_ENABLE_DEBUG - invalidate_all_iterators(); + invalidate_iterators_except(end()); #endif return m_buff; } @@ -1061,7 +1065,12 @@ Invalidates all iterators pointing to the <code>circular_buffer</code>. \sa <code>clear()</code> */ - ~circular_buffer() { destroy(); } + ~circular_buffer() { + destroy(); +#if BOOST_CB_ENABLE_DEBUG + invalidate_all_iterators(); +#endif + } public: // Assign methods @@ -1896,9 +1905,6 @@ void destroy_content() { for (size_type ii = 0; ii < size(); ++ii, increment(m_first)) destroy_item(m_first); -#if BOOST_CB_ENABLE_DEBUG - invalidate_iterators(end()); -#endif } //! Destroy content and free allocated memory. Index: debug.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/circular_buffer/debug.hpp,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- debug.hpp 26 Feb 2007 22:37:09 -0000 1.10 +++ debug.hpp 6 Mar 2007 00:03:46 -0000 1.11 @@ -22,47 +22,47 @@ // The value the uninitialized memory is filled with. const int UNINITIALIZED = 0xcc; -class iterator_registry; +class debug_iterator_registry; /*! - \class iterator_base + \class debug_iterator_base \brief Registers/unregisters iterators into the registry of valid iterators. This class is intended to be a base class of an iterator. */ -class iterator_base { +class debug_iterator_base { private: // Members //! Iterator registry. - mutable const iterator_registry* m_registry; + mutable const debug_iterator_registry* m_registry; //! Next iterator in the iterator chain. - mutable const iterator_base* m_next; + mutable const debug_iterator_base* m_next; public: // Construction/destruction //! Default constructor. - iterator_base(); + debug_iterator_base(); //! Constructor taking the iterator registry as a parameter. - iterator_base(const iterator_registry* registry); + debug_iterator_base(const debug_iterator_registry* registry); //! Copy constructor. - iterator_base(const iterator_base& rhs); + debug_iterator_base(const debug_iterator_base& rhs); //! Destructor. - ~iterator_base(); + ~debug_iterator_base(); // Methods //! Assign operator. - iterator_base& operator = (const iterator_base& rhs); + debug_iterator_base& operator = (const debug_iterator_base& rhs); //! Is the iterator valid? - bool is_valid(const iterator_registry* registry) const; + bool is_valid(const debug_iterator_registry* registry) const; //! Invalidate the iterator. /*! @@ -71,13 +71,13 @@ void invalidate() const; //! Return the next iterator in the iterator chain. - const iterator_base* next() const; + const debug_iterator_base* next() const; //! Set the next iterator in the iterator chain. /*! \note The method is const in order to set a next iterator to a const iterator, too. */ - void set_next(const iterator_base* it) const; + void set_next(const debug_iterator_base* it) const; private: // Helpers @@ -90,27 +90,27 @@ }; /*! - \class iterator_registry + \class debug_iterator_registry \brief Registry of valid iterators. This class is intended to be a base class of a container. */ -class iterator_registry { +class debug_iterator_registry { //! Pointer to the chain of valid iterators. - mutable const iterator_base* m_iterators; + mutable const debug_iterator_base* m_iterators; public: // Methods //! Default constructor. - iterator_registry() : m_iterators(0) {} + debug_iterator_registry() : m_iterators(0) {} //! Register an iterator into the list of valid iterators. /*! \note The method is const in order to register iterators into const containers, too. */ - void register_iterator(const iterator_base* it) const { + void register_iterator(const debug_iterator_base* it) const { it->set_next(m_iterators); m_iterators = it; } @@ -119,24 +119,17 @@ /*! \note The method is const in order to unregister iterators from const containers, too. */ - void unregister_iterator(const iterator_base* it) const { - const iterator_base* previous = 0; - for (const iterator_base* p = m_iterators; p != it; previous = p, p = p->next()); + void unregister_iterator(const debug_iterator_base* it) const { + const debug_iterator_base* previous = 0; + for (const debug_iterator_base* p = m_iterators; p != it; previous = p, p = p->next()); remove(it, previous); } - //! Invalidate all iterators. - void invalidate_all_iterators() { - for (const iterator_base* p = m_iterators; p != 0; p = p->next()) - p->invalidate(); - m_iterators = 0; - } - - //! Invalidate every iterator conforming to the condition. + //! Invalidate every iterator pointing to the same element as the iterator passed as a parameter. template <class Iterator> void invalidate_iterators(const Iterator& it) { - const iterator_base* previous = 0; - for (const iterator_base* p = m_iterators; p != 0; p = p->next()) { + const debug_iterator_base* previous = 0; + for (const debug_iterator_base* p = m_iterators; p != 0; p = p->next()) { if (((Iterator*)p)->m_it == it.m_it) { p->invalidate(); remove(p, previous); @@ -146,12 +139,33 @@ } } + //! Invalidate all iterators except an iterator poining to the same element as the iterator passed as a parameter. + template <class Iterator> + void invalidate_iterators_except(const Iterator& it) { + const debug_iterator_base* previous = 0; + for (const debug_iterator_base* p = m_iterators; p != 0; p = p->next()) { + if (((Iterator*)p)->m_it != it.m_it) { + p->invalidate(); + remove(p, previous); + continue; + } + previous = p; + } + } + + //! Invalidate all iterators. + void invalidate_all_iterators() { + for (const debug_iterator_base* p = m_iterators; p != 0; p = p->next()) + p->invalidate(); + m_iterators = 0; + } + private: // Helpers //! Remove the current iterator from the iterator chain. - void remove(const iterator_base* current, - const iterator_base* previous) const { + void remove(const debug_iterator_base* current, + const debug_iterator_base* previous) const { if (previous == 0) m_iterators = m_iterators->next(); else @@ -159,23 +173,23 @@ } }; -// Implementation of the iterator_base methods. +// Implementation of the debug_iterator_base methods. -inline iterator_base::iterator_base() : m_registry(0), m_next(0) {} +inline debug_iterator_base::debug_iterator_base() : m_registry(0), m_next(0) {} -inline iterator_base::iterator_base(const iterator_registry* registry) +inline debug_iterator_base::debug_iterator_base(const debug_iterator_registry* registry) : m_registry(registry), m_next(0) { register_self(); } -inline iterator_base::iterator_base(const iterator_base& rhs) +inline debug_iterator_base::debug_iterator_base(const debug_iterator_base& rhs) : m_registry(rhs.m_registry), m_next(0) { register_self(); } -inline iterator_base::~iterator_base() { unregister_self(); } +inline debug_iterator_base::~debug_iterator_base() { unregister_self(); } -inline iterator_base& iterator_base::operator = (const iterator_base& rhs) { +inline debug_iterator_base& debug_iterator_base::operator = (const debug_iterator_base& rhs) { if (m_registry == rhs.m_registry) return *this; unregister_self(); @@ -184,42 +198,26 @@ return *this; } -inline bool iterator_base::is_valid(const iterator_registry* registry) const { return m_registry == registry; } +inline bool debug_iterator_base::is_valid(const debug_iterator_registry* registry) const { + return m_registry == registry; +} -inline void iterator_base::invalidate() const { m_registry = 0; } +inline void debug_iterator_base::invalidate() const { m_registry = 0; } -inline const iterator_base* iterator_base::next() const { return m_next; } +inline const debug_iterator_base* debug_iterator_base::next() const { return m_next; } -inline void iterator_base::set_next(const iterator_base* it) const { m_next = it; } +inline void debug_iterator_base::set_next(const debug_iterator_base* it) const { m_next = it; } -inline void iterator_base::register_self() { +inline void debug_iterator_base::register_self() { if (m_registry != 0) m_registry->register_iterator(this); } -inline void iterator_base::unregister_self() { +inline void debug_iterator_base::unregister_self() { if (m_registry != 0) m_registry->unregister_iterator(this); } -#else // #if BOOST_CB_ENABLE_DEBUG - -class iterator_registry { -#if BOOST_WORKAROUND(__BORLANDC__, < 0x6000) - char dummy_; // BCB: by default empty structure has 8 bytes -#endif -}; - -class iterator_base { -#if BOOST_WORKAROUND(__BORLANDC__, < 0x6000) - char dummy_; // BCB: by default empty structure has 8 bytes -#endif - -public: - iterator_base() {} - iterator_base(const iterator_registry*) {} -}; - #endif // #if BOOST_CB_ENABLE_DEBUG } // namespace cb_details Index: details.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/circular_buffer/details.hpp,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- details.hpp 26 Feb 2007 22:37:09 -0000 1.23 +++ details.hpp 6 Mar 2007 00:03:46 -0000 1.24 @@ -191,8 +191,10 @@ typename Traits::value_type, typename Traits::difference_type, typename Traits::pointer, - typename Traits::reference>, - public iterator_base + typename Traits::reference> +#if BOOST_CB_ENABLE_DEBUG + , public debug_iterator_base +#endif // #if BOOST_CB_ENABLE_DEBUG { private: // Helper types @@ -226,6 +228,9 @@ //! Difference type. typedef typename base_iterator::difference_type difference_type; +#if !defined(BOOST_CB_TEST) +private: +#endif // #if !defined(BOOST_CB_TEST) // Member variables //! The circular buffer where the iterator points to. @@ -234,6 +239,7 @@ //! An internal iterator. pointer m_it; +public: // Construction & assignment // Default copy constructor. @@ -241,20 +247,32 @@ //! Default constructor. iterator() : m_buff(0), m_it(0) {} +#if BOOST_CB_ENABLE_DEBUG + //! Copy constructor (used for converting from a non-const to a const iterator). - iterator(const nonconst_self& it) : iterator_base(it), m_buff(it.m_buff), m_it(it.m_it) {} + iterator(const nonconst_self& it) : debug_iterator_base(it), m_buff(it.m_buff), m_it(it.m_it) {} //! Internal constructor. /*! \note This constructor is not intended to be used directly by the user. */ - iterator(const Buff* cb, const pointer p) : iterator_base(cb), m_buff(cb), m_it(p) {} + iterator(const Buff* cb, const pointer p) : debug_iterator_base(cb), m_buff(cb), m_it(p) {} + +#else + + iterator(const nonconst_self& it) : m_buff(it.m_buff), m_it(it.m_it) {} + + iterator(const Buff* cb, const pointer p) : m_buff(cb), m_it(p) {} + +#endif // #if BOOST_CB_ENABLE_DEBUG //! Assign operator. iterator& operator = (const iterator& it) { if (this == &it) return *this; - iterator_base::operator =(it); +#if BOOST_CB_ENABLE_DEBUG + debug_iterator_base::operator =(it); +#endif // #if BOOST_CB_ENABLE_DEBUG m_buff = it.m_buff; m_it = it.m_it; return *this; |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 21:08:44
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv5663/thread_safe_signals/detail Modified Files: slot_template.hpp Log Message: Removed overload of slot::track() that takes a signal reference, since signals cannot be tracked in general (except in the usual way all other objects can be tracked. Index: slot_template.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/slot_template.hpp,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- slot_template.hpp 5 Mar 2007 14:52:46 -0000 1.8 +++ slot_template.hpp 5 Mar 2007 21:08:38 -0000 1.9 @@ -101,12 +101,6 @@ } return *this; } - BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)& track(const signalslib::detail::signal_base &signal) - { - // call base class function, since it is a friend of signal_base and can call lock_pimpl() - track_signal(signal); - return *this; - } const slot_function_type& slot_function() const {return _slot_function;} slot_function_type& slot_function() {return _slot_function;} |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 19:56:01
|
Update of /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/doc In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv6716 Added Files: index.html Log Message: Copied from signals/doc. --- NEW FILE: index.html --- <html> <head> <meta http-equiv="refresh" content="0; URL=../../../doc/html/signals.html"> </head> <body> Automatic redirection failed, please go to <a href="../../../doc/html/signals.html">../../../doc/html/signals.html</a> <hr> <p>© Copyright Beman Dawes, 2001</p> <p>Distributed under the Boost Software License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p> </body> </html> |
Update of /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/doc In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv5908/doc Added Files: design.xml faq.xml introduction.xml rationale.xml signals.xml tests.xml tutorial.xml Log Message: Moved docs from libs/signals/doc. Updated to reflect some of the more recent changes. --- NEW FILE: faq.xml --- <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> <section last-revision="$Date: 2007/03/05 19:54:28 $"> <title>Frequently Asked Questions</title> <qandaset> <qandaentry> <question> <para>Don't noncopyable signal semantics mean that a class with a signal member will be noncopyable as well?</para> </question> <answer> <para>No. The compiler will not be able to generate a copy constructor or copy assignment operator for your class if it has a signal as a member, but you are free to write your own copy constructor and/or copy assignment operator. Just don't try to copy the signal.</para> </answer> </qandaentry> <qandaentry> <question> <para>Is Boost.Signals thread-safe?</para> </question> <answer> <para>Yes, if the ThreadingModel template parameter of the signal is set to boost::signals::multi_threaded. If you use thread-safe signals in your code, you will also have to link to libboost_thread.</para> </answer> </qandaentry> <qandaentry> <question> <para>How do I get Boost.Signals to work with Qt?</para> </question> <answer> <para>When building with Qt, the Moc keywords <code>signals</code> and <code>slots</code> are defined using preprocessor macros, causing programs using Boost.Signals and Qt together to fail to compile.</para> <para><emphasis>For Qt 4.1 and later</emphasis>, This behavior can be turned off in Qt on a per-project or per-file basis with the <code>no_keywords</code> option. This works with out-of-the-box builds of Boost and Qt. You do not need to re-configure, re-build, or duplicate existing libraries. For a project where you want to use both Boost.Signals and Qt Signals and Slots, the relevant part of your .pro file might look like this:</para> <programlisting> CONFIG += no_keywords # so Qt won't #define any non-all-caps `keywords' INCLUDEPATH += . /usr/local/include/boost-1_33_1/ macx:LIBS += /usr/local/lib/libboost_signals-1_33_1.a # ...your exact paths may vary </programlisting> <para>Now you can mix Boost.Signals and Qt Signals and Slots in the same files, and even within the same class or function. You will have to use the upper-case versions of Qt macros in your own code. See the article <ulink url="http://scottcollins.net/articles/a-deeper-look-at-signals-and-slots.html">A Deeper Look at Signals and Slots</ulink> [off-site] for more complete examples and a survey of the strengths of the two systems.</para> <para><emphasis>Older versions of Qt</emphasis> did not provide a reliable mechanism for avoiding these unfriendly, all lower-case `keyword'-like macros. Although this is a problem with Qt and not Boost.Signals, a user can use the two systems together with a little extra effort. There are two ways to do this:</para> <para>The first way involves defining the <code>BOOST_SIGNALS_NAMESPACE</code> macro to some other identifier (e.g., <code>signalslib</code>) when building and using the Boost.Signals library. Then the namespace of the Boost.Signals library will be <code>boost::BOOST_SIGNALS_NAMESPACE</code> instead of <code>boost::signals</code>. To retain the original namespace name in translation units that do not interact with Qt, you can use a namespace alias:</para> <programlisting> namespace boost { namespace signals = BOOST_SIGNALS_NAMESPACE; } </programlisting> <para>The second way, provided by Frank Hess, involves creating a header <code>signalslib.hpp</code> that contains the following code:</para> <programlisting>#ifdef signals #error "signalslib.hpp must be included before any qt header" #endif #include <boost/signal.hpp> namespace boost { namespace signalslib = signals; }</programlisting> <para>This header must be included before any Qt headers. Once it has been included, you can refer to the Signals library via the namespace <code>boost::signalslib</code>. This option is preferable to the first option because it can be used without recompiling the Signals library binary. </para> </answer> </qandaentry> </qandaset> </section> --- NEW FILE: rationale.xml --- <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> <section last-revision="$Date: 2007/03/05 19:54:28 $"> <title>Design Rationale</title> <using-namespace name="boost"/> <using-namespace name="boost::signals"/> <using-class name="boost::signalN"/> <section> <title>Choice of Slot Definitions</title> <para> The definition of a slot differs amongst signals and slots libraries. Within Boost.Signals, a slot is defined in a very loose manner: it can be any function object that is callable given parameters of the types specified by the signal, and whose return value is convertible to the result type expected by the signal. However, alternative definitions have associated pros and cons that were considered prior to the construction of Boost.Signals.</para> <itemizedlist> <listitem> <para><emphasis role="bold">Slots derive from a specific base class</emphasis>: generally a scheme such as this will require all user-defined slots to derive from some library-specified <code>Slot</code> abstract class that defines a virtual function calling the slot. Adaptors can be used to convert a definition such as this to a definition similar to that used by Boost.Signals, but the use of a large number of small adaptor classes containing virtual functions has been found to cause an unacceptable increase in the size of executables (polymorphic class types require more code than non-polymorphic types).</para> <para> This approach does have the benefit of simplicity of implementation and user interface, from an object-oriented perspective.</para> </listitem> <listitem> <para><emphasis role="bold">Slots constructed from a set of primitives</emphasis>: in this scheme the slot can have a limited set of types (often derived from a common abstract base class) that are constructed from some library-defined set of primitives that often include conversions from free function pointers and member function pointers, and a limited set of binding capabilities. Such an approach is reasonably simple and cover most common cases, but it does not allow a large degree of flexibility in slot construction. Libraries for function object composition have become quite advanced and it is out of the scope of a signals and slots library to encorporate such enhancements. Thus Boost.Signals does not include argument binding or function object composition primitives, but instead provides a hook (via the <code><functionname>visit_each</functionname></code> mechanism) that allows existing binder/composition libraries to provide the necessary information to Signals.</para> </listitem> </itemizedlist> <para> Users not satisfied with the slot definition choice may opt to replace the default slot function type with an alternative that meets their specific needs.</para> </section> <section> <title>User-level Connection Management</title> <para> Users need to have fine control over the connection of signals to slots and their eventual disconnection. The approach taken by Boost.Signals is to return a <code><classname>connection</classname></code> object that enables connected/disconnected query, manual disconnection, and an automatic disconnection on destruction mode. Some other possible interfaces include:</para> <itemizedlist> <listitem> <para><emphasis role="bold">Pass slot to disconnect</emphasis>: in this interface model, the disconnection of a slot connected with <code>sig.<methodname>connect</methodname>(slot)</code> is performed via <code>sig.<methodname>disconnect</methodname>(slot)</code>. Internally, a linear search using slot comparison is performed and the slot, if found, is removed from the list. Unfortunately, querying connectedness will generally also end up as linear-time operations. This model also fails for implementation reasons when slots become more complex than simple function pointers, member function pointers and a limited set of compositions and argument binders: to match the slot given in the call to <code><methodname>disconnect</methodname></code> with an existing slot we would need to be able to compare arbitrary function objects, which is not feasible.</para> </listitem> <listitem> <para><emphasis role="bold">Pass a token to disconnect</emphasis>: this approach identifies slots with a token that is easily comparable (e.g., a string), enabling slots to be arbitrary function objects. While this approach is essentially equivalent to the approach taken by Boost.Signals, it is possibly more error-prone for several reasons:</para> <itemizedlist> <listitem> <para>Connections and disconnections must be paired, so the problem becomes similar to the problems incurred when pairing <code>new</code> and <code>delete</code> for dynamic memory allocation. While errors of this sort would not be catastrophic for a signals and slots implementation, their detection is generally nontrivial.</para> </listitem> <listitem> <para>Tokens must be unique, otherwise two slots will have the same name and will be indistinguishable. In environments where many connections will be made dynamically, name generation becomes an additional task for the user. Uniqueness of tokens also results in an additional failure mode when attempting to connect a slot using a token that has already been used.</para> </listitem> <listitem> <para>More parameterization would be required, because the token type must be user-defined. Additional parameterization steepens the learning curver and overcomplicates a simple interface.</para> </listitem> </itemizedlist> <para> This type of interface is supported in Boost.Signals via the slot grouping mechanism. It augments the <code><classname>connection</classname></code> object-based connection management scheme.</para> </listitem> </itemizedlist> </section> <section> <title>Combiner Interface</title> <para> The Combiner interface was chosen to mimic a call to an algorithm in the C++ standard library. It is felt that by viewing slot call results as merely a sequence of values accessed by input iterators, the combiner interface would be most natural to a proficient C++ programmer. Competing interface design generally required the combiners to be constructed to conform to an interface that would be customized for (and limited to) the Signals library. While these interfaces are generally enable more straighforward implementation of the signals & slots libraries, the combiners are unfortunately not reusable (either in other signals & slots libraries or within other generic algorithms), and the learning curve is steepened slightly to learn the specific combiner interface.</para> <para> The Signals formulation of combiners is based on the combiner using the "pull" mode of communication, instead of the more complex "push" mechanism. With a "pull" mechanism, the combiner's state can be kept on the stack and in the program counter, because whenever new data is required (i.e., calling the next slot to retrieve its return value), there is a simple interface to retrieve that data immediately and without returning from the combiner's code. Contrast this with the "push" mechanism, where the combiner must keep all state in class members because the combiner's routines will be invoked for each signal called. Compare, for example, a combiner that returns the maximum element from calling the slots. If the maximum element ever exceeds 100, no more slots are to be called.</para> <informaltable> <tgroup cols="2" align="left"> <thead> <row> <entry><para>Pull</para></entry> <entry><para>Push</para></entry> </row> </thead> <tbody> <row> <entry> <programlisting> struct pull_max { typedef int result_type; template<typename InputIterator> result_type operator()(InputIterator first, InputIterator last) { if (first == last) throw std::runtime_error("Empty!"); int max_value = *first++; while(first != last && *first <= 100) { if (*first > max_value) max_value = *first; ++first; } return max_value; } }; </programlisting> </entry> <entry> <programlisting> struct push_max { typedef int result_type; push_max() : max_value(), got_first(false) {} // returns false when we want to stop bool operator()(int result) { if (result > 100) return false; if (!got_first) { got_first = true; max_value = result; return true; } if (result > max_value) max_value = result; return true; } int get_value() const { if (!got_first) throw std::runtime_error("Empty!"); return max_value; } private: int max_value; bool got_first; }; </programlisting> </entry> </row> </tbody> </tgroup> </informaltable> <para>There are several points to note in these examples. The "pull" version is a reusable function object that is based on an input iterator sequence with an integer <code>value_type</code>, and is very straightforward in design. The "push" model, on the other hand, relies on an interface specific to the caller and is not generally reusable. It also requires extra state values to determine, for instance, if any elements have been received. Though code quality and ease-of-use is generally subjective, the "pull" model is clearly shorter and more reusable and will often be construed as easier to write and understand, even outside the context of a signals & slots library.</para> <para> The cost of the "pull" combiner interface is paid in the implementation of the Signals library itself. To correctly handle slot disconnections during calls (e.g., when the dereference operator is invoked), one must construct the iterator to skip over disconnected slots. Additionally, the iterator must carry with it the set of arguments to pass to each slot (although a reference to a structure containing those arguments suffices), and must cache the result of calling the slot so that multiple dereferences don't result in multiple calls. This apparently requires a large degree of overhead, though if one considers the entire process of invoking slots one sees that the overhead is nearly equivalent to that in the "push" model, but we have inverted the control structures to make iteration and dereference complex (instead of making combiner state-finding complex).</para> </section> <section> <title>Connection Interfaces: += operator</title> <para> Boost.Signals supports a connection syntax with the form <code>sig.<methodname>connect</methodname>(slot)</code>, but a more terse syntax <code>sig += slot</code> has been suggested (and has been used by other signals & slots implementations). There are several reasons as to why this syntax has been rejected:</para> <itemizedlist> <listitem> <para><emphasis role="bold">It's unnecessary</emphasis>: the connection syntax supplied by Boost.Signals is no less powerful that that supplied by the <code>+=</code> operator. The savings in typing (<code>connect()</code> vs. <code>+=</code>) is essentially negligible. Furthermore, one could argue that calling <code>connect()</code> is more readable than an overload of <code>+=</code>.</para> </listitem> <listitem> <para><emphasis role="bold">Ambiguous return type</emphasis>: there is an ambiguity concerning the return value of the <code>+=</code> operation: should it be a reference to the signal itself, to enable <code>sig += slot1 += slot2</code>, or should it return a <code><classname>connection</classname></code> for the newly-created signal/slot connection?</para> </listitem> <listitem> <para><emphasis role="bold">Gateway to operators -=, +</emphasis>: when one has added a connection operator <code>+=</code>, it seems natural to have a disconnection operator <code>-=</code>. However, this presents problems when the library allows arbitrary function objects to implicitly become slots, because slots are no longer comparable. <!-- (see the discussion on this topic in User-level Connection Management). --></para> <para> The second obvious addition when one has <code>operator+=</code> would be to add a <code>+</code> operator that supports addition of multiple slots, followed by assignment to a signal. However, this would require implementing <code>+</code> such that it can accept any two function objects, which is technically infeasible.</para> </listitem> </itemizedlist> </section> <section> <title><code>trackable</code> rationale</title> <para> The <code><classname>trackable</classname></code> class is the primary user interface to automatic connection lifetime management, and its design affects users directly. Two issues stick out most: the odd copying behavior of <code>trackable</code>, and the limitation requiring users to derive from <code>trackable</code> to create types that can participate in automatic connection management.</para> <section> <title><code>trackable</code> copying behavior</title> <para> The copying behavior of <code><classname>trackable</classname></code> is essentially that <code><classname>trackable</classname></code> subobjects are never copied; instead, the copy operation is merely a no-op. To understand this, we look at the nature of a signal-slot connection and note that the connection is based on the entities that are being connected; when one of the entities is destroyed, the connection is destroyed. Therefore, when a <code><classname>trackable</classname></code> subobject is copied, we cannot copy the connections because the connections don't refer to the target entity - they refer to the source entity. This reason is dual to the reason signals are noncopyable: the slots connected to them are connected to that particular signal, not the data contained in the signal.</para> </section> <section> <title>Why derivation from <code>trackable</code>?</title> <para> For <code><classname>trackable</classname></code> to work properly, there are two constraints:</para> <itemizedlist> <listitem> <para><code><classname>trackable</classname></code> must have storage space to keep track of all connections made to this object.</para> </listitem> <listitem> <para><code><classname>trackable</classname></code> must be notified when the object is being destructed so that it can disconnect its connections.</para> </listitem> </itemizedlist> <para>Clearly, deriving from <code><classname>trackable</classname></code> meets these two guidelines. We have not yet found a superior solution.</para> </section> </section> <section> <title>Comparison with other Signal/Slot implementations</title> <section> <title>libsigc++</title> <para> <ulink url="http://libsigc.sourceforge.net">libsigc++</ulink> is a C++ signals & slots library that originally started as part of an initiative to wrap the C interfaces to <ulink url="http://www.gtk.org">GTK</ulink> libraries in C++, and has grown to be a separate library maintained by Karl Nelson. There are many similarities between libsigc++ and Boost.Signals, and indeed Boost.Signals was strongly influenced by Karl Nelson and libsigc++. A cursory inspection of each library will find a similar syntax for the construction of signals and in the use of connections and automatic connection lifetime management. There are some major differences in design that separate these libraries:</para> <itemizedlist> <listitem> <para><emphasis role="bold">Slot definitions</emphasis>: slots in libsigc++ are created using a set of primitives defined by the library. These primitives allow binding of objects (as part of the library), explicit adaptation from the argument and return types of the signal to the argument and return types of the slot (libsigc++ is, by default, more strict about types than Boost.Signals). A discussion of this approach with a comparison against the approach taken by Boost.Signals is given in Choice of Slot Definitions.</para> </listitem> <listitem> <para><emphasis role="bold">Combiner/Marshaller interface</emphasis>: the equivalent to Boost.Signals combiners in libsigc++ are the marshallers. Marshallers are similar to the "push" interface described in Combiner Interface, and a proper treatment of the topic is given there.</para> </listitem> </itemizedlist> </section> <section> <title>.NET delegates</title> <para> <ulink url="http://www.microsoft.com">Microsoft</ulink> has introduced the .NET Framework and an associated set of languages and language extensions, one of which is the delegate. Delegates are similar to signals and slots, but they are more limited than most C++ signals and slots implementations in that they:</para> <itemizedlist> <listitem> <para>Require exact type matches between a delegate and what it is calling.</para> </listitem> <listitem><para>Only return the result of the last target called, with no option for customization.</para></listitem> <listitem> <para>Must call a method with <code>this</code> already bound.</para> </listitem> </itemizedlist> </section> </section> </section> --- NEW FILE: tests.xml --- <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE testsuite PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> <testsuite last-revision="$Date: 2007/03/05 19:54:28 $"> <run-test filename="dead_slot_test.cpp"> <lib>../../../libs/test/build/boost_test_exec_monitor</lib> <lib>../build/boost_signals</lib> <purpose> <para>Ensure that calling <methodname>connect</methodname> with a slot that has already been disconnected via deletion does not actually connect to the slot.</para> </purpose> </run-test> <run-test filename="deletion_test.cpp"> <lib>../../../libs/test/build/boost_test_exec_monitor</lib> <lib>../build/boost_signals</lib> <purpose> <para>Test deletion of slots.</para> </purpose> </run-test> <run-test filename="ordering_test.cpp"> <lib>../../../libs/test/build/boost_test_exec_monitor</lib> <lib>../build/boost_signals</lib> <purpose><para>Test slot group ordering.</para></purpose> </run-test> <run-test filename="signal_n_test.cpp"> <lib>../../../libs/test/build/boost_test_exec_monitor</lib> <lib>../build/boost_signals</lib> <purpose> <para>Basic test of signal/slot connections and invocation using the <classname>boost::signalN</classname> class templates.</para> </purpose> </run-test> <run-test filename="signal_test.cpp"> <lib>../../../libs/test/build/boost_test_exec_monitor</lib> <lib>../build/boost_signals</lib> <purpose> <para>Basic test of signal/slot connections and invocation using the <classname>boost::signal</classname> class template.</para> </purpose> <if-fails> <para>The <classname>boost::signal</classname> class template may not be usable on your compiler. However, the <classname>boost::signalN</classname> class templates may still be usable.</para> </if-fails> </run-test> <run-test filename="trackable_test.cpp"> <lib>../../../libs/test/build/boost_test_exec_monitor</lib> <lib>../build/boost_signals</lib> <purpose> <para>Test automatic lifetime management using <classname>boost::trackable</classname> objects.</para> </purpose> </run-test> </testsuite> --- NEW FILE: tutorial.xml --- <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> <section last-revision="$Date: 2007/03/05 19:54:28 $" id="signals.tutorial"> <title>Tutorial</title> <using-namespace name="boost"/> <using-namespace name="boost::signals"/> <using-class name="boost::signalN"/> <using-class name="boost::slotN"/> <section> <title>How to Read this Tutorial</title> <para>This tutorial is not meant to be read linearly. Its top-level structure roughly separates different concepts in the library (e.g., handling calling multiple slots, passing values to and from slots) and in each of these concepts the basic ideas are presented first and then more complex uses of the library are described later. Each of the sections is marked <emphasis>Beginner</emphasis>, [...1090 lines suppressed...] TextView v1(doc); HexView v2(doc); doc.append(argc == 2 ? argv[1] : "Hello world!"); return 0; }</programlisting> <para>The complete example source, contributed by Keith MacDonald, is available in <ulink url="../../libs/signals/example/doc_view.cpp"><code>libs/signals/example/doc_view.cpp</code></ulink>.</para> </section> <section> <title>Linking against the Signals library</title> <para>The thread_safe_signals version of Boost.Signals is currently a header-only library. No linking is to a compiled binary library is required. </para> </section> </section> --- NEW FILE: design.xml --- <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> <section last-revision="$Date: 2007/03/05 19:54:28 $"> <title>Design Overview</title> <using-namespace name="boost"/> <using-namespace name="boost::signals"/> <section> <title>Type Erasure</title> <para>"Type erasure", where static type information is eliminated by the use of dynamically dispatched interfaces, is used extensively within the Boost.Signals library to reduce the amount of code generated by template instantiation. Each signal must manage a list of slots and their associated connections, along with a <code>std::map</code> to map from group identifiers to their associated connections. However, instantiating this map for every token type, and perhaps within each translation unit (for some popular template instantiation strategies) increase compile time overhead and space overhead.</para> <para> To combat this so-called "template bloat", we use Boost.Function and Boost.Any to store unknown types and operations. Then, all of the code for handling the list of slots and the mapping from slot identifiers to connections is factored into the class <code><classname>signal_base</classname></code> that deals exclusively with the <code>any</code> and <code><classname>function</classname></code> objects, hiding the actual implementations using the well-known pimpl idiom. The actual <code><classname>signalN</classname></code> class templates deal only with code that will change depending on the number of arguments or which is inherently template-dependent (such as connection).</para> </section> <section> <title><code>connection</code> class</title> <para> The <code><classname>connection</classname></code> class is central to the behavior of the Boost.Signals library. It is the only entity within the Boost.Signals system that has knowledge of all objects that are associated by a given connection. To be specific, the <code><classname>connection</classname></code> class itself is merely a thin wrapper over a <code><classname>shared_ptr</classname></code> to a <code>basic_connection</code> object.</para> <para> <code><classname>connection</classname></code> objects are stored by all participants in the Signals system: each <code><classname>trackable</classname></code> object contains a list of <code><classname>connection</classname></code> objects describing all connections it is a part of; similarly, all signals contain a set of pairs that define a slot. The pairs consist of a slot function object (generally a Boost.Function object) and a <code><classname>connection</classname></code> object (that will disconnect on destruction). Finally, the mapping from slot groups to slots is based on the key value in a <code><classname>std::multimap</classname></code> (the stored data in the <code><classname>std::multimap</classname></code> is the slot pair).</para> </section> <section> <title>Slot Call Iterator</title> <para> The slot call iterator is conceptually a stack of iterator adaptors that modify the behavior of the underlying iterator through the list of slots. The following table describes the type and behavior of each iterator adaptor required. Note that this is only a conceptual model: the implementation collapses all these layers into a single iterator adaptor because several popular compilers failed to compile the implementation of the conceptual model.</para> <informaltable> <tgroup cols="2" align="left"> <thead> <row> <entry>Iterator Adaptor</entry> <entry>Purpose</entry> </row> </thead> <tbody> <row> <entry><para>Slot List Iterator</para></entry> <entry><para>An iterator through the list of slots connected to a signal. The <code>value_type</code> of this iterator will be <code><classname>std::pair</classname><any, connection></code>, where the <code><classname>any</classname></code> contains an instance of the slot function type.</para></entry> </row> <row> <entry><para>Filter Iterator Adaptor</para></entry> <entry><para>This filtering iterator adaptor filters out slots that have been disconnected, so we never see a disconnected slot in later stages.</para></entry> </row> <row> <entry><para>Projection Iterator Adaptor</para></entry> <entry><para>The projection iterator adaptor returns a reference to the first member of the pair that constitutes a connected slot (e.g., just the <code><classname>boost::any</classname></code> object that holds the slot function).</para></entry> </row> <row> <entry><para>Transform Iterator Adaptor</para></entry> <entry><para>This transform iterator adaptor performs an <code><functionname>any_cast</functionname></code> to extract a reference to the slot function with the appropriate slot function type.</para></entry> </row> <row> <entry><para>Transform Iterator Adaptor</para></entry> <entry><para>This transform iterator adaptor calls the function object returned by dereferencing the underlying iterator with the set of arguments given to the signal itself, and returns the result of that slot call.</para></entry> </row> <row> <entry><para>Input Caching Iterator Adaptor</para></entry> <entry><para>This iterator adaptor caches the result of dereferencing the underlying iterator. Therefore, dereferencing this iterator multiple times will only result in the underlying iterator being dereferenced once; thus, a slot can only be called once but its result can be used multiple times.</para></entry> </row> <row> <entry><para>Slot Call Iterator</para></entry> <entry><para>Iterates over calls to each slot.</para></entry> </row> </tbody> </tgroup> </informaltable> </section> <section> <title><code>visit_each</code> function template</title> <para> The <code><functionname>visit_each</functionname></code> function template is a mechanism for discovering objects that are stored within another object. Function template <code><functionname>visit_each</functionname></code> takes three arguments: an object to explore, a visitor function object that is invoked with each subobject, and the <code>int</code> 0. </para> <para> The third parameter is merely a temporary solution to the widespread lack of proper function template partial ordering. The primary <code><functionname>visit_each</functionname></code> function template specifies this third parameter type to be <code>long</code>, whereas any user specializations must specify their third parameter to be of type <code>int</code>. Thus, even though a broken compiler cannot tell the ordering between, e.g., a match against a parameter <code>T</code> and a parameter <code>A<T></code>, it can determine that the conversion from the integer 0 to <code>int</code> is better than the conversion to <code>long</code>. The ordering determined by this conversion thus achieves partial ordering of the function templates in a limited, but successful, way. The following example illustrates the use of this technique:</para> <programlisting> template<typename> class A {}; template<typename T> void foo(T, long); template<typename T> void foo(A<T>, int); A<T> at; foo(at, 0); </programlisting> <para> In this example, we assume that our compiler can not tell that <code>A<T></code> is a better match than <code>T</code>, and therefore assume that the function templates cannot be ordered based on that parameter. Then the conversion from 0 to <code>int</code> is better than the conversion from 0 to <code>long</code>, and the second function template is chosen. </para> </section> </section> --- NEW FILE: signals.xml --- <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> <library name="Signals" dirname="signals" xmlns:xi="http://www.w3.org/2001/XInclude" id="signals" last-revision="$Date: 2007/03/05 19:54:28 $"> <libraryinfo> <author> <firstname>Douglas</firstname> <surname>Gregor</surname> <!-- <email>gr...@cs...</email> --> </author> <author> <firstname>Frank</firstname> <surname>Hess</surname> <!-- <email>fm...@us...</email> --> </author> <copyright> <year>2001</year> <year>2002</year> <year>2003</year> <year>2004</year> <holder>Douglas Gregor</holder> </copyright> <copyright> <year>2007</year> <holder>Frank Mori Hess</holder> </copyright> <legalnotice> <para>Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file <filename>LICENSE_1_0.txt</filename> or copy at <ulink url="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</ulink>)</para> </legalnotice> <librarypurpose>Managed signals & slots callback implementation</librarypurpose> <librarycategory name="category:higher-order"/> </libraryinfo> <title>Boost.Signals (thread_safe_signals version)</title> <xi:include href="introduction.xml"/> <xi:include href="tutorial.xml"/> <xi:include href="reference/reference.xml"/> <xi:include href="faq.xml"/> <xi:include href="design.xml"/> <xi:include href="rationale.xml"/> <xi:include href="tests.xml"/> </library> --- NEW FILE: introduction.xml --- <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> <section last-revision="$Date: 2007/03/05 19:54:28 $"> <title>Introduction</title> <para>This documentation describes a thread-safe variant of the official Boost.Signals library. There have been some changes to the interface to support thread-safety, mostly with respect to automatic connection management. </para> <para>The Boost.Signals library is an implementation of a managed signals and slots system. Signals represent callbacks with multiple targets, and are also called publishers or events in similar systems. Signals are connected to some set of slots, which are callback receivers (also called event targets or subscribers), which are called when the signal is "emitted."</para> <para>Signals and slots are managed, in that signals and slots (or, more properly, objects that occur as part of the slots) track all connections and are capable of automatically disconnecting signal/slot connections when either is destroyed. This enables the user to make signal/slot connections without expending a great effort to manage the lifetimes of those connections with regard to the lifetimes of all objects involved.</para> <para>When signals are connected to multiple slots, there is a question regarding the relationship between the return values of the slots and the return value of the signals. Boost.Signals allows the user to specify the manner in which multiple return values are combined.</para> </section> |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 19:53:02
|
Update of /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/doc/reference In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv5509/reference Log Message: Directory /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/doc/reference added to the repository |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 19:52:52
|
Update of /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/doc In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv5495/doc Log Message: Directory /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/doc added to the repository |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 15:34:39
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv1733/thread_safe_signals Modified Files: connection.hpp shared_connection_block.hpp Log Message: Added shared_connection_block::block() to allow user to re-acquire block without creating a new shared_connection_block object. Index: shared_connection_block.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/shared_connection_block.hpp,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- shared_connection_block.hpp 2 Mar 2007 16:00:38 -0000 1.1 +++ shared_connection_block.hpp 5 Mar 2007 15:34:36 -0000 1.2 @@ -13,6 +13,7 @@ #include <boost/shared_ptr.hpp> #include <boost/thread_safe_signals/connection.hpp> +#include <boost/weak_ptr.hpp> #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -26,13 +27,23 @@ { public: shared_connection_block(connection &conn): - _blocker(conn.get_blocker()) - {} + _weakConnectionBody(conn._weakConnectionBody) + { + block(); + } + void block() + { + if(_blocker) return; + boost::shared_ptr<detail::ConnectionBodyBase> connectionBody(_weakConnectionBody.lock()); + if(connectionBody == 0) return; + _blocker = connectionBody->get_blocker(); + } void unblock() { _blocker.reset(); } private: + boost::weak_ptr<detail::ConnectionBodyBase> _weakConnectionBody; shared_ptr<void> _blocker; }; } Index: connection.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/connection.hpp,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- connection.hpp 5 Mar 2007 15:10:55 -0000 1.24 +++ connection.hpp 5 Mar 2007 15:34:36 -0000 1.25 @@ -182,12 +182,6 @@ std::swap(_weakConnectionBody, other._weakConnectionBody); } private: - shared_ptr<void> get_blocker() - { - boost::shared_ptr<detail::ConnectionBodyBase> connectionBody(_weakConnectionBody.lock()); - if(connectionBody == 0) return shared_ptr<void>(); - return connectionBody->get_blocker(); - } boost::weak_ptr<detail::ConnectionBodyBase> _weakConnectionBody; }; |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 15:10:59
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv24123/thread_safe_signals/detail Modified Files: slot_call_iterator.hpp Log Message: Throw more specific "expired_slot" exception, derived from bad_weak_ptr when slot is called with an expired tracked object. Index: slot_call_iterator.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/slot_call_iterator.hpp,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- slot_call_iterator.hpp 5 Mar 2007 14:52:46 -0000 1.24 +++ slot_call_iterator.hpp 5 Mar 2007 15:10:55 -0000 1.25 @@ -67,7 +67,7 @@ { cache->reset(f(*iter)); } - catch(const bad_weak_ptr &err) + catch(const expired_slot &err) { (*iter)->disconnect(); throw; |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 15:10:55
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv24123 Modified Files: last_value.hpp Log Message: Throw more specific "expired_slot" exception, derived from bad_weak_ptr when slot is called with an expired tracked object. Index: last_value.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/last_value.hpp,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- last_value.hpp 2 Mar 2007 22:04:46 -0000 1.3 +++ last_value.hpp 5 Mar 2007 15:10:54 -0000 1.4 @@ -13,10 +13,10 @@ #include <cassert> #include <boost/optional.hpp> -#include <boost/weak_ptr.hpp> #include <stdexcept> namespace boost { + class expired_slot; // no_slots_error is thrown when we are unable to generate a return value // due to no slots being connected to the signal. class no_slots_error: public std::runtime_error @@ -56,7 +56,7 @@ { value = *first; } - catch(const bad_weak_ptr &err) + catch(const expired_slot &err) {} ++first; } @@ -82,7 +82,7 @@ { *first; } - catch(const bad_weak_ptr &err) + catch(const expired_slot &err) {} ++first; } |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 15:10:55
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv24123/thread_safe_signals Modified Files: connection.hpp slot_base.hpp Log Message: Throw more specific "expired_slot" exception, derived from bad_weak_ptr when slot is called with an expired tracked object. Index: slot_base.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/slot_base.hpp,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- slot_base.hpp 2 Mar 2007 22:04:47 -0000 1.3 +++ slot_base.hpp 5 Mar 2007 15:10:55 -0000 1.4 @@ -23,6 +23,15 @@ namespace boost { + class expired_slot: public bad_weak_ptr + { + public: + virtual char const * what() const throw() + { + return "boost::expired_slot"; + } + }; + namespace signalslib { namespace detail @@ -40,7 +49,14 @@ tracked_container_type::const_iterator it; for(it = tracked_objects().begin(); it != tracked_objects().end(); ++it) { - locked_objects.push_back(shared_ptr<void>(*it)); + try + { + locked_objects.push_back(shared_ptr<void>(*it)); + } + catch(const bad_weak_ptr &err) + { + throw expired_slot(); + } } return locked_objects; } Index: connection.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/connection.hpp,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- connection.hpp 2 Mar 2007 22:04:47 -0000 1.23 +++ connection.hpp 5 Mar 2007 15:10:55 -0000 1.24 @@ -119,7 +119,7 @@ { locked_objects = slot.lock(); } - catch(const bad_weak_ptr &err) + catch(const expired_slot &err) { _connected = false; return locked_objects; |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 14:52:47
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv16902/thread_safe_signals/detail Modified Files: signal_template.hpp slot_call_iterator.hpp slot_template.hpp Log Message: Restored explicit slot-to-slot tracking, since implicit version only detects slot expiration on invocation. Index: slot_call_iterator.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/slot_call_iterator.hpp,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- slot_call_iterator.hpp 2 Mar 2007 22:04:47 -0000 1.23 +++ slot_call_iterator.hpp 5 Mar 2007 14:52:46 -0000 1.24 @@ -29,95 +29,97 @@ namespace boost { namespace signalslib { namespace detail { - // Generates a slot call iterator. Essentially, this is an iterator that: - // - skips over disconnected slots in the underlying list - // - calls the connected slots when dereferenced - // - caches the result of calling the slots - template<typename Function, typename Iterator, typename ConnectionBody> - class slot_call_iterator_t - : public boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, - typename Function::result_type, - boost::single_pass_traversal_tag, - typename Function::result_type const&> - { - typedef boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, + // Generates a slot call iterator. Essentially, this is an iterator that: + // - skips over disconnected slots in the underlying list + // - calls the connected slots when dereferenced + // - caches the result of calling the slots + template<typename Function, typename Iterator, typename ConnectionBody> + class slot_call_iterator_t + : public boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, typename Function::result_type, boost::single_pass_traversal_tag, typename Function::result_type const&> - inherited; + { + typedef boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, + typename Function::result_type, + boost::single_pass_traversal_tag, + typename Function::result_type const&> + inherited; - typedef typename Function::result_type result_type; + typedef typename Function::result_type result_type; - friend class boost::iterator_core_access; + friend class boost::iterator_core_access; - public: - slot_call_iterator_t(Iterator iter_in, Iterator end_in, Function f, - boost::optional<result_type> &c): - iter(iter_in), end(end_in), f(f), - cache(&c), callable_iter(end_in) - { - lockNextCallable(); - } + public: + slot_call_iterator_t(Iterator iter_in, Iterator end_in, Function f, + boost::optional<result_type> &c): + iter(iter_in), end(end_in), f(f), + cache(&c), callable_iter(end_in) + { + lockNextCallable(); + } - typename inherited::reference - dereference() const - { - if (!(*cache)) { - try - { - cache->reset(f(*iter)); - } - catch(const bad_weak_ptr &err) - { - (*iter)->nolock_disconnect(); - throw; + typename inherited::reference + dereference() const + { + if (!(*cache)) { + try + { + cache->reset(f(*iter)); + } + catch(const bad_weak_ptr &err) + { + (*iter)->disconnect(); + throw; + } } + return cache->get(); } - return cache->get(); - } - - void increment() - { - ++iter; - lockNextCallable(); - cache->reset(); - } - bool equal(const slot_call_iterator_t& other) const - { - return iter == other.iter; - } - - private: - typedef typename ConnectionBody::mutex_type::scoped_lock lock_type; + void increment() + { + ++iter; + lockNextCallable(); + cache->reset(); + } - void lockNextCallable() const - { - if(iter == callable_iter) + bool equal(const slot_call_iterator_t& other) const { - return; + return iter == other.iter; } - for(;iter != end; ++iter) + + private: + typedef typename ConnectionBody::mutex_type::scoped_lock lock_type; + + void lockNextCallable() const { - lock_type lock((*iter)->mutex); - if((*iter)->nolock_nograb_blocked() == false) + if(iter == callable_iter) { - callable_iter = iter; - break; + return; + } + for(;iter != end; ++iter) + { + lock_type lock((*iter)->mutex); + tracked_ptrs = (*iter)->nolock_grab_tracked_objects(); + if((*iter)->nolock_nograb_blocked() == false) + { + callable_iter = iter; + break; + } + } + if(iter == end) + { + callable_iter = end; } } - if(iter == end) - { - callable_iter = end; - } - } - mutable Iterator iter; - Iterator end; - Function f; - optional<result_type>* cache; - mutable Iterator callable_iter; - }; + mutable Iterator iter; + Iterator end; + Function f; + optional<result_type>* cache; + mutable Iterator callable_iter; + mutable typename slot_base::locked_container_type tracked_ptrs; + }; } // end namespace detail } // end namespace BOOST_SIGNALS_NAMESPACE } // end namespace boost Index: signal_template.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/signal_template.hpp,v retrieving revision 1.42 retrieving revision 1.43 diff -u -d -r1.42 -r1.43 --- signal_template.hpp 2 Mar 2007 16:00:39 -0000 1.42 +++ signal_template.hpp 5 Mar 2007 14:52:46 -0000 1.43 @@ -264,12 +264,12 @@ result_type m_invoke(const connection_body_type &connectionBody, const signalslib::detail::unusable *resolver) const { - connectionBody->slot(BOOST_SIGNAL_SIGNATURE_ARG_NAMES(BOOST_SIGNALS_NUM_ARGS)); + connectionBody->slot.slot_function()(BOOST_SIGNAL_SIGNATURE_ARG_NAMES(BOOST_SIGNALS_NUM_ARGS)); return signalslib::detail::unusable(); } result_type m_invoke(const connection_body_type &connectionBody, ...) const { - return connectionBody->slot(BOOST_SIGNAL_SIGNATURE_ARG_NAMES(BOOST_SIGNALS_NUM_ARGS)); + return connectionBody->slot.slot_function()(BOOST_SIGNAL_SIGNATURE_ARG_NAMES(BOOST_SIGNALS_NUM_ARGS)); } }; // a struct used to optimize (minimize) the number of shared_ptrs that need to be created Index: slot_template.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/slot_template.hpp,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- slot_template.hpp 2 Mar 2007 22:04:47 -0000 1.7 +++ slot_template.hpp 5 Mar 2007 14:52:46 -0000 1.8 @@ -48,6 +48,18 @@ BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)(const F& f): _slot_function(signalslib::detail::get_invocable_slot(f, signalslib::detail::tag_type(f))) { } + // copy constructors + template<BOOST_SIGNAL_PREFIXED_SIGNATURE_TEMPLATE_DECL(BOOST_SIGNALS_NUM_ARGS, Other), typename OtherSlotFunction> + BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)(const BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS) + <BOOST_SIGNAL_PREFIXED_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS_NUM_ARGS, Other), OtherSlotFunction> &other_slot): + signalslib::detail::slot_base(other_slot), _slot_function(other_slot._slot_function) + { + } + template<typename Signature, typename OtherSlotFunction> + BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)(const slot<Signature, OtherSlotFunction> &other_slot): + signalslib::detail::slot_base(other_slot), _slot_function(other_slot._slot_function) + { + } // bind syntactic sugar // ArgTypeN argN #define BOOST_SLOT_BINDING_ARG_DECL(z, n, data) \ @@ -63,6 +75,7 @@ #undef BOOST_SLOT_MAX_BINDING_ARGS #undef BOOST_SLOT_BINDING_ARG_DECL #undef BOOST_SLOT_BINDING_CONSTRUCTOR + // invocation R operator()(BOOST_SIGNAL_SIGNATURE_FULL_ARGS(BOOST_SIGNALS_NUM_ARGS)) { locked_container_type locked_objects = lock(); @@ -73,18 +86,30 @@ locked_container_type locked_objects = lock(); return _slot_function(BOOST_SIGNAL_SIGNATURE_ARG_NAMES(BOOST_SIGNALS_NUM_ARGS)); } + // tracking BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)& track(const weak_ptr<void> &tracked) { _trackedObjects.push_back(tracked); return *this; } + BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)& track(const slot_base &slot) + { + tracked_container_type::const_iterator it; + for(it = slot.tracked_objects().begin(); it != slot.tracked_objects().end(); ++it) + { + track(*it); + } + return *this; + } BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)& track(const signalslib::detail::signal_base &signal) { // call base class function, since it is a friend of signal_base and can call lock_pimpl() track_signal(signal); return *this; } + const slot_function_type& slot_function() const {return _slot_function;} + slot_function_type& slot_function() {return _slot_function;} private: SlotFunction _slot_function; }; |
|
From: Frank M. H. <fm...@us...> - 2007-03-05 14:51:34
|
Update of /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/test In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv16835 Modified Files: track_test.cpp Log Message: Test explicit slot-to-slot tracking. Index: track_test.cpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/libs/thread_safe_signals/test/track_test.cpp,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- track_test.cpp 2 Mar 2007 22:04:47 -0000 1.6 +++ track_test.cpp 5 Mar 2007 14:51:26 -0000 1.7 @@ -47,6 +47,7 @@ { typedef boost::signal1<int, int, max_or_default<int> > sig_type; sig_type s1; + boost::signalslib::connection connection; // Test auto-disconnection BOOST_CHECK(s1(5) == 0); @@ -77,9 +78,10 @@ boost::shared_ptr<int> shorty(new int(2)); boost::slot<int (double)> other_slot(&myfunc, boost::cref(*shorty.get()), _1); other_slot.track(shorty); - s1.connect(sig_type::slot_type(other_slot, 0.5)); + connection = s1.connect(sig_type::slot_type(other_slot, 0.5).track(other_slot)); BOOST_CHECK(s1(3) == 2); } + BOOST_CHECK(connection.connected() == false); BOOST_CHECK(s1(3) == 0); // Test binding of a signal as a slot |
|
From: Frank M. H. <fm...@us...> - 2007-03-03 16:46:32
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv11613 Modified Files: predestructible.hpp Log Message: Made predestruct public so users can define custom deleters that call predestruct. Index: predestructible.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/predestructible.hpp,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- predestructible.hpp 7 Feb 2007 18:14:48 -0000 1.2 +++ predestructible.hpp 3 Mar 2007 16:46:29 -0000 1.3 @@ -14,16 +14,13 @@ namespace boost { - template<typename T> class predestructing_deleter; - class predestructible { public: - template<typename T> friend class predestructing_deleter; + virtual void predestruct() {} protected: predestructible() {} virtual ~predestructible() {} - virtual void predestruct() {} }; } #endif |
|
From: Frank M. H. <fm...@us...> - 2007-03-02 22:05:11
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv20359/boost Modified Files: last_value.hpp Log Message: Made slots throw bad_weak_ptr when called with expired tracked objects. Combiners now have to catch bad_weak_ptr exceptions thrown on slot iterator dereference. Tracking works automatically now for slots that call other slots. Index: last_value.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/last_value.hpp,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- last_value.hpp 11 Feb 2007 23:02:50 -0000 1.2 +++ last_value.hpp 2 Mar 2007 22:04:46 -0000 1.3 @@ -13,11 +13,12 @@ #include <cassert> #include <boost/optional.hpp> +#include <boost/weak_ptr.hpp> #include <stdexcept> namespace boost { // no_slots_error is thrown when we are unable to generate a return value - // due to no slots being connected to the signal. + // due to no slots being connected to the signal. class no_slots_error: public std::runtime_error { public: @@ -43,15 +44,24 @@ template<typename InputIterator> T operator()(InputIterator first, InputIterator last) const { + T * resolver = 0; if(first == last) { - T *resolver = 0; return last_value_detail::default_construct(resolver); } - T value = *first++; + optional<T> value; while (first != last) - value = *first++; - return value; + { + try + { + value = *first; + } + catch(const bad_weak_ptr &err) + {} + ++first; + } + if(value) return value.get(); + return last_value_detail::default_construct(resolver); } }; @@ -67,7 +77,15 @@ operator()(InputIterator first, InputIterator last) const { while (first != last) - *first++; + { + try + { + *first; + } + catch(const bad_weak_ptr &err) + {} + ++first; + } return result_type(); } }; |
|
From: Frank M. H. <fm...@us...> - 2007-03-02 22:05:11
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv20359/boost/thread_safe_signals/detail Modified Files: slot_call_iterator.hpp slot_template.hpp Log Message: Made slots throw bad_weak_ptr when called with expired tracked objects. Combiners now have to catch bad_weak_ptr exceptions thrown on slot iterator dereference. Tracking works automatically now for slots that call other slots. Index: slot_call_iterator.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/slot_call_iterator.hpp,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- slot_call_iterator.hpp 1 Mar 2007 15:57:25 -0000 1.22 +++ slot_call_iterator.hpp 2 Mar 2007 22:04:47 -0000 1.23 @@ -20,6 +20,7 @@ #include <boost/thread_safe_signals/connection.hpp> #include <boost/thread_safe_signals/slot_base.hpp> #include <boost/type_traits.hpp> +#include <boost/weak_ptr.hpp> #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -62,7 +63,15 @@ dereference() const { if (!(*cache)) { - cache->reset(f(*iter)); + try + { + cache->reset(f(*iter)); + } + catch(const bad_weak_ptr &err) + { + (*iter)->nolock_disconnect(); + throw; + } } return cache->get(); } @@ -91,7 +100,6 @@ for(;iter != end; ++iter) { lock_type lock((*iter)->mutex); - tracked_ptrs = (*iter)->nolock_grab_tracked_objects(); if((*iter)->nolock_nograb_blocked() == false) { callable_iter = iter; @@ -109,7 +117,6 @@ Function f; optional<result_type>* cache; mutable Iterator callable_iter; - mutable typename slot_base::locked_container_type tracked_ptrs; }; } // end namespace detail } // end namespace BOOST_SIGNALS_NAMESPACE Index: slot_template.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/detail/slot_template.hpp,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- slot_template.hpp 2 Mar 2007 19:34:30 -0000 1.6 +++ slot_template.hpp 2 Mar 2007 22:04:47 -0000 1.7 @@ -48,18 +48,6 @@ BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)(const F& f): _slot_function(signalslib::detail::get_invocable_slot(f, signalslib::detail::tag_type(f))) { } - // copy constructors - template<BOOST_SIGNAL_PREFIXED_SIGNATURE_TEMPLATE_DECL(BOOST_SIGNALS_NUM_ARGS, Other), typename OtherSlotFunction> - BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)(const BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS) - <BOOST_SIGNAL_PREFIXED_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS_NUM_ARGS, Other), OtherSlotFunction> &other_slot): - signalslib::detail::slot_base(other_slot), _slot_function(other_slot._slot_function) - { - } - template<typename Signature, typename OtherSlotFunction> - BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)(const slot<Signature, OtherSlotFunction> &other_slot): - signalslib::detail::slot_base(other_slot), _slot_function(other_slot._slot_function) - { - } // bind syntactic sugar // ArgTypeN argN #define BOOST_SLOT_BINDING_ARG_DECL(z, n, data) \ @@ -77,10 +65,12 @@ #undef BOOST_SLOT_BINDING_CONSTRUCTOR R operator()(BOOST_SIGNAL_SIGNATURE_FULL_ARGS(BOOST_SIGNALS_NUM_ARGS)) { + locked_container_type locked_objects = lock(); return _slot_function(BOOST_SIGNAL_SIGNATURE_ARG_NAMES(BOOST_SIGNALS_NUM_ARGS)); } R operator()(BOOST_SIGNAL_SIGNATURE_FULL_ARGS(BOOST_SIGNALS_NUM_ARGS)) const { + locked_container_type locked_objects = lock(); return _slot_function(BOOST_SIGNAL_SIGNATURE_ARG_NAMES(BOOST_SIGNALS_NUM_ARGS)); } BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)& track(const weak_ptr<void> &tracked) @@ -88,15 +78,6 @@ _trackedObjects.push_back(tracked); return *this; } - BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)& track(const slot_base &slot) - { - tracked_container_type::const_iterator it; - for(it = slot.tracked_objects().begin(); it != slot.tracked_objects().end(); ++it) - { - track(*it); - } - return *this; - } BOOST_SLOT_CLASS_NAME(BOOST_SIGNALS_NUM_ARGS)& track(const signalslib::detail::signal_base &signal) { // call base class function, since it is a friend of signal_base and can call lock_pimpl() |
|
From: Frank M. H. <fm...@us...> - 2007-03-02 22:05:11
|
Update of /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv20359/boost/thread_safe_signals Modified Files: connection.hpp slot_base.hpp Log Message: Made slots throw bad_weak_ptr when called with expired tracked objects. Combiners now have to catch bad_weak_ptr exceptions thrown on slot iterator dereference. Tracking works automatically now for slots that call other slots. Index: slot_base.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/slot_base.hpp,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- slot_base.hpp 28 Feb 2007 16:19:41 -0000 1.2 +++ slot_base.hpp 2 Mar 2007 22:04:47 -0000 1.3 @@ -46,13 +46,10 @@ } bool expired() const { - try - { - lock(); - } - catch(const bad_weak_ptr &err) + tracked_container_type::const_iterator it; + for(it = tracked_objects().begin(); it != tracked_objects().end(); ++it) { - return true; + if(it->expired()) return true; } return false; } Index: connection.hpp =================================================================== RCS file: /cvsroot/boost-sandbox/boost-sandbox/boost/thread_safe_signals/connection.hpp,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- connection.hpp 2 Mar 2007 16:00:38 -0000 1.22 +++ connection.hpp 2 Mar 2007 22:04:47 -0000 1.23 @@ -50,10 +50,7 @@ virtual void disconnect() = 0; void nolock_disconnect() { - if(_connected) - { - _connected = false; - } + _connected = false; } virtual bool connected() const = 0; virtual shared_ptr<void> get_blocker() = 0; |