ATLAS Offline Software
Loading...
Searching...
No Matches
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
28namespace 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 */
38template <class CONTAINER, class ELT>
39inline
40void 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 */
54template <class CONTAINER, class ELT>
55inline
56void 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 */
68template <class ITERATOR>
69inline
70const 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 */
83template <class ITERATOR>
84inline
85const 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 */
94template <class T>
95SG::AuxVectorBase* dvlGetBase (T* p, const std::true_type&)
96{
97 return p;
98}
99template <class T>
100SG::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 */
109inline
110const 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 */
120inline
121const 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 */
132template <class T>
133DVLInfo<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 */
151template <class T>
152void* 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 */
166template <class T>
167void 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 */
180template <class T>
181size_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 */
192template <class T>
193void 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 */
204template <class T>
205void 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 */
216template <class T>
217void* 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 */
231template <class T>
232const 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 */
243template <class T>
244DVLIteratorBase* 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 */
255template <class T>
256SG::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 */
270template <class T>
271DVLIterator<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 */
287template <class T>
288const 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 */
309template <class T>
310inline
311size_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 */
323template <class T>
324inline
325size_t dvl_size_const (const std::list<T>& /*c*/)
326{
327 return 0;
328}
329
330
331#if defined(XAOD_STANDALONE)
332template <class T>
333void* 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 */
350template <class T>
351void* 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 */
394template <class T>
395void* 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 */
419template <class T>
420void* 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)
434template <class T>
435void 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 */
452template <class T>
453void 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 */
497template <class CONTAINER>
498void dvl_makecontainer (size_t /*nreserve*/, CONTAINER*& cont)
499{
500 cont = new CONTAINER;
501 std::abort();
502}
503
504
505