]> git.lyx.org Git - lyx.git/blob - boost/boost/function/function_template.hpp
major boost update
[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     typename Policy    = empty_function_policy,
233     typename Mixin     = empty_function_mixin,
234     typename Allocator = BOOST_FUNCTION_DEFAULT_ALLOCATOR
235   >
236   class BOOST_FUNCTION_FUNCTION : public function_base, public Mixin
237   {
238     typedef typename detail::function::function_return_type<R>::type 
239       internal_result_type;
240
241   public:
242     BOOST_STATIC_CONSTANT(int, args = BOOST_FUNCTION_NUM_ARGS);
243     
244 #if BOOST_FUNCTION_NUM_ARGS == 1
245     typedef T0 argument_type;
246 #elif BOOST_FUNCTION_NUM_ARGS == 2
247     typedef T0 first_argument_type;
248     typedef T1 second_argument_type;
249 #endif
250
251 #ifndef BOOST_NO_VOID_RETURNS
252     typedef R         result_type;
253 #else
254     typedef internal_result_type result_type;
255 #endif // BOOST_NO_VOID_RETURNS
256     typedef Policy    policy_type;
257     typedef Mixin     mixin_type;
258     typedef Allocator allocator_type;
259     typedef BOOST_FUNCTION_FUNCTION self_type;
260
261     BOOST_FUNCTION_FUNCTION() : function_base(), Mixin(), invoker(0) {}
262
263     explicit BOOST_FUNCTION_FUNCTION(const Mixin& m) : 
264       function_base(), Mixin(m), invoker(0) 
265     {
266     }
267
268     // MSVC chokes if the following two constructors are collapsed into
269     // one with a default parameter.
270     template<typename Functor>
271     BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) :
272       function_base(), Mixin(), invoker(0)
273     {
274       this->assign_to(f);
275     }
276
277     template<typename Functor>
278     BOOST_FUNCTION_FUNCTION(Functor f, const Mixin& m) :
279       function_base(), Mixin(m), invoker(0)
280     {
281       this->assign_to(f);
282     }
283
284     BOOST_FUNCTION_FUNCTION(const BOOST_FUNCTION_FUNCTION& f) :
285       function_base(), Mixin(static_cast<const Mixin&>(f)), invoker(0)
286     {
287       this->assign_to_own(f);
288     }
289
290     ~BOOST_FUNCTION_FUNCTION() { clear(); }
291
292     result_type operator()(BOOST_FUNCTION_PARMS) const
293     {
294       assert(!this->empty());
295
296       policy_type policy;
297       policy.precall(this);
298
299       internal_result_type result = invoker(function_base::functor 
300                                             BOOST_FUNCTION_COMMA
301                                             BOOST_FUNCTION_ARGS);
302
303       policy.postcall(this);
304 #ifndef BOOST_NO_VOID_RETURNS
305       return static_cast<result_type>(result);
306 #else
307       return result;
308 #endif // BOOST_NO_VOID_RETURNS
309     }
310
311     // The distinction between when to use BOOST_FUNCTION_FUNCTION and
312     // when to use self_type is obnoxious. MSVC cannot handle self_type as
313     // the return type of these assignment operators, but Borland C++ cannot
314     // handle BOOST_FUNCTION_FUNCTION as the type of the temporary to 
315     // construct.
316     template<typename Functor>
317     BOOST_FUNCTION_FUNCTION& 
318     operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f)
319     {
320       self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
321       return *this;
322     }
323
324     template<typename Functor>
325     void set(Functor BOOST_FUNCTION_TARGET_FIX(const &) f)
326     {
327       self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
328     }
329
330     // Assignment from another BOOST_FUNCTION_FUNCTION
331     BOOST_FUNCTION_FUNCTION& operator=(const BOOST_FUNCTION_FUNCTION& f)
332     {
333       if (&f == this)
334         return *this;
335
336       self_type(f).swap(*this);
337       return *this;
338     }
339
340     // Assignment from another BOOST_FUNCTION_FUNCTION
341     void set(const BOOST_FUNCTION_FUNCTION& f)
342     {
343       if (&f == this)
344         return;
345
346       self_type(f).swap(*this);
347     }
348
349     void swap(BOOST_FUNCTION_FUNCTION& other)
350     {
351       if (&other == this)
352         return;
353
354       std::swap(function_base::manager, other.manager);
355       std::swap(function_base::functor, other.functor);
356       std::swap(invoker, other.invoker);
357       std::swap(static_cast<Mixin&>(*this), static_cast<Mixin&>(other));
358     }
359
360     // Clear out a target, if there is one
361     void clear()
362     {
363       if (function_base::manager) {
364         function_base::functor = 
365           function_base::manager(function_base::functor, 
366                                  detail::function::destroy_functor_tag);
367       }
368
369       function_base::manager = 0;
370       invoker = 0;
371     }
372
373   private:
374     void assign_to_own(const BOOST_FUNCTION_FUNCTION& f)
375     {
376       if (!f.empty()) {
377         invoker = f.invoker;
378         function_base::manager = f.manager;
379         function_base::functor = 
380           f.manager(f.functor, detail::function::clone_functor_tag);
381       }          
382     }
383
384     template<typename Functor>
385     void assign_to(Functor f)
386     {
387       typedef typename detail::function::get_function_tag<Functor>::type tag;
388       this->assign_to(f, tag());
389     }
390
391     template<typename FunctionPtr>
392     void assign_to(FunctionPtr f, detail::function::function_ptr_tag)
393     {
394       clear();
395         
396       if (f) {
397         typedef typename detail::function::BOOST_FUNCTION_GET_FUNCTION_INVOKER<
398                            FunctionPtr,
399                            R BOOST_FUNCTION_COMMA
400                            BOOST_FUNCTION_TEMPLATE_ARGS
401                          >::type
402           invoker_type;
403     
404         invoker = &invoker_type::invoke;
405         function_base::manager = 
406           &detail::function::functor_manager<FunctionPtr, Allocator>::manage;
407         function_base::functor = 
408           function_base::manager(detail::function::any_pointer(
409                             // should be a reinterpret cast, but some compilers
410                             // insist on giving cv-qualifiers to free functions
411                             (void (*)())(f)
412                           ),
413                           detail::function::clone_functor_tag);
414       }
415     }  
416
417 #if BOOST_FUNCTION_NUM_ARGS > 0
418     template<typename MemberPtr>
419     void assign_to(MemberPtr f, detail::function::member_ptr_tag)
420     {
421       this->assign_to(mem_fn(f));
422     }
423 #endif // BOOST_FUNCTION_NUM_ARGS > 0
424         
425     template<typename FunctionObj>
426     void assign_to(FunctionObj f, detail::function::function_obj_tag)
427     {
428       if (!detail::function::has_empty_target(addressof(f))) {
429         typedef 
430           typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
431                                        FunctionObj,
432                                        R BOOST_FUNCTION_COMMA
433                                        BOOST_FUNCTION_TEMPLATE_ARGS
434                                      >::type
435           invoker_type;
436     
437         invoker = &invoker_type::invoke;
438         function_base::manager = &detail::function::functor_manager<
439                                     FunctionObj, Allocator>::manage;
440 #ifndef BOOST_NO_STD_ALLOCATOR
441         typedef typename Allocator::template rebind<FunctionObj>::other 
442           allocator_type;
443         typedef typename allocator_type::pointer pointer_type;
444         allocator_type allocator;
445         pointer_type copy = allocator.allocate(1);
446         allocator.construct(copy, f);
447
448         // Get back to the original pointer type
449         FunctionObj* new_f = static_cast<FunctionObj*>(copy);
450 #else
451         FunctionObj* new_f = new FunctionObj(f);
452 #endif // BOOST_NO_STD_ALLOCATOR
453         function_base::functor = 
454           detail::function::any_pointer(static_cast<void*>(new_f));
455       }
456     }
457     
458     template<typename FunctionObj>
459     void assign_to(const reference_wrapper<FunctionObj>& f, 
460                    detail::function::function_obj_ref_tag)
461     {
462       if (!detail::function::has_empty_target(f.get_pointer())) {
463         typedef 
464           typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
465                                        FunctionObj,
466                                        R BOOST_FUNCTION_COMMA
467                                        BOOST_FUNCTION_TEMPLATE_ARGS
468                                      >::type
469           invoker_type;
470     
471         invoker = &invoker_type::invoke;
472         function_base::manager = &detail::function::trivial_manager;
473         function_base::functor = 
474           function_base::manager(
475             detail::function::any_pointer(
476               const_cast<FunctionObj*>(f.get_pointer())),
477             detail::function::clone_functor_tag);
478       }
479     }
480     
481     template<typename FunctionObj>
482     void assign_to(FunctionObj, detail::function::stateless_function_obj_tag)
483     {
484       typedef 
485           typename detail::function::
486                      BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER<
487                        FunctionObj,
488                        R BOOST_FUNCTION_COMMA
489                        BOOST_FUNCTION_TEMPLATE_ARGS
490                      >::type
491           invoker_type;
492       invoker = &invoker_type::invoke;
493       function_base::manager = &detail::function::trivial_manager;
494       function_base::functor = detail::function::any_pointer(this);
495     }
496
497     typedef internal_result_type (*invoker_type)(detail::function::any_pointer
498                                                  BOOST_FUNCTION_COMMA
499                                                  BOOST_FUNCTION_TEMPLATE_ARGS);
500     
501     invoker_type invoker;
502   };
503
504   template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
505            typename Policy, typename Mixin, typename Allocator>
506   inline void swap(BOOST_FUNCTION_FUNCTION<
507                      R BOOST_FUNCTION_COMMA
508                      BOOST_FUNCTION_TEMPLATE_ARGS ,
509                      Policy,
510                      Mixin,
511                      Allocator
512                    >& f1,
513                    BOOST_FUNCTION_FUNCTION<
514                      R BOOST_FUNCTION_COMMA 
515                      BOOST_FUNCTION_TEMPLATE_ARGS,
516                      Policy,
517                      Mixin,
518                      Allocator
519                    >& f2)
520   {
521     f1.swap(f2);
522   }
523 }
524
525 // Cleanup after ourselves...
526 #undef BOOST_FUNCTION_DEFAULT_ALLOCATOR
527 #undef BOOST_FUNCTION_COMMA
528 #undef BOOST_FUNCTION_FUNCTION
529 #undef BOOST_FUNCTION_FUNCTION_INVOKER
530 #undef BOOST_FUNCTION_VOID_FUNCTION_INVOKER
531 #undef BOOST_FUNCTION_FUNCTION_OBJ_INVOKER
532 #undef BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER
533 #undef BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER
534 #undef BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER
535 #undef BOOST_FUNCTION_GET_FUNCTION_INVOKER
536 #undef BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER
537 #undef BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER
538 #undef BOOST_FUNCTION_GET_MEM_FUNCTION_INVOKER