| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <array> | ||
| 4 | #include <vector> | ||
| 5 | #include <cassert> | ||
| 6 | #include <memory> | ||
| 7 | |||
| 8 | #include "na64util/array-unwinding.hh" | ||
| 9 | |||
| 10 | namespace na64dp { | ||
| 11 | namespace util { | ||
| 12 | |||
| 13 | /**\brief Helper class representing stateful generator for cartesian product | ||
| 14 | * | ||
| 15 | * Initialized with a sequence of homogeneous STL containers, implements an | ||
| 16 | * iterator over cartesian product results (pairs, triplets, quadruplets, etc). | ||
| 17 | * | ||
| 18 | * \ingroup numerical-utils | ||
| 19 | * */ | ||
| 20 | template<Arity_t NT, typename SeqT> | ||
| 21 | class CartesianProduct { | ||
| 22 | private: | ||
| 23 | /// Set of ends for hits collections | ||
| 24 | std::array<typename SeqT::const_iterator, NT> _begins | ||
| 25 | , _state | ||
| 26 | , _ends | ||
| 27 | ; | ||
| 28 | public: | ||
| 29 | template<typename ... ArgsT> | ||
| 30 | 4 | CartesianProduct( ArgsT & ... args ) : _begins{args.begin()...} | |
| 31 | 4 | , _state(_begins) | |
| 32 | 4 | , _ends{args.end()...} | |
| 33 | 4 | {} | |
| 34 | CartesianProduct( CartesianProduct<NT, SeqT> && o) | ||
| 35 | : _begins(std::move(o._begins)) | ||
| 36 | , _state(std::move(o._state)) | ||
| 37 | , _ends(std::move(o._ends)) {} | ||
| 38 | /// Writes set of IDs to given destination, if possible. If not, | ||
| 39 | /// returns `false` | ||
| 40 | 12 | bool operator>>(std::array<typename SeqT::value_type, NT> & dest) { | |
| 41 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 10 times.
|
42 | for( Arity_t i = 0; i < NT; ++i ) { |
| 42 |
2/2✓ Branch 3 taken 2 times.
✓ Branch 4 taken 30 times.
|
32 | if( _ends[i] == _state[i] ) return false; |
| 43 | 30 | dest[i] = *_state[i]; | |
| 44 | } | ||
| 45 | 10 | ++_state[NT-1]; | |
| 46 | // advance states | ||
| 47 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
|
18 | for( Arity_t i = NT-1; i != 0; --i) { |
| 48 |
2/2✓ Branch 3 taken 7 times.
✓ Branch 4 taken 8 times.
|
15 | if( _state[i] != _ends[i] ) break; |
| 49 | 8 | _state[i] = _begins[i]; | |
| 50 | 8 | ++_state[i-1]; | |
| 51 | } | ||
| 52 | 10 | return true; | |
| 53 | } | ||
| 54 | |||
| 55 | void reset() { _state = _begins; } | ||
| 56 | }; | ||
| 57 | |||
| 58 | template<typename ObjectT, typename ArgT, Arity_t... Ns> ObjectT | ||
| 59 | 1 | unwind_array_to_constructor( const ArgT && arg, std::index_sequence<Ns...> ) { | |
| 60 | 1 | return ObjectT( std::move(arg [Ns]) ... ); | |
| 61 | } | ||
| 62 | |||
| 63 | template<typename ObjectT, typename ArgT, Arity_t... Ns> std::shared_ptr<ObjectT> | ||
| 64 | unwind_array_to_constructor_shared( ArgT && arg, std::index_sequence<Ns...> ) { | ||
| 65 | return std::shared_ptr<ObjectT>( std::move(arg [Ns]) ... ); | ||
| 66 | } | ||
| 67 | |||
| 68 | //template<typename ObjectT, typename ArgT, Arity_t... Ns> ObjectT | ||
| 69 | //unwind_array_to_constructor( const ArgT & arg, std::index_sequence<Ns...> ) { | ||
| 70 | // return ObjectT( arg [Ns] ... ); | ||
| 71 | //} | ||
| 72 | // | ||
| 73 | //template<typename ArgT, typename CallableT, Arity_t... Ns> auto | ||
| 74 | //unwind_array_to_call( CallableT c, const ArgT & arg, std::index_sequence<Ns...> ) { | ||
| 75 | // return c( arg [Ns] ... ); | ||
| 76 | //} | ||
| 77 | |||
| 78 | /**\brief Product result in array of fixed arity | ||
| 79 | * | ||
| 80 | * \ingroup numerical-utils | ||
| 81 | * */ | ||
| 82 | template<typename T, Arity_t NT> | ||
| 83 | struct CartesianProductCollections : protected std::array<std::vector<T>, NT> { | ||
| 84 | /// Adds new element into n-th set | ||
| 85 | 5 | void add(Arity_t n, const T & element) { | |
| 86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | assert(n < NT); |
| 87 | 5 | std::array<std::vector<T>, NT>::operator[](n).push_back(element); | |
| 88 | 5 | } | |
| 89 | /// Clears collected sets | ||
| 90 | void clear() { | ||
| 91 | for(Arity_t n = 0; n < NT; ++n) { | ||
| 92 | std::array<std::vector<T>, NT>::operator[](n).clear(); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | 1 | auto get() const { | |
| 97 | return unwind_array_to_constructor< CartesianProduct< NT, std::vector<T> > | ||
| 98 | , std::array<std::vector<T>, NT> | ||
| 99 | 1 | >( std::move(static_cast<const std::array<std::vector<T>, NT>&>(*this)) | |
| 100 | 1 | , std::make_integer_sequence<Arity_t, NT>{} ); | |
| 101 | } | ||
| 102 | }; | ||
| 103 | |||
| 104 | } // namespace ::na64dp::util | ||
| 105 | } // namespace na64dp | ||
| 106 | |||
| 107 |