1 ///////////////////////// -*- C++ -*- /////////////////////////////
4 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
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"
15 #include <type_traits>
19 // Some helper functions.
23 // If T is a DataObject, increment its reference count.
25 requires (!std::derived_from<T, DataObject>)
27 void db_maybe_ref (T*)
31 void db_maybe_ref (DataObject* ptr)
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.
42 requires (!std::derived_from<T, DataObject>)
44 void db_free_ptr (T* ptr)
49 void db_free_ptr (const DataObject* ptr)
51 DataObject* ptr_nc ATLAS_THREAD_SAFE = const_cast<DataObject*>(ptr);
58 ///////////////////////////////////////////////////////////////////////////////
60 ///////////////////////////////////////////////////////////////////////////////
62 SG::DataBucket<T>::DataBucket(T* data)
65 // If T is a DataObject, increase the refcount.
67 SG::db_maybe_ref (m_ptr);
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_);
84 ///////////////////////////////////////////////////////////////////////////////
86 ///////////////////////////////////////////////////////////////////////////////
88 const CLID& SG::DataBucket<T>::clID() const {return classID();}
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();
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.
106 template <typename T>
108 SG::DataBucket<T>::cast (CLID clid,
109 IRegisterTransient* irt /*= 0*/,
110 bool isConst /*=true*/)
112 // First see if we're asking for class T.
113 if (ATH_LIKELY (clid == classID())) {
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);
125 // Then try using BaseInfo, in case of SG_ADD_BASES.
126 ret = SG::BaseInfo<T>::cast (m_ptr, clid);
130 // Is there a copy conversion available?
131 const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (clid);
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);
141 void* newcont = cc->create();
143 cc->convertUntyped (m_ptr, newcont);
144 m_cnvcopies.push_back (std::make_pair (cc, newcont));
145 irt->registerTransient (newcont);
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.
162 template <typename T>
163 void* SG::DataBucket<T>::cast (const std::type_info& tinfo,
164 IRegisterTransient* irt /*= 0*/,
165 bool isConst /*= true*/)
167 // First see if we're asking for class T.
168 if (ATH_LIKELY (tinfo == typeid(T))) {
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);
180 // Then try using BaseInfo, in case of SG_ADD_BASES.
181 ret = SG::BaseInfo<T>::cast (m_ptr, tinfo);
182 if (ret || !isConst) {
186 // Is there a copy conversion available?
187 const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (tinfo);
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);
197 void* newcont = cc->create();
199 cc->convertUntyped (m_ptr, newcont);
200 m_cnvcopies.push_back (std::make_pair (cc, newcont));
201 irt->registerTransient (newcont);
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.
219 * This allows the callee to choose whether to use clid or tinfo.
222 template <typename T>
224 void* SG::DataBucket<T>::cast (CLID clid,
225 const std::type_info& /*tinfo*/,
226 SG::IRegisterTransient* irt /*= 0*/,
227 bool isConst /*= true*/)
229 // Don't use virtual dispatch for this call.
230 return DataBucket::cast (clid, irt, isConst);
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.
239 template <typename T>
240 DataBucket<T>::~DataBucket()
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);
248 // Either delete m_ptr or decrement the refcount,
249 // depending on whether or not T is a DataObject.
251 SG::db_free_ptr(m_ptr);
261 void call_lock (T* p, std::true_type)
263 typedef typename std::remove_const<T>::type T_nc;
264 ILockable* l = dynamic_cast<ILockable*> (const_cast<T_nc*>(p));
270 void call_lock (T*, std::false_type)
275 } // anonymous namespace
279 * If the held object derives from @c ILockable, call @lock() on it.
282 void SG::DataBucket<T>::lock()
284 call_lock (m_ptr, typename std::is_polymorphic<T>::type());
289 * @brief Try a conversion using static SG_BASES information.
290 * @param clid The class ID to which to convert.
292 * This can all be unfolded at compile time, so is fast, but
293 * doesn't take into account SG_ADD_BASES.
297 void* SG::DataBucket<T>::tryStaticConversion (CLID clid)
299 auto tryconv = [&] (auto* p, bool /*is_virtual*/)
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));
305 return static_cast<void*> (nullptr);
307 return SG::Bases<T>::bases::foreach_ (tryconv);
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.
315 * This can all be unfolded at compile time, so is fast, but
316 * doesn't take into account SG_ADD_BASES.
320 void* SG::DataBucket<T>::tryStaticConversion (const std::type_info& tinfo)
322 auto tryconv = [&] (auto* p, bool /*is_virtual*/)
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));
328 return static_cast<void*> (nullptr);
330 return SG::Bases<T>::bases::foreach_ (tryconv);