ATLAS Offline Software
DVLDataBucket.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 /*
4  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
5 */
6 /**
7  * @file AthContainers/tools/DVLDataBucket.icc
8  * @author scott snyder
9  * @date Mar 2008
10  * @brief A @c DataBucket specialized for @c DataVector/@c DataList.
11  *
12  * Template and inline implementations.
13  */
14 
15 
16 #include "AthContainers/exceptions.h"
17 #include "AthenaKernel/IRegisterTransient.h"
18 #include "CxxUtils/AthUnlikelyMacros.h"
19 
20 
21 namespace SG {
22 
23 
24 /**
25  * @brief Is a @c DataVector we're trying to record actually a @c ViewVector?
26  * @param data Object being recorded.
27  * @param[out] clid If the object is a @c ViewVector, set to the CLID
28  * of that class. Otherwise unchanged.
29  * @returns The @c type_info for the object being recorded, either the
30  * @c DataVector or a @c ViewVector that derives from it.
31  */
32 template <class T>
33 const std::type_info* testViewVector (const DataVector<T>& data,
34  CLID& clid)
35 {
36  // If this is a view container, test for @c ViewVector.
37  if (data.ownPolicy() == SG::VIEW_ELEMENTS) {
38  // See if we actually have a @c ViewVector.
39  // FIXME: This doesn't work if @c ViewVector is templated on an intermediate
40  // class rather than @c DataVector directly.
41  if (dynamic_cast<const ViewVector<DataVector<T> >*> (&data)) {
42  const std::type_info& ti = typeid(ViewVector<DataVector<T> >);
43  const SG::BaseInfoBase* bib = SG::BaseInfoBase::find (ti);
44  if (bib) {
45  clid = bib->clid();
46  if (clid == CLID_NULL)
47  SG::throwExcMissingViewVectorCLID (ti);
48  return &ti;
49  }
50  else {
51  SG::throwExcMissingBaseInfo (ti);
52  }
53  }
54  }
55  return &typeid(DataVector<T>);
56 }
57 
58 
59 /**
60  * @brief Is a @c DataVector we're trying to record actually a @c ViewVector?
61  *
62  * Handle the case where the object being recorded is not a @c DataVector.
63  */
64 template <class T>
65 const std::type_info* testViewVector (const T& ,
66  CLID& )
67 {
68  return &typeid(T);
69 }
70 
71 
72 /**
73  * @brief Constructor from a payload object.
74  * @param data Object to hold in the bucket.
75  */
76 template <class T>
77 DVLDataBucket<T>::DVLDataBucket (T* data)
78  : DataBucket<T> (data)
79 {
80  // cppcheck-suppress useInitializationList
81  m_clid = DataBucket<T>::classID();
82  m_ti = testViewVector (*this->ptr(), m_clid);
83 }
84 
85 
86 /**
87  * @brief Constructor from a payload object.
88  * @param data Object to hold in the bucket.
89  */
90 template <class T>
91 template <class U>
92 DVLDataBucket<T>::DVLDataBucket (std::unique_ptr<U> data)
93  : DataBucket<T> (std::move (data))
94 {
95  // cppcheck-suppress useInitializationList
96  m_clid = DataBucket<T>::classID();
97  // cppcheck-suppress missingReturn; false positive
98  m_ti = testViewVector (*this->ptr(), m_clid);
99 }
100 
101 
102 /**
103  * @brief Copy constructor.
104  * @param other Bucket to copy.
105  */
106 template <typename T>
107 DVLDataBucket<T>::DVLDataBucket (const DVLDataBucket& other)
108  : SG::DataBucket<T> (new T (*(T*)(other.cptr()))),
109  m_copies (other.m_copies),
110  m_ti (other.m_ti),
111  m_clid (other.m_clid)
112 {
113  // Make a copy of each of the copies.
114  vec_t::iterator end = m_copies.end();
115  for (vec_t::iterator it = m_copies.begin(); it != end; ++it) {
116  it->second = it->first->clone (it->second);
117  }
118 }
119 
120 
121 /**
122  * @brief Destructor.
123  */
124 template <typename T>
125 DVLDataBucket<T>::~DVLDataBucket()
126 {
127  // Delete any copies.
128  vec_t::iterator end = m_copies.end();
129  for (vec_t::iterator it = m_copies.begin(); it != end; ++it) {
130  it->first->del (it->second);
131  }
132 }
133 
134 
135 /**
136  * @brief Return the contents of the @c DataBucket,
137  * converted to type given by @a clid. Note that only
138  * derived->base conversions are allowed here.
139  * @param clid The class ID to which to convert.
140  * @param irt To be called if we make a new instance.
141  * @param isConst True if the object being converted is regarded as const.
142  */
143 template <typename T>
144 void*
145 DVLDataBucket<T>::cast (CLID clid, IRegisterTransient* irt /*= 0*/,
146  bool /*isConst = true*/)
147 {
148  // Test for trivial conversion.
149  // FIXME: Assumes we can reinterpret_cast between DV* and ViewVector<DV>*.
150  if (ATH_LIKELY (clid == m_clid) || clid == DataBucket<T>::classID())
151  return this->ptr();
152 
153  // Try looking for a true base conversion,
154  // first using static SG_BASES information.
155  // This can all be unfolded at compile time, so is fast, but
156  // doesn't take into account SG_ADD_BASES.
157  void* ret = this->tryStaticConversion (clid);
158  if (ret) {
159  return ret;
160  }
161 
162  T* ptr = this->ptr();
163 
164  // Then try using BaseInfo, in case of SG_ADD_BASES.
165  ret = SG::BaseInfo<T>::cast (ptr, clid);
166  if (ret) {
167  return ret;
168  }
169 
170  // See if we've already made an instance for this type.
171  // We don't expect to have more than a few, so no point in doing
172  // anything more complicated than a linear search.
173  vec_t::iterator end = m_copies.end();
174  for (vec_t::iterator it = m_copies.begin(); it != end; ++it) {
175  if (clid == it->first->clid()) {
176  // Recopy the elements if the container size has changed.
177  if (it->first->size (it->second) != ptr->size()) {
178  dvl_update (*ptr, it->second, it->first);
179  }
180  return it->second;
181  }
182  }
183 
184  // Try to do a copying conversion.
185  DataModel_detail::DVLInfoBase* info;
186  void* newcont = dvl_convert (*ptr, clid, info);
187  if (newcont) {
188  m_copies.push_back (std::make_pair (info, newcont));
189  irt->registerTransient (newcont);
190  }
191 
192  return newcont;
193 }
194 
195 
196 /**
197  * @brief Return the contents of the @c DataBucket,
198  * converted to type given by @a std::type_info. Note that only
199  * derived->base conversions are allowed here.
200  * @param clid The @a std::type_info of the type to which to convert.
201  * @param irt To be called if we make a new instance.
202  * @param isConst True if the object being converted is regarded as const.
203  */
204 template <typename T>
205 void*
206 DVLDataBucket<T>::cast (const std::type_info& tinfo,
207  IRegisterTransient* irt /*= 0*/,
208  bool /*isConst = true*/)
209 {
210  // Test for trivial conversion.
211  // FIXME: Assumes we can reinterpret_cast between DV* and ViewVector<DV>*.
212  if (ATH_LIKELY (&tinfo == m_ti) || tinfo == DataBucket<T>::tinfo())
213  return this->ptr();
214 
215  // Try looking for a true base conversion,
216  // first using static SG_BASES information.
217  // This can all be unfolded at compile time, so is fast, but
218  // doesn't take into account SG_ADD_BASES.
219  void* ret = this->tryStaticConversion (tinfo);
220  if (ret) {
221  return ret;
222  }
223 
224  T* ptr = this->ptr();
225 
226  // Try looking for a true base conversion.
227  ret = SG::BaseInfo<T>::cast (ptr, tinfo);
228  if (ret) {
229  return ret;
230  }
231 
232  // See if we've already made an instance for this type.
233  // We don't expect to have more than a few, so no point in doing
234  // anything more complicated than a linear search.
235  vec_t::iterator end = m_copies.end();
236  for (vec_t::iterator it = m_copies.begin(); it != end; ++it) {
237  if (tinfo == it->first->tinfo()) {
238  // Recopy the elements if the container size has changed.
239  if (it->first->size (it->second) != ptr->size()) {
240  dvl_update (*ptr, it->second, it->first);
241  }
242  return it->second;
243  }
244  }
245 
246  // Try to do a copying conversion.
247  DataModel_detail::DVLInfoBase* info;
248  void* newcont = dvl_convert (*ptr, tinfo, info);
249  if (newcont) {
250  m_copies.push_back (std::make_pair (info, newcont));
251  irt->registerTransient (newcont);
252  }
253 
254  return newcont;
255 }
256 
257 
258 /**
259  * @brief Return the contents of the @c DataBucket,
260  * converted to type given by @a clid. Note that only
261  * derived->base conversions are allowed here.
262  * @param clid The class ID to which to convert.
263  * @param tinfo The @a std::type_info of the type to which to convert.
264  * @param irt To be called if we make a new instance.
265  * @param isConst True if the object being converted is regarded as const.
266  *
267  * This allows the callee to choose whether to use clid or tinfo.
268  * Here we use clid.
269  */
270 template <typename T>
271 inline
272 void* DVLDataBucket<T>::cast (CLID clid,
273  const std::type_info& /*tinfo*/,
274  SG::IRegisterTransient* irt /*= 0*/,
275  bool isConst /*= true*/)
276 {
277  return DVLDataBucket::cast (clid, irt, isConst);
278 }
279 
280 
281 /**
282  * @brief The CLID for the class of object we're holding.
283  *
284  * May be different from that of the base @c DataVector in the case
285  * of a @c ViewVector.
286  */
287 template <typename T>
288 const CLID& DVLDataBucket<T>::clID() const
289 {
290  return m_clid;
291 }
292 
293 
294 /**
295  * @brief The std::type_info for the class of object we're holding.
296  *
297  * May be different from that of the base @c DataVector in the case
298  * of a @c ViewVector.
299  */
300 template <typename T>
301 const std::type_info& DVLDataBucket<T>::tinfo() const
302 {
303  return *m_ti;
304 }
305 
306 
307 } // namespace SG