diff options
Diffstat (limited to 'src/boost/libs/signals2')
41 files changed, 3941 insertions, 0 deletions
diff --git a/src/boost/libs/signals2/CMakeLists.txt b/src/boost/libs/signals2/CMakeLists.txt new file mode 100644 index 000000000..3755a5628 --- /dev/null +++ b/src/boost/libs/signals2/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright 2019 Mike Dev +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt +# +# NOTE: CMake support for Boost.Signals2 is currently experimental at best +# and the interface is likely to change in the future + +cmake_minimum_required( VERSION 3.5...3.16 ) +project( BoostSignals2 LANGUAGES CXX) + +option( BOOST_SIGNALS2_INCLUDE_EXAMPLES "Add boost signals2 examples" OFF ) + +add_library( boost_signals2 INTERFACE ) +add_library( Boost::signals2 ALIAS boost_signals2 ) + +target_include_directories( boost_signals2 INTERFACE include ) + +target_link_libraries( boost_signals2 + INTERFACE + Boost::assert + Boost::bind + Boost::config + Boost::core + Boost::function + Boost::iterator + Boost::mpl + Boost::optional + Boost::parameter + Boost::predef + Boost::preprocessor + Boost::smart_ptr + Boost::throw_exception + Boost::tuple + Boost::type_traits + Boost::variant +) + +if( BOOST_SIGNALS2_INCLUDE_EXAMPLES ) + add_subdirectory( example ) +endif() + diff --git a/src/boost/libs/signals2/Jamfile b/src/boost/libs/signals2/Jamfile new file mode 100644 index 000000000..d88704f2e --- /dev/null +++ b/src/boost/libs/signals2/Jamfile @@ -0,0 +1,11 @@ +# Boost.Signals2 Library Jamfile +# +# Copyright (c) 2018 James E. King III +# +# Use, modification, and distribution are 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) + +# please order by name to ease maintenance +build-project example ; +build-project test ; diff --git a/src/boost/libs/signals2/LICENSE b/src/boost/libs/signals2/LICENSE new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/src/boost/libs/signals2/LICENSE @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/boost/libs/signals2/README.md b/src/boost/libs/signals2/README.md new file mode 100644 index 000000000..9c5621ba0 --- /dev/null +++ b/src/boost/libs/signals2/README.md @@ -0,0 +1,35 @@ +Signals2, part of collection of the [Boost C++ Libraries](http://github.com/boostorg), is an implementation of a managed signals and slots system. + +### License + +Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). + +### Properties + +* C++03 +* Header-Only + +### Build Status + +Branch | Travis | Appveyor | Coverity Scan | codecov.io | Deps | Docs | Tests | +:-------------: | ------ | -------- | ------------- | ---------- | ---- | ---- | ----- | +[`master`](https://github.com/boostorg/signals2/tree/master) | [![Build Status](https://travis-ci.org/boostorg/signals2.svg?branch=master)](https://travis-ci.org/boostorg/signals2) | [![Build status](https://ci.appveyor.com/api/projects/status/vjbstowu1s13x4l5/branch/master?svg=true)](https://ci.appveyor.com/project/jeking3/signals2-db91c/branch/master) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/15884/badge.svg)](https://scan.coverity.com/projects/boostorg-signals2) | [![codecov](https://codecov.io/gh/boostorg/signals2/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/signals2/branch/master)| [![Deps](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/signals2.html) | [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](http://www.boost.org/doc/libs/master/doc/html/signals2.html) | [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/signals2.html) +[`develop`](https://github.com/boostorg/signals2/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/signals2.svg?branch=develop)](https://travis-ci.org/boostorg/signals2) | [![Build status](https://ci.appveyor.com/api/projects/status/vjbstowu1s13x4l5/branch/develop?svg=true)](https://ci.appveyor.com/project/jeking3/signals2-db91c/branch/develop) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/15884/badge.svg)](https://scan.coverity.com/projects/boostorg-signals2) | [![codecov](https://codecov.io/gh/boostorg/signals2/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/signals2/branch/develop) | [![Deps](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/signals2.html) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/develop/doc/html/signals2.html) | [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/signals2.html) + +### Directories + +| Name | Purpose | +| ----------- | ------------------------------ | +| `ci` | continuous integration scripts | +| `doc` | documentation | +| `example` | examples | +| `include` | headers | +| `test` | unit tests | + +### More information + +* [Ask questions](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-signals2) +* [Report bugs](https://github.com/boostorg/signals2/issues): Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. +* Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). +* Discussions about the library are held on the [Boost developers mailing list](http://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[signals2]` tag at the beginning of the subject line. + diff --git a/src/boost/libs/signals2/example/CMakeLists.txt b/src/boost/libs/signals2/example/CMakeLists.txt new file mode 100644 index 000000000..3b42e58d8 --- /dev/null +++ b/src/boost/libs/signals2/example/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright 2019 Mike Dev +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt +# +# NOTE: CMake support for Boost.Signals2 is currently experimental at best +# and the interface is likely to change in the future + +file( GLOB example_src_files *.cpp ) + +find_package(Threads REQUIRED) + +foreach( file IN LISTS example_src_files ) + + get_filename_component( example_name ${file} NAME_WE ) + + add_executable( boost_signals2_example_${example_name} ${file} ) + target_link_libraries( boost_signals2_example_${example_name} + PUBLIC + Boost::signals2 + Boost::io + Threads::Threads + ) + +endforeach() diff --git a/src/boost/libs/signals2/example/Jamfile.v2 b/src/boost/libs/signals2/example/Jamfile.v2 new file mode 100644 index 000000000..079ad4432 --- /dev/null +++ b/src/boost/libs/signals2/example/Jamfile.v2 @@ -0,0 +1,42 @@ +# Boost.Signals2 example programs + +# Copyright Michael Caisse 2010 +# 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 + +project : requirements <implicit-dependency>/boost//headers ; + +exe hello_world_slot : hello_world_slot.cpp ; + +exe hello_world_multi_slot : hello_world_multi_slot.cpp ; + +exe ordering_slots : ordering_slots.cpp ; + +exe passing_slots : passing_slots.cpp ; + +exe extended_slot : extended_slot.cpp ; + +exe custom_combiners : custom_combiners.cpp ; + +exe disconnect_and_block : disconnect_and_block.cpp ; + +exe doc_view : doc_view.cpp ; + +exe doc_view_acm : doc_view_acm.cpp ; + +exe doc_view_acm_deconstruct : doc_view_acm_deconstruct.cpp ; + +exe postconstructor_ex1 : postconstructor_ex1.cpp ; + +exe postconstructor_ex2 : postconstructor_ex2.cpp ; + +exe predestructor_example : predestructor_example.cpp ; + +exe signal_return_value : signal_return_value.cpp ; + +exe slot_arguments : slot_arguments.cpp ; + diff --git a/src/boost/libs/signals2/example/custom_combiners.cpp b/src/boost/libs/signals2/example/custom_combiners.cpp new file mode 100644 index 000000000..72e43b760 --- /dev/null +++ b/src/boost/libs/signals2/example/custom_combiners.cpp @@ -0,0 +1,109 @@ +// Example program showing signals with custom combiners. +// +// Copyright Douglas Gregor 2001-2004. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <boost/signals2/signal.hpp> +#include <vector> + +float product(float x, float y) { return x * y; } +float quotient(float x, float y) { return x / y; } +float sum(float x, float y) { return x + y; } +float difference(float x, float y) { return x - y; } + +//[ custom_combiners_maximum_def_code_snippet +// combiner which returns the maximum value returned by all slots +template<typename T> +struct maximum +{ + typedef T result_type; + + template<typename InputIterator> + T operator()(InputIterator first, InputIterator last) const + { + // If there are no slots to call, just return the + // default-constructed value + if(first == last ) return T(); + T max_value = *first++; + while (first != last) { + if (max_value < *first) + max_value = *first; + ++first; + } + + return max_value; + } +}; +//] + +void maximum_combiner_example() +{ + // signal which uses our custom "maximum" combiner + boost::signals2::signal<float (float x, float y), maximum<float> > sig; + +//[ custom_combiners_maximum_usage_code_snippet + sig.connect(&product); + sig.connect("ient); + sig.connect(&sum); + sig.connect(&difference); + + // Outputs the maximum value returned by the connected slots, in this case + // 15 from the product function. + std::cout << "maximum: " << sig(5, 3) << std::endl; +//] +} + +//[ custom_combiners_aggregate_values_def_code_snippet +// aggregate_values is a combiner which places all the values returned +// from slots into a container +template<typename Container> +struct aggregate_values +{ + typedef Container result_type; + + template<typename InputIterator> + Container operator()(InputIterator first, InputIterator last) const + { + Container values; + + while(first != last) { + values.push_back(*first); + ++first; + } + return values; + } +}; +//] + +void aggregate_values_example() +{ + // signal which uses aggregate_values as its combiner + boost::signals2::signal<float (float, float), + aggregate_values<std::vector<float> > > sig; + +//[ custom_combiners_aggregate_values_usage_code_snippet + sig.connect("ient); + sig.connect(&product); + sig.connect(&sum); + sig.connect(&difference); + + std::vector<float> results = sig(5, 3); + std::cout << "aggregate values: "; + std::copy(results.begin(), results.end(), + std::ostream_iterator<float>(std::cout, " ")); + std::cout << "\n"; +//] +} + +int main() +{ + maximum_combiner_example(); + aggregate_values_example(); +} diff --git a/src/boost/libs/signals2/example/disconnect_and_block.cpp b/src/boost/libs/signals2/example/disconnect_and_block.cpp new file mode 100644 index 000000000..4478be005 --- /dev/null +++ b/src/boost/libs/signals2/example/disconnect_and_block.cpp @@ -0,0 +1,114 @@ +// Various simple examples involving disconnecting and blocking slots. +// Copyright Douglas Gregor 2001-2004. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <boost/signals2/signal.hpp> +#include <boost/signals2/shared_connection_block.hpp> + +struct HelloWorld +{ + void operator()() const + { + std::cout << "Hello, World!" << std::endl; + } +}; + +void disconnect_example() +{ + boost::signals2::signal<void ()> sig; + +//[ disconnect_code_snippet + boost::signals2::connection c = sig.connect(HelloWorld()); + std::cout << "c is connected\n"; + sig(); // Prints "Hello, World!" + + c.disconnect(); // Disconnect the HelloWorld object + std::cout << "c is disconnected\n"; + sig(); // Does nothing: there are no connected slots +//] +} + +void block_example() +{ + boost::signals2::signal<void ()> sig; + +//[ block_code_snippet + boost::signals2::connection c = sig.connect(HelloWorld()); + std::cout << "c is not blocked.\n"; + sig(); // Prints "Hello, World!" + + { + boost::signals2::shared_connection_block block(c); // block the slot + std::cout << "c is blocked.\n"; + sig(); // No output: the slot is blocked + } // shared_connection_block going out of scope unblocks the slot + std::cout << "c is not blocked.\n"; + sig(); // Prints "Hello, World!"} +//] +} + +struct ShortLived +{ + void operator()() const + { + std::cout << "Life is short!" << std::endl; + } +}; + +void scoped_connection_example() +{ + boost::signals2::signal<void ()> sig; + +//[ scoped_connection_code_snippet + { + boost::signals2::scoped_connection c(sig.connect(ShortLived())); + sig(); // will call ShortLived function object + } // scoped_connection goes out of scope and disconnects + + sig(); // ShortLived function object no longer connected to sig +//] +} + +//[ disconnect_by_slot_def_code_snippet +void foo() { std::cout << "foo"; } +void bar() { std::cout << "bar\n"; } +//] + +void disconnect_by_slot_example() +{ + boost::signals2::signal<void()> sig; + +//[ disconnect_by_slot_usage_code_snippet + sig.connect(&foo); + sig.connect(&bar); + sig(); + + // disconnects foo, but not bar + sig.disconnect(&foo); + sig(); +//] +} + +int main() +{ + std::cout << "Disconnect example:\n"; + disconnect_example(); + + std::cout << "\nBlock example:\n"; + block_example(); + + std::cout << "\nScoped connection example:\n"; + scoped_connection_example(); + + std::cout << "\nDisconnect by slot example:\n"; + disconnect_by_slot_example(); + + return 0; +} diff --git a/src/boost/libs/signals2/example/doc_view.cpp b/src/boost/libs/signals2/example/doc_view.cpp new file mode 100644 index 000000000..7ff1990e9 --- /dev/null +++ b/src/boost/libs/signals2/example/doc_view.cpp @@ -0,0 +1,115 @@ +// Document/View sample for Boost.Signals +// Copyright Keith MacDonald 2005. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <string> +#include <boost/signals2/signal.hpp> +#include <boost/bind.hpp> + +//[ document_def_code_snippet +class Document +{ +public: + typedef boost::signals2::signal<void ()> signal_t; + +public: + Document() + {} + + /* Connect a slot to the signal which will be emitted whenever + text is appended to the document. */ + boost::signals2::connection connect(const signal_t::slot_type &subscriber) + { + return m_sig.connect(subscriber); + } + + void append(const char* s) + { + m_text += s; + m_sig(); + } + + const std::string& getText() const + { + return m_text; + } + +private: + signal_t m_sig; + std::string m_text; +}; +//] + +//[ text_view_def_code_snippet +class TextView +{ +public: + TextView(Document& doc): m_document(doc) + { + m_connection = m_document.connect(boost::bind(&TextView::refresh, this)); + } + + ~TextView() + { + m_connection.disconnect(); + } + + void refresh() const + { + std::cout << "TextView: " << m_document.getText() << std::endl; + } +private: + Document& m_document; + boost::signals2::connection m_connection; +}; +//] + +//[ hex_view_def_code_snippet +class HexView +{ +public: + HexView(Document& doc): m_document(doc) + { + m_connection = m_document.connect(boost::bind(&HexView::refresh, this)); + } + + ~HexView() + { + m_connection.disconnect(); + } + + void refresh() const + { + const std::string& s = m_document.getText(); + + std::cout << "HexView:"; + + for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) + std::cout << ' ' << std::hex << static_cast<int>(*it); + + std::cout << std::endl; + } +private: + Document& m_document; + boost::signals2::connection m_connection; +}; +//] + +//[ document_view_main_code_snippet +int main(int argc, char* argv[]) +{ + Document doc; + TextView v1(doc); + HexView v2(doc); + + doc.append(argc == 2 ? argv[1] : "Hello world!"); + return 0; +} +//] diff --git a/src/boost/libs/signals2/example/doc_view_acm.cpp b/src/boost/libs/signals2/example/doc_view_acm.cpp new file mode 100644 index 000000000..ffc790826 --- /dev/null +++ b/src/boost/libs/signals2/example/doc_view_acm.cpp @@ -0,0 +1,127 @@ +// Document/View sample for Boost.Signals2. +// Expands on doc_view.cpp example by using automatic +// connection management. +// +// Copyright Keith MacDonald 2005. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <string> +#include <boost/bind.hpp> +#include <boost/io/ios_state.hpp> +#include <boost/signals2/signal.hpp> +#include <boost/shared_ptr.hpp> + +class Document +{ +public: + typedef boost::signals2::signal<void ()> signal_t; + +public: + Document() + {} + + /* connect a slot to the signal which will be emitted whenever + text is appended to the document. */ + boost::signals2::connection connect(const signal_t::slot_type &subscriber) + { + return m_sig.connect(subscriber); + } + + void append(const char* s) + { + m_text += s; + m_sig(); + } + + const std::string& getText() const + { + return m_text; + } + +private: + signal_t m_sig; + std::string m_text; +}; + +class TextView +{ +public: + // static factory function that sets up automatic connection tracking + static boost::shared_ptr<TextView> create(Document& doc) + { + boost::shared_ptr<TextView> new_view(new TextView(doc)); + { + typedef Document::signal_t::slot_type slot_type; + slot_type myslot(&TextView::refresh, new_view.get()); + doc.connect(myslot.track(new_view)); + } + return new_view; + } + + void refresh() const + { + std::cout << "TextView: " << m_document.getText() << std::endl; + } +private: + // private constructor to force use of static factory function + TextView(Document &doc): m_document(doc) + {} + + Document& m_document; +}; + +class HexView +{ +public: + // static factory function that sets up automatic connection tracking + static boost::shared_ptr<HexView> create(Document& doc) + { + boost::shared_ptr<HexView> new_view(new HexView(doc)); + { + typedef Document::signal_t::slot_type slot_type; + slot_type myslot(&HexView::refresh, new_view.get()); + doc.connect(myslot.track(new_view)); + } + return new_view; + } + + void refresh() const + { + boost::io::ios_flags_saver ifs(std::cout); + const std::string& s = m_document.getText(); + + std::cout << "HexView:"; + + for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) + std::cout << ' ' << std::hex << static_cast<int>(*it); + + std::cout << std::endl; + } +private: + // private constructor to force use of static factory function + HexView(Document& doc): m_document(doc) + {} + + Document& m_document; +}; + +int main(int argc, char* argv[]) +{ + Document doc; + boost::shared_ptr<TextView> v1 = TextView::create(doc); + boost::shared_ptr<HexView> v2 = HexView::create(doc); + + doc.append(argc >= 2 ? argv[1] : "Hello world!"); + + v2.reset(); // destroy the HexView, automatically disconnecting + doc.append(" HexView should no longer be connected."); + + return 0; +} diff --git a/src/boost/libs/signals2/example/doc_view_acm_deconstruct.cpp b/src/boost/libs/signals2/example/doc_view_acm_deconstruct.cpp new file mode 100644 index 000000000..1855c7806 --- /dev/null +++ b/src/boost/libs/signals2/example/doc_view_acm_deconstruct.cpp @@ -0,0 +1,135 @@ +// Document/View sample for Boost.Signals2. +// Expands on doc_view_acm.cpp example by using boost::signals2::deconstruct +// as a post-constructing factory function. +// +// Copyright Keith MacDonald 2005. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <string> +#include <boost/bind.hpp> +#include <boost/ref.hpp> +#include <boost/signals2/deconstruct.hpp> +#include <boost/signals2/signal.hpp> +#include <boost/shared_ptr.hpp> + +class Document +{ +public: + typedef boost::signals2::signal<void ()> signal_t; + +public: + Document() + {} + + /* Connect a slot to the signal which will be emitted whenever + text is appended to the document. */ + boost::signals2::connection connect(const signal_t::slot_type &subscriber) + { + return m_sig.connect(subscriber); + } + + void append(const char* s) + { + m_text += s; + m_sig(); + } + + const std::string& getText() const + { + return m_text; + } + +private: + signal_t m_sig; + std::string m_text; +}; + +class TextView +{ +public: + /* This adl_postconstruct function will be found + via argument-dependent lookup when using boost::signals2::deconstruct. */ + template<typename T> + friend void adl_postconstruct(const boost::shared_ptr<T> &view_sp, TextView *view, Document& doc) + { + view->m_document = &doc; + { + typedef Document::signal_t::slot_type slot_type; + slot_type myslot(&TextView::refresh, view); + doc.connect(myslot.track(view_sp)); + } + } + + void refresh() const + { + std::cout << "TextView: " << m_document->getText() << std::endl; + } +private: + // give boost::signals2::deconstruct access to private constructor + friend class boost::signals2::deconstruct_access; + // private constructor to force use of deconstruct + TextView() : m_document(0) + {} + + Document* m_document; +}; + +class HexView +{ +public: + /* This adl_postconstruct function will be found + via argument-dependent lookup when using boost::signals2::deconstruct. */ + template<typename T> + friend void adl_postconstruct(const boost::shared_ptr<T> &view_sp, HexView *view, Document& doc) + { + view->m_document = &doc; + { + typedef Document::signal_t::slot_type slot_type; + slot_type myslot(&HexView::refresh, view); + doc.connect(myslot.track(view_sp)); + } + } + + void refresh() const + { + const std::string& s = m_document->getText(); + + std::cout << "HexView:"; + + for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) + std::cout << ' ' << std::hex << static_cast<int>(*it); + + std::cout << std::endl; + } +private: + // give boost::signals2::deconstruct access to private constructor + friend class boost::signals2::deconstruct_access; + // private constructor to force use of deconstruct + HexView(): m_document(0) + {} + + Document* m_document; +}; + +namespace bs2 = boost::signals2; + +int main(int argc, char* argv[]) +{ + Document doc; + boost::shared_ptr<TextView> v1 = bs2::deconstruct<TextView>().postconstruct(boost::ref(doc)); + boost::shared_ptr<HexView> v2 = bs2::deconstruct<HexView>().postconstruct(boost::ref(doc)); + + doc.append(argc >= 2 ? argv[1] : "Hello world!"); + + v2.reset(); // destroy the HexView, automatically disconnecting + doc.append(" HexView should no longer be connected."); + + return 0; +} diff --git a/src/boost/libs/signals2/example/extended_slot.cpp b/src/boost/libs/signals2/example/extended_slot.cpp new file mode 100644 index 000000000..40699e53c --- /dev/null +++ b/src/boost/libs/signals2/example/extended_slot.cpp @@ -0,0 +1,42 @@ +// Example program for connecting an extended slot, +// using a signal's connect_extended and extended_slot_type. +// +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <boost/signals2/signal.hpp> +#include <iostream> +#include <string> + +namespace bs2 = boost::signals2; + +void single_shot_slot(const bs2::connection &conn, const std::string &message) +{ + conn.disconnect(); + std::cout << message; +} + +int main() +{ + typedef bs2::signal<void (void)> sig_type; + sig_type sig; + { + sig_type::extended_slot_type hello(&single_shot_slot, _1, "Hello"); + sig.connect_extended(hello); + } + sig(); // prints "Hello" + { + sig_type::extended_slot_type world(&single_shot_slot, _1, ", World!\n"); + sig.connect_extended(world); + } + sig(); // only prints ", World!\n" since hello slot has disconnected itself + sig(); // prints nothing, world slot has disconnected itself + + return 0; +} + diff --git a/src/boost/libs/signals2/example/hello_world_multi_slot.cpp b/src/boost/libs/signals2/example/hello_world_multi_slot.cpp new file mode 100644 index 000000000..f47835148 --- /dev/null +++ b/src/boost/libs/signals2/example/hello_world_multi_slot.cpp @@ -0,0 +1,47 @@ +// Multiple slot hello world example for Boost.Signals2 +// Copyright Douglas Gregor 2001-2004. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <boost/signals2/signal.hpp> + +//[ hello_def_code_snippet +struct Hello +{ + void operator()() const + { + std::cout << "Hello"; + } +}; +//] + +//[ world_def_code_snippet +struct World +{ + void operator()() const + { + std::cout << ", World!" << std::endl; + } +}; +//] + +int main() +{ +//[ hello_world_multi_code_snippet + boost::signals2::signal<void ()> sig; + + sig.connect(Hello()); + sig.connect(World()); + + sig(); +//] + + return 0; +} + diff --git a/src/boost/libs/signals2/example/hello_world_slot.cpp b/src/boost/libs/signals2/example/hello_world_slot.cpp new file mode 100644 index 000000000..18e3c6a38 --- /dev/null +++ b/src/boost/libs/signals2/example/hello_world_slot.cpp @@ -0,0 +1,40 @@ +// Beginner hello world example for Boost.Signals2 +// Copyright Douglas Gregor 2001-2004. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <boost/signals2/signal.hpp> + +//[ hello_world_def_code_snippet +struct HelloWorld +{ + void operator()() const + { + std::cout << "Hello, World!" << std::endl; + } +}; +//] + +int main() +{ +//[ hello_world_single_code_snippet + // Signal with no arguments and a void return value + boost::signals2::signal<void ()> sig; + + // Connect a HelloWorld slot + HelloWorld hello; + sig.connect(hello); + + // Call all of the slots + sig(); +//] + + return 0; +} + diff --git a/src/boost/libs/signals2/example/ordering_slots.cpp b/src/boost/libs/signals2/example/ordering_slots.cpp new file mode 100644 index 000000000..f69bc182c --- /dev/null +++ b/src/boost/libs/signals2/example/ordering_slots.cpp @@ -0,0 +1,62 @@ +// Ordered slots hello world example for Boost.Signals2 +// Copyright Douglas Gregor 2001-2004. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <boost/signals2/signal.hpp> + +struct Hello +{ + void operator()() const + { + std::cout << "Hello"; + } +}; + +struct World +{ + void operator()() const + { + std::cout << ", World!" << std::endl; + } +}; + +//[ good_morning_def_code_snippet +struct GoodMorning +{ + void operator()() const + { + std::cout << "... and good morning!" << std::endl; + } +}; +//] + +int main() +{ +//[ hello_world_ordered_code_snippet + boost::signals2::signal<void ()> sig; + + sig.connect(1, World()); // connect with group 1 + sig.connect(0, Hello()); // connect with group 0 +//] + +//[ hello_world_ordered_invoke_code_snippet + // by default slots are connected at the end of the slot list + sig.connect(GoodMorning()); + + // slots are invoked this order: + // 1) ungrouped slots connected with boost::signals2::at_front + // 2) grouped slots according to ordering of their groups + // 3) ungrouped slots connected with boost::signals2::at_back + sig(); +//] + + return 0; +} + diff --git a/src/boost/libs/signals2/example/passing_slots.cpp b/src/boost/libs/signals2/example/passing_slots.cpp new file mode 100644 index 000000000..d2c098cb3 --- /dev/null +++ b/src/boost/libs/signals2/example/passing_slots.cpp @@ -0,0 +1,55 @@ +// Example program showing passing of slots through an interface. +// +// Copyright Douglas Gregor 2001-2004. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <boost/signals2/signal.hpp> + +//[ passing_slots_defs_code_snippet +// a pretend GUI button +class Button +{ + typedef boost::signals2::signal<void (int x, int y)> OnClick; +public: + typedef OnClick::slot_type OnClickSlotType; + // forward slots through Button interface to its private signal + boost::signals2::connection doOnClick(const OnClickSlotType & slot); + + // simulate user clicking on GUI button at coordinates 52, 38 + void simulateClick(); +private: + OnClick onClick; +}; + +boost::signals2::connection Button::doOnClick(const OnClickSlotType & slot) +{ + return onClick.connect(slot); +} + +void Button::simulateClick() +{ + onClick(52, 38); +} + +void printCoordinates(long x, long y) +{ + std::cout << "(" << x << ", " << y << ")\n"; +} +//] + +int main() +{ +//[ passing_slots_usage_code_snippet + Button button; + button.doOnClick(&printCoordinates); + button.simulateClick(); +//] + return 0; +} diff --git a/src/boost/libs/signals2/example/postconstructor_ex1.cpp b/src/boost/libs/signals2/example/postconstructor_ex1.cpp new file mode 100644 index 000000000..89f684bba --- /dev/null +++ b/src/boost/libs/signals2/example/postconstructor_ex1.cpp @@ -0,0 +1,45 @@ +// Minimal example of defining a postconstructor for a class which +// uses boost::signals2::deconstruct as its factory function. +// +// Copyright Frank Mori Hess 2009. + +// 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 + +#include <boost/shared_ptr.hpp> +#include <boost/signals2/deconstruct.hpp> +#include <iostream> + +namespace bs2 = boost::signals2; + +namespace mynamespace +{ + class X + { + public: + /* This adl_postconstruct function will be found + via argument-dependent lookup when using boost::signals2::deconstruct. */ + template<typename T> friend + void adl_postconstruct(const boost::shared_ptr<T> &, X *) + { + std::cout << "world!" << std::endl; + } + private: + friend class bs2::deconstruct_access; // give boost::signals2::deconstruct access to private constructor + // private constructor forces use of boost::signals2::deconstruct to create objects. + X() + { + std::cout << "Hello, "; + } + }; +} + +int main() +{ + // adl_postconstruct will be called during implicit conversion of return value to shared_ptr + boost::shared_ptr<mynamespace::X> x = bs2::deconstruct<mynamespace::X>(); + return 0; +} diff --git a/src/boost/libs/signals2/example/postconstructor_ex2.cpp b/src/boost/libs/signals2/example/postconstructor_ex2.cpp new file mode 100644 index 000000000..fdd1bd4ec --- /dev/null +++ b/src/boost/libs/signals2/example/postconstructor_ex2.cpp @@ -0,0 +1,55 @@ +// An example of defining a postconstructor for a class which +// uses boost::signals2::deconstruct as its factory function. +// This example expands on the basic postconstructor_ex1.cpp example +// by passing arguments to the constructor and postconstructor. +// +// Copyright Frank Mori Hess 2009. + +// 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 + +#include <boost/shared_ptr.hpp> +#include <boost/signals2/deconstruct.hpp> +#include <iostream> +#include <sstream> +#include <string> + +namespace bs2 = boost::signals2; + +namespace mynamespace +{ + class Y + { + public: + /* This adl_postconstruct function will be found + via argument-dependent lookup when using boost::signals2::deconstruct. */ + template<typename T> friend + void adl_postconstruct(const boost::shared_ptr<T> &, Y *y, const std::string &text) + { + y->_text_stream << text; + } + void print() const + { + std::cout << _text_stream.str() << std::endl; + } + private: + friend class bs2::deconstruct_access; // give boost::signals2::deconstruct access to private constructor + // private constructor forces use of boost::signals2::deconstruct to create objects. + Y(const std::string &text) + { + _text_stream << text; + } + + std::ostringstream _text_stream; + }; +} + +int main() +{ + boost::shared_ptr<mynamespace::Y> y = bs2::deconstruct<mynamespace::Y>("Hello, ").postconstruct("world!"); + y->print(); + return 0; +} diff --git a/src/boost/libs/signals2/example/predestructor_example.cpp b/src/boost/libs/signals2/example/predestructor_example.cpp new file mode 100644 index 000000000..6f10195e5 --- /dev/null +++ b/src/boost/libs/signals2/example/predestructor_example.cpp @@ -0,0 +1,52 @@ +// Minimal example of defining a predestructor for a class which +// uses boost::signals2::deconstruct as its factory function. +// +// Copyright Frank Mori Hess 2009. + +// 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 + +#include <boost/shared_ptr.hpp> +#include <boost/signals2/deconstruct.hpp> +#include <iostream> + +namespace bs2 = boost::signals2; + +namespace mynamespace +{ + class X + { + public: + ~X() + { + std::cout << "cruel world!" << std::endl; + } + /* This adl_predestruct friend function will be found by + via argument-dependent lookup when using boost::signals2::deconstruct. */ + friend void adl_predestruct(X *) + { + std::cout << "Goodbye, "; + } + /* boost::signals2::deconstruct always requires an adl_postconstruct function + which can be found via argument-dependent, so we define one which does nothing. */ + template<typename T> friend + void adl_postconstruct(const boost::shared_ptr<T> &, X *) + {} + private: + friend class bs2::deconstruct_access; // give boost::signals2::deconstruct access to private constructor + // private constructor forces use of boost::signals2::deconstruct to create objects. + X() + {} + }; +} + +int main() +{ + { + boost::shared_ptr<mynamespace::X> x = bs2::deconstruct<mynamespace::X>(); + } + return 0; +} diff --git a/src/boost/libs/signals2/example/signal_return_value.cpp b/src/boost/libs/signals2/example/signal_return_value.cpp new file mode 100644 index 000000000..163f29abf --- /dev/null +++ b/src/boost/libs/signals2/example/signal_return_value.cpp @@ -0,0 +1,38 @@ +// Example program for returning a value from slots to signal invocation. +// +// Copyright Douglas Gregor 2001-2004. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <boost/signals2/signal.hpp> + +//[ signal_return_value_slot_defs_code_snippet +float product(float x, float y) { return x * y; } +float quotient(float x, float y) { return x / y; } +float sum(float x, float y) { return x + y; } +float difference(float x, float y) { return x - y; } +//] + +int main() +{ + boost::signals2::signal<float (float x, float y)> sig; + +//[ signal_return_value_main_code_snippet + sig.connect(&product); + sig.connect("ient); + sig.connect(&sum); + sig.connect(&difference); + + // The default combiner returns a boost::optional containing the return + // value of the last slot in the slot list, in this case the + // difference function. + std::cout << *sig(5, 3) << std::endl; +//] +} + diff --git a/src/boost/libs/signals2/example/slot_arguments.cpp b/src/boost/libs/signals2/example/slot_arguments.cpp new file mode 100644 index 000000000..86c49cb6f --- /dev/null +++ b/src/boost/libs/signals2/example/slot_arguments.cpp @@ -0,0 +1,57 @@ +// Example program for passing arguments from signal invocations to slots. +// +// Copyright Douglas Gregor 2001-2004. +// Copyright Frank Mori Hess 2009. +// +// 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 + +#include <iostream> +#include <boost/signals2/signal.hpp> + +//[ slot_arguments_slot_defs_code_snippet +void print_args(float x, float y) +{ + std::cout << "The arguments are " << x << " and " << y << std::endl; +} + +void print_sum(float x, float y) +{ + std::cout << "The sum is " << x + y << std::endl; +} + +void print_product(float x, float y) +{ + std::cout << "The product is " << x * y << std::endl; +} + +void print_difference(float x, float y) +{ + std::cout << "The difference is " << x - y << std::endl; +} + +void print_quotient(float x, float y) +{ + std::cout << "The quotient is " << x / y << std::endl; +} +//] + +int main() +{ +//[ slot_arguments_main_code_snippet + boost::signals2::signal<void (float, float)> sig; + + sig.connect(&print_args); + sig.connect(&print_sum); + sig.connect(&print_product); + sig.connect(&print_difference); + sig.connect(&print_quotient); + + sig(5., 3.); +//] + return 0; +} + diff --git a/src/boost/libs/signals2/index.html b/src/boost/libs/signals2/index.html new file mode 100644 index 000000000..53a66dffa --- /dev/null +++ b/src/boost/libs/signals2/index.html @@ -0,0 +1,13 @@ +<html> +<head> +<meta http-equiv="refresh" content="0; URL=../../doc/html/signals2.html"> +</head> +<body> +Automatic redirection failed, please go to +<a href="../../doc/html/signals2.html">../../doc/html/signals2.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> diff --git a/src/boost/libs/signals2/meta/libraries.json b/src/boost/libs/signals2/meta/libraries.json new file mode 100644 index 000000000..cb5e0654f --- /dev/null +++ b/src/boost/libs/signals2/meta/libraries.json @@ -0,0 +1,15 @@ +{ + "key": "signals2", + "name": "Signals2", + "authors": [ + "Frank Mori Hess" + ], + "description": "Managed signals & slots callback implementation (thread-safe version 2).", + "category": [ + "Function-objects", + "Patterns" + ], + "maintainers": [ + "Frank Mori Hess <fmhess -at- users.sourceforge.net>" + ] +} diff --git a/src/boost/libs/signals2/test/Jamfile.v2 b/src/boost/libs/signals2/test/Jamfile.v2 new file mode 100644 index 000000000..aacb3a4ce --- /dev/null +++ b/src/boost/libs/signals2/test/Jamfile.v2 @@ -0,0 +1,51 @@ +# Boost.Signals2 Library + +# Copyright Douglas Gregor 2001-2003. +# Copyright Frank Mori Hess 2009. +# 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 + +# bring in rules for testing +import testing ; + +project + : source-location . + : requirements + <hardcode-dll-paths>true +# <library>/boost/test//boost_unit_test_framework +# <link>static + ; + +rule thread-run ( sources ) +{ + return + [ run $(sources) : : : <library>/boost/thread//boost_thread/ + <threading>multi ] + ; +} + +{ + test-suite signals2 + : + [ run connection_test.cpp ] + [ run dead_slot_test.cpp ] + [ run deadlock_regression_test.cpp ] + [ run deconstruct_test.cpp ] + [ run deletion_test.cpp ] + [ thread-run mutex_test.cpp ] + [ run ordering_test.cpp ] + [ run regression_test.cpp ] + [ run shared_connection_block_test.cpp ] + [ run signal_n_test.cpp ] + [ run signal_test.cpp ] + [ run signal_type_test.cpp ] + [ run slot_compile_test.cpp ] + [ thread-run threading_models_test.cpp ] + [ run trackable_test.cpp ] + [ run track_test.cpp ] + ; +} diff --git a/src/boost/libs/signals2/test/connection_test.cpp b/src/boost/libs/signals2/test/connection_test.cpp new file mode 100644 index 000000000..bfe0894bc --- /dev/null +++ b/src/boost/libs/signals2/test/connection_test.cpp @@ -0,0 +1,130 @@ +// Signals2 library +// tests for connection class + +// Copyright Frank Mori Hess 2008 +// 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 +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE connection_test +#include <boost/test/included/unit_test.hpp> + +namespace bs2 = boost::signals2; + +typedef bs2::signal<void ()> sig_type; + +void myslot() +{} + +void swap_test() +{ + sig_type sig; + + { + bs2::connection conn1 = sig.connect(&myslot); + BOOST_CHECK(conn1.connected()); + bs2::connection conn2; + BOOST_CHECK(conn2.connected() == false); + + conn1.swap(conn2); + BOOST_CHECK(conn2.connected()); + BOOST_CHECK(conn1.connected() == false); + + swap(conn1, conn2); + BOOST_CHECK(conn1.connected()); + BOOST_CHECK(conn2.connected() == false); + } + + { + bs2::scoped_connection conn1; + conn1 = sig.connect(&myslot); + BOOST_CHECK(conn1.connected()); + bs2::scoped_connection conn2; + BOOST_CHECK(conn2.connected() == false); + + conn1.swap(conn2); + BOOST_CHECK(conn2.connected()); + BOOST_CHECK(conn1.connected() == false); + + swap(conn1, conn2); + BOOST_CHECK(conn1.connected()); + BOOST_CHECK(conn2.connected() == false); + } +} + +void release_test() +{ + sig_type sig; + bs2::connection conn; + { + bs2::scoped_connection scoped(sig.connect(&myslot)); + BOOST_CHECK(scoped.connected()); + conn = scoped.release(); + } + BOOST_CHECK(conn.connected()); + + bs2::connection conn2; + { + bs2::scoped_connection scoped(conn); + BOOST_CHECK(scoped.connected()); + conn = scoped.release(); + BOOST_CHECK(conn.connected()); + BOOST_CHECK(scoped.connected() == false); + conn.disconnect(); + + // earlier release shouldn't affect new connection + conn2 = sig.connect(&myslot); + scoped = conn2; + } + BOOST_CHECK(conn2.connected() == false); +} + +void move_test() +{ +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + sig_type sig; + bs2::connection conn; + // test move assignment from scoped_connection to connection + { + bs2::scoped_connection scoped(sig.connect(&myslot)); + BOOST_CHECK(scoped.connected()); + conn = std::move(scoped); + BOOST_CHECK(scoped.connected() == false); + } + BOOST_CHECK(conn.connected()); + + // test move construction from scoped to scoped + { + bs2::scoped_connection scoped2(conn); + BOOST_CHECK(scoped2.connected()); + bs2::scoped_connection scoped3(std::move(scoped2)); + BOOST_CHECK(scoped2.connected() == false); + BOOST_CHECK(scoped3.connected() == true); + BOOST_CHECK(conn.connected() == true); + } + BOOST_CHECK(conn.connected() == false); + + // test move assignment from scoped to scoped + conn = sig.connect(&myslot); + { + bs2::scoped_connection scoped3; + bs2::scoped_connection scoped2(conn); + BOOST_CHECK(scoped2.connected()); + scoped3 = std::move(scoped2); + BOOST_CHECK(scoped2.connected() == false); + BOOST_CHECK(scoped3.connected() == true); + BOOST_CHECK(conn.connected() == true); + } + BOOST_CHECK(conn.connected() == false); +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + release_test(); + swap_test(); + move_test(); +} diff --git a/src/boost/libs/signals2/test/dead_slot_test.cpp b/src/boost/libs/signals2/test/dead_slot_test.cpp new file mode 100644 index 000000000..b1ec1d5a0 --- /dev/null +++ b/src/boost/libs/signals2/test/dead_slot_test.cpp @@ -0,0 +1,47 @@ +// Boost.Signals library + +// Copyright (C) Douglas Gregor 2001-2006. 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 + +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE dead_slot_test +#include <boost/test/included/unit_test.hpp> + +using namespace boost::placeholders; + +typedef boost::signals2::signal<int (int)> sig_type; + +class with_constant { +public: + with_constant(int c) : constant(c) {} + + int add(int i) { return i + constant; } + +private: + int constant; +}; + +void do_delayed_connect(boost::shared_ptr<with_constant> &wc, + sig_type& sig, + sig_type::slot_type slot) +{ + // Should invalidate the slot, so that we cannot connect to it + wc.reset(); + + boost::signals2::connection c = sig.connect(slot); + BOOST_CHECK(!c.connected()); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + sig_type s1; + boost::shared_ptr<with_constant> wc1(new with_constant(7)); + + do_delayed_connect(wc1, s1, sig_type::slot_type(&with_constant::add, wc1.get(), _1).track(wc1)); +} diff --git a/src/boost/libs/signals2/test/deadlock_regression_test.cpp b/src/boost/libs/signals2/test/deadlock_regression_test.cpp new file mode 100644 index 000000000..ac9d89190 --- /dev/null +++ b/src/boost/libs/signals2/test/deadlock_regression_test.cpp @@ -0,0 +1,109 @@ +// Signals2 library +// +// Regression test based on bug report from Arian Alin Radu. +// The problem was that tracked objects could be released +// while holding the signal mutex during signal invocation. +// This could result in a recursive +// lock attempt if the tracked object manipulates the signal +// in its destructor. + +// Copyright Frank Mori Hess 2019 +// 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_TEST_MODULE signals2 deadlock regression test +#include <boost/test/included/unit_test.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/make_shared.hpp> +#include <boost/signals2/signal.hpp> +#include <boost/signals2/signal_type.hpp> + +namespace bs2 = boost::signals2; + + +// dummy mutex that detects attempts to recursively lock +class test_mutex +{ +public: + test_mutex(): m_locked(false) {} + void lock() + { + BOOST_CHECK(m_locked == false); + m_locked = true; + } + bool try_lock() + { + if(m_locked) return false; + lock(); + return true; + } + void unlock() + { + m_locked = false; + } +private: + bool m_locked; +}; + +using namespace bs2::keywords; +typedef bs2::signal_type<void(), mutex_type<test_mutex> >::type Signal; + +class SelfReference: private boost::noncopyable +{ +public: + boost::shared_ptr<SelfReference> m_self; + boost::shared_ptr<Signal> m_signal; + + boost::signals2::connection m_conReleaseSelf; + boost::signals2::connection m_conDoNothing; + + SelfReference() + { + m_signal = boost::make_shared<Signal>(); + } + + ~SelfReference() + { + // the first slot (ReleaseSelf) has been called; now the trackable object (this) + // was released, while the second slot is locked + BOOST_CHECK(!m_conReleaseSelf.connected()); + // the second slot is locked, and we enter a recursive (pthread: dead) lock + BOOST_CHECK(m_conDoNothing.connected()); + m_conReleaseSelf.disconnect(); + m_conDoNothing.disconnect(); + // enter recursive (pthread: dead) lock again: + BOOST_CHECK(m_signal->empty()); + } + + void ReleaseSelf() + { + m_self.reset(); + } + + static void DoNothing() + { + } + + static void Run() + { + boost::shared_ptr<Signal> signal; + { + boost::shared_ptr<SelfReference> obj = boost::make_shared<SelfReference>(); + obj->m_self = obj; + signal = obj->m_signal; + + obj->m_conReleaseSelf = signal->connect(Signal::slot_type(&SelfReference::ReleaseSelf, obj.get()).track(obj)); + obj->m_conDoNothing = signal->connect(Signal::slot_type(&SelfReference::DoNothing)); + } + (*signal)(); + } +}; + +BOOST_AUTO_TEST_CASE(test_main) +{ + SelfReference::Run(); +} diff --git a/src/boost/libs/signals2/test/deconstruct_test.cpp b/src/boost/libs/signals2/test/deconstruct_test.cpp new file mode 100644 index 000000000..96d9949e4 --- /dev/null +++ b/src/boost/libs/signals2/test/deconstruct_test.cpp @@ -0,0 +1,174 @@ +// Tests for boost::signals2::deconstruct_ptr and friends + +// Copyright Frank Mori Hess 2007-2008. +// Distributed under 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) + +// See http://www.boost.org/libs/signals2 for library home page. + +#include <boost/enable_shared_from_this.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/signals2/deconstruct.hpp> +#include <boost/signals2/deconstruct_ptr.hpp> +#define BOOST_TEST_MODULE deconstruct_test +#include <boost/test/included/unit_test.hpp> + +class X: public boost::signals2::postconstructible { +public: + X(): _postconstructed(false) + {} + ~X() + { + BOOST_CHECK(_postconstructed); + } +protected: + virtual void postconstruct() + { + BOOST_CHECK(!_postconstructed); + _postconstructed = true; + } + bool _postconstructed; +}; + +class Y: public boost::signals2::predestructible { +public: + Y(): _predestructed(false) + {} + ~Y() + { + BOOST_CHECK(_predestructed); + } +protected: + virtual void predestruct() + { + _predestructed = true; + } + bool _predestructed; +}; + +class Z: public X, public Y +{}; + +class by_deconstruct_only: public boost::signals2::postconstructible { +public: + ~by_deconstruct_only() + { + BOOST_CHECK(_postconstructed); + } + int value; +protected: + virtual void postconstruct() + { + BOOST_CHECK(!_postconstructed); + _postconstructed = true; + } + bool _postconstructed; +private: + friend class boost::signals2::deconstruct_access; + by_deconstruct_only(int value_in): + value(value_in), _postconstructed(false) + {} +}; + +namespace mytest +{ + class A + { + public: + template<typename T> friend + void adl_postconstruct(const boost::shared_ptr<T> &sp, A *p) + { + BOOST_CHECK(!p->_postconstructed); + p->_postconstructed = true; + } + template<typename T> friend + void adl_postconstruct(const boost::shared_ptr<T> &sp, A *p, int val) + { + p->value = val; + BOOST_CHECK(!p->_postconstructed); + p->_postconstructed = true; + } + friend void adl_predestruct(A *p) + { + p->_predestructed = true; + } + ~A() + { + BOOST_CHECK(_postconstructed); + BOOST_CHECK(_predestructed); + } + int value; + private: + friend class boost::signals2::deconstruct_access; + A(int value_in = 0): + value(value_in), + _postconstructed(false), + _predestructed(false) + {} + bool _postconstructed; + bool _predestructed; + }; +} + +void deconstruct_ptr_test() +{ + { + boost::shared_ptr<X> x = boost::signals2::deconstruct_ptr(new X); + } + { + boost::shared_ptr<Y> x = boost::signals2::deconstruct_ptr(new Y); + } + { + boost::shared_ptr<Z> z = boost::signals2::deconstruct_ptr(new Z); + } +} + +class deconstructed_esft : public boost::enable_shared_from_this<deconstructed_esft> +{ +public: + deconstructed_esft() : x(0) {} + +private: + friend void adl_postconstruct(boost::shared_ptr<void>, deconstructed_esft *) {} + int x; +}; + +void deconstruct_test() +{ + { + boost::shared_ptr<X> x = boost::signals2::deconstruct<X>(); + } + { + boost::shared_ptr<Y> x = boost::signals2::deconstruct<Y>(); + } + { + boost::shared_ptr<Z> z = boost::signals2::deconstruct<Z>(); + } + { + boost::shared_ptr<by_deconstruct_only> a = boost::signals2::deconstruct<by_deconstruct_only>(1); + BOOST_CHECK(a->value == 1); + } + { + boost::shared_ptr<mytest::A> a = boost::signals2::deconstruct<mytest::A>(1); + BOOST_CHECK(a->value == 1); + } + {// deconstruct const type + boost::shared_ptr<const mytest::A> a = boost::signals2::deconstruct<const mytest::A>(3); + BOOST_CHECK(a->value == 3); + } + {// passing arguments to postconstructor + boost::shared_ptr<mytest::A> a = boost::signals2::deconstruct<mytest::A>().postconstruct(2); + BOOST_CHECK(a->value == 2); + } + {// enable_shared_from_this with deconstruct + boost::shared_ptr<deconstructed_esft> a = boost::signals2::deconstruct<deconstructed_esft>(); + BOOST_CHECK(!(a->shared_from_this() < a || a < a->shared_from_this())); + } +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + deconstruct_ptr_test(); + deconstruct_test(); +} diff --git a/src/boost/libs/signals2/test/deletion_test.cpp b/src/boost/libs/signals2/test/deletion_test.cpp new file mode 100644 index 000000000..577c8512a --- /dev/null +++ b/src/boost/libs/signals2/test/deletion_test.cpp @@ -0,0 +1,297 @@ +// Boost.Signals2 library + +// Copyright Douglas Gregor 2001-2003. +// 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 + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE deletion_test +#include <boost/test/included/unit_test.hpp> +#include <iostream> +#include <string> + +static boost::signals2::connection connections[5]; + +static std::string test_output; + +struct remove_connection { + explicit remove_connection(int v = 0, int i = -1) : value(v), idx(i) {} + + void operator()() const { + if (idx >= 0) + connections[idx].disconnect(); + + //return value; + std::cout << value << " "; + + test_output += static_cast<char>(value + '0'); + } + + int value; + int idx; +}; + +bool operator==(const remove_connection& x, const remove_connection& y) +{ return x.value == y.value && x.idx == y.idx; } + +static void +test_remove_self() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2, 2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "Deleting 2" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "013"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.empty()); + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3, 3)); + + std::cout << "Deleting 3" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "012"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.num_slots() == 0); + + connections[0] = s0.connect(remove_connection(0, 0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "Deleting 0" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "123"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.empty()); + + connections[0] = s0.connect(remove_connection(0, 0)); + connections[1] = s0.connect(remove_connection(1, 1)); + connections[2] = s0.connect(remove_connection(2, 2)); + connections[3] = s0.connect(remove_connection(3, 3)); + + std::cout << "Mass suicide" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == ""); +} + +static void +test_remove_prior() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1, 0)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "1 removes 0" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "123"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.empty()); + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3, 2)); + + std::cout << "3 removes 2" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "013"); +} + +static void +test_remove_after() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0, 1)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "0 removes 1" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "023"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "023"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.empty()); + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1, 3)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "1 removes 3" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "012"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "012"); +} + +static void +test_bloodbath() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0, 1)); + connections[1] = s0.connect(remove_connection(1, 1)); + connections[2] = s0.connect(remove_connection(2, 0)); + connections[3] = s0.connect(remove_connection(3, 2)); + + std::cout << "0 removes 1, 2 removes 0, 3 removes 2" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "023"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "3"); +} + +static void +test_disconnect_equal() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "Deleting 2" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + connections[2].disconnect(); +#else + s0.disconnect(remove_connection(2)); +#endif + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "013"); +} + +struct signal_deletion_tester +{ +public: + signal_deletion_tester() { + b_has_run = false; + sig = new boost::signals2::signal<void(void)>(); + connection0 = sig->connect(0, boost::bind(&signal_deletion_tester::a, this)); + connection1 = sig->connect(1, boost::bind(&signal_deletion_tester::b, this)); + } + + ~signal_deletion_tester() + { + if(sig != 0) + delete sig; + } + + void a() + { + if(sig != 0) + delete sig; + sig = 0; + } + + void b() + { + b_has_run = true; + } + + boost::signals2::signal<void(void)> *sig; + bool b_has_run; + boost::signals2::connection connection0; + boost::signals2::connection connection1; +}; + +// If a signal is deleted mid-invocation, the invocation in progress +// should complete normally. Once all invocations complete, all +// slots which were connected to the deleted signal should be in the +// disconnected state. +static void test_signal_deletion() +{ + signal_deletion_tester tester; + (*tester.sig)(); + BOOST_CHECK(tester.b_has_run); + BOOST_CHECK(tester.connection0.connected() == false); + BOOST_CHECK(tester.connection1.connected() == false); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_remove_self(); + test_remove_prior(); + test_remove_after(); + test_bloodbath(); + test_disconnect_equal(); + test_signal_deletion(); +} diff --git a/src/boost/libs/signals2/test/invocation_benchmark.cpp b/src/boost/libs/signals2/test/invocation_benchmark.cpp new file mode 100644 index 000000000..6a464fc52 --- /dev/null +++ b/src/boost/libs/signals2/test/invocation_benchmark.cpp @@ -0,0 +1,60 @@ +/* multi-threaded signal invocation benchmark */ + +// Copyright Frank Mori Hess 2007-2008. +// Distributed under 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) + +#include <cstdlib> +#include <iostream> +#include <boost/bind/bind.hpp> +#include <boost/signals2.hpp> +#include <boost/thread/thread.hpp> + +using namespace boost::placeholders; + +typedef boost::signals2::signal<void ()> signal_type; + +void myslot() +{ +/* std::cout << __FUNCTION__ << std::endl; + sleep(1);*/ +} + +void thread_initial(signal_type *signal, unsigned num_invocations) +{ + unsigned i; + for(i = 0; i < num_invocations; ++i) + { + (*signal)(); + } +} + +int main(int argc, const char **argv) +{ + if(argc < 3) + { + std::cerr << "usage: " << argv[0] << " <num threads> <num connections>" << std::endl; + return -1; + } + static const unsigned num_threads = std::strtol(argv[1], 0, 0); + static const unsigned num_connections = std::strtol(argv[2], 0, 0); + boost::thread_group threads; + signal_type sig; + + std::cout << "Connecting " << num_connections << " connections to signal.\n"; + unsigned i; + for(i = 0; i < num_connections; ++i) + { + sig.connect(&myslot); + } + const unsigned num_slot_invocations = 1000000; + const unsigned signal_invocations_per_thread = num_slot_invocations / (num_threads * num_connections); + std::cout << "Launching " << num_threads << " thread(s) to invoke signal " << signal_invocations_per_thread << " times per thread.\n"; + for(i = 0; i < num_threads; ++i) + { + threads.create_thread(boost::bind(&thread_initial, &sig, signal_invocations_per_thread)); + } + threads.join_all(); + return 0; +} diff --git a/src/boost/libs/signals2/test/mutex_test.cpp b/src/boost/libs/signals2/test/mutex_test.cpp new file mode 100644 index 000000000..8da2972a5 --- /dev/null +++ b/src/boost/libs/signals2/test/mutex_test.cpp @@ -0,0 +1,292 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Copyright Frank Mori Hess 2009 +// +// 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) + +// This is a simplified/modified version of libs/thread/test/test_mutex.cpp +// added to test boost::signals2::mutex. +// For more information, see http://www.boost.org + +// Note boost/test/minimal.hpp can cause windows.h to get included, which +// can screw up our checks of _WIN32_WINNT if it is included +// after boost/signals2/mutex.hpp. Frank Hess 2009-03-07. +// We now use boost/test/included/unit_test.hpp, not sure if above still +// applies, but might as well leave the include where it is. +#define BOOST_TEST_MODULE mutex_test +#include <boost/test/included/unit_test.hpp> + +#include <boost/bind/bind.hpp> +#include <boost/signals2/dummy_mutex.hpp> +#include <boost/signals2/mutex.hpp> +#include <boost/thread/locks.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/thread.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/condition.hpp> + +using namespace boost::placeholders; + +class execution_monitor +{ +public: + execution_monitor(int secs) + : done(false), m_secs(secs) { } + void start() + { + boost::mutex::scoped_lock lock(mutex); + done = false; + } + void finish() + { + boost::mutex::scoped_lock lock(mutex); + done = true; + cond.notify_one(); + } + bool wait() + { + boost::posix_time::time_duration timeout = boost::posix_time::seconds(m_secs); + boost::mutex::scoped_lock lock(mutex); + while (!done) { + if (!cond.timed_wait(lock, timeout)) + break; + } + return done; + } + +private: + boost::mutex mutex; + boost::condition cond; + bool done; + int m_secs; +}; + +template <typename F> +class indirect_adapter +{ +public: + indirect_adapter(F func, execution_monitor& monitor) + : m_func(func), m_monitor(monitor) { } + void operator()() const + { + try + { + boost::thread thrd(m_func); + thrd.join(); + } + catch (...) + { + m_monitor.finish(); + throw; + } + m_monitor.finish(); + } + +private: + F m_func; + execution_monitor& m_monitor; + void operator=(indirect_adapter&); +}; + +template <typename F> +void timed_test(F func, int secs) +{ + execution_monitor monitor(secs); + indirect_adapter<F> ifunc(func, monitor); + monitor.start(); + boost::thread thrd(ifunc); + BOOST_REQUIRE(monitor.wait()); // Timed test didn't complete in time, possible deadlock +} + +template <typename M> +struct test_lock +{ + typedef M mutex_type; + typedef typename boost::unique_lock<M> lock_type; + + void operator()() + { + mutex_type mutex; + boost::condition condition; + + // Test the lock's constructors. + { + lock_type lock(mutex, boost::defer_lock); + BOOST_CHECK(!lock); + } + lock_type lock(mutex); + BOOST_CHECK(lock ? true : false); + + // Construct a fast time out. + boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100); + + // Test the lock and the mutex with condition variables. + // No one is going to notify this condition variable. We expect to + // time out. + BOOST_CHECK(!condition.timed_wait(lock, timeout)); + BOOST_CHECK(lock ? true : false); + + // Test the lock and unlock methods. + lock.unlock(); + BOOST_CHECK(!lock); + lock.lock(); + BOOST_CHECK(lock ? true : false); + } +}; + +template <typename M> +struct test_trylock +{ + typedef M mutex_type; + typedef typename boost::unique_lock<M> lock_type; + + void operator()() + { + mutex_type mutex; + boost::condition condition; + + // Test the lock's constructors. + { + lock_type lock(mutex, boost::try_to_lock); + BOOST_CHECK(lock ? true : false); + } + { + lock_type lock(mutex, boost::defer_lock); + BOOST_CHECK(!lock); + } + lock_type lock(mutex, boost::try_to_lock); + BOOST_CHECK(lock ? true : false); + + // Construct a fast time out. + boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100); + + // Test the lock and the mutex with condition variables. + // No one is going to notify this condition variable. We expect to + // time out. + BOOST_CHECK(!condition.timed_wait(lock, timeout)); + BOOST_CHECK(lock ? true : false); + + // Test the lock, unlock and trylock methods. + lock.unlock(); + BOOST_CHECK(!lock); + lock.lock(); + BOOST_CHECK(lock ? true : false); + lock.unlock(); + BOOST_CHECK(!lock); + BOOST_CHECK(lock.try_lock()); + BOOST_CHECK(lock ? true : false); + } +}; + +template<typename Mutex> +struct test_lock_exclusion +{ + typedef boost::unique_lock<Mutex> Lock; + + Mutex m; + boost::mutex done_mutex; + bool done; + bool locked; + boost::condition_variable done_cond; + + test_lock_exclusion(): + done(false),locked(false) + {} + + void locking_thread() + { + Lock lock(m); + + boost::lock_guard<boost::mutex> lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + bool is_done() const + { + return done; + } + + typedef test_lock_exclusion<Mutex> this_type; + + void do_test(void (this_type::*test_func)()) + { + Lock lock(m); + + { + boost::lock_guard<boost::mutex> lk(done_mutex); + locked=false; + } + + done=false; + + boost::thread t(test_func,this); + + try + { + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(!done_cond.timed_wait(lk, boost::posix_time::seconds(1), + boost::bind(&this_type::is_done,this))); + } + lock.unlock(); + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(done_cond.timed_wait(lk, boost::posix_time::seconds(1), + boost::bind(&this_type::is_done,this))); + } + t.join(); + BOOST_CHECK(locked); + } + catch(...) + { + lock.unlock(); + t.join(); + throw; + } + } + + + void operator()() + { + do_test(&this_type::locking_thread); + } +}; + + +void do_test_mutex() +{ + test_lock<boost::signals2::mutex>()(); +// try_lock not supported on old versions of windows +#if !defined(BOOST_HAS_WINTHREADS) || (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)) + test_trylock<boost::signals2::mutex>()(); +#endif + test_lock_exclusion<boost::signals2::mutex>()(); +} + +void test_mutex() +{ + timed_test(&do_test_mutex, 3); +} + +void do_test_dummy_mutex() +{ + test_lock<boost::signals2::dummy_mutex>()(); + test_trylock<boost::signals2::dummy_mutex>()(); +} + +void test_dummy_mutex() +{ + timed_test(&do_test_dummy_mutex, 2); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_mutex(); + test_dummy_mutex(); +} diff --git a/src/boost/libs/signals2/test/ordering_test.cpp b/src/boost/libs/signals2/test/ordering_test.cpp new file mode 100644 index 000000000..9636fb016 --- /dev/null +++ b/src/boost/libs/signals2/test/ordering_test.cpp @@ -0,0 +1,128 @@ +// Boost.Signals2 library + +// Copyright Douglas Gregor 2002-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 + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE ordering_test +#include <boost/test/included/unit_test.hpp> +#include <iostream> +#include <vector> +#include <algorithm> +#include <cstdlib> +#include <ctime> +#include <functional> + +std::vector<int> valuesOutput; +bool ungrouped1 = false; +bool ungrouped2 = false; +bool ungrouped3 = false; + +struct emit_int { + emit_int(int v) : value(v) {} + + void operator()() const + { + BOOST_CHECK(value == 42 || (!ungrouped1 && !ungrouped2 && !ungrouped3)); + valuesOutput.push_back(value); + std::cout << value << ' '; + } + +private: + int value; +}; + +struct write_ungrouped1 { + void operator()() const + { + BOOST_CHECK(!ungrouped1); + ungrouped1 = true; + std::cout << "(Ungrouped #1)" << ' '; + } +}; + +struct write_ungrouped2 { + void operator()() const + { + BOOST_CHECK(!ungrouped2); + ungrouped2 = true; + std::cout << "(Ungrouped #2)" << ' '; + } +}; + +struct write_ungrouped3 { + void operator()() const + { + BOOST_CHECK(!ungrouped3); + ungrouped3 = true; + std::cout << "(Ungrouped #3)" << ' '; + } +}; + +int return_argument(int x) +{ + return x; +} + +void test_group_compare() +{ + boost::signals2::signal + < + int (), + boost::signals2::last_value<int>, + int, + std::greater< int > + > sig; + + sig.connect( 1, boost::bind( &return_argument, 1) ); + sig.connect( 2, boost::bind( &return_argument, 2) ); + + BOOST_CHECK(sig() == 1); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + using namespace std; + srand(time(0)); + + std::vector<int> sortedValues; + + boost::signals2::signal<void ()> sig; + sig.connect(write_ungrouped1()); + for (int i = 0; i < 100; ++i) { +#ifdef BOOST_NO_STDC_NAMESPACE + int v = rand() % 100; +#else + int v = std::rand() % 100; +#endif + sortedValues.push_back(v); + sig.connect(v, emit_int(v)); + + if (i == 50) { + sig.connect(write_ungrouped2()); + } + } + sig.connect(write_ungrouped3()); + + std::sort(sortedValues.begin(), sortedValues.end()); + + // 17 at beginning, 42 at end + sortedValues.insert(sortedValues.begin(), 17); + sig.connect(emit_int(17), boost::signals2::at_front); + sortedValues.push_back(42); + sig.connect(emit_int(42)); + + sig(); + std::cout << std::endl; + + BOOST_CHECK(valuesOutput == sortedValues); + BOOST_CHECK(ungrouped1); + BOOST_CHECK(ungrouped2); + BOOST_CHECK(ungrouped3); + + test_group_compare(); +} diff --git a/src/boost/libs/signals2/test/regression_test.cpp b/src/boost/libs/signals2/test/regression_test.cpp new file mode 100644 index 000000000..59187353c --- /dev/null +++ b/src/boost/libs/signals2/test/regression_test.cpp @@ -0,0 +1,109 @@ +// thread_safe_signals library +// Some assorted tests to expose various bugs that existed at some point, +// to make sure they stay fixed + +// Copyright Frank Mori Hess 2008 +// 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 + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE regression_test +#include <boost/test/included/unit_test.hpp> + +typedef boost::signals2::signal<void ()> sig0_type; + +// combiner that returns the number of slots invoked +struct slot_counter { + typedef unsigned result_type; + template<typename InputIterator> + unsigned operator()(InputIterator first, InputIterator last) const + { + unsigned count = 0; + for (; first != last; ++first) + { + try + { + *first; + ++count; + } + catch(const boost::bad_weak_ptr &) + {} + } + return count; + } +}; + +void my_slot() +{ +} + +void my_connecting_slot(sig0_type &sig) +{ + sig.connect(&my_slot); +} + +void slot_connect_test() +{ + sig0_type sig; + sig.connect(sig0_type::slot_type(&my_connecting_slot, boost::ref(sig)).track(sig)); + /* 2008-02-28: the following signal invocation triggered a (bogus) failed assertion of _shared_state.unique() + at detail/signal_template.hpp:285 */ + sig(); + BOOST_CHECK(sig.num_slots() == 2); + sig.disconnect(&my_slot); + BOOST_CHECK(sig.num_slots() == 1); + /* 2008-03-11: checked iterator barfed on next line, due to bad semantics of copy construction + for boost::signals2::detail::grouped_list */ + sig(); + BOOST_CHECK(sig.num_slots() == 2); +} + +/* 2008-03-10: we weren't disconnecting old connection in scoped_connection assignment operator */ +void scoped_connection_test() +{ + typedef boost::signals2::signal<void (), slot_counter> signal_type; + signal_type sig; + { + boost::signals2::scoped_connection conn(sig.connect(&my_slot)); + BOOST_CHECK(sig() == 1); + conn = sig.connect(&my_slot); + BOOST_CHECK(sig() == 1); + } + BOOST_CHECK(sig() == 0); +} + +// testsignal that returns a reference type + +struct ref_returner +{ + static int i; + + int& ref_return_slot() + { + return i; + } +}; + +int ref_returner::i = 0; + +void reference_return_test() +{ + boost::signals2::signal<int& ()> rTest; + ref_returner rr; + rTest.connect(boost::bind(&ref_returner::ref_return_slot, &rr)); + int& r = *rTest(); + BOOST_CHECK(ref_returner::i == 0); + r = 1; + BOOST_CHECK(ref_returner::i == 1); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + slot_connect_test(); + scoped_connection_test(); + reference_return_test(); +} diff --git a/src/boost/libs/signals2/test/shared_connection_block_test.cpp b/src/boost/libs/signals2/test/shared_connection_block_test.cpp new file mode 100644 index 000000000..4ad5bdf33 --- /dev/null +++ b/src/boost/libs/signals2/test/shared_connection_block_test.cpp @@ -0,0 +1,112 @@ +// Boost.Signals2 library + +// Copyright Douglas Gregor 2001-2003. +// 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 + +#include <boost/array.hpp> +#include <boost/signals2/shared_connection_block.hpp> +#include <boost/signals2/signal.hpp> +#define BOOST_TEST_MODULE shared_connection_block_test +#include <boost/test/included/unit_test.hpp> +#include <iostream> +#include <sstream> +#include <string> + +static boost::array<boost::signals2::connection, 4> connections; + +static std::ostringstream test_output; + +struct test_slot { + explicit test_slot(int v = 0) : value(v) + {} + + void operator()() const { + test_output << value; + } + + int value; +}; + +BOOST_AUTO_TEST_CASE(test_main) +{ + boost::signals2::signal<void ()> s0; + + for(unsigned i = 0; i < connections.size(); ++i) + { + connections.at(i) = s0.connect(test_slot(i)); + } + + + { + // Blocking 2 + boost::signals2::shared_connection_block block(connections.at(2)); + BOOST_CHECK(block.blocking()); + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "013"); + } + + // Unblocking 2 + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "0123"); + + { + // Blocking 1 through const connection + const boost::signals2::connection conn = connections.at(1); + boost::signals2::shared_connection_block block(conn); + test_output.str(""); + s0(); + std::cout << test_output.str() << std::endl; + BOOST_CHECK(test_output.str() == "023"); + // Unblocking 1 + block.unblock(); + BOOST_CHECK(block.blocking() == false); + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "0123"); + } + + { + // initially unblocked + boost::signals2::shared_connection_block block(connections.at(3), false); + BOOST_CHECK(block.blocking() == false); + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "0123"); + // block + block.block(); + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "012"); + } + + { + // test default constructed block + boost::signals2::shared_connection_block block; + BOOST_CHECK(block.blocking() == true); + block.unblock(); + BOOST_CHECK(block.blocking() == false); + block.block(); + BOOST_CHECK(block.blocking() == true); + + // test assignment + { + block.unblock(); + boost::signals2::shared_connection_block block2(connections.at(0)); + BOOST_CHECK(block.connection() != block2.connection()); + BOOST_CHECK(block.blocking() != block2.blocking()); + block = block2; + BOOST_CHECK(block.connection() == block2.connection()); + BOOST_CHECK(block.blocking() == block2.blocking()); + } + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "123"); + } +} diff --git a/src/boost/libs/signals2/test/signal_n_test.cpp b/src/boost/libs/signals2/test/signal_n_test.cpp new file mode 100644 index 000000000..c1c2b4027 --- /dev/null +++ b/src/boost/libs/signals2/test/signal_n_test.cpp @@ -0,0 +1,352 @@ +// Boost.Signals library + +// Copyright Douglas Gregor 2001-2003. 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 + +#include <boost/bind/bind.hpp> +#include <boost/config.hpp> +#define BOOST_TEST_MODULE signal_n_test +#include <boost/test/included/unit_test.hpp> + +using namespace boost::placeholders; + +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES +BOOST_AUTO_TEST_CASE(test_main) +{ +} +#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES + +#include <boost/optional.hpp> +#include <boost/ref.hpp> +#include <boost/signals2.hpp> +#include <functional> + +template<typename T> +struct max_or_default { + typedef T result_type; + template<typename InputIterator> + typename InputIterator::value_type + operator()(InputIterator first, InputIterator last) const + { + boost::optional<T> max; + for (; first != last; ++first) + { + try + { + if(!max) max = *first; + else max = (*first > max.get())? *first : max; + } + catch(const boost::bad_weak_ptr &) + {} + } + if(max) return max.get(); + return T(); + } +}; + +struct make_int { + make_int(int n, int cn) : N(n), CN(n) {} + int operator()() { return N; } + int operator()() const { return CN; } + + int N; + int CN; +}; + +template<int N> +struct make_increasing_int { + make_increasing_int() : n(N) {} + + int operator()() const { return n++; } + + mutable int n; +}; + +int get_37() { return 37; } + +static void +test_zero_args() +{ + make_int i42(42, 41); + make_int i2(2, 1); + make_int i72(72, 71); + make_int i63(63, 63); + make_int i62(62, 61); + + { + boost::signals2::signal0<int, max_or_default<int>, std::string> s0; + boost::signals2::connection c2 = s0.connect(i2); + boost::signals2::connection c72 = s0.connect("72", i72); + boost::signals2::connection c62 = s0.connect("6x", i62); + boost::signals2::connection c42 = s0.connect(i42); + boost::signals2::connection c37 = s0.connect(&get_37); + + BOOST_CHECK(s0() == 72); + + s0.disconnect("72"); + BOOST_CHECK(s0() == 62); + + c72.disconnect(); // Double-disconnect should be safe + BOOST_CHECK(s0() == 62); + + s0.disconnect("72"); // Triple-disconect should be safe + BOOST_CHECK(s0() == 62); + + // Also connect 63 in the same group as 62 + s0.connect("6x", i63); + BOOST_CHECK(s0() == 63); + + // Disconnect all of the 60's + s0.disconnect("6x"); + BOOST_CHECK(s0() == 42); + + c42.disconnect(); + BOOST_CHECK(s0() == 37); + + c37.disconnect(); + BOOST_CHECK(s0() == 2); + + c2.disconnect(); + BOOST_CHECK(s0() == 0); + } + + { + boost::signals2::signal0<int, max_or_default<int> > s0; + boost::signals2::connection c2 = s0.connect(i2); + boost::signals2::connection c72 = s0.connect(i72); + boost::signals2::connection c62 = s0.connect(i62); + boost::signals2::connection c42 = s0.connect(i42); + + const boost::signals2::signal0<int, max_or_default<int> >& cs0 = s0; + BOOST_CHECK(cs0() == 72); + } + + { + make_increasing_int<7> i7; + make_increasing_int<10> i10; + + boost::signals2::signal0<int, max_or_default<int> > s0; + boost::signals2::connection c7 = s0.connect(i7); + boost::signals2::connection c10 = s0.connect(i10); + + BOOST_CHECK(s0() == 10); + BOOST_CHECK(s0() == 11); + } +} + +static void +test_one_arg() +{ + boost::signals2::signal1<int, int, max_or_default<int> > s1; + + s1.connect(std::negate<int>()); + s1.connect(boost::bind(std::multiplies<int>(), 2, _1)); + + BOOST_CHECK(s1(1) == 2); + BOOST_CHECK(s1(-1) == 1); +} + +static void +test_signal_signal_connect() +{ + typedef boost::signals2::signal1<int, int, max_or_default<int> > signal_type; + signal_type s1; + + s1.connect(std::negate<int>()); + + BOOST_CHECK(s1(3) == -3); + + { + signal_type s2; + s1.connect(s2); + s2.connect(boost::bind(std::multiplies<int>(), 2, _1)); + s2.connect(boost::bind(std::multiplies<int>(), -3, _1)); + + BOOST_CHECK(s2(-3) == 9); + BOOST_CHECK(s1(3) == 6); + } // s2 goes out of scope and disconnects + + BOOST_CHECK(s1(3) == -3); + + // test auto-track of signal wrapped in a reference_wrapper + { + signal_type s2; + s1.connect(boost::cref(s2)); + s2.connect(boost::bind(std::multiplies<int>(), 2, _1)); + s2.connect(boost::bind(std::multiplies<int>(), -3, _1)); + + BOOST_CHECK(s2(-3) == 9); + BOOST_CHECK(s1(3) == 6); + } // s2 goes out of scope and disconnects + + BOOST_CHECK(s1(3) == -3); +} + +struct EventCounter +{ + EventCounter() : count(0) {} + + void operator()() + { + ++count; + } + + int count; +}; + +static void +test_ref() +{ + EventCounter ec; + boost::signals2::signal0<void> s; + + { + boost::signals2::scoped_connection c(s.connect(boost::ref(ec))); + BOOST_CHECK(ec.count == 0); + s(); + BOOST_CHECK(ec.count == 1); + } + s(); + BOOST_CHECK(ec.count == 1); +} + +static void test_default_combiner() +{ + boost::signals2::signal0<int> sig; + boost::optional<int> result; + result = sig(); + BOOST_CHECK(!result); + + sig.connect(make_int(0, 0)); + result = sig(); + BOOST_CHECK(result); + BOOST_CHECK(*result == 0); + + sig.connect(make_int(1, 1)); + result = sig(); + BOOST_CHECK(result); + BOOST_CHECK(*result == 1); +} + +template<typename ResultType> + ResultType disconnecting_slot(const boost::signals2::connection &conn, int) +{ + conn.disconnect(); + return ResultType(); +} + +#ifdef BOOST_NO_VOID_RETURNS +template<> + void disconnecting_slot<void>(const boost::signals2::connection &conn, int) +{ + conn.disconnect(); + return; +} +#endif + +template<typename ResultType> + void test_extended_slot() +{ + { + typedef boost::signals2::signal1<ResultType, int> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig(0); + BOOST_CHECK(sig.num_slots() == 0); + } + { // test 0 arg signal + typedef boost::signals2::signal0<ResultType> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp, _1, 0); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig(); + BOOST_CHECK(sig.num_slots() == 0); + } + // test disconnection by slot + { + typedef boost::signals2::signal1<ResultType, int> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig.disconnect(fp); + BOOST_CHECK(sig.num_slots() == 0); + } +} +class dummy_combiner +{ +public: + typedef int result_type; + + dummy_combiner(result_type return_value): _return_value(return_value) + {} + template<typename SlotIterator> + result_type operator()(SlotIterator, SlotIterator) + { + return _return_value; + } +private: + result_type _return_value; +}; + +static void +test_set_combiner() +{ + typedef boost::signals2::signal0<int, dummy_combiner> signal_type; + signal_type sig(dummy_combiner(0)); + BOOST_CHECK(sig() == 0); + BOOST_CHECK(sig.combiner()(0,0) == 0); + sig.set_combiner(dummy_combiner(1)); + BOOST_CHECK(sig() == 1); + BOOST_CHECK(sig.combiner()(0,0) == 1); +} + +static void +test_swap() +{ + typedef boost::signals2::signal0<int, dummy_combiner> signal_type; + signal_type sig1(dummy_combiner(1)); + BOOST_CHECK(sig1() == 1); + signal_type sig2(dummy_combiner(2)); + BOOST_CHECK(sig2() == 2); + + sig1.swap(sig2); + BOOST_CHECK(sig1() == 2); + BOOST_CHECK(sig2() == 1); + + using std::swap; + swap(sig1, sig2); + BOOST_CHECK(sig1() == 1); + BOOST_CHECK(sig2() == 2); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_zero_args(); + test_one_arg(); + test_signal_signal_connect(); + test_ref(); + test_default_combiner(); + test_extended_slot<void>(); + test_extended_slot<int>(); + test_set_combiner(); + test_swap(); +} + +#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES diff --git a/src/boost/libs/signals2/test/signal_test.cpp b/src/boost/libs/signals2/test/signal_test.cpp new file mode 100644 index 000000000..3ae2817f7 --- /dev/null +++ b/src/boost/libs/signals2/test/signal_test.cpp @@ -0,0 +1,348 @@ +// Boost.Signals library + +// Copyright Frank Mori Hess 2008-2009. +// Copyright Douglas Gregor 2001-2003. +// +// 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 + +#include <boost/bind/bind.hpp> +#include <boost/optional.hpp> +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE signal_test +#include <boost/test/included/unit_test.hpp> +#include <functional> +#include <iostream> +#include <typeinfo> + +using namespace boost::placeholders; + +template<typename T> +struct max_or_default { + typedef T result_type; + template<typename InputIterator> + typename InputIterator::value_type + operator()(InputIterator first, InputIterator last) const + { + boost::optional<T> max; + for (; first != last; ++first) + { + try + { + if(!max) max = *first; + else max = (*first > max.get())? *first : max; + } + catch(const boost::bad_weak_ptr &) + {} + } + if(max) return max.get(); + return T(); + } +}; + +struct make_int { + make_int(int n, int cn) : N(n), CN(cn) {} + + int operator()() { return N; } + int operator()() const { return CN; } + + int N; + int CN; +}; + +template<int N> +struct make_increasing_int { + make_increasing_int() : n(N) {} + + int operator()() const { return n++; } + + mutable int n; +}; + +static void +test_zero_args() +{ + make_int i42(42, 41); + make_int i2(2, 1); + make_int i72(72, 71); + make_int i63(63, 63); + make_int i62(62, 61); + + { + boost::signals2::signal<int (), max_or_default<int> > s0; + + std::cout << "sizeof(signal) = " << sizeof(s0) << std::endl; + boost::signals2::connection c2 = s0.connect(i2); + boost::signals2::connection c72 = s0.connect(72, i72); + boost::signals2::connection c62 = s0.connect(60, i62); + boost::signals2::connection c42 = s0.connect(i42); + + BOOST_CHECK(s0() == 72); + + s0.disconnect(72); + BOOST_CHECK(s0() == 62); + + c72.disconnect(); // Double-disconnect should be safe + BOOST_CHECK(s0() == 62); + + s0.disconnect(72); // Triple-disconect should be safe + BOOST_CHECK(s0() == 62); + + // Also connect 63 in the same group as 62 + s0.connect(60, i63); + BOOST_CHECK(s0() == 63); + + // Disconnect all of the 60's + s0.disconnect(60); + BOOST_CHECK(s0() == 42); + + c42.disconnect(); + BOOST_CHECK(s0() == 2); + + c2.disconnect(); + BOOST_CHECK(s0() == 0); + } + + { + boost::signals2::signal<int (), max_or_default<int> > s0; + boost::signals2::connection c2 = s0.connect(i2); + boost::signals2::connection c72 = s0.connect(i72); + boost::signals2::connection c62 = s0.connect(i62); + boost::signals2::connection c42 = s0.connect(i42); + + const boost::signals2::signal<int (), max_or_default<int> >& cs0 = s0; + BOOST_CHECK(cs0() == 72); + } + + { + make_increasing_int<7> i7; + make_increasing_int<10> i10; + + boost::signals2::signal<int (), max_or_default<int> > s0; + boost::signals2::connection c7 = s0.connect(i7); + boost::signals2::connection c10 = s0.connect(i10); + + BOOST_CHECK(s0() == 10); + BOOST_CHECK(s0() == 11); + } +} + +static void +test_one_arg() +{ + boost::signals2::signal<int (int value), max_or_default<int> > s1; + + s1.connect(std::negate<int>()); + s1.connect(boost::bind(std::multiplies<int>(), 2, _1)); + + BOOST_CHECK(s1(1) == 2); + BOOST_CHECK(s1(-1) == 1); +} + +static void +test_signal_signal_connect() +{ + typedef boost::signals2::signal<int (int value), max_or_default<int> > signal_type; + signal_type s1; + + s1.connect(std::negate<int>()); + + BOOST_CHECK(s1(3) == -3); + + { + signal_type s2; + s1.connect(s2); + s2.connect(boost::bind(std::multiplies<int>(), 2, _1)); + s2.connect(boost::bind(std::multiplies<int>(), -3, _1)); + + BOOST_CHECK(s2(-3) == 9); + BOOST_CHECK(s1(3) == 6); + } // s2 goes out of scope and disconnects + BOOST_CHECK(s1(3) == -3); +} + +template<typename ResultType> + ResultType disconnecting_slot(const boost::signals2::connection &conn, int) +{ + conn.disconnect(); + return ResultType(); +} + +#ifdef BOOST_NO_VOID_RETURNS +template<> + void disconnecting_slot<void>(const boost::signals2::connection &conn, int) +{ + conn.disconnect(); + return; +} +#endif + +template<typename ResultType> + void test_extended_slot() +{ + { + typedef boost::signals2::signal<ResultType (int)> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig(0); + BOOST_CHECK(sig.num_slots() == 0); + } + { // test 0 arg signal + typedef boost::signals2::signal<ResultType ()> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp, _1, 0); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig(); + BOOST_CHECK(sig.num_slots() == 0); + } + // test disconnection by slot + { + typedef boost::signals2::signal<ResultType (int)> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig.disconnect(fp); + BOOST_CHECK(sig.num_slots() == 0); + } +} + +void increment_arg(int &value) +{ + ++value; +} + +static void +test_reference_args() +{ + typedef boost::signals2::signal<void (int &)> signal_type; + signal_type s1; + + s1.connect(&increment_arg); + int value = 0; + s1(value); + BOOST_CHECK(value == 1); +} + +static void +test_typedefs_etc() +{ + typedef boost::signals2::signal<int (double, long)> signal_type; + typedef signal_type::slot_type slot_type; + + BOOST_CHECK(typeid(signal_type::slot_result_type) == typeid(int)); + BOOST_CHECK(typeid(signal_type::result_type) == typeid(boost::optional<int>)); + BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(double)); + BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(long)); + BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(signal_type::first_argument_type)); + BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(signal_type::second_argument_type)); + BOOST_CHECK(typeid(signal_type::signature_type) == typeid(int (double, long))); + BOOST_CHECK(signal_type::arity == 2); + + BOOST_CHECK(typeid(slot_type::result_type) == typeid(signal_type::slot_result_type)); + BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(signal_type::arg<0>::type)); + BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(signal_type::arg<1>::type)); + BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(slot_type::first_argument_type)); + BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(slot_type::second_argument_type)); + BOOST_CHECK(typeid(slot_type::signature_type) == typeid(signal_type::signature_type)); + BOOST_CHECK(slot_type::arity == signal_type::arity); + + typedef boost::signals2::signal<void (short)> unary_signal_type; + BOOST_CHECK(typeid(unary_signal_type::slot_result_type) == typeid(void)); + BOOST_CHECK(typeid(unary_signal_type::argument_type) == typeid(short)); + BOOST_CHECK(typeid(unary_signal_type::slot_type::argument_type) == typeid(short)); +} + +class dummy_combiner +{ +public: + typedef int result_type; + + dummy_combiner(result_type return_value): _return_value(return_value) + {} + template<typename SlotIterator> + result_type operator()(SlotIterator, SlotIterator) + { + return _return_value; + } +private: + result_type _return_value; +}; + +static void +test_set_combiner() +{ + typedef boost::signals2::signal<int (), dummy_combiner> signal_type; + signal_type sig(dummy_combiner(0)); + BOOST_CHECK(sig() == 0); + BOOST_CHECK(sig.combiner()(0,0) == 0); + sig.set_combiner(dummy_combiner(1)); + BOOST_CHECK(sig() == 1); + BOOST_CHECK(sig.combiner()(0,0) == 1); +} + +static void +test_swap() +{ + typedef boost::signals2::signal<int (), dummy_combiner> signal_type; + signal_type sig1(dummy_combiner(1)); + BOOST_CHECK(sig1() == 1); + signal_type sig2(dummy_combiner(2)); + BOOST_CHECK(sig2() == 2); + + sig1.swap(sig2); + BOOST_CHECK(sig1() == 2); + BOOST_CHECK(sig2() == 1); + + using std::swap; + swap(sig1, sig2); + BOOST_CHECK(sig1() == 1); + BOOST_CHECK(sig2() == 2); +} + +void test_move() +{ +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + typedef boost::signals2::signal<int (), dummy_combiner> signal_type; + signal_type sig1(dummy_combiner(1)); + BOOST_CHECK(sig1() == 1); + signal_type sig2(dummy_combiner(2)); + BOOST_CHECK(sig2() == 2); + + sig1 = std::move(sig2); + BOOST_CHECK(sig1() == 2); + + signal_type sig3(std::move(sig1)); + BOOST_CHECK(sig3() == 2); +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_zero_args(); + test_one_arg(); + test_signal_signal_connect(); + test_extended_slot<void>(); + test_extended_slot<int>(); + test_reference_args(); + test_typedefs_etc(); + test_set_combiner(); + test_swap(); + test_move(); +} diff --git a/src/boost/libs/signals2/test/signal_type_test.cpp b/src/boost/libs/signals2/test/signal_type_test.cpp new file mode 100644 index 000000000..94c746429 --- /dev/null +++ b/src/boost/libs/signals2/test/signal_type_test.cpp @@ -0,0 +1,43 @@ +// Tests for boost::signals2::signal_type + +// Copyright Frank Mori Hess 2009. +// Distributed under 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) + +// See http://www.boost.org/libs/signals2 for library home page. + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE signal_type_test +#include <boost/test/included/unit_test.hpp> + +namespace bs2 = boost::signals2; + +BOOST_AUTO_TEST_CASE(test_main) +{ + { + bs2::signal_type<void ()>::type mysig; + bs2::signal<void ()> mysig2; + BOOST_CHECK(typeid(mysig) == typeid(mysig2)); + } + + { + bs2::signal_type<double (int), bs2::last_value<double> >::type mysig; + bs2::signal<double (int), bs2::last_value<double> > mysig2; + BOOST_CHECK(typeid(mysig) == typeid(mysig2)); + } + + { + using namespace bs2::keywords; + bs2::signal_type<double (int), group_compare_type<std::less<float> >, group_type<float> >::type mysig; + bs2::signal<double (int), bs2::optional_last_value<double>, float, std::less<float> > mysig2; + BOOST_CHECK(typeid(mysig) == typeid(mysig2)); + } + + { + using namespace bs2::keywords; + bs2::signal_type<signature_type<float (long*)> >::type mysig; + bs2::signal<float (long*)> mysig2; + BOOST_CHECK(typeid(mysig) == typeid(mysig2)); + } +} diff --git a/src/boost/libs/signals2/test/slot_compile_test.cpp b/src/boost/libs/signals2/test/slot_compile_test.cpp new file mode 100644 index 000000000..6ce6c3715 --- /dev/null +++ b/src/boost/libs/signals2/test/slot_compile_test.cpp @@ -0,0 +1,27 @@ +// Signals2 library +// test for compilation of boost/signals2/slot.hpp + +// Copyright Frank Mori Hess 2008 +// 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 + +#include <boost/signals2/slot.hpp> +#define BOOST_TEST_MODULE slot_compile_test +#include <boost/test/included/unit_test.hpp> + +void myslot() +{} + +int myslot2(int) +{ + return 0; +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + boost::signals2::slot<void (void)> sl0(&myslot); +} diff --git a/src/boost/libs/signals2/test/threading_models_test.cpp b/src/boost/libs/signals2/test/threading_models_test.cpp new file mode 100644 index 000000000..bddae17c0 --- /dev/null +++ b/src/boost/libs/signals2/test/threading_models_test.cpp @@ -0,0 +1,86 @@ +// thread_safe_signals library +// basic test for alternate threading models + +// Copyright Frank Mori Hess 2008 +// 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 + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE threading_models_test +#include <boost/test/included/unit_test.hpp> +#include <boost/thread/mutex.hpp> + +// combiner that returns the number of slots invoked +struct slot_counter { + typedef unsigned result_type; + template<typename InputIterator> + unsigned operator()(InputIterator first, InputIterator last) const + { + unsigned count = 0; + for (; first != last; ++first) + { + try + { + *first; + ++count; + } + catch(const boost::bad_weak_ptr &) + {} + } + return count; + } +}; + +void myslot() +{ +} + +template<typename signal_type> +void simple_test() +{ + signal_type sig; + sig.connect(typename signal_type::slot_type(&myslot)); + BOOST_CHECK(sig() == 1); + sig.disconnect(&myslot); + BOOST_CHECK(sig() == 0); +} + +class recursion_checking_dummy_mutex +{ + int recursion_count; +public: + recursion_checking_dummy_mutex(): recursion_count(0) + {} + void lock() + { + BOOST_REQUIRE(recursion_count == 0); + ++recursion_count; + } + bool try_lock() + { + lock(); + return true; + } + void unlock() + { + --recursion_count; + BOOST_REQUIRE(recursion_count == 0); + } +}; + +BOOST_AUTO_TEST_CASE(test_main) +{ + typedef boost::signals2::signal<void (), slot_counter, int, std::less<int>, boost::function<void ()>, + boost::function<void (const boost::signals2::connection &)>, recursion_checking_dummy_mutex> sig0_rc_type; + simple_test<sig0_rc_type>(); + typedef boost::signals2::signal<void (), slot_counter, int, std::less<int>, boost::function<void ()>, + boost::function<void (const boost::signals2::connection &)>, boost::mutex> sig0_mt_type; + simple_test<sig0_mt_type>(); + typedef boost::signals2::signal<void (), slot_counter, int, std::less<int>, boost::function<void ()>, + boost::function<void (const boost::signals2::connection &)>, boost::signals2::dummy_mutex> sig0_st_type; + simple_test<sig0_st_type>(); +} diff --git a/src/boost/libs/signals2/test/track_test.cpp b/src/boost/libs/signals2/test/track_test.cpp new file mode 100644 index 000000000..405aa11b6 --- /dev/null +++ b/src/boost/libs/signals2/test/track_test.cpp @@ -0,0 +1,167 @@ +// Boost.Signals library + +// Copyright Douglas Gregor 2001-2006 +// Copyright Frank Mori Hess 2007 +// 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 + +#include <memory> +#include <boost/optional.hpp> +#include <boost/ref.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE track_test +#include <boost/test/included/unit_test.hpp> +#include <boost/bind/bind.hpp> + +using namespace boost::placeholders; + +struct swallow { + typedef int result_type; + template<typename T> result_type operator()(const T*, int i) { return i; } +}; + +template<typename T> +struct max_or_default { + typedef T result_type; + + template<typename InputIterator> + T operator()(InputIterator first, InputIterator last) const + { + boost::optional<T> max; + for(; first != last; ++first) + { + T value = *first; + if(!max) + { + max = value; + }else if(value > *max) + { + max = value; + } + } + if(max) return *max; + else return T(); + } +}; + +static int myfunc(int i, double z) +{ + return i; +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + typedef boost::signals2::signal<int (int), max_or_default<int> > sig_type; + sig_type s1; + boost::signals2::connection connection; + + // Test auto-disconnection + BOOST_CHECK(s1(5) == 0); + { + boost::shared_ptr<int> shorty(new int()); + s1.connect(sig_type::slot_type(swallow(), shorty.get(), _1).track(shorty)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + + // Test auto-disconnection of slot before signal connection + { + boost::shared_ptr<int> shorty(new int(1)); +// doesn't work on gcc 3.3.5, it says: error: type specifier omitted for parameter `shorty' +// does work on gcc 4.1.2 +// sig_type::slot_type slot(swallow(), shorty.get(), _1); + swallow myswallow; + sig_type::slot_type slot(myswallow, shorty.get(), _1); + + slot.track(shorty); + shorty.reset(); + s1.connect(slot); + BOOST_CHECK(s1(5) == 0); + } + + // Test binding of a slot to another slot + { + boost::shared_ptr<int> shorty(new int(2)); + boost::signals2::slot<int (double)> other_slot(&myfunc, boost::cref(*shorty.get()), _1); + other_slot.track(shorty); + 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 + { + sig_type s2; + s1.connect(s2); + s2.connect(sig_type::slot_type(&myfunc, _1, 0.7)); + BOOST_CHECK(s1(4) == 4); + } + BOOST_CHECK(s1(4) == 0); + + // Test tracking of null but not empty shared_ptr + BOOST_CHECK(s1(2) == 0); + { + boost::shared_ptr<int> shorty((int*)(0)); + s1.connect(sig_type::slot_type(swallow(), shorty.get(), _1).track(shorty)); + BOOST_CHECK(s1(2) == 2); + } + BOOST_CHECK(s1(2) == 0); + +#ifndef BOOST_NO_CXX11_SMART_PTR + // Test tracking through std::shared_ptr/weak_ptr + BOOST_CHECK(s1(5) == 0); + { + std::shared_ptr<int> shorty(new int()); + s1.connect(sig_type::slot_type(swallow(), shorty.get(), _1).track_foreign(shorty)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + { + std::shared_ptr<int> shorty(new int()); + s1.connect + ( + sig_type::slot_type + ( + swallow(), + shorty.get(), + _1 + ).track_foreign + ( + std::weak_ptr<int>(shorty) + ) + ); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + // make sure tracking foreign shared_ptr<const void> works + { + std::shared_ptr<const void> shorty(new int()); + s1.connect(sig_type::slot_type(swallow(), shorty.get(), _1).track_foreign(shorty)); + BOOST_CHECK(s1(5) == 5); + } + { + std::shared_ptr<int> shorty(new int()); + s1.connect + ( + sig_type::slot_type + ( + swallow(), + shorty.get(), + _1 + ).track_foreign + ( + std::weak_ptr<const void>(shorty) + ) + ); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + BOOST_CHECK(s1(5) == 0); +#endif +} diff --git a/src/boost/libs/signals2/test/trackable_test.cpp b/src/boost/libs/signals2/test/trackable_test.cpp new file mode 100644 index 000000000..b3049cdfd --- /dev/null +++ b/src/boost/libs/signals2/test/trackable_test.cpp @@ -0,0 +1,112 @@ +// Boost.Signals2 library + +// Copyright Douglas Gregor 2001-2006. +// Copyright Frank Mori Hess 2009. +// 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 + +#include <boost/signals2/signal.hpp> +#include <boost/signals2/trackable.hpp> +#define BOOST_TEST_MODULE trackable_test +#include <boost/test/included/unit_test.hpp> +#include <boost/bind/bind.hpp> +#include <boost/ref.hpp> +#include <boost/weak_ptr.hpp> + +using namespace boost::placeholders; + +struct short_lived : public boost::signals2::trackable { + ~short_lived() {} +}; + +struct swallow { + typedef int result_type; + template<typename T> int operator()(const T*, int i) { return i; } + template<typename T> int operator()(T &, int i) { return i; } + template<typename T> int operator()(boost::weak_ptr<T>, int i) { return i; } +}; + +template<typename T> +struct max_or_default { + typedef T result_type; + + template<typename InputIterator> + T operator()(InputIterator first, InputIterator last) const + { + if (first == last) + return T(); + + T max = *first++; + for (; first != last; ++first) + max = (*first > max)? *first : max; + + return max; + } +}; + +struct self_deleting : public boost::signals2::trackable { + void delete_myself(boost::signals2::connection connection) + { + BOOST_CHECK(connection.connected()); + delete this; + BOOST_CHECK(connection.connected() == false); + } +}; + +// test that slot assocated with signals2::trackable +// gets disconnected immediately upon deletion of the +// signals2::trackable, even when a signal invocation +// is in progress. +void test_immediate_disconnect_on_delete() +{ + boost::signals2::signal<void () > sig; + self_deleting *obj = new self_deleting(); + sig.connect_extended(boost::bind(&self_deleting::delete_myself, obj, _1)); + sig(); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + typedef boost::signals2::signal<int (int), max_or_default<int> > sig_type; + sig_type s1; + + // Test auto-disconnection + BOOST_CHECK(s1(5) == 0); + { + short_lived shorty; + s1.connect(boost::bind<int>(swallow(), &shorty, _1)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + // Test auto-disconnection of trackable inside reference_wrapper + { + short_lived shorty; + s1.connect(boost::bind<int>(swallow(), boost::ref(shorty), _1)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + + // Test multiple arg slot constructor + { + short_lived shorty; + s1.connect(sig_type::slot_type(swallow(), &shorty, _1)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + + // Test auto-disconnection of slot before signal connection + { + short_lived* shorty = new short_lived(); + + sig_type::slot_type slot(boost::bind<int>(swallow(), shorty, _1)); + delete shorty; + + BOOST_CHECK(s1(5) == 0); + } + + test_immediate_disconnect_on_delete(); +} |