1 ///////////////////////////////////////////////////////////////////////////////
2 // env.hpp
3 // Helpers for producing and consuming tranform env variables.
4 //
5 //  Copyright 2012 Eric Niebler. Distributed under the Boost
6 //  Software License, Version 1.0. (See accompanying file
7 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_PROTO_TRANSFORM_ENV_HPP_EAN_18_07_2012
10 #define BOOST_PROTO_TRANSFORM_ENV_HPP_EAN_18_07_2012
11 
12 #include <boost/config.hpp>
13 #include <boost/detail/workaround.hpp>
14 #include <boost/ref.hpp>
15 #include <boost/utility/enable_if.hpp>
16 #include <boost/type_traits/is_const.hpp>
17 #include <boost/type_traits/is_same.hpp>
18 #include <boost/type_traits/add_const.hpp>
19 #include <boost/type_traits/add_reference.hpp>
20 #include <boost/type_traits/remove_const.hpp>
21 #include <boost/mpl/assert.hpp>
22 #include <boost/mpl/bool.hpp>
23 #include <boost/mpl/if.hpp>
24 #include <boost/mpl/not.hpp>
25 #include <boost/proto/proto_fwd.hpp>
26 #include <boost/proto/transform/impl.hpp>
27 #include <boost/proto/detail/poly_function.hpp>
28 #include <boost/proto/detail/is_noncopyable.hpp>
29 
30 #ifdef _MSC_VER
31 # pragma warning(push)
32 # pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
33 #endif
34 
35 namespace boost
36 {
37     namespace proto
38     {
39         namespace detail
40         {
41             template<typename T>
42             struct value_type
43             {
44                 typedef typename remove_const<T>::type value;
45                 typedef typename add_reference<T>::type reference;
46                 typedef typename mpl::if_c<is_noncopyable<T>::value, reference, value>::type type;
47             };
48 
49             template<typename T>
50             struct value_type<T &>
51             {
52                 typedef T &value;
53                 typedef T &reference;
54                 typedef T &type;
55             };
56         }
57 
58     #define BOOST_PROTO_DEFINE_ENV_VAR(TAG, NAME)                                                   \
59         struct TAG                                                                                  \
60         {                                                                                           \
61             template<typename Value>                                                                \
62             boost::proto::env<TAG, Value &> const                                                   \
63                 operator =(boost::reference_wrapper<Value> &value) const                            \
64             {                                                                                       \
65                 return boost::proto::env<TAG, Value &>(value.get());                                \
66             }                                                                                       \
67             template<typename Value>                                                                \
68             boost::proto::env<TAG, Value &> const                                                   \
69                 operator =(boost::reference_wrapper<Value> const &value) const                      \
70             {                                                                                       \
71                 return boost::proto::env<TAG, Value &>(value.get());                                \
72             }                                                                                       \
73             template<typename Value>                                                                \
74             typename boost::disable_if_c<                                                           \
75                 boost::is_const<Value>::value                                                       \
76               , boost::proto::env<TAG, typename boost::proto::detail::value_type<Value>::type>      \
77             >::type const operator =(Value &value) const                                            \
78             {                                                                                       \
79                 return boost::proto::env<TAG, typename boost::proto::detail::value_type<Value>::type>(value); \
80             }                                                                                       \
81             template<typename Value>                                                                \
82             boost::proto::env<TAG, typename boost::proto::detail::value_type<Value const>::type> const \
83                 operator =(Value const &value) const                                                \
84             {                                                                                       \
85                 return boost::proto::env<TAG, typename boost::proto::detail::value_type<Value const>::type>(value); \
86             }                                                                                       \
87         };                                                                                          \
88                                                                                                     \
89         TAG const NAME = {}                                                                         \
90         /**/
91 
92         namespace envns_
93         {
94             ////////////////////////////////////////////////////////////////////////////////////////////
95             // env
96             // A transform env is a slot-based storage mechanism, accessible by tag.
97             template<typename Key, typename Value, typename Base /*= empty_env*/>
98             struct env
99               : private Base
100             {
101             private:
102                 Value value_;
103 
104             public:
105                 typedef Value value_type;
106                 typedef typename add_reference<Value>::type reference;
107                 typedef typename add_reference<typename add_const<Value>::type>::type const_reference;
108                 typedef void proto_environment_; ///< INTERNAL ONLY
109 
envboost::proto::envns_::env110                 explicit env(const_reference value, Base const &base = Base())
111                   : Base(base)
112                   , value_(value)
113                 {}
114 
115                 #if BOOST_WORKAROUND(__GNUC__, == 3) || (BOOST_WORKAROUND(__GNUC__, == 4) && __GNUC_MINOR__ <= 2)
116                 /// INTERNAL ONLY
117                 struct found
118                 {
119                     typedef Value type;
120                     typedef typename add_reference<typename add_const<Value>::type>::type const_reference;
121                 };
122 
123                 template<typename OtherKey, typename OtherValue = key_not_found>
124                 struct lookup
125                   : mpl::if_c<
126                         is_same<OtherKey, Key>::value
127                       , found
128                       , typename Base::template lookup<OtherKey, OtherValue>
129                     >::type
130                 {};
131                 #else
132                 /// INTERNAL ONLY
133                 template<typename OtherKey, typename OtherValue = key_not_found>
134                 struct lookup
135                   : Base::template lookup<OtherKey, OtherValue>
136                 {};
137 
138                 /// INTERNAL ONLY
139                 template<typename OtherValue>
140                 struct lookup<Key, OtherValue>
141                 {
142                     typedef Value type;
143                     typedef typename add_reference<typename add_const<Value>::type>::type const_reference;
144                 };
145                 #endif
146 
147                 // For key-based lookups not intended to fail
148                 using Base::operator[];
operator []boost::proto::envns_::env149                 const_reference operator[](Key) const
150                 {
151                     return this->value_;
152                 }
153 
154                 // For key-based lookups that can fail, use the default if key not found.
155                 using Base::at;
156                 template<typename T>
atboost::proto::envns_::env157                 const_reference at(Key, T const &) const
158                 {
159                     return this->value_;
160                 }
161             };
162 
163             // define proto::data_type type and proto::data global
164             BOOST_PROTO_DEFINE_ENV_VAR(data_type, data);
165         }
166 
167         using envns_::data;
168 
169         namespace functional
170         {
171             ////////////////////////////////////////////////////////////////////////////////////////
172             // as_env
173             struct as_env
174             {
175                 BOOST_PROTO_CALLABLE()
176                 BOOST_PROTO_POLY_FUNCTION()
177 
178                 /// INTERNAL ONLY
179                 template<typename T, bool B = is_env<T>::value>
180                 struct impl
181                 {
182                     typedef env<data_type, typename detail::value_type<T>::type> result_type;
183 
operator ()boost::proto::functional::as_env::impl184                     result_type const operator()(detail::arg<T> t) const
185                     {
186                         return result_type(t());
187                     }
188                 };
189 
190                 /// INTERNAL ONLY
191                 template<typename T>
192                 struct impl<T, true>
193                 {
194                     typedef T result_type;
195 
operator ()boost::proto::functional::as_env::impl196                     typename add_const<T>::type operator()(detail::arg<T> t) const
197                     {
198                         return t();
199                     }
200                 };
201 
202                 template<typename Sig>
203                 struct result;
204 
205                 template<typename This, typename T>
206                 struct result<This(T)>
207                 {
208                     typedef typename impl<typename detail::normalize_arg<T>::type>::result_type type;
209                 };
210 
211                 template<typename T>
212                 typename impl<typename detail::normalize_arg<T &>::type>::result_type const
operator ()boost::proto::functional::as_env213                     operator()(T &t BOOST_PROTO_DISABLE_IF_IS_CONST(T)) const
214                 {
215                     return impl<typename detail::normalize_arg<T &>::type>()(
216                         static_cast<typename detail::normalize_arg<T &>::reference>(t)
217                     );
218                 }
219 
220                 template<typename T>
221                 typename impl<typename detail::normalize_arg<T const &>::type>::result_type const
operator ()boost::proto::functional::as_env222                     operator()(T const &t) const
223                 {
224                     return impl<typename detail::normalize_arg<T const &>::type>()(
225                         static_cast<typename detail::normalize_arg<T const &>::reference>(t)
226                     );
227                 }
228             };
229 
230             ////////////////////////////////////////////////////////////////////////////////////////
231             // has_env_var
232             template<typename Key>
233             struct has_env_var
234               : detail::poly_function<has_env_var<Key> >
235             {
236                 BOOST_PROTO_CALLABLE()
237 
238                 template<typename Env, bool IsEnv = is_env<Env>::value>
239                 struct impl
240                 {
241                     typedef
242                         mpl::not_<
243                             is_same<
244                                 typename remove_reference<Env>::type::template lookup<Key>::type
245                               , key_not_found
246                             >
247                         >
248                     result_type;
249 
operator ()boost::proto::functional::has_env_var::impl250                     result_type operator()(detail::arg<Env>) const
251                     {
252                         return result_type();
253                     }
254                 };
255 
256                 template<typename Env>
257                 struct impl<Env, false>
258                 {
259                     typedef mpl::false_ result_type;
260 
operator ()boost::proto::functional::has_env_var::impl261                     result_type operator()(detail::arg<Env>) const
262                     {
263                         return result_type();
264                     }
265                 };
266             };
267 
268             template<>
269             struct has_env_var<data_type>
270               : detail::poly_function<has_env_var<data_type> >
271             {
272                 BOOST_PROTO_CALLABLE()
273 
274                 template<typename Env, bool IsEnv = is_env<Env>::value>
275                 struct impl
276                 {
277                     typedef
278                         mpl::not_<
279                             is_same<
280                                 typename remove_reference<Env>::type::template lookup<data_type>::type
281                               , key_not_found
282                             >
283                         >
284                     result_type;
285 
operator ()boost::proto::functional::has_env_var::impl286                     result_type operator()(detail::arg<Env>) const
287                     {
288                         return result_type();
289                     }
290                 };
291 
292                 template<typename Env>
293                 struct impl<Env, false>
294                 {
295                     typedef mpl::true_ result_type;
296 
operator ()boost::proto::functional::has_env_var::impl297                     result_type operator()(detail::arg<Env>) const
298                     {
299                         return result_type();
300                     }
301                 };
302             };
303 
304             ////////////////////////////////////////////////////////////////////////////////////////
305             // env_var
306             template<typename Key>
307             struct env_var
308               : detail::poly_function<env_var<Key> >
309             {
310                 BOOST_PROTO_CALLABLE()
311 
312                 template<typename Env>
313                 struct impl
314                 {
315                     typedef
316                         typename remove_reference<Env>::type::template lookup<Key>::type
317                     result_type;
318 
operator ()boost::proto::functional::env_var::impl319                     result_type operator()(detail::arg<Env> e) const
320                     {
321                         return e()[Key()];
322                     }
323                 };
324             };
325 
326             template<>
327             struct env_var<data_type>
328               : detail::poly_function<env_var<data_type> >
329             {
330                 BOOST_PROTO_CALLABLE()
331 
332                 template<typename Env, bool B = is_env<Env>::value>
333                 struct impl
334                 {
335                     typedef Env result_type;
336 
operator ()boost::proto::functional::env_var::impl337                     result_type operator()(detail::arg<Env> e) const
338                     {
339                         return e();
340                     }
341                 };
342 
343                 template<typename Env>
344                 struct impl<Env, true>
345                 {
346                     typedef
347                         typename remove_reference<Env>::type::template lookup<data_type>::type
348                     result_type;
349 
operator ()boost::proto::functional::env_var::impl350                     result_type operator()(detail::arg<Env> e) const
351                     {
352                         return e()[proto::data];
353                     }
354                 };
355             };
356         }
357 
358         namespace result_of
359         {
360             template<typename T>
361             struct as_env
362               : BOOST_PROTO_RESULT_OF<functional::as_env(T)>
363             {};
364 
365             template<typename Env, typename Key>
366             struct has_env_var
367               : BOOST_PROTO_RESULT_OF<functional::has_env_var<Key>(Env)>::type
368             {};
369 
370             template<typename Env, typename Key>
371             struct env_var
372               : BOOST_PROTO_RESULT_OF<functional::env_var<Key>(Env)>
373             {};
374         }
375 
376         ////////////////////////////////////////////////////////////////////////////////////////////
377         // as_env
378         template<typename T>
as_env(T & t BOOST_PROTO_DISABLE_IF_IS_CONST (T))379         typename proto::result_of::as_env<T &>::type const as_env(T &t BOOST_PROTO_DISABLE_IF_IS_CONST(T))
380         {
381             return proto::functional::as_env()(t);
382         }
383 
384         template<typename T>
as_env(T const & t)385         typename proto::result_of::as_env<T const &>::type const as_env(T const &t)
386         {
387             return proto::functional::as_env()(t);
388         }
389 
390         ////////////////////////////////////////////////////////////////////////////////////////////
391         // has_env_var
392         template<typename Key, typename Env>
has_env_var(Env & e BOOST_PROTO_DISABLE_IF_IS_CONST (Env))393         typename proto::result_of::has_env_var<Env &, Key>::type has_env_var(Env &e BOOST_PROTO_DISABLE_IF_IS_CONST(Env))
394         {
395             return functional::has_env_var<Key>()(e);
396         }
397 
398         template<typename Key, typename Env>
has_env_var(Env const & e)399         typename proto::result_of::has_env_var<Env const &, Key>::type has_env_var(Env const &e)
400         {
401             return functional::has_env_var<Key>()(e);
402         }
403 
404         ////////////////////////////////////////////////////////////////////////////////////////////
405         // env_var
406         template<typename Key, typename Env>
env_var(Env & e BOOST_PROTO_DISABLE_IF_IS_CONST (Env))407         typename proto::result_of::env_var<Env &, Key>::type env_var(Env &e BOOST_PROTO_DISABLE_IF_IS_CONST(Env))
408         {
409             return functional::env_var<Key>()(e);
410         }
411 
412         template<typename Key, typename Env>
env_var(Env const & e)413         typename proto::result_of::env_var<Env const &, Key>::type env_var(Env const &e)
414         {
415             return functional::env_var<Key>()(e);
416         }
417 
418         namespace envns_
419         {
420             ////////////////////////////////////////////////////////////////////////////////////////
421             // env operator,
422             template<typename T, typename T1, typename V1>
423             inline typename disable_if_c<
424                 is_const<T>::value
425               , env<T1, V1, BOOST_PROTO_UNCVREF(typename result_of::as_env<T &>::type)>
operator ,(T & t,env<T1,V1> const & head)426             >::type const operator,(T &t, env<T1, V1> const &head)
427             {
428                 return env<T1, V1, BOOST_PROTO_UNCVREF(typename result_of::as_env<T &>::type)>(
429                     head[T1()]
430                   , proto::as_env(t)
431                 );
432             }
433 
434             template<typename T, typename T1, typename V1>
435             inline env<T1, V1, BOOST_PROTO_UNCVREF(typename result_of::as_env<T const &>::type)> const
operator ,(T const & t,env<T1,V1> const & head)436                 operator,(T const &t, env<T1, V1> const &head)
437             {
438                 return env<T1, V1, BOOST_PROTO_UNCVREF(typename result_of::as_env<T const &>::type)>(
439                     head[T1()]
440                   , proto::as_env(t)
441                 );
442             }
443         }
444 
445         ////////////////////////////////////////////////////////////////////////////////////////////
446         // _env_var
447         template<typename Key>
448         struct _env_var
449           : proto::transform<_env_var<Key> >
450         {
451             template<typename Expr, typename State, typename Data>
452             struct impl
453               : transform_impl<Expr, State, Data>
454             {
455                 typedef typename impl::data::template lookup<Key>::type result_type;
456                 BOOST_MPL_ASSERT_NOT((is_same<result_type, key_not_found>)); // lookup failed
457 
BOOST_PROTO_RETURN_TYPE_STRICT_LOOSEboost::proto::_env_var::impl458                 BOOST_PROTO_RETURN_TYPE_STRICT_LOOSE(result_type, typename impl::data::template lookup<Key>::const_reference)
459                 operator ()(
460                     typename impl::expr_param
461                   , typename impl::state_param
462                   , typename impl::data_param d
463                 ) const
464                 {
465                     return d[Key()];
466                 }
467             };
468         };
469 
470         struct _env
471           : transform<_env>
472         {
473             template<typename Expr, typename State, typename Data>
474             struct impl
475               : transform_impl<Expr, State, Data>
476             {
477                 typedef Data result_type;
478 
BOOST_PROTO_RETURN_TYPE_STRICT_LOOSEboost::proto::_env::impl479                 BOOST_PROTO_RETURN_TYPE_STRICT_LOOSE(result_type, typename impl::data_param)
480                 operator ()(
481                     typename impl::expr_param
482                   , typename impl::state_param
483                   , typename impl::data_param d
484                 ) const
485                 {
486                     return d;
487                 }
488             };
489         };
490 
491         /// INTERNAL ONLY
492         template<typename Key>
493         struct is_callable<_env_var<Key> >
494           : mpl::true_
495         {};
496 
497         /// INTERNAL ONLY
498         template<typename Key>
499         struct is_callable<functional::has_env_var<Key> >
500           : mpl::true_
501         {};
502 
503         /// INTERNAL ONLY
504         template<typename Key>
505         struct is_callable<functional::env_var<Key> >
506           : mpl::true_
507         {};
508     }
509 }
510 
511 #ifdef _MSC_VER
512 # pragma warning(pop)
513 #endif
514 
515 #endif
516