]> git.lyx.org Git - lyx.git/blobdiff - boost/boost/function/function_base.hpp
boost: update to version 1.40
[lyx.git] / boost / boost / function / function_base.hpp
index 7165434c0ffe12eb0cba57c2d7e00cdb6ffb2e69..c4663c35a873f168995c4cdf79a2f48e48e668aa 100644 (file)
@@ -1,8 +1,9 @@
 // Boost.Function library
 
-//  Copyright 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
+//  Copyright Douglas Gregor 2001-2006
+//  Copyright Emil Dotchevski 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 <typeinfo>
 #include <boost/config.hpp>
 #include <boost/assert.hpp>
+#include <boost/integer.hpp>
+#include <boost/type_traits/has_trivial_copy.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/type_traits/is_const.hpp>
 #include <boost/type_traits/is_integral.hpp>
+#include <boost/type_traits/is_volatile.hpp>
 #include <boost/type_traits/composite_traits.hpp>
+#include <boost/type_traits/ice.hpp>
 #include <boost/ref.hpp>
 #include <boost/mpl/if.hpp>
 #include <boost/detail/workaround.hpp>
 #  include "boost/mpl/bool.hpp"
 #endif
 #include <boost/function_equal.hpp>
+#include <boost/function/function_fwd.hpp>
+
+#if defined(BOOST_MSVC)
+#   pragma warning( push )
+#   pragma warning( disable : 4793 ) // complaint about native code generation
+#   pragma warning( disable : 4127 ) // "conditional expression is constant"
+#endif       
+
+// Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info.
+#ifdef BOOST_NO_STD_TYPEINFO
+// Embedded VC++ does not have type_info in namespace std
+#  define BOOST_FUNCTION_STD_NS
+#else
+#  define BOOST_FUNCTION_STD_NS std
+#endif
 
 // Borrowed from Boost.Python library: determines the cases where we
 // need to use std::type_info::name to compare instead of operator==.
 #  define BOOST_FUNCTION_TARGET_FIX(x)
 #endif // not MSVC
 
-#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
-// Work around a compiler bug.
-// boost::python::objects::function has to be seen by the compiler before the
-// boost::function class template.
-namespace boost { namespace python { namespace objects {
-  class function;
-}}}
-#endif
-
-#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)                    \
- || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG)                         \
- || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540)
-#  define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX
-#endif
-
-#if !BOOST_WORKAROUND(__BORLANDC__, < 0x600)
+#if !BOOST_WORKAROUND(__BORLANDC__, < 0x5A0)
 #  define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type)              \
       typename ::boost::enable_if_c<(::boost::type_traits::ice_not<          \
                             (::boost::is_integral<Functor>::value)>::value), \
@@ -77,31 +84,6 @@ namespace boost { namespace python { namespace objects {
                        Type>::type
 #endif
 
-#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
-namespace boost {
-
-#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
-// The library shipping with MIPSpro 7.3.1.3m has a broken allocator<void>
-class function_base;
-
-template<typename Signature,
-         typename Allocator = std::allocator<function_base> >
-class function;
-#else
-template<typename Signature, typename Allocator = std::allocator<void> >
-class function;
-#endif
-
-template<typename Signature, typename Allocator>
-inline void swap(function<Signature, Allocator>& f1,
-                 function<Signature, Allocator>& f2)
-{
-  f1.swap(f2);
-}
-
-} // end namespace boost
-#endif // have partial specialization
-
 namespace boost {
   namespace detail {
     namespace function {
@@ -116,11 +98,18 @@ namespace boost {
       union function_buffer
       {
         // For pointers to function objects
-        void* obj_ptr;
+        mutable void* obj_ptr;
 
         // For pointers to std::type_info objects
-        // (get_functor_type_tag, check_functor_type_tag).
-        const void* const_obj_ptr;
+        struct type_t {
+          // (get_functor_type_tag, check_functor_type_tag).
+          const BOOST_FUNCTION_STD_NS::type_info* type;
+
+          // Whether the type is const-qualified.
+          bool const_qualified;
+          // Whether the type is volatile-qualified.
+          bool volatile_qualified;
+        } type;
 
         // For function pointers of all kinds
         mutable void (*func_ptr)();
@@ -131,6 +120,14 @@ namespace boost {
           void* obj_ptr;
         } bound_memfunc_ptr;
 
+        // For references to function objects. We explicitly keep
+        // track of the cv-qualifiers on the object referenced.
+        struct obj_ref_t {
+          mutable void* obj_ptr;
+          bool is_const_qualified;
+          bool is_volatile_qualified;
+        } obj_ref;
+
         // To relax aliasing constraints
         mutable char data;
       };
@@ -162,6 +159,7 @@ namespace boost {
       // The operation type to perform on the given functor/function pointer
       enum functor_manager_operation_type {
         clone_functor_tag,
+        move_functor_tag,
         destroy_functor_tag,
         check_functor_type_tag,
         get_functor_type_tag
@@ -198,34 +196,45 @@ namespace boost {
       struct reference_manager
       {
         static inline void
-        get(const function_buffer& in_buffer, function_buffer& out_buffer, 
-            functor_manager_operation_type op)
+        manage(const function_buffer& in_buffer, function_buffer& out_buffer, 
+               functor_manager_operation_type op)
         {
           switch (op) {
           case clone_functor_tag: 
-            out_buffer.obj_ptr = in_buffer.obj_ptr;
+            out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
+            return;
+
+          case move_functor_tag:
+            out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
+            in_buffer.obj_ref.obj_ptr = 0;
             return;
 
           case destroy_functor_tag:
-            out_buffer.obj_ptr = 0;
+            out_buffer.obj_ref.obj_ptr = 0;
             return;
 
           case check_functor_type_tag:
             {
-              // DPG TBD: Since we're only storing a pointer, it's
-              // possible that the user could ask for a base class or
-              // derived class. Is that okay?
-              const std::type_info& check_type = 
-                *static_cast<const std::type_info*>(out_buffer.const_obj_ptr);
-              if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F)))
-                out_buffer.obj_ptr = in_buffer.obj_ptr;
+              const BOOST_FUNCTION_STD_NS::type_info& check_type 
+                = *out_buffer.type.type;
+
+              // Check whether we have the same type. We can add
+              // cv-qualifiers, but we can't take them away.
+              if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))
+                  && (!in_buffer.obj_ref.is_const_qualified 
+                      || out_buffer.type.const_qualified)
+                  && (!in_buffer.obj_ref.is_volatile_qualified
+                      || out_buffer.type.volatile_qualified))
+                out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
               else
                 out_buffer.obj_ptr = 0;
             }
             return;
 
           case get_functor_type_tag:
-            out_buffer.const_obj_ptr = &typeid(F);
+            out_buffer.type.type = &typeid(F);
+            out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified;
+            out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified;
             return;
           }
         }
@@ -245,115 +254,254 @@ namespace boost {
                       % alignment_of<F>::value == 0))));
       };
 
+      template <typename F,typename A>
+      struct functor_wrapper: public F, public A
+      {
+        functor_wrapper( F f, A a ):
+          F(f),
+          A(a)
+        {
+        }
+       
+       functor_wrapper(const functor_wrapper& f) :
+          F(static_cast<const F&>(f)),
+          A(static_cast<const A&>(f))
+       {
+       }
+      };
+
       /**
        * The functor_manager class contains a static function "manage" which
        * can clone or destroy the given function/function object pointer.
        */
-      template<typename Functor, typename Allocator>
-      struct functor_manager
+      template<typename Functor>
+      struct functor_manager_common
       {
-      private:
         typedef Functor functor_type;
 
-        // For function pointers, the manager is trivial
+        // Function pointers
         static inline void
-        manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
-                functor_manager_operation_type op, function_ptr_tag)
+        manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer, 
+                functor_manager_operation_type op)
         {
           if (op == clone_functor_tag)
             out_buffer.func_ptr = in_buffer.func_ptr;
-          else if (op == destroy_functor_tag)
+          else if (op == move_functor_tag) {
+            out_buffer.func_ptr = in_buffer.func_ptr;
+            in_buffer.func_ptr = 0;
+          } else if (op == destroy_functor_tag)
             out_buffer.func_ptr = 0;
-          else /* op == check_functor_type_tag */ {
-            const std::type_info& check_type = 
-              *static_cast<const std::type_info*>(out_buffer.const_obj_ptr);
+          else if (op == check_functor_type_tag) {
+            const BOOST_FUNCTION_STD_NS::type_info& check_type 
+              = *out_buffer.type.type;
             if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
               out_buffer.obj_ptr = &in_buffer.func_ptr;
             else
               out_buffer.obj_ptr = 0;
+          } else /* op == get_functor_type_tag */ {
+            out_buffer.type.type = &typeid(Functor);
+            out_buffer.type.const_qualified = false;
+            out_buffer.type.volatile_qualified = false;
           }
         }
 
         // Function objects that fit in the small-object buffer.
         static inline void
-        manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
-                functor_manager_operation_type op, mpl::true_)
+        manage_small(const function_buffer& in_buffer, function_buffer& out_buffer, 
+                functor_manager_operation_type op)
         {
-          if (op == clone_functor_tag) {
+          if (op == clone_functor_tag || op == move_functor_tag) {
             const functor_type* in_functor = 
               reinterpret_cast<const functor_type*>(&in_buffer.data);
             new ((void*)&out_buffer.data) functor_type(*in_functor);
+
+            if (op == move_functor_tag) {
+              reinterpret_cast<functor_type*>(&in_buffer.data)->~Functor();
+            }
           } else if (op == destroy_functor_tag) {
             // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
             reinterpret_cast<functor_type*>(&out_buffer.data)->~Functor();
-          } else /* op == check_functor_type_tag */ {
-            const std::type_info& check_type = 
-              *static_cast<const std::type_info*>(out_buffer.const_obj_ptr);
+          } else if (op == check_functor_type_tag) {
+            const BOOST_FUNCTION_STD_NS::type_info& check_type 
+              = *out_buffer.type.type;
             if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
               out_buffer.obj_ptr = &in_buffer.data;
             else
               out_buffer.obj_ptr = 0;
+          } else /* op == get_functor_type_tag */ {
+            out_buffer.type.type = &typeid(Functor);
+            out_buffer.type.const_qualified = false;
+            out_buffer.type.volatile_qualified = false;            
           }
         }
+      };
+
+      template<typename Functor>
+      struct functor_manager
+      {
+      private:
+        typedef Functor functor_type;
+
+        // Function pointers
+        static inline void
+        manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
+                functor_manager_operation_type op, function_ptr_tag)
+        {
+          functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
+        }
+
+        // Function objects that fit in the small-object buffer.
+        static inline void
+        manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
+                functor_manager_operation_type op, mpl::true_)
+        {
+          functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
+        }
         
         // Function objects that require heap allocation
         static inline void
         manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
                 functor_manager_operation_type op, mpl::false_)
         {
-#ifndef BOOST_NO_STD_ALLOCATOR
-          typedef typename Allocator::template rebind<functor_type>::other
-            allocator_type;
-          typedef typename allocator_type::pointer pointer_type;
-#else
-          typedef functor_type* pointer_type;
-#endif // BOOST_NO_STD_ALLOCATOR
-
-#  ifndef BOOST_NO_STD_ALLOCATOR
-          allocator_type allocator;
-#  endif // BOOST_NO_STD_ALLOCATOR
-
           if (op == clone_functor_tag) {
+            // Clone the functor
             // GCC 2.95.3 gets the CV qualifiers wrong here, so we
             // can't do the static_cast that we should do.
             const functor_type* f =
               (const functor_type*)(in_buffer.obj_ptr);
-
-            // Clone the functor
-#  ifndef BOOST_NO_STD_ALLOCATOR
-            pointer_type copy = allocator.allocate(1);
-            allocator.construct(copy, *f);
-
-            // Get back to the original pointer type
-            functor_type* new_f = static_cast<functor_type*>(copy);
-#  else
             functor_type* new_f = new functor_type(*f);
-#  endif // BOOST_NO_STD_ALLOCATOR
             out_buffer.obj_ptr = new_f;
+          } else if (op == move_functor_tag) {
+            out_buffer.obj_ptr = in_buffer.obj_ptr;
+            in_buffer.obj_ptr = 0;
           } else if (op == destroy_functor_tag) {
             /* Cast from the void pointer to the functor pointer type */
             functor_type* f =
               static_cast<functor_type*>(out_buffer.obj_ptr);
+            delete f;
+            out_buffer.obj_ptr = 0;
+          } else if (op == check_functor_type_tag) {
+            const BOOST_FUNCTION_STD_NS::type_info& check_type
+              = *out_buffer.type.type;
+            if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
+              out_buffer.obj_ptr = in_buffer.obj_ptr;
+            else
+              out_buffer.obj_ptr = 0;
+          } else /* op == get_functor_type_tag */ {
+            out_buffer.type.type = &typeid(Functor);
+            out_buffer.type.const_qualified = false;
+            out_buffer.type.volatile_qualified = false;
+          }
+        }
 
-#  ifndef BOOST_NO_STD_ALLOCATOR
-            /* Cast from the functor pointer type to the allocator's pointer
-               type */
-            pointer_type victim = static_cast<pointer_type>(f);
+        // For function objects, we determine whether the function
+        // object can use the small-object optimization buffer or
+        // whether we need to allocate it on the heap.
+        static inline void
+        manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
+                functor_manager_operation_type op, function_obj_tag)
+        {
+          manager(in_buffer, out_buffer, op,
+                  mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
+        }
 
-            // Destroy and deallocate the functor
-            allocator.destroy(victim);
-            allocator.deallocate(victim, 1);
-#  else
-            delete f;
-#  endif // BOOST_NO_STD_ALLOCATOR
+        // For member pointers, we use the small-object optimization buffer.
+        static inline void
+        manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
+                functor_manager_operation_type op, member_ptr_tag)
+        {
+          manager(in_buffer, out_buffer, op, mpl::true_());
+        }
+
+      public:
+        /* Dispatch to an appropriate manager based on whether we have a
+           function pointer or a function object pointer. */
+        static inline void
+        manage(const function_buffer& in_buffer, function_buffer& out_buffer, 
+               functor_manager_operation_type op)
+        {
+          typedef typename get_function_tag<functor_type>::type tag_type;
+          switch (op) {
+          case get_functor_type_tag:
+            out_buffer.type.type = &typeid(functor_type);
+            out_buffer.type.const_qualified = false;
+            out_buffer.type.volatile_qualified = false;
+            return;
+
+          default:
+            manager(in_buffer, out_buffer, op, tag_type());
+            return;
+          }
+        }
+      };
+
+      template<typename Functor, typename Allocator>
+      struct functor_manager_a
+      {
+      private:
+        typedef Functor functor_type;
+
+        // Function pointers
+        static inline void
+        manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
+                functor_manager_operation_type op, function_ptr_tag)
+        {
+          functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
+        }
+
+        // Function objects that fit in the small-object buffer.
+        static inline void
+        manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
+                functor_manager_operation_type op, mpl::true_)
+        {
+          functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
+        }
+        
+        // Function objects that require heap allocation
+        static inline void
+        manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
+                functor_manager_operation_type op, mpl::false_)
+        {
+          typedef functor_wrapper<Functor,Allocator> functor_wrapper_type;
+          typedef typename Allocator::template rebind<functor_wrapper_type>::other
+            wrapper_allocator_type;
+          typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type;
+
+          if (op == clone_functor_tag) {
+            // Clone the functor
+            // GCC 2.95.3 gets the CV qualifiers wrong here, so we
+            // can't do the static_cast that we should do.
+            const functor_wrapper_type* f =
+              (const functor_wrapper_type*)(in_buffer.obj_ptr);
+            wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
+            wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
+            wrapper_allocator.construct(copy, *f);
+
+            // Get back to the original pointer type
+            functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
+            out_buffer.obj_ptr = new_f;
+          } else if (op == move_functor_tag) {
+            out_buffer.obj_ptr = in_buffer.obj_ptr;
+            in_buffer.obj_ptr = 0;
+          } else if (op == destroy_functor_tag) {
+            /* Cast from the void pointer to the functor_wrapper_type */
+            functor_wrapper_type* victim =
+              static_cast<functor_wrapper_type*>(in_buffer.obj_ptr);
+            wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
+            wrapper_allocator.destroy(victim);
+            wrapper_allocator.deallocate(victim,1);
             out_buffer.obj_ptr = 0;
-          } else /* op == check_functor_type_tag */ {
-            const std::type_info& check_type = 
-              *static_cast<const std::type_info*>(out_buffer.const_obj_ptr);
+          } else if (op == check_functor_type_tag) {
+            const BOOST_FUNCTION_STD_NS::type_info& check_type 
+              = *out_buffer.type.type;
             if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
               out_buffer.obj_ptr = in_buffer.obj_ptr;
             else
               out_buffer.obj_ptr = 0;
+          } else /* op == get_functor_type_tag */ {
+            out_buffer.type.type = &typeid(Functor);
+            out_buffer.type.const_qualified = false;
+            out_buffer.type.volatile_qualified = false;
           }
         }
 
@@ -378,7 +526,9 @@ namespace boost {
           typedef typename get_function_tag<functor_type>::type tag_type;
           switch (op) {
           case get_functor_type_tag:
-            out_buffer.const_obj_ptr = &typeid(functor_type);
+            out_buffer.type.type = &typeid(functor_type);
+            out_buffer.type.const_qualified = false;
+            out_buffer.type.volatile_qualified = false;
             return;
 
           default:
@@ -456,7 +606,6 @@ namespace boost {
        */
       struct vtable_base
       {
-        vtable_base() : manager(0) { }
         void (*manager)(const function_buffer& in_buffer, 
                         function_buffer& out_buffer, 
                         functor_manager_operation_type op);
@@ -480,13 +629,13 @@ public:
 
   /** Retrieve the type of the stored function object, or typeid(void)
       if this is empty. */
-  const std::type_info& target_type() const
+  const BOOST_FUNCTION_STD_NS::type_info& target_type() const
   {
     if (!vtable) return typeid(void);
 
     detail::function::function_buffer type;
-    vtable->manager(functor, type, detail::function::get_functor_type_tag);
-    return *static_cast<const std::type_info*>(type.const_obj_ptr);
+    get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
+    return *type.type.type;
   }
 
   template<typename Functor>
@@ -495,8 +644,10 @@ public:
       if (!vtable) return 0;
 
       detail::function::function_buffer type_result;
-      type_result.const_obj_ptr = &typeid(Functor);
-      vtable->manager(functor, type_result, 
+      type_result.type.type = &typeid(Functor);
+      type_result.type.const_qualified = is_const<Functor>::value;
+      type_result.type.volatile_qualified = is_volatile<Functor>::value;
+      get_vtable()->manager(functor, type_result, 
                       detail::function::check_functor_type_tag);
       return static_cast<Functor*>(type_result.obj_ptr);
     }
@@ -511,8 +662,10 @@ public:
       if (!vtable) return 0;
 
       detail::function::function_buffer type_result;
-      type_result.const_obj_ptr = &typeid(Functor);
-      vtable->manager(functor, type_result, 
+      type_result.type.type = &typeid(Functor);
+      type_result.type.const_qualified = true;
+      type_result.type.volatile_qualified = is_volatile<Functor>::value;
+      get_vtable()->manager(functor, type_result, 
                       detail::function::check_functor_type_tag);
       // GCC 2.95.3 gets the CV qualifiers wrong here, so we
       // can't do the static_cast that we should do.
@@ -558,6 +711,15 @@ public:
 #endif
 
 public: // should be protected, but GCC 2.95.3 will fail to allow access
+  detail::function::vtable_base* get_vtable() const {
+    return reinterpret_cast<detail::function::vtable_base*>(
+             reinterpret_cast<std::size_t>(vtable) & ~(std::size_t)0x01);
+  }
+
+  bool has_trivial_copy_and_destroy() const {
+    return reinterpret_cast<std::size_t>(vtable) & 0x01;
+  }
+
   detail::function::vtable_base* vtable;
   mutable detail::function::function_buffer functor;
 };
@@ -733,4 +895,8 @@ namespace detail {
 #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
 #undef BOOST_FUNCTION_COMPARE_TYPE_ID
 
+#if defined(BOOST_MSVC)
+#   pragma warning( pop )
+#endif       
+
 #endif // BOOST_FUNCTION_BASE_HEADER