ATLAS Offline Software
DVLInfo.icc
Go to the documentation of this file.
1 // This file's extension implies that it's C, but it's really -*- C++ -*-.
2 /*
3  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
4 */
5 /**
6  * @file AthContainers/tools/DVLInfo.icc
7  * @author scott snyder
8  * @date Mar, 2008
9  * @brief Holder to implement conversion copies for @c DataVector/@c DataList.
10  *
11  * Template and inline implementations.
12  */
13 
14 
15 #include "AthContainers/OwnershipPolicy.h"
16 #include "CxxUtils/checker_macros.h"
17 #include <vector>
18 #include <list>
19 #include <cassert>
20 #include <cstdlib>
21 
22 
23 #ifndef XAOD_STANDALONE
24 #include "AthenaKernel/BaseInfo.h"
25 #endif
26 
27 
28 namespace DataModel_detail {
29 
30 
31 /**
32  * @brief Helper function to do @c push_back on a container.
33  * @param cont The container.
34  * @param elt The element to push
35  *
36  * This specialization is for the case when the container holds pointers.
37  */
38 template <class CONTAINER, class ELT>
39 inline
40 void dvlPush (CONTAINER& cont, ELT* elt, const std::true_type&)
41 {
42  cont.push_back (elt);
43 }
44 
45 
46 /**
47  * @brief Helper function to do @c push_back on a container.
48  * @param cont The container.
49  * @param elt The element to push
50  *
51  * This specialization is for the case when the container does not
52  * hold pointers.
53  */
54 template <class CONTAINER, class ELT>
55 inline
56 void dvlPush (CONTAINER& cont, ELT* elt, const std::false_type&)
57 {
58  cont.push_back (*elt);
59 }
60 
61 
62 /**
63  * @brief Helper function to return a pointer from an iterator.
64  * @param it The iterator.
65  *
66  * This specialization is for the case when the container holds pointers.
67  */
68 template <class ITERATOR>
69 inline
70 const void* dvlGetPointer (ITERATOR& it, const std::true_type&)
71 {
72  return *it;
73 }
74 
75 
76 /**
77  * @brief Helper function to return a pointer from an iterator.
78  * @param it The iterator.
79  *
80  * This specialization is for the case when the container does not
81  * hold pointers.
82  */
83 template <class ITERATOR>
84 inline
85 const void* dvlGetPointer (ITERATOR& it, const std::false_type&)
86 {
87  return &*it;
88 }
89 
90 
91 /**
92  * @brief Helper for converting a container to @x AuxVectorBase.
93  */
94 template <class T>
95 SG::AuxVectorBase* dvlGetBase (T* p, const std::true_type&)
96 {
97  return p;
98 }
99 template <class T>
100 SG::AuxVectorBase* dvlGetBase (T*, const std::false_type&)
101 {
102  return 0;
103 }
104 
105 
106 /**
107  * @brief Return the @c type_info for the container.
108  */
109 inline
110 const std::type_info& DVLInfoBase::tinfo() const
111 {
112  return m_tinfo;
113 }
114 
115 
116 /**
117  * @brief Return the @c type_info for the container's element.
118  * (Pointer and const stripped.)
119  */
120 inline
121 const std::type_info& DVLInfoBase::elt_tinfo() const
122 {
123  return m_elt_tinfo;
124 }
125 
126 
127 /**
128  * @brief Constructor.
129  *
130  * Note: these objects should only be allocated statically.
131  */
132 template <class T>
133 DVLInfo<T>::DVLInfo()
134  : DVLInfoBase (typeid (Container), typeid (Elt))
135 {
136 #if !defined(XAOD_STANDALONE)
137  // Also make sure that the BaseInfo instance for this container has been
138  // created. If this container does not have a DATAVECTOR_BASE
139  // declaration, then it may not have been.
140  // See ATEAM-674.
141  SG::BaseInfo<T>::maybeInit();
142 #endif
143 }
144 
145 
146 /**
147  * @brief Construct a new container.
148  * @param nreserve Number of elements for which to reserve space.
149  * (Ignored if not appropriate.)
150  */
151 template <class T>
152 void* DVLInfo<T>::make (size_t nreserve) const
153 {
154  T* cont = 0;
155  dvl_makecontainer (nreserve, cont);
156  return cont;
157 }
158 
159 
160 /**
161  * @brief Push a new pointer into the container.
162  * @param cont_p Pointer to the container.
163  * @param elt_p Pointer to the element to push.
164  * (Must match the container's declared element type.)
165  */
166 template <class T>
167 void DVLInfo<T>::push (void* cont_p, void* elt_p) const
168 {
169  Container* cont = reinterpret_cast<Container*> (cont_p);
170  Elt* elt = reinterpret_cast<Elt*> (elt_p);
171  dvlPush (*cont, elt,
172  typename std::is_pointer<typename Container::value_type>::type());
173 }
174 
175 
176 /**
177  * @brief Return the size of the container.
178  * @param cont_p Pointer to the container.
179  */
180 template <class T>
181 size_t DVLInfo<T>::size (void* cont_p) const
182 {
183  Container* cont = reinterpret_cast<Container*> (cont_p);
184  return cont->size();
185 }
186 
187 
188 /**
189  * @brief Erase the elements in the container.
190  * @param cont_p Pointer to the container.
191  */
192 template <class T>
193 void DVLInfo<T>::clear (void* cont_p) const
194 {
195  Container* cont = reinterpret_cast<Container*> (cont_p);
196  cont->clear();
197 }
198 
199 
200 /**
201  * @brief Delete a container.
202  * @param cont_p Pointer to the container.
203  */
204 template <class T>
205 void DVLInfo<T>::del (void* cont_p) const
206 {
207  Container* cont = reinterpret_cast<Container*> (cont_p);
208  delete cont;
209 }
210 
211 
212 /**
213  * @brief Copy a container.
214  * @param cont_p Pointer to the container.
215  */
216 template <class T>
217 void* DVLInfo<T>::clone (void* cont_p) const
218 {
219  Container* cont = reinterpret_cast<Container*> (cont_p);
220  return new T (*cont);
221 }
222 
223 
224 /**
225  * @brief Helper to create the @c DVLInfo static instance.
226  *
227  * Calling this will create the @c DVLInfo static instance.
228  * This can be called from, for example, an initializer for
229  * a class static variable.
230  */
231 template <class T>
232 const std::type_info* DVLInfo<T>::initHelper()
233 {
234  static DVLInfo<T> inst;
235  return &inst.tinfo();
236 }
237 
238 
239 /**
240  * @brief Return a new iterator object.
241  * @param cont_p Pointer to the container.
242  */
243 template <class T>
244 DVLIteratorBase* DVLInfo<T>::iterator (const void* cont_p) const
245 {
246  const Container* cont = reinterpret_cast<const Container*> (cont_p);
247  return new DVLIterator<T> (cont->begin(), cont->end());
248 }
249 
250 
251 /**
252  * @brief Return a pointer to the container base.
253  * @param cont_p Pointer to the container.
254  */
255 template <class T>
256 SG::AuxVectorBase* DVLInfo<T>::base (void* cont_p) const
257 {
258  Container* cont = reinterpret_cast<Container*> (cont_p);
259  return DataModel_detail::dvlGetBase
260  (cont,
261  typename std::is_base_of<SG::AuxVectorBase,T>::type());
262 }
263 
264 
265 /**
266  * @brief Constructor.
267  * @param beg Start of the container.
268  * @param end End of the container.
269  */
270 template <class T>
271 DVLIterator<T>::DVLIterator (const base_iterator& beg,
272  const base_iterator& end)
273  : m_it (beg),
274  m_end (end)
275 {
276 }
277 
278 
279 /**
280  * @brief Return the next element from the container.
281  *
282  * This is the next pointer from the container (it's a pointer to the
283  * element itself, not a pointer to the pointer). It will be properly
284  * cast to the type described by elt_tinfo(). Null pointers are skipped;
285  * this function signals the end of iteration by returning 0.
286  */
287 template <class T>
288 const void* DVLIterator<T>::next()
289 {
290  const void* ret = 0;
291  while (ret == 0) {
292  if (m_it == m_end)
293  return 0;
294  ret = dvlGetPointer (m_it,
295  typename std::is_pointer<typename T::value_type>::type());
296  ++m_it;
297  }
298  return ret;
299 }
300 
301 
302 /**
303  * @brief Return container size in constant time, or 0.
304  * @param c The container.
305  *
306  * This will return the size of container @a c, if it is possible
307  * to do so in constant time. Otherwise, it returns 0.
308  */
309 template <class T>
310 inline
311 size_t dvl_size_const (const T& c)
312 {
313  return c.size();
314 }
315 
316 
317 /**
318  * @brief Return container size in constant time, or 0.
319  * @param c The container.
320  *
321  * This is a specialization for @c list; here we just return 0.
322  */
323 template <class T>
324 inline
325 size_t dvl_size_const (const std::list<T>& /*c*/)
326 {
327  return 0;
328 }
329 
330 
331 #if defined(XAOD_STANDALONE)
332 template <class T>
333 void* dvl_convert (const T& ,
334  const DVLInfoBase& )
335 {
336  // not implemented for standalone.
337  std::abort();
338 }
339 #else
340 /**
341  * @brief Perform @c DataVector/@c DataList conversion copying.
342  * @param src The source container.
343  * @param targ_info The @c DVLInfo for the target container type.
344  * @return The new container, or 0.
345  *
346  * If the elements of @a src can be converted to elements
347  * of a @a targ_tinfo container, then we make a new (view)
348  * container of that type and populate it with elements copied from @a src.
349  */
350 template <class T>
351 void* dvl_convert (const T& src,
352  const DVLInfoBase& targ_info)
353 {
354  // @a src's element type, with pointer and const removed.
355  typedef
356  typename std::remove_const<typename T::base_value_type>::type
357  Elt;
358 
359  // Fetch the cast function.
360  SG::BaseInfoBase::castfn_t* castfn =
361  SG::BaseInfo<Elt>::castfn (targ_info.elt_tinfo());
362  if (!castfn)
363  return 0;
364 
365  // Make the target container.
366  void* newcont = targ_info.make (dvl_size_const (src));
367 
368  // Copy the contents of the source to the target container,
369  // converting as we go.
370  typename T::const_iterator it = src.begin();
371  typename T::const_iterator end = src.end();
372  for (; it != end; ++it) {
373  Elt* elt ATLAS_THREAD_SAFE = const_cast<Elt*> (*it);
374  targ_info.push (newcont, castfn (elt));
375  }
376 
377  return newcont;
378 }
379 #endif
380 
381 
382 
383 /**
384  * @brief Perform @c DataVector/@c DataList conversion copying.
385  * @param src The source container.
386  * @param targ_tinfo @c type_info for the desired container type.
387  * @param targ_info[out] The @c DVLInfo for the target container type.
388  * @return The new container, or 0.
389  *
390  * If the elements of @a src can be converted to elements
391  * of a @a targ_tinfo container, then we make a new (view)
392  * container of that type and populate it with elements copied from @a src.
393  */
394 template <class T>
395 void* dvl_convert (const T& src,
396  const std::type_info& targ_tinfo,
397  DVLInfoBase*& targ_info)
398 {
399  // Look up the info for the target container.
400  targ_info = DVLInfoBase::find (targ_tinfo);
401  if (!targ_info)
402  return 0;
403 
404  return dvl_convert (src, *targ_info);
405 }
406 
407 
408 /**
409  * @brief Perform @c DataVector/@c DataList conversion copying.
410  * @param src The source container.
411  * @param clid CLID for the desired container type.
412  * @param targ_info[out] The @c DVLInfo for the target container type.
413  * @return The new container, or 0.
414  *
415  * If the elements of @a src can be converted to elements
416  * of a @a targ_tinfo container, then we make a new (view)
417  * container of that type and populate it with elements copied from @a src.
418  */
419 template <class T>
420 void* dvl_convert (const T& src,
421  CLID clid,
422  DVLInfoBase*& targ_info)
423 {
424  // Look up the info for the target container.
425  targ_info = DVLInfoBase::find (clid);
426  if (!targ_info)
427  return 0;
428 
429  return dvl_convert (src, *targ_info);
430 }
431 
432 
433 #if defined(XAOD_STANDALONE)
434 template <class T>
435 void dvl_update (const T&,
436  void* ,
437  const DVLInfoBase* )
438 {
439  // Not implemented for standalone.
440  std::abort();
441 }
442 #else
443 /**
444  * @brief Update the elements in the target container from the source.
445  * @param src The source container.
446  * @param target The target container.
447  * @param targ_info The @c DVLInfo for the target container type.
448  *
449  * The target container is cleared and then repopulated from the elements
450  * of the source container.
451  */
452 template <class T>
453 void dvl_update (const T& src,
454  void* target,
455  const DVLInfoBase* targ_info)
456 {
457  // @a src's element type, with pointer and const removed.
458  typedef
459  typename std::remove_const<typename T::base_value_type>::type
460  Elt;
461 
462  // Clear the target container.
463  targ_info->clear (target);
464 
465  // Fetch the cast function.
466  SG::BaseInfoBase::castfn_t* castfn =
467  SG::BaseInfo<Elt>::castfn (targ_info->elt_tinfo());
468  assert (castfn != 0);
469 
470  // Copy the contents of the source to the target container,
471  // converting as we go.
472  typename T::const_iterator it = src.begin();
473  typename T::const_iterator end = src.end();
474  for (; it != end; ++it) {
475  Elt* elt ATLAS_THREAD_SAFE = const_cast<Elt*> (*it);
476  targ_info->push (target, castfn (elt));
477  }
478 }
479 #endif
480 
481 
482 } // namespace DataModel_detail
483 
484 
485 /**
486  * @brief Construct a new container.
487  * @param nreserve Number of elements for which to reserve space.
488  * (Ignored if not appropriate.)
489  * @param cont[out] Pointer to the constructed container.
490  * (Returned via an argument to allow for template
491  * argument deduction.)
492  *
493  * This is broken out from the @c make method to allow specializing
494  * just this method. (Needs to be in the global namespace for proper
495  * resolution.)
496  */
497 template <class CONTAINER>
498 void dvl_makecontainer (size_t /*nreserve*/, CONTAINER*& cont)
499 {
500  cont = new CONTAINER;
501  std::abort();
502 }
503 
504 
505