1 ///////////////////////////////////////////////////////////////////////////////
3 // Helpers for producing and consuming tranform env variables.
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)
9 #ifndef BOOST_PROTO_TRANSFORM_ENV_HPP_EAN_18_07_2012
10 #define BOOST_PROTO_TRANSFORM_ENV_HPP_EAN_18_07_2012
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>
31 # pragma warning(push)
32 # pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
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;
50 struct value_type<T &>
58 #define BOOST_PROTO_DEFINE_ENV_VAR(TAG, NAME) \
61 template<typename Value> \
62 boost::proto::env<TAG, Value &> const \
63 operator =(boost::reference_wrapper<Value> &value) const \
65 return boost::proto::env<TAG, Value &>(value.get()); \
67 template<typename Value> \
68 boost::proto::env<TAG, Value &> const \
69 operator =(boost::reference_wrapper<Value> const &value) const \
71 return boost::proto::env<TAG, Value &>(value.get()); \
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 \
79 return boost::proto::env<TAG, typename boost::proto::detail::value_type<Value>::type>(value); \
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 \
85 return boost::proto::env<TAG, typename boost::proto::detail::value_type<Value const>::type>(value); \
94 ////////////////////////////////////////////////////////////////////////////////////////////
96 // A transform env is a slot-based storage mechanism, accessible by tag.
97 template<typename Key, typename Value, typename Base /*= empty_env*/>
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
110 explicit env(const_reference value, Base const &base = Base())
115 #if BOOST_WORKAROUND(__GNUC__, == 3) || (BOOST_WORKAROUND(__GNUC__, == 4) && __GNUC_MINOR__ <= 2)
120 typedef typename add_reference<typename add_const<Value>::type>::type const_reference;
123 template<typename OtherKey, typename OtherValue = key_not_found>
126 is_same<OtherKey, Key>::value
128 , typename Base::template lookup<OtherKey, OtherValue>
133 template<typename OtherKey, typename OtherValue = key_not_found>
135 : Base::template lookup<OtherKey, OtherValue>
139 template<typename OtherValue>
140 struct lookup<Key, OtherValue>
143 typedef typename add_reference<typename add_const<Value>::type>::type const_reference;
147 // For key-based lookups not intended to fail
148 using Base::operator[];
149 const_reference operator[](Key) const
154 // For key-based lookups that can fail, use the default if key not found.
157 const_reference at(Key, T const &) const
163 // define proto::data_type type and proto::data global
164 BOOST_PROTO_DEFINE_ENV_VAR(data_type, data);
171 ////////////////////////////////////////////////////////////////////////////////////////
175 BOOST_PROTO_CALLABLE()
176 BOOST_PROTO_POLY_FUNCTION()
179 template<typename T, bool B = is_env<T>::value>
182 typedef env<data_type, typename detail::value_type<T>::type> result_type;
184 result_type const operator()(detail::arg<T> t) const
186 return result_type(t());
194 typedef T result_type;
196 typename add_const<T>::type operator()(detail::arg<T> t) const
202 template<typename Sig>
205 template<typename This, typename T>
206 struct result<This(T)>
208 typedef typename impl<typename detail::normalize_arg<T>::type>::result_type type;
212 typename impl<typename detail::normalize_arg<T &>::type>::result_type const
213 operator()(T &t BOOST_PROTO_DISABLE_IF_IS_CONST(T)) const
215 return impl<typename detail::normalize_arg<T &>::type>()(
216 static_cast<typename detail::normalize_arg<T &>::reference>(t)
221 typename impl<typename detail::normalize_arg<T const &>::type>::result_type const
222 operator()(T const &t) const
224 return impl<typename detail::normalize_arg<T const &>::type>()(
225 static_cast<typename detail::normalize_arg<T const &>::reference>(t)
230 ////////////////////////////////////////////////////////////////////////////////////////
232 template<typename Key>
234 : detail::poly_function<has_env_var<Key> >
236 BOOST_PROTO_CALLABLE()
238 template<typename Env, bool IsEnv = is_env<Env>::value>
244 typename remove_reference<Env>::type::template lookup<Key>::type
250 result_type operator()(detail::arg<Env>) const
252 return result_type();
256 template<typename Env>
257 struct impl<Env, false>
259 typedef mpl::false_ result_type;
261 result_type operator()(detail::arg<Env>) const
263 return result_type();
269 struct has_env_var<data_type>
270 : detail::poly_function<has_env_var<data_type> >
272 BOOST_PROTO_CALLABLE()
274 template<typename Env, bool IsEnv = is_env<Env>::value>
280 typename remove_reference<Env>::type::template lookup<data_type>::type
286 result_type operator()(detail::arg<Env>) const
288 return result_type();
292 template<typename Env>
293 struct impl<Env, false>
295 typedef mpl::true_ result_type;
297 result_type operator()(detail::arg<Env>) const
299 return result_type();
304 ////////////////////////////////////////////////////////////////////////////////////////
306 template<typename Key>
308 : detail::poly_function<env_var<Key> >
310 BOOST_PROTO_CALLABLE()
312 template<typename Env>
316 typename remove_reference<Env>::type::template lookup<Key>::type
319 result_type operator()(detail::arg<Env> e) const
327 struct env_var<data_type>
328 : detail::poly_function<env_var<data_type> >
330 BOOST_PROTO_CALLABLE()
332 template<typename Env, bool B = is_env<Env>::value>
335 typedef Env result_type;
337 result_type operator()(detail::arg<Env> e) const
343 template<typename Env>
344 struct impl<Env, true>
347 typename remove_reference<Env>::type::template lookup<data_type>::type
350 result_type operator()(detail::arg<Env> e) const
352 return e()[proto::data];
362 : BOOST_PROTO_RESULT_OF<functional::as_env(T)>
365 template<typename Env, typename Key>
367 : BOOST_PROTO_RESULT_OF<functional::has_env_var<Key>(Env)>::type
370 template<typename Env, typename Key>
372 : BOOST_PROTO_RESULT_OF<functional::env_var<Key>(Env)>
376 ////////////////////////////////////////////////////////////////////////////////////////////
379 typename proto::result_of::as_env<T &>::type const as_env(T &t BOOST_PROTO_DISABLE_IF_IS_CONST(T))
381 return proto::functional::as_env()(t);
385 typename proto::result_of::as_env<T const &>::type const as_env(T const &t)
387 return proto::functional::as_env()(t);
390 ////////////////////////////////////////////////////////////////////////////////////////////
392 template<typename Key, typename Env>
393 typename proto::result_of::has_env_var<Env &, Key>::type has_env_var(Env &e BOOST_PROTO_DISABLE_IF_IS_CONST(Env))
395 return functional::has_env_var<Key>()(e);
398 template<typename Key, typename Env>
399 typename proto::result_of::has_env_var<Env const &, Key>::type has_env_var(Env const &e)
401 return functional::has_env_var<Key>()(e);
404 ////////////////////////////////////////////////////////////////////////////////////////////
406 template<typename Key, typename Env>
407 typename proto::result_of::env_var<Env &, Key>::type env_var(Env &e BOOST_PROTO_DISABLE_IF_IS_CONST(Env))
409 return functional::env_var<Key>()(e);
412 template<typename Key, typename Env>
413 typename proto::result_of::env_var<Env const &, Key>::type env_var(Env const &e)
415 return functional::env_var<Key>()(e);
420 ////////////////////////////////////////////////////////////////////////////////////////
422 template<typename T, typename T1, typename V1>
423 inline typename disable_if_c<
425 , env<T1, V1, BOOST_PROTO_UNCVREF(typename result_of::as_env<T &>::type)>
426 >::type const operator,(T &t, env<T1, V1> const &head)
428 return env<T1, V1, BOOST_PROTO_UNCVREF(typename result_of::as_env<T &>::type)>(
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
436 operator,(T const &t, env<T1, V1> const &head)
438 return env<T1, V1, BOOST_PROTO_UNCVREF(typename result_of::as_env<T const &>::type)>(
445 ////////////////////////////////////////////////////////////////////////////////////////////
447 template<typename Key>
449 : proto::transform<_env_var<Key> >
451 template<typename Expr, typename State, typename Data>
453 : transform_impl<Expr, State, Data>
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
458 BOOST_PROTO_RETURN_TYPE_STRICT_LOOSE(result_type, typename impl::data::template lookup<Key>::const_reference)
460 typename impl::expr_param
461 , typename impl::state_param
462 , typename impl::data_param d
473 template<typename Expr, typename State, typename Data>
475 : transform_impl<Expr, State, Data>
477 typedef Data result_type;
479 BOOST_PROTO_RETURN_TYPE_STRICT_LOOSE(result_type, typename impl::data_param)
481 typename impl::expr_param
482 , typename impl::state_param
483 , typename impl::data_param d
492 template<typename Key>
493 struct is_callable<_env_var<Key> >
498 template<typename Key>
499 struct is_callable<functional::has_env_var<Key> >
504 template<typename Key>
505 struct is_callable<functional::env_var<Key> >
512 # pragma warning(pop)