Sign in to follow this  
thesimon

boost mpl loop unrolling

Recommended Posts

hi there, i have a question regarding Boost.MPL. the situation is this: i need to enable the users of my code to pass a set of functions that are then executed over an array of objects by my function.. allowing the user to customize a certain part of an algorithm. the problem is that the size of the set of functions being passed is unknown to me, but of course known at compile time. my first solution to this was to let the user pass an array of boost::function<>s to my function and then execute them using a standard for loop. this works fine, of course, but the problem with this is that the compilers don't inline this. to enable inlining i thought of parameterizing the object that includes the function applying the user supplied functions. that template parameter must be used to specifiy a boost::mpl::vector<> of function object types. example:
template<class Funcs>
class algorithm
{
    // ...
    void execute() { /* ... */ } 
};


// user code:
struct func1 { template<class T, class R> static R apply(T &t) { /*do something*/ } };
struct func1 { template<class T, class R> static R apply(T &t) { /*do something*/ } };

typedef algorithm<boost::mpl::vector<func1, func2> > algorightm_type;
algorightm_type alg();
alg.execute();
now my problem is to unroll the calls to the function object types in the mpl::vector<>. after a short search i came across the following few lines of code demonstrating mpl to unroll a loop:
mpl::for_each< mpl::range_c<int,0,10> >( 
          boost::bind(&foobar, _1) 
        ); 
i have the special requirement that the return values of the functions being passed withing the mpl::vector<> must be stored separately i.e. i have an array the same size as the mpl::set<> and the result of the n-th function in the mpl::vector<> is stored in the n-th element of the array. to accomplish that i wrote a function object that does just this:
template<class Func, size_t N, class ReturnType> 
struct exec_fn
{ 
	template<class Array, class Objects> 
         void operator () (Array &a, Objects &objects)
	{ a[N] = Func::apply<ReturnType>(objects); }
};
then in my algorithm<>::execute() method i have the following code:
static const size_t n_funcs = boost::mpl::size<Funcs>::value;
boost::array<float, n_funcs> array;
for(object_iterator it = ............ begin to end of my obejcts)
{
boost::mpl::for_each<boost::mpl::range_c<size_t, 0, n_funcs> > 
( exec_fn<typename boost::mpl::at<Funcs, boost::mpl::int_<1> >::type, 1, float>
         ()(it, array);
);					
}
this thing compiles fine. but of course it doesn't execute the loop correctly. i just used the constants 1 and int_<1> in order to make it compile. the problem is i can't figure out how to access the current iteration variable of the mpl::for_each<>. i know its in the _1 lambda but i don't know what to do with it... basically i need this to be something like
boost::mpl::for_each<boost::mpl::range_c<size_t, 0, n_funcs> > 
( exec_fn<typename boost::mpl::at<Funcs, _1>::type, _1, float>
         ()(it, array);
);
which doesn't compile.... but i can't figure out why. i suppose i could roll my own templates recursively executing the contents of the mpl::vector<> but i don't want to. i'd like only use mpl's facilities for obvious reasons. can anyone help there? thanks in advance, thesimon. note: i wrote the code above without compiling.. it's roughly based on what i have. i needed to simplify quite a bit. also i strongly believe that only going in the direction of compile time unrolling using mpl is the way to go. i can't afford the calls to the user supplied functions being made with a run-time loop. these functions are executed quite number of time.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Maybe something like this helps:


#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/array.hpp>

namespace mpl = boost::mpl;

struct thing
{};

template<class Iterator>
struct execute_function
{
execute_function(Iterator i, thing& objects)
: i(i)
, objects(objects)
{}

template<class F>
void operator()(F f)
{
*i++ = f(objects);
}

Iterator i;
thing& objects;
};

struct f1
{
int operator()(thing& x)
{
return 1;
}
};

struct f2
{
int operator()(thing& x)
{
return 2;
}
};

int main()
{
typedef mpl::vector2<f1,f2> functions;

boost::array<int,2> result;
thing objects;

mpl::for_each<functions>(
execute_function<boost::array<int,2>::iterator>(
result.begin(), objects
)
);
}

Share this post


Link to post
Share on other sites
HA AP ! thanks for your reply. it worked.

i also checked the resulting assembly output and the user supplied functions get nicely inlined, too... i was a bit sceptic whether it would inline the functions because you suggested to write the user supplied functions like typical function objects.... that need to be instantiated before calls to their operators () can be made. obviously the compiler can successfully optimize that away.

still figuring out if the generated assembly is as slick as i want it to be but everything looks like i imagined it should look.

i didn't think of doing it that way because i didn't want to instantiate the function objects. rather i wanted to call static functions and have an explicit iteration variable. well...... your solution is shorter and works :)

thanks again.

i'll return if i find something i don't like about the code being generated ;) but i don't think that'll happen.

Share this post


Link to post
Share on other sites
the interesting thing though is: when i test something like


res = result.begin();
for(object_iterator it = ..... first to last object)
*res++ = func1()(it);


the call to func1::operator() doesn't get inlined. only the version with mpl-style unrolling inlines everything. quite interesting... am i experiencing the power of mpl? +g+

quite nice, but i don't know why it does inlining with the mpl::for_each<> and doesn't with the code above.

this post is just a remark. thanks to AP my problem from the initial post has been solved :)

-thesimon

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this