source: src/graph/mpl_nested_loop.hh @ b9bbc3

Revision b9bbc3, 9.3 KB checked in by Tiago de Paula Peixoto <tiago@…>, 3 years ago (diff)
Update encoding and copyright information in source files
  • Property mode set to 100644
Line 
1// graph-tool -- a general graph modification and manipulation thingy
2//
3// Copyright (C) 2007-2010 Tiago de Paula Peixoto <tiago@forked.de>
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version 3
8// of the License, or (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18#ifndef NESTED_FOR_LOOP_HH
19#define NESTED_FOR_LOOP_HH
20
21#include <boost/mpl/for_each.hpp>
22#include <boost/mpl/vector.hpp>
23#include <boost/mpl/empty.hpp>
24#include <boost/any.hpp>
25
26namespace boost
27{
28namespace mpl
29{
30// The following is a implementation of a nested for_each loop, which runs a
31// given Action functor for each combination of its arguments, given by the type
32// ranges, as such:
33//
34//     struct foo
35//     {
36//         template<class T1, class T2, class T3>
37//         void operator()(T1, T2, T3) const
38//         {
39//             ...
40//         }
41//     };
42//
43//     ...
44//
45//     typedef mpl::vector<int,float,long> r1;
46//     typedef mpl::vector<string,double> r2;
47//     typedef mpl::vector<size_t,char> r3;
48//
49//     nested_for_each<r1,r2,r3>(foo());
50//
51// The code above will run foo::operator(T1, T2, T3) for all combinations given
52// by r1, r2 and r3. This provides a more general compile-time to run-time
53// meta-programming than the more simple mpl::for_each().
54//
55// Implementation notes: This supports up to 5 nested type ranges. In principle
56// this could be generalized, and a lot of the boiler plate code in the
57// implementation could be eliminated, by making more thorough use of MPL's
58// meta-functions. My attempts to do this, however, tried to make use of
59// lambda's bind function, which requires the arity of the function being bound
60// to be known in advance. I tried to implement a bind_last() function, which
61// always binds the last argument of a given functor, independently of its exact
62// arity, but it made use of the typeof operator a lot, and at a given point
63// caused GCC (4.2.2) to ICE... Thus, I decided to write the inner loops by
64// hand, and wait before GCC implements the auto and typedecl functionality of
65// c++0x, making the life of C++ template meta-programmers less horrible.
66//
67// In any case, "five nested levels should be enough for everybody".
68
69template <class TR1, class TR2, class TR3, class TR4, class TR5>
70struct nested_for_each
71{
72    template <class Action>
73    void operator()(Action a) const
74    {
75        for_each<TR1>(inner_loop1<Action>(a));
76    }
77
78    template <class Action>
79    struct inner_loop1
80    {
81        inner_loop1(Action a): _a(a) {}
82
83        template <class T1>
84        void operator()(T1) const
85        {
86            typedef typename mpl::if_<mpl::empty<TR3>,
87                                      TR2,
88                                      mpl::vector<> >::type eval_range;
89            if(mpl::empty<TR3>::type::value)
90                for_each<eval_range>(eval_action2<Action,T1>(_a));
91            else
92                for_each<TR2>(inner_loop2<Action,T1>(_a));
93        }
94
95        Action _a;
96    };
97
98    template<class Action, class T1>
99    struct inner_loop2
100    {
101        inner_loop2(Action a): _a(a) {}
102
103        template <class T2>
104        void operator()(T2) const
105        {
106            typedef typename mpl::if_<mpl::empty<TR4>,
107                                      TR3,
108                                      mpl::vector<> >::type eval_range;
109            if(mpl::empty<TR4>::type::value)
110                for_each<eval_range>(eval_action3<Action,T1,T2>(_a));
111            else
112                for_each<TR3>(inner_loop3<Action, T1, T2>(_a));
113        }
114
115        Action _a;
116    };
117
118    template<class Action, class T1, class T2>
119    struct inner_loop3
120    {
121        inner_loop3(Action a): _a(a) {}
122
123        template <class T3>
124        void operator()(T3) const
125        {
126            typedef typename mpl::if_<mpl::empty<TR5>,
127                                      TR4,
128                                      mpl::vector<> >::type eval_range;
129            if(mpl::empty<TR5>::type::value)
130                for_each<eval_range>(eval_action4<Action,T1,T2,T3>(_a));
131            else
132                for_each<TR4>(inner_loop4<Action, T1, T2, T3>(_a));
133        }
134
135        Action _a;
136    };
137
138    template<class Action, class T1, class T2, class T3>
139    struct inner_loop4
140    {
141        inner_loop4(Action a): _a(a) {}
142
143        template <class T4>
144        void operator()(T4) const
145        {
146            for_each<TR5>(eval_action5<Action, T1, T2, T3, T4>(_a));
147        }
148
149        Action _a;
150    };
151
152    template<class Action, class T1>
153    struct eval_action2
154    {
155        eval_action2(Action a): _a(a) {}
156
157        template <class T2>
158        void operator()(T2) const
159        {
160            _a(T1(), T2());
161        }
162
163        Action _a;
164    };
165
166    template<class Action, class T1, class T2>
167    struct eval_action3
168    {
169        eval_action3(Action a): _a(a) {}
170
171        template <class T3>
172        void operator()(T3) const
173        {
174            _a(T1(), T2(), T3());
175        }
176
177        Action _a;
178    };
179
180    template<class Action, class T1, class T2, class T3>
181    struct eval_action4
182    {
183        eval_action4(Action a): _a(a) {}
184
185        template <class T4>
186        void operator()(T4) const
187        {
188            _a(T1(), T2(), T3(), T4());
189        }
190
191        Action _a;
192    };
193
194    template<class Action, class T1, class T2, class T3, class T4>
195    struct eval_action5
196    {
197        eval_action5(Action a): _a(a) {}
198
199        template <class T5>
200        void operator()(T5) const
201        {
202            _a(T1(), T2(), T3(), T4(), T5());
203        }
204
205        Action _a;
206        };
207};
208
209template <class TR1, class TR2, class TR3 = mpl::vector<>,
210          class TR4 = mpl::vector<>, class TR5 = mpl::vector<> >
211struct nested_for_each;
212
213// The functor below wraps another functor Action, but only calls it for the
214// correct argument types, determined at runtime. Together with
215// nested_for_each() above, it provides general means of selecting static
216// polymorphic implementation of algorithms at run-time, as such:
217//
218//    struct foo
219//    {
220//        template <class T1, class T2>
221//        void operator()(T1 x, T2 y) const
222//        {
223//            ... do something with x and y ...
224//        }x
225//    };
226//
227//    typedef mpl::vector<double,std::string,int> types;
228//
229//    any x = double(1.0)               // determined at run-time
230//    any y = std::string("user input") // determined at run-time
231//
232//    bool found;
233//    mpl::nested_for_each<types,types>(mpl::select_types(foo, x, y));
234//
235// The last line will call foo::operator()(double, std::string) passing the
236// values of x and y, and the found variable will contain the value 'true'.
237
238template <class Action> struct selected_types; // forward decl.
239
240template <class Action>
241selected_types<Action>
242select_types(Action a, bool& found, any a1 = any(), any a2 = any(),
243             any a3 = any(), any a4 = any(), any a5 = any())
244{
245    return selected_types<Action>(a, found, a1, a2, a3, a4, a5);
246}
247
248template <class Action>
249struct selected_types
250{
251    selected_types(Action a, bool& found, any a1, any a2, any a3, any a4,
252                   any a5)
253        : _a(a), _found(found), _a1(a1), _a2(a2), _a3(a3), _a4(a4), _a5(a5) {}
254
255    template <class T1>
256    void operator()(T1) const
257    {
258        const T1* a1 = any_cast<T1>(&_a1);
259        if (a1 != 0)
260        {
261            _a(*a1);
262            _found = true;
263        }
264    }
265
266    template <class T1, class T2>
267    void operator()(T1, T2) const
268    {
269        const T1* a1 = any_cast<T1>(&_a1);
270        const T2* a2 = any_cast<T2>(&_a2);
271        if (a1 != 0 && a2 != 0)
272        {
273            _a(*a1, *a2);
274            _found = true;
275        }
276    }
277
278    template <class T1, class T2, class T3>
279    void operator()(T1, T2, T3) const
280    {
281        const T1* a1 = any_cast<T1>(&_a1);
282        const T2* a2 = any_cast<T2>(&_a2);
283        const T3* a3 = any_cast<T3>(&_a3);
284
285        if (a1 != 0 && a2 != 0 && a3 != 0)
286        {
287            _a(*a1, *a2, *a3);
288            _found = true;
289        }
290    }
291
292    template <class T1, class T2, class T3, class T4>
293    void operator()(T1, T2, T3, T4) const
294    {
295        const T1* a1 = any_cast<T1>(&_a1);
296        const T2* a2 = any_cast<T2>(&_a2);
297        const T3* a3 = any_cast<T3>(&_a3);
298        const T4* a4 = any_cast<T4>(&_a4);
299
300        if (a1 != 0 && a2 != 0 && a3 != 0 && a4 != 0)
301        {
302            _a(*a1, *a2, *a3, *a4);
303            _found = true;
304        }
305
306    }
307
308    template <class T1, class T2, class T3, class T4, class T5>
309    void operator()(T1, T2, T3, T4, T5) const
310    {
311        const T1* a1 = any_cast<T1>(&_a1);
312        const T2* a2 = any_cast<T2>(&_a2);
313        const T3* a3 = any_cast<T3>(&_a3);
314        const T4* a4 = any_cast<T4>(&_a4);
315        const T5* a5 = any_cast<T5>(&_a5);
316
317        if (a1 != 0 && a2 != 0 && a3 != 0 && a4 != 0 && a5 != 0)
318        {
319            _a(*a1, *a2, *a3, *a4, *a5);
320            _found = true;
321        }
322    }
323
324    Action _a;
325    bool& _found;
326    any _a1, _a2, _a3, _a4, _a5;
327};
328
329} // mpl namespace
330} // boost namespace
331
332#endif //NESTED_FOR_LOOP_HH
Note: See TracBrowser for help on using the repository browser.