1 /*=============================================================================
2     Copyright (c) 2001-2009 Joel de Guzman
3     Copyright (c) 2005-2006 Dan Marsden
4     Copyright (c) 2009-2011 Christopher Schmidt
5     Copyright (c) 2013-2014 Damien Buhl
6 
7     Distributed under the Boost Software License, Version 1.0. (See accompanying
8     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 ==============================================================================*/
10 
11 #ifndef BOOST_FUSION_ADAPTED_STRUCT_DETAIL_ADAPT_BASE_HPP
12 #define BOOST_FUSION_ADAPTED_STRUCT_DETAIL_ADAPT_BASE_HPP
13 
14 #include <boost/fusion/support/config.hpp>
15 #include <boost/config.hpp>
16 #include <boost/fusion/support/tag_of_fwd.hpp>
17 #include <boost/fusion/adapted/struct/detail/adapt_auto.hpp>
18 #include <boost/fusion/adapted/struct/detail/adapt_is_tpl.hpp>
19 
20 #include <boost/preprocessor/empty.hpp>
21 #include <boost/preprocessor/stringize.hpp>
22 #include <boost/preprocessor/control/if.hpp>
23 #include <boost/preprocessor/seq/size.hpp>
24 #include <boost/preprocessor/seq/for_each.hpp>
25 #include <boost/preprocessor/seq/for_each_i.hpp>
26 #include <boost/preprocessor/seq/enum.hpp>
27 #include <boost/preprocessor/seq/seq.hpp>
28 #include <boost/preprocessor/tuple/eat.hpp>
29 #include <boost/preprocessor/tuple/elem.hpp>
30 #include <boost/preprocessor/arithmetic/dec.hpp>
31 #include <boost/preprocessor/comparison/less.hpp>
32 #include <boost/mpl/bool.hpp>
33 #include <boost/mpl/tag.hpp>
34 #include <boost/mpl/eval_if.hpp>
35 #include <boost/mpl/identity.hpp>
36 #include <boost/type_traits/add_const.hpp>
37 
38 #include <boost/typeof/typeof.hpp>
39 
40 
41 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME_TEMPLATE_PARAMS(SEQ)              \
42     BOOST_PP_SEQ_HEAD(SEQ)<BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TAIL(SEQ))>           \
43     BOOST_PP_EMPTY()
44 
45 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(SEQ)                              \
46     BOOST_PP_IF(                                                                \
47         BOOST_PP_SEQ_HEAD(SEQ),                                                 \
48         BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME_TEMPLATE_PARAMS,                  \
49         BOOST_PP_SEQ_HEAD)(BOOST_PP_SEQ_TAIL(SEQ))
50 
51 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS_IMPL_C(R, _, ELEM)     \
52     (typename ELEM)
53 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS_IMPL(SEQ)              \
54     BOOST_PP_SEQ_ENUM(                                                          \
55         BOOST_PP_SEQ_FOR_EACH(                                                  \
56             BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS_IMPL_C,            \
57             _,                                                                  \
58             BOOST_PP_SEQ_TAIL(SEQ)))
59 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(SEQ)                   \
60     BOOST_PP_IF(                                                                \
61         BOOST_PP_SEQ_HEAD(SEQ),                                                 \
62         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS_IMPL,                  \
63         BOOST_PP_TUPLE_EAT(1))(SEQ)
64 
65 #ifdef BOOST_MSVC
66 #   define BOOST_FUSION_ATTRIBUTE_TYPEOF(                                       \
67         NAME_SEQ, ATTRIBUTE, ATTRIBUTE_TUPEL_SIZE, PREFIX, TEMPLATE_PARAMS_SEQ) \
68                                                                                 \
69     BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS(                    \
70         TEMPLATE_PARAMS_SEQ)                                                    \
71                                                                                 \
72     struct deduced_attr_type {                                                  \
73       static const BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)& obj;        \
74       typedef                                                                   \
75       BOOST_PP_IF(BOOST_FUSION_ADAPT_IS_TPL(TEMPLATE_PARAMS_SEQ), typename, )   \
76       BOOST_TYPEOF( PREFIX() obj.BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPEL_SIZE,      \
77             0, ATTRIBUTE))                                                      \
78       type;                                                                     \
79     };                                                                          \
80                                                                                 \
81     typedef                                                                     \
82         BOOST_PP_IF(BOOST_FUSION_ADAPT_IS_TPL(TEMPLATE_PARAMS_SEQ), typename, ) \
83         deduced_attr_type::type attribute_type;
84 
85 #else
86 #   define BOOST_FUSION_ATTRIBUTE_TYPEOF(                                       \
87         NAME_SEQ, ATTRIBUTE, ATTRIBUTE_TUPEL_SIZE, PREFIX, TEMPLATE_PARAMS_SEQ) \
88                                                                                 \
89     struct deduced_attr_type {                                                  \
90       static const BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)& obj;        \
91       typedef BOOST_TYPEOF(                                                     \
92           PREFIX() obj.BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPEL_SIZE, 0, ATTRIBUTE)) \
93       type;                                                                     \
94     };                                                                          \
95                                                                                 \
96     typedef                                                                     \
97         BOOST_PP_IF(BOOST_FUSION_ADAPT_IS_TPL(TEMPLATE_PARAMS_SEQ), typename, ) \
98         deduced_attr_type::type attribute_type;
99 
100 #endif
101 
102 #define BOOST_FUSION_ATTRIBUTE_GIVENTYPE(                                       \
103     NAME_SEQ, ATTRIBUTE, ATTRIBUTE_TUPEL_SIZE, PREFIX, TEMPLATE_PARAMS_SEQ)     \
104     typedef                                                                     \
105         BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPEL_SIZE, 0, ATTRIBUTE) attribute_type;
106 
107 
108 #ifdef BOOST_NO_PARTIAL_SPECIALIZATION_IMPLICIT_DEFAULT_ARGS
109 #   define BOOST_FUSION_ADAPT_STRUCT_TAG_OF_SPECIALIZATION(                     \
110         MODIFIER, TEMPLATE_PARAMS_SEQ, NAME_SEQ, TAG)                           \
111                                                                                 \
112     template<                                                                   \
113         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(TEMPLATE_PARAMS_SEQ)   \
114     >                                                                           \
115     struct tag_of<                                                              \
116         BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ) MODIFIER                \
117       , void                                                                    \
118     >                                                                           \
119     {                                                                           \
120         typedef TAG type;                                                       \
121     };
122 #else
123 #   define BOOST_FUSION_ADAPT_STRUCT_TAG_OF_SPECIALIZATION(                     \
124         MODIFIER, TEMPLATE_PARAMS_SEQ, NAME_SEQ, TAG)                           \
125                                                                                 \
126     template<                                                                   \
127         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(TEMPLATE_PARAMS_SEQ)   \
128     >                                                                           \
129     struct tag_of<BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ) MODIFIER>     \
130     {                                                                           \
131         typedef TAG type;                                                       \
132     };
133 #endif
134 
135 #define BOOST_FUSION_ADAPT_STRUCT_BASE_UNPACK_AND_CALL(R,DATA,I,ATTRIBUTE)      \
136     BOOST_PP_TUPLE_ELEM(4,0,DATA)(                                              \
137         BOOST_PP_TUPLE_ELEM(4,1,DATA),                                          \
138         BOOST_PP_TUPLE_ELEM(4,2,DATA),                                          \
139         BOOST_PP_TUPLE_ELEM(4,3,DATA),                                          \
140         I,                                                                      \
141         ATTRIBUTE)
142 
143 #ifdef BOOST_MSVC
144 #   define BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAM(R,_,ELEM)     \
145         typedef ELEM ELEM;
146 #   define BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS_IMPL(SEQ)    \
147         BOOST_PP_SEQ_FOR_EACH(                                                  \
148             BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAM,             \
149             _,                                                                  \
150             BOOST_PP_SEQ_TAIL(SEQ))
151 #   define BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS(SEQ)         \
152         BOOST_PP_IF(                                                            \
153             BOOST_PP_SEQ_HEAD(SEQ),                                             \
154             BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS_IMPL,       \
155             BOOST_PP_TUPLE_EAT(1))(SEQ)
156 #else
157 #   define BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS(SEQ)
158 #endif
159 
160 #define BOOST_FUSION_ADAPT_STRUCT_C_BASE(                                       \
161     TEMPLATE_PARAMS_SEQ,NAME_SEQ,IS_VIEW,                                       \
162     I,PREFIX,ATTRIBUTE,ATTRIBUTE_TUPEL_SIZE,                                    \
163     DEDUCE_TYPE)                                                                \
164                                                                                 \
165     template<                                                                   \
166         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(TEMPLATE_PARAMS_SEQ)   \
167     >                                                                           \
168     struct access::struct_member<                                               \
169         BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)                         \
170       , I                                                                       \
171     >                                                                           \
172     {                                                                           \
173         BOOST_PP_IF(DEDUCE_TYPE,                                                \
174             BOOST_FUSION_ATTRIBUTE_TYPEOF, BOOST_FUSION_ATTRIBUTE_GIVENTYPE)(   \
175                 NAME_SEQ,                                                       \
176                 ATTRIBUTE,                                                      \
177                 ATTRIBUTE_TUPEL_SIZE,                                           \
178                 PREFIX,                                                         \
179                 TEMPLATE_PARAMS_SEQ)                                            \
180                                                                                 \
181         BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS(                \
182             TEMPLATE_PARAMS_SEQ)                                                \
183                                                                                 \
184         typedef attribute_type type;                                            \
185                                                                                 \
186         template<typename Seq>                                                  \
187         struct apply                                                            \
188         {                                                                       \
189             typedef typename                                                    \
190                 add_reference<                                                  \
191                     typename mpl::eval_if<                                      \
192                         is_const<Seq>                                           \
193                       , add_const<attribute_type>                               \
194                       , mpl::identity<attribute_type>                           \
195                     >::type                                                     \
196                 >::type                                                         \
197             type;                                                               \
198                                                                                 \
199             BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED                            \
200             static type                                                         \
201             call(Seq& seq)                                                      \
202             {                                                                   \
203                 return seq.PREFIX()                                             \
204                     BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPEL_SIZE,                   \
205                         BOOST_PP_IF(DEDUCE_TYPE, 0, 1), ATTRIBUTE);             \
206             }                                                                   \
207         };                                                                      \
208     };                                                                          \
209                                                                                 \
210     template<                                                                   \
211         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(TEMPLATE_PARAMS_SEQ)   \
212     >                                                                           \
213     struct struct_member_name<                                                  \
214         BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)                         \
215       , I                                                                       \
216     >                                                                           \
217     {                                                                           \
218         typedef char const* type;                                               \
219                                                                                 \
220         BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED                                \
221         static type                                                             \
222         call()                                                                  \
223         {                                                                       \
224             return BOOST_PP_STRINGIZE(                                          \
225                BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPEL_SIZE,                        \
226                         BOOST_PP_IF(DEDUCE_TYPE, 0, 1),                         \
227                           ATTRIBUTE));                                          \
228         }                                                                       \
229     };
230 
231 #define BOOST_FUSION_ADAPT_STRUCT_BASE(                                         \
232     TEMPLATE_PARAMS_SEQ,                                                        \
233     NAME_SEQ,                                                                   \
234     TAG,                                                                        \
235     IS_VIEW,                                                                    \
236     ATTRIBUTES_SEQ,                                                             \
237     ATTRIBUTES_CALLBACK)                                                        \
238                                                                                 \
239 namespace boost                                                                 \
240 {                                                                               \
241     namespace fusion                                                            \
242     {                                                                           \
243         namespace traits                                                        \
244         {                                                                       \
245             BOOST_FUSION_ADAPT_STRUCT_TAG_OF_SPECIALIZATION(                    \
246                 BOOST_PP_EMPTY(), TEMPLATE_PARAMS_SEQ, NAME_SEQ, TAG)           \
247             BOOST_FUSION_ADAPT_STRUCT_TAG_OF_SPECIALIZATION(                    \
248                 const, TEMPLATE_PARAMS_SEQ, NAME_SEQ, TAG)                      \
249         }                                                                       \
250                                                                                 \
251         namespace extension                                                     \
252         {                                                                       \
253             BOOST_PP_IF(                                                        \
254                 BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(ATTRIBUTES_SEQ)),                \
255                 BOOST_PP_SEQ_FOR_EACH_I_R,                                      \
256                 BOOST_PP_TUPLE_EAT(4))(                                         \
257                     1,                                                          \
258                     BOOST_FUSION_ADAPT_STRUCT_BASE_UNPACK_AND_CALL,             \
259                     (ATTRIBUTES_CALLBACK,TEMPLATE_PARAMS_SEQ,NAME_SEQ, IS_VIEW),\
260                     BOOST_PP_SEQ_TAIL(ATTRIBUTES_SEQ))                          \
261                                                                                 \
262             template<                                                           \
263                 BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(               \
264                     TEMPLATE_PARAMS_SEQ)                                        \
265             >                                                                   \
266             struct struct_size<BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)> \
267               : mpl::int_<BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(ATTRIBUTES_SEQ))>      \
268             {};                                                                 \
269                                                                                 \
270             template<                                                           \
271                 BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(               \
272                     TEMPLATE_PARAMS_SEQ)                                        \
273             >                                                                   \
274             struct struct_is_view<                                              \
275                 BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)                 \
276             >                                                                   \
277               : mpl::BOOST_PP_IF(IS_VIEW,true_,false_)                          \
278             {};                                                                 \
279         }                                                                       \
280     }                                                                           \
281                                                                                 \
282     namespace mpl                                                               \
283     {                                                                           \
284         template<typename>                                                      \
285         struct sequence_tag;                                                    \
286                                                                                 \
287         template<                                                               \
288             BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(                   \
289                 TEMPLATE_PARAMS_SEQ)                                            \
290         >                                                                       \
291         struct sequence_tag<BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)>    \
292         {                                                                       \
293             typedef fusion::fusion_sequence_tag type;                           \
294         };                                                                      \
295                                                                                 \
296         template<                                                               \
297             BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(                   \
298                 TEMPLATE_PARAMS_SEQ)                                            \
299         >                                                                       \
300         struct sequence_tag<                                                    \
301             BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ) const               \
302         >                                                                       \
303         {                                                                       \
304             typedef fusion::fusion_sequence_tag type;                           \
305         };                                                                      \
306     }                                                                           \
307 }
308 
309 #endif
310