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