1 
2 // (C) Copyright Tobias Schwinger
3 //
4 // Use modification and distribution are subject to the boost Software License,
5 // Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
6 
7 //------------------------------------------------------------------------------
8 
9 #ifndef BOOST_FT_COMPONENTS_HPP_INCLUDED
10 #define BOOST_FT_COMPONENTS_HPP_INCLUDED
11 
12 #include <cstddef>
13 
14 #include <boost/config.hpp>
15 
16 #include <boost/detail/workaround.hpp>
17 #include <boost/mpl/aux_/lambda_support.hpp>
18 
19 #include <boost/type_traits/integral_constant.hpp>
20 
21 #include <boost/mpl/if.hpp>
22 #include <boost/mpl/integral_c.hpp>
23 #include <boost/mpl/vector/vector0.hpp>
24 
25 #if BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x565)
26 #   include <boost/type_traits/remove_cv.hpp>
27 
28 #   include <boost/mpl/identity.hpp>
29 #   include <boost/mpl/bitand.hpp>
30 #   include <boost/mpl/vector/vector10.hpp>
31 #   include <boost/mpl/front.hpp>
32 #   include <boost/mpl/begin.hpp>
33 #   include <boost/mpl/advance.hpp>
34 #   include <boost/mpl/iterator_range.hpp>
35 #   include <boost/mpl/joint_view.hpp>
36 #   include <boost/mpl/equal_to.hpp>
37 #   include <boost/mpl/copy.hpp>
38 #   include <boost/mpl/front_inserter.hpp>
39 
40 #   include <boost/function_types/detail/classifier.hpp>
41 #endif
42 
43 #ifndef BOOST_FT_NO_CV_FUNC_SUPPORT
44 #   include <boost/mpl/remove.hpp>
45 #endif
46 
47 #include <boost/function_types/config/config.hpp>
48 
49 #   if   BOOST_FT_MAX_ARITY < 10
50 #     include <boost/mpl/vector/vector10.hpp>
51 #   elif BOOST_FT_MAX_ARITY < 20
52 #     include <boost/mpl/vector/vector20.hpp>
53 #   elif BOOST_FT_MAX_ARITY < 30
54 #     include <boost/mpl/vector/vector30.hpp>
55 #   elif BOOST_FT_MAX_ARITY < 40
56 #     include <boost/mpl/vector/vector40.hpp>
57 #   elif BOOST_FT_MAX_ARITY < 50
58 #     include <boost/mpl/vector/vector50.hpp>
59 #   endif
60 
61 #include <boost/function_types/detail/class_transform.hpp>
62 #include <boost/function_types/property_tags.hpp>
63 
64 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
65 
66 namespace boost
67 {
68   namespace function_types
69   {
70 
71     using mpl::placeholders::_;
72 
73     template< typename T, typename ClassTypeTransform = add_reference<_> >
74     struct components;
75 
76     namespace detail
77     {
78       template<typename T, typename L> struct components_impl;
79 #if BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x565)
80       template<typename T, typename OrigT, typename L> struct components_bcc;
81 #endif
82     }
83 
84     template<typename T, typename ClassTypeTransform>
85     struct components
86 #if !BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x565)
87       : detail::components_impl<T, ClassTypeTransform>
88 #else
89       : detail::components_bcc<typename remove_cv<T>::type,T,
90             ClassTypeTransform>
91 #endif
92     {
93       typedef components<T,ClassTypeTransform> type;
94 
95       BOOST_MPL_AUX_LAMBDA_SUPPORT(2,components,(T,ClassTypeTransform))
96     };
97 
98 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
99 
100   namespace detail {
101 
102     struct components_mpl_sequence_tag;
103 
104     struct components_non_func_base
105     {
106       typedef mpl::vector0<> types;
107       typedef void function_arity;
108 
109       typedef detail::constant<0> bits;
110       typedef detail::constant<0> mask;
111 
112       typedef components_mpl_sequence_tag tag;
113     };
114 
115     template
116     < typename Components
117     , typename IfTagged
118     , typename ThenTag
119     , typename DefaultBase = components_non_func_base
120     >
121     struct retagged_if
122       : mpl::if_
123         < detail::represents_impl<Components, IfTagged>
124         , detail::changed_tag<Components,IfTagged,ThenTag>
125         , DefaultBase
126         >::type
127     { };
128 
129     // We detect plain function types and function references as function
130     // pointers by recursive instantiation of components_impl.
131     // The third specialization of components_impl makes sure the recursion
132     // terminates (when adding pointers).
133     template<typename T, typename L>
134     struct components_impl
135       : detail::retagged_if
136         < detail::components_impl<T*,L>
137         , pointer_tag, /* --> */ function_tag >
138     { };
139     template<typename T, typename L>
140     struct components_impl<T&, L>
141       : detail::retagged_if
142         < detail::components_impl<T*,L>
143         , pointer_tag, /* --> */ reference_tag >
144     { };
145 
146 #if !BOOST_FT_NO_CV_FUNC_SUPPORT
147     // Retry the type with a member pointer attached to detect cv functions
148     class a_class;
149 
150     template<typename Base, typename T, typename L>
151     struct cv_func_base
152       : detail::retagged_if<Base,member_pointer_tag,function_tag>
153     {
154       typedef typename
155         mpl::remove
156           < typename Base::types
157           , typename detail::class_transform<a_class,L>::type>::type
158       types;
159     };
160 
161     template<typename T, typename L>
162     struct components_impl<T*, L>
163       : mpl::if_
164         < detail::represents_impl< detail::components_impl<T a_class::*, L>
165                                  , member_pointer_tag >
166         , detail::cv_func_base< detail::components_impl<T a_class::*, L>, T, L>
167         , components_non_func_base
168         >::type
169     { };
170 
171     template<typename T, typename L>
172     struct components_impl<T a_class::*, L>
173       : components_non_func_base
174     { };
175 #else
176     template<typename T, typename L>
177     struct components_impl<T*, L>
178       : components_non_func_base
179     { };
180 #endif
181 
182     template<typename T, typename L>
183     struct components_impl<T* const, L>
184       : components_impl<T*,L>
185     { };
186 
187     template<typename T, typename L>
188     struct components_impl<T* volatile, L>
189       : components_impl<T*,L>
190     { };
191 
192     template<typename T, typename L>
193     struct components_impl<T* const volatile, L>
194       : components_impl<T*,L>
195     { };
196 
197     template<typename T, typename L>
198     struct components_impl<T const, L>
199       : components_impl<T,L>
200     { };
201 
202     template<typename T, typename L>
203     struct components_impl<T volatile, L>
204       : components_impl<T,L>
205     { };
206 
207     template<typename T, typename L>
208     struct components_impl<T const volatile, L>
209       : components_impl<T,L>
210     { };
211 
212 
213     template<typename T, class C>
214     struct member_obj_ptr_result
215     { typedef T & type; };
216 
217     template<typename T, class C>
218     struct member_obj_ptr_result<T, C const>
219     { typedef T const & type; };
220 
221     template<typename T, class C>
222     struct member_obj_ptr_result<T, C volatile>
223     { typedef T volatile & type; };
224 
225     template<typename T, class C>
226     struct member_obj_ptr_result<T, C const volatile>
227     { typedef T const volatile & type; };
228 
229     template<typename T, class C>
230     struct member_obj_ptr_result<T &, C>
231     { typedef T & type; };
232 
233     template<typename T, class C>
234     struct member_obj_ptr_result<T &, C const>
235     { typedef T & type; };
236 
237     template<typename T, class C>
238     struct member_obj_ptr_result<T &, C volatile>
239     { typedef T & type; };
240 
241     template<typename T, class C>
242     struct member_obj_ptr_result<T &, C const volatile>
243     { typedef T & type; };
244 
245     template<typename T, class C, typename L>
246     struct member_obj_ptr_components
247       : member_object_pointer_base
248     {
249       typedef function_types::components<T C::*, L> type;
250       typedef components_mpl_sequence_tag tag;
251 
252       typedef mpl::integral_c<std::size_t,1> function_arity;
253 
254       typedef mpl::vector2< typename detail::member_obj_ptr_result<T,C>::type,
255           typename detail::class_transform<C,L>::type > types;
256     };
257 
258 #if !BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x565)
259 #   define BOOST_FT_variations BOOST_FT_pointer|BOOST_FT_member_pointer
260 
261     template<typename T, class C, typename L>
262     struct components_impl<T C::*, L>
263       : member_obj_ptr_components<T,C,L>
264     { };
265 
266 #else
267 #   define BOOST_FT_variations BOOST_FT_pointer
268 
269     // This workaround removes the member pointer from the type to allow
270     // detection of member function pointers with BCC.
271     template<typename T, typename C, typename L>
272     struct components_impl<T C::*, L>
273       : detail::retagged_if
274         < detail::components_impl<typename boost::remove_cv<T>::type *, L>
275         , pointer_tag, /* --> */ member_function_pointer_tag
276         , member_obj_ptr_components<T,C,L> >
277     { };
278 
279     // BCC lets us test the cv-qualification of a function type by template
280     // partial specialization - so we use this bug feature to find out the
281     // member function's cv-qualification (unfortunately there are some
282     // invisible modifiers that impose some limitations on these types even if
283     // we remove the qualifiers, So we cannot exploit the same bug to make the
284     // library work for cv-qualified function types).
285     template<typename T> struct encode_cv
286     { typedef char (& type)[1]; BOOST_STATIC_CONSTANT(std::size_t, value = 1); };
287     template<typename T> struct encode_cv<T const *>
288     { typedef char (& type)[2]; BOOST_STATIC_CONSTANT(std::size_t, value = 2); };
289     template<typename T> struct encode_cv<T volatile *>
290     { typedef char (& type)[3]; BOOST_STATIC_CONSTANT(std::size_t, value = 3); };
291     template<typename T> struct encode_cv<T const volatile *>
292     { typedef char (& type)[4]; BOOST_STATIC_CONSTANT(std::size_t, value = 4); };
293 
294     // For member function pointers we have to use a function template (partial
295     // template specialization for a member pointer drops the cv qualification
296     // of the function type).
297     template<typename T, typename C>
298     typename encode_cv<T *>::type mfp_cv_tester(T C::*);
299 
300     template<typename T> struct encode_mfp_cv
301     {
302       BOOST_STATIC_CONSTANT(std::size_t, value =
303           sizeof(detail::mfp_cv_tester((T)0L)));
304     };
305 
306     // Associate bits with the CV codes above.
307     template<std::size_t> struct cv_tag_mfp_impl;
308 
309     template<typename T> struct cv_tag_mfp
310       : detail::cv_tag_mfp_impl
311         < ::boost::function_types::detail::encode_mfp_cv<T>::value >
312     { };
313 
314     template<> struct cv_tag_mfp_impl<1> : non_cv              { };
315     template<> struct cv_tag_mfp_impl<2> : const_non_volatile  { };
316     template<> struct cv_tag_mfp_impl<3> : volatile_non_const  { };
317     template<> struct cv_tag_mfp_impl<4> : cv_qualified        { };
318 
319     // Metafunction to decode the cv code and apply it to a type.
320     // We add a pointer, because otherwise cv-qualifiers won't stick (another bug).
321     template<typename T, std::size_t CV> struct decode_cv;
322 
323     template<typename T> struct decode_cv<T,1> : mpl::identity<T *>          {};
324     template<typename T> struct decode_cv<T,2> : mpl::identity<T const *>    {};
325     template<typename T> struct decode_cv<T,3> : mpl::identity<T volatile *> {};
326     template<typename T> struct decode_cv<T,4>
327                                          : mpl::identity<T const volatile *> {};
328 
329     // The class type transformation comes after adding cv-qualifiers. We have
330     // wrap it to remove the pointer added in decode_cv_impl.
331     template<typename T, typename L> struct bcc_class_transform_impl;
332     template<typename T, typename L> struct bcc_class_transform_impl<T *, L>
333       : class_transform<T,L>
334     { };
335 
336     template<typename T, typename D, typename L> struct bcc_class_transform
337       : bcc_class_transform_impl
338         < typename decode_cv
339           < T
340           , ::boost::function_types::detail::encode_mfp_cv<D>::value
341           >::type
342         , L
343         >
344     { };
345 
346     // After extracting the member pointee from the type the class type is still
347     // in the type (somewhere -- you won't see with RTTI, that is) and that type
348     // is flagged unusable and *not* identical to the nonmember function type.
349     // We can, however, decompose this type via components_impl but surprisingly
350     // a pointer to the const qualified class type pops up again as the first
351     // parameter type.
352     // We have to replace this type with the properly cv-qualified and
353     // transformed class type, integrate the cv qualification into the bits.
354     template<typename Base, typename MFP, typename OrigT, typename L>
355     struct mfp_components;
356 
357 
358     template<typename Base, typename T, typename C, typename OrigT, typename L>
359     struct mfp_components<Base,T C::*,OrigT,L>
360     {
361     private:
362       typedef typename mpl::front<typename Base::types>::type result_type;
363       typedef typename detail::bcc_class_transform<C,OrigT,L>::type class_type;
364 
365       typedef mpl::vector2<result_type, class_type> result_and_class_type;
366 
367       typedef typename
368         mpl::advance
369         < typename mpl::begin<typename Base::types>::type
370         , typename mpl::if_
371           < mpl::equal_to< typename detail::classifier<OrigT>::function_arity
372                          , typename Base::function_arity >
373           , mpl::integral_c<int,2> , mpl::integral_c<int,1>
374           >::type
375         >::type
376       from;
377       typedef typename mpl::end<typename Base::types>::type to;
378 
379       typedef mpl::iterator_range<from,to> param_types;
380 
381       typedef mpl::joint_view< result_and_class_type, param_types> types_view;
382     public:
383 
384       typedef typename
385         mpl::reverse_copy<types_view, mpl::front_inserter< mpl::vector0<> > >::type
386       types;
387 
388       typedef typename
389         function_types::tag< Base, detail::cv_tag_mfp<OrigT> >::bits
390       bits;
391 
392       typedef typename Base::mask mask;
393 
394       typedef typename detail::classifier<OrigT>::function_arity function_arity;
395 
396       typedef components_mpl_sequence_tag tag;
397     };
398 
399     // Now put it all together: detect cv-qualification of function types and do
400     // the weird transformations above for member function pointers.
401     template<typename T, typename OrigT, typename L>
402     struct components_bcc
403       : mpl::if_
404         < detail::represents_impl< detail::components_impl<T,L>
405                                  , member_function_pointer_tag>
406         , detail::mfp_components<detail::components_impl<T,L>,T,OrigT,L>
407         , detail::components_impl<T,L>
408         >::type
409     { };
410 
411 #endif // end of BORLAND WORKAROUND
412 
413 #define BOOST_FT_al_path boost/function_types/detail/components_impl
414 #include <boost/function_types/detail/pp_loop.hpp>
415 
416   } } // namespace function_types::detail
417 
418 } // namespace ::boost
419 
420 #include <boost/function_types/detail/components_as_mpl_sequence.hpp>
421 #include <boost/function_types/detail/retag_default_cc.hpp>
422 
423 #endif
424 
425