diff --git a/simgear/io/HTTPRequest.cxx b/simgear/io/HTTPRequest.cxx index 900b7fc2..0809c70a 100644 --- a/simgear/io/HTTPRequest.cxx +++ b/simgear/io/HTTPRequest.cxx @@ -39,7 +39,7 @@ Request* Request::done(const Callback& cb) if( _ready_state == DONE ) cb(this); else - _cb_done = cb; + _cb_done.push_back(cb); return this; } @@ -50,7 +50,7 @@ Request* Request::fail(const Callback& cb) if( _ready_state == FAILED ) cb(this); else - _cb_fail = cb; + _cb_fail.push_back(cb); return this; } @@ -61,7 +61,7 @@ Request* Request::always(const Callback& cb) if( isComplete() ) cb(this); else - _cb_always = cb; + _cb_always.push_back(cb); return this; } @@ -321,22 +321,19 @@ void Request::setReadyState(ReadyState state) onDone(); onAlways(); - if( _cb_done ) - _cb_done(this); + _cb_done(this); } else if( state == FAILED ) { onFail(); onAlways(); - if( _cb_fail ) - _cb_fail(this); + _cb_fail(this); } else return; - if( _cb_always ) - _cb_always(this); + _cb_always(this); } //------------------------------------------------------------------------------ diff --git a/simgear/io/HTTPRequest.hxx b/simgear/io/HTTPRequest.hxx index ef101b3f..f739d2b8 100644 --- a/simgear/io/HTTPRequest.hxx +++ b/simgear/io/HTTPRequest.hxx @@ -3,13 +3,13 @@ #include +#include #include #include #include #include #include -#include class SGPropertyNode; @@ -47,7 +47,7 @@ public: { return _request_headers.get(key); } /** - * Set the handler to be called when the request successfully completes. + * Add a handler to be called when the request successfully completes. * * @note If the request is already complete, the handler is called * immediately. @@ -61,7 +61,7 @@ public: } /** - * Set the handler to be called when the request completes or aborts with an + * Add a handler to be called when the request completes or aborts with an * error. * * @note If the request has already failed, the handler is called @@ -76,8 +76,8 @@ public: } /** - * Set the handler to be called when the request either successfully - * completes or fails. + * Add a handler to be called when the request either successfully completes + * or fails. * * @note If the request is already complete or has already failed, the * handler is called immediately. @@ -224,9 +224,9 @@ private: unsigned int _responseLength; unsigned int _receivedBodyBytes; - Callback _cb_done, - _cb_fail, - _cb_always; + function_list _cb_done, + _cb_fail, + _cb_always; ReadyState _ready_state; bool _willClose; diff --git a/simgear/package/Install.cxx b/simgear/package/Install.cxx index b5c9487d..659511ff 100644 --- a/simgear/package/Install.cxx +++ b/simgear/package/Install.cxx @@ -325,7 +325,7 @@ Install* Install::done(const Callback& cb) if( _status == Delegate::FAIL_SUCCESS ) cb(this); else - _cb_done = cb; + _cb_done.push_back(cb); return this; } @@ -337,7 +337,7 @@ Install* Install::fail(const Callback& cb) && _status != Delegate::FAIL_IN_PROGRESS ) cb(this); else - _cb_fail = cb; + _cb_fail.push_back(cb); return this; } @@ -348,7 +348,7 @@ Install* Install::always(const Callback& cb) if( _status != Delegate::FAIL_IN_PROGRESS ) cb(this); else - _cb_always = cb; + _cb_always.push_back(cb); return this; } @@ -356,7 +356,7 @@ Install* Install::always(const Callback& cb) //------------------------------------------------------------------------------ Install* Install::progress(const ProgressCallback& cb) { - _cb_progress = cb; + _cb_progress.push_back(cb); return this; } @@ -365,24 +365,20 @@ void Install::installResult(Delegate::FailureCode aReason) { if (aReason == Delegate::FAIL_SUCCESS) { m_package->catalog()->root()->finishInstall(this); - if( _cb_done ) - _cb_done(this); + _cb_done(this); } else { m_package->catalog()->root()->failedInstall(this, aReason); - if( _cb_fail ) - _cb_fail(this); + _cb_fail(this); } - if( _cb_always ) - _cb_always(this); + _cb_always(this); } //------------------------------------------------------------------------------ void Install::installProgress(unsigned int aBytes, unsigned int aTotal) { - m_package->catalog()->root()->installProgress(this, aBytes, aTotal); - if( _cb_progress ) - _cb_progress(this, aBytes, aTotal); + m_package->catalog()->root()->installProgress(this, aBytes, aTotal); + _cb_progress(this, aBytes, aTotal); } diff --git a/simgear/package/Install.hxx b/simgear/package/Install.hxx index 81cf580a..e65789c4 100644 --- a/simgear/package/Install.hxx +++ b/simgear/package/Install.hxx @@ -23,11 +23,11 @@ #include #include +#include #include #include #include -#include namespace simgear { @@ -156,11 +156,10 @@ private: Delegate::FailureCode _status; - Callback _cb_done, - _cb_fail, - _cb_always; - ProgressCallback _cb_progress; - + function_list _cb_done, + _cb_fail, + _cb_always; + function_list _cb_progress; }; diff --git a/simgear/structure/CMakeLists.txt b/simgear/structure/CMakeLists.txt index 7679588c..0c41b622 100644 --- a/simgear/structure/CMakeLists.txt +++ b/simgear/structure/CMakeLists.txt @@ -21,12 +21,17 @@ set(HEADERS commands.hxx event_mgr.hxx exception.hxx + function_list.hxx intern.hxx map.hxx subsystem_mgr.hxx StateMachine.hxx ) +set(DETAIL_HEADERS + detail/function_list_template.hxx +) + set(SOURCES SGAtomic.cxx SGBinding.cxx @@ -43,6 +48,7 @@ set(SOURCES ) simgear_component(structure structure "${SOURCES}" "${HEADERS}") +simgear_component(structure/detail structure/detail "" "${DETAIL_HEADERS}") if(ENABLE_TESTS) @@ -56,6 +62,11 @@ add_test(expressions ${EXECUTABLE_OUTPUT_PATH}/test_expressions) endif(ENABLE_TESTS) +add_boost_test(function_list + SOURCES function_list_test.cxx + LIBRARIES ${TEST_LIBS} +) + add_boost_test(shared_ptr SOURCES shared_ptr_test.cpp LIBRARIES ${TEST_LIBS} diff --git a/simgear/structure/detail/function_list_template.hxx b/simgear/structure/detail/function_list_template.hxx new file mode 100644 index 00000000..92a10a27 --- /dev/null +++ b/simgear/structure/detail/function_list_template.hxx @@ -0,0 +1,37 @@ +#ifndef SG_FUNCTION_LIST_HXX_ +# error function_list - do not include this file! +#endif + +#ifndef SG_DONT_DO_ANYTHING +#define n BOOST_PP_ITERATION() +#define SG_FUNC_TYPE boost::function +#define SG_LIST_TYPE std::vector + +template +class function_list: + public SG_LIST_TYPE +{ + public: + typedef SG_FUNC_TYPE function_type; + typedef typename SG_LIST_TYPE::iterator iterator; + typedef typename SG_LIST_TYPE::const_iterator const_iterator; + + Ret operator()(BOOST_PP_ENUM_BINARY_PARAMS(n, A, a)) const + { + if( this->empty() ) + return Ret(); + + const_iterator list_end = --this->end(); + for(const_iterator f = this->begin(); f != list_end; ++f) + if( *f ) + (*f)(BOOST_PP_ENUM_PARAMS(n, a)); + + return (*list_end) ? (*list_end)(BOOST_PP_ENUM_PARAMS(n, a)) : Ret(); + } +}; + +#undef n +#undef SG_FUNC_TYPE +#undef SG_LIST_TYPE + +#endif // SG_DONT_DO_ANYTHING diff --git a/simgear/structure/function_list.hxx b/simgear/structure/function_list.hxx new file mode 100644 index 00000000..28ef08e4 --- /dev/null +++ b/simgear/structure/function_list.hxx @@ -0,0 +1,51 @@ +///@file Handle a list of callbacks like a single boost::function +// +// Copyright (C) 2014 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_FUNCTION_LIST_HXX_ +#define SG_FUNCTION_LIST_HXX_ + +#include +#include +#include +#include +#include +#include + +namespace simgear +{ + template class function_list; + + // Build dependency for CMake, gcc, etc. +# define SG_DONT_DO_ANYTHING +# include +# undef SG_DONT_DO_ANYTHING + +# define BOOST_PP_ITERATION_LIMITS (0, 3) +# define BOOST_PP_FILENAME_1 +# include BOOST_PP_ITERATE() + + template + class function_list >: + public function_list + { + + }; + +} // namespace simgear + +#endif /* SG_FUNCTION_LIST_HXX_ */ diff --git a/simgear/structure/function_list_test.cxx b/simgear/structure/function_list_test.cxx new file mode 100644 index 00000000..58202c9c --- /dev/null +++ b/simgear/structure/function_list_test.cxx @@ -0,0 +1,77 @@ +#define BOOST_TEST_MODULE structurce +#include + +#include "function_list.hxx" + +static int func_called = 0, + func2_called = 0; + +int func(int x) +{ + ++func_called; + return x; +} + +int func2(int x) +{ + ++func2_called; + return 2 * x; +} + +int func_add(int x, int y) +{ + return func(x) + y; +} + +int func2_add(int x, int y) +{ + return func2(x) + y; +} + +static int func_void_called = 0; +void func_void() +{ + ++func_void_called; +} + +BOOST_AUTO_TEST_CASE( create_and_call ) +{ + using namespace simgear; + + function_list func_list; + + BOOST_REQUIRE(func_list.empty()); + + func_list.push_back(&func); + BOOST_REQUIRE_EQUAL(func_list(2), 2); + BOOST_REQUIRE_EQUAL(func_called, 1); + + func_list.push_back(&func2); + BOOST_REQUIRE_EQUAL(func_list(2), 4); + BOOST_REQUIRE_EQUAL(func_called, 2); + BOOST_REQUIRE_EQUAL(func2_called, 1); + + function_list > func_list2; + func_list2.push_back(&func); + func_list2.push_back(&func2); + func_list2.push_back(&func2); + + BOOST_REQUIRE_EQUAL(func_list2(2), 4); + BOOST_REQUIRE_EQUAL(func_called, 3); + BOOST_REQUIRE_EQUAL(func2_called, 3); + + // two parameters + function_list > func_list3; + func_list3.push_back(&func_add); + func_list3.push_back(&func2_add); + + BOOST_REQUIRE_EQUAL(func_list3(2, 3), 7); + BOOST_REQUIRE_EQUAL(func_called, 4); + BOOST_REQUIRE_EQUAL(func2_called, 4); + + // returning void/no params + function_list void_func_list; + void_func_list.push_back(&func_void); + void_func_list(); + BOOST_REQUIRE_EQUAL(func_void_called, 1); +}