Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r58436 - sandbox/function/boost/function
From: dsaritz_at_[hidden]
Date: 2009-12-17 12:01:39


Author: psiha
Date: 2009-12-17 12:01:39 EST (Thu, 17 Dec 2009)
New Revision: 58436
URL: http://svn.boost.org/trac/boost/changeset/58436

Log:
Changed the vtable::invoker_placeholder_type type/signature to be a function_buffer (instead of a function_buffer_holder) member function. This allowed for simpler/more readable BOOST_FUNCTION_FUNCTION::invoke() member function overloads and is legal as unions are allowed to have member functions by the standard.

Fixed the BOOST_FUNCTION_FUNCTION::vtable_for_functor<>() member function overloads to no longer use SFINAE and to disallow incorrect assignement and/or construction from objects of boost::function<> instances with different signatures (this now correctly causes a compile-time error).

Updated related comments.
Minor other stylistic changes.
Text files modified:
   sandbox/function/boost/function/function_base.hpp | 7 +++
   sandbox/function/boost/function/function_template.hpp | 79 ++++++++++++++++++++-------------------
   2 files changed, 47 insertions(+), 39 deletions(-)

Modified: sandbox/function/boost/function/function_base.hpp
==============================================================================
--- sandbox/function/boost/function/function_base.hpp (original)
+++ sandbox/function/boost/function/function_base.hpp 2009-12-17 12:01:39 EST (Thu, 17 Dec 2009)
@@ -873,9 +873,14 @@
       // that it can (more easily) be placed at the beginning of the vtable so
       // that a vtable pointer would actually point directly to it (thus
       // avoiding pointer offset calculation on invocation).
+ // This also gives a unique/non-template vtable that can be held by
+ // function_base entirely but it also opens a window for erroneous vtable
+ // copying/assignment between different boost::function<> instantiations.
+ // A typed wrapper should therefor be added to the boost::function<>
+ // class to catch such errors at compile-time.
       struct vtable
       {
- typedef void ( function_buffer_holder::* invoker_placeholder_type )( void );
+ typedef void ( function_buffer::* invoker_placeholder_type )( void );
         template<typename TargetInvokerType>
         TargetInvokerType const & invoker() const { return reinterpret_cast<TargetInvokerType const &>( void_invoker ); }
 

Modified: sandbox/function/boost/function/function_template.hpp
==============================================================================
--- sandbox/function/boost/function/function_template.hpp (original)
+++ sandbox/function/boost/function/function_template.hpp 2009-12-17 12:01:39 EST (Thu, 17 Dec 2009)
@@ -73,32 +73,32 @@
         typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS
>
      struct BOOST_FUNCTION_FUNCTION_OBJ_INVOKER : public function_buffer_holder
- {
- R invoke( BOOST_FUNCTION_PARMS )
- {
- // We provide the invoker with a manager with a minimum amount of
- // type information (because it already knows the stored function
- // object it works with, it only needs to get its address from a
- // function_buffer object). Because of this we must cast the pointer
- // returned by FunctionObjManager::functor_ptr() because it can be
- // a plain void * in case of the trivial managers. In case of the
- // trivial ptr manager it is even a void * * so a double static_cast
- // (or a reinterpret_cast) is necessary.
- FunctionObj & functionObject
- (
- *static_cast<FunctionObj *>
- (
- static_cast<void *>
- (
- FunctionObjManager::functor_ptr( buffer )
- )
- )
- );
- // unwrap_ref is needed because boost::reference_wrapper<T>, unlike
- // the one from std::tr1, does not support callable objects
- return unwrap_ref( functionObject )( BOOST_FUNCTION_ARGS );
- }
- };
+ {
+ R invoke( BOOST_FUNCTION_PARMS )
+ {
+ // We provide the invoker with a manager with a minimum amount of
+ // type information (because it already knows the stored function
+ // object it works with, it only needs to get its address from a
+ // function_buffer object). Because of this we must cast the pointer
+ // returned by FunctionObjManager::functor_ptr() because it can be
+ // a plain void * in case of the trivial managers. In case of the
+ // trivial ptr manager it is even a void * * so a double static_cast
+ // (or a reinterpret_cast) is necessary.
+ FunctionObj & functionObject
+ (
+ *static_cast<FunctionObj *>
+ (
+ static_cast<void *>
+ (
+ FunctionObjManager::functor_ptr( buffer )
+ )
+ )
+ );
+ // unwrap_ref is needed because boost::reference_wrapper<T>, unlike
+ // the one from std::tr1, does not support callable objects
+ return unwrap_ref( functionObject )( BOOST_FUNCTION_ARGS );
+ }
+ };
 
       template
       <
@@ -449,29 +449,32 @@
         throw()
     #endif
     {
- typedef result_type (detail::function::function_buffer_holder::* invoker_type)(BOOST_FUNCTION_TEMPLATE_ARGS);
- return (reinterpret_cast<detail::function::function_buffer_holder &>( this->functor ).*get_vtable().invoker<invoker_type>())
- (BOOST_FUNCTION_ARGS);
+ typedef result_type (detail::function::function_buffer::* invoker_type)(BOOST_FUNCTION_TEMPLATE_ARGS);
+ return (functor.*(get_vtable().invoker<invoker_type>()))(BOOST_FUNCTION_ARGS);
     }
 
     result_type invoke(BOOST_FUNCTION_PARMS BOOST_FUNCTION_COMMA mpl::false_ /*throwable invoker*/) const
     {
- typedef result_type (detail::function::function_buffer_holder::* invoker_type)(BOOST_FUNCTION_TEMPLATE_ARGS);
- return (reinterpret_cast<detail::function::function_buffer_holder &>( this->functor ).*get_vtable().invoker<invoker_type>())
- (BOOST_FUNCTION_ARGS);
+ typedef result_type (detail::function::function_buffer::* invoker_type)(BOOST_FUNCTION_TEMPLATE_ARGS);
+ return (functor.*(get_vtable().invoker<invoker_type>()))(BOOST_FUNCTION_ARGS);
     }
 
- template <typename ActualFunctor, typename StoredFunctor>
- typename enable_if<is_base_of<function_base, StoredFunctor>, vtable_type const &>::type
- static vtable_for_functor( StoredFunctor const & functor )
+ // This overload should not actually be for a 'complete' BOOST_FUNCTION_FUNCTION as it is enough
+ // for the signature template parameter to be the same (and therefor the vtable is the same, with
+ // a possibly exception being the case of an empty source as empty handler vtables depend on the
+ // policy as well as the signature).
+ template <typename ActualFunctor>
+ static vtable_type const & vtable_for_functor( BOOST_FUNCTION_FUNCTION const & functor )
     {
- return functor.get_vtable();
+ BOOST_STATIC_ASSERT(( is_same<ActualFunctor, BOOST_FUNCTION_FUNCTION>::value ));
+ return functor.get_vtable();
     }
 
     template <typename ActualFunctor, typename StoredFunctor>
- typename disable_if<is_base_of<function_base, StoredFunctor>, vtable_type const &>::type
- static vtable_for_functor( StoredFunctor const & /*functor*/ )
+ static vtable_type const & vtable_for_functor( StoredFunctor const & /*functor*/ )
     {
+ BOOST_STATIC_ASSERT(( !is_same<StoredFunctor, BOOST_FUNCTION_FUNCTION>::value ));
+
       using namespace detail::function;
 
       // A minimally typed manager is used for the invoker (anti-code-bloat).


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk