mpl_nested_loop.hh 4.29 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-2020 Tiago de Paula Peixoto <tiago@skewed.de>
4
//
5
6
7
8
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 3 of the License, or (at your option) any
// later version.
9
//
10
11
12
13
// 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 Lesser General Public License for more
// details.
14
//
15
// You should have received a copy of the GNU Lesser General Public License
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
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#ifndef NESTED_FOR_LOOP_HH
#define NESTED_FOR_LOOP_HH

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;
//
44
45
46
//     any x = float(2);
//     any y = string("foo");
//     any z = size_t(42);
47
//
48
49
50
51
//     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,
52
53
// 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
54
55
// run-time bridge than the simpler mpl::for_each().

56
57
58

// this is a functor wrapper that will perform an any_cast<> in each in an array
// of arguments according to the called types. If the cast is successful, the
59
// function will be called with those types, and true will be returned.
60

61
62
63
// recursion-free variadic version of for_each
template <class...>
struct for_each_variadic;
64

65
66
template <class F, class... Ts>
struct for_each_variadic<F,std::tuple<Ts...>>
67
{
68
    bool operator()(F f)
69
    {
70
71
        auto call = [&](auto&& arg) -> bool {return f(std::forward<decltype(arg)>(arg));};
        return (call(typename std::add_pointer<Ts>::type()) || ...);
72
    }
73
74
};

75
76
77
// convert mpl sequence to std::tuple
template <class T, class R>
struct to_tuple_imp;
78

79
80
template <class... Ts, class X>
struct to_tuple_imp<std::tuple<Ts...>, X>
81
{
82
    typedef std::tuple<Ts..., X> type;
83
};
84

85
86
template <class Seq>
struct to_tuple
87
{
88
89
90
91
    typedef typename mpl::fold<Seq, std::tuple<>,
                               to_tuple_imp<mpl::_1, mpl::_2>>::type type;
};

92
93
94
template <class Seq>
using to_tuple_t = typename to_tuple<Seq>::type;

95
96
97
98
// nested type loops via variadic templates

template <class...>
struct inner_loop {};
99

100
101
template <class Action, class... Ts>
struct inner_loop<Action, std::tuple<Ts...>>
102
{
103
    inner_loop(Action a): _a(a) {}
104

105
    template <class T>
106
    [[gnu::always_inline]]
107
108
109
    bool operator()(T*) const
    { return _a(typename std::add_pointer<Ts>::type()...,
                typename std::add_pointer<T>::type()); }  // innermost loop
110
111
    Action _a;
};
112

113
114
template <class Action, class... Ts, class TR1, class... TRS>
struct inner_loop<Action, std::tuple<Ts...>, TR1, TRS...>
115
116
{
    inner_loop(Action a): _a(a) {}
117

118
    template <class T>
119
    [[gnu::always_inline]]
120
    bool operator()(T*) const
121
    {
122
123
        typedef inner_loop<Action, std::tuple<Ts..., T>, TRS...> inner_loop_t;
        typedef typename to_tuple<TR1>::type tr_tuple;
124
        return for_each_variadic<inner_loop_t, tr_tuple>()(inner_loop_t(_a));
125
126
127
    }
    Action _a;
};
128

129
// final function
130

131
132
133
template <class TR1, class... TRS, class Action>
void nested_for_each(Action a)
{
134
135
136
    typedef typename to_tuple<TR1>::type tr_tuple;

    // wrap action into a bool-returning function
137
    auto ab = [=](auto*... args) -> bool { a(args...); return false; };
138
139
140

    typedef inner_loop<decltype(ab), std::tuple<>, TRS...> inner_loop_t;
    for_each_variadic<inner_loop_t, tr_tuple>()(inner_loop_t(ab));
141
142
143
}


144
145
146
147
} // mpl namespace
} // boost namespace

#endif //NESTED_FOR_LOOP_HH