2  * Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration.
 
    5  * @file AthContainers/tools/PackedLinkVectorHelper.icc
 
    6  * @author scott snyder <snyder@bnl.gov>
 
    8  * @brief Helper functions for managing @c PackedLink variables.
 
   12 namespace SG::detail {
 
   16  * @brief Constructor from an @c IAuxTypeVector directly.
 
   17  * @param linkedVector The @c IAuxTypeVector for the aux variable.
 
   20 PackedLinkVectorHelperBase::LinkedVector::LinkedVector (IAuxTypeVector& linkedVector)
 
   21   : m_data (&linkedVector)
 
   27  * @brief Constructor from a container and aux ID.
 
   28  * @param container Container holding the variables.
 
   29  * @param auxid The ID of the PackedLink variable.
 
   32 PackedLinkVectorHelperBase::LinkedVector::LinkedVector (AuxVectorData& container, SG::auxid_t auxid)
 
   33   : m_data (std::make_pair (&container, auxid))
 
   39  * @brief Return the @c IAuxTypeVector.
 
   42 IAuxTypeVector* PackedLinkVectorHelperBase::LinkedVector::get()
 
   44   // If we already have it, return it.
 
   45   if (m_data.index() == 0)
 
   46     return std::get<0>(m_data);
 
   48   // Look it up from the container.
 
   49   auto [container, auxid] = std::get<1>(m_data);
 
   50   IAuxTypeVector* lv = container->getStore()->linkedVector (auxid);
 
   52   // Remember it to possibly use again.
 
   59  * @brief Return the @c IAuxTypeVector.
 
   63 PackedLinkVectorHelperBase::LinkedVector::operator*()
 
   70  * @brief Return the @c IAuxTypeVector.
 
   73 IAuxTypeVector* PackedLinkVectorHelperBase::LinkedVector::operator->()
 
   80  * @brief Return the current store from the first valid link in the span.
 
   81  *        If there are no valid links, then return the global default.
 
   82  * @param links The span of links.
 
   85 auto PackedLinkVectorHelperBase::storeFromSpan ([[maybe_unused]] DataLinkBase_span& links)
 
   88 #ifndef XAOD_STANDALONE
 
   89   if (links.size() > 1) {
 
   90     return links[1].source();
 
   93   return CurrentEventStore::store();
 
   98  * @brief Return a span over all the linked @c DataLinkBase's.
 
   99  *        from the linked vector.
 
  100  * @param linkedVec Interface for the linked vector of @c DataLinkBase's.
 
  103 auto PackedLinkVectorHelperBase::getLinkBaseSpan (IAuxTypeVector& linkedVec)
 
  106   return DataLinkBase_span (linkedVec.getDataSpan());
 
  111  * @brief Return a span over all the linked @c DataLinkBase's.
 
  112  *        from the linked vector.
 
  113  * @param linkedVec Interface for the linked vector of @c DataLinkBase's.
 
  116 auto PackedLinkVectorHelperBase::getLinkBaseSpan (const IAuxTypeVector& linkedVec)
 
  117   -> const_DataLinkBase_span
 
  119   return const_DataLinkBase_span (linkedVec.getDataSpan());
 
  124  * @brief Find the collection index in the linked DataLinks for a sgkey.
 
  125  * @param linkedVec How to find the linked vector.
 
  126  * @param sgkey Hashed key for which to search.
 
  127  * @param links Span over the vector of @c DataLinks, as @c DataLinkBase.
 
  128  *              May be modified if the vector grows.
 
  129  * @param sg The @c IProxyDict of the current store.
 
  130  *           May be null to use the global, thread-local default.
 
  132  * Searches for a @c DataLink matching @c sgkey in the linked vector.
 
  133  * If not found, then a new entry is added.
 
  134  * Returns a pair (INDEX, CACHEVALID).  INDEX is the index in the vector
 
  135  * of the sgkey (and thus the collection index to store in the @c PackedLink).
 
  136  * CACHEVALID is true if it is known that the payload of the vector
 
  137  * has not moved.  (If this is false, any caches/iterators must be assumed
 
  140 template <class CONT>
 
  142 std::pair<size_t, bool> PackedLinkVectorHelper<CONT>::findCollection
 
  143    (LinkedVector& linkedVec,
 
  144     sgkey_t sgkey, DataLinkBase_span& links, IProxyDict* sg)
 
  146   return findCollectionBase (linkedVec, sgkey, links, sg, initLink);
 
  151  * @brief Update collection index of a collection of @c PackedLink.
 
  152  * @param linkedVec Interface for the linked vector of DataLinks.
 
  153  * @param ptr Pointer to the start of the PackedLink collection.
 
  154  * @param n Length of the PackedLink collection.
 
  155  * @param srcDLinks Span over the vector of DataLinks
 
  156  *                  for the source container of the links.
 
  157  * @param sg The @c IProxyDict of the current store.
 
  158  *           If null, take it from the links in @c srcDlinks,
 
  159  *           or use the global, thread-local default.
 
  161  * To be used after links have been copied/moved from one container
 
  162  * to another.  The collection indices are updated to be appropriate
 
  163  * for the destination container.
 
  164  * Returns true if it is known that the payload of the linked vector
 
  165  * has not moved.  (If this is false, any caches/iterators must be assumed
 
  168 template <class CONT>
 
  170 bool PackedLinkVectorHelper<CONT>::updateLinks (IAuxTypeVector& linkedVec,
 
  171                                                 SG::PackedLink<CONT>* ptr,
 
  173                                                 const const_DataLinkBase_span& srcDLinks,
 
  176   PackedLinkBase_span span (static_cast<PackedLinkBase*>(ptr), n);
 
  177   return updateLinksBase (linkedVec, span, srcDLinks, sg, initLink);
 
  182  * @brief Update collection index of a collection of @c PackedLink.
 
  183  * @param linkedVec Interface for the linked vector of DataLinks.
 
  184  * @param ptr Pointer to the start of the PackedLink collection.
 
  185  * @param n Length of the PackedLink collection.
 
  186  * @param srclv Interface for the linked vector
 
  187  *              for the source container of the links.
 
  188  * @param sg The @c IProxyDict of the current store.
 
  189  *           If null, take it from the links in @c srcDlinks,
 
  190  *           or use the global, thread-local default.
 
  192  * To be used after links have been copied/moved from one container
 
  193  * to another.  The collection indices are updated to be appropriate
 
  194  * for the destination container.
 
  195  * Returns true if it is known that the payload of the linked vector
 
  196  * has not moved.  (If this is false, any caches/iterators must be assumed
 
  199 template <class CONT>
 
  201 bool PackedLinkVectorHelper<CONT>::updateLinks (IAuxTypeVector& linkedVec,
 
  202                                                 SG::PackedLink<CONT>* ptr,
 
  204                                                 const IAuxTypeVector& srclv,
 
  207   const_DataLinkBase_span srcDLinks = getLinkBaseSpan (srclv);
 
  208   PackedLinkBase_span span (static_cast<PackedLinkBase*>(ptr), n);
 
  209   return updateLinksBase (linkedVec, span, srcDLinks, sg, initLink);
 
  214  * @brief Update collection index of a collection of @c PackedLink vectors.
 
  215  * @param linkedVec Interface for the linked vector of DataLinks.
 
  216  * @param ptr Pointer to the start of the PackedLink vector collection.
 
  217  * @param n Length of the PackedLink vector collection.
 
  218  * @param srclv Interface for the linked vector
 
  219  *              for the source container of the links.
 
  220  * @param sg The @c IProxyDict of the current store.
 
  221  *           If null, take it from the links in @c srcDlinks,
 
  222  *           or use the global, thread-local default.
 
  224  * To be used after links have been copied/moved from one container
 
  225  * to another.  The collection indices are updated to be appropriate
 
  226  * for the destination container.
 
  227  * Returns true if it is known that the payload of the linked vector
 
  228  * has not moved.  (If this is false, any caches/iterators must be assumed
 
  231 template <class CONT>
 
  232 template <class VALLOC>
 
  233 bool PackedLinkVectorHelper<CONT>::updateLinks (IAuxTypeVector& linkedVec,
 
  234                                                 std::vector<SG::PackedLink<CONT>, VALLOC>* ptr,
 
  236                                                 const IAuxTypeVector& srclv,
 
  239   const_DataLinkBase_span srcDLinks = getLinkBaseSpan (srclv);
 
  241     DataLinkBase_span DLinks (getLinkBaseSpan (linkedVec));
 
  242     sg = storeFromSpan (DLinks);
 
  244   bool cacheValid = true;
 
  245   for (size_t i = 0; i < n; i++) {
 
  246     PackedLinkBase_span span (static_cast<PackedLinkBase*>(ptr[i].data()),
 
  248     cacheValid &= updateLinksBase (linkedVec, span, srcDLinks, sg, initLink);
 
  255  * @brief Assign a range of @c ElementLink to a vector of @c Packedlink.
 
  256  * @param vect The vector of @c PackedLink to which to assign.
 
  257  * @param linkedVec Interface for the linked vector of DataLinks.
 
  258  * @param dlinks Span over the link vector, as @c DataLinkBase.
 
  259  * @param x The range to assign.
 
  261  * Returns true if it is known that the payload of the linked vector
 
  262  * has not moved.  (If this is false, any caches/iterators must be assumed
 
  265 template <class CONT>
 
  266 template <class VALLOC, ElementLinkRange<CONT> RANGE>
 
  268 PackedLinkVectorHelper<CONT>::assignVElt (std::vector<PLink_t, VALLOC>& velt,
 
  269                                           IAuxTypeVector& linkedVec,
 
  270                                           DataLinkBase_span& dlinks,
 
  273   // Define a ElementLink->PackedLink transform.
 
  274   bool cacheValid = true;
 
  275   LinkedVector lv (linkedVec);
 
  276   auto xform = [&] (const Link_t& el) {
 
  277     auto [dlindex, flag] = findCollection (lv,
 
  282     return PackedLink<CONT> (dlindex, el.isDefault() ? 0 : el.index());
 
  285   // Make a transformed range and assign it to the vector.
 
  286 #ifdef __cpp_lib_containers_ranges // c++23
 
  287   velt.assign_range (x | std::views::transform (xform));
 
  289   const auto r = x | std::views::transform (xform);
 
  290   velt.assign (r.begin(), r.end());
 
  297  * @brief Insert a range of @c ElementLink into a vector of @c Packedlink.
 
  298  * @param vect The vector of @c PackedLink to which to assign.
 
  299  * @param pos The position at which to do the insertion.
 
  300  * @param linkedVec Interface for the linked vector of DataLinks.
 
  301  * @param dlinks Span over the link vector, as @c DataLinkBase.
 
  302  * @param x The range to assign.
 
  304  * Returns true if it is known that the payload of the linked vector
 
  305  * has not moved.  (If this is false, any caches/iterators must be assumed
 
  308 template <class CONT>
 
  309 template <class VALLOC, ElementLinkRange<CONT> RANGE>
 
  311 PackedLinkVectorHelper<CONT>::insertVElt (std::vector<PLink_t, VALLOC>& velt,
 
  313                                           IAuxTypeVector& linkedVec,
 
  314                                           DataLinkBase_span& dlinks,
 
  317   // Define a ElementLink->PackedLink transform.
 
  318   bool cacheValid = true;
 
  319   LinkedVector lv (linkedVec);
 
  320   auto xform = [&] (const Link_t& el) {
 
  321     auto [dlindex, flag] = findCollection (lv,
 
  326     return PackedLink<CONT> (dlindex, el.isDefault() ? 0 : el.index());
 
  329   // Make a transformed range and assign it to the vector.
 
  330 #ifdef __cpp_lib_containers_ranges // c++23
 
  331   velt.insert_range (velt.begin()+pos, x | std::views::transform (xform));
 
  333   const auto r = x | std::views::transform (xform);
 
  334   velt.insert (velt.begin()+pos, r.begin(), r.end());
 
  340 #ifndef XAOD_STANDALONE
 
  342  * @brief Apply thinning to packed links, to prepare them for output.
 
  343  * @param linkedVec Interface for the linked vector of @c DataLinks.
 
  344  * @param ptr Pointer to the start of the PackedLink collection.
 
  345  * @param n Length of the PackedLink collection.
 
  346  * @param dlinks Span over the source link vector, as @c DataLinkBase.
 
  347  * @param tc The @c ThinningCache for this object, if it exists.
 
  348  * @param sg The @c IProxyDict of the current store.
 
  349  *           If null, take it from the links in @c srcDlinks,
 
  350  *           or use the global, thread-local default.
 
  352  * Returns true if it is known that the payload of the linked vector
 
  353  * has not moved.  (If this is false, any caches/iterators must be assumed
 
  356 template <class CONT>
 
  359 PackedLinkVectorHelper<CONT>::applyThinning (IAuxTypeVector& linkedVec,
 
  360                                              PackedLink<CONT>* ptr,
 
  362                                              DataLinkBase_span& dlinks,
 
  363                                              const SG::ThinningCache* tc,
 
  366   PackedLinkBase_span lspan (static_cast<PackedLinkBase*>(ptr), n);
 
  367   return applyThinningBase (linkedVec, lspan, dlinks, tc, sg, initLink);
 
  373  * @brief Initialize a @c DataLink.
 
  374  * @param dl The link to initialize.  Really of type @c DLink_t.
 
  375  * @param sgkey Hashed key to which to initialize the link.
 
  376  * @param sg The @c IProxyDict of the current store.
 
  377  *           May be null to use the global, thread-local default.
 
  379 template <class CONT>
 
  381 void PackedLinkVectorHelper<CONT>::initLink (DataLinkBase& dl,
 
  383                                              [[maybe_unused]] IProxyDict* sg)
 
  385 #ifdef XAOD_STANDALONE
 
  386   dl.setPersKey (sgkey);
 
  388   static_cast<DLink_t&>(dl).toIdentifiedObject (sgkey, sg);
 
  393 } // namespace SG::detail