@@ -58,6 +58,8 @@ void missingFilterDeclaration(int hash, int ai);
5858void notBoundTable (const char * tableName);
5959void * extractCCDBPayload (char * payload, size_t size, TClass const * cl, const char * what);
6060
61+ static constexpr char asciiToLower (char c);
62+
6163template <typename ... C>
6264auto createFieldsFromColumns (framework::pack<C...>)
6365{
@@ -1316,8 +1318,8 @@ static constexpr auto hasColumnForKey(framework::pack<C...>, std::string_view ke
13161318 return std::ranges::equal (
13171319 str1, str2,
13181320 [](char c1, char c2) {
1319- return std::tolower (static_cast <unsigned char >(c1)) ==
1320- std::tolower (static_cast <unsigned char >(c2));
1321+ return asciiToLower (static_cast <unsigned char >(c1)) ==
1322+ asciiToLower (static_cast <unsigned char >(c2));
13211323 });
13221324 };
13231325 return (caseInsensitiveCompare (C::inherited_t ::mLabel , key) || ...);
@@ -1418,12 +1420,7 @@ struct PreslicePolicySorted : public PreslicePolicyBase {
14181420 void updateSliceInfo (SliceInfoPtr&& si);
14191421
14201422 SliceInfoPtr sliceInfo;
1421- std::shared_ptr<arrow::Table> getSliceFor (int value, std::shared_ptr<arrow::Table> const & input, uint64_t & offset) const ;
1422- // One-slot cache for the empty (0-row) slice, so that empty groups do not
1423- // slice every column only to produce 0 rows (the common case for sparse
1424- // grouping, e.g. candidates per collision). Keyed by the input table, which
1425- // changes with every dataframe.
1426- mutable std::pair<arrow::Table const *, std::shared_ptr<arrow::Table>> emptySlice{nullptr , nullptr };
1423+ o2::soa::ArrowTableRef getSliceFor (int value, o2::soa::ArrowTableRef const & input) const ;
14271424};
14281425
14291426struct PreslicePolicyGeneral : public PreslicePolicyBase {
@@ -1447,14 +1444,14 @@ struct PresliceBase : public Policy {
14471444 {
14481445 }
14491446
1450- std::shared_ptr<arrow::Table> getSliceFor (int value, std::shared_ptr<arrow::Table> const & input, uint64_t & offset ) const
1447+ o2::soa::ArrowTableRef getSliceFor (int value, o2::soa::ArrowTableRef const & input) const
14511448 {
14521449 if constexpr (OPT ) {
14531450 if (Policy::isMissing ()) {
14541451 return nullptr ;
14551452 }
14561453 }
1457- return Policy::getSliceFor (value, input, offset );
1454+ return Policy::getSliceFor (value, input);
14581455 }
14591456
14601457 std::span<const int64_t > getSliceFor (int value) const
@@ -1524,8 +1521,7 @@ auto doSliceBy(T const* table, o2::framework::PresliceBase<C, Policy, OPT> const
15241521 missingOptionalPreslice (getLabelFromType<std::decay_t <T>>().data (), container.bindingKey .key .c_str ());
15251522 }
15261523 }
1527- uint64_t offset = 0 ;
1528- auto out = container.getSliceFor (value, table->asArrowTable (), offset);
1524+ auto out = container.getSliceFor (value, table->asArrowTableRef ());
15291525 auto t = typename T::self_t ({out}, offset);
15301526 if (t.tableSize () != 0 ) {
15311527 table->copyIndexBindings (t);
@@ -1537,7 +1533,7 @@ auto doSliceBy(T const* table, o2::framework::PresliceBase<C, Policy, OPT> const
15371533template <soa::is_filtered_table T>
15381534auto doSliceByHelper (T const * table, std::span<const int64_t > const & selection)
15391535{
1540- auto t = soa::Filtered<typename T::base_t >({table->asArrowTable ()}, selection);
1536+ auto t = soa::Filtered<typename T::base_t >({table->asArrowTableRef ()}, selection);
15411537 if (t.tableSize () != 0 ) {
15421538 table->copyIndexBindings (t);
15431539 t.bindInternalIndicesTo (table);
@@ -1550,7 +1546,7 @@ template <soa::is_table T>
15501546 requires (!soa::is_filtered_table<T>)
15511547auto doSliceByHelper (T const * table, std::span<const int64_t > const & selection)
15521548{
1553- auto t = soa::Filtered<T>({table->asArrowTable ()}, selection);
1549+ auto t = soa::Filtered<T>({table->asArrowTableRef ()}, selection);
15541550 if (t.tableSize () != 0 ) {
15551551 table->copyIndexBindings (t);
15561552 t.bindInternalIndicesTo (table);
@@ -1574,17 +1570,17 @@ auto doSliceBy(T const* table, o2::framework::PresliceBase<C, Policy, OPT> const
15741570SelectionVector sliceSelection (std::span<int64_t const > const & mSelectedRows , int64_t nrows, uint64_t offset);
15751571
15761572template <soa::is_filtered_table T>
1577- auto prepareFilteredSlice (T const * table, std::shared_ptr<arrow::Table> slice, uint64_t offset )
1573+ auto prepareFilteredSlice (T const * table, o2::soa::ArrowTableRef slice)
15781574{
1579- if (offset >= static_cast <uint64_t >(table->tableSize ())) {
1575+ if (slice. range . offset >= static_cast <uint64_t >(table->tableSize ())) {
15801576 Filtered<typename T::base_t > fresult{{{slice}}, SelectionVector{}, 0 };
15811577 if (fresult.tableSize () != 0 ) {
15821578 table->copyIndexBindings (fresult);
15831579 }
15841580 return fresult;
15851581 }
1586- auto slicedSelection = sliceSelection (table->getSelectedRows (), slice->num_rows (), offset);
1587- Filtered<typename T::base_t > fresult{{{slice}}, std::move (slicedSelection), offset };
1582+ auto slicedSelection = sliceSelection (table->getSelectedRows (), slice->num_rows (), slice. range . offset );
1583+ Filtered<typename T::base_t > fresult{{{slice}}, std::move (slicedSelection)};
15881584 if (fresult.tableSize () != 0 ) {
15891585 table->copyIndexBindings (fresult);
15901586 }
@@ -1600,9 +1596,8 @@ auto doFilteredSliceBy(T const* table, o2::framework::PresliceBase<C, framework:
16001596 missingOptionalPreslice (getLabelFromType<T>().data (), container.bindingKey .key .c_str ());
16011597 }
16021598 }
1603- uint64_t offset = 0 ;
1604- auto slice = container.getSliceFor (value, table->asArrowTable (), offset);
1605- return prepareFilteredSlice (table, slice, offset);
1599+ auto slice = container.getSliceFor (value, table->asArrowTable ());
1600+ return prepareFilteredSlice (table, slice);
16061601}
16071602
16081603std::function<framework::ConcreteDataMatcher(framework::ConcreteDataMatcher&&)> originReplacement (header::DataOrigin newOrigin);
@@ -1613,10 +1608,7 @@ auto doSliceByCached(T const* table, framework::expressions::BindingNode const&
16131608 auto localCache = cache.ptr ->getCacheFor ({" " , originReplacement (cache.ptr ->newOrigin )(o2::soa::getMatcherFromTypeForKey<T>(node.name )),
16141609 node.name });
16151610 auto [offset, count] = localCache.getSliceFor (value);
1616- // Empty group: reuse a cached empty (0-row) table instead of slicing every column.
1617- auto slice = count == 0 ? cache.ptr ->getEmptySliceFor (table->asArrowTable ())
1618- : table->asArrowTable ()->Slice (static_cast <uint64_t >(offset), count);
1619- auto t = typename T::self_t ({slice}, static_cast <uint64_t >(offset));
1611+ auto t = typename T::self_t ({table->asArrowTableRef ().slice (static_cast <uint64_t >(offset), count)});
16201612 if (t.tableSize () != 0 ) {
16211613 table->copyIndexBindings (t);
16221614 }
@@ -1629,10 +1621,7 @@ auto doFilteredSliceByCached(T const* table, framework::expressions::BindingNode
16291621 auto localCache = cache.ptr ->getCacheFor ({" " , originReplacement (cache.ptr ->newOrigin )(o2::soa::getMatcherFromTypeForKey<T>(node.name )),
16301622 node.name });
16311623 auto [offset, count] = localCache.getSliceFor (value);
1632- // Empty group: reuse a cached empty (0-row) table instead of slicing every column.
1633- auto slice = count == 0 ? cache.ptr ->getEmptySliceFor (table->asArrowTable ())
1634- : table->asArrowTable ()->Slice (static_cast <uint64_t >(offset), count);
1635- return prepareFilteredSlice (table, slice, offset);
1624+ return prepareFilteredSlice (table, table->asArrowTableRef ().slice (static_cast <uint64_t >(offset), count));
16361625}
16371626
16381627template <soa::is_table T>
@@ -1641,14 +1630,14 @@ auto doSliceByCachedUnsorted(T const* table, framework::expressions::BindingNode
16411630 auto localCache = cache.ptr ->getCacheUnsortedFor ({" " , originReplacement (cache.ptr ->newOrigin )(o2::soa::getMatcherFromTypeForKey<T>(node.name )),
16421631 node.name });
16431632 if constexpr (soa::is_filtered_table<T>) {
1644- auto t = typename T::self_t ({table->asArrowTable ()}, localCache.getSliceFor (value));
1633+ auto t = typename T::self_t ({table->asArrowTableRef ()}, localCache.getSliceFor (value));
16451634 if (t.tableSize () != 0 ) {
16461635 t.intersectWithSelection (table->getSelectedRows ());
16471636 table->copyIndexBindings (t);
16481637 }
16491638 return t;
16501639 } else {
1651- auto t = Filtered<T>({table->asArrowTable ()}, localCache.getSliceFor (value));
1640+ auto t = Filtered<T>({table->asArrowTableRef ()}, localCache.getSliceFor (value));
16521641 if (t.tableSize () != 0 ) {
16531642 table->copyIndexBindings (t);
16541643 }
0 commit comments