views:

69

answers:

0

hello.

I wrote this generator, and I think to submit to boost people. Can you give me some feedback about it? It basically allows to collapse multidimensional loops to flat multi-index queue. Loop can be boost lambda expressions. Main reason for doing this is to make parallel loops easier and separate algorithm from controlling structure (my fieldwork is computational chemistry where deep loops are common)

#ifndef _GENERATOR_HPP_
#define _GENERATOR_HPP_

#include <boost/array.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/noncopyable.hpp>

#include <boost/mpl/bool.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/erase.hpp>

#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/fusion/include/as_vector.hpp>

#include <memory>

/**
   for loop generator which can use lambda expressions.

   For example:
   @code
   using namespace generator;
   using namespace boost::lambda;
   make_for(N, N, range(bind(std::max<int>, _1, _2), N), range(_2, _3+1));
   // equivalent to  pseudocode
   // for l=0,N: for k=0,N: for j=max(l,k),N: for i=k,j
   @endcode

   If range is given as upper bound only,
   lower bound is assumed to be default constructed
   Lambda placeholders may only reference first three indices.
*/

namespace generator {
    namespace detail {

        using boost::lambda::constant_type;
        using boost::lambda::constant;

        /// lambda expression identity
        template<class E, class enable = void>
        struct lambda {
            typedef E type;
        };

        /// transform/construct constant lambda expression from non-lambda
        template<class E>
        struct lambda<E, typename boost::disable_if<
                             boost::lambda::is_lambda_functor<E> >::type>
        {
            struct constant : boost::lambda::constant_type<E>::type {
                typedef typename boost::lambda::constant_type<E>::type base_type;
                constant() : base_type(boost::lambda::constant(E())) {}
                constant(const E &e) : base_type(boost::lambda::constant(e)) {}
            };
            typedef constant type;
        };

        /// range functor
        template<class L, class U>
        struct range_ {
            typedef boost::array<int,4> index_type;
            range_(U upper) : bounds_(typename lambda<L>::type(), upper) {}
            range_(L lower, U upper) : bounds_(lower, upper) {}

            template< typename T, size_t N>
            T lower(const boost::array<T,N> &index) {
                return bound<0>(index);
            }

            template< typename T, size_t N>
            T upper(const boost::array<T,N> &index) {
                return bound<1>(index);
            }

        private:
            template<bool b, typename T>
            T bound(const boost::array<T,1> &index) {
                return (boost::fusion::at_c<b>(bounds_))(index[0]);
            }

            template<bool b, typename T>
            T bound(const boost::array<T,2> &index) {
                return (boost::fusion::at_c<b>(bounds_))(index[0], index[1]);
            }

            template<bool b, typename T, size_t N>
            T bound(const boost::array<T,N> &index) {
                using boost::fusion::at_c;
                return (at_c<b>(bounds_))(index[0], index[1], index[2]);
            }

            boost::fusion::vector<typename lambda<L>::type,
                                  typename lambda<U>::type> bounds_;
        };

        template<typename T, size_t N>
        struct for_base {
            typedef boost::array<T,N> value_type;
            virtual ~for_base() {}
            virtual value_type next() = 0;
        };

        /// N-index generator
        template<typename T, size_t N, class R, class I>
        struct for_ : for_base<T,N> {
            typedef typename for_base<T,N>::value_type value_type;
            typedef R range_tuple;
            for_(const range_tuple &r) : r_(r), state_(true) {
                boost::fusion::for_each(r_, initialize(index));
            }
            /// @return new generator
            for_* new_() { return new for_(r_); }
            /// @return next index value and increment
            value_type next() {
                value_type next;
                using namespace boost::lambda;
                typename value_type::iterator n = next.begin();
                typename value_type::iterator i = index.begin();
                boost::mpl::for_each<I>(*(var(n))++ = var(i)[_1]);

                state_ = advance<N>(r_, index);
                return next;
            }
            /// @return false if out of bounds, true otherwise
            operator bool() { return state_; }

        private:
            /// initialize indices
            struct initialize {
                value_type &index_;
                mutable size_t i_;
                initialize(value_type &index) : index_(index), i_(0) {}
                template<class R_> void operator()(R_& r) const {
                    index_[i_++] = r.lower(index_);
                }
            };

            /// advance index[0:M)
            template<size_t M>
            struct advance {
                /// stop recursion
                struct stop {
                    stop(R r, value_type &index) {}
                };
                /// advance index
                /// @param r range tuple
                /// @param index  index array
                advance(R &r, value_type &index) : index_(index), i_(0) {
                    namespace fusion = boost::fusion;
                    index[M-1] += 1; // increment index
                    fusion::for_each(r, *this); // update indices
                    state_ = index[M-1] >= fusion::at_c<M-1>(r).upper(index);
                    if (state_) { // out of bounds
                        typename boost::mpl::if_c<(M > 1),
                            advance<M-1>, stop>::type(r, index);
                    }
                }
                /// apply lower bound of range to index
                template<typename R_> void operator()(R_& r) const {
                    if (i_ >= M) index_[i_] = r.lower(index_);
                    ++i_;
                }
                /// @return false if out of bounds, true otherwise
                operator bool() { return state_; }
            private:
                value_type &index_; ///< index array reference
                mutable size_t i_; ///< running index
                bool state_;    ///< out of bounds state
            };

            value_type index;
            range_tuple r_;
            bool state_;
        };


        /// polymorphic generator template base
        template<typename T,size_t N>
        struct For : boost::noncopyable {
            typedef boost::array<T,N> value_type;
            /// @return next index value and increment
            value_type next() { return for_->next(); }
            /// @return false if out of bounds, true otherwise
            operator bool() const { return for_; }
        protected:
            /// reset smart pointer
            void reset(for_base<T,N> *f) { for_.reset(f); }
            std::auto_ptr<for_base<T,N> > for_;
        };

        /// range [T,R) type
        template<typename T, typename R>
        struct range_type {
            typedef range_<T,R> type;
        };

        /// range identity specialization
        template<typename T, class L, class U>
        struct range_type<T, range_<L,U> > {
            typedef range_<L,U> type;
        };

        namespace fusion = boost::fusion;
        namespace mpl = boost::mpl;

        template<typename T, size_t N, class R1, class R2, class R3, class R4>
        struct range_tuple {
            // full range vector
            typedef typename mpl::vector<R1,R2,R3,R4> v;
            typedef typename mpl::end<v>::type end;
            typedef typename mpl::advance_c<typename mpl::begin<v>::type, N>::type pos;
            // [0:N) range vector
            typedef typename mpl::erase<v, pos, end>::type t;
            // transform into proper range fusion::vector
            typedef typename fusion::result_of::as_vector<
                typename mpl::transform<t,range_type<T, mpl::_1> >::type
                >::type type;
        };


        template<typename T, size_t N,
                 class R1, class R2, class R3, class R4,
                 class O>
        struct for_type {
            typedef typename range_tuple<T,N,R1,R2,R3,R4>::type range_tuple;
            typedef for_<T, N, range_tuple, O> type;
        };

    } // namespace detail


    /// default index order, [0:N)
    template<size_t  N>
    struct order {
        typedef boost::mpl::range_c<size_t,0, N> type;
    };

    /// N-loop generator, 0 < N <= 5
    /// @tparam T index type
    /// @tparam N number of indices/loops
    /// @tparam R1,... range types
    /// @tparam O index order
    template<typename T, size_t N,
             class R1, class R2 = void, class R3 = void, class R4 = void,
             class O = typename order<N>::type>
    struct for_ : detail::for_type<T, N, R1, R2, R3, R4, O>::type {
        typedef typename detail::for_type<T, N, R1, R2, R3, R4, O>::type base_type;
        typedef typename base_type::range_tuple range_tuple;
        for_(const range_tuple &range) : base_type(range) {}
    };

    /// loop range [L:U)
    /// @tparam L lower bound type
    /// @tparam U upper bound type
    /// @return range
    template<class L, class U>
    detail::range_<L,U> range(L lower, U upper) {
        return detail::range_<L,U>(lower, upper);
    }

    /// make 4-loop generator with specified index ordering
    template<typename T, class R1, class R2, class R3, class R4, class O>
    for_<T, 4, R1, R2, R3, R4, O>
    make_for(R1 r1, R2 r2, R3 r3, R4 r4, const O&) {
        typedef for_<T, 4, R1, R2, R3, R4, O> F;
        return F(F::range_tuple(r1, r2, r3, r4));
    }

    /// polymorphic generator template forward declaration
    template<typename T,size_t N>
    struct For;

    /// polymorphic 4-loop generator
    template<typename T>
    struct For<T,4> : detail::For<T,4> {
        /// generator with default index ordering
        template<class R1, class R2, class R3, class R4>
        For(R1 r1, R2 r2, R3 r3, R4 r4) {
            this->reset(make_for<T>(r1, r2, r3, r4).new_());
        }
        /// generator with specified index ordering
        template<class R1, class R2, class R3, class R4, class O>
        For(R1 r1, R2 r2, R3 r3, R4 r4, O o) {
            this->reset(make_for<T>(r1, r2, r3, r4, o).new_());
        }
    };

}


#endif /* _GENERATOR_HPP_ */