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/preprocessor/logical/not.hpp>
33 #include <boost/mpl/bool.hpp>
34 #include <boost/mpl/tag.hpp>
35 #include <boost/mpl/eval_if.hpp>
36 #include <boost/mpl/identity.hpp>
37 #include <boost/type_traits/is_const.hpp>
38 #include <boost/type_traits/add_const.hpp>
39 #include <boost/type_traits/add_reference.hpp>
40 
41 #include <boost/typeof/typeof.hpp>
42 
43 
44 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME_TEMPLATE_PARAMS(SEQ)              \
45     BOOST_PP_SEQ_HEAD(SEQ)<BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TAIL(SEQ))>           \
46     BOOST_PP_EMPTY()
47 
48 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(SEQ)                              \
49     BOOST_PP_IF(                                                                \
50         BOOST_PP_SEQ_HEAD(SEQ),                                                 \
51         BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME_TEMPLATE_PARAMS,                  \
52         BOOST_PP_SEQ_HEAD)(BOOST_PP_SEQ_TAIL(SEQ))
53 
54 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS_IMPL_C(R, _, ELEM)     \
55     (typename ELEM)
56 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS_IMPL(SEQ)              \
57     BOOST_PP_SEQ_ENUM(                                                          \
58         BOOST_PP_SEQ_FOR_EACH(                                                  \
59             BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS_IMPL_C,            \
60             _,                                                                  \
61             BOOST_PP_SEQ_TAIL(SEQ)))
62 #define BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(SEQ)                   \
63     BOOST_PP_IF(                                                                \
64         BOOST_PP_SEQ_HEAD(SEQ),                                                 \
65         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS_IMPL,                  \
66         BOOST_PP_TUPLE_EAT(1))(SEQ)
67 
68 #ifdef BOOST_MSVC
69 #   define BOOST_FUSION_ATTRIBUTE_TYPEOF(                                       \
70         NAME_SEQ, ATTRIBUTE, ATTRIBUTE_TUPLE_SIZE, PREFIX, TEMPLATE_PARAMS_SEQ) \
71                                                                                 \
72     BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS(                    \
73         TEMPLATE_PARAMS_SEQ)                                                    \
74                                                                                 \
75     struct deduced_attr_type {                                                  \
76       static const BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)& obj;        \
77       typedef                                                                   \
78       BOOST_PP_IF(BOOST_FUSION_ADAPT_IS_TPL(TEMPLATE_PARAMS_SEQ), typename, )   \
79       BOOST_TYPEOF( PREFIX() obj.BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPLE_SIZE,      \
80             0, ATTRIBUTE))                                                      \
81       type;                                                                     \
82     };                                                                          \
83                                                                                 \
84     typedef                                                                     \
85         BOOST_PP_IF(BOOST_FUSION_ADAPT_IS_TPL(TEMPLATE_PARAMS_SEQ), typename, ) \
86         deduced_attr_type::type attribute_type;
87 
88 #else
89 #   define BOOST_FUSION_ATTRIBUTE_TYPEOF(                                       \
90         NAME_SEQ, ATTRIBUTE, ATTRIBUTE_TUPLE_SIZE, PREFIX, TEMPLATE_PARAMS_SEQ) \
91                                                                                 \
92     struct deduced_attr_type {                                                  \
93       static const BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)& obj;        \
94       typedef BOOST_TYPEOF(                                                     \
95           PREFIX() obj.BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPLE_SIZE, 0, ATTRIBUTE)) \
96       type;                                                                     \
97     };                                                                          \
98                                                                                 \
99     typedef                                                                     \
100         BOOST_PP_IF(BOOST_FUSION_ADAPT_IS_TPL(TEMPLATE_PARAMS_SEQ), typename, ) \
101         deduced_attr_type::type attribute_type;
102 
103 #endif
104 
105 #define BOOST_FUSION_ATTRIBUTE_GIVENTYPE(                                       \
106     NAME_SEQ, ATTRIBUTE, ATTRIBUTE_TUPLE_SIZE, PREFIX, TEMPLATE_PARAMS_SEQ)     \
107     typedef                                                                     \
108         BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPLE_SIZE, 0, ATTRIBUTE) attribute_type;
109 
110 
111 #ifdef BOOST_NO_PARTIAL_SPECIALIZATION_IMPLICIT_DEFAULT_ARGS
112 #   define BOOST_FUSION_ADAPT_STRUCT_TAG_OF_SPECIALIZATION(                     \
113         MODIFIER, TEMPLATE_PARAMS_SEQ, NAME_SEQ, TAG)                           \
114                                                                                 \
115     template<                                                                   \
116         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(TEMPLATE_PARAMS_SEQ)   \
117     >                                                                           \
118     struct tag_of<                                                              \
119         BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ) MODIFIER                \
120       , void                                                                    \
121     >                                                                           \
122     {                                                                           \
123         typedef TAG type;                                                       \
124     };
125 #else
126 #   define BOOST_FUSION_ADAPT_STRUCT_TAG_OF_SPECIALIZATION(                     \
127         MODIFIER, TEMPLATE_PARAMS_SEQ, NAME_SEQ, TAG)                           \
128                                                                                 \
129     template<                                                                   \
130         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(TEMPLATE_PARAMS_SEQ)   \
131     >                                                                           \
132     struct tag_of<BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ) MODIFIER>     \
133     {                                                                           \
134         typedef TAG type;                                                       \
135     };
136 #endif
137 
138 #define BOOST_FUSION_ADAPT_STRUCT_BASE_UNPACK_AND_CALL(R,DATA,I,ATTRIBUTE)      \
139     BOOST_PP_TUPLE_ELEM(4,0,DATA)(                                              \
140         BOOST_PP_TUPLE_ELEM(4,1,DATA),                                          \
141         BOOST_PP_TUPLE_ELEM(4,2,DATA),                                          \
142         BOOST_PP_TUPLE_ELEM(4,3,DATA),                                          \
143         I,                                                                      \
144         ATTRIBUTE)
145 
146 #ifdef BOOST_MSVC
147 #   define BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAM(R,_,ELEM)     \
148         typedef ELEM ELEM;
149 #   define BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS_IMPL(SEQ)    \
150         BOOST_PP_SEQ_FOR_EACH(                                                  \
151             BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAM,             \
152             _,                                                                  \
153             BOOST_PP_SEQ_TAIL(SEQ))
154 #   define BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS(SEQ)         \
155         BOOST_PP_IF(                                                            \
156             BOOST_PP_SEQ_HEAD(SEQ),                                             \
157             BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS_IMPL,       \
158             BOOST_PP_TUPLE_EAT(1))(SEQ)
159 #else
160 #   define BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS(SEQ)
161 #endif
162 
163 #define BOOST_FUSION_ADAPT_STRUCT_C_BASE(                                       \
164     TEMPLATE_PARAMS_SEQ,NAME_SEQ,IS_VIEW,                                       \
165     I,PREFIX,ATTRIBUTE,ATTRIBUTE_TUPLE_SIZE,                                    \
166     DEDUCE_TYPE)                                                                \
167                                                                                 \
168     template<                                                                   \
169         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(TEMPLATE_PARAMS_SEQ)   \
170     >                                                                           \
171     struct access::struct_member<                                               \
172         BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)                         \
173       , I                                                                       \
174     >                                                                           \
175     {                                                                           \
176         BOOST_PP_IF(DEDUCE_TYPE,                                                \
177             BOOST_FUSION_ATTRIBUTE_TYPEOF, BOOST_FUSION_ATTRIBUTE_GIVENTYPE)(   \
178                 NAME_SEQ,                                                       \
179                 ATTRIBUTE,                                                      \
180                 ATTRIBUTE_TUPLE_SIZE,                                           \
181                 PREFIX,                                                         \
182                 TEMPLATE_PARAMS_SEQ)                                            \
183                                                                                 \
184         BOOST_FUSION_ADAPT_STRUCT_MSVC_REDEFINE_TEMPLATE_PARAMS(                \
185             TEMPLATE_PARAMS_SEQ)                                                \
186                                                                                 \
187         typedef attribute_type type;                                            \
188                                                                                 \
189         template<typename Seq>                                                  \
190         struct apply                                                            \
191         {                                                                       \
192             typedef typename                                                    \
193                 add_reference<                                                  \
194                     typename mpl::eval_if<                                      \
195                         is_const<Seq>                                           \
196                       , add_const<attribute_type>                               \
197                       , mpl::identity<attribute_type>                           \
198                     >::type                                                     \
199                 >::type                                                         \
200             type;                                                               \
201                                                                                 \
202             BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED                            \
203             static type                                                         \
204             call(Seq& seq)                                                      \
205             {                                                                   \
206                 return seq.PREFIX()                                             \
207                     BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPLE_SIZE,                   \
208                         BOOST_PP_NOT(DEDUCE_TYPE), ATTRIBUTE);                  \
209             }                                                                   \
210         };                                                                      \
211     };                                                                          \
212                                                                                 \
213     template<                                                                   \
214         BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(TEMPLATE_PARAMS_SEQ)   \
215     >                                                                           \
216     struct struct_member_name<                                                  \
217         BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)                         \
218       , I                                                                       \
219     >                                                                           \
220     {                                                                           \
221         typedef char const* type;                                               \
222                                                                                 \
223         BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED                                \
224         static type                                                             \
225         call()                                                                  \
226         {                                                                       \
227             return BOOST_PP_STRINGIZE(                                          \
228                BOOST_PP_TUPLE_ELEM(ATTRIBUTE_TUPLE_SIZE,                        \
229                    BOOST_PP_NOT(DEDUCE_TYPE), ATTRIBUTE));                      \
230         }                                                                       \
231     };
232 
233 #define BOOST_FUSION_ADAPT_STRUCT_BASE(                                         \
234     TEMPLATE_PARAMS_SEQ,                                                        \
235     NAME_SEQ,                                                                   \
236     TAG,                                                                        \
237     IS_VIEW,                                                                    \
238     ATTRIBUTES_SEQ,                                                             \
239     ATTRIBUTES_CALLBACK)                                                        \
240                                                                                 \
241 namespace boost                                                                 \
242 {                                                                               \
243     namespace fusion                                                            \
244     {                                                                           \
245         namespace traits                                                        \
246         {                                                                       \
247             BOOST_FUSION_ADAPT_STRUCT_TAG_OF_SPECIALIZATION(                    \
248                 BOOST_PP_EMPTY(), TEMPLATE_PARAMS_SEQ, NAME_SEQ, TAG)           \
249             BOOST_FUSION_ADAPT_STRUCT_TAG_OF_SPECIALIZATION(                    \
250                 const, TEMPLATE_PARAMS_SEQ, NAME_SEQ, TAG)                      \
251         }                                                                       \
252                                                                                 \
253         namespace extension                                                     \
254         {                                                                       \
255             BOOST_PP_IF(                                                        \
256                 BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(ATTRIBUTES_SEQ)),                \
257                 BOOST_PP_SEQ_FOR_EACH_I_R,                                      \
258                 BOOST_PP_TUPLE_EAT(4))(                                         \
259                     1,                                                          \
260                     BOOST_FUSION_ADAPT_STRUCT_BASE_UNPACK_AND_CALL,             \
261                     (ATTRIBUTES_CALLBACK,TEMPLATE_PARAMS_SEQ,NAME_SEQ, IS_VIEW),\
262                     BOOST_PP_SEQ_TAIL(ATTRIBUTES_SEQ))                          \
263                                                                                 \
264             template<                                                           \
265                 BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(               \
266                     TEMPLATE_PARAMS_SEQ)                                        \
267             >                                                                   \
268             struct struct_size<BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)> \
269               : mpl::int_<BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(ATTRIBUTES_SEQ))>      \
270             {};                                                                 \
271                                                                                 \
272             template<                                                           \
273                 BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(               \
274                     TEMPLATE_PARAMS_SEQ)                                        \
275             >                                                                   \
276             struct struct_is_view<                                              \
277                 BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)                 \
278             >                                                                   \
279               : mpl::BOOST_PP_IIF(IS_VIEW,true_,false_)                         \
280             {};                                                                 \
281         }                                                                       \
282     }                                                                           \
283                                                                                 \
284     namespace mpl                                                               \
285     {                                                                           \
286         template<typename>                                                      \
287         struct sequence_tag;                                                    \
288                                                                                 \
289         template<                                                               \
290             BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(                   \
291                 TEMPLATE_PARAMS_SEQ)                                            \
292         >                                                                       \
293         struct sequence_tag<BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ)>    \
294         {                                                                       \
295             typedef fusion::fusion_sequence_tag type;                           \
296         };                                                                      \
297                                                                                 \
298         template<                                                               \
299             BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS(                   \
300                 TEMPLATE_PARAMS_SEQ)                                            \
301         >                                                                       \
302         struct sequence_tag<                                                    \
303             BOOST_FUSION_ADAPT_STRUCT_UNPACK_NAME(NAME_SEQ) const               \
304         >                                                                       \
305         {                                                                       \
306             typedef fusion::fusion_sequence_tag type;                           \
307         };                                                                      \
308     }                                                                           \
309 }
310 
311 #endif
312