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( __GNUC__ ) || defined( __clang__ )
24 # define BOOST_MP11_UNREACHABLE_DEFAULT default: __builtin_unreachable();
25 #elif defined( _MSC_VER )
26 # define BOOST_MP11_UNREACHABLE_DEFAULT default: __assume(false);
27 #else
28 # define BOOST_MP11_UNREACHABLE_DEFAULT
29 #endif
30 
31 namespace boost
32 {
33 namespace mp11
34 {
35 
36 namespace detail
37 {
38 
39 template<std::size_t N> struct mp_with_index_impl_
40 {
callboost::mp11::detail::mp_with_index_impl_41     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 )
42     {
43         if( i < N / 2 )
44         {
45             return mp_with_index_impl_<N/2>::template call<K>( i, std::forward<F>(f) );
46         }
47         else
48         {
49             return mp_with_index_impl_<N-N/2>::template call<K+N/2>( i - N/2, std::forward<F>(f) );
50         }
51     }
52 };
53 
54 template<> struct mp_with_index_impl_<0>
55 {
56 };
57 
58 template<> struct mp_with_index_impl_<1>
59 {
callboost::mp11::detail::mp_with_index_impl_60     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 )
61     {
62         return std::forward<F>(f)( mp_size_t<K+0>() );
63     }
64 };
65 
66 template<> struct mp_with_index_impl_<2>
67 {
callboost::mp11::detail::mp_with_index_impl_68     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 )
69     {
70         switch( i )
71         {
72         BOOST_MP11_UNREACHABLE_DEFAULT
73         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
74         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
75         }
76     }
77 };
78 
79 template<> struct mp_with_index_impl_<3>
80 {
callboost::mp11::detail::mp_with_index_impl_81     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 )
82     {
83         switch( i )
84         {
85         BOOST_MP11_UNREACHABLE_DEFAULT
86         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
87         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
88         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
89         }
90     }
91 };
92 
93 template<> struct mp_with_index_impl_<4>
94 {
callboost::mp11::detail::mp_with_index_impl_95     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 )
96     {
97         switch( i )
98         {
99         BOOST_MP11_UNREACHABLE_DEFAULT
100         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
101         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
102         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
103         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
104         }
105     }
106 };
107 
108 template<> struct mp_with_index_impl_<5>
109 {
callboost::mp11::detail::mp_with_index_impl_110     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 )
111     {
112         switch( i )
113         {
114         BOOST_MP11_UNREACHABLE_DEFAULT
115         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
116         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
117         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
118         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
119         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
120         }
121     }
122 };
123 
124 template<> struct mp_with_index_impl_<6>
125 {
callboost::mp11::detail::mp_with_index_impl_126     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 )
127     {
128         switch( i )
129         {
130         BOOST_MP11_UNREACHABLE_DEFAULT
131         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
132         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
133         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
134         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
135         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
136         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
137         }
138     }
139 };
140 
141 template<> struct mp_with_index_impl_<7>
142 {
callboost::mp11::detail::mp_with_index_impl_143     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 )
144     {
145         switch( i )
146         {
147         BOOST_MP11_UNREACHABLE_DEFAULT
148         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
149         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
150         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
151         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
152         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
153         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
154         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
155         }
156     }
157 };
158 
159 template<> struct mp_with_index_impl_<8>
160 {
callboost::mp11::detail::mp_with_index_impl_161     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 )
162     {
163         switch( i )
164         {
165         BOOST_MP11_UNREACHABLE_DEFAULT
166         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
167         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
168         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
169         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
170         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
171         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
172         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
173         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
174         }
175     }
176 };
177 
178 template<> struct mp_with_index_impl_<9>
179 {
callboost::mp11::detail::mp_with_index_impl_180     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 )
181     {
182         switch( i )
183         {
184         BOOST_MP11_UNREACHABLE_DEFAULT
185         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
186         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
187         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
188         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
189         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
190         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
191         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
192         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
193         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
194         }
195     }
196 };
197 
198 template<> struct mp_with_index_impl_<10>
199 {
callboost::mp11::detail::mp_with_index_impl_200     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 )
201     {
202         switch( i )
203         {
204         BOOST_MP11_UNREACHABLE_DEFAULT
205         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
206         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
207         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
208         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
209         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
210         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
211         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
212         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
213         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
214         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
215         }
216     }
217 };
218 
219 template<> struct mp_with_index_impl_<11>
220 {
callboost::mp11::detail::mp_with_index_impl_221     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 )
222     {
223         switch( i )
224         {
225         BOOST_MP11_UNREACHABLE_DEFAULT
226         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
227         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
228         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
229         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
230         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
231         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
232         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
233         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
234         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
235         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
236         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
237         }
238     }
239 };
240 
241 template<> struct mp_with_index_impl_<12>
242 {
callboost::mp11::detail::mp_with_index_impl_243     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 )
244     {
245         switch( i )
246         {
247         BOOST_MP11_UNREACHABLE_DEFAULT
248         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
249         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
250         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
251         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
252         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
253         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
254         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
255         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
256         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
257         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
258         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
259         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
260         }
261     }
262 };
263 
264 template<> struct mp_with_index_impl_<13>
265 {
callboost::mp11::detail::mp_with_index_impl_266     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 )
267     {
268         switch( i )
269         {
270         BOOST_MP11_UNREACHABLE_DEFAULT
271         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
272         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
273         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
274         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
275         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
276         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
277         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
278         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
279         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
280         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
281         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
282         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
283         case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
284         }
285     }
286 };
287 
288 template<> struct mp_with_index_impl_<14>
289 {
callboost::mp11::detail::mp_with_index_impl_290     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 )
291     {
292         switch( i )
293         {
294         BOOST_MP11_UNREACHABLE_DEFAULT
295         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
296         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
297         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
298         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
299         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
300         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
301         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
302         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
303         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
304         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
305         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
306         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
307         case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
308         case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
309         }
310     }
311 };
312 
313 template<> struct mp_with_index_impl_<15>
314 {
callboost::mp11::detail::mp_with_index_impl_315     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 )
316     {
317         switch( i )
318         {
319         BOOST_MP11_UNREACHABLE_DEFAULT
320         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
321         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
322         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
323         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
324         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
325         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
326         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
327         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
328         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
329         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
330         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
331         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
332         case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
333         case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
334         case 14: return std::forward<F>(f)( mp_size_t<K+14>() );
335         }
336     }
337 };
338 
339 template<> struct mp_with_index_impl_<16>
340 {
callboost::mp11::detail::mp_with_index_impl_341     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 )
342     {
343         switch( i )
344         {
345         BOOST_MP11_UNREACHABLE_DEFAULT
346         case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
347         case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
348         case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
349         case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
350         case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
351         case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
352         case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
353         case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
354         case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
355         case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
356         case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
357         case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
358         case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
359         case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
360         case 14: return std::forward<F>(f)( mp_size_t<K+14>() );
361         case 15: return std::forward<F>(f)( mp_size_t<K+15>() );
362         }
363     }
364 };
365 
366 } // namespace detail
367 
mp_with_index(std::size_t i,F && f)368 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 )
369 {
370     assert( i < N );
371     return detail::mp_with_index_impl_<N>::template call<0>( i, std::forward<F>(f) );
372 }
373 
mp_with_index(std::size_t i,F && f)374 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 )
375 {
376     return mp_with_index<std::size_t{N::value}>( i, std::forward<F>(f) );
377 }
378 
379 #undef BOOST_MP11_CONSTEXPR14
380 #undef BOOST_MP11_UNREACHABLE_DEFAULT
381 
382 } // namespace mp11
383 } // namespace boost
384 
385 #endif // #ifndef BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED
386