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