Boost logo

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