mpl_nested_loop.hh 4.81 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
//
// 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;
//
49
50
51
//     any x = float(2);
//     any y = string("foo");
//     any z = size_t(42);
52
//
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//     bool found = nested_for_each<r1,r2,r3>(foo(), x, y, z);
//
// The code above will run iterate through all combinations of foo::operator(T1,
// T2, T3) and call the one that corresponds to the actual types stored in x, y,
// and z. If the types are not found during iteration, we have found = true,
// otherwise found = false. This provides a more general compile-time to
// run-time bridge than the simpler mpl::for_each().

template <class Action, class T>
struct bind_arg
{
    bind_arg(Action a, any& arg, bool& found)
        : _a(a), _arg(arg), _found(found) {}

    template <class... Ts>
    __attribute__((always_inline))
    void operator()(Ts&&... args) const
    {
        T* v = const_cast<T*>(any_cast<T>(&_arg));
        if (v != 0)
            _a(*v, args...);
    }

    __attribute__((always_inline))
    void operator()() const
    {
        T* v = const_cast<T*>(any_cast<T>(&_arg));
        if (v != 0)
        {
            _a(*v);
            _found = true;
        }
    }

    Action _a;
    any& _arg;
    bool& _found;
};

92

93
template <class Action>
94
struct dispatch
95
{
96
97
    dispatch(Action a, any* args, bool& found)
        : _a(a), _args(args), _found(found) {}
98

99
    template <class T>
100
101
    __attribute__((always_inline))
    auto get_next() const
102
    {
103
104
        bind_arg<Action, T> a(_a, *_args, _found);
        return dispatch<bind_arg<Action, T>>(a, _args + 1, _found);
105
    }
106

107
    template <class T>
108
    __attribute__((always_inline))
109
    void operator()(T) const
110
    {
111
112
        bind_arg<Action, T> a(_a, *_args, _found);
        a();
113
    }
114

115
    __attribute__((always_inline))
116
    void operator()() const
117
    {
118
        _a();
119
    }
120

121
    Action _a;
122
123
124
125
126
127
128
129
130
131
132
133
134
    any* _args;
    bool& _found;
};

template <class F>
inline void for_each_pack(F)
{};

template <class F, class T, class... Ts>
inline void for_each_pack(F f)
{
    f(T());
    for_each_pack<F, Ts...>(f);
135
};
136

137
138
139
140
141
142
143
144
145
146
147
148
149
150
template <class F, class Seq, class Iter, class... Ts>
inline void for_each_alt(F f, Iter)
{
    for_each_alt<F, Seq, typename next<Iter>::type, Ts...,
                 typename deref<Iter>::type>
        (f, typename next<Iter>::type());
}

template <class F, class Seq, class Iter, class... Ts>
inline void for_each_alt(F f, typename end<Seq>::type)
{
    for_each_pack<F, Ts...>(f);
}

151
152
template <class TR1, class... TRS, class Action>
void nested_for_each_imp(Action a);
153

154
155
156
157
template <class Action, class... TRS>
struct inner_loop
{
    inner_loop(Action a): _a(a) {}
158

159
    template <class T>
160
    __attribute__((always_inline))
161
    void operator()(T) const
162
    {
163
        nested_for_each_imp<TRS...>(_a.template get_next<T>());
164
165
166
    }
    Action _a;
};
167

168
169
170
template <class TR1, class... TRS, class Action>
void nested_for_each_imp(Action a)
{
171
172
173
    for_each_alt<inner_loop<Action, TRS...>,
                 TR1, typename begin<TR1>::type>
        (inner_loop<Action, TRS...>(a), typename begin<TR1>::type());
174
}
175

176
177
178
179
180
template <class Action>
void nested_for_each_imp(Action a)
{
    a();
}
181

182
183
template <class... TRS, class Action, class... Args>
bool nested_for_each(Action a, Args... args)
184
{
185
    bool found = false;
Tiago Peixoto's avatar
Tiago Peixoto committed
186
    std::array<any, sizeof...(args)> as{{args...}};
187
    auto b = dispatch<Action>(a, &as[0], found);
188
    nested_for_each_imp<TRS...>(b);
189
    return found;
190
}
191
192
193
194
195

} // mpl namespace
} // boost namespace

#endif //NESTED_FOR_LOOP_HH