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-2021 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  m_ti = testViewVector (*this->ptr(), m_clid);
98 }
99 
100 
101 /**
102  * @brief Copy constructor.
103  * @param other Bucket to copy.
104  */
105 template <typename T>
106 DVLDataBucket<T>::DVLDataBucket (const DVLDataBucket& other)
107  : SG::DataBucket<T> (new T (*(T*)(other.cptr()))),
108  m_copies (other.m_copies),
109  m_ti (other.m_ti),
110  m_clid (other.m_clid)
111 {
112  // Make a copy of each of the copies.
113  vec_t::iterator end = m_copies.end();
114  for (vec_t::iterator it = m_copies.begin(); it != end; ++it) {
115  it->second = it->first->clone (it->second);
116  }
117 }
118 
119 
120 /**
121  * @brief Destructor.
122  */
123 template <typename T>
124 DVLDataBucket<T>::~DVLDataBucket()
125 {
126  // Delete any copies.
127  vec_t::iterator end = m_copies.end();
128  for (vec_t::iterator it = m_copies.begin(); it != end; ++it) {
129  it->first->del (it->second);
130  }
131 }
132 
133 
134 /**
135  * @brief Return the contents of the @c DataBucket,
136  * converted to type given by @a clid. Note that only
137  * derived->base conversions are allowed here.
138  * @param clid The class ID to which to convert.
139  * @param irt To be called if we make a new instance.
140  * @param isConst True if the object being converted is regarded as const.
141  */
142 template <typename T>
143 void*
144 DVLDataBucket<T>::cast (CLID clid, IRegisterTransient* irt /*= 0*/,
145  bool /*isConst = true*/)
146 {
147  // Test for trivial conversion.
148  // FIXME: Assumes we can reinterpret_cast between DV* and ViewVector<DV>*.
149  if (ATH_LIKELY (clid == m_clid) || clid == DataBucket<T>::classID())
150  return this->ptr();
151 
152  // Try looking for a true base conversion,
153  // first using static SG_BASES information.
154  // This can all be unfolded at compile time, so is fast, but
155  // doesn't take into account SG_ADD_BASES.
156  void* ret = this->tryStaticConversion (clid);
157  if (ret) {
158  return ret;
159  }
160 
161  T* ptr = this->ptr();
162 
163  // Then try using BaseInfo, in case of SG_ADD_BASES.
164  ret = SG::BaseInfo<T>::cast (ptr, clid);
165  if (ret) {
166  return ret;
167  }
168 
169  // See if we've already made an instance for this type.
170  // We don't expect to have more than a few, so no point in doing
171  // anything more complicated than a linear search.
172  vec_t::iterator end = m_copies.end();
173  for (vec_t::iterator it = m_copies.begin(); it != end; ++it) {
174  if (clid == it->first->clid()) {
175  // Recopy the elements if the container size has changed.
176  if (it->first->size (it->second) != ptr->size()) {
177  dvl_update (*ptr, it->second, it->first);
178  }
179  return it->second;
180  }
181  }
182 
183  // Try to do a copying conversion.
184  DataModel_detail::DVLInfoBase* info;
185  void* newcont = dvl_convert (*ptr, clid, info);
186  if (newcont) {
187  m_copies.push_back (std::make_pair (info, newcont));
188  irt->registerTransient (newcont);
189  }
190 
191  return newcont;
192 }
193 
194 
195 /**
196  * @brief Return the contents of the @c DataBucket,
197  * converted to type given by @a std::type_info. Note that only
198  * derived->base conversions are allowed here.
199  * @param clid The @a std::type_info of the type to which to convert.
200  * @param irt To be called if we make a new instance.
201  * @param isConst True if the object being converted is regarded as const.
202  */
203 template <typename T>
204 void*
205 DVLDataBucket<T>::cast (const std::type_info& tinfo,
206  IRegisterTransient* irt /*= 0*/,
207  bool /*isConst = true*/)
208 {
209  // Test for trivial conversion.
210  // FIXME: Assumes we can reinterpret_cast between DV* and ViewVector<DV>*.
211  if (ATH_LIKELY (&tinfo == m_ti) || tinfo == DataBucket<T>::tinfo())
212  return this->ptr();
213 
214  // Try looking for a true base conversion,
215  // first using static SG_BASES information.
216  // This can all be unfolded at compile time, so is fast, but
217  // doesn't take into account SG_ADD_BASES.
218  void* ret = this->tryStaticConversion (tinfo);
219  if (ret) {
220  return ret;
221  }
222 
223  T* ptr = this->ptr();
224 
225  // Try looking for a true base conversion.
226  ret = SG::BaseInfo<T>::cast (ptr, tinfo);
227  if (ret) {
228  return ret;
229  }
230 
231  // See if we've already made an instance for this type.
232  // We don't expect to have more than a few, so no point in doing
233  // anything more complicated than a linear search.
234  vec_t::iterator end = m_copies.end();
235  for (vec_t::iterator it = m_copies.begin(); it != end; ++it) {
236  if (tinfo == it->first->tinfo()) {
237  // Recopy the elements if the container size has changed.
238  if (it->first->size (it->second) != ptr->size()) {
239  dvl_update (*ptr, it->second, it->first);
240  }
241  return it->second;
242  }
243  }
244 
245  // Try to do a copying conversion.
246  DataModel_detail::DVLInfoBase* info;
247  void* newcont = dvl_convert (*ptr, tinfo, info);
248  if (newcont) {
249  m_copies.push_back (std::make_pair (info, newcont));
250  irt->registerTransient (newcont);
251  }
252 
253  return newcont;
254 }
255 
256 
257 /**
258  * @brief Return the contents of the @c DataBucket,
259  * converted to type given by @a clid. Note that only
260  * derived->base conversions are allowed here.
261  * @param clid The class ID to which to convert.
262  * @param tinfo The @a std::type_info of the type to which to convert.
263  * @param irt To be called if we make a new instance.
264  * @param isConst True if the object being converted is regarded as const.
265  *
266  * This allows the callee to choose whether to use clid or tinfo.
267  * Here we use clid.
268  */
269 template <typename T>
270 inline
271 void* DVLDataBucket<T>::cast (CLID clid,
272  const std::type_info& /*tinfo*/,
273  SG::IRegisterTransient* irt /*= 0*/,
274  bool isConst /*= true*/)
275 {
276  return DVLDataBucket::cast (clid, irt, isConst);
277 }
278 
279 
280 /**
281  * @brief The CLID for the class of object we're holding.
282  *
283  * May be different from that of the base @c DataVector in the case
284  * of a @c ViewVector.
285  */
286 template <typename T>
287 const CLID& DVLDataBucket<T>::clID() const
288 {
289  return m_clid;
290 }
291 
292 
293 /**
294  * @brief The std::type_info for the class of object we're holding.
295  *
296  * May be different from that of the base @c DataVector in the case
297  * of a @c ViewVector.
298  */
299 template <typename T>
300 const std::type_info& DVLDataBucket<T>::tinfo() const
301 {
302  return *m_ti;
303 }
304 
305 
306 } // namespace SG