1 #ifndef BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED
2 #define BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED
3 
4 //  Copyright 2017 Peter Dimov.
5 //
6 //  Distributed under the Boost Software License, Version 1.0.
7 //
8 //  See accompanying file LICENSE_1_0.txt or copy at
9 //  http://www.boost.org/LICENSE_1_0.txt
10 
11 #include <boost/mp11/integral.hpp>
12 #include <boost/mp11/detail/config.hpp>
13 #include <type_traits>
14 #include <utility>
15 #include <cassert>
16 
17 #if defined( BOOST_MP11_HAS_CXX14_CONSTEXPR )
18 # define BOOST_MP11_CONSTEXPR14 constexpr
19 #else
20 # define BOOST_MP11_CONSTEXPR14
21 #endif
22 
23 #if defined( _MSC_VER ) && !defined( __clang__ )
24 # define BOOST_MP11_UNREACHABLE() __assume(false)
25 #else
26 # define BOOST_MP11_UNREACHABLE() __builtin_unreachable()
27 #endif
28 
29 namespace boost
30 {
31 namespace mp11
32 {
33 
34 namespace detail
35 {
36 
37 template<std::size_t N> struct mp_with_index_impl_
38 {
callboost::mp11::detail::mp_with_index_impl_39     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
40     {
41         switch( i )
42         {
43         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
44         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
45         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
46         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
47         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
48         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
49         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
50         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
51         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
52         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
53         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
54         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
55         case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
56         case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
57         case 14: return std::forward<F>(f)( mp_size_t<K+14>() );
58         case 15: return std::forward<F>(f)( mp_size_t<K+15>() );
59         }
60 
61         return mp_with_index_impl_<N-16>::template call<K+16>( i-16, std::forward<F>(f) );
62     }
63 };
64 
65 template<> struct mp_with_index_impl_<0>
66 {
67 };
68 
69 template<> struct mp_with_index_impl_<1>
70 {
callboost::mp11::detail::mp_with_index_impl_71     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t /*i*/, F && f )
72     {
73         return std::forward<F>(f)( mp_size_t<K+0>() );
74     }
75 };
76 
77 template<> struct mp_with_index_impl_<2>
78 {
callboost::mp11::detail::mp_with_index_impl_79     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
80     {
81         switch( i )
82         {
83         default: BOOST_MP11_UNREACHABLE();
84         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
85         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
86         }
87     }
88 };
89 
90 template<> struct mp_with_index_impl_<3>
91 {
callboost::mp11::detail::mp_with_index_impl_92     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
93     {
94         switch( i )
95         {
96         default: BOOST_MP11_UNREACHABLE();
97         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
98         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
99         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
100         }
101     }
102 };
103 
104 template<> struct mp_with_index_impl_<4>
105 {
callboost::mp11::detail::mp_with_index_impl_106     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
107     {
108         switch( i )
109         {
110         default: BOOST_MP11_UNREACHABLE();
111         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
112         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
113         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
114         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
115         }
116     }
117 };
118 
119 template<> struct mp_with_index_impl_<5>
120 {
callboost::mp11::detail::mp_with_index_impl_121     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
122     {
123         switch( i )
124         {
125         default: BOOST_MP11_UNREACHABLE();
126         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
127         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
128         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
129         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
130         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
131         }
132     }
133 };
134 
135 template<> struct mp_with_index_impl_<6>
136 {
callboost::mp11::detail::mp_with_index_impl_137     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
138     {
139         switch( i )
140         {
141         default: BOOST_MP11_UNREACHABLE();
142         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
143         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
144         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
145         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
146         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
147         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
148         }
149     }
150 };
151 
152 template<> struct mp_with_index_impl_<7>
153 {
callboost::mp11::detail::mp_with_index_impl_154     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
155     {
156         switch( i )
157         {
158         default: BOOST_MP11_UNREACHABLE();
159         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
160         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
161         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
162         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
163         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
164         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
165         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
166         }
167     }
168 };
169 
170 template<> struct mp_with_index_impl_<8>
171 {
callboost::mp11::detail::mp_with_index_impl_172     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
173     {
174         switch( i )
175         {
176         default: BOOST_MP11_UNREACHABLE();
177         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
178         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
179         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
180         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
181         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
182         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
183         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
184         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
185         }
186     }
187 };
188 
189 template<> struct mp_with_index_impl_<9>
190 {
callboost::mp11::detail::mp_with_index_impl_191     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
192     {
193         switch( i )
194         {
195         default: BOOST_MP11_UNREACHABLE();
196         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
197         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
198         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
199         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
200         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
201         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
202         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
203         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
204         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
205         }
206     }
207 };
208 
209 template<> struct mp_with_index_impl_<10>
210 {
callboost::mp11::detail::mp_with_index_impl_211     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
212     {
213         switch( i )
214         {
215         default: BOOST_MP11_UNREACHABLE();
216         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
217         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
218         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
219         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
220         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
221         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
222         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
223         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
224         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
225         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
226         }
227     }
228 };
229 
230 template<> struct mp_with_index_impl_<11>
231 {
callboost::mp11::detail::mp_with_index_impl_232     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
233     {
234         switch( i )
235         {
236         default: BOOST_MP11_UNREACHABLE();
237         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
238         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
239         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
240         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
241         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
242         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
243         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
244         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
245         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
246         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
247         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
248         }
249     }
250 };
251 
252 template<> struct mp_with_index_impl_<12>
253 {
callboost::mp11::detail::mp_with_index_impl_254     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
255     {
256         switch( i )
257         {
258         default: BOOST_MP11_UNREACHABLE();
259         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
260         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
261         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
262         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
263         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
264         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
265         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
266         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
267         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
268         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
269         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
270         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
271         }
272     }
273 };
274 
275 template<> struct mp_with_index_impl_<13>
276 {
callboost::mp11::detail::mp_with_index_impl_277     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
278     {
279         switch( i )
280         {
281         default: BOOST_MP11_UNREACHABLE();
282         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
283         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
284         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
285         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
286         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
287         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
288         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
289         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
290         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
291         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
292         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
293         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
294         case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
295         }
296     }
297 };
298 
299 template<> struct mp_with_index_impl_<14>
300 {
callboost::mp11::detail::mp_with_index_impl_301     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
302     {
303         switch( i )
304         {
305         default: BOOST_MP11_UNREACHABLE();
306         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
307         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
308         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
309         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
310         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
311         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
312         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
313         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
314         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
315         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
316         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
317         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
318         case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
319         case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
320         }
321     }
322 };
323 
324 template<> struct mp_with_index_impl_<15>
325 {
callboost::mp11::detail::mp_with_index_impl_326     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
327     {
328         switch( i )
329         {
330         default: BOOST_MP11_UNREACHABLE();
331         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
332         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
333         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
334         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
335         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
336         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
337         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
338         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
339         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
340         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
341         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
342         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
343         case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
344         case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
345         case 14: return std::forward<F>(f)( mp_size_t<K+14>() );
346         }
347     }
348 };
349 
350 template<> struct mp_with_index_impl_<16>
351 {
callboost::mp11::detail::mp_with_index_impl_352     template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
353     {
354         switch( i )
355         {
356         default: BOOST_MP11_UNREACHABLE();
357         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
358         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
359         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
360         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
361         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
362         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
363         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
364         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
365         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
366         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
367         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
368         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
369         case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
370         case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
371         case 14: return std::forward<F>(f)( mp_size_t<K+14>() );
372         case 15: return std::forward<F>(f)( mp_size_t<K+15>() );
373         }
374     }
375 };
376 
377 } // namespace detail
378 
mp_with_index(std::size_t i,F && f)379 template<std::size_t N, class F> inline BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && f )
380 {
381     assert( i < N );
382     return detail::mp_with_index_impl_<N>::template call<0>( i, std::forward<F>(f) );
383 }
384 
mp_with_index(std::size_t i,F && f)385 template<class N, class F> inline BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && f )
386 {
387     return mp_with_index<std::size_t{N::value}>( i, std::forward<F>(f) );
388 }
389 
390 #undef BOOST_MP11_CONSTEXPR14
391 #undef BOOST_MP11_UNREACHABLE
392 
393 } // namespace mp11
394 } // namespace boost
395 
396 #endif // #ifndef BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED
397