|
13 | 13 |
|
14 | 14 | #include "Framework/ASoA.h" |
15 | 15 |
|
| 16 | +#include <iterator> |
| 17 | +#include <tuple> |
| 18 | +#include <utility> |
| 19 | + |
16 | 20 | namespace o2::soa |
17 | 21 | { |
18 | 22 |
|
19 | | -/// @return a vector of pairs with all the possible |
20 | | -/// combinations of the rows of the table T. |
| 23 | +template <typename T2, std::size_t K2> |
| 24 | +void addOne(std::array<T2, K2>& array, const T2& maxOffset, bool& isEnd) |
| 25 | +{ |
| 26 | + for (int i = 0; i < K2; i++) { |
| 27 | + array[K2 - i - 1]++; |
| 28 | + if (array[K2 - i - 1] != maxOffset + K2 - i - 1) { // no < operator for RowViewBase |
| 29 | + for (int j = K2 - i; j < K2; j++) { |
| 30 | + array[j].setCursor(array[j - 1].mRowIndex + 1); |
| 31 | + } |
| 32 | + isEnd = false; |
| 33 | + return; |
| 34 | + } |
| 35 | + } |
| 36 | + isEnd = true; |
| 37 | +} |
| 38 | + |
| 39 | +/// @return next K-combination of the rows of the table T. |
21 | 40 | /// FIXME: move to coroutines once we have C++20 |
22 | | -template <typename T> |
23 | | -std::vector<std::pair<typename T::iterator, typename T::iterator>> |
24 | | - combinations(T const& table) |
| 41 | +template <typename T, int K> |
| 42 | +class CombinationsGenerator |
25 | 43 | { |
26 | | - std::vector<std::pair<typename T::iterator, typename T::iterator>> result; |
27 | | - result.reserve((table.size() + 1) * table.size() / 2); |
28 | | - for (auto t0 = table.begin(); t0 + 1 != table.end(); ++t0) { |
29 | | - for (auto t1 = t0 + 1; t1 != table.end(); ++t1) { |
30 | | - result.push_back(std::make_pair(t0, t1)); |
| 44 | + public: |
| 45 | + using IteratorType = typename T::iterator; |
| 46 | + using CombinationType = std::array<IteratorType, K>; |
| 47 | + using FunctionType = std::function<bool(const CombinationType&)>; |
| 48 | + |
| 49 | + class CombinationsIterator : public std::iterator<std::forward_iterator_tag, CombinationType> |
| 50 | + { |
| 51 | + public: |
| 52 | + using reference = CombinationType&; |
| 53 | + using value_type = CombinationType; |
| 54 | + using pointer = CombinationType*; |
| 55 | + using iterator_category = std::forward_iterator_tag; |
| 56 | + |
| 57 | + CombinationsIterator() = delete; |
| 58 | + |
| 59 | + CombinationsIterator(const IteratorType& begin, int n, const FunctionType& condition) |
| 60 | + : mN(n), mIsEnd(false), mTableBegin(begin), mMaxOffset(begin + n - K + 1), mCondition(condition) |
| 61 | + { |
| 62 | + initIterators(); |
| 63 | + } |
| 64 | + |
| 65 | + ~CombinationsIterator() = default; |
| 66 | + |
| 67 | + // prefix increment |
| 68 | + CombinationsIterator& operator++() |
| 69 | + { |
| 70 | + if (!mIsEnd) { |
| 71 | + addOne(mCurrent, mMaxOffset, mIsEnd); |
| 72 | + } |
| 73 | + while (!mIsEnd && !mCondition(mCurrent)) { |
| 74 | + addOne(mCurrent, mMaxOffset, mIsEnd); |
| 75 | + } |
| 76 | + return *this; |
| 77 | + } |
| 78 | + // postfix increment |
| 79 | + CombinationsIterator operator++(int /*unused*/) |
| 80 | + { |
| 81 | + CombinationsIterator copy(*this); |
| 82 | + operator++(); |
| 83 | + return copy; |
| 84 | + } |
| 85 | + // return reference |
| 86 | + reference operator*() |
| 87 | + { |
| 88 | + return mCurrent; |
31 | 89 | } |
| 90 | + bool operator==(const CombinationsIterator& rh) |
| 91 | + { |
| 92 | + return (mIsEnd && rh.mIsEnd) || (mCurrent == rh.mCurrent); |
| 93 | + } |
| 94 | + bool operator!=(const CombinationsIterator& rh) |
| 95 | + { |
| 96 | + return !(*this == rh); |
| 97 | + } |
| 98 | + |
| 99 | + void initIterators() |
| 100 | + { |
| 101 | + for (int i = 0; i < K; i++) { |
| 102 | + mCurrent[i] = mTableBegin + i; |
| 103 | + } |
| 104 | + if (!mCondition(mCurrent)) { |
| 105 | + operator++(); |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + void goToEnd() |
| 110 | + { |
| 111 | + for (int i = 0; i < K; i++) { |
| 112 | + mCurrent[i].setCursor(mN - K + i); |
| 113 | + } |
| 114 | + operator++(); |
| 115 | + } |
| 116 | + |
| 117 | + private: |
| 118 | + CombinationType mCurrent; |
| 119 | + int mN; // number of elements |
| 120 | + bool mIsEnd; // whether there are any more tuples available |
| 121 | + FunctionType mCondition; // only tuples satisfying the condition will be outputed |
| 122 | + IteratorType mTableBegin; // start of the table for which tuples are generated |
| 123 | + IteratorType mMaxOffset; // one position past maximum acceptable position for 0th element of combination |
| 124 | + }; |
| 125 | + |
| 126 | + using iterator = CombinationsIterator; |
| 127 | + using const_iterator = CombinationsIterator; |
| 128 | + |
| 129 | + inline iterator begin() |
| 130 | + { |
| 131 | + return iterator(mTableBegin, mN, mCondition); |
| 132 | + } |
| 133 | + inline iterator end() |
| 134 | + { |
| 135 | + auto it = iterator(mTableBegin, mN, mCondition); |
| 136 | + it.goToEnd(); |
| 137 | + return it; |
32 | 138 | } |
33 | | - return result; |
| 139 | + |
| 140 | + CombinationsGenerator() = delete; |
| 141 | + CombinationsGenerator(const T& table, const FunctionType& condition) |
| 142 | + : mTableBegin(table.begin()), mN(table.size()), mCondition(condition) |
| 143 | + { |
| 144 | + static_assert(K > 0); |
| 145 | + } |
| 146 | + ~CombinationsGenerator() = default; |
| 147 | + |
| 148 | + private: |
| 149 | + IteratorType mTableBegin; |
| 150 | + int mN; |
| 151 | + FunctionType mCondition; |
34 | 152 | }; |
35 | 153 |
|
36 | 154 | } // namespace o2::soa |
|
0 commit comments