ATLAS Offline Software
AuxTypeVector.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/AuxTypeVector.icc
6  * @author scott snyder <snyder@bnl.gov>
7  * @date Sep, 2013
8  * @brief Implementation of @c IAuxTypeVector for specific types.
9  */
10 
11 
12 
13 
14 namespace SG {
15 
16 
17 /**
18  * @brief Constructor.
19  * @param auxid The auxid of the variable this vector represents.
20  * @param vecPtr Pointer to the object (of type @c CONT).
21  * @param ownFlag If true, take ownership of the object.
22  * @param isLinked True if this variable is linked from another one.
23  */
24 template <class T, class CONT>
25 inline
26 AuxTypeVectorHolder<T, CONT>::AuxTypeVectorHolder (auxid_t auxid,
27  vector_type* vecPtr,
28  bool ownFlag,
29  bool isLinked)
30  : IAuxTypeVector (auxid, isLinked),
31  m_vecPtr (vecPtr),
32  m_ownFlag (ownFlag)
33 {
34 }
35 
36 
37 /**
38  * @brief Destructor.
39  * If @c ownFlag was true, then delete the vector object.
40  */
41 template <class T, class CONT>
42 inline
43 AuxTypeVectorHolder<T, CONT>::~AuxTypeVectorHolder()
44 {
45  if (m_ownFlag)
46  delete m_vecPtr;
47 }
48 
49 
50 /**
51  * @brief Copy constructor.
52  * @param other Object to copy.
53  */
54 template <class T, class CONT>
55 AuxTypeVectorHolder<T, CONT>::AuxTypeVectorHolder
56  (const AuxTypeVectorHolder& other)
57  : IAuxTypeVector (other)
58 {
59  // If we own the payload, then make a copy, else just use the same pointer.
60  m_ownFlag = other.m_ownFlag;
61  if (other.m_ownFlag)
62  m_vecPtr = new vector_type (*other.m_vecPtr);
63  else
64  m_vecPtr = other.m_vecPtr;
65 }
66 
67 
68 /**
69  * @brief Move constructor.
70  * @param other Object to move.
71  */
72 template <class T, class CONT>
73 AuxTypeVectorHolder<T, CONT>::AuxTypeVectorHolder (AuxTypeVectorHolder&& other)
74  : IAuxTypeVector (other)
75 {
76  m_ownFlag = other.m_ownFlag;
77  m_vecPtr = other.m_vecPtr;
78  other.m_ownFlag = false;
79 }
80 
81 
82 /**
83  * @brief Assignment.
84  */
85 template <class T, class CONT>
86 AuxTypeVectorHolder<T, CONT>&
87 AuxTypeVectorHolder<T, CONT>::operator= (const AuxTypeVectorHolder& other)
88 {
89  if (this != &other) {
90  IAuxTypeVector::operator= (other);
91  if (m_ownFlag)
92  delete m_vecPtr;
93  m_ownFlag = other.m_ownFlag;
94  if (other.m_ownFlag)
95  m_vecPtr = new vector_type (*other.m_vecPtr);
96  else
97  m_vecPtr = other.m_vecPtr;
98  }
99  return *this;
100 }
101 
102 
103 /**
104  * @brief Move assignment.
105  */
106 template <class T, class CONT>
107 AuxTypeVectorHolder<T, CONT>&
108 AuxTypeVectorHolder<T, CONT>::operator= (AuxTypeVectorHolder&& other)
109 {
110  if (this != &other) {
111  IAuxTypeVector::operator= (other);
112  if (m_ownFlag)
113  delete m_vecPtr;
114  m_ownFlag = other.m_ownFlag;
115  m_vecPtr = other.m_vecPtr;
116  other.m_ownFlag = false;
117  }
118  return *this;
119 }
120 
121 
122 /**
123  * @brief Return a reference to the payload vector.
124  */
125 template <class T, class CONT>
126 inline
127 typename AuxTypeVectorHolder<T, CONT>::vector_type& AuxTypeVectorHolder<T, CONT>::vec()
128 {
129  return *m_vecPtr;
130 }
131 
132 
133 /**
134  * @brief Make a copy of this vector.
135  */
136 template <class T, class CONT>
137 inline
138 std::unique_ptr<IAuxTypeVector> AuxTypeVectorHolder<T, CONT>::clone() const
139 {
140  vector_type* vecPtr = new vector_type (*m_vecPtr);
141  return std::make_unique<AuxTypeVectorHolder<T, CONT> > (auxid(),
142  vecPtr,
143  true,
144  isLinked());
145 }
146 
147 
148 /**
149  * @brief Return a pointer to the start of the vector's data.
150  */
151 template <class T, class CONT>
152 inline
153 void* AuxTypeVectorHolder<T, CONT>::toPtr ()
154 {
155  if (m_vecPtr->empty())
156  return nullptr;
157  return m_vecPtr->data();
158 }
159 
160 
161 /**
162  * @brief Return a pointer to the start of the vector's data.
163  */
164 template <class T, class CONT>
165 inline
166 const void* AuxTypeVectorHolder<T, CONT>::toPtr () const
167 {
168  if (m_vecPtr->empty())
169  return nullptr;
170  return std::as_const (*m_vecPtr).data();
171 }
172 
173 
174 /**
175  * @brief Return a pointer to the STL vector itself.
176  */
177 template <class T, class CONT>
178 inline
179 void* AuxTypeVectorHolder<T, CONT>::toVector ()
180 {
181  return m_vecPtr;
182 }
183 
184 
185 /**
186  * @brief Return the type of the complete payload object.
187  *
188  * May be different from what we get from the registry; if packing
189  * is used, for example.
190  */
191 template <class T, class CONT>
192 inline
193 const std::type_info* AuxTypeVectorHolder<T, CONT>::objType() const
194 {
195  return &typeid(vector_type);
196 }
197 
198 
199 /**
200  * @brief Return the size of the vector.
201  */
202 template <class T, class CONT>
203 inline
204 size_t AuxTypeVectorHolder<T, CONT>::size () const
205 {
206  return m_vecPtr->size() / SCALE;
207 }
208 
209 
210 /**
211  * @brief Change the size of the vector.
212  * @param sz The new vector size.
213  * Returns true if it is known that iterators have not been invalidated;
214  * false otherwise. (Will always return false when increasing the size
215  * of an empty container.)
216  */
217 template <class T, class CONT>
218 inline
219 bool AuxTypeVectorHolder<T, CONT>::resize (size_t sz)
220 {
221  const void* orig = m_vecPtr->empty() ? nullptr : m_vecPtr->data();
222  m_vecPtr->resize (sz * SCALE,
223  Zero<typename AuxDataTraits<T>::element_type>::zero());
224  return m_vecPtr->data() == orig;
225 }
226 
227 
228 /**
229  * @brief Change the capacity of the vector.
230  * @param sz The new vector capacity.
231  */
232 template <class T, class CONT>
233 inline
234 void AuxTypeVectorHolder<T, CONT>::reserve (size_t sz)
235 {
236  m_vecPtr->reserve (sz * SCALE);
237 }
238 
239 
240 } // namespace SG
241 
242 
243 namespace DataModel_detail {
244 
245 
246 /// Make an option setting. VEC derives from @c IAuxSetOption.
247 template <class VEC>
248 bool setOptionHelper (VEC* vec, const SG::AuxDataOption& option, std::true_type)
249 {
250  SG::IAuxSetOption* setopt = static_cast<SG::IAuxSetOption*> (vec);
251  return setopt->setOption (option);
252 }
253 
254 
255 /// Make an option setting. VEC does not derive from @c IAuxSetOption,
256 /// so this just returns failure.
257 template <class VEC>
258 bool setOptionHelper (VEC* /*vec*/, const SG::AuxDataOption& /*option*/, std::false_type)
259 {
260  return false;
261 }
262 
263 
264 } // namespace DataModel_detail
265 
266 
267 namespace SG {
268 
269 
270 /**
271  * @brief Make an option setting.
272  * @param option The option to set.
273  *
274  * The interpretation of the option depends on the concrete class.
275  *
276  * Returns true if the option setting was successful; false otherwise.
277  */
278 template <class T, class CONT>
279 inline
280 bool AuxTypeVectorHolder<T, CONT>::setOption (const AuxDataOption& option)
281 {
282  // Need to instantiate different functions depending on whether or not
283  // the payload implements @c SG::IAuxSetOption.
284  return DataModel_detail::setOptionHelper
285  (m_vecPtr,
286  option,
287  typename std::is_base_of<SG::IAuxSetOption,vector_type>::type());
288 }
289 
290 
291 /**
292  * @brief Shift the elements of the vector.
293  * @param pos The starting index for the shift.
294  * @param offs The (signed) amount of the shift.
295  *
296  * This operation shifts the elements in the vectors for all
297  * aux data items, to implement an insertion or deletion.
298  * @c offs may be either positive or negative.
299  *
300  * If @c offs is positive, then the container is growing.
301  * The container size should be increased by @c offs,
302  * the element at @c pos moved to @c pos + @c offs,
303  * and similarly for following elements.
304  * The elements between @c pos and @c pos + @c offs should
305  * be default-initialized.
306  *
307  * If @c offs is negative, then the container is shrinking.
308  * The element at @c pos should be moved to @c pos + @c offs,
309  * and similarly for following elements.
310  * The container should then be shrunk by @c -offs elements
311  * (running destructors as appropriate).
312  *
313  * Returns true if it is known that iterators have not been invalidated;
314  * false otherwise. (Will always return false when increasing the size
315  * of an empty container.)
316  */
317 template <class T, class CONT>
318 bool AuxTypeVectorHolder<T, CONT>::shift (size_t pos, ptrdiff_t offs)
319 {
320  vector_type& vec = *m_vecPtr;
321  if (offs < 0) {
322  if (-offs > static_cast<ptrdiff_t>(pos)) offs = -pos;
323  std::copy (vec.begin() + pos*SCALE,
324  vec.end(),
325  vec.begin() + (pos+offs)*SCALE);
326  vec.resize (vec.size() + offs*SCALE);
327  return true;
328  }
329  else if (offs > 0) {
330  const void* orig = vec.data();
331  size_t oldsz = vec.size();
332  // Add to the end, zero-filled.
333  vec.resize (vec.size() + offs*SCALE,
334  Zero<typename AuxDataTraits<T>::element_type>::zero());
335  if (oldsz != pos) {
336  // Shift existing elements. If we're just extending,
337  // then we can skip this.
338  std::copy (vec.rbegin() + offs*SCALE,
339  vec.rbegin() + (offs+oldsz-pos)*SCALE,
340  vec.rbegin());
341  std::fill (vec.begin() + pos*SCALE,
342  vec.begin() + (pos+offs)*SCALE,
343  Zero<typename AuxDataTraits<T>::element_type>::zero());
344  }
345  return vec.data() == orig;
346  }
347  return true;
348 }
349 
350 
351 /**
352  * @brief Helper for @c insertMove.
353  * @param pos The starting index of the insertion.
354  * @param beg Start of the range of elements to insert.
355  * @param end End of the range of elements to insert.
356  *
357  * This does the actual move for POD types.
358  */
359 template <class T, class CONT>
360 void AuxTypeVectorHolder<T, CONT>::insertMove1
361  (typename CONT::iterator pos,
362  element_type* beg,
363  element_type* end,
364  std::true_type)
365 {
366  m_vecPtr->insert (pos, beg, end);
367 }
368 
369 
370 /**
371  * @brief Helper for @c insertMove.
372  * @param pos The starting index of the insertion.
373  * @param beg Start of the range of elements to insert.
374  * @param end End of the range of elements to insert.
375  *
376  * This does the actual move for non-POD types.
377  */
378 template <class T, class CONT>
379 void AuxTypeVectorHolder<T, CONT>::insertMove1
380  (typename CONT::iterator pos,
381  element_type* beg,
382  element_type* end,
383  std::false_type)
384 {
385  // std::vector doesn't provide a way to insert a range via move.
386  // So first make space, then move.
387  typename CONT::iterator pos2= m_vecPtr->insert (pos, end-beg, SG::Zero<element_type>::zero());
388  std::move (beg, end, pos2);
389 }
390 
391 
392 /**
393  * @brief Insert elements into the vector via move semantics.
394  * @param pos The starting index of the insertion.
395  * @param beg Start of the range of elements to insert.
396  * @param end End of the range of elements to insert.
397  * @param srcStore The source store.
398  *
399  * @c beg and @c end define a range of container elements, with length
400  * @c len defined by the difference of the pointers divided by the
401  * element size.
402  *
403  * The size of the container will be increased by @c len, with the elements
404  * starting at @c pos copied to @c pos+len.
405  *
406  * The contents of the @c beg:end range will then be moved to our vector
407  * starting at @c pos. This will be done via move semantics if possible;
408  * otherwise, it will be done with a copy.
409  *
410  * Returns true if it is known that the vector's memory did not move,
411  * false otherwise.
412  */
413 template <class T, class CONT>
414 bool AuxTypeVectorHolder<T, CONT>::insertMove (size_t pos, void* beg, void* end,
415  IAuxStore& /*srcStore*/)
416 {
417  const void* orig = m_vecPtr->data();
418  insertMove1 (m_vecPtr->begin() + pos*SCALE,
419  reinterpret_cast<element_type*> (beg),
420  reinterpret_cast<element_type*> (end),
421  typename std::conjunction<std::is_standard_layout<element_type>,
422  std::is_trivial<element_type> >::type());
423  return m_vecPtr->data() == orig;
424 }
425 
426 
427 } // namespace SG
428 
429 
430 namespace DataModel_detail {
431 
432 
433 /// Specialization for the case of types that can be packed.
434 template <class T, class ALLOC>
435 std::unique_ptr<SG::IAuxTypeVector> makePacked (SG::auxid_t auxid,
436  bool isLinked,
437  std::vector<T, ALLOC>& v,
438  std::true_type)
439 {
440  // Make the new container and move our contents.
441  auto iv =
442  std::make_unique<SG::AuxTypeVector<T, ALLOC, SG::PackedContainer<T, ALLOC> > > (auxid, 0, 0, isLinked);
443  iv->vec().swap (v);
444 #ifdef __COVERITY__
445  // Coverity gives a bogus complaint about the derived->base conversion here.
446  return std::unique_ptr<SG::IAuxTypeVector> (iv.release());
447 #else
448  return iv;
449 #endif
450 }
451 
452 
453 /// Specialization for the case of types that cannot be packed.
454 template <class T, class FLAG>
455 std::unique_ptr<SG::IAuxTypeVector> makePacked (SG::auxid_t, bool, T&, FLAG)
456 {
457  return nullptr;
458 }
459 
460 
461 /// Metafunction to determine if a @c vector<T> can be packed.
462 /// Arithmetic types can be packed, as can arbitrarily-nested vectors
463 /// of them, except that integers larger than 32 bits and long double
464 /// cannot be packed.
465 template <class T>
466 struct can_pack
467 {
468  typedef typename std::is_arithmetic<T>::type type;
469 };
470 template <>
471 struct can_pack<uint64_t>
472 {
473  typedef std::false_type type;
474 };
475 template <>
476 struct can_pack<int64_t>
477 {
478  typedef std::false_type type;
479 };
480 template <>
481 struct can_pack<long double>
482 {
483  typedef std::false_type type;
484 };
485 template <class T, class ALLOC>
486 struct can_pack<std::vector<T, ALLOC> >
487 {
488  typedef typename can_pack<T>::type type;
489 };
490 
491 
492 } // namespace DataModel_detail
493 
494 
495 namespace SG {
496 
497 
498 /**
499  * @brief Try to convert this aux vector to a @c PackedContainer.
500  *
501  * If successful, returns a newly-allocated @c IAuxTypeVector.
502  * In this case, the contents of the vector will have been moved
503  * to the new vector (and this object will be empty).
504  *
505  * Returns null on failure.
506  */
507 template <class T, class CONT>
508 std::unique_ptr<IAuxTypeVector> AuxTypeVectorHolder<T, CONT>::toPacked()
509 {
510  /// Use the proper instantiation depending on whether or not
511  /// this type can be packed.
512  return DataModel_detail::makePacked
513  (auxid(), isLinked(), *m_vecPtr, typename DataModel_detail::can_pack<T>::type());
514 }
515 
516 
517 //**********************************************************************
518 
519 
520 /**
521  * @brief Constructor. Makes a new vector.
522  * @param auxid The auxid of the variable this vector represents.
523  * @param size Initial size of the new vector.
524  * @param capacity Initial capacity of the new vector.
525  * @param isLinked True if this variable is linked from another one.
526  */
527 template <class HOLDER>
528 AuxTypeVectorT<HOLDER>::AuxTypeVectorT (auxid_t auxid,
529  size_t size,
530  size_t capacity,
531  bool isLinked)
532  : Base (auxid, &m_vec, false, isLinked)
533 {
534  m_vec.reserve (capacity * Base::SCALE);
535  m_vec.resize (size * Base::SCALE);
536 }
537 
538 
539 /**
540  * @brief Copy constructor.
541  */
542 template <class HOLDER>
543 AuxTypeVectorT<HOLDER>::AuxTypeVectorT (const AuxTypeVectorT& other)
544  : Base (other.auxid(), &m_vec, false, other.isLinked()),
545  m_vec (other.m_vec)
546 {
547 }
548 
549 
550 /**
551  * @brief Move constructor.
552  */
553 template <class HOLDER>
554 AuxTypeVectorT<HOLDER>::AuxTypeVectorT (AuxTypeVectorT&& other)
555  : Base (other.auxid(), &m_vec, false, other.isLinked()),
556  m_vec (std::move (other.m_vec))
557 {
558 }
559 
560 
561 /**
562  * @brief Assignment.
563  */
564 template <class HOLDER>
565 AuxTypeVectorT<HOLDER>&
566 AuxTypeVectorT<HOLDER>::operator= (const AuxTypeVectorT& other)
567 {
568  if (this != &other) {
569  Base::IAuxTypeVector::operator= (other);
570  m_vec = other.m_vec;
571  }
572  return *this;
573 }
574 
575 
576 /**
577  * @brief Move assignment.
578  */
579 template <class HOLDER>
580 AuxTypeVectorT<HOLDER>&
581 AuxTypeVectorT<HOLDER>::operator= (AuxTypeVectorT&& other)
582 {
583  if (this != &other) {
584  Base::IAuxTypeVector::operator= (other);
585  m_vec = std::move (other.m_vec);
586  }
587  return *this;
588 }
589 
590 
591 /**
592  * @brief Make a copy of this vector.
593  */
594 template <class HOLDER>
595 inline
596 std::unique_ptr<IAuxTypeVector> AuxTypeVectorT<HOLDER>::clone() const
597 {
598  return std::make_unique<AuxTypeVectorT> (*this);
599 }
600 
601 
602 } // namespace SG