mpl_nested_loop.hh 4.86 KB
Newer Older
1
2
// graph-tool -- a general graph modification and manipulation thingy
//
Tiago Peixoto's avatar
Tiago Peixoto committed
3
// Copyright (C) 2006-2015 Tiago de Paula Peixoto <tiago@skewed.de>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#ifndef NESTED_FOR_LOOP_HH
#define NESTED_FOR_LOOP_HH

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/any.hpp>

namespace boost
{
namespace mpl
{
// The following is a implementation of a nested for_each loop, which runs a
// given Action functor for each combination of its arguments, given by the type
// ranges, as such:
//
//     struct foo
//     {
//         template<class T1, class T2, class T3>
//         void operator()(T1, T2, T3) const
//         {
//             ...
//         }
//     };
//
//     ...
//
//     typedef mpl::vector<int,float,long> r1;
//     typedef mpl::vector<string,double> r2;
//     typedef mpl::vector<size_t,char> r3;
//
//     nested_for_each<r1,r2,r3>(foo());
//
// The code above will run foo::operator(T1, T2, T3) for all combinations given
// by r1, r2 and r3. This provides a more general compile-time to run-time
// meta-programming than the more simple mpl::for_each().

55
56
template <class Action, class... Args>
struct dispatch
57
{
58
    dispatch(Action a): _a(a) {}
59

60
61
    template <class T>
    dispatch<Action, Args..., T> join() const
62
    {
63
64
        return dispatch<Action, Args..., T>(_a);
    }
65

66
67
    template <class T>
    void operator()(T) const
68
    {
69
70
        _a(Args()..., T());
    }
71

72
    void operator()() const
73
    {
74
75
        _a(Args()...);
    }
76

77
78
    Action _a;
};
79

80
81
template <class TR1, class... TRS, class Action>
void nested_for_each_imp(Action a);
82

83
84
85
86
template <class Action, class... TRS>
struct inner_loop
{
    inner_loop(Action a): _a(a) {}
87

88
89
    template <class T>
    void operator()(T) const
90
    {
91
        nested_for_each_imp<TRS...>(_a.template join<T>());
92
    }
93

94
95
    Action _a;
};
96

97
98
99
100
101
template <class TR1, class... TRS, class Action>
void nested_for_each_imp(Action a)
{
    for_each<TR1>(inner_loop<Action, TRS...>(a));
}
102

103
104
105
106
107
template <class Action>
void nested_for_each_imp(Action a)
{
    a();
}
108

109
110
111
112
113
114
template <class... TRS, class Action>
void nested_for_each(Action a)
{
    auto b = dispatch<Action>(a);
    nested_for_each_imp<TRS...>(b);
}
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143


// The functor below wraps another functor Action, but only calls it for the
// correct argument types, determined at runtime. Together with
// nested_for_each() above, it provides general means of selecting static
// polymorphic implementation of algorithms at run-time, as such:
//
//    struct foo
//    {
//        template <class T1, class T2>
//        void operator()(T1 x, T2 y) const
//        {
//            ... do something with x and y ...
//        }x
//    };
//
//    typedef mpl::vector<double,std::string,int> types;
//
//    any x = double(1.0)               // determined at run-time
//    any y = std::string("user input") // determined at run-time
//
//    bool found;
//    mpl::nested_for_each<types,types>(mpl::select_types(foo, x, y));
//
// The last line will call foo::operator()(double, std::string) passing the
// values of x and y, and the found variable will contain the value 'true'.

template <class Action> struct selected_types; // forward decl.

144
template <class Action, class... Args>
145
selected_types<Action>
146
select_types(Action a, bool& found, Args... args)
147
{
148
    return selected_types<Action>(a, found, args...);
149
150
151
152
153
}

template <class Action>
struct selected_types
{
154
155
156
    template <class... Args>
    selected_types(Action a, bool& found, Args&&... args)
        : _a(a), _found(found)
157
    {
158
        _args = {args...};
159
160
161
    }


162
163
    template <class... Args, class T, class... Ts>
    void dispatch(unsigned int i, std::tuple<T, Ts...>, Args&&... args) const
164
    {
165
166
167
168
        assert(i < _args.size());
        T* a = const_cast<T*>(any_cast<T>(&_args[i]));
        if (a != 0)
            dispatch(i + 1, std::tuple<Ts...>(), std::forward<Args>(args)..., *a);
169
170
    }

171
    template <class... Args>
172
    void dispatch(unsigned int, std::tuple<>, Args&&... args) const
173
    {
174
175
        _a(std::forward<Args>(args)...);
        _found = true;
176
177
    }

178
    template <class... Ts>
179
    void operator()(Ts&&...) const
180
    {
181
        dispatch(0, std::tuple<Ts...>());
182
183
184
185
    }

    Action _a;
    bool& _found;
186
    std::vector<any> _args;
187
188
189
190
191
192
};

} // mpl namespace
} // boost namespace

#endif //NESTED_FOR_LOOP_HH