1 // This file's extension implies that it's C, but it's really -*- C++ -*-.
3 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
6 * @file AthContainers/tools/DVLInfo.icc
9 * @brief Holder to implement conversion copies for @c DataVector/@c DataList.
11 * Template and inline implementations.
15 #include "AthContainers/OwnershipPolicy.h"
16 #include "CxxUtils/checker_macros.h"
23 #ifndef XAOD_STANDALONE
24 #include "AthenaKernel/BaseInfo.h"
28 namespace DataModel_detail {
32 * @brief Helper function to do @c push_back on a container.
33 * @param cont The container.
34 * @param elt The element to push
36 * This specialization is for the case when the container holds pointers.
38 template <class CONTAINER, class ELT>
40 void dvlPush (CONTAINER& cont, ELT* elt, const std::true_type&)
47 * @brief Helper function to do @c push_back on a container.
48 * @param cont The container.
49 * @param elt The element to push
51 * This specialization is for the case when the container does not
54 template <class CONTAINER, class ELT>
56 void dvlPush (CONTAINER& cont, ELT* elt, const std::false_type&)
58 cont.push_back (*elt);
63 * @brief Helper function to return a pointer from an iterator.
64 * @param it The iterator.
66 * This specialization is for the case when the container holds pointers.
68 template <class ITERATOR>
70 const void* dvlGetPointer (ITERATOR& it, const std::true_type&)
77 * @brief Helper function to return a pointer from an iterator.
78 * @param it The iterator.
80 * This specialization is for the case when the container does not
83 template <class ITERATOR>
85 const void* dvlGetPointer (ITERATOR& it, const std::false_type&)
92 * @brief Helper for converting a container to @x AuxVectorBase.
95 SG::AuxVectorBase* dvlGetBase (T* p, const std::true_type&)
100 SG::AuxVectorBase* dvlGetBase (T*, const std::false_type&)
107 * @brief Return the @c type_info for the container.
110 const std::type_info& DVLInfoBase::tinfo() const
117 * @brief Return the @c type_info for the container's element.
118 * (Pointer and const stripped.)
121 const std::type_info& DVLInfoBase::elt_tinfo() const
128 * @brief Constructor.
130 * Note: these objects should only be allocated statically.
133 DVLInfo<T>::DVLInfo()
134 : DVLInfoBase (typeid (Container), typeid (Elt))
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.
141 SG::BaseInfo<T>::maybeInit();
147 * @brief Construct a new container.
148 * @param nreserve Number of elements for which to reserve space.
149 * (Ignored if not appropriate.)
152 void* DVLInfo<T>::make (size_t nreserve) const
155 dvl_makecontainer (nreserve, cont);
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.)
167 void DVLInfo<T>::push (void* cont_p, void* elt_p) const
169 Container* cont = reinterpret_cast<Container*> (cont_p);
170 Elt* elt = reinterpret_cast<Elt*> (elt_p);
172 typename std::is_pointer<typename Container::value_type>::type());
177 * @brief Return the size of the container.
178 * @param cont_p Pointer to the container.
181 size_t DVLInfo<T>::size (void* cont_p) const
183 Container* cont = reinterpret_cast<Container*> (cont_p);
189 * @brief Erase the elements in the container.
190 * @param cont_p Pointer to the container.
193 void DVLInfo<T>::clear (void* cont_p) const
195 Container* cont = reinterpret_cast<Container*> (cont_p);
201 * @brief Delete a container.
202 * @param cont_p Pointer to the container.
205 void DVLInfo<T>::del (void* cont_p) const
207 Container* cont = reinterpret_cast<Container*> (cont_p);
213 * @brief Copy a container.
214 * @param cont_p Pointer to the container.
217 void* DVLInfo<T>::clone (void* cont_p) const
219 Container* cont = reinterpret_cast<Container*> (cont_p);
220 return new T (*cont);
225 * @brief Helper to create the @c DVLInfo static instance.
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.
232 const std::type_info* DVLInfo<T>::initHelper()
234 static DVLInfo<T> inst;
235 return &inst.tinfo();
240 * @brief Return a new iterator object.
241 * @param cont_p Pointer to the container.
244 DVLIteratorBase* DVLInfo<T>::iterator (const void* cont_p) const
246 const Container* cont = reinterpret_cast<const Container*> (cont_p);
247 return new DVLIterator<T> (cont->begin(), cont->end());
252 * @brief Return a pointer to the container base.
253 * @param cont_p Pointer to the container.
256 SG::AuxVectorBase* DVLInfo<T>::base (void* cont_p) const
258 Container* cont = reinterpret_cast<Container*> (cont_p);
259 return DataModel_detail::dvlGetBase
261 typename std::is_base_of<SG::AuxVectorBase,T>::type());
266 * @brief Constructor.
267 * @param beg Start of the container.
268 * @param end End of the container.
271 DVLIterator<T>::DVLIterator (const base_iterator& beg,
272 const base_iterator& end)
280 * @brief Return the next element from the container.
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.
288 const void* DVLIterator<T>::next()
294 ret = dvlGetPointer (m_it,
295 typename std::is_pointer<typename T::value_type>::type());
303 * @brief Return container size in constant time, or 0.
304 * @param c The container.
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.
311 size_t dvl_size_const (const T& c)
318 * @brief Return container size in constant time, or 0.
319 * @param c The container.
321 * This is a specialization for @c list; here we just return 0.
325 size_t dvl_size_const (const std::list<T>& /*c*/)
331 #if defined(XAOD_STANDALONE)
333 void* dvl_convert (const T& ,
336 // not implemented for standalone.
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.
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.
351 void* dvl_convert (const T& src,
352 const DVLInfoBase& targ_info)
354 // @a src's element type, with pointer and const removed.
356 typename std::remove_const<typename T::base_value_type>::type
359 // Fetch the cast function.
360 SG::BaseInfoBase::castfn_t* castfn =
361 SG::BaseInfo<Elt>::castfn (targ_info.elt_tinfo());
365 // Make the target container.
366 void* newcont = targ_info.make (dvl_size_const (src));
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));
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.
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.
395 void* dvl_convert (const T& src,
396 const std::type_info& targ_tinfo,
397 DVLInfoBase*& targ_info)
399 // Look up the info for the target container.
400 targ_info = DVLInfoBase::find (targ_tinfo);
404 return dvl_convert (src, *targ_info);
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.
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.
420 void* dvl_convert (const T& src,
422 DVLInfoBase*& targ_info)
424 // Look up the info for the target container.
425 targ_info = DVLInfoBase::find (clid);
429 return dvl_convert (src, *targ_info);
433 #if defined(XAOD_STANDALONE)
435 void dvl_update (const T&,
439 // Not implemented for standalone.
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.
449 * The target container is cleared and then repopulated from the elements
450 * of the source container.
453 void dvl_update (const T& src,
455 const DVLInfoBase* targ_info)
457 // @a src's element type, with pointer and const removed.
459 typename std::remove_const<typename T::base_value_type>::type
462 // Clear the target container.
463 targ_info->clear (target);
465 // Fetch the cast function.
466 SG::BaseInfoBase::castfn_t* castfn =
467 SG::BaseInfo<Elt>::castfn (targ_info->elt_tinfo());
468 assert (castfn != 0);
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));
482 } // namespace DataModel_detail
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.)
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
497 template <class CONTAINER>
498 void dvl_makecontainer (size_t /*nreserve*/, CONTAINER*& cont)
500 cont = new CONTAINER;