Loading...
Searching...
No Matches
multirange_for.h
Go to the documentation of this file.
1#ifndef _BBM_MULTI_RANGE_FOR_H_
2#define _BBM_MULTI_RANGE_FOR_H_
3
4#include <tuple>
5#include <cassert>
6#include <functional>
7
8#include "core/error.h"
9#include "concepts/util.h"
10#include "util/iterator_util.h"
11
12/***********************************************************************/
13/*! \file multirange_for.h
14 \brief ranged for loop over multiple containers at once
15************************************************************************/
16
17namespace bbm {
18
19 /*********************************************************************/
20 /*! \brief ranged for loop over multiple containers at once
21
22 \param func = function to call in each loop. The function is expected to
23 return void, and takes as many arguments as there are containers. For each
24 call, a reference to the corresponding element in each container is
25 passed.
26 \param containers... = containers. If not iterable, then the value is passed to each call of FUNC.
27
28 Example:
29
30 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
31 multirange_for( [&](auto& a_element, auto& b_element)
32 {
33 a += b;
34 }, a_container, b_container);
35 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36
37 This method will compute 'a_container += b_container'.
38
39 Note: all containers must either have size==1 or the same size.
40
41 ***********************************************************************/
42 template<typename FUNC, typename... Ts>
43 inline void multirange_for(FUNC&& func, Ts&&... containers)
44 {
45 // nothing to do
46 if constexpr (sizeof...(Ts) == 0) return;
47
48 // determine number of iterations
49 size_t size = 0;
50 ((size = std::max(size, bbm::size(containers))), ... );
51
52 // validate the size of each container (must be 1 or 'size')
53 if ( !((bbm::size(containers) == 1 || bbm::size(containers) == size) && ...) ) throw bbm_size_error;
54
55 // create iterator for all containers (using bbm::begin instead of std::begin!)
56 auto itr = std::make_tuple( (bbm::begin(containers))... );
57
58 // helper lambdas
59 auto idx = std::make_index_sequence<sizeof...(Ts)>{};
60 auto incr = []<typename C>(C&& /*container*/, auto& itr) { if constexpr (std::ranges::range<C>) return ++itr; };
61 auto incr_all = [&]<size_t... IDX>(std::index_sequence<IDX...>) { (incr(containers, std::get<IDX>(itr)), ...); };
62 auto apply_all = [&]<size_t... IDX>(std::index_sequence<IDX...>) { std::invoke(std::forward<FUNC>(func), (*std::get<IDX>(itr))...); };
63
64 // loop over all elements and call 'func'. Increment itr after every loop.
65 for(size_t i=0; i != size; ++i, incr_all(idx))
66 apply_all(idx);
67
68 // Done.
69 }
70
71}
72
73#endif /* _BBM_MULTI_RANGE_FOR_H_ */
Predefined exceptions for common errors.
#define bbm_size_error
Definition: error.h:45
Extensions for STL iterators/ranges.
Definition: aggregatebsdf.h:29
auto apply_all(const FUNC &func, const T &... t)
Apply a function.
Definition: apply_all.h:42
void multirange_for(FUNC &&func, Ts &&... containers)
ranged for loop over multiple containers at once
Definition: multirange_for.h:43
size_t size(T &&t)
Definition: iterator_util.h:22
auto begin(T &&t)
Definition: iterator_util.h:29
Additional basic helper concepts.