Index: boost/function/detail/gen_maybe_include.pl =================================================================== --- boost/function/detail/gen_maybe_include.pl (revision 65811) +++ boost/function/detail/gen_maybe_include.pl (working copy) @@ -29,7 +29,10 @@ print OUT " BOOST_FUNCTION_NUM_ARGS == $on_arg\n"; print OUT "# ifndef BOOST_FUNCTION_$on_arg\n"; print OUT "# define BOOST_FUNCTION_$on_arg\n"; + print OUT "# define BOOST_FUNCTION_BE_SAFE\n"; print OUT "# include \n"; + print OUT "# undef BOOST_FUNCTION_BE_SAFE\n"; + print OUT "# include \n"; print OUT "# endif\n"; } print OUT "#else\n"; Index: boost/function/detail/maybe_include.hpp =================================================================== --- boost/function/detail/maybe_include.hpp (revision 65811) +++ boost/function/detail/maybe_include.hpp (working copy) @@ -10,257 +10,410 @@ #if BOOST_FUNCTION_NUM_ARGS == 0 # ifndef BOOST_FUNCTION_0 # define BOOST_FUNCTION_0 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 1 # ifndef BOOST_FUNCTION_1 # define BOOST_FUNCTION_1 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 2 # ifndef BOOST_FUNCTION_2 # define BOOST_FUNCTION_2 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 3 # ifndef BOOST_FUNCTION_3 # define BOOST_FUNCTION_3 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 4 # ifndef BOOST_FUNCTION_4 # define BOOST_FUNCTION_4 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 5 # ifndef BOOST_FUNCTION_5 # define BOOST_FUNCTION_5 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 6 # ifndef BOOST_FUNCTION_6 # define BOOST_FUNCTION_6 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 7 # ifndef BOOST_FUNCTION_7 # define BOOST_FUNCTION_7 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 8 # ifndef BOOST_FUNCTION_8 # define BOOST_FUNCTION_8 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 9 # ifndef BOOST_FUNCTION_9 # define BOOST_FUNCTION_9 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 10 # ifndef BOOST_FUNCTION_10 # define BOOST_FUNCTION_10 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 11 # ifndef BOOST_FUNCTION_11 # define BOOST_FUNCTION_11 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 12 # ifndef BOOST_FUNCTION_12 # define BOOST_FUNCTION_12 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 13 # ifndef BOOST_FUNCTION_13 # define BOOST_FUNCTION_13 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 14 # ifndef BOOST_FUNCTION_14 # define BOOST_FUNCTION_14 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 15 # ifndef BOOST_FUNCTION_15 # define BOOST_FUNCTION_15 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 16 # ifndef BOOST_FUNCTION_16 # define BOOST_FUNCTION_16 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 17 # ifndef BOOST_FUNCTION_17 # define BOOST_FUNCTION_17 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 18 # ifndef BOOST_FUNCTION_18 # define BOOST_FUNCTION_18 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 19 # ifndef BOOST_FUNCTION_19 # define BOOST_FUNCTION_19 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 20 # ifndef BOOST_FUNCTION_20 # define BOOST_FUNCTION_20 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 21 # ifndef BOOST_FUNCTION_21 # define BOOST_FUNCTION_21 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 22 # ifndef BOOST_FUNCTION_22 # define BOOST_FUNCTION_22 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 23 # ifndef BOOST_FUNCTION_23 # define BOOST_FUNCTION_23 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 24 # ifndef BOOST_FUNCTION_24 # define BOOST_FUNCTION_24 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 25 # ifndef BOOST_FUNCTION_25 # define BOOST_FUNCTION_25 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 26 # ifndef BOOST_FUNCTION_26 # define BOOST_FUNCTION_26 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 27 # ifndef BOOST_FUNCTION_27 # define BOOST_FUNCTION_27 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 28 # ifndef BOOST_FUNCTION_28 # define BOOST_FUNCTION_28 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 29 # ifndef BOOST_FUNCTION_29 # define BOOST_FUNCTION_29 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 30 # ifndef BOOST_FUNCTION_30 # define BOOST_FUNCTION_30 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 31 # ifndef BOOST_FUNCTION_31 # define BOOST_FUNCTION_31 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 32 # ifndef BOOST_FUNCTION_32 # define BOOST_FUNCTION_32 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 33 # ifndef BOOST_FUNCTION_33 # define BOOST_FUNCTION_33 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 34 # ifndef BOOST_FUNCTION_34 # define BOOST_FUNCTION_34 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 35 # ifndef BOOST_FUNCTION_35 # define BOOST_FUNCTION_35 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 36 # ifndef BOOST_FUNCTION_36 # define BOOST_FUNCTION_36 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 37 # ifndef BOOST_FUNCTION_37 # define BOOST_FUNCTION_37 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 38 # ifndef BOOST_FUNCTION_38 # define BOOST_FUNCTION_38 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 39 # ifndef BOOST_FUNCTION_39 # define BOOST_FUNCTION_39 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 40 # ifndef BOOST_FUNCTION_40 # define BOOST_FUNCTION_40 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 41 # ifndef BOOST_FUNCTION_41 # define BOOST_FUNCTION_41 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 42 # ifndef BOOST_FUNCTION_42 # define BOOST_FUNCTION_42 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 43 # ifndef BOOST_FUNCTION_43 # define BOOST_FUNCTION_43 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 44 # ifndef BOOST_FUNCTION_44 # define BOOST_FUNCTION_44 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 45 # ifndef BOOST_FUNCTION_45 # define BOOST_FUNCTION_45 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 46 # ifndef BOOST_FUNCTION_46 # define BOOST_FUNCTION_46 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 47 # ifndef BOOST_FUNCTION_47 # define BOOST_FUNCTION_47 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 48 # ifndef BOOST_FUNCTION_48 # define BOOST_FUNCTION_48 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 49 # ifndef BOOST_FUNCTION_49 # define BOOST_FUNCTION_49 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #elif BOOST_FUNCTION_NUM_ARGS == 50 # ifndef BOOST_FUNCTION_50 # define BOOST_FUNCTION_50 +# define BOOST_FUNCTION_BE_SAFE # include +# undef BOOST_FUNCTION_BE_SAFE +# include # endif #else # error Cannot handle Boost.Function objects that accept more than 50 arguments! Index: boost/function/function_template.hpp =================================================================== --- boost/function/function_template.hpp (revision 65811) +++ boost/function/function_template.hpp (working copy) @@ -41,7 +41,16 @@ #endif // BOOST_FUNCTION_NUM_ARGS > 0 // Class names used in this version of the code -#define BOOST_FUNCTION_FUNCTION BOOST_JOIN(function,BOOST_FUNCTION_NUM_ARGS) +#define BOOST_FUNCTION_SAFE_WRAPPER function +#define BOOST_FUNCTION_UNSAFE_WRAPPER unsafe_function +#define BOOST_FUNCTION_SAFE_FUNCTION BOOST_JOIN(BOOST_FUNCTION_SAFE_WRAPPER,BOOST_FUNCTION_NUM_ARGS) +#define BOOST_FUNCTION_UNSAFE_FUNCTION BOOST_JOIN(BOOST_FUNCTION_UNSAFE_WRAPPER,BOOST_FUNCTION_NUM_ARGS) +#if defined(BOOST_FUNCTION_BE_SAFE) +# define BOOST_FUNCTION_WRAPPER BOOST_FUNCTION_SAFE_WRAPPER +#else +# define BOOST_FUNCTION_WRAPPER BOOST_FUNCTION_UNSAFE_WRAPPER +#endif +#define BOOST_FUNCTION_FUNCTION BOOST_JOIN(BOOST_FUNCTION_WRAPPER,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_FUNCTION_INVOKER \ BOOST_JOIN(function_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_VOID_FUNCTION_INVOKER \ @@ -79,6 +88,7 @@ #endif namespace boost { +#if defined(BOOST_FUNCTION_BE_SAFE) namespace detail { namespace function { template< @@ -645,6 +655,10 @@ } // end namespace function } // end namespace detail + template + class BOOST_FUNCTION_UNSAFE_FUNCTION; +#endif // BOOST_FUNCTION_BE_SAFE + template< typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS @@ -749,6 +763,17 @@ this->assign_to_own(f); } + BOOST_FUNCTION_FUNCTION( +#if defined(BOOST_FUNCTION_BE_SAFE) + const BOOST_FUNCTION_UNSAFE_FUNCTION& f +#else + const BOOST_FUNCTION_SAFE_FUNCTION& f +#endif + ) : function_base() + { + this->assign_to_own(f); + } + ~BOOST_FUNCTION_FUNCTION() { clear(); } #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) @@ -756,8 +781,10 @@ // these definitions can become very costly. result_type operator()(BOOST_FUNCTION_PARMS) const { +#if defined(BOOST_FUNCTION_BE_SAFE) if (this->empty()) boost::throw_exception(bad_function_call()); +#endif return get_vtable()->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); @@ -878,7 +905,7 @@ #endif private: - void assign_to_own(const BOOST_FUNCTION_FUNCTION& f) + void assign_to_own(const function_base& f) { if (!f.empty()) { this->vtable = f.vtable; @@ -1006,8 +1033,10 @@ BOOST_FUNCTION_FUNCTION ::operator()(BOOST_FUNCTION_PARMS) const { +#if defined(BOOST_FUNCTION_BE_SAFE) if (this->empty()) boost::throw_exception(bad_function_call()); +#endif return get_vtable()->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); @@ -1040,20 +1069,20 @@ template -class function +class BOOST_FUNCTION_WRAPPER : public BOOST_FUNCTION_FUNCTION { typedef BOOST_FUNCTION_FUNCTION base_type; - typedef function self_type; + typedef BOOST_FUNCTION_WRAPPER self_type; struct clear_type {}; public: - function() : base_type() {} + BOOST_FUNCTION_WRAPPER() : base_type() {} template - function(Functor f + BOOST_FUNCTION_WRAPPER(Functor f #ifndef BOOST_NO_SFINAE ,typename enable_if_c< (boost::type_traits::ice_not< @@ -1065,7 +1094,7 @@ { } template - function(Functor f, Allocator a + BOOST_FUNCTION_WRAPPER(Functor f, Allocator a #ifndef BOOST_NO_SFINAE ,typename enable_if_c< (boost::type_traits::ice_not< @@ -1078,13 +1107,29 @@ } #ifndef BOOST_NO_SFINAE - function(clear_type*) : base_type() {} + BOOST_FUNCTION_WRAPPER(clear_type*) : base_type() {} #endif - function(const self_type& f) : base_type(static_cast(f)){} + BOOST_FUNCTION_WRAPPER(const self_type& f) : base_type(static_cast(f)){} - function(const base_type& f) : base_type(static_cast(f)){} + BOOST_FUNCTION_WRAPPER(const base_type& f) : base_type(static_cast(f)){} +#if defined(BOOST_FUNCTION_BE_SAFE) + BOOST_FUNCTION_WRAPPER(const BOOST_FUNCTION_UNSAFE_WRAPPER& f) + : base_type( + static_cast< + const BOOST_FUNCTION_UNSAFE_FUNCTION& + >(f) + ) {} +#else + BOOST_FUNCTION_WRAPPER(const BOOST_FUNCTION_SAFE_WRAPPER& f) + : base_type( + static_cast< + const BOOST_FUNCTION_SAFE_FUNCTION& + >(f) + ) {} +#endif + self_type& operator=(const self_type& f) { self_type(f).swap(*this); @@ -1119,6 +1164,16 @@ self_type(f).swap(*this); return *this; } + +#if defined(BOOST_FUNCTION_BE_SAFE) + self_type& operator=(const BOOST_FUNCTION_UNSAFE_WRAPPER& f) +#else + self_type& operator=(const BOOST_FUNCTION_SAFE_WRAPPER& f) +#endif + { + self_type(f).swap(*this); + return *this; + } }; #undef BOOST_FUNCTION_PARTIAL_SPEC @@ -1127,6 +1182,11 @@ } // end namespace boost // Cleanup after ourselves... +#undef BOOST_FUNCTION_SAFE_WRAPPER +#undef BOOST_FUNCTION_UNSAFE_WRAPPER +#undef BOOST_FUNCTION_SAFE_FUNCTION +#undef BOOST_FUNCTION_UNSAFE_FUNCTION +#undef BOOST_FUNCTION_WRAPPER #undef BOOST_FUNCTION_VTABLE #undef BOOST_FUNCTION_COMMA #undef BOOST_FUNCTION_FUNCTION Index: boost/function/function_fwd.hpp =================================================================== --- boost/function/function_fwd.hpp (revision 65811) +++ boost/function/function_fwd.hpp (working copy) @@ -37,6 +37,28 @@ { f1.swap(f2); } + + template class unsafe_function; + + template + inline void swap(unsafe_function& f1, unsafe_function& f2) + { + f1.swap(f2); + } + + template + inline void swap(unsafe_function& f1, function& f2) + { + unsafe_function tmp = f1; + f1 = f2; + f2 = tmp; + } + + template + inline void swap(function& f1, unsafe_function& f2) + { + swap(f2, f1); + } #endif // have partial specialization // Portable syntax Index: libs/function/test/Jamfile.v2 =================================================================== --- libs/function/test/Jamfile.v2 (revision 65811) +++ libs/function/test/Jamfile.v2 (working copy) @@ -62,6 +62,10 @@ [ run libs/function/test/nothrow_swap.cpp : : : : ] [ compile libs/function/test/function_typeof_test.cpp ] + + [ run libs/function/test/unsafe_function_cxx98.cpp : : : : ] + + [ run libs/function/test/no_exceptions.cpp : : : : ] ; } Index: libs/function/test/no_exceptions.cpp =================================================================== --- libs/function/test/no_exceptions.cpp (revision 0) +++ libs/function/test/no_exceptions.cpp (revision 0) @@ -0,0 +1,29 @@ +// Boost.Function library +// +// Copyright Daniel Walker 2010. 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) +// +// For more information, see http://www.boost.org/libs/function +// + +// Briefly check that boost::unsafe_function works out-of-the-box +// when Boost exceptions are not available. + +#include + +#define BOOST_NO_EXCEPTIONS +#include + +int f(int x) { return x; } + +int main(int, char*[]) +{ + boost::unsafe_function1 g = &f; + assert(g); + assert(g == &f); + assert(f(0xABCD) == 0xABCD); + assert(g(0xABCD) == 0xABCD); + return 0; +} Index: libs/function/test/unsafe_function_cxx98.cpp =================================================================== --- libs/function/test/unsafe_function_cxx98.cpp (revision 0) +++ libs/function/test/unsafe_function_cxx98.cpp (revision 0) @@ -0,0 +1,113 @@ +// Boost.Function library +// +// Copyright Daniel Walker 2010. 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) +// +// For more information, see http://www.boost.org/libs/function +// + +// Since the same preprocessor boilerplate is used to generate both +// boost::function and boost::unsafe_function, the API tests are +// performed on boost::function and are not duplicated for +// boost::unsafe_function. The only new methods specific to +// boost::unsafe_function are swap, construction and assignment +// with boost::function, which are tested below. + +#include + +#include +#include + +int f(int x) { return x; } + +int test_main(int, char*[]) +{ + // Sanity check: construction, assignment, comparison and + // call-operator. + { + boost::unsafe_function g(&f); + BOOST_REQUIRE(g); + BOOST_REQUIRE(g == &f); + boost::unsafe_function h; + BOOST_REQUIRE(!h); + h = &f; + BOOST_REQUIRE(h); + BOOST_REQUIRE(h == &f); + BOOST_REQUIRE(f(0xABCD) == 0xABCD); + BOOST_REQUIRE(h(0xABCD) == 0xABCD); + } + + // Swap. + { + boost::unsafe_function g, h(&f); + boost::swap(g, h); + BOOST_REQUIRE(!h); + BOOST_REQUIRE(g); + BOOST_REQUIRE(g == &f); + } + + // Construction from boost::function. + { + boost::function g = &f; + boost::unsafe_function h(g); + BOOST_REQUIRE(h == &f); + } + + // Assignment from boost::function. + { + boost::function g = &f; + boost::unsafe_function h; + h = g; + BOOST_REQUIRE(h == &f); + } + + // Construction from boost::unsafe_function. + { + boost::unsafe_function g = &f; + boost::function h(g); + BOOST_REQUIRE(h == &f); + } + + // Assignment from boost::unsafe_function. + { + boost::unsafe_function g = &f; + boost::function h; + h = g; + BOOST_REQUIRE(h == &f); + } + + // Swap with boost::function. + { + boost::function g; + boost::unsafe_function h(&f); + boost::swap(g, h); + BOOST_REQUIRE(!h); + BOOST_REQUIRE(g == &f); + boost::swap(h, g); + BOOST_REQUIRE(!g); + BOOST_REQUIRE(h == &f); + } + + // In unoptimized object code, boost::unsafe_function should have + // less runtime cost than boost::function. + #ifndef NDEBUG + { + int n = INT_MAX/4; + boost::function g = &f; + boost::timer t; + for(int i = 0; i < n; ++i) + g(i); + const double function_cost = t.elapsed(); + + boost::unsafe_function h = g; + t.restart(); + for(int i = 0; i < n; ++i) + h(i); + const double unsafe_function_cost = t.elapsed(); + BOOST_CHECK(unsafe_function_cost <= function_cost*1.1); + } + #endif + return 0; +} Index: libs/function/doc/tutorial.xml =================================================================== --- libs/function/doc/tutorial.xml (revision 65811) +++ libs/function/doc/tutorial.xml (working copy) @@ -159,7 +159,13 @@ Invoking a function object wrapper that does not actually contain a function object is a precondition violation, much like -trying to call through a null function pointer, and will throw a bad_function_call exception). We can check for an +trying to call through a null function +pointer. boost::function will throw +a bad_function_call exception when invoked +with no target. +Alternatively, boost::unsafe_function +has no exception safety guarantee and puts the onus on the user to +check if it is empty prior to attempting a call. We can check for an empty function object wrapper by using it in a boolean context (it evaluates true if the wrapper is not empty) or compare it against 0. For instance: if (f) std::cout << f(5, 3) << std::endl; @@ -360,5 +366,67 @@ +
+ Boost.Function exception safety + Boost.Function provides function object wrappers with two + levels of exception safety. A strong exception safety guarantee is + provided by boost::function, which will + either call the target function or + throw bad_function_call if it has no + target. boost::function + uses boost::throw_exception and can be + further configured via the + Boost Exception Library. + + In circumstances where no exception safety guarantee is + desirable, such as some embedded + systems, boost::unsafe_function + may be used as a direct substitute + for boost::function, with the caveat that the + behavior + of boost::unsafe_function is + undefined when invoked with no target. For example, the following + demonstrates how to + handle boost::function + and boost::unsafe_function + when their preconditions are violated: + + + + + Preferred syntax + Portable syntax + + + + + +boost::function<void ()> f; +boost::unsafe_function<void ()> g; + + +boost::function0<void> f; +boost::unsafe_function0<void> g; + + + + + +try { + f(); // throws bad_function_call +} +catch(boost::bad_function_call e) { + std::cerr << e.what() << std::endl; +} + +if(g) + g(); // undefined behavior +else + std::cerr << "boost::unsafe_function is empty" << std::endl; + + More information about exception safety guarantees in C++ may + be found here.
+ + Index: libs/function/doc/faq.xml =================================================================== --- libs/function/doc/faq.xml (revision 65811) +++ libs/function/doc/faq.xml (working copy) @@ -153,9 +153,17 @@ standard function pointer, differences of order of 10% have been noted to the benefit or disadvantage of using boost::function to call a function that contains a - tight loop depending on your compilation circumstances.
+ tight loop depending on your compilation circumstances.* - [Answer provided by Matt Hurd. See ] + The difference in overhead + between boost::unsafe_function + and boost::function will vary according to the + optimization strategy of your compiler. For example, their + performance is almost the same (within a few hundred + picoseconds) using MSVC Release mode or gcc + -O2. + + [*Answer provided by Matt Hurd. See ] Index: libs/function/doc/reference.xml =================================================================== --- libs/function/doc/reference.xml (revision 65811) +++ libs/function/doc/reference.xml (working copy) @@ -153,7 +153,10 @@ alt="functionN">function0, function1, etc., up to some implementation-defined maximum. In this context, N - refers to the number of parameters. + refers to the number of parameters. The corresponding class + template unsafe_fuctionN + has no exception safety guarantee when invoked with no + target. R @@ -322,7 +325,7 @@ argN_type f(a1, a2, ..., aN), where f is the target of *this. if R is void, nothing is returned; otherwise, the return value of the call to f is returned. - bad_function_call if this->empty(). Otherwise, may through any exception thrown by the target function f. + bad_function_call if this->empty(). Otherwise, may through any exception thrown by the target function f. The behavior of unsafe_functionN is undefined if this->empty(). @@ -558,7 +561,11 @@ function are equivalent to that of the underlying functionN object, although additional member functions are required to allow proper copy - construction and copy assignment of function objects. + construction and copy assignment of function objects. The + corresponding class + template unsafe_fuction + has no exception safety guarantee when invoked with no + target. R @@ -742,7 +749,7 @@ argN_type f(a1, a2, ..., aN), where f is the target of *this. if R is void, nothing is returned; otherwise, the return value of the call to f is returned. - bad_function_call if this->empty(). Otherwise, may through any exception thrown by the target function f. + bad_function_call if this->empty(). Otherwise, may through any exception thrown by the target function f. The behavior of unsafe_function is undefined if this->empty(). Index: libs/function/example/exception_safety.cpp =================================================================== --- libs/function/example/exception_safety.cpp (revision 0) +++ libs/function/example/exception_safety.cpp (revision 0) @@ -0,0 +1,35 @@ +// Boost.Function library example +// +// Copyright Daniel Walker 2010. 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) +// +// For more information, see http://www.boost.org/libs/function +// + +// This example demonstrates how to handle boost::function and +// boost::unsafe_function when their preconditions are violated. + +#include +#include + +int main(int, char*[]) +{ + boost::function f; + boost::unsafe_function g; + + try { + f(); // throws bad_function_call + } + catch(boost::bad_function_call e) { + std::cerr << e.what() << std::endl; + } + + if(g) + g(); // undefined behavior + else + std::cerr << "boost::unsafe_function is empty" << std::endl; + + return 0; +}