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