|
Boost : |
From: Maurizio Vitale (mav_at_[hidden])
Date: 2007-05-15 22:55:41
Wonderful, I didn't think of two contexts. Here's the result, with only two changes to your suggestion:
- I nested the two contexts inside each other
- I've added arguments to the inner_context so that is able to use the outer_context for evaluation
This is beacause when you have a function with more than one arguments is is possible that some
of them are compile-time constants, so it is worth a trip to save run-time evaluations.
Haven't checked the generated assembly, so I don't know the effect of passing target and source through
the constructor of the inner_context.
Maybe this can also be turned into an example.
Thanks again,
Maurizio
--------------------------------------------------------------------------------------------------------
template<typename Target, typename Source>
struct meta_context : proto::callable_context<const meta_context<Target,Source> > {
typedef meta_context<Target, Source> self;
typedef unsigned int result_type;
meta_context (const Target& target, const Source& source) : m_inner_context(*this, target, source) {}
template<typename Expr_>
struct compile_time_eval : meta_transform<Target, Source>::template apply<Expr_,mpl::void_, mpl::void_> {};
template<typename Expr_>
struct compile_time_unknown : boost::is_same<typename compile_time_eval<Expr_>::type, run_time> {
};
template<typename Expr_, typename Enable=void>
struct eval {
typedef unsigned int result_type;
result_type operator () (const Expr_& expr, self ctx) const {
return compile_time_eval<Expr_>::type::value;
}
};
template<typename Expr_>
struct eval<Expr_, typename boost::enable_if<typename compile_time_unknown<Expr_>::type >::type > {
typedef unsigned int result_type;
result_type operator () (const Expr_& expr, self ctx) const {
return proto::eval (expr, ctx.m_inner_context);
}
};
template<typename Outer_Context>
struct inner_context : proto::callable_context<const inner_context<Outer_Context> > {
typedef meta_context<Target, Source> self;
typedef unsigned int result_type;
inner_context (const Outer_Context& outer_context, const Target& target, const Source& source)
: m_outer_context (outer_context),
m_target (target),
m_source (source)
{}
#define RESULT_FOR(NAME, EXPR) result_type operator () (proto::tag::terminal, NAME##_tag NAME) const { return EXPR; }
RESULT_FOR (source, proto::arg(m_source).m_data)
RESULT_FOR (source_left, proto::arg(m_source).left ())
RESULT_FOR (source_right, proto::arg(m_source).right ())
RESULT_FOR (target, proto::arg(m_target).m_data)
RESULT_FOR (target_left, proto::arg(m_target).left ())
RESULT_FOR (target_right, proto::arg(m_target).right ())
template<typename What, typename Left, typename Right>
result_type operator () (mask_tag, const What& what, const Left& left, const Right& right) const {
std::size_t what_value = proto::eval (what, m_outer_context);
std::size_t left_value = proto::eval (left, m_outer_context);
std::size_t right_value = proto::eval (right, m_outer_context);
if (left_value == sizeof (unsigned long long)*8)
return what_value & (~0ULL << right_value);
else
return what_value & (~(~1ull << (left_value-1) | ~(~0ull << right_value)));
}
template<typename Left, typename Right>
result_type operator () (mask_tag, const Left& left, const Right& right) const {
std::size_t left_value = proto::eval (left, m_outer_context);
std::size_t right_value = proto::eval (right, m_outer_context);
if (left_value == sizeof (unsigned long long)*8)
return ~0ULL << right_value;
else
return ~(~1ull << (left_value-1) | ~(~0ull << right_value));
}
#undef RESULT_FOR
const Outer_Context& m_outer_context;
const Target& m_target;
const Source& m_source;
};
inner_context<self> m_inner_context;
};
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk