utils.hpp 19.6 KB
Newer Older
1
2
3
4
5
6
7
// --------------------------------
// See LICENCE file at project root
// File : meta/utils.hpp
// --------------------------------
#ifndef SCALFMM_META_UTILS_HPP
#define SCALFMM_META_UTILS_HPP

ESTERIE Pierre's avatar
ESTERIE Pierre committed
8
#include <algorithm>
9
#include <any>
10
#include <array>
11
#include <bits/c++config.h>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
12
13
14
#include <functional>
#include <iomanip>
#include <iostream>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
15
#include <memory>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
16
#include <tuple>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
17
#include <type_traits>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
18
#include <utility>
19
#include "scalfmm/meta/traits.hpp"
20
#include "scalfmm/meta/forward.hpp"
21
22
23

namespace scalfmm::meta
{
ESTERIE Pierre's avatar
ESTERIE Pierre committed
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    struct noop_t
    {
        template<typename... Types>
        noop_t(const Types&... ts)
        {
        }
    };

    struct noop_f
    {
        template<typename... F>
        noop_f(F... fs)
        {
        }
    };

40
41
42
43
44
45
46
47
48
    template<typename, typename>
    struct cat;

    template<typename... L, typename... R>
    struct cat<std::tuple<L...>, std::tuple<R...>>
    {
        using type = std::tuple<L..., R...>;
    };

ESTERIE Pierre's avatar
ESTERIE Pierre committed
49
50
    // standart traits and forward declaration
    template<typename T>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
51
52
53
    struct tuple_size : std::tuple_size<T>
    {
    };
ESTERIE Pierre's avatar
ESTERIE Pierre committed
54
55
56
57

    template<typename T>
    static constexpr std::size_t tuple_size_v = meta::tuple_size<T>::value;

ESTERIE Pierre's avatar
ESTERIE Pierre committed
58
59
60
    template<typename Derived, typename... Containers>
    struct tuple_size<container::variadic_adaptor<Derived, Containers...>>
      : tuple_size<typename container::variadic_adaptor<Derived, Containers...>::base_type>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
61
62
63
    {
    };

ESTERIE Pierre's avatar
ESTERIE Pierre committed
64
65
66
    template<typename Derived, template<typename U, typename Allocator> class Container, typename... Types>
    struct tuple_size<container::unique_variadic_container<Derived, Container, Types...>>
      : tuple_size<typename container::unique_variadic_container<Derived, Container, Types...>::base_type>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
67
68
69
    {
    };

ESTERIE Pierre's avatar
ESTERIE Pierre committed
70
71
72
    template<typename Derived, typename... Types>
    struct tuple_size<container::variadic_container<Derived, Types...>>
      : tuple_size<typename container::variadic_container<Derived, Types...>::base_type>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
73
74
75
    {
    };

ESTERIE Pierre's avatar
ESTERIE Pierre committed
76
77
78
    template<typename Derived, typename Tuple>
    struct tuple_size<container::variadic_container_tuple<Derived, Tuple>>
      : tuple_size<typename container::variadic_container_tuple<Derived, Tuple>::base_type>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
79
80
    {
    };
ESTERIE Pierre's avatar
ESTERIE Pierre committed
81

82
83
84
85
86
87
88
89
90
91
92
93
    template<typename ValueType, std::size_t Dimension>
    struct tuple_size<scalfmm::container::point_impl<ValueType, Dimension>>
      : tuple_size<typename scalfmm::container::point_impl<ValueType, Dimension>::base_type>
    {
    };

    template<typename ValueType, std::size_t Dimension>
    struct tuple_size<scalfmm::container::point_proxy<ValueType, Dimension>>
      : tuple_size<typename scalfmm::container::point_proxy<ValueType, Dimension>::base_type>
    {
    };

ESTERIE Pierre's avatar
ESTERIE Pierre committed
94
    template<typename ValueType, std::size_t Dimension, typename Enable>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
95
96
97
98
    struct tuple_size<scalfmm::container::point<ValueType, Dimension, Enable>>
      : tuple_size<typename scalfmm::container::point<ValueType, Dimension, Enable>::base_type>
    {
    };
ESTERIE Pierre's avatar
ESTERIE Pierre committed
99

100
101
102
103
104
105
106
    template<typename PositionType, std::size_t PositionDim, typename InputsType, std::size_t NInputs,
             typename OutputsType, std::size_t MOutputs, typename... Variables>
    struct tuple_size<scalfmm::container::particle<PositionType,PositionDim,InputsType,NInputs,OutputsType,MOutputs,Variables...>>
      : std::integral_constant<std::size_t, PositionDim+NInputs+MOutputs+sizeof...(Variables)>
    {
    };

ESTERIE Pierre's avatar
ESTERIE Pierre committed
107
108
109
110
111
112
113
114
115
    template<std::size_t I, typename T>
    inline constexpr auto get(T&& t) noexcept -> auto&&
    {
        return std::get<I>(std::forward<T>(t));
    }

    template<std::size_t I, typename ValueType, std::size_t Dimension, typename Enable>
    inline constexpr auto get(container::point<ValueType, Dimension, Enable> const& p) noexcept -> ValueType const&
    {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
116
        return p.at(I);
ESTERIE Pierre's avatar
ESTERIE Pierre committed
117
118
119
120
121
    }

    template<std::size_t I, typename ValueType, std::size_t Dimension, typename Enable>
    inline constexpr auto get(container::point<ValueType, Dimension, Enable>& p) noexcept -> ValueType&
    {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
122
        return p.at(I);
ESTERIE Pierre's avatar
ESTERIE Pierre committed
123
124
125
126
    }

    //////////////////////////////////////////////
    template<std::size_t Added, std::size_t... Is>
127
    inline constexpr auto add_to_sequence(std::index_sequence<Is...> seq)
ESTERIE Pierre's avatar
ESTERIE Pierre committed
128
    {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
129
        return std::index_sequence<(Added + Is)...>{};
ESTERIE Pierre's avatar
ESTERIE Pierre committed
130
131
    }

132
    template<typename T, size_t... I>
133
    inline constexpr auto reverse_impl(T&& t, std::index_sequence<I...> /*unused*/)
134
      -> std::tuple<typename std::tuple_element<sizeof...(I) - 1 - I, T>::type...>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
135
136
137
138
    {
        return std::make_tuple(meta::get<sizeof...(I) - 1 - I>(std::forward<T>(t))...);
    }

139
    template<typename T>
140
    inline constexpr auto reverse(T&& t)
141
      -> decltype(reverse_impl(std::forward<T>(t), std::make_index_sequence<meta::tuple_size<std::decay_t<T>>::value>()))
ESTERIE Pierre's avatar
ESTERIE Pierre committed
142
    {
143
        return reverse_impl(std::forward<T>(t), std::make_index_sequence<meta::tuple_size<std::decay_t<T>>::value>());
ESTERIE Pierre's avatar
ESTERIE Pierre committed
144
145
    }

146
147
148
149
150
    // Genrate a tuple of Ts
    template<std::size_t, typename T>
    using type_id = T;

    template<typename T, std::size_t... Is>
151
    inline constexpr auto generate_tuple(std::index_sequence<Is...> s)
ESTERIE Pierre's avatar
ESTERIE Pierre committed
152
153
154
    {
        return std::tuple<type_id<Is, T>...>{};
    }
155
156

    template<typename T, std::size_t N>
157
    inline constexpr auto generate_tuple()
ESTERIE Pierre's avatar
ESTERIE Pierre committed
158
    {
159
        return generate_tuple<T>(std::make_index_sequence<N>{});
ESTERIE Pierre's avatar
ESTERIE Pierre committed
160
    }
161

162
    template<typename T, std::size_t N>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
163
    using generate_tuple_t = decltype(generate_tuple<T, N>());
164

165
    template<template<class> class New, typename Tuple, std::size_t... Is>
166
    inline constexpr auto replace_inner_tuple_type(std::index_sequence<Is...> s)
167
168
169
170
171
    {
        return std::tuple<type_id<Is, New<typename std::tuple_element<Is, Tuple>::type>>...>{};
    }

    template<template<class> class New, typename Tuple>
172
    inline constexpr auto replace_inner_tuple_type()
173
174
175
176
    {
        return replace_inner_tuple_type<New, Tuple>(std::make_index_sequence<meta::tuple_size_v<Tuple>>{});
    }

177
    template<template<class> class New, typename Tuple>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
178
    using replace_inner_tuple_type_t = decltype(replace_inner_tuple_type<New, Tuple>());
179

ESTERIE Pierre's avatar
ESTERIE Pierre committed
180
    template<class Tuple, class T = std::decay_t<std::tuple_element_t<0, std::decay_t<Tuple>>>>
181
182
183
184
185
186
    constexpr inline auto to_array(Tuple t)
    {
        return std::apply([](auto... elems) { return std::array<T, sizeof...(elems)>{elems...}; }, t);
    }

    template<class T, std::size_t N>
ESTERIE Pierre's avatar
ESTERIE Pierre committed
187
    constexpr inline auto to_tuple(std::array<T, N> a)
188
189
190
191
192
193
194
195
196
197
    {
        return std::apply([](auto... elems) { return std::make_tuple(elems...); }, a);
    }

    template<std::size_t Offset, typename Seq>
    struct offset_sequence;

    template<std::size_t Offset, std::size_t... Ints>
    struct offset_sequence<Offset, std::index_sequence<Ints...>>
    {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
198
        using type = std::index_sequence<Offset + Ints...>;
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    };

    template<std::size_t Offset, typename Seq>
    using offset_sequence_t = typename offset_sequence<Offset, Seq>::type;

    template<std::size_t Begin, std::size_t End>
    struct make_range_sequence : public offset_sequence_t<Begin, std::make_index_sequence<End - Begin>>
    {
    };

    template<typename T, std::size_t... Is>
    constexpr inline auto sub_tuple(T&& t, std::index_sequence<Is...> s)
    {
        return std::forward_as_tuple(meta::get<Is>(std::forward<decltype(t)>(t))...);
    }

ESTERIE Pierre's avatar
ESTERIE Pierre committed
215
    template<typename... Args>
216
    inline auto print(std::ostream& out, Args&&... args)
ESTERIE Pierre's avatar
ESTERIE Pierre committed
217
    {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
218
        ((out << ' ' << std::forward<Args>(args)), ...);
ESTERIE Pierre's avatar
ESTERIE Pierre committed
219
220
    }

221
    template<typename... Args>
222
    inline constexpr auto multiply(Args&... args)
223
224
225
226
    {
        return (args * ...);
    }

ESTERIE Pierre's avatar
ESTERIE Pierre committed
227
228
229
230
231
232
233
234
235
    template<typename... Args>
    inline constexpr auto all(Args... args) -> bool
    {
        return (... && args);
    }

    namespace details
    {
        template<typename T, typename U, std::size_t... Is>
236
        inline constexpr auto tuple_sum_update(T&& lhs, U&& rhs, std::index_sequence<Is...> s) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
237
238
239
240
        {
            noop_t{((meta::get<Is>(std::forward<T>(lhs)) += meta::get<Is>(std::forward<U>(rhs))), 0)...};
        }

ESTERIE Pierre's avatar
ESTERIE Pierre committed
241
        template<typename T, typename U, std::size_t... Is>
242
        inline constexpr auto tuple_min_update(T&& lhs, U&& rhs, std::index_sequence<Is...> s) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
243
244
245
246
        {
            noop_t{((meta::get<Is>(std::forward<T>(lhs)) -= meta::get<Is>(std::forward<U>(rhs))), 0)...};
        }

ESTERIE Pierre's avatar
ESTERIE Pierre committed
247
        template<typename F, typename LHS, typename RHS1, typename RHS2, std::size_t... Is>
248
        inline constexpr auto for_each(std::index_sequence<Is...> s, F&& f, LHS&& lhs, RHS1&& rhs1, RHS2&& rhs2) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
249
        {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
250
251
252
253
            noop_t{(((meta::get<Is>(std::forward<LHS>(lhs)) =
                        std::invoke(std::forward<F>(f), meta::get<Is>(std::forward<RHS1>(rhs1)),
                                    meta::get<Is>(std::forward<RHS2>(rhs2))))),
                    0)...};
ESTERIE Pierre's avatar
ESTERIE Pierre committed
254
255
256
        }

        template<typename T, typename U, typename F, std::size_t... Is>
257
        inline constexpr auto for_each(T&& lhs, U&& rhs, F&& f, std::index_sequence<Is...> s) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
258
        {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
259
260
261
            noop_t{((meta::get<Is>(std::forward<T>(lhs)) =
                       std::invoke(std::forward<F>(f), meta::get<Is>(std::forward<U>(rhs)))),
                    0)...};
ESTERIE Pierre's avatar
ESTERIE Pierre committed
262
263
264
        }

        template<typename T, typename F, std::size_t... Is>
265
        inline constexpr auto for_each(T&& t, F&& f, std::index_sequence<Is...> s) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
266
        {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
267
            noop_t{(std::invoke(std::forward<F>(f), meta::get<Is>(std::forward<T>(t))), 0)...};
ESTERIE Pierre's avatar
ESTERIE Pierre committed
268
269
        }

270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
        template<typename F, typename T0, typename T1, typename T2, typename T3, std::size_t... Is>
        inline constexpr auto repeat(F&& f, T0&& t0, T1&& t1, T2&& t2, T3&& t3, std::index_sequence<Is...> s) -> void
        {
            noop_t{(
              (std::invoke(std::forward<F>(f), meta::get<Is>(std::forward<T0>(t0)), meta::get<Is>(std::forward<T1>(t1)),
                           meta::get<Is>(std::forward<T2>(t2)), meta::get<Is>(std::forward<T3>(t3)))),
              0)...};
        }

        template<typename F, typename T0, typename T1, typename T2, std::size_t... Is>
        inline constexpr auto repeat(F&& f, T0&& t0, T1&& t1, T2&& t2, std::index_sequence<Is...> s) -> void
        {
            noop_t{((std::invoke(std::forward<F>(f), meta::get<Is>(std::forward<T0>(t0)),
                                 meta::get<Is>(std::forward<T1>(t1)), meta::get<Is>(std::forward<T2>(t2)))),
                    0)...};
        }

        template<typename F, typename T0, typename T1, std::size_t... Is>
        inline constexpr auto repeat(F&& f, T0&& t0, T1&& t1, std::index_sequence<Is...> s) -> void
        {
            noop_t{((std::invoke(std::forward<F>(f), meta::get<Is>(std::forward<T0>(t0)),
                                 meta::get<Is>(std::forward<T1>(t1)))),
                    0)...};
        }

        template<typename F, typename T0, std::size_t... Is>
        inline constexpr auto repeat(F&& f, T0&& t0, std::index_sequence<Is...> s) -> void
        {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
298
            noop_t{((std::invoke(std::forward<F>(f), meta::get<Is>(std::forward<T0>(t0)))), 0)...};
299
300
        }

301
302
303
304
305
306
        template<typename F, typename T0, typename T1, typename T2, typename T3, std::size_t... Is>
        inline constexpr auto repeat_indexed(F&& f, T0&& t0, T1&& t1, T2&& t2, T3&& t3, std::index_sequence<Is...> s)
          -> void
        {
            noop_t{((std::invoke(std::forward<F>(f), Is, meta::get<Is>(std::forward<T0>(t0)),
                                 meta::get<Is>(std::forward<T1>(t1)), meta::get<Is>(std::forward<T2>(t2)),
307
                                 meta::get<Is>(std::forward<T3>(t3)))),
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
                    0)...};
        }

        template<typename F, typename T0, typename T1, typename T2, std::size_t... Is>
        inline constexpr auto repeat_indexed(F&& f, T0&& t0, T1&& t1, T2&& t2, std::index_sequence<Is...> s) -> void
        {
            noop_t{((std::invoke(std::forward<F>(f), Is, meta::get<Is>(std::forward<T0>(t0)),
                                 meta::get<Is>(std::forward<T1>(t1)), meta::get<Is>(std::forward<T2>(t2)))),
                    0)...};
        }

        template<typename F, typename T0, typename T1, std::size_t... Is>
        inline constexpr auto repeat_indexed(F&& f, T0&& t0, T1&& t1, std::index_sequence<Is...> s) -> void
        {
            noop_t{((std::invoke(std::forward<F>(f), Is, meta::get<Is>(std::forward<T0>(t0)),
                                 meta::get<Is>(std::forward<T1>(t1)))),
                    0)...};
        }

327
328
329
330
331
332
        template<typename F, typename T0, std::size_t... Is>
        inline constexpr auto repeat_indexed(F&& f, T0&& t0, std::index_sequence<Is...> s) -> void
        {
            noop_t{((std::invoke(std::forward<F>(f), Is, meta::get<Is>(std::forward<T0>(t0)))), 0)...};
        }

ESTERIE Pierre's avatar
ESTERIE Pierre committed
333
334
335
336
337
338
339
340
        template<typename T, typename F, std::size_t... Is>
        inline constexpr auto apply(T&& t, F&& f, std::index_sequence<Is...> s)
        {
            return std::make_tuple(std::invoke(std::forward<F>(f), meta::get<Is>(std::forward<T>(t)))...);
        }
    }   // namespace details

    template<typename T, typename U>
341
    inline constexpr auto tuple_sum_update(T&& lhs, U&& rhs) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
342
343
    {
        return details::tuple_sum_update(std::forward<T>(lhs), std::forward<U>(rhs),
ESTERIE Pierre's avatar
ESTERIE Pierre committed
344
345
346
347
                                         std::make_index_sequence<meta::tuple_size<std::decay_t<T>>::value>{});
    }

    template<typename T, typename U>
348
    inline constexpr auto tuple_min_update(T&& lhs, U&& rhs) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
349
350
351
    {
        return details::tuple_min_update(std::forward<T>(lhs), std::forward<U>(rhs),
                                         std::make_index_sequence<meta::tuple_size<std::decay_t<T>>::value>{});
ESTERIE Pierre's avatar
ESTERIE Pierre committed
352
353
354
    }

    template<typename F, typename LHS, typename RHS1, typename RHS2>
355
    inline constexpr auto for_each(LHS&& lhs, RHS1&& rhs1, RHS2&& rhs2, F&& f) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
356
357
    {
        return details::for_each(std::make_index_sequence<meta::tuple_size<std::decay_t<LHS>>::value>{},
ESTERIE Pierre's avatar
ESTERIE Pierre committed
358
359
                                 std::forward<F>(f), std::forward<LHS>(lhs), std::forward<RHS1>(rhs1),
                                 std::forward<RHS2>(rhs2));
ESTERIE Pierre's avatar
ESTERIE Pierre committed
360
361
362
    }

    template<typename T, typename U, typename F>
363
    inline constexpr auto for_each(T&& lhs, U&& rhs, F&& f) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
364
365
366
367
368
369
    {
        return details::for_each(std::forward<T>(lhs), std::forward<U>(rhs), std::forward<F>(f),
                                 std::make_index_sequence<meta::tuple_size<std::decay_t<T>>::value>{});
    }

    template<typename T, typename F>
370
    inline constexpr auto for_each(T&& tuple, F&& f) -> void
ESTERIE Pierre's avatar
ESTERIE Pierre committed
371
372
373
374
375
    {
        return details::for_each(std::forward<T>(tuple), std::forward<F>(f),
                                 std::make_index_sequence<meta::tuple_size<std::decay_t<T>>::value>{});
    }

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
    template<typename F, typename T0, typename T1, typename T2, typename T3>
    inline constexpr auto repeat(F&& f, T0&& t0, T1&& t1, T2&& t2, T3&& t3) -> void
    {
        details::repeat(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1), std::forward<T2>(t2),
                        std::forward<T3>(t3), std::make_index_sequence<meta::tuple_size<std::decay_t<T0>>::value>{});
    }

    template<typename F, typename T0, typename T1, typename T2>
    inline constexpr auto repeat(F&& f, T0&& t0, T1&& t1, T2&& t2) -> void
    {
        details::repeat(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1), std::forward<T2>(t2),
                        std::make_index_sequence<meta::tuple_size<std::decay_t<T0>>::value>{});
    }

    template<typename F, typename T0, typename T1>
    inline constexpr auto repeat(F&& f, T0&& t0, T1&& t1) -> void
    {
        details::repeat(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1),
                        std::make_index_sequence<meta::tuple_size<std::decay_t<T0>>::value>{});
    }

    template<typename F, typename T0>
    inline constexpr auto repeat(F&& f, T0&& t0) -> void
    {
        details::repeat(std::forward<F>(f), std::forward<T0>(t0),
                        std::make_index_sequence<meta::tuple_size<std::decay_t<T0>>::value>{});
    }

404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
    template<typename F, typename T0, typename T1, typename T2, typename T3>
    inline constexpr auto repeat_indexed(F&& f, T0&& t0, T1&& t1, T2&& t2, T3&& t3) -> void
    {
        details::repeat_indexed(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1), std::forward<T2>(t2),
                                std::forward<T3>(t3),
                                std::make_index_sequence<meta::tuple_size<std::decay_t<T0>>::value>{});
    }

    template<typename F, typename T0, typename T1, typename T2>
    inline constexpr auto repeat_indexed(F&& f, T0&& t0, T1&& t1, T2&& t2) -> void
    {
        details::repeat_indexed(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1), std::forward<T2>(t2),
                                std::make_index_sequence<meta::tuple_size<std::decay_t<T0>>::value>{});
    }
    template<typename F, typename T0, typename T1>
    inline constexpr auto repeat_indexed(F&& f, T0&& t0, T1&& t1) -> void
    {
        details::repeat_indexed(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1),
                                std::make_index_sequence<meta::tuple_size<std::decay_t<T0>>::value>{});
    }

425
426
427
428
    template<typename F, typename T0>
    inline constexpr auto repeat_indexed(F&& f, T0&& t0) -> void
    {
        details::repeat_indexed(std::forward<F>(f), std::forward<T0>(t0),
429
                                std::make_index_sequence<meta::tuple_size<std::decay_t<T0>>::value>{});
430
431
    }

ESTERIE Pierre's avatar
ESTERIE Pierre committed
432
433
434
435
436
437
438
    template<typename T, typename F>
    inline constexpr auto apply(T&& t, F&& f)
    {
        return details::apply(std::forward<T>(t), std::forward<F>(f),
                              std::make_index_sequence<meta::tuple_size<std::decay_t<T>>::value>{});
    }

439
440
441
442
    template<std::size_t N>
    struct looper
    {
        template<typename F, std::size_t Dimension, typename... Is>
443
        constexpr inline auto operator()(F&& f, std::array<std::size_t, Dimension> const& stops, Is&... is)
444
        {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
445
            for(std::size_t i = 0; i < meta::get<N - 1>(stops); ++i)
446
            {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
447
                looper<N - 1>()(std::forward<F>(f), stops, is..., i);
448
449
450
451
452
453
454
455
            }
        }
    };

    template<>
    struct looper<1>
    {
        template<typename F, std::size_t Dimension, typename... Is>
456
        constexpr inline auto operator()(F&& f, std::array<std::size_t, Dimension> const& stops, Is&... is)
457
        {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
458
            for(std::size_t i = 0; i < meta::get<0>(stops); ++i)
459
            {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
460
                f(is..., i);
461
462
463
            }
        }
    };
ESTERIE Pierre's avatar
ESTERIE Pierre committed
464
465
466
467
468

    template<std::size_t N>
    struct looper_range
    {
        template<typename F, std::size_t Dimension, typename... Is>
469
        constexpr inline auto operator()(F&& f, std::array<int, Dimension> const& starts,
ESTERIE Pierre's avatar
ESTERIE Pierre committed
470
                                         std::array<int, Dimension> const& stops, Is&... is)
ESTERIE Pierre's avatar
ESTERIE Pierre committed
471
        {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
472
            for(int i = meta::get<N - 1>(starts); i < meta::get<N - 1>(stops); ++i)
ESTERIE Pierre's avatar
ESTERIE Pierre committed
473
            {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
474
                looper_range<N - 1>()(std::forward<F>(f), starts, stops, is..., i);
ESTERIE Pierre's avatar
ESTERIE Pierre committed
475
476
477
478
479
480
481
482
            }
        }
    };

    template<>
    struct looper_range<1>
    {
        template<typename F, std::size_t Dimension, typename... Is>
483
        constexpr inline auto operator()(F&& f, std::array<int, Dimension> const& starts,
ESTERIE Pierre's avatar
ESTERIE Pierre committed
484
                                         std::array<int, Dimension> const& stops, Is&... is)
ESTERIE Pierre's avatar
ESTERIE Pierre committed
485
        {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
486
            for(int i = meta::get<0>(starts); i < meta::get<0>(stops); ++i)
ESTERIE Pierre's avatar
ESTERIE Pierre committed
487
            {
ESTERIE Pierre's avatar
ESTERIE Pierre committed
488
                std::invoke(std::forward<F>(f), is..., i);
ESTERIE Pierre's avatar
ESTERIE Pierre committed
489
490
491
            }
        }
    };
492
493
494
495
496
497
498
499
500
501
502
503
504

    template<typename ParticleOrTuple>
    auto inline as_tuple(ParticleOrTuple&& p)
    {
        if constexpr(is_particle_v<std::decay_t<ParticleOrTuple>>)
        {
            return std::forward<ParticleOrTuple>(p).as_tuple();
        }
        else if constexpr(is_tuple_v<std::decay_t<ParticleOrTuple>>)
        {
            return std::forward<ParticleOrTuple>(p);
        }
    }
505
506
}   // namespace scalfmm::meta
#endif   // SCALFMM_META_UTILS_HPP