/*============================================================================= | |
Copyright (c) 2001-2007 Joel de Guzman | |
Copyright (c) 2004 Daniel Wallin | |
Distributed under the Boost Software License, Version 1.0. (See accompanying | |
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
==============================================================================*/ | |
#ifndef PHOENIX_SCOPE_DETAIL_LOCAL_VARIABLE_HPP | |
#define PHOENIX_SCOPE_DETAIL_LOCAL_VARIABLE_HPP | |
#include <boost/mpl/int.hpp> | |
#include <boost/mpl/bool.hpp> | |
#include <boost/mpl/eval_if.hpp> | |
#include <boost/mpl/equal_to.hpp> | |
#include <boost/mpl/identity.hpp> | |
#include <boost/mpl/less.hpp> | |
#include <boost/mpl/size.hpp> | |
#include <boost/fusion/include/at.hpp> | |
#include <boost/fusion/include/value_at.hpp> | |
#include <boost/preprocessor/enum.hpp> | |
#include <boost/preprocessor/repeat.hpp> | |
#include <boost/type_traits/remove_reference.hpp> | |
#include <boost/type_traits/is_reference.hpp> | |
#define PHOENIX_MAP_LOCAL_TEMPLATE_PARAM(z, n, data) \ | |
typename T##n = unused<n> | |
#define PHOENIX_MAP_LOCAL_DISPATCH(z, n, data) \ | |
typedef char(&result##n)[n+2]; \ | |
static result##n get(T##n*); | |
namespace boost { namespace phoenix | |
{ | |
template <typename Env, typename OuterEnv, typename Locals, typename Map> | |
struct scoped_environment; | |
namespace detail | |
{ | |
template <typename Env> | |
struct initialize_local | |
{ | |
template <class F> | |
struct result; | |
template <class F, class Actor> | |
struct result<F(Actor)> | |
{ | |
typedef typename remove_reference<Actor>::type actor_type; | |
typedef typename actor_type::template result<Env>::type type; | |
}; | |
initialize_local(Env const& env) | |
: env(env) {} | |
template <typename Actor> | |
typename result<initialize_local(Actor)>::type | |
operator()(Actor const& actor) const | |
{ | |
return actor.eval(env); | |
} | |
Env const& env; | |
private: | |
// silence MSVC warning C4512: assignment operator could not be generated | |
initialize_local& operator= (initialize_local const&); | |
}; | |
template <typename T> | |
struct is_scoped_environment : mpl::false_ {}; | |
template <typename Env, typename OuterEnv, typename Locals, typename Map> | |
struct is_scoped_environment<scoped_environment<Env, OuterEnv, Locals, Map> > | |
: mpl::true_ {}; | |
template <int N> | |
struct unused; | |
template <BOOST_PP_ENUM( | |
PHOENIX_LOCAL_LIMIT, PHOENIX_MAP_LOCAL_TEMPLATE_PARAM, _)> | |
struct map_local_index_to_tuple | |
{ | |
typedef char(¬_found)[1]; | |
static not_found get(...); | |
BOOST_PP_REPEAT(PHOENIX_LOCAL_LIMIT, PHOENIX_MAP_LOCAL_DISPATCH, _) | |
}; | |
template<typename T> | |
T* generate_pointer(); | |
template <typename Map, typename Tag> | |
struct get_index | |
{ | |
BOOST_STATIC_CONSTANT(int, | |
value = ( | |
static_cast<int>((sizeof(Map::get(generate_pointer<Tag>()))) / sizeof(char)) - 2 | |
)); | |
// if value == -1, Tag is not found | |
typedef mpl::int_<value> type; | |
}; | |
template <typename Local, typename Env> | |
struct apply_local; | |
template <typename Local, typename Env> | |
struct outer_local | |
{ | |
typedef typename | |
apply_local<Local, typename Env::outer_env_type>::type | |
type; | |
}; | |
template <typename Locals, typename Index> | |
struct get_local_or_void | |
{ | |
typedef typename | |
mpl::eval_if< | |
mpl::less<Index, mpl::size<Locals> > | |
, fusion::result_of::at<Locals, Index> | |
, mpl::identity<fusion::void_> | |
>::type | |
type; | |
}; | |
template <typename Local, typename Env, typename Index> | |
struct get_local_from_index | |
{ | |
typedef typename | |
mpl::eval_if< | |
mpl::equal_to<Index, mpl::int_<-1> > | |
, outer_local<Local, Env> | |
, get_local_or_void<typename Env::locals_type, Index> | |
>::type | |
type; | |
}; | |
template <typename Local, typename Env> | |
struct get_local | |
{ | |
typedef typename | |
get_index< | |
typename Env::map_type, typename Local::key_type>::type | |
index_type; | |
typedef typename | |
get_local_from_index<Local, Env, index_type>::type | |
type; | |
}; | |
template <typename Local, typename Env> | |
struct apply_local | |
{ | |
// $$$ TODO: static assert that Env is a scoped_environment $$$ | |
typedef typename get_local<Local, Env>::type type; | |
}; | |
template <typename Key> | |
struct eval_local | |
{ | |
template <typename RT, typename Env, typename Index> | |
static RT | |
get(Env const& env, Index, mpl::false_) | |
{ | |
return RT(fusion::at<Index>(env.locals)); | |
} | |
template <typename RT, typename Env, typename Index> | |
static RT | |
get(Env const& env, Index index, mpl::true_) | |
{ | |
typedef typename | |
get_index<typename Env::outer_env_type::map_type, Key>::type | |
index_type; | |
return get<RT>( | |
env.outer_env | |
, index_type() | |
, mpl::equal_to<index_type, mpl::int_<-1> >()); | |
} | |
template <typename RT, typename Env, typename Index> | |
static RT | |
get(Env const& env, Index index) | |
{ | |
return get<RT>( | |
env | |
, index | |
, mpl::equal_to<Index, mpl::int_<-1> >()); | |
} | |
}; | |
} | |
}} | |
#undef PHOENIX_MAP_LOCAL_TEMPLATE_PARAM | |
#undef PHOENIX_MAP_LOCAL_DISPATCH | |
#endif |