C++/boost generator module, feedback/critic please
- by aaa
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)
1 #ifndef _GENERATOR_HPP_
2 #define _GENERATOR_HPP_
3
4 #include <boost/array.hpp>
5 #include <boost/lambda/lambda.hpp>
6 #include <boost/noncopyable.hpp>
7
8 #include <boost/mpl/bool.hpp>
9 #include <boost/mpl/int.hpp>
10 #include <boost/mpl/for_each.hpp>
11 #include <boost/mpl/range_c.hpp>
12 #include <boost/mpl/vector.hpp>
13 #include <boost/mpl/transform.hpp>
14 #include <boost/mpl/erase.hpp>
15
16 #include <boost/fusion/include/vector.hpp>
17 #include <boost/fusion/include/for_each.hpp>
18 #include <boost/fusion/include/at_c.hpp>
19 #include <boost/fusion/mpl.hpp>
20 #include <boost/fusion/include/as_vector.hpp>
21
22 #include <memory>
23
24 /**
25 for loop generator which can use lambda expressions.
26
27 For example:
28 @code
29 using namespace generator;
30 using namespace boost::lambda;
31 make_for(N, N, range(bind(std::max<int>, _1, _2), N), range(_2, _3+1));
32 // equivalent to pseudocode
33 // for l=0,N: for k=0,N: for j=max(l,k),N: for i=k,j
34 @endcode
35
36 If range is given as upper bound only,
37 lower bound is assumed to be default constructed
38 Lambda placeholders may only reference first three indices.
39 */
40
41 namespace generator {
42 namespace detail {
43
44 using boost::lambda::constant_type;
45 using boost::lambda::constant;
46
47 /// lambda expression identity
48 template<class E, class enable = void>
49 struct lambda {
50 typedef E type;
51 };
52
53 /// transform/construct constant lambda expression from non-lambda
54 template<class E>
55 struct lambda<E, typename boost::disable_if<
56 boost::lambda::is_lambda_functor<E> >::type>
57 {
58 struct constant : boost::lambda::constant_type<E>::type {
59 typedef typename boost::lambda::constant_type<E>::type base_type;
60 constant() : base_type(boost::lambda::constant(E())) {}
61 constant(const E &e) : base_type(boost::lambda::constant(e)) {}
62 };
63 typedef constant type;
64 };
65
66 /// range functor
67 template<class L, class U>
68 struct range_ {
69 typedef boost::array<int,4> index_type;
70 range_(U upper) : bounds_(typename lambda<L>::type(), upper) {}
71 range_(L lower, U upper) : bounds_(lower, upper) {}
72
73 template< typename T, size_t N>
74 T lower(const boost::array<T,N> &index) {
75 return bound<0>(index);
76 }
77
78 template< typename T, size_t N>
79 T upper(const boost::array<T,N> &index) {
80 return bound<1>(index);
81 }
82
83 private:
84 template<bool b, typename T>
85 T bound(const boost::array<T,1> &index) {
86 return (boost::fusion::at_c<b>(bounds_))(index[0]);
87 }
88
89 template<bool b, typename T>
90 T bound(const boost::array<T,2> &index) {
91 return (boost::fusion::at_c<b>(bounds_))(index[0], index[1]);
92 }
93
94 template<bool b, typename T, size_t N>
95 T bound(const boost::array<T,N> &index) {
96 using boost::fusion::at_c;
97 return (at_c<b>(bounds_))(index[0], index[1], index[2]);
98 }
99
100 boost::fusion::vector<typename lambda<L>::type,
101 typename lambda<U>::type> bounds_;
102 };
103
104 template<typename T, size_t N>
105 struct for_base {
106 typedef boost::array<T,N> value_type;
107 virtual ~for_base() {}
108 virtual value_type next() = 0;
109 };
110
111 /// N-index generator
112 template<typename T, size_t N, class R, class I>
113 struct for_ : for_base<T,N> {
114 typedef typename for_base<T,N>::value_type value_type;
115 typedef R range_tuple;
116 for_(const range_tuple &r) : r_(r), state_(true) {
117 boost::fusion::for_each(r_, initialize(index));
118 }
119 /// @return new generator
120 for_* new_() { return new for_(r_); }
121 /// @return next index value and increment
122 value_type next() {
123 value_type next;
124 using namespace boost::lambda;
125 typename value_type::iterator n = next.begin();
126 typename value_type::iterator i = index.begin();
127 boost::mpl::for_each<I>(*(var(n))++ = var(i)[_1]);
128
129 state_ = advance<N>(r_, index);
130 return next;
131 }
132 /// @return false if out of bounds, true otherwise
133 operator bool() { return state_; }
134
135 private:
136 /// initialize indices
137 struct initialize {
138 value_type &index_;
139 mutable size_t i_;
140 initialize(value_type &index) : index_(index), i_(0) {}
141 template<class R_> void operator()(R_& r) const {
142 index_[i_++] = r.lower(index_);
143 }
144 };
145
146 /// advance index[0:M)
147 template<size_t M>
148 struct advance {
149 /// stop recursion
150 struct stop {
151 stop(R r, value_type &index) {}
152 };
153 /// advance index
154 /// @param r range tuple
155 /// @param index index array
156 advance(R &r, value_type &index) : index_(index), i_(0) {
157 namespace fusion = boost::fusion;
158 index[M-1] += 1; // increment index
159 fusion::for_each(r, *this); // update indices
160 state_ = index[M-1] >= fusion::at_c<M-1>(r).upper(index);
161 if (state_) { // out of bounds
162 typename boost::mpl::if_c<(M > 1),
163 advance<M-1>, stop>::type(r, index);
164 }
165 }
166 /// apply lower bound of range to index
167 template<typename R_> void operator()(R_& r) const {
168 if (i_ >= M) index_[i_] = r.lower(index_);
169 ++i_;
170 }
171 /// @return false if out of bounds, true otherwise
172 operator bool() { return state_; }
173 private:
174 value_type &index_; ///< index array reference
175 mutable size_t i_; ///< running index
176 bool state_; ///< out of bounds state
177 };
178
179 value_type index;
180 range_tuple r_;
181 bool state_;
182 };
183
184
185 /// polymorphic generator template base
186 template<typename T,size_t N>
187 struct For : boost::noncopyable {
188 typedef boost::array<T,N> value_type;
189 /// @return next index value and increment
190 value_type next() { return for_->next(); }
191 /// @return false if out of bounds, true otherwise
192 operator bool() const { return for_; }
193 protected:
194 /// reset smart pointer
195 void reset(for_base<T,N> *f) { for_.reset(f); }
196 std::auto_ptr<for_base<T,N> > for_;
197 };
198
199 /// range [T,R) type
200 template<typename T, typename R>
201 struct range_type {
202 typedef range_<T,R> type;
203 };
204
205 /// range identity specialization
206 template<typename T, class L, class U>
207 struct range_type<T, range_<L,U> > {
208 typedef range_<L,U> type;
209 };
210
211 namespace fusion = boost::fusion;
212 namespace mpl = boost::mpl;
213
214 template<typename T, size_t N, class R1, class R2, class R3, class R4>
215 struct range_tuple {
216 // full range vector
217 typedef typename mpl::vector<R1,R2,R3,R4> v;
218 typedef typename mpl::end<v>::type end;
219 typedef typename mpl::advance_c<typename mpl::begin<v>::type, N>::type pos;
220 // [0:N) range vector
221 typedef typename mpl::erase<v, pos, end>::type t;
222 // transform into proper range fusion::vector
223 typedef typename fusion::result_of::as_vector<
224 typename mpl::transform<t,range_type<T, mpl::_1> >::type
225 >::type type;
226 };
227
228
229 template<typename T, size_t N,
230 class R1, class R2, class R3, class R4,
231 class O>
232 struct for_type {
233 typedef typename range_tuple<T,N,R1,R2,R3,R4>::type range_tuple;
234 typedef for_<T, N, range_tuple, O> type;
235 };
236
237 } // namespace detail
238
239
240 /// default index order, [0:N)
241 template<size_t N>
242 struct order {
243 typedef boost::mpl::range_c<size_t,0, N> type;
244 };
245
246 /// N-loop generator, 0 < N <= 5
247 /// @tparam T index type
248 /// @tparam N number of indices/loops
249 /// @tparam R1,... range types
250 /// @tparam O index order
251 template<typename T, size_t N,
252 class R1, class R2 = void, class R3 = void, class R4 = void,
253 class O = typename order<N>::type>
254 struct for_ : detail::for_type<T, N, R1, R2, R3, R4, O>::type {
255 typedef typename detail::for_type<T, N, R1, R2, R3, R4, O>::type base_type;
256 typedef typename base_type::range_tuple range_tuple;
257 for_(const range_tuple &range) : base_type(range) {}
258 };
259
260 /// loop range [L:U)
261 /// @tparam L lower bound type
262 /// @tparam U upper bound type
263 /// @return range
264 template<class L, class U>
265 detail::range_<L,U> range(L lower, U upper) {
266 return detail::range_<L,U>(lower, upper);
267 }
268
269 /// make 4-loop generator with specified index ordering
270 template<typename T, class R1, class R2, class R3, class R4, class O>
271 for_<T, 4, R1, R2, R3, R4, O>
272 make_for(R1 r1, R2 r2, R3 r3, R4 r4, const O&) {
273 typedef for_<T, 4, R1, R2, R3, R4, O> F;
274 return F(F::range_tuple(r1, r2, r3, r4));
275 }
276
277 /// polymorphic generator template forward declaration
278 template<typename T,size_t N>
279 struct For;
280
281 /// polymorphic 4-loop generator
282 template<typename T>
283 struct For<T,4> : detail::For<T,4> {
284 /// generator with default index ordering
285 template<class R1, class R2, class R3, class R4>
286 For(R1 r1, R2 r2, R3 r3, R4 r4) {
287 this->reset(make_for<T>(r1, r2, r3, r4).new_());
288 }
289 /// generator with specified index ordering
290 template<class R1, class R2, class R3, class R4, class O>
291 For(R1 r1, R2 r2, R3 r3, R4 r4, O o) {
292 this->reset(make_for<T>(r1, r2, r3, r4, o).new_());
293 }
294 };
295
296 }
297
298
299 #endif /* _GENERATOR_HPP_ */