Skip to content

Instantly share code, notes, and snippets.

@sithhell
Created August 15, 2010 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sithhell/525569 to your computer and use it in GitHub Desktop.
Save sithhell/525569 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <boost/proto/proto.hpp>
#include <boost/fusion/include/pair.hpp>
#include <boost/fusion/include/as_map.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/push_back.hpp>
using namespace std;
using namespace boost::proto;
struct param_domain;
////////////////////////////////////////////////////////////////////////////////
// Parameters expression
////////////////////////////////////////////////////////////////////////////////
template<typename Expr>
struct param_expr : extends<Expr, param_expr<Expr>, param_domain>
{
typedef extends<Expr, param_expr<Expr>, param_domain> base_type;
explicit param_expr(Expr const &expr = Expr()) : base_type(expr) {}
BOOST_PROTO_EXTENDS_USING_ASSIGN(param_expr)
};
////////////////////////////////////////////////////////////////////////////////
// Add a parameters into the parameters map
////////////////////////////////////////////////////////////////////////////////
struct _insert : boost::proto::callable
{
template<class Sig> struct result;
template<class This, class Left, class Right, class State>
struct result<This(Left,Right,State)>
{
typedef typename boost::remove_const<typename boost::remove_reference<Left>::type>::type left_type;
typedef typename boost::remove_const<typename boost::remove_reference<Right>::type>::type right_type;
typedef typename boost::remove_const<typename boost::remove_reference<State>::type>::type state_type;
typedef boost::fusion::pair<left_type, right_type> value_type;
typedef typename boost::fusion::result_of::push_back<state_type const, value_type>::type type;
};
template<class Left, class Right, class State>
typename result<_insert(Left,Right,State)>::type
operator()(Left const& ,Right const& r,State& s) const
{
return boost::fusion::push_back(s,boost::fusion::make_pair<Left>(r));
}
};
////////////////////////////////////////////////////////////////////////////////
// Parameters Grammar
////////////////////////////////////////////////////////////////////////////////
struct param_grammar
: or_< when< assign< _, _>
, _insert(_value(_left),_value(_right),_state)
>
, when< comma<param_grammar,param_grammar>
, param_grammar(_right, param_grammar(_left))
>
>
{};
////////////////////////////////////////////////////////////////////////////////
// Parameters domain: perform copy of the parameters value
////////////////////////////////////////////////////////////////////////////////
struct param_domain : domain<generator<param_expr> >
{
template <typename T> struct as_child : as_expr<T> {};
};
////////////////////////////////////////////////////////////////////////////////
// Create a new parameters placeholder
////////////////////////////////////////////////////////////////////////////////
#define BOOST_REGISTER_PARAMETERS(Name) \
struct BOOST_PP_CAT(tag_,Name) {}; \
param_expr<terminal<BOOST_PP_CAT(tag_,Name)>::type> const Name \
/**/
////////////////////////////////////////////////////////////////////////////////
// Parameters pack
////////////////////////////////////////////////////////////////////////////////
struct no_parameter_found {};
template<class Map> struct parameters
{
parameters( Map const& m ) : values(m) {}
template<class Sig> struct result;
template<class This, class Name>
struct result<This(param_expr<Name>)>
{
typedef typename boost::fusion::result_of::has_key<
Map const
, typename boost::proto::result_of::value<Name>::type
>::type found;
typedef boost::fusion::result_of::at_key<
Map const
, typename boost::proto::result_of::value<Name>::type
> base;
typedef typename boost::mpl::eval_if<found, base, boost::mpl::identity<no_parameter_found> >::type type;
};
template<class This, class Name, class Default>
struct result<This(param_expr<Name>,Default)>
{
typedef typename boost::fusion::result_of::has_key<
Map const
, typename boost::proto::result_of::value<Name>::type
>::type found;
typedef boost::fusion::result_of::at_key<
Map const
, typename boost::proto::result_of::value<Name>::type
> base;
typedef typename boost::mpl::eval_if<found, base, boost::mpl::identity<Default> >::type type;
};
template<class Name>
typename result<parameters(param_expr<Name>)>::type
operator()(param_expr<Name> const& p) const
{
typedef typename boost::fusion
::result_of::has_key< Map const
, typename boost::proto
::result_of::value<Name>::type
>::type found;
return eval(p, found());
//return boost::fusion::at_key<typename boost::proto::result_of::value<Name>::type>(values);
}
template<class Name, class Default>
typename result<parameters(param_expr<Name>,Default)>::type
operator()(param_expr<Name> const& p, Default const& v ) const
{
typedef typename boost::fusion
::result_of::has_key< Map const
, typename boost::proto
::result_of::value<Name>::type
>::type found;
return eval(p,v, found());
}
template<class Name, class Default>
typename result<parameters(param_expr<Name>,Default)>::type
eval(param_expr<Name> const&, Default const& , boost::mpl::true_ ) const
{
return boost::fusion::at_key<typename boost::proto::result_of::value<Name>::type>(values);
}
template<class Name, class Default>
typename result<parameters(param_expr<Name>,Default)>::type
eval(param_expr<Name> const&, Default const& v, boost::mpl::false_ ) const
{
return v;
}
template<class Name>
typename result<parameters(param_expr<Name>)>::type
eval(param_expr<Name> const&, boost::mpl::true_) const
{
return boost::fusion::at_key<typename boost::proto::result_of::value<Name>::type>(values);
}
template<class Name>
typename result<parameters(param_expr<Name>)>::type
eval(param_expr<Name> const&, boost::mpl::false_) const
{
BOOST_MPL_ASSERT_MSG(false, PARAMETER_NOT_FOUND, (Name));
return no_parameter_found();
}
Map values;
};
////////////////////////////////////////////////////////////////////////////////
// Option binder class
////////////////////////////////////////////////////////////////////////////////
struct option_binder
{
template<class X> struct result
{
typedef typename boost::result_of < param_grammar ( param_expr<X> const&
, boost::fusion::vector<>&
)
>::type pack;
typedef typename boost::fusion::result_of::as_map<pack>::type map_type;
typedef parameters<map_type> type;
};
template<class X>
typename result<X>::type
operator[]( param_expr<X> const& xpr ) const
{
using boost::fusion::as_map;
boost::fusion::vector<> base;
typename result<X>::type that(as_map(param_grammar()(xpr,base)));
return that;
}
};
////////////////////////////////////////////////////////////////////////////////
// options entry-point
////////////////////////////////////////////////////////////////////////////////
option_binder const options = {};
///////////////////////////////////////////////////////////////////////////////
// User written code begins here
///////////////////////////////////////////////////////////////////////////////
BOOST_REGISTER_PARAMETERS(speed);
BOOST_REGISTER_PARAMETERS(force);
BOOST_REGISTER_PARAMETERS(bar);
struct foo
{
template <typename ParamMap>
foo( ParamMap const& opt )
: speed_( opt(speed) )
, force_( opt(force) )
, bar_( opt(bar, true) )
{}
float speed_;
int force_;
bool bar_;
};
struct baz
{
template <typename ParamMap>
baz( ParamMap const& opt )
: speed_( opt(speed) )
, force_( opt(force) )
, bar_( opt(bar) )
{}
float speed_;
int force_;
bool bar_;
};
int main()
{
{
foo f(options[speed = 8.9f, bar= false, force = 5]);
cout << f.speed_ << " " << f.force_ << " " << f.bar_ << "\n";
}
{
foo f(options[speed = 8.9f, force = 5]);
cout << f.speed_ << " " << f.force_ << " " << f.bar_ << "\n";
}
{
// uncomment this to get an error
//baz b(options[speed = 9.9f, force = 5]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment