ATLAS Offline Software
DataBucket.icc
Go to the documentation of this file.
1 ///////////////////////// -*- C++ -*- /////////////////////////////
2 
3 /*
4  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
5 */
6 
7 #include "AthenaKernel/IRegisterTransient.h"
8 #include "AthenaKernel/ClassID_traits.h"
9 #include "AthenaKernel/BaseInfo.h"
10 #include "AthenaKernel/ILockable.h"
11 #include "AthenaKernel/tools/safe_clid.h"
12 #include "CxxUtils/AthUnlikelyMacros.h"
13 #include "CxxUtils/checker_macros.h"
14 
15 #include <type_traits>
16 
17 
18 // Some helper functions.
19 namespace SG {
20 
21 
22 // If T is a DataObject, increment its reference count.
23 // The second parameter tells whether or not T is a DataObject.
24 template <class T>
25 void db_maybe_ref (T*, std::false_type)
26 {
27 }
28 template <class T>
29 void db_maybe_ref (T* ptr, std::true_type)
30 {
31  ptr->addRef();
32 }
33 
34 
35 // Release the pointer PTR.
36 // If T is a DataObject, then decrement the reference count;
37 // otherwise, just delete it.
38 // The second parameter tells whether or not T is a DataObject.
39 template <class T>
40 void db_free_ptr (T* ptr, std::false_type)
41 {
42  // std::cout << "db_free_ptr: deleting ptr @" << ptr << " of type " << ClassID_traits<T>::typeName() << std::endl;
43  delete ptr;
44 }
45 template <class T>
46 void db_free_ptr (T* ptr, std::true_type)
47 {
48  typedef typename std::remove_const<T>::type T_nc;
49  // std::cout << "db_free_ptr: releasing ptr @" << ptr << " of type " << ClassID_traits<T>::typeName() << std::endl;
50  const_cast<T_nc*>(ptr)->release();
51 }
52 
53 } // namespace SG
54 
55 
56 ///////////////////////////////////////////////////////////////////////////////
57 // CONSTRUCTORS
58 ///////////////////////////////////////////////////////////////////////////////
59 template <typename T>
60 SG::DataBucket<T>::DataBucket(T* data)
61  : m_ptr(data)
62 {
63  // If T is a DataObject, increase the refcount.
64  typedef typename ClassID_traits<T>::is_DataObject_tag tag;
65  if (m_ptr)
66  SG::db_maybe_ref (m_ptr, tag());
67 }
68 
69 template <typename T>
70 template <typename U>
71 // cppcheck-suppress uninitMemberVar ; false positive
72 SG::DataBucket<T>::DataBucket(std::unique_ptr<U> data)
73  // Rely on our caller to retain constness.
74  // cppcheck 2.12 puts the identifier used for the argument here in the
75  // wrong scope potentially causing problems later, so uglify it.
76  : DataBucket ([] (U* ptr_) { typedef typename std::remove_const<U>::type UNC;
77  UNC* tmp ATLAS_THREAD_SAFE = const_cast<UNC*> (ptr_);
78  return tmp; }
79  (data.release()))
80 {
81 }
82 
83 template <typename T>
84 SG::DataBucket<T>::DataBucket(SG::DataObjectSharedPtr<T> data)
85  : m_ptr(data.detach())
86 {
87 }
88 
89 ///////////////////////////////////////////////////////////////////////////////
90 // DATAOBJECT
91 ///////////////////////////////////////////////////////////////////////////////
92 template <typename T>
93 const CLID& SG::DataBucket<T>::clID() const {return classID();}
94 
95 template <typename T>
96 const CLID& SG::DataBucket<T>::classID() {
97  typedef typename std::remove_pointer<T>::type BareTp;
98  typedef typename std::remove_const<BareTp>::type BareT;
99  return ClassID_traits<BareT>::ID();
100 }
101 
102 
103 /**
104  * @brief Return the contents of the @c DataBucket,
105  * converted to type given by @a clid. Note that only
106  * derived->base conversions are allowed here.
107  * @param clid The class ID to which to convert.
108  * @param irt To be called if we make a new instance.
109  * @param isConst True if the object being converted is regarded as const.
110  */
111 template <typename T>
112 void*
113 SG::DataBucket<T>::cast (CLID clid,
114  IRegisterTransient* irt /*= 0*/,
115  bool isConst /*=true*/)
116 {
117  // First see if we're asking for class T.
118  if (ATH_LIKELY (clid == classID())) {
119  return m_ptr;
120  }
121 
122  // Then try a conversion using static SG_BASES information.
123  // This can all be unfolded at compile time, so is fast, but
124  // doesn't take into account SG_ADD_BASES.
125  void* ret = this->tryStaticConversion (clid);
126  if (ret) {
127  return ret;
128  }
129 
130  // Then try using BaseInfo, in case of SG_ADD_BASES.
131  ret = SG::BaseInfo<T>::cast (m_ptr, clid);
132  if (ret || !isConst)
133  return ret;
134 
135  // Is there a copy conversion available?
136  const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (clid);
137  if (cc) {
138  vec_t::iterator end = m_cnvcopies.end();
139  for (vec_t::iterator it = m_cnvcopies.begin(); it != end; ++it) {
140  if (cc == it->first) {
141  cc->convertUntyped (m_ptr, it->second);
142  return it->second;
143  }
144  }
145 
146  void* newcont = cc->create();
147  if (newcont) {
148  cc->convertUntyped (m_ptr, newcont);
149  m_cnvcopies.push_back (std::make_pair (cc, newcont));
150  irt->registerTransient (newcont);
151  }
152  return newcont;
153  }
154 
155  return 0;
156 }
157 
158 
159 /**
160  * @brief Return the contents of the @c DataBucket,
161  * converted to type given by @a std::type_info. Note that only
162  * derived->base conversions are allowed here.
163  * @param tinfo The @a std::type_info of the type to which to convert.
164  * @param irt To be called if we make a new instance.
165  * @param isConst True if the object being converted is regarded as const.
166  */
167 template <typename T>
168 void* SG::DataBucket<T>::cast (const std::type_info& tinfo,
169  IRegisterTransient* irt /*= 0*/,
170  bool isConst /*= true*/)
171 {
172  // First see if we're asking for class T.
173  if (ATH_LIKELY (tinfo == typeid(T))) {
174  return m_ptr;
175  }
176 
177  // Then try a conversion using static SG_BASES information.
178  // This can all be unfolded at compile time, so is fast, but
179  // doesn't take into account SG_ADD_BASES.
180  void* ret = this->tryStaticConversion (tinfo);
181  if (ret) {
182  return ret;
183  }
184 
185  // Then try using BaseInfo, in case of SG_ADD_BASES.
186  ret = SG::BaseInfo<T>::cast (m_ptr, tinfo);
187  if (ret || !isConst) {
188  return ret;
189  }
190 
191  // Is there a copy conversion available?
192  const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (tinfo);
193  if (cc) {
194  vec_t::iterator end = m_cnvcopies.end();
195  for (vec_t::iterator it = m_cnvcopies.begin(); it != end; ++it) {
196  if (cc == it->first) {
197  cc->convertUntyped (m_ptr, it->second);
198  return it->second;
199  }
200  }
201 
202  void* newcont = cc->create();
203  if (newcont) {
204  cc->convertUntyped (m_ptr, newcont);
205  m_cnvcopies.push_back (std::make_pair (cc, newcont));
206  irt->registerTransient (newcont);
207  }
208  return newcont;
209  }
210 
211  return 0;
212 }
213 
214 
215 /**
216  * @brief Return the contents of the @c DataBucket,
217  * converted to type given by @a clid. Note that only
218  * derived->base conversions are allowed here.
219  * @param clid The class ID to which to convert.
220  * @param tinfo The @a std::type_info of the type to which to convert.
221  * @param irt To be called if we make a new instance.
222  * @param isConst True if the object being converted is regarded as const.
223  *
224  * This allows the callee to choose whether to use clid or tinfo.
225  * Here we use clid.
226  */
227 template <typename T>
228 inline
229 void* SG::DataBucket<T>::cast (CLID clid,
230  const std::type_info& /*tinfo*/,
231  SG::IRegisterTransient* irt /*= 0*/,
232  bool isConst /*= true*/)
233 {
234  // Don't use virtual dispatch for this call.
235  return DataBucket::cast (clid, irt, isConst);
236 }
237 
238 
239 // The DataBucket destructor is put into an explicit namespace scope to get rid
240 // of a pesky warning from DPC++. Unfortunately Clang has an issue with the
241 // class name having a scope declaration on the destructor for some reason.
242 namespace SG {
243 
244 template <typename T>
245 DataBucket<T>::~DataBucket()
246 {
247  // Delete any copies.
248  vec_t::iterator end = m_cnvcopies.end();
249  for (vec_t::iterator it = m_cnvcopies.begin(); it != end; ++it) {
250  it->first->destroy (it->second);
251  }
252 
253  // Either delete m_ptr or decrement the refcount,
254  // depending on whether or not T is a DataObject.
255  typedef typename ClassID_traits<T>::is_DataObject_tag tag;
256  if (m_ptr)
257  SG::db_free_ptr(m_ptr, tag());
258 }
259 
260 } // namespace SG
261 
262 
263 namespace {
264 
265 
266 template <class T>
267 void call_lock (T* p, std::true_type)
268 {
269  typedef typename std::remove_const<T>::type T_nc;
270  ILockable* l = dynamic_cast<ILockable*> (const_cast<T_nc*>(p));
271  if (l) l->lock();
272 }
273 
274 
275 template <class T>
276 void call_lock (T*, std::false_type)
277 {
278 }
279 
280 
281 } // anonymous namespace
282 
283 
284 /**
285  * If the held object derives from @c ILockable, call @lock() on it.
286  */
287 template <class T>
288 void SG::DataBucket<T>::lock()
289 {
290  call_lock (m_ptr, typename std::is_polymorphic<T>::type());
291 }
292 
293 
294 /**
295  * @brief Try a conversion using static SG_BASES information.
296  * @param clid The class ID to which to convert.
297  *
298  * This can all be unfolded at compile time, so is fast, but
299  * doesn't take into account SG_ADD_BASES.
300  */
301 template <class T>
302 inline
303 void* SG::DataBucket<T>::tryStaticConversion (CLID clid)
304 {
305  auto tryconv = [&] (auto* p, bool /*is_virtual*/)
306  {
307  using base_t = typename std::remove_pointer_t<decltype(p)>;
308  if (clid == SG::safe_clid<base_t>()) {
309  return static_cast<void*> (static_cast<base_t*> (m_ptr));
310  }
311  return static_cast<void*> (nullptr);
312  };
313  return SG::Bases<T>::bases::foreach_ (tryconv);
314 }
315 
316 
317 /**
318  * @brief Try a conversion using static SG_BASES information.
319  * @param tinfo The @a std::type_info of the type to which to convert.
320  *
321  * This can all be unfolded at compile time, so is fast, but
322  * doesn't take into account SG_ADD_BASES.
323  */
324 template <class T>
325 inline
326 void* SG::DataBucket<T>::tryStaticConversion (const std::type_info& tinfo)
327 {
328  auto tryconv = [&] (auto* p, bool /*is_virtual*/)
329  {
330  using base_t = typename std::remove_pointer_t<decltype(p)>;
331  if (tinfo == typeid(base_t)) {
332  return static_cast<void*> (static_cast<base_t*> (m_ptr));
333  }
334  return static_cast<void*> (nullptr);
335  };
336  return SG::Bases<T>::bases::foreach_ (tryconv);
337 }