2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
5 namespace DerivationFramework { namespace TriggerMatchingUtils {
7 template <typename T, typename PROJ>
8 bool insertIntoSortedVector(std::vector<T>& vec, const T& ele,
11 auto itr = std::ranges::lower_bound(vec, proj(ele), {}, proj);
12 // if no lower bound is found or the found element doesn't equal ele then
13 // insert ele at this point
14 if (itr == vec.end() || *itr != ele) {
22 template <typename R, typename PROJ>
23 std::vector<typename R::value_type> sorted(const R& r, PROJ proj)
25 std::vector<typename R::value_type> output(std::begin(r), std::end(r));
26 std::ranges::sort(output, {}, proj);
31 template <typename T, typename INNERPROJ, typename OUTERPROJ>
32 std::vector<std::vector<T>> getAllDistinctCombinations(
33 std::vector<RangedItr<typename std::vector<T>::const_iterator>>& inputs,
37 // This is where the output will go
38 std::vector<std::vector<T>> output;
40 // If inputs is empty or if any of the ranges within inputs are empty then
41 // no combinations will be found!
42 if (inputs.empty() || std::any_of(inputs.begin(), inputs.end(),
43 [] (const auto& rangedItr) { return rangedItr.exhausted(); }) )
46 // This is the current output combination being built
47 std::vector<T> currentCombination;
49 // This iterator points to where in the vector of ranged iterators we are
50 // looking. This can therefore often be acting as an iterator to and
51 // iterator! *itr is an iterator, **itr is a const T&!
52 // To disambiguate I will refer to itr as the outer iterator and *itr as the
54 auto itr = inputs.begin();
56 // Have we exhausted our current inner iterator?
57 if (itr == inputs.end() || itr->exhausted() ) {
58 // If the outer iterator has returned to the beginning then we're done
59 // and every combination has been checked.
60 if (itr == inputs.begin() )
62 // otherwise we need to continue. To do this we
63 // - reset the current inner iterator. This is so that the next time we
64 // return to it we look through all the elements again
65 // - step the outer iterator back
66 // - remove the last element of the current combination. That
67 // element will be replaced by the next valid one from the list *now*
68 // pointed to by the outer iterator.
69 if (itr != inputs.end() )
72 currentCombination.pop_back();
73 } //> end if inner iterator is exhausted
75 // Check if the pointed-to element is already in the current combination
76 const T& currentCandidate = **itr;
77 // Now that we've accessed this value, step past it
80 currentCombination.begin(),
81 currentCombination.end(),
82 currentCandidate) == currentCombination.end() ) {
83 // If it isn't, then add it.
84 currentCombination.push_back(currentCandidate);
85 // Step the outer iterator forwards so we're looking at the next list
87 if (itr == inputs.end() ) {
88 // If we're at the end then this is a complete combination, add it
90 insertIntoSortedVector(output,
91 sorted(currentCombination, innerproj),
94 } //> end if currentCandidate is in currentCombination
95 } //> end else (if inner iterator is exhausted)
98 } //> end function getAllDistinctCombinations
100 }} //> end namespace DerivationFramework::TriggerMatchingUtils