ATLAS Offline Software
Loading...
Searching...
No Matches
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/tools/safe_clid.h"
11#include "SGCore/ILockable.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.
20namespace SG {
21
22
23// If T is a DataObject, increment its reference count.
24template <class T>
25requires (!std::derived_from<T, DataObject>)
26inline
27void db_maybe_ref (T*)
28{
29}
30inline
31void 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.
41template <class T>
42requires (!std::derived_from<T, DataObject>)
43inline
44void db_free_ptr (T* ptr)
45{
46 delete ptr;
47}
48inline
49void 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///////////////////////////////////////////////////////////////////////////////
61template <typename T>
62SG::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
70template <typename T>
71template <typename U>
72SG::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///////////////////////////////////////////////////////////////////////////////
87template <typename T>
88const CLID& SG::DataBucket<T>::clID() const {return classID();}
89
90template <typename T>
91const 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 */
106template <typename T>
107void*
108SG::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 */
162template <typename T>
163void* 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 */
222template <typename T>
223inline
224void* 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.
237namespace SG {
238
239template <typename T>
240DataBucket<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
257namespace {
258
259
260template <class T>
261void 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
269template <class T>
270void 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 */
281template <class T>
282void 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 */
295template <class T>
296inline
297void* 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 */
318template <class T>
319inline
320void* 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}