Ticket #1910: moving_function_swap.patch

File moving_function_swap.patch, 7.7 KB (added by niels_dekker, 14 years ago)
  • function_base.hpp

     
    122122      union function_buffer
    123123      {
    124124        // For pointers to function objects
    125         void* obj_ptr;
     125        mutable void* obj_ptr;
    126126
    127127        // For pointers to std::type_info objects
    128128        // (get_functor_type_tag, check_functor_type_tag).
     
    203203      template<typename F>
    204204      struct reference_manager
    205205      {
     206        // Note: the 4th argument (bool) would specify whether to move the buffer,
     207        // but this is irrelevant in this case.
    206208        static inline void
    207209        get(const function_buffer& in_buffer, function_buffer& out_buffer,
    208             functor_manager_operation_type op)
     210            functor_manager_operation_type op, bool)
    209211        {
    210212          switch (op) {
    211213          case clone_functor_tag:
     
    319321        typedef Functor functor_type;
    320322
    321323        // Function pointers
     324        // Note: the 5th argument (bool) would specify whether to move the buffer,
     325        // but this is irrelevant for function pointers.
    322326        static inline void
    323327        manager(const function_buffer& in_buffer, function_buffer& out_buffer,
    324                 functor_manager_operation_type op, function_ptr_tag)
     328                functor_manager_operation_type op, function_ptr_tag, bool)
    325329        {
    326330          functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
    327331        }
    328332
    329333        // Function objects that fit in the small-object buffer.
     334        // Note: the 5th argument (bool) would specify whether to move the buffer,
     335        // but this is irrelevant when the small-object buffer is used.
    330336        static inline void
    331337        manager(const function_buffer& in_buffer, function_buffer& out_buffer,
    332                 functor_manager_operation_type op, mpl::true_)
     338                functor_manager_operation_type op, mpl::true_, bool)
    333339        {
    334340          functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
    335341        }
     
    337343        // Function objects that require heap allocation
    338344        static inline void
    339345        manager(const function_buffer& in_buffer, function_buffer& out_buffer,
    340                 functor_manager_operation_type op, mpl::false_)
     346                functor_manager_operation_type op, mpl::false_, bool move_buffer)
    341347        {
    342348          if (op == clone_functor_tag) {
    343             // Clone the functor
    344             // GCC 2.95.3 gets the CV qualifiers wrong here, so we
    345             // can't do the static_cast that we should do.
    346             const functor_type* f =
    347               (const functor_type*)(in_buffer.obj_ptr);
    348             functor_type* new_f = new functor_type(*f);
    349             out_buffer.obj_ptr = new_f;
     349            if (move_buffer)
     350            {
     351              out_buffer.obj_ptr = in_buffer.obj_ptr;
     352              in_buffer.obj_ptr = 0;
     353            }
     354            else
     355            {
     356              // Clone the functor
     357              // GCC 2.95.3 gets the CV qualifiers wrong here, so we
     358              // can't do the static_cast that we should do.
     359              const functor_type* f =
     360                (const functor_type*)(in_buffer.obj_ptr);
     361              functor_type* new_f = new functor_type(*f);
     362              out_buffer.obj_ptr = new_f;
     363            }
    350364          } else if (op == destroy_functor_tag) {
    351365            /* Cast from the void pointer to the functor pointer type */
    352366            functor_type* f =
     
    368382        // whether we need to allocate it on the heap.
    369383        static inline void
    370384        manager(const function_buffer& in_buffer, function_buffer& out_buffer,
    371                 functor_manager_operation_type op, function_obj_tag)
     385                functor_manager_operation_type op, function_obj_tag, bool move_buffer)
    372386        {
    373387          manager(in_buffer, out_buffer, op,
    374                   mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
     388                  mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>(), move_buffer);
    375389        }
    376390
    377391      public:
     
    379393           function pointer or a function object pointer. */
    380394        static inline void
    381395        manage(const function_buffer& in_buffer, function_buffer& out_buffer,
    382                functor_manager_operation_type op)
     396               functor_manager_operation_type op, bool move_buffer)
    383397        {
    384398          typedef typename get_function_tag<functor_type>::type tag_type;
    385399          switch (op) {
     
    388402            return;
    389403
    390404          default:
    391             manager(in_buffer, out_buffer, op, tag_type());
     405            manager(in_buffer, out_buffer, op, tag_type(), move_buffer);
    392406            return;
    393407          }
    394408        }
     
    403417        // Function pointers
    404418        static inline void
    405419        manager(const function_buffer& in_buffer, function_buffer& out_buffer,
    406                 functor_manager_operation_type op, function_ptr_tag)
     420                functor_manager_operation_type op, function_ptr_tag, bool move_buffer)
    407421        {
    408422          functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
    409423        }
     
    559573        vtable_base() : manager(0) { }
    560574        void (*manager)(const function_buffer& in_buffer,
    561575                        function_buffer& out_buffer,
    562                         functor_manager_operation_type op);
     576                        functor_manager_operation_type op,
     577                        bool move_buffer);
    563578      };
    564579    } // end namespace function
    565580  } // end namespace detail
     
    585600    if (!vtable) return typeid(void);
    586601
    587602    detail::function::function_buffer type;
    588     vtable->manager(functor, type, detail::function::get_functor_type_tag);
     603    vtable->manager(functor, type, detail::function::get_functor_type_tag, false);
    589604    return *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(type.const_obj_ptr);
    590605  }
    591606
  • function_template.hpp

     
    286286        void clear(function_buffer& functor)
    287287        {
    288288          if (manager)
    289             manager(functor, functor, destroy_functor_tag);
     289            manager(functor, functor, destroy_functor_tag, false);
    290290        }
    291291
    292292      private:
     
    729729      if (&other == this)
    730730        return;
    731731
    732       BOOST_FUNCTION_FUNCTION tmp = *this;
    733       *this = other;
    734       other = tmp;
     732      BOOST_FUNCTION_FUNCTION tmp;
     733      tmp.move_assign(*this);
     734      this->move_assign(other);
     735      other.move_assign(tmp);
    735736    }
    736737
    737738    // Clear out a target, if there is one
     
    768769      if (!f.empty()) {
    769770        this->vtable = f.vtable;
    770771        f.vtable->manager(f.functor, this->functor,
    771                           boost::detail::function::clone_functor_tag);
     772                          boost::detail::function::clone_functor_tag, false);
    772773      }
    773774    }
    774775
     776    // Moves the value from the specified argument to *this. If the argument
     777    // has its function object allocated on the heap, move_assign will pass
     778    // its buffer to *this, and set the argument's buffer pointer to NULL.
     779    void move_assign(BOOST_FUNCTION_FUNCTION& f)
     780    {
     781      if (&f == this)
     782        return;
     783
     784      clear();
     785      try {
     786        if (!f.empty()) {
     787          this->vtable = f.vtable;
     788          f.vtable->manager(f.functor, this->functor,
     789                            boost::detail::function::clone_functor_tag, true);
     790        }
     791      } catch (...) {
     792        vtable = 0;
     793        throw;
     794      }
     795    }
     796
    775797    template<typename Functor>
    776798    void assign_to(Functor f)
    777799    {