source: NonGTP/Boost/boost/function/function_base.hpp @ 857

Revision 857, 22.6 KB checked in by igarcia, 18 years ago (diff)
Line 
1// Boost.Function library
2
3//  Copyright Douglas Gregor 2001-2004. Use, modification and
4//  distribution is subject to the Boost Software License, Version
5//  1.0. (See accompanying file LICENSE_1_0.txt or copy at
6//  http://www.boost.org/LICENSE_1_0.txt)
7
8// For more information, see http://www.boost.org
9
10#ifndef BOOST_FUNCTION_BASE_HEADER
11#define BOOST_FUNCTION_BASE_HEADER
12
13#include <stdexcept>
14#include <string>
15#include <memory>
16#include <new>
17#include <typeinfo>
18#include <boost/config.hpp>
19#include <boost/assert.hpp>
20#include <boost/type_traits/is_integral.hpp>
21#include <boost/type_traits/composite_traits.hpp>
22#include <boost/type_traits/is_stateless.hpp>
23#include <boost/ref.hpp>
24#include <boost/pending/ct_if.hpp>
25#include <boost/detail/workaround.hpp>
26#ifndef BOOST_NO_SFINAE
27#  include "boost/utility/enable_if.hpp"
28#else
29#  include "boost/mpl/bool.hpp"
30#endif
31#include <boost/function_equal.hpp>
32
33// Borrowed from Boost.Python library: determines the cases where we
34// need to use std::type_info::name to compare instead of operator==.
35# if (defined(__GNUC__) && __GNUC__ >= 3) \
36 || defined(_AIX) \
37 || (   defined(__sgi) && defined(__host_mips))
38#  include <cstring>
39#  define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \
40     (std::strcmp((X).name(),(Y).name()) == 0)
41# else
42#  define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
43#endif
44
45#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG)
46#  define BOOST_FUNCTION_TARGET_FIX(x) x
47#else
48#  define BOOST_FUNCTION_TARGET_FIX(x)
49#endif // not MSVC
50
51#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
52// Work around a compiler bug.
53// boost::python::objects::function has to be seen by the compiler before the
54// boost::function class template.
55namespace boost { namespace python { namespace objects {
56  class function;
57}}}
58#endif
59
60#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)                    \
61 || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG)                         \
62 || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540)
63#  define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX
64#endif
65
66#if !BOOST_WORKAROUND(__BORLANDC__, < 0x600)
67#  define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type)              \
68      typename ::boost::enable_if_c<(::boost::type_traits::ice_not<          \
69                            (::boost::is_integral<Functor>::value)>::value), \
70                           Type>::type
71#else
72// BCC doesn't recognize this depends on a template argument and complains
73// about the use of 'typename'
74#  define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type)     \
75      ::boost::enable_if_c<(::boost::type_traits::ice_not<          \
76                   (::boost::is_integral<Functor>::value)>::value), \
77                       Type>::type
78#endif
79
80#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
81namespace boost {
82
83#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
84// The library shipping with MIPSpro 7.3.1.3m has a broken allocator<void>
85class function_base;
86
87template<typename Signature,
88         typename Allocator = std::allocator<function_base> >
89class function;
90#else
91template<typename Signature, typename Allocator = std::allocator<void> >
92class function;
93#endif
94
95template<typename Signature, typename Allocator>
96inline void swap(function<Signature, Allocator>& f1,
97                 function<Signature, Allocator>& f2)
98{
99  f1.swap(f2);
100}
101
102} // end namespace boost
103#endif // have partial specialization
104
105namespace boost {
106  namespace detail {
107    namespace function {
108      /**
109       * A union of a function pointer and a void pointer. This is necessary
110       * because 5.2.10/6 allows reinterpret_cast<> to safely cast between
111       * function pointer types and 5.2.9/10 allows static_cast<> to safely
112       * cast between a void pointer and an object pointer. But it is not legal
113       * to cast between a function pointer and a void* (in either direction),
114       * so function requires a union of the two. */
115      union any_pointer
116      {
117        void* obj_ptr;
118        const void* const_obj_ptr;
119        void (*func_ptr)();
120        char data[1];
121      };
122
123      inline any_pointer make_any_pointer(void* o)
124      {
125        any_pointer p;
126        p.obj_ptr = o;
127        return p;
128      }
129
130      inline any_pointer make_any_pointer(const void* o)
131      {
132        any_pointer p;
133        p.const_obj_ptr = o;
134        return p;
135      }
136
137      inline any_pointer make_any_pointer(void (*f)())
138      {
139        any_pointer p;
140        p.func_ptr = f;
141        return p;
142      }
143
144      /**
145       * The unusable class is a placeholder for unused function arguments
146       * It is also completely unusable except that it constructable from
147       * anything. This helps compilers without partial specialization to
148       * handle Boost.Function objects returning void.
149       */
150      struct unusable
151      {
152        unusable() {}
153        template<typename T> unusable(const T&) {}
154      };
155
156      /* Determine the return type. This supports compilers that do not support
157       * void returns or partial specialization by silently changing the return
158       * type to "unusable".
159       */
160      template<typename T> struct function_return_type { typedef T type; };
161
162      template<>
163      struct function_return_type<void>
164      {
165        typedef unusable type;
166      };
167
168      // The operation type to perform on the given functor/function pointer
169      enum functor_manager_operation_type {
170        clone_functor_tag,
171        destroy_functor_tag,
172        check_functor_type_tag
173      };
174
175      // Tags used to decide between different types of functions
176      struct function_ptr_tag {};
177      struct function_obj_tag {};
178      struct member_ptr_tag {};
179      struct function_obj_ref_tag {};
180      struct stateless_function_obj_tag {};
181
182      template<typename F>
183      class get_function_tag
184      {
185        typedef typename ct_if<(is_pointer<F>::value),
186                            function_ptr_tag,
187                            function_obj_tag>::type ptr_or_obj_tag;
188
189        typedef typename ct_if<(is_member_pointer<F>::value),
190                            member_ptr_tag,
191                            ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
192
193        typedef typename ct_if<(is_reference_wrapper<F>::value),
194                             function_obj_ref_tag,
195                             ptr_or_obj_or_mem_tag>::type or_ref_tag;
196
197      public:
198        typedef typename ct_if<(is_stateless<F>::value),
199                            stateless_function_obj_tag,
200                            or_ref_tag>::type type;
201      };
202
203      // The trivial manager does nothing but return the same pointer (if we
204      // are cloning) or return the null pointer (if we are deleting).
205      template<typename F>
206      struct trivial_manager
207      {
208        static inline any_pointer
209        get(any_pointer f, functor_manager_operation_type op)
210        {
211          switch (op) {
212          case clone_functor_tag: return f;
213
214          case destroy_functor_tag:
215            return make_any_pointer(reinterpret_cast<void*>(0));
216
217          case check_functor_type_tag:
218            {
219              std::type_info* t = static_cast<std::type_info*>(f.obj_ptr);
220              return BOOST_FUNCTION_COMPARE_TYPE_ID(typeid(F), *t)?
221                f
222                : make_any_pointer(reinterpret_cast<void*>(0));
223            }
224          }
225
226          // Clears up a warning with GCC 3.2.3
227          return make_any_pointer(reinterpret_cast<void*>(0));
228        }
229      };
230
231      /**
232       * The functor_manager class contains a static function "manage" which
233       * can clone or destroy the given function/function object pointer.
234       */
235      template<typename Functor, typename Allocator>
236      struct functor_manager
237      {
238      private:
239        typedef Functor functor_type;
240
241        // For function pointers, the manager is trivial
242        static inline any_pointer
243        manager(any_pointer function_ptr,
244                functor_manager_operation_type op,
245                function_ptr_tag)
246        {
247          if (op == clone_functor_tag)
248            return function_ptr;
249          else
250            return make_any_pointer(static_cast<void (*)()>(0));
251        }
252
253        // For function object pointers, we clone the pointer to each
254        // function has its own version.
255        static inline any_pointer
256        manager(any_pointer function_obj_ptr,
257                functor_manager_operation_type op,
258                function_obj_tag)
259        {
260#ifndef BOOST_NO_STD_ALLOCATOR
261        typedef typename Allocator::template rebind<functor_type>::other
262          allocator_type;
263        typedef typename allocator_type::pointer pointer_type;
264#else
265        typedef functor_type* pointer_type;
266#endif // BOOST_NO_STD_ALLOCATOR
267
268#  ifndef BOOST_NO_STD_ALLOCATOR
269          allocator_type allocator;
270#  endif // BOOST_NO_STD_ALLOCATOR
271
272          if (op == clone_functor_tag) {
273            functor_type* f =
274              static_cast<functor_type*>(function_obj_ptr.obj_ptr);
275
276            // Clone the functor
277#  ifndef BOOST_NO_STD_ALLOCATOR
278            pointer_type copy = allocator.allocate(1);
279            allocator.construct(copy, *f);
280
281            // Get back to the original pointer type
282            functor_type* new_f = static_cast<functor_type*>(copy);
283#  else
284            functor_type* new_f = new functor_type(*f);
285#  endif // BOOST_NO_STD_ALLOCATOR
286            return make_any_pointer(static_cast<void*>(new_f));
287          }
288          else {
289            /* Cast from the void pointer to the functor pointer type */
290            functor_type* f =
291              reinterpret_cast<functor_type*>(function_obj_ptr.obj_ptr);
292
293#  ifndef BOOST_NO_STD_ALLOCATOR
294            /* Cast from the functor pointer type to the allocator's pointer
295               type */
296            pointer_type victim = static_cast<pointer_type>(f);
297
298            // Destroy and deallocate the functor
299            allocator.destroy(victim);
300            allocator.deallocate(victim, 1);
301#  else
302            delete f;
303#  endif // BOOST_NO_STD_ALLOCATOR
304
305            return make_any_pointer(static_cast<void*>(0));
306          }
307        }
308      public:
309        /* Dispatch to an appropriate manager based on whether we have a
310           function pointer or a function object pointer. */
311        static any_pointer
312        manage(any_pointer functor_ptr, functor_manager_operation_type op)
313        {
314          if (op == check_functor_type_tag) {
315            std::type_info* type =
316              static_cast<std::type_info*>(functor_ptr.obj_ptr);
317            return (BOOST_FUNCTION_COMPARE_TYPE_ID(typeid(Functor), *type)?
318                    functor_ptr
319                    : make_any_pointer(reinterpret_cast<void*>(0)));
320          }
321          else {
322            typedef typename get_function_tag<functor_type>::type tag_type;
323            return manager(functor_ptr, op, tag_type());
324          }
325        }
326      };
327
328      // A type that is only used for comparisons against zero
329      struct useless_clear_type {};
330
331#ifdef BOOST_NO_SFINAE
332      // These routines perform comparisons between a Boost.Function
333      // object and an arbitrary function object (when the last
334      // parameter is mpl::bool_<false>) or against zero (when the
335      // last parameter is mpl::bool_<true>). They are only necessary
336      // for compilers that don't support SFINAE.
337      template<typename Function, typename Functor>
338        bool
339        compare_equal(const Function& f, const Functor&, int, mpl::bool_<true>)
340        { return f.empty(); }
341
342      template<typename Function, typename Functor>
343        bool
344        compare_not_equal(const Function& f, const Functor&, int,
345                          mpl::bool_<true>)
346        { return !f.empty(); }
347
348      template<typename Function, typename Functor>
349        bool
350        compare_equal(const Function& f, const Functor& g, long,
351                      mpl::bool_<false>)
352        {
353          if (const Functor* fp = f.template target<Functor>())
354            return function_equal(*fp, g);
355          else return false;
356        }
357
358      template<typename Function, typename Functor>
359        bool
360        compare_equal(const Function& f, const reference_wrapper<Functor>& g,
361                      int, mpl::bool_<false>)
362        {
363          if (const Functor* fp = f.template target<Functor>())
364            return fp == g.get_pointer();
365          else return false;
366        }
367
368      template<typename Function, typename Functor>
369        bool
370        compare_not_equal(const Function& f, const Functor& g, long,
371                          mpl::bool_<false>)
372        {
373          if (const Functor* fp = f.template target<Functor>())
374            return !function_equal(*fp, g);
375          else return true;
376        }
377
378      template<typename Function, typename Functor>
379        bool
380        compare_not_equal(const Function& f,
381                          const reference_wrapper<Functor>& g, int,
382                          mpl::bool_<false>)
383        {
384          if (const Functor* fp = f.template target<Functor>())
385            return fp != g.get_pointer();
386          else return true;
387        }
388#endif // BOOST_NO_SFINAE
389    } // end namespace function
390  } // end namespace detail
391
392/**
393 * The function_base class contains the basic elements needed for the
394 * function1, function2, function3, etc. classes. It is common to all
395 * functions (and as such can be used to tell if we have one of the
396 * functionN objects).
397 */
398class function_base
399{
400public:
401  function_base() : manager(0)
402  {
403    functor.obj_ptr = 0;
404  }
405
406  // Is this function empty?
407  bool empty() const { return !manager; }
408
409  template<typename Functor>
410    Functor* target()
411    {
412      if (!manager) return 0;
413
414      detail::function::any_pointer result =
415        manager(detail::function::make_any_pointer(&typeid(Functor)),
416                detail::function::check_functor_type_tag);
417      if (!result.obj_ptr) return 0;
418      else {
419        typedef typename detail::function::get_function_tag<Functor>::type tag;
420        return get_functor_pointer<Functor>(tag(), 0);
421      }
422    }
423
424  template<typename Functor>
425
426#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
427    const Functor* target( Functor * = 0 ) const
428#else
429    const Functor* target() const
430#endif
431    {
432      if (!manager) return 0;
433
434      detail::function::any_pointer result =
435        manager(detail::function::make_any_pointer(&typeid(Functor)),
436                detail::function::check_functor_type_tag);
437      if (!result.obj_ptr) return 0;
438      else {
439        typedef typename detail::function::get_function_tag<Functor>::type tag;
440
441#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
442        return get_functor_pointer(tag(), 0, (Functor*)0);
443#else
444        return get_functor_pointer<Functor>(tag(), 0);
445#endif
446      }
447    }
448
449  template<typename F>
450    bool contains(const F& f) const
451    {
452#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
453      if (const F* fp = this->target( (F*)0 )) {
454#else
455      if (const F* fp = this->template target<F>()) {
456#endif
457        return function_equal(*fp, f);
458      } else {
459        return false;
460      }
461    }
462
463#if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3
464  // GCC 3.3 and newer cannot copy with the global operator==, due to
465  // problems with instantiation of function return types before it
466  // has been verified that the argument types match up.
467  template<typename Functor>
468    BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
469    operator==(Functor g) const
470    {
471      if (const Functor* fp = target<Functor>())
472        return function_equal(*fp, g);
473      else return false;
474    }
475
476  template<typename Functor>
477    BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
478    operator!=(Functor g) const
479    {
480      if (const Functor* fp = target<Functor>())
481        return !function_equal(*fp, g);
482      else return true;
483    }
484#endif
485
486public: // should be protected, but GCC 2.95.3 will fail to allow access
487  detail::function::any_pointer (*manager)(
488    detail::function::any_pointer,
489    detail::function::functor_manager_operation_type);
490  detail::function::any_pointer functor;
491
492private:
493  template<typename Functor>
494#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
495    Functor* get_functor_pointer(detail::function::function_ptr_tag, int, Functor * = 0)
496#else
497    Functor* get_functor_pointer(detail::function::function_ptr_tag, int)
498#endif
499    { return reinterpret_cast<Functor*>(&functor.func_ptr); }
500
501  template<typename Functor, typename Tag>
502#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
503    Functor* get_functor_pointer(Tag, long, Functor * = 0)
504#else
505    Functor* get_functor_pointer(Tag, long)
506#endif
507    { return static_cast<Functor*>(functor.obj_ptr); }
508
509  template<typename Functor>
510    const Functor*
511#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
512    get_functor_pointer(detail::function::function_ptr_tag, int, Functor * = 0) const
513#else
514    get_functor_pointer(detail::function::function_ptr_tag, int) const
515#endif
516    { return reinterpret_cast<const Functor*>(&functor.func_ptr); }
517
518  template<typename Functor, typename Tag>
519#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
520    const Functor* get_functor_pointer(Tag, long, Functor * = 0) const
521#else
522    const Functor* get_functor_pointer(Tag, long) const
523#endif
524    { return static_cast<const Functor*>(functor.const_obj_ptr); }
525};
526
527/**
528 * The bad_function_call exception class is thrown when a boost::function
529 * object is invoked
530 */
531class bad_function_call : public std::runtime_error
532{
533public:
534  bad_function_call() : std::runtime_error("call to empty boost::function") {}
535};
536
537#ifndef BOOST_NO_SFINAE
538inline bool operator==(const function_base& f,
539                       detail::function::useless_clear_type*)
540{
541  return f.empty();
542}
543
544inline bool operator!=(const function_base& f,
545                       detail::function::useless_clear_type*)
546{
547  return !f.empty();
548}
549
550inline bool operator==(detail::function::useless_clear_type*,
551                       const function_base& f)
552{
553  return f.empty();
554}
555
556inline bool operator!=(detail::function::useless_clear_type*,
557                       const function_base& f)
558{
559  return !f.empty();
560}
561#endif
562
563#ifdef BOOST_NO_SFINAE
564// Comparisons between boost::function objects and arbitrary function objects
565template<typename Functor>
566  inline bool operator==(const function_base& f, Functor g)
567  {
568    typedef mpl::bool_<(is_integral<Functor>::value)> integral;
569    return detail::function::compare_equal(f, g, 0, integral());
570  }
571
572template<typename Functor>
573  inline bool operator==(Functor g, const function_base& f)
574  {
575    typedef mpl::bool_<(is_integral<Functor>::value)> integral;
576    return detail::function::compare_equal(f, g, 0, integral());
577  }
578
579template<typename Functor>
580  inline bool operator!=(const function_base& f, Functor g)
581  {
582    typedef mpl::bool_<(is_integral<Functor>::value)> integral;
583    return detail::function::compare_not_equal(f, g, 0, integral());
584  }
585
586template<typename Functor>
587  inline bool operator!=(Functor g, const function_base& f)
588  {
589    typedef mpl::bool_<(is_integral<Functor>::value)> integral;
590    return detail::function::compare_not_equal(f, g, 0, integral());
591  }
592#else
593
594#  if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
595// Comparisons between boost::function objects and arbitrary function
596// objects. GCC 3.3 and before has an obnoxious bug that prevents this
597// from working.
598template<typename Functor>
599  BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
600  operator==(const function_base& f, Functor g)
601  {
602    if (const Functor* fp = f.template target<Functor>())
603      return function_equal(*fp, g);
604    else return false;
605  }
606
607template<typename Functor>
608  BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
609  operator==(Functor g, const function_base& f)
610  {
611    if (const Functor* fp = f.template target<Functor>())
612      return function_equal(g, *fp);
613    else return false;
614  }
615
616template<typename Functor>
617  BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
618  operator!=(const function_base& f, Functor g)
619  {
620    if (const Functor* fp = f.template target<Functor>())
621      return !function_equal(*fp, g);
622    else return true;
623  }
624
625template<typename Functor>
626  BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
627  operator!=(Functor g, const function_base& f)
628  {
629    if (const Functor* fp = f.template target<Functor>())
630      return !function_equal(g, *fp);
631    else return true;
632  }
633#  endif
634
635template<typename Functor>
636  BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
637  operator==(const function_base& f, reference_wrapper<Functor> g)
638  {
639    if (const Functor* fp = f.template target<Functor>())
640      return fp == g.get_pointer();
641    else return false;
642  }
643
644template<typename Functor>
645  BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
646  operator==(reference_wrapper<Functor> g, const function_base& f)
647  {
648    if (const Functor* fp = f.template target<Functor>())
649      return g.get_pointer() == fp;
650    else return false;
651  }
652
653template<typename Functor>
654  BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
655  operator!=(const function_base& f, reference_wrapper<Functor> g)
656  {
657    if (const Functor* fp = f.template target<Functor>())
658      return fp != g.get_pointer();
659    else return true;
660  }
661
662template<typename Functor>
663  BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
664  operator!=(reference_wrapper<Functor> g, const function_base& f)
665  {
666    if (const Functor* fp = f.template target<Functor>())
667      return g.get_pointer() != fp;
668    else return true;
669  }
670
671#endif // Compiler supporting SFINAE
672
673namespace detail {
674  namespace function {
675    inline bool has_empty_target(const function_base* f)
676    {
677      return f->empty();
678    }
679
680#if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
681    inline bool has_empty_target(const void*)
682    {
683      return false;
684    }
685#else
686    inline bool has_empty_target(...)
687    {
688      return false;
689    }
690#endif
691  } // end namespace function
692} // end namespace detail
693} // end namespace boost
694
695#undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
696#undef BOOST_FUNCTION_COMPARE_TYPE_ID
697
698#endif // BOOST_FUNCTION_BASE_HEADER
Note: See TracBrowser for help on using the repository browser.