boost/xpressive/proto/transform/construct.hpp
#ifndef BOOST_PP_IS_ITERATING
///////////////////////////////////////////////////////////////////////////////
/// \file construct.hpp
/// For constructing an arbitrary type from a bunch of transforms.
//
// Copyright 2007 Eric Niebler. 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 BOOST_PROTO_TRANSFORM_CONSTRUCT_HPP_EAN_12_26_2006
#define BOOST_PROTO_TRANSFORM_CONSTRUCT_HPP_EAN_12_26_2006
#include <boost/xpressive/proto/detail/prefix.hpp>
#include <boost/preprocessor/iterate.hpp>
#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/aux_/has_type.hpp>
#include <boost/mpl/aux_/lambda_arity_param.hpp>
#include <boost/type_traits/is_pod.hpp>
#include <boost/type_traits/is_function.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/xpressive/proto/proto_fwd.hpp>
#include <boost/xpressive/proto/detail/suffix.hpp>
namespace boost { namespace proto { namespace transform
{
namespace detail
{
template<typename T>
struct is_aggregate
: is_pod<T>
{};
template<typename Tag, typename Args, long N>
struct is_aggregate<expr<Tag, Args, N> >
: mpl::true_
{};
template<typename T, bool HasType = mpl::aux::has_type<T>::value>
struct nested_type
{
typedef typename T::type type;
};
template<typename T>
struct nested_type<T, false>
{
typedef T type;
};
template<typename T BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(BOOST_PROTO_MAX_ARITY, typename A, = no_type BOOST_PP_INTERCEPT)>
struct nested_type_if
: nested_type<T>
{
typedef yes_type proto_transform_applied;
};
template<typename T>
struct nested_type_if<T BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, no_type BOOST_PP_INTERCEPT)>
{
typedef T type;
typedef no_type proto_transform_applied;
};
template<typename Arg, bool IsFunction = is_function<typename remove_pointer<Arg>::type>::value>
struct as_transform
{
typedef Arg type;
};
template<typename Arg>
struct as_transform<Arg, true>
{
typedef construct<_, typename remove_pointer<Arg>::type> type;
};
template<typename Arg, bool IsFunction = is_function<typename remove_pointer<Arg>::type>::value>
struct as_pod_transform
{
typedef Arg type;
};
template<typename Arg>
struct as_pod_transform<Arg, true>
{
typedef pod_construct<_, typename remove_pointer<Arg>::type> type;
};
template<typename R, typename Expr, typename State, typename Visitor
BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(long Arity = mpl::aux::template_arity<R>::value)
>
struct apply_aux_
{
typedef R type;
typedef no_type proto_transform_applied;
};
template<typename R, typename Expr, typename State, typename Visitor, bool IsTransform = is_transform<R>::value>
struct apply_
: apply_aux_<R, Expr, State, Visitor>
{};
template<typename R, typename Expr, typename State, typename Visitor>
struct apply_<R, Expr, State, Visitor, true>
: nested_type<typename R::template apply<Expr, State, Visitor>::type>
{
typedef yes_type proto_transform_applied;
};
// work around GCC bug
template<typename Tag, typename Args, long N, typename Expr, typename State, typename Visitor>
struct apply_<expr<Tag, Args, N>, Expr, State, Visitor, false>
{
typedef expr<Tag, Args, N> type;
typedef no_type proto_transform_applied;
};
template<typename T>
void ignore_unused(T const &)
{}
}
template<typename Grammar, typename ConstructorFun>
struct construct
: Grammar
{
template<typename Expr, typename State, typename Visitor>
struct apply
: ConstructorFun::template apply<typename Grammar::template apply<Expr, State, Visitor>::type, State, Visitor>
{};
template<typename Expr, typename State, typename Visitor>
static typename apply<Expr, State, Visitor>::type
call(Expr const &expr, State const &state, Visitor &visitor)
{
return ConstructorFun::call(Grammar::call(expr, state, visitor), state, visitor);
}
};
#define BOOST_PROTO_APPLY_(Z, N, DATA) \
typename apply_<BOOST_PP_CAT(DATA, N), Expr, State, Visitor>::type \
/**/
#define BOOST_PROTO_IS_APPLIED_(Z, N, DATA) \
typename apply_<BOOST_PP_CAT(DATA, N), Expr, State, Visitor>::proto_transform_applied \
/**/
#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, BOOST_PROTO_MAX_ARITY, <boost/xpressive/proto/transform/construct.hpp>))
#include BOOST_PP_ITERATE()
#undef BOOST_PROTO_APPLY_
#undef BOOST_PROTO_IS_APPLIED_
}}}
namespace boost { namespace proto
{
template<typename Grammar, typename ConstructorFun>
struct is_transform<transform::construct<Grammar, ConstructorFun> >
: mpl::true_
{};
template<typename Grammar, typename ConstructorFun>
struct is_transform<transform::pod_construct<Grammar, ConstructorFun> >
: mpl::true_
{};
}}
#endif
#else
#define N BOOST_PP_ITERATION()
#if N > 0
namespace detail
{
template<
template<BOOST_PP_ENUM_PARAMS(N, typename BOOST_PP_INTERCEPT)> class T
BOOST_PP_ENUM_TRAILING_PARAMS(N, typename G),
typename Expr, typename State, typename Visitor
>
struct apply_aux_<T<BOOST_PP_ENUM_PARAMS(N, G)>, Expr, State, Visitor BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(N)>
: nested_type_if<
T<BOOST_PP_ENUM(N, BOOST_PROTO_APPLY_, G)>
BOOST_PP_ENUM_TRAILING(N, BOOST_PROTO_IS_APPLIED_, G)
>
{};
}
#endif
template<typename Grammar, typename Result BOOST_PP_ENUM_TRAILING_PARAMS(N, typename Arg)>
struct construct<Grammar, Result(BOOST_PP_ENUM_PARAMS(N, Arg))>
: Grammar
{
template<typename Expr, typename State, typename Visitor>
struct apply
: detail::apply_<Result, typename Grammar::template apply<Expr, State, Visitor>::type, State, Visitor>
{};
template<typename Expr, typename State, typename Visitor>
static typename apply<Expr, State, Visitor>::type
call(Expr const &expr, State const &state, Visitor &visitor)
{
typedef typename apply<Expr, State, Visitor>::type result_type;
return construct::call_(expr, state, visitor, detail::is_aggregate<result_type>());
}
private:
/// INTERNAL ONLY
///
template<typename Expr, typename State, typename Visitor>
static typename apply<Expr, State, Visitor>::type
call_(Expr const &expr, State const &state, Visitor &visitor, mpl::true_)
{
typename Grammar::template apply<Expr, State, Visitor>::type const &expr2
= Grammar::call(expr, state, visitor);
detail::ignore_unused(expr2);
typename apply<Expr, State, Visitor>::type that = {
BOOST_PP_ENUM_BINARY_PARAMS(N, detail::as_transform<Arg, >::type::call(expr2, state, visitor) BOOST_PP_INTERCEPT)
};
return that;
}
/// INTERNAL ONLY
///
template<typename Expr, typename State, typename Visitor>
static typename apply<Expr, State, Visitor>::type
call_(Expr const &expr, State const &state, Visitor &visitor, mpl::false_)
{
typename Grammar::template apply<Expr, State, Visitor>::type const &expr2
= Grammar::call(expr, state, visitor);
detail::ignore_unused(expr2);
return typename apply<Expr, State, Visitor>::type(
BOOST_PP_ENUM_BINARY_PARAMS(N, detail::as_transform<Arg, >::type::call(expr2, state, visitor) BOOST_PP_INTERCEPT)
);
}
};
template<typename Grammar, typename Result BOOST_PP_ENUM_TRAILING_PARAMS(N, typename Arg)>
struct pod_construct<Grammar, Result(BOOST_PP_ENUM_PARAMS(N, Arg))>
: Grammar
{
template<typename Expr, typename State, typename Visitor>
struct apply
: detail::apply_<Result, typename Grammar::template apply<Expr, State, Visitor>::type, State, Visitor>
{};
template<typename Expr, typename State, typename Visitor>
static typename apply<Expr, State, Visitor>::type
call(Expr const &expr, State const &state, Visitor &visitor)
{
typename Grammar::template apply<Expr, State, Visitor>::type const &expr2
= Grammar::call(expr, state, visitor);
detail::ignore_unused(expr2);
typename apply<Expr, State, Visitor>::type that = {
BOOST_PP_ENUM_BINARY_PARAMS(N, detail::as_pod_transform<Arg, >::type::call(expr2, state, visitor) BOOST_PP_INTERCEPT)
};
return that;
}
};
#undef N
#endif