]> git.lyx.org Git - lyx.git/blob - boost/boost/function/function_template.hpp
update from Boost CVS
[lyx.git] / boost / boost / function / function_template.hpp
1 // Boost.Function library
2
3 // Copyright (C) 2001 Doug Gregor (gregod@cs.rpi.edu)
4 //
5 // Permission to copy, use, sell and distribute this software is granted
6 // provided this copyright notice appears in all copies.
7 // Permission to modify the code and to distribute modified code is granted
8 // provided this copyright notice appears in all copies, and a notice
9 // that the code was modified is included with the copyright notice.
10 //
11 // This software is provided "as is" without express or implied warranty,
12 // and with no claim as to its suitability for any purpose.
13
14 // For more information, see http://www.boost.org
15
16 // Note: this header is a header template and must NOT have multiple-inclusion
17 // protection.
18
19 #ifndef BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP
20 #define BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP
21 #  include <cassert>
22 #  include <algorithm>
23 #  include <boost/config.hpp>
24 #  include <boost/function/function_base.hpp>
25 #  include <boost/mem_fn.hpp>
26 #endif // BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP
27
28 // Type of the default allocator
29 #ifndef BOOST_NO_STD_ALLOCATOR
30 #  define BOOST_FUNCTION_DEFAULT_ALLOCATOR std::allocator<function_base>
31 #else
32 #  define BOOST_FUNCTION_DEFAULT_ALLOCATOR int
33 #endif // BOOST_NO_STD_ALLOCATOR
34
35 // Comma if nonzero number of arguments
36 #if BOOST_FUNCTION_NUM_ARGS == 0
37 #  define BOOST_FUNCTION_COMMA
38 #else
39 #  define BOOST_FUNCTION_COMMA ,
40 #endif // BOOST_FUNCTION_NUM_ARGS > 0
41
42 // Class names used in this version of the code
43 #define BOOST_FUNCTION_FUNCTION BOOST_JOIN(function,BOOST_FUNCTION_NUM_ARGS)
44 #define BOOST_FUNCTION_FUNCTION_INVOKER \
45   BOOST_JOIN(function_invoker,BOOST_FUNCTION_NUM_ARGS)
46 #define BOOST_FUNCTION_VOID_FUNCTION_INVOKER \
47   BOOST_JOIN(void_function_invoker,BOOST_FUNCTION_NUM_ARGS)
48 #define BOOST_FUNCTION_FUNCTION_OBJ_INVOKER \
49   BOOST_JOIN(function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
50 #define BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER \
51   BOOST_JOIN(void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
52 #define BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER \
53   BOOST_JOIN(stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
54 #define BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER \
55   BOOST_JOIN(stateless_void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
56 #define BOOST_FUNCTION_GET_FUNCTION_INVOKER \
57   BOOST_JOIN(get_function_invoker,BOOST_FUNCTION_NUM_ARGS)
58 #define BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER \
59   BOOST_JOIN(get_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
60 #define BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER \
61   BOOST_JOIN(get_stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
62
63 namespace boost {
64   namespace detail {
65     namespace function {
66       template<
67         typename FunctionPtr,
68         typename R BOOST_FUNCTION_COMMA
69         BOOST_FUNCTION_TEMPLATE_PARMS
70         >
71       struct BOOST_FUNCTION_FUNCTION_INVOKER
72       {
73         static R invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA
74                         BOOST_FUNCTION_PARMS)
75         {
76           FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.func_ptr);
77           return f(BOOST_FUNCTION_ARGS);
78         }
79       };
80
81       template<
82         typename FunctionPtr,
83         typename R BOOST_FUNCTION_COMMA
84         BOOST_FUNCTION_TEMPLATE_PARMS
85         >
86       struct BOOST_FUNCTION_VOID_FUNCTION_INVOKER
87       {
88         static unusable invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA
89                                BOOST_FUNCTION_PARMS)
90
91         {
92           FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.func_ptr);
93           f(BOOST_FUNCTION_ARGS);
94           return unusable();
95         }
96       };
97
98       template<
99         typename FunctionObj,
100         typename R BOOST_FUNCTION_COMMA
101         BOOST_FUNCTION_TEMPLATE_PARMS
102       >
103       struct BOOST_FUNCTION_FUNCTION_OBJ_INVOKER
104       {
105         static R invoke(any_pointer function_obj_ptr BOOST_FUNCTION_COMMA
106                         BOOST_FUNCTION_PARMS)
107
108         {
109           FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr);
110           return (*f)(BOOST_FUNCTION_ARGS);
111         }
112       };
113
114       template<
115         typename FunctionObj,
116         typename R BOOST_FUNCTION_COMMA
117         BOOST_FUNCTION_TEMPLATE_PARMS
118       >
119       struct BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER
120       {
121         static unusable invoke(any_pointer function_obj_ptr
122                                BOOST_FUNCTION_COMMA
123                                BOOST_FUNCTION_PARMS)
124
125         {
126           FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr);
127           (*f)(BOOST_FUNCTION_ARGS);
128           return unusable();
129         }
130       };
131
132       template<
133         typename FunctionObj,
134         typename R BOOST_FUNCTION_COMMA
135         BOOST_FUNCTION_TEMPLATE_PARMS
136       >
137       struct BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER
138       {
139         static R invoke(any_pointer BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS)
140         {
141           FunctionObj f = FunctionObj();
142           return f(BOOST_FUNCTION_ARGS);
143         }
144       };
145
146       template<
147         typename FunctionObj,
148         typename R BOOST_FUNCTION_COMMA
149         BOOST_FUNCTION_TEMPLATE_PARMS
150       >
151       struct BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER
152       {
153         static unusable invoke(any_pointer BOOST_FUNCTION_COMMA
154                                BOOST_FUNCTION_PARMS)
155
156         {
157           FunctionObj f = FunctionObj();
158           f(BOOST_FUNCTION_ARGS);
159           return unusable();
160         }
161       };
162
163       template<
164         typename FunctionPtr,
165         typename R BOOST_FUNCTION_COMMA
166         BOOST_FUNCTION_TEMPLATE_PARMS
167       >
168       struct BOOST_FUNCTION_GET_FUNCTION_INVOKER
169       {
170         typedef typename ct_if<(is_void<R>::value),
171                             BOOST_FUNCTION_VOID_FUNCTION_INVOKER<
172                             FunctionPtr,
173                             R BOOST_FUNCTION_COMMA
174                             BOOST_FUNCTION_TEMPLATE_ARGS
175                           >,
176                           BOOST_FUNCTION_FUNCTION_INVOKER<
177                             FunctionPtr,
178                             R BOOST_FUNCTION_COMMA
179                             BOOST_FUNCTION_TEMPLATE_ARGS
180                           >
181                        >::type type;
182       };
183
184       template<
185         typename FunctionObj,
186         typename R BOOST_FUNCTION_COMMA
187         BOOST_FUNCTION_TEMPLATE_PARMS
188        >
189       struct BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER
190       {
191         typedef typename ct_if<(is_void<R>::value),
192                             BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER<
193                             FunctionObj,
194                             R BOOST_FUNCTION_COMMA
195                             BOOST_FUNCTION_TEMPLATE_ARGS
196                           >,
197                           BOOST_FUNCTION_FUNCTION_OBJ_INVOKER<
198                             FunctionObj,
199                             R BOOST_FUNCTION_COMMA
200                             BOOST_FUNCTION_TEMPLATE_ARGS
201                           >
202                        >::type type;
203       };
204
205       template<
206         typename FunctionObj,
207         typename R BOOST_FUNCTION_COMMA
208         BOOST_FUNCTION_TEMPLATE_PARMS
209        >
210       struct BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER
211       {
212         typedef typename ct_if<(is_void<R>::value),
213                             BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER<
214                             FunctionObj,
215                             R BOOST_FUNCTION_COMMA
216                             BOOST_FUNCTION_TEMPLATE_ARGS
217                           >,
218                           BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER<
219                             FunctionObj,
220                             R BOOST_FUNCTION_COMMA
221                             BOOST_FUNCTION_TEMPLATE_ARGS
222                           >
223                        >::type type;
224       };
225
226     } // end namespace function
227   } // end namespace detail
228
229   template<
230     typename R BOOST_FUNCTION_COMMA
231     BOOST_FUNCTION_TEMPLATE_PARMS,
232 #ifndef BOOST_FUNCTION_NO_DEPRECATED
233     typename Policy    = empty_function_policy,
234     typename Mixin     = empty_function_mixin,
235 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
236     typename Allocator = BOOST_FUNCTION_DEFAULT_ALLOCATOR
237   >
238   class BOOST_FUNCTION_FUNCTION : public function_base
239 #ifndef BOOST_FUNCTION_NO_DEPRECATED
240                                 , public Mixin
241 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
242   {
243     typedef typename detail::function::function_return_type<R>::type
244       internal_result_type;
245
246   public:
247     BOOST_STATIC_CONSTANT(int, args = BOOST_FUNCTION_NUM_ARGS);
248
249 #if BOOST_FUNCTION_NUM_ARGS == 1
250     typedef T0 argument_type;
251 #elif BOOST_FUNCTION_NUM_ARGS == 2
252     typedef T0 first_argument_type;
253     typedef T1 second_argument_type;
254 #endif
255
256 #ifndef BOOST_NO_VOID_RETURNS
257     typedef R         result_type;
258 #else
259     typedef internal_result_type result_type;
260 #endif // BOOST_NO_VOID_RETURNS
261 #ifndef BOOST_FUNCTION_NO_DEPRECATED
262     typedef Policy    policy_type;
263     typedef Mixin     mixin_type;
264 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
265     typedef Allocator allocator_type;
266     typedef BOOST_FUNCTION_FUNCTION self_type;
267
268     BOOST_FUNCTION_FUNCTION() : function_base()
269 #ifndef BOOST_FUNCTION_NO_DEPRECATED
270                               , Mixin()
271 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
272                               , invoker(0) {}
273
274 #ifndef BOOST_FUNCTION_NO_DEPRECATED
275     explicit BOOST_FUNCTION_FUNCTION(const Mixin& m) :
276       function_base(), 
277       Mixin(m), 
278       invoker(0) 
279     {
280     }
281 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
282
283     // MSVC chokes if the following two constructors are collapsed into
284     // one with a default parameter.
285     template<typename Functor>
286     BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) :
287       function_base(), 
288 #ifndef BOOST_FUNCTION_NO_DEPRECATED
289       Mixin(), 
290 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
291       invoker(0)
292     {
293       this->assign_to(f);
294     }
295
296 #ifndef BOOST_FUNCTION_NO_DEPRECATED
297     template<typename Functor>
298     BOOST_FUNCTION_FUNCTION(Functor f, const Mixin& m) :
299       function_base(), 
300       Mixin(m), 
301       invoker(0)
302     {
303       this->assign_to(f);
304     }
305 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
306
307     BOOST_FUNCTION_FUNCTION(const BOOST_FUNCTION_FUNCTION& f) :
308       function_base(),
309 #ifndef BOOST_FUNCTION_NO_DEPRECATED
310       Mixin(static_cast<const Mixin&>(f)), 
311 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
312       invoker(0)
313     {
314       this->assign_to_own(f);
315     }
316
317     ~BOOST_FUNCTION_FUNCTION() { clear(); }
318
319     result_type operator()(BOOST_FUNCTION_PARMS) const
320     {
321       assert(!this->empty());
322
323 #ifndef BOOST_FUNCTION_NO_DEPRECATED
324       policy_type policy;
325       policy.precall(this);
326 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
327
328       internal_result_type result = invoker(function_base::functor
329                                             BOOST_FUNCTION_COMMA
330                                             BOOST_FUNCTION_ARGS);
331
332 #ifndef BOOST_FUNCTION_NO_DEPRECATED
333       policy.postcall(this);
334 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
335
336 #ifndef BOOST_NO_VOID_RETURNS
337       return static_cast<result_type>(result);
338 #else
339       return result;
340 #endif // BOOST_NO_VOID_RETURNS
341     }
342
343     // The distinction between when to use BOOST_FUNCTION_FUNCTION and
344     // when to use self_type is obnoxious. MSVC cannot handle self_type as
345     // the return type of these assignment operators, but Borland C++ cannot
346     // handle BOOST_FUNCTION_FUNCTION as the type of the temporary to
347     // construct.
348     template<typename Functor>
349     BOOST_FUNCTION_FUNCTION&
350     operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f)
351     {
352 #ifndef BOOST_FUNCTION_NO_DEPRECATED
353       self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
354 #else
355       self_type(f).swap(*this);
356 #endif // BOOST_FUNCTION_NO_DEPRECATED
357       return *this;
358     }
359
360 #ifndef BOOST_FUNCTION_NO_DEPRECATED
361     template<typename Functor>
362     BOOST_FUNCTION_DEPRECATED_PRE
363     void set(Functor BOOST_FUNCTION_TARGET_FIX(const &) f)
364     {
365       BOOST_FUNCTION_DEPRECATED_INNER
366       self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
367     }
368 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
369
370     // Assignment from another BOOST_FUNCTION_FUNCTION
371     BOOST_FUNCTION_FUNCTION& operator=(const BOOST_FUNCTION_FUNCTION& f)
372     {
373       if (&f == this)
374         return *this;
375
376       self_type(f).swap(*this);
377       return *this;
378     }
379
380 #ifndef BOOST_FUNCTION_NO_DEPRECATED
381     // Assignment from another BOOST_FUNCTION_FUNCTION
382     BOOST_FUNCTION_DEPRECATED_PRE
383     void set(const BOOST_FUNCTION_FUNCTION& f)
384     {
385       BOOST_FUNCTION_DEPRECATED_INNER
386       if (&f == this)
387         return;
388
389       self_type(f).swap(*this);
390     }
391 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
392
393     void swap(BOOST_FUNCTION_FUNCTION& other)
394     {
395       if (&other == this)
396         return;
397
398       std::swap(function_base::manager, other.manager);
399       std::swap(function_base::functor, other.functor);
400       std::swap(invoker, other.invoker);
401 #ifndef BOOST_FUNCTION_NO_DEPRECATED
402       std::swap(static_cast<Mixin&>(*this), static_cast<Mixin&>(other));
403 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
404     }
405
406     // Clear out a target, if there is one
407     void clear()
408     {
409       if (function_base::manager) {
410         function_base::functor =
411           function_base::manager(function_base::functor,
412                                  detail::function::destroy_functor_tag);
413       }
414
415       function_base::manager = 0;
416       invoker = 0;
417     }
418
419   private:
420     void assign_to_own(const BOOST_FUNCTION_FUNCTION& f)
421     {
422       if (!f.empty()) {
423         invoker = f.invoker;
424         function_base::manager = f.manager;
425         function_base::functor =
426           f.manager(f.functor, detail::function::clone_functor_tag);
427       }
428     }
429
430     template<typename Functor>
431     void assign_to(Functor f)
432     {
433       typedef typename detail::function::get_function_tag<Functor>::type tag;
434       this->assign_to(f, tag());
435     }
436
437     template<typename FunctionPtr>
438     void assign_to(FunctionPtr f, detail::function::function_ptr_tag)
439     {
440       clear();
441
442       if (f) {
443         typedef typename detail::function::BOOST_FUNCTION_GET_FUNCTION_INVOKER<
444                            FunctionPtr,
445                            R BOOST_FUNCTION_COMMA
446                            BOOST_FUNCTION_TEMPLATE_ARGS
447                          >::type
448           invoker_type;
449
450         invoker = &invoker_type::invoke;
451         function_base::manager =
452           &detail::function::functor_manager<FunctionPtr, Allocator>::manage;
453         function_base::functor =
454           function_base::manager(detail::function::any_pointer(
455                             // should be a reinterpret cast, but some compilers
456                             // insist on giving cv-qualifiers to free functions
457                             (void (*)())(f)
458                           ),
459                           detail::function::clone_functor_tag);
460       }
461     }
462
463 #if BOOST_FUNCTION_NUM_ARGS > 0
464     template<typename MemberPtr>
465     void assign_to(MemberPtr f, detail::function::member_ptr_tag)
466     {
467       this->assign_to(mem_fn(f));
468     }
469 #endif // BOOST_FUNCTION_NUM_ARGS > 0
470
471     template<typename FunctionObj>
472     void assign_to(FunctionObj f, detail::function::function_obj_tag)
473     {
474       if (!detail::function::has_empty_target(addressof(f))) {
475         typedef
476           typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
477                                        FunctionObj,
478                                        R BOOST_FUNCTION_COMMA
479                                        BOOST_FUNCTION_TEMPLATE_ARGS
480                                      >::type
481           invoker_type;
482
483         invoker = &invoker_type::invoke;
484         function_base::manager = &detail::function::functor_manager<
485                                     FunctionObj, Allocator>::manage;
486 #ifndef BOOST_NO_STD_ALLOCATOR
487         typedef typename Allocator::template rebind<FunctionObj>::other
488           allocator_type;
489         typedef typename allocator_type::pointer pointer_type;
490         allocator_type allocator;
491         pointer_type copy = allocator.allocate(1);
492         allocator.construct(copy, f);
493
494         // Get back to the original pointer type
495         FunctionObj* new_f = static_cast<FunctionObj*>(copy);
496 #else
497         FunctionObj* new_f = new FunctionObj(f);
498 #endif // BOOST_NO_STD_ALLOCATOR
499         function_base::functor =
500           detail::function::any_pointer(static_cast<void*>(new_f));
501       }
502     }
503
504     template<typename FunctionObj>
505     void assign_to(const reference_wrapper<FunctionObj>& f,
506                    detail::function::function_obj_ref_tag)
507     {
508       if (!detail::function::has_empty_target(f.get_pointer())) {
509         typedef
510           typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
511                                        FunctionObj,
512                                        R BOOST_FUNCTION_COMMA
513                                        BOOST_FUNCTION_TEMPLATE_ARGS
514                                      >::type
515           invoker_type;
516
517         invoker = &invoker_type::invoke;
518         function_base::manager = &detail::function::trivial_manager;
519         function_base::functor =
520           function_base::manager(
521             detail::function::any_pointer(
522               const_cast<FunctionObj*>(f.get_pointer())),
523             detail::function::clone_functor_tag);
524       }
525     }
526
527     template<typename FunctionObj>
528     void assign_to(FunctionObj, detail::function::stateless_function_obj_tag)
529     {
530       typedef
531           typename detail::function::
532                      BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER<
533                        FunctionObj,
534                        R BOOST_FUNCTION_COMMA
535                        BOOST_FUNCTION_TEMPLATE_ARGS
536                      >::type
537           invoker_type;
538       invoker = &invoker_type::invoke;
539       function_base::manager = &detail::function::trivial_manager;
540       function_base::functor = detail::function::any_pointer(this);
541     }
542
543     typedef internal_result_type (*invoker_type)(detail::function::any_pointer
544                                                  BOOST_FUNCTION_COMMA
545                                                  BOOST_FUNCTION_TEMPLATE_ARGS);
546
547     invoker_type invoker;
548   };
549
550   template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
551 #ifndef BOOST_FUNCTION_NO_DEPRECATED
552            typename Policy, typename Mixin, 
553 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
554            typename Allocator>
555   inline void swap(BOOST_FUNCTION_FUNCTION<
556                      R BOOST_FUNCTION_COMMA
557                      BOOST_FUNCTION_TEMPLATE_ARGS ,
558 #ifndef BOOST_FUNCTION_NO_DEPRECATED
559                      Policy,
560                      Mixin,
561 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
562                      Allocator
563                    >& f1,
564                    BOOST_FUNCTION_FUNCTION<
565                      R BOOST_FUNCTION_COMMA
566                      BOOST_FUNCTION_TEMPLATE_ARGS,
567 #ifndef BOOST_FUNCTION_NO_DEPRECATED
568                      Policy,
569                      Mixin,
570 #endif // ndef BOOST_FUNCTION_NO_DEPRECATED
571                      Allocator
572                    >& f2)
573   {
574     f1.swap(f2);
575   }
576 }
577
578 // Cleanup after ourselves...
579 #undef BOOST_FUNCTION_DEFAULT_ALLOCATOR
580 #undef BOOST_FUNCTION_COMMA
581 #undef BOOST_FUNCTION_FUNCTION
582 #undef BOOST_FUNCTION_FUNCTION_INVOKER
583 #undef BOOST_FUNCTION_VOID_FUNCTION_INVOKER
584 #undef BOOST_FUNCTION_FUNCTION_OBJ_INVOKER
585 #undef BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER
586 #undef BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER
587 #undef BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER
588 #undef BOOST_FUNCTION_GET_FUNCTION_INVOKER
589 #undef BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER
590 #undef BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER
591 #undef BOOST_FUNCTION_GET_MEM_FUNCTION_INVOKER