ATLAS Offline Software
PackedLinkVectorHelper.icc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
3  */
4 /**
5  * @file AthContainers/tools/PackedLinkVectorHelper.icc
6  * @author scott snyder <snyder@bnl.gov>
7  * @date May, 2024
8  * @brief Helper functions for managing @c PackedLink variables.
9  */
10 
11 
12 namespace SG::detail {
13 
14 
15 /**
16  * @brief Constructor from an @c IAuxTypeVector directly.
17  * @param linkedVector The @c IAuxTypeVector for the aux variable.
18  */
19 inline
20 PackedLinkVectorHelperBase::LinkedVector::LinkedVector (IAuxTypeVector& linkedVector)
21  : m_data (&linkedVector)
22 {
23 }
24 
25 
26 /**
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.
30  */
31 inline
32 PackedLinkVectorHelperBase::LinkedVector::LinkedVector (AuxVectorData& container, SG::auxid_t auxid)
33  : m_data (std::make_pair (&container, auxid))
34 {
35 }
36 
37 
38 /**
39  * @brief Return the @c IAuxTypeVector.
40  */
41 inline
42 IAuxTypeVector* PackedLinkVectorHelperBase::LinkedVector::get()
43 {
44  // If we already have it, return it.
45  if (m_data.index() == 0)
46  return std::get<0>(m_data);
47 
48  // Look it up from the container.
49  auto [container, auxid] = std::get<1>(m_data);
50  IAuxTypeVector* lv = container->getStore()->linkedVector (auxid);
51 
52  // Remember it to possibly use again.
53  m_data = lv;
54  return lv;
55 }
56 
57 
58 /**
59  * @brief Return the @c IAuxTypeVector.
60  */
61 inline
62 IAuxTypeVector&
63 PackedLinkVectorHelperBase::LinkedVector::operator*()
64 {
65  return *get();
66 }
67 
68 
69 /**
70  * @brief Return the @c IAuxTypeVector.
71  */
72 inline
73 IAuxTypeVector* PackedLinkVectorHelperBase::LinkedVector::operator->()
74 {
75  return get();
76 }
77 
78 
79 /**
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.
83  */
84 inline
85 auto PackedLinkVectorHelperBase::storeFromSpan ([[maybe_unused]] DataLinkBase_span& links)
86  -> IProxyDict*
87 {
88 #ifndef XAOD_STANDALONE
89  if (links.size() > 1) {
90  return links[1].source();
91  }
92 #endif
93  return CurrentEventStore::store();
94 }
95 
96 
97 /**
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.
101  */
102 inline
103 auto PackedLinkVectorHelperBase::getLinkBaseSpan (IAuxTypeVector& linkedVec)
104  -> DataLinkBase_span
105 {
106  return DataLinkBase_span (linkedVec.getDataSpan());
107 }
108 
109 
110 /**
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.
114  */
115 inline
116 auto PackedLinkVectorHelperBase::getLinkBaseSpan (const IAuxTypeVector& linkedVec)
117  -> const_DataLinkBase_span
118 {
119  return const_DataLinkBase_span (linkedVec.getDataSpan());
120 }
121 
122 
123 /**
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.
131  *
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
138  * to be invalid.)
139  */
140 template <class CONT>
141 inline
142 std::pair<size_t, bool> PackedLinkVectorHelper<CONT>::findCollection
143  (LinkedVector& linkedVec,
144  sgkey_t sgkey, DataLinkBase_span& links, IProxyDict* sg)
145 {
146  return findCollectionBase (linkedVec, sgkey, links, sg, initLink);
147 }
148 
149 
150 /**
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.
160  *
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
166  * to be invalid.)
167  */
168 template <class CONT>
169 inline
170 bool PackedLinkVectorHelper<CONT>::updateLinks (IAuxTypeVector& linkedVec,
171  SG::PackedLink<CONT>* ptr,
172  size_t n,
173  const const_DataLinkBase_span& srcDLinks,
174  IProxyDict* sg)
175 {
176  PackedLinkBase_span span (static_cast<PackedLinkBase*>(ptr), n);
177  return updateLinksBase (linkedVec, span, srcDLinks, sg, initLink);
178 }
179 
180 
181 /**
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.
191  *
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
197  * to be invalid.)
198  */
199 template <class CONT>
200 inline
201 bool PackedLinkVectorHelper<CONT>::updateLinks (IAuxTypeVector& linkedVec,
202  SG::PackedLink<CONT>* ptr,
203  size_t n,
204  const IAuxTypeVector& srclv,
205  IProxyDict* sg)
206 {
207  const_DataLinkBase_span srcDLinks = getLinkBaseSpan (srclv);
208  PackedLinkBase_span span (static_cast<PackedLinkBase*>(ptr), n);
209  return updateLinksBase (linkedVec, span, srcDLinks, sg, initLink);
210 }
211 
212 
213 /**
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.
223  *
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
229  * to be invalid.)
230  */
231 template <class CONT>
232 template <class VALLOC>
233 bool PackedLinkVectorHelper<CONT>::updateLinks (IAuxTypeVector& linkedVec,
234  std::vector<SG::PackedLink<CONT>, VALLOC>* ptr,
235  size_t n,
236  const IAuxTypeVector& srclv,
237  IProxyDict* sg)
238 {
239  const_DataLinkBase_span srcDLinks = getLinkBaseSpan (srclv);
240  if (sg == nullptr) {
241  DataLinkBase_span DLinks (getLinkBaseSpan (linkedVec));
242  sg = storeFromSpan (DLinks);
243  }
244  bool cacheValid = true;
245  for (size_t i = 0; i < n; i++) {
246  PackedLinkBase_span span (static_cast<PackedLinkBase*>(ptr[i].data()),
247  ptr[i].size());
248  cacheValid &= updateLinksBase (linkedVec, span, srcDLinks, sg, initLink);
249  }
250  return cacheValid;
251 }
252 
253 
254 /**
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.
260  *
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
263  * to be invalid.)
264  */
265 template <class CONT>
266 template <class VALLOC, ElementLinkRange<CONT> RANGE>
267 bool
268 PackedLinkVectorHelper<CONT>::assignVElt (std::vector<PLink_t, VALLOC>& velt,
269  IAuxTypeVector& linkedVec,
270  DataLinkBase_span& dlinks,
271  const RANGE& x)
272 {
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,
278  el.key(),
279  dlinks,
280  el.source());
281  cacheValid &= flag;
282  return PackedLink<CONT> (dlindex, el.isDefault() ? 0 : el.index());
283  };
284 
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));
288 #else
289  const auto r = x | std::views::transform (xform);
290  velt.assign (r.begin(), r.end());
291 #endif
292  return cacheValid;
293 }
294 
295 
296 /**
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.
303  *
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
306  * to be invalid.)
307  */
308 template <class CONT>
309 template <class VALLOC, ElementLinkRange<CONT> RANGE>
310 bool
311 PackedLinkVectorHelper<CONT>::insertVElt (std::vector<PLink_t, VALLOC>& velt,
312  size_t pos,
313  IAuxTypeVector& linkedVec,
314  DataLinkBase_span& dlinks,
315  const RANGE& x)
316 {
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,
322  el.key(),
323  dlinks,
324  el.source());
325  cacheValid &= flag;
326  return PackedLink<CONT> (dlindex, el.isDefault() ? 0 : el.index());
327  };
328 
329  // Make a transformed range and assign it to the vector.
330 #ifdef __cpp_lib_containers_ranges // c++23
331  velt.assign_range (velt.begin()+pos, x | std::views::transform (xform));
332 #else
333  const auto r = x | std::views::transform (xform);
334  velt.insert (velt.begin()+pos, r.begin(), r.end());
335 #endif
336  return cacheValid;
337 }
338 
339 
340 #ifndef XAOD_STANDALONE
341 /**
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.
351  *
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
354  * to be invalid.)
355  */
356 template <class CONT>
357 inline
358 bool
359 PackedLinkVectorHelper<CONT>::applyThinning (IAuxTypeVector& linkedVec,
360  PackedLink<CONT>* ptr,
361  size_t n,
362  DataLinkBase_span& dlinks,
363  const SG::ThinningCache* tc,
364  IProxyDict* sg)
365 {
366  PackedLinkBase_span lspan (static_cast<PackedLinkBase*>(ptr), n);
367  return applyThinningBase (linkedVec, lspan, dlinks, tc, sg, initLink);
368 }
369 #endif
370 
371 
372 /**
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.
378  */
379 template <class CONT>
380 inline
381 void PackedLinkVectorHelper<CONT>::initLink (DataLinkBase& dl,
382  sgkey_t sgkey,
383  [[maybe_unused]] IProxyDict* sg)
384 {
385 #ifdef XAOD_STANDALONE
386  dl.setPersKey (sgkey);
387 #else
388  static_cast<DLink_t&>(dl).toIdentifiedObject (sgkey, sg);
389 #endif
390 }
391 
392 
393 } // namespace SG::detail