1///////////////////////// -*- C++ -*- /////////////////////////////
4 Copyright (C) 2002-2026 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/tools/safe_clid.h"
11#include "SGCore/ILockable.h"
12#include "CxxUtils/checker_macros.h"
18// Some helper functions.
22// If T is a DataObject, increment its reference count.
24requires (!std::derived_from<T, DataObject>)
30void db_maybe_ref (DataObject* ptr)
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.
41requires (!std::derived_from<T, DataObject>)
43void db_free_ptr (T* ptr)
48void db_free_ptr (const DataObject* ptr)
50 DataObject* ptr_nc ATLAS_THREAD_SAFE = const_cast<DataObject*>(ptr);
57///////////////////////////////////////////////////////////////////////////////
59///////////////////////////////////////////////////////////////////////////////
61SG::DataBucket<T>::DataBucket(T* data)
64 // If T is a DataObject, increase the refcount.
66 SG::db_maybe_ref (m_ptr);
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_);
83///////////////////////////////////////////////////////////////////////////////
85///////////////////////////////////////////////////////////////////////////////
87const CLID& SG::DataBucket<T>::clID() const { static const CLID cid = classID(); return cid; }
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();
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.
107SG::DataBucket<T>::cast (CLID clid,
108 IRegisterTransient* irt /*= 0*/,
109 bool isConst /*=true*/)
111 // First see if we're asking for class T.
112 if (clid == classID()) [[likely]] {
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);
124 // Then try using BaseInfo, in case of SG_ADD_BASES.
125 ret = SG::BaseInfo<T>::cast (m_ptr, clid);
129 // Is there a copy conversion available?
130 const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (clid);
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);
140 void* newcont = cc->create();
142 cc->convertUntyped (m_ptr, newcont);
143 m_cnvcopies.push_back (std::make_pair (cc, newcont));
144 irt->registerTransient (newcont);
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.
162void* SG::DataBucket<T>::cast (const std::type_info& tinfo,
163 IRegisterTransient* irt /*= 0*/,
164 bool isConst /*= true*/)
166 // First see if we're asking for class T.
167 if (tinfo == typeid(T)) [[likely]] {
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);
179 // Then try using BaseInfo, in case of SG_ADD_BASES.
180 ret = SG::BaseInfo<T>::cast (m_ptr, tinfo);
181 if (ret || !isConst) {
185 // Is there a copy conversion available?
186 const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (tinfo);
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);
196 void* newcont = cc->create();
198 cc->convertUntyped (m_ptr, newcont);
199 m_cnvcopies.push_back (std::make_pair (cc, newcont));
200 irt->registerTransient (newcont);
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.
218 * This allows the callee to choose whether to use clid or tinfo.
223void* SG::DataBucket<T>::cast (CLID clid,
224 const std::type_info& /*tinfo*/,
225 SG::IRegisterTransient* irt /*= 0*/,
226 bool isConst /*= true*/)
228 // Don't use virtual dispatch for this call.
229 return DataBucket::cast (clid, irt, isConst);
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.
239DataBucket<T>::~DataBucket()
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);
247 // Either delete m_ptr or decrement the refcount,
248 // depending on whether or not T is a DataObject.
250 SG::db_free_ptr(m_ptr);
260void call_lock (T* p, std::true_type)
262 typedef typename std::remove_const<T>::type T_nc;
263 ILockable* l = dynamic_cast<ILockable*> (const_cast<T_nc*>(p));
269void call_lock (T*, std::false_type)
274} // anonymous namespace
278 * If the held object derives from @c ILockable, call @lock() on it.
281void SG::DataBucket<T>::lock()
283 call_lock (m_ptr, typename std::is_polymorphic<T>::type());
288 * @brief Try a conversion using static SG_BASES information.
289 * @param clid The class ID to which to convert.
291 * This can all be unfolded at compile time, so is fast, but
292 * doesn't take into account SG_ADD_BASES.
296void* SG::DataBucket<T>::tryStaticConversion (CLID clid)
298 auto tryconv = [&] (auto* p, bool /*is_virtual*/)
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));
304 return static_cast<void*> (nullptr);
306 return SG::Bases<T>::bases::foreach_ (tryconv);
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.
314 * This can all be unfolded at compile time, so is fast, but
315 * doesn't take into account SG_ADD_BASES.
319void* SG::DataBucket<T>::tryStaticConversion (const std::type_info& tinfo)
321 auto tryconv = [&] (auto* p, bool /*is_virtual*/)
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));
327 return static_cast<void*> (nullptr);
329 return SG::Bases<T>::bases::foreach_ (tryconv);