Skip to content

Commit 0734484

Browse files
committed
avoid copying a vector; start adapting GroupSlicer to use matchers
1 parent ac4d8fa commit 0734484

5 files changed

Lines changed: 85 additions & 75 deletions

File tree

Framework/Core/include/Framework/ASoA.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,7 @@ static constexpr framework::ConcreteDataMatcher getMatcherFromTypeForKey(std::st
14811481
auto locate = [&]<size_t... Is>(std::index_sequence<Is...>) {
14821482
return std::vector{hasKeyM<T::originals[Is]>(key)...};
14831483
}(std::make_index_sequence<T::originals.size()>{});
1484-
auto it = std::find_if(locate.begin(), locate.end(), [](auto const& x) { return x.first; });
1484+
auto it = std::ranges::find_if(locate, [](auto const& x) { return x.first; });
14851485
if (it != locate.end()) {
14861486
return it->second;
14871487
}
@@ -4303,7 +4303,7 @@ using SmallGroupsUnfiltered = SmallGroupsBase<T, false>;
43034303

43044304
template <typename T>
43054305
concept is_smallgroups = requires {
4306-
[]<typename B, bool A>(SmallGroupsBase<B, A>*) {}(std::declval<T*>());
4306+
[]<typename B, bool A>(SmallGroupsBase<B, A>*) {}(std::declval<std::decay_t<T>*>());
43074307
};
43084308
} // namespace o2::soa
43094309

Framework/Core/include/Framework/AnalysisHelpers.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include "Framework/DataAllocator.h"
1717
#include "Framework/IndexBuilderHelpers.h"
1818
#include "Framework/InputSpec.h"
19-
#include "Framework/Output.h"
2019
#include "Framework/OutputObjHeader.h"
2120
#include "Framework/OutputRef.h"
2221
#include "Framework/OutputSpec.h"
@@ -26,6 +25,17 @@
2625
#include "Framework/Traits.h"
2726

2827
#include <string>
28+
namespace o2::framework {
29+
/// Structure to contain mapping between matchers and process functions.
30+
/// Process function is identified by hash, each matcher has associated
31+
/// argument position for that process function; single argument can have
32+
/// many matchers associated due to complicated joins
33+
struct InputInfo {
34+
uint32_t hash;
35+
std::vector<std::pair<int, ConcreteDataMatcher>> matchers;
36+
};
37+
}
38+
2939
namespace o2::soa
3040
{
3141
struct IndexRecord {

Framework/Core/include/Framework/AnalysisTask.h

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,6 @@ concept is_enumeration = is_enumeration_v<std::decay_t<T>>;
6969
template <typename T>
7070
concept is_table_iterator_or_enumeration = soa::is_table_or_iterator<T> || is_enumeration<T>;
7171

72-
/// Structure to contain mapping between matchers and process functions.
73-
/// Process function is identified by hash, each matcher has associated
74-
/// argument position for that process function; single argument can have
75-
/// many matchers associated due to complicated joins
76-
struct InputInfo {
77-
uint32_t hash;
78-
std::vector<std::pair<int, ConcreteDataMatcher>> matchers;
79-
};
80-
8172
// Helper struct which builds a DataProcessorSpec from
8273
// the contents of an AnalysisTask...
8374
namespace
@@ -268,38 +259,37 @@ struct AnalysisDataProcessorBuilder {
268259
}
269260
}
270261

271-
template <is_enumeration T, int AI>
272-
static auto extract(InputRecord&, std::vector<InputInfo>, std::vector<ExpressionInfo>&, size_t)
262+
template <is_enumeration T, int AI, std::ranges::input_range R>
263+
static auto extract(InputRecord&, R, std::vector<ExpressionInfo>&, size_t)
273264
{
274265
return T{};
275266
}
276267

277-
template <soa::is_table_or_iterator T, int AI>
278-
static auto extract(InputRecord& record, std::vector<InputInfo> iInfos, std::vector<ExpressionInfo>& infos, size_t phash)
268+
template <soa::is_table_or_iterator T, int AI, std::ranges::input_range R>
269+
static auto extract(InputRecord& record, R matchers, std::vector<ExpressionInfo>& infos, size_t phash)
279270
{
280-
auto matchers = std::ranges::find_if(iInfos, [&phash](auto const& info) { return info.hash == phash; })->matchers | std::views::filter([](auto const& pair) { return pair.first == AI; });
271+
// auto matchers = std::ranges::find_if(iInfos, [&phash](auto const& info) { return info.hash == phash; })->matchers | std::views::filter([](auto const& pair) { return pair.first == AI; });
281272
if constexpr (soa::is_filtered<T>) {
282273
return extractFilteredFromRecord<T>(record, matchers, *std::ranges::find_if(infos, [&phash](ExpressionInfo const& i) { return (i.processHash == phash && i.argumentIndex == AI); }));
283274
} else {
284275
return extractFromRecord<T>(record, matchers);
285276
}
286277
}
287278

288-
template <typename C, is_table_iterator_or_enumeration Grouping, soa::is_table... Args>
289-
static auto bindGroupingTable(InputRecord& record, std::vector<InputInfo> iInfos, void (C::*)(Grouping, Args...), std::vector<ExpressionInfo>& infos)
279+
template <std::ranges::input_range R, typename C, is_table_iterator_or_enumeration Grouping, soa::is_table... Args>
280+
static auto bindGroupingTable(InputRecord& record, R matchers, void (C::*)(Grouping, Args...), std::vector<ExpressionInfo>& infos)
290281
requires(!std::same_as<Grouping, void>)
291282
{
292283
constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(Grouping, Args...)>();
293-
return extract<std::decay_t<Grouping>, 0>(record, iInfos, infos, hash);
284+
return extract<std::decay_t<Grouping>, 0>(record, matchers | std::views::filter([](auto const& pair) { return pair.first == 0; }), infos, hash);
294285
}
295286

296-
template <typename C, is_table_iterator_or_enumeration Grouping, soa::is_table... Args>
297-
static auto bindAssociatedTables(InputRecord& record, std::vector<InputInfo> iInfos, void (C::*)(Grouping, Args...), std::vector<ExpressionInfo>& infos)
287+
template <std::ranges::input_range R, typename C, is_table_iterator_or_enumeration Grouping, soa::is_table... Args>
288+
static auto bindAssociatedTables(InputRecord& record, R matchers, void (C::*)(Grouping, Args...), std::vector<ExpressionInfo>& infos)
298289
requires(!std::same_as<Grouping, void> && sizeof...(Args) > 0)
299290
{
300-
constexpr auto p = pack<Args...>{};
301291
constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(Grouping, Args...)>();
302-
return std::make_tuple(extract<std::decay_t<Args>, has_type_at_v<Args>(p) + 1>(record, iInfos, infos, hash)...);
292+
return std::make_tuple(extract<std::decay_t<Args>, has_type_at_v<Args>(pack<Args...>{}) + 1>(record, matchers | std::views::filter([](auto const& pair) { return pair.first == has_type_at_v<Args>(pack<Args...>{}) + 1; }), infos, hash)...);
303293
}
304294

305295
template <soa::is_table... As>
@@ -308,11 +298,11 @@ struct AnalysisDataProcessorBuilder {
308298
(std::get<As>(dest).bindInternalIndicesTo(&std::get<As>(src)), ...);
309299
}
310300

311-
template <typename Task, is_table_iterator_or_enumeration Grouping, soa::is_table... Associated>
312-
static void invokeProcess(Task& task, InputRecord& inputs, std::vector<InputInfo> iInfos, void (Task::*processingFunction)(Grouping, Associated...), std::vector<ExpressionInfo>& infos, ArrowTableSlicingCache& slices, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
301+
template <typename Task, is_table_iterator_or_enumeration Grouping, std::ranges::input_range R, soa::is_table... Associated>
302+
static void invokeProcess(Task& task, InputRecord& inputs, R matchers, void (Task::*processingFunction)(Grouping, Associated...), std::vector<ExpressionInfo>& infos, ArrowTableSlicingCache& slices, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
313303
{
314304
using G = std::decay_t<Grouping>;
315-
auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, iInfos, processingFunction, infos);
305+
auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, matchers, processingFunction, infos);
316306

317307
constexpr const int numElements = nested_brace_constructible_size<false, std::decay_t<Task>>() / 10;
318308

@@ -341,7 +331,7 @@ struct AnalysisDataProcessorBuilder {
341331
}
342332
} else {
343333
// multiple arguments to process
344-
auto associatedTables = AnalysisDataProcessorBuilder::bindAssociatedTables(inputs, iInfos, processingFunction, infos);
334+
auto associatedTables = AnalysisDataProcessorBuilder::bindAssociatedTables(inputs, matchers, processingFunction, infos);
345335
// pre-bind self indices
346336
std::apply(
347337
[&task](auto&... t) mutable {
@@ -381,7 +371,7 @@ struct AnalysisDataProcessorBuilder {
381371
task);
382372
overwriteInternalIndices(associatedTables, associatedTables);
383373
if constexpr (soa::is_iterator<G>) {
384-
auto slicer = GroupSlicer(groupingTable, associatedTables, slices, newOrigin);
374+
auto slicer = GroupSlicer(groupingTable, associatedTables, slices, matchers, newOrigin);
385375
for (auto& slice : slicer) {
386376
auto associatedSlices = slice.associatedTables();
387377
overwriteInternalIndices(associatedSlices, associatedTables);
@@ -674,14 +664,18 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args)
674664
}
675665
// execute process()
676666
if constexpr (requires { &T::process; }) {
677-
AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), inputInfos, &T::process, expressionInfos, slices, newOrigin);
667+
constexpr auto phash = o2::framework::TypeIdHelpers::uniqueId<decltype(&T::process)>();
668+
auto matchers = std::ranges::find_if(inputInfos, [&phash](auto const& info) { return info.hash == phash; })->matchers;
669+
AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), matchers, &T::process, expressionInfos, slices, newOrigin);
678670
}
679671
// execute optional process()
680672
homogeneous_apply_refs_sized<numElements>(
681673
[&pc, &expressionInfos, &task, &slices, &inputInfos, &newOrigin](auto& x) {
682674
if constexpr (is_process_configurable<decltype(x)>) {
683675
if (x.value == true) {
684-
AnalysisDataProcessorBuilder::invokeProcess(*task.get(), pc.inputs(), inputInfos, x.process, expressionInfos, slices, newOrigin);
676+
constexpr auto phash = o2::framework::TypeIdHelpers::uniqueId<decltype(x.process)>();
677+
auto matchers = std::ranges::find_if(inputInfos, [&phash](auto const& info) { return info.hash == phash; })->matchers;
678+
AnalysisDataProcessorBuilder::invokeProcess(*task.get(), pc.inputs(), matchers, x.process, expressionInfos, slices, newOrigin);
685679
return true;
686680
}
687681
return false;

Framework/Core/include/Framework/GroupSlicer.h

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,27 @@
2020
#include <arrow/util/key_value_metadata.h>
2121
#include <type_traits>
2222
#include <string>
23+
namespace {
24+
template <typename T>
25+
auto getMatcherFor(std::string const& columnName, o2::header::DataOrigin newOrigin = o2::header::DataOrigin{"AOD"})
26+
{
27+
auto matcher = o2::soa::getMatcherFromTypeForKey<std::decay_t<T>>(columnName);
28+
if ((matcher.origin == o2::header::DataOrigin{"AOD"}) && (newOrigin != o2::header::DataOrigin{"AOD"})) {
29+
matcher = o2::framework::replaceOrigin(matcher, newOrigin);
30+
}
31+
return matcher;
32+
}
33+
}
34+
2335

2436
namespace o2::framework
2537
{
26-
template <typename G, typename... A>
38+
template <typename G, std::ranges::input_range R, typename... A>
2739
struct GroupSlicer {
2840
using grouping_t = std::decay_t<G>;
29-
GroupSlicer(G& gt, std::tuple<A...>& at, ArrowTableSlicingCache& slices, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
41+
GroupSlicer(G& gt, std::tuple<A...>& at, ArrowTableSlicingCache& slices, R matchers, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
3042
: max{gt.size()},
31-
mBegin{GroupSlicerIterator(gt, at, slices, newOrigin)}
43+
mBegin{GroupSlicerIterator(gt, at, slices, matchers, newOrigin)}
3244
{
3345
}
3446

@@ -50,27 +62,24 @@ struct GroupSlicer {
5062
{
5163
}
5264

53-
template <typename T>
54-
requires(o2::soa::relatedByIndex<std::decay_t<G>, std::decay_t<T>>())
65+
template <soa::is_table T>
66+
requires(o2::soa::relatedByIndex<std::decay_t<G>, std::decay_t<T>>() && !soa::is_smallgroups<T>)
5567
auto splittingFunction(T&& table)
5668
{
57-
constexpr auto index = framework::has_type_at_v<std::decay_t<T>>(associated_pack_t{});
58-
auto matcher = o2::soa::getMatcherFromTypeForKey<std::decay_t<T>>(mIndexColumnName);
59-
if ((matcher.origin == header::DataOrigin{"AOD"}) && (replacementOrigin != header::DataOrigin{"AOD"})) {
60-
matcher = framework::replaceOrigin(matcher, replacementOrigin);
69+
if (table.size() == 0) {
70+
return;
6171
}
62-
auto bk = Entry("", matcher, mIndexColumnName);
63-
if constexpr (!o2::soa::is_smallgroups<std::decay_t<T>>) {
64-
if (table.size() == 0) {
65-
return;
66-
}
67-
sliceInfos[index] = mSlices->getCacheFor(bk);
68-
} else {
69-
if (table.tableSize() == 0) {
70-
return;
71-
}
72-
sliceInfosUnsorted[index] = mSlices->getCacheUnsortedFor(bk);
72+
sliceInfos[framework::has_type_at_v<std::decay_t<T>>(associated_pack_t{})] = mSlices->getCacheFor(Entry("", getMatcherFor<T>(mIndexColumnName, replacementOrigin), mIndexColumnName));
73+
}
74+
75+
template <soa::is_smallgroups T>
76+
requires(o2::soa::relatedByIndex<std::decay_t<G>, std::decay_t<T>>())
77+
auto splittingFunction(T&& table)
78+
{
79+
if (table.tableSize() == 0) {
80+
return;
7381
}
82+
sliceInfosUnsorted[framework::has_type_at_v<std::decay_t<T>>(associated_pack_t{})] = mSlices->getCacheUnsortedFor(Entry("", getMatcherFor<T>(mIndexColumnName, replacementOrigin), mIndexColumnName));
7483
}
7584

7685
template <typename T>
@@ -86,33 +95,28 @@ struct GroupSlicer {
8695
starts[index] = selections[index]->begin();
8796
}
8897

89-
GroupSlicerIterator(G& gt, std::tuple<A...>& at, ArrowTableSlicingCache& slices, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
98+
GroupSlicerIterator(G& gt, std::tuple<A...>& at, ArrowTableSlicingCache& slices, R matchers_, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
9099
: mIndexColumnName{std::string("fIndex") + o2::framework::cutString(o2::soa::getLabelFromType<G>())},
91100
mGt{&gt},
92101
mAt{&at},
93102
mGroupingElement{gt.begin()},
94103
position{0},
95104
mSlices{&slices},
96-
replacementOrigin{newOrigin}
105+
replacementOrigin{newOrigin},
106+
matchers{matchers_}
97107
{
98108
if constexpr (soa::is_filtered_table<std::decay_t<G>>) {
99109
groupSelection = mGt->getSelectedRows();
100110
}
101111

102112
/// prepare slices and offsets for all associated tables that have index
103113
/// to grouping table
104-
///
105-
std::apply(
106-
[&](auto&&... x) -> void {
107-
(splittingFunction(x), ...);
108-
},
109-
at);
110114
/// extract selections from filtered associated tables
111-
std::apply(
112-
[&](auto&&... x) -> void {
113-
(extractingFunction(x), ...);
114-
},
115-
at);
115+
116+
[this]<size_t... Is>(std::tuple<A...>& at, std::index_sequence<Is...>){
117+
(splittingFunction(std::get<Is>(at)), ...);
118+
(extractingFunction(std::get<Is>(at)), ...);
119+
}(*mAt, std::make_index_sequence<sizeof...(A)>());
116120
}
117121

118122
GroupSlicerIterator& operator++()
@@ -277,6 +281,7 @@ struct GroupSlicer {
277281
std::array<SliceInfoUnsortedPtr, sizeof...(A)> sliceInfosUnsorted;
278282
ArrowTableSlicingCache* mSlices;
279283
header::DataOrigin replacementOrigin;
284+
R matchers;
280285
};
281286

282287
GroupSlicerIterator& begin()

Framework/Core/test/test_GroupSlicer.cxx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include "Framework/GroupSlicer.h"
1616
#include "Framework/ArrowTableSlicingCache.h"
1717
#include <arrow/util/config.h>
18-
#include <iostream>
1918

2019
#include <catch_amalgamated.hpp>
2120

@@ -94,6 +93,8 @@ TEST_CASE("RelatedByIndex")
9493
CHECK(soa::relatedByIndex<aod::Collision, aod::Tracks>() == true);
9594
}
9695

96+
using Matchers = std::vector<std::pair<int, ConcreteDataMatcher>>;
97+
9798
TEST_CASE("GroupSlicerOneAssociated")
9899
{
99100
TableBuilder builderE;
@@ -120,7 +121,7 @@ TEST_CASE("GroupSlicerOneAssociated")
120121
std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType<aod::Events>());
121122
ArrowTableSlicingCache slices({{soa::getLabelFromType<aod::TrksX>(), soa::getMatcherFromTypeForKey<aod::TrksX>(key), key}});
122123
auto s = slices.updateCacheEntry(0, trkTable);
123-
o2::framework::GroupSlicer g(e, tt, slices);
124+
o2::framework::GroupSlicer g(e, tt, slices, Matchers{});
124125

125126
auto count = 0;
126127
for (auto& slice : g) {
@@ -198,7 +199,7 @@ TEST_CASE("GroupSlicerSeveralAssociated")
198199
auto s = slices.updateCacheEntry(0, {trkTableX});
199200
s = slices.updateCacheEntry(1, {trkTableY});
200201
s = slices.updateCacheEntry(2, {trkTableZ});
201-
o2::framework::GroupSlicer g(e, tt, slices);
202+
o2::framework::GroupSlicer g(e, tt, slices, Matchers{});
202203

203204
auto count = 0;
204205
for (auto& slice : g) {
@@ -260,7 +261,7 @@ TEST_CASE("GroupSlicerMismatchedGroups")
260261
std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType<aod::Events>());
261262
ArrowTableSlicingCache slices({{soa::getLabelFromType<aod::TrksX>(), soa::getMatcherFromTypeForKey<aod::TrksX>(key), key}});
262263
auto s = slices.updateCacheEntry(0, trkTable);
263-
o2::framework::GroupSlicer g(e, tt, slices);
264+
o2::framework::GroupSlicer g(e, tt, slices, Matchers{});
264265

265266
for (auto& slice : g) {
266267
auto as = slice.associatedTables();
@@ -317,7 +318,7 @@ TEST_CASE("GroupSlicerMismatchedUnassignedGroups")
317318
std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType<aod::Events>());
318319
ArrowTableSlicingCache slices({{soa::getLabelFromType<aod::TrksX>(), soa::getMatcherFromTypeForKey<aod::TrksX>(key), key}});
319320
auto s = slices.updateCacheEntry(0, trkTable);
320-
o2::framework::GroupSlicer g(e, tt, slices);
321+
o2::framework::GroupSlicer g(e, tt, slices, Matchers{});
321322

322323
auto count = 0;
323324
for (auto& slice : g) {
@@ -368,7 +369,7 @@ TEST_CASE("GroupSlicerMismatchedFilteredGroups")
368369
std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType<aod::Events>());
369370
ArrowTableSlicingCache slices({{soa::getLabelFromType<aod::TrksX>(), soa::getMatcherFromTypeForKey<aod::TrksX>(key), key}});
370371
auto s = slices.updateCacheEntry(0, trkTable);
371-
o2::framework::GroupSlicer g(e, tt, slices);
372+
o2::framework::GroupSlicer g(e, tt, slices, Matchers{});
372373

373374
auto count = 0;
374375

@@ -430,7 +431,7 @@ TEST_CASE("GroupSlicerMismatchedUnsortedFilteredGroups")
430431
std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType<aod::Events>());
431432
ArrowTableSlicingCache slices({}, {{soa::getLabelFromType<aod::TrksXU>(), soa::getMatcherFromTypeForKey<aod::TrksXU>(key), key}});
432433
auto s = slices.updateCacheEntryUnsorted(0, trkTable);
433-
o2::framework::GroupSlicer g(e, tt, slices);
434+
o2::framework::GroupSlicer g(e, tt, slices, Matchers{});
434435

435436
unsigned int count = 0;
436437

@@ -453,7 +454,7 @@ TEST_CASE("GroupSlicerMismatchedUnsortedFilteredGroups")
453454
std::vector<int64_t> sele;
454455
soa::SmallGroups<aod::TrksXU> te{{trkTableE}, std::move(sele)};
455456
auto tte = std::make_tuple(te);
456-
o2::framework::GroupSlicer ge(e, tte, slices);
457+
o2::framework::GroupSlicer ge(e, tte, slices, Matchers{});
457458

458459
count = 0;
459460
for (auto& slice : ge) {
@@ -467,7 +468,7 @@ TEST_CASE("GroupSlicerMismatchedUnsortedFilteredGroups")
467468

468469
soa::SmallGroupsUnfiltered<aod::TrksXU> tu{{trkTable}, std::vector<int64_t>{}};
469470
auto ttu = std::make_tuple(tu);
470-
o2::framework::GroupSlicer gu(e, ttu, slices);
471+
o2::framework::GroupSlicer gu(e, ttu, slices, Matchers{});
471472

472473
count = 0;
473474
for (auto& slice : gu) {
@@ -557,7 +558,7 @@ TEST_CASE("GroupSlicerMismatchedUnsortedFilteredGroupsWithSelfIndex")
557558
{soa::getLabelFromType<aod::Things>(), soa::getMatcherFromTypeForKey<aod::Things>(key), key}});
558559
auto s0 = slices.updateCacheEntry(0, partsTable);
559560
auto s1 = slices.updateCacheEntry(1, thingsTable);
560-
o2::framework::GroupSlicer g(e, associatedTuple, slices);
561+
o2::framework::GroupSlicer g(e, associatedTuple, slices, Matchers{});
561562

562563
overwriteInternalIndices(associatedTuple, associatedTuple);
563564

@@ -616,7 +617,7 @@ TEST_CASE("EmptySliceables")
616617
std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType<aod::Events>());
617618
ArrowTableSlicingCache slices({{soa::getLabelFromType<aod::TrksX>(), soa::getMatcherFromTypeForKey<aod::TrksX>(key), key}});
618619
auto s = slices.updateCacheEntry(0, trkTable);
619-
o2::framework::GroupSlicer g(e, tt, slices);
620+
o2::framework::GroupSlicer g(e, tt, slices, Matchers{});
620621

621622
unsigned int count = 0;
622623
for (auto& slice : g) {

0 commit comments

Comments
 (0)