1 /*=============================================================================
2     Copyright (c) 2001-2007 Joel de Guzman
3     Copyright (c) 2004 Daniel Wallin
4     Copyright (c) 2011 Thomas Heller
5 
6     Distributed under the Boost Software License, Version 1.0. (See accompanying
7     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 ==============================================================================*/
9 #ifndef PHOENIX_SCOPE_DETAIL_LOCAL_VARIABLE_HPP
10 #define PHOENIX_SCOPE_DETAIL_LOCAL_VARIABLE_HPP
11 
12 #include <boost/mpl/int.hpp>
13 #include <boost/mpl/bool.hpp>
14 #include <boost/mpl/eval_if.hpp>
15 #include <boost/mpl/identity.hpp>
16 #include <boost/fusion/include/at.hpp>
17 #include <boost/fusion/include/value_at.hpp>
18 #include <boost/preprocessor/enum.hpp>
19 #include <boost/preprocessor/repeat.hpp>
20 #include <boost/type_traits/remove_reference.hpp>
21 #include <boost/type_traits/is_reference.hpp>
22 
23 #define BOOST_PHOENIX_MAP_LOCAL_TEMPLATE_PARAM(z, n, data) \
24     typename T##n = unused<n>
25 
26 #define BOOST_PHOENIX_MAP_LOCAL_DISPATCH(z, n, data)  \
27     typedef char(&result##n)[n+2];              \
28     static result##n get(T##n*);
29 
30 namespace boost { namespace phoenix
31 {
32     template <typename Env, typename OuterEnv, typename Locals, typename Map>
33     struct scoped_environment;
34 
35     namespace detail
36     {
37         template <typename Key>
38         struct local
39         {
40             typedef Key key_type;
41         };
42 
43         namespace result_of
44         {
45             template <typename Locals, typename Context>
46             struct initialize_locals;
47 
48             template <typename Context>
49             struct initialize_locals<vector0<>, Context>
50             {
51                 typedef vector0<> type;
52             };
53 
54         #define M1(Z, N, D)                                                     \
55             typename boost::phoenix::result_of::eval<                           \
56                 BOOST_PP_CAT(A, N)                                              \
57               , Context                                                         \
58             >::type                                                             \
59         /**/
60 
61         #define M0(Z, N, D)                                                     \
62             template <BOOST_PHOENIX_typename_A(N), typename Context>            \
63             struct initialize_locals<                                           \
64                 BOOST_PP_CAT(vector, N)<                                        \
65                     BOOST_PHOENIX_A(N)                                          \
66                 >                                                               \
67               , Context                                                         \
68             >                                                                   \
69             {                                                                   \
70                 typedef                                                         \
71                     BOOST_PP_CAT(vector, N)<                                    \
72                         BOOST_PP_ENUM(N, M1, _)                                 \
73                     >                                                           \
74                     type;                                                       \
75             };                                                                  \
76         /**/
77             BOOST_PP_REPEAT_FROM_TO(1, BOOST_PHOENIX_LIMIT, M0, _)
78         #undef M0
79         }
80 
81         template <typename Context>
82         vector0<>
initialize_locals(vector0<> const &,Context const &)83         initialize_locals(vector0<> const &, Context const &)
84         {
85             vector0<> vars;
86             return vars;
87         }
88     #define M2(Z, N, D)                                                         \
89         eval(locals. BOOST_PP_CAT(a, N), ctx)                                   \
90     /**/
91 
92     #define M0(Z, N, D)                                                         \
93         template <BOOST_PHOENIX_typename_A(N), typename Context>                \
94         BOOST_PP_CAT(vector, N)<BOOST_PP_ENUM(N, M1, _)>                        \
95         initialize_locals(                                                      \
96             BOOST_PP_CAT(vector, N)<BOOST_PHOENIX_A(N)> const & locals          \
97           , Context const & ctx                                                 \
98         )                                                                       \
99         {                                                                       \
100             BOOST_PP_CAT(vector, N)<BOOST_PP_ENUM(N, M1, _)> vars               \
101                 = {BOOST_PP_ENUM(N, M2, _)};                                    \
102             return vars;                                                        \
103         }                                                                       \
104     /**/
105         BOOST_PP_REPEAT_FROM_TO(1, BOOST_PHOENIX_LIMIT, M0, _)
106         #undef M0
107         #undef M1
108         #undef M2
109 
110         template <int N>
111         struct unused;
112 
113         template <
114             BOOST_PP_ENUM(
115                 BOOST_PHOENIX_LOCAL_LIMIT
116               , BOOST_PHOENIX_MAP_LOCAL_TEMPLATE_PARAM
117               , _
118             )
119         >
120         struct map_local_index_to_tuple
121         {
122             typedef char(&not_found)[1];
123             static not_found get(...);
124 
125             BOOST_PP_REPEAT(BOOST_PHOENIX_LOCAL_LIMIT, BOOST_PHOENIX_MAP_LOCAL_DISPATCH, _)
126         };
127 
128         template<typename T>
129         T* generate_pointer();
130 
131         template <typename Map, typename Tag>
132         struct get_index
133         {
134             BOOST_STATIC_CONSTANT(int,
135                 value = (
136                     static_cast<int>((sizeof(Map::get(generate_pointer<Tag>()))) / sizeof(char)) - 2
137                 ));
138 
139             // if value == -1, Tag is not found
140             typedef mpl::int_<value> type;
141         };
142 
143 
144         template <typename Local, typename Env>
145         struct apply_local;
146 
147         template <typename Local, typename Env>
148         struct outer_local
149         {
150             typedef typename
151                 apply_local<Local, typename Env::outer_env_type>::type
152             type;
153         };
154 
155         template <typename Locals, int Index>
156         struct get_local_or_void
157         {
158             typedef typename
159                 mpl::eval_if_c<
160                     Index < Locals::size_value
161                   , fusion::result_of::at_c<Locals, Index>
162                   , mpl::identity<fusion::void_>
163                 >::type
164                 type;
165         };
166 
167         template <typename Local, typename Env, int Index>
168         struct get_local_from_index
169         {
170             typedef typename
171                 mpl::eval_if_c<
172                     Index == -1
173                   , outer_local<Local, Env>
174                   , get_local_or_void<typename Env::locals_type, Index>
175                 >::type
176                 type;
177         };
178 
179         template <typename Local, typename Env>
180         struct get_local
181         {
182             static const int index_value = get_index<typename Env::map_type, Local>::value;
183 
184             typedef typename
185                 get_local_from_index<Local, Env, index_value>::type
186             type;
187         };
188 
189         template <typename Local, typename Env>
190         struct apply_local
191         {
192             // $$$ TODO: static assert that Env is a scoped_environment $$$
193             typedef typename get_local<Local, Env>::type type;
194         };
195 
196         template <typename Key>
197         struct eval_local
198         {
199             template <typename RT, int Index, typename Env>
200             static RT
getboost::phoenix::detail::eval_local201             get(Env const& env, mpl::false_)
202             {
203                 return RT(fusion::at_c<Index>(env.locals));
204             }
205 
206             template <typename RT, int Index, typename Env>
207             static RT
getboost::phoenix::detail::eval_local208             get(Env const& env, mpl::true_)
209             {
210                 static const int index_value = get_index<typename Env::outer_env_type::map_type, detail::local<Key> >::value;
211 
212                 return get<RT, index_value>(
213                     env.outer_env
214                   , mpl::bool_<index_value == -1>());
215             }
216 
217             template <typename RT, int Index, typename Env>
218             static RT
getboost::phoenix::detail::eval_local219             get(Env const& env)
220             {
221                 return get<RT, Index>(
222                     env
223                   , mpl::bool_<Index == -1>());
224             }
225         };
226     }
227 }}
228 
229 #undef BOOST_PHOENIX_MAP_LOCAL_TEMPLATE_PARAM
230 #undef BOOST_PHOENIX_MAP_LOCAL_DISPATCH
231 
232 #endif
233