// Copyright 2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See copy at http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #include #include #include #include #include #include using boost::mpl::int_; // Begin iterator of a sequence template inline typename Seq::const_iterator begin(const Seq& seq) { return seq.begin(); } // End iterator of a sequence template inline typename Seq::const_iterator end(const Seq& seq) { return seq.end(); } // Stores state associated with the Ith parameter in a parameter // sweep. template struct bound_state : public State { bound_state(const State& state, const Value& value) : State(state), value(value) { } Value value; }; // Stores a task htat has bound to a particular parameter. template struct bound_task : public State { typedef bound_task self_type; bound_task(const State& state, const Task& task) : State(state), task(task) { } template inline bound_task bind(const NewTask& task) { return bound_task(*this, task); } Task task; }; // Empty state struct empty_state { template inline bound_task bind(const Task& task) { return bound_task(*this, task); } }; // Iteration through a tuple template struct tuple_iterator { BOOST_STATIC_CONSTANT(int, length = boost::tuples::length::value); typedef typename boost::mpl::if_c<(I < length), boost::tuples::element, boost::mpl::identity >::type::type type; explicit tuple_iterator(const Tuple& tuple) : tuple(tuple) { } type operator*() const { using boost::tuples::get; return get(tuple); } tuple_iterator next() const { return tuple_iterator(tuple); } const Tuple& tuple; }; template inline tuple_iterator, 0> begin(const boost::tuples::tuple& t) { return tuple_iterator, 0>(t); } template inline tuple_iterator, 1> end(const boost::tuples::tuple& t) { return tuple_iterator, 1>(t); } template inline tuple_iterator, 0> begin(const boost::tuples::tuple& t) { return tuple_iterator, 0>(t); } template inline tuple_iterator, 2> end(const boost::tuples::tuple& t) { return tuple_iterator, 2>(t); } template inline tuple_iterator, 0> begin(const boost::tuples::tuple& t) { return tuple_iterator, 0>(t); } template inline tuple_iterator, 3> end(const boost::tuples::tuple& t) { return tuple_iterator, 3>(t); } // Give bound_state a tuple-like interface. namespace boost { namespace tuples { template inline const Value& get(const bound_state& state) { return state.value; } template struct length > { BOOST_STATIC_CONSTANT(int, value = (I + 1)); }; } } namespace detail { // If there is task bound to the Ith parameter, execute its setup // member. template inline void do_setup(bound_task& task, State& state) { task.task.setup(state); } template inline void do_setup(empty_state&, State) { } // If there is task bound to the Ith parameter, execute its cleanup // member. template inline void do_cleanup(bound_task& task, State& state) { task.task.cleanup(state); } template inline void do_cleanup(empty_state&, State) { } // Append a value of type Value as the Ith parameter in a parameter // sweep. This metafunction produces the return type of // append_state(). template struct append_state_t { typedef bound_state type; }; // Append a value of type Value as the Ith parameter in a parameter // sweep and produce a new state containing that value. template inline typename append_state_t::type append_state(const State& state, int_, const Value& value) { return typename append_state_t::type(state, value); } // Forward declaration needed because sweep_impl is mutually // recursive with the sweep_*_param functions. template inline typename boost::enable_if_c<(I < boost::tuples::length::value)>::type sweep_impl(const Tuple& params, Experiment& experiment, State& state, int_ i); template inline typename boost::enable_if_c<(I == boost::tuples::length::value)>::type sweep_impl(const Tuple&, Experiment& experiment, State& state, int_); // Iterate over all of the values of the (homogeneous) container of // parameters. template inline void sweep_container_param(ForwardIterator first, ForwardIterator last, const Tuple& params, Experiment& experiment, State& state, int_ i) { typedef typename std::iterator_traits::value_type value_type; while (first != last) { typename append_state_t::type new_state = detail::append_state(state, i, *first); do_setup(new_state, new_state); detail::sweep_impl(params, experiment, new_state, int_()); do_cleanup(new_state, new_state); ++first; } } // Termination condition for sweep of heterogenerous parameters. template inline void sweep_hetero_param(Iterator, Iterator, const Tuple& params, Experiment& experiment, State& state, int_ i) { } // Iterate over all of the values of heterogeneous parameters. template inline void sweep_hetero_param(FIterator first, LIterator last, const Tuple& params, Experiment& experiment, State& state, int_ i) { typedef typename FIterator::type value_type; typename append_state_t::type new_state = detail::append_state(state, i, *first); do_setup(new_state, new_state); detail::sweep_impl(params, experiment, new_state, int_()); do_cleanup(new_state, new_state); sweep_hetero_param(first.next(), last, params, experiment, state, i); } // Iterate over all of the values of the (heterogeneous) container of // parameters. template inline void sweep_container_param(FIterator first, LIterator last, const Tuple& params, Experiment& experiment, State& state, int_ i) { sweep_hetero_param(first, last, params, experiment, state, i); } // Sweep over the given parameter, expanding the nested loop. This // default implementation assumes that the parameters are actually a // collection and that we can get begin/end iterators. template inline void sweep_param(const Param& param, const Tuple& params, Experiment& experiment, State& state, int_ i) { sweep_container_param(begin(param), end(param), params, experiment, state, i); } // The body of the inner loop in a parameter sweep. We need only // invoke the experiment with the given state. template inline typename boost::enable_if_c<(I == boost::tuples::length::value)>::type sweep_impl(const Tuple&, Experiment& experiment, State& state, int_) { experiment(state); } // One loop within the loop nest. This expands to a nested loop from // the Ith parameter inward. template inline typename boost::enable_if_c<(I < boost::tuples::length::value)>::type sweep_impl(const Tuple& params, Experiment& experiment, State& state, int_ i) { using boost::tuples::get; sweep_param(get(params), params, experiment, state, i); } } template inline void sweep(const Tuple& params, const State& state, Experiment experiment) { // Yes, const_cast is evil, but more evil is the fact that we can't // bind a temporary to a reference when we need to :) detail::sweep_impl(params, experiment, const_cast(state), int_<0>()); } template inline void sweep(const Tuple& params, Experiment experiment) { empty_state state; sweep(params, state, experiment); }