1 ///////////////////////// -*- C++ -*- /////////////////////////////
4 Copyright (C) 2002-2023 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>
18 // Some helper functions.
22 // If T is a DataObject, increment its reference count.
23 // The second parameter tells whether or not T is a DataObject.
25 void db_maybe_ref (T*, std::false_type)
29 void db_maybe_ref (T* ptr, std::true_type)
35 // Release the pointer PTR.
36 // If T is a DataObject, then decrement the reference count;
37 // otherwise, just delete it.
38 // The second parameter tells whether or not T is a DataObject.
40 void db_free_ptr (T* ptr, std::false_type)
42 // std::cout << "db_free_ptr: deleting ptr @" << ptr << " of type " << ClassID_traits<T>::typeName() << std::endl;
46 void db_free_ptr (T* ptr, std::true_type)
48 typedef typename std::remove_const<T>::type T_nc;
49 // std::cout << "db_free_ptr: releasing ptr @" << ptr << " of type " << ClassID_traits<T>::typeName() << std::endl;
50 const_cast<T_nc*>(ptr)->release();
56 ///////////////////////////////////////////////////////////////////////////////
58 ///////////////////////////////////////////////////////////////////////////////
60 SG::DataBucket<T>::DataBucket(T* data)
63 // If T is a DataObject, increase the refcount.
64 typedef typename ClassID_traits<T>::is_DataObject_tag tag;
66 SG::db_maybe_ref (m_ptr, tag());
71 // cppcheck-suppress uninitMemberVar ; false positive
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 SG::DataBucket<T>::DataBucket(SG::DataObjectSharedPtr<T> data)
85 : m_ptr(data.detach())
89 ///////////////////////////////////////////////////////////////////////////////
91 ///////////////////////////////////////////////////////////////////////////////
93 const CLID& SG::DataBucket<T>::clID() const {return classID();}
96 const CLID& SG::DataBucket<T>::classID() {
97 typedef typename std::remove_pointer<T>::type BareTp;
98 typedef typename std::remove_const<BareTp>::type BareT;
99 return ClassID_traits<BareT>::ID();
104 * @brief Return the contents of the @c DataBucket,
105 * converted to type given by @a clid. Note that only
106 * derived->base conversions are allowed here.
107 * @param clid The class ID to which to convert.
108 * @param irt To be called if we make a new instance.
109 * @param isConst True if the object being converted is regarded as const.
111 template <typename T>
113 SG::DataBucket<T>::cast (CLID clid,
114 IRegisterTransient* irt /*= 0*/,
115 bool isConst /*=true*/)
117 // First see if we're asking for class T.
118 if (ATH_LIKELY (clid == classID())) {
122 // Then try a conversion using static SG_BASES information.
123 // This can all be unfolded at compile time, so is fast, but
124 // doesn't take into account SG_ADD_BASES.
125 void* ret = this->tryStaticConversion (clid);
130 // Then try using BaseInfo, in case of SG_ADD_BASES.
131 ret = SG::BaseInfo<T>::cast (m_ptr, clid);
135 // Is there a copy conversion available?
136 const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (clid);
138 vec_t::iterator end = m_cnvcopies.end();
139 for (vec_t::iterator it = m_cnvcopies.begin(); it != end; ++it) {
140 if (cc == it->first) {
141 cc->convertUntyped (m_ptr, it->second);
146 void* newcont = cc->create();
148 cc->convertUntyped (m_ptr, newcont);
149 m_cnvcopies.push_back (std::make_pair (cc, newcont));
150 irt->registerTransient (newcont);
160 * @brief Return the contents of the @c DataBucket,
161 * converted to type given by @a std::type_info. Note that only
162 * derived->base conversions are allowed here.
163 * @param tinfo The @a std::type_info of the type to which to convert.
164 * @param irt To be called if we make a new instance.
165 * @param isConst True if the object being converted is regarded as const.
167 template <typename T>
168 void* SG::DataBucket<T>::cast (const std::type_info& tinfo,
169 IRegisterTransient* irt /*= 0*/,
170 bool isConst /*= true*/)
172 // First see if we're asking for class T.
173 if (ATH_LIKELY (tinfo == typeid(T))) {
177 // Then try a conversion using static SG_BASES information.
178 // This can all be unfolded at compile time, so is fast, but
179 // doesn't take into account SG_ADD_BASES.
180 void* ret = this->tryStaticConversion (tinfo);
185 // Then try using BaseInfo, in case of SG_ADD_BASES.
186 ret = SG::BaseInfo<T>::cast (m_ptr, tinfo);
187 if (ret || !isConst) {
191 // Is there a copy conversion available?
192 const CopyConversionBase* cc = SG::BaseInfo<T>::baseinfo().copy_conversion (tinfo);
194 vec_t::iterator end = m_cnvcopies.end();
195 for (vec_t::iterator it = m_cnvcopies.begin(); it != end; ++it) {
196 if (cc == it->first) {
197 cc->convertUntyped (m_ptr, it->second);
202 void* newcont = cc->create();
204 cc->convertUntyped (m_ptr, newcont);
205 m_cnvcopies.push_back (std::make_pair (cc, newcont));
206 irt->registerTransient (newcont);
216 * @brief Return the contents of the @c DataBucket,
217 * converted to type given by @a clid. Note that only
218 * derived->base conversions are allowed here.
219 * @param clid The class ID to which to convert.
220 * @param tinfo The @a std::type_info of the type to which to convert.
221 * @param irt To be called if we make a new instance.
222 * @param isConst True if the object being converted is regarded as const.
224 * This allows the callee to choose whether to use clid or tinfo.
227 template <typename T>
229 void* SG::DataBucket<T>::cast (CLID clid,
230 const std::type_info& /*tinfo*/,
231 SG::IRegisterTransient* irt /*= 0*/,
232 bool isConst /*= true*/)
234 // Don't use virtual dispatch for this call.
235 return DataBucket::cast (clid, irt, isConst);
239 // The DataBucket destructor is put into an explicit namespace scope to get rid
240 // of a pesky warning from DPC++. Unfortunately Clang has an issue with the
241 // class name having a scope declaration on the destructor for some reason.
244 template <typename T>
245 DataBucket<T>::~DataBucket()
247 // Delete any copies.
248 vec_t::iterator end = m_cnvcopies.end();
249 for (vec_t::iterator it = m_cnvcopies.begin(); it != end; ++it) {
250 it->first->destroy (it->second);
253 // Either delete m_ptr or decrement the refcount,
254 // depending on whether or not T is a DataObject.
255 typedef typename ClassID_traits<T>::is_DataObject_tag tag;
257 SG::db_free_ptr(m_ptr, tag());
267 void call_lock (T* p, std::true_type)
269 typedef typename std::remove_const<T>::type T_nc;
270 ILockable* l = dynamic_cast<ILockable*> (const_cast<T_nc*>(p));
276 void call_lock (T*, std::false_type)
281 } // anonymous namespace
285 * If the held object derives from @c ILockable, call @lock() on it.
288 void SG::DataBucket<T>::lock()
290 call_lock (m_ptr, typename std::is_polymorphic<T>::type());
295 * @brief Try a conversion using static SG_BASES information.
296 * @param clid The class ID to which to convert.
298 * This can all be unfolded at compile time, so is fast, but
299 * doesn't take into account SG_ADD_BASES.
303 void* SG::DataBucket<T>::tryStaticConversion (CLID clid)
305 auto tryconv = [&] (auto* p, bool /*is_virtual*/)
307 using base_t = typename std::remove_pointer_t<decltype(p)>;
308 if (clid == SG::safe_clid<base_t>()) {
309 return static_cast<void*> (static_cast<base_t*> (m_ptr));
311 return static_cast<void*> (nullptr);
313 return SG::Bases<T>::bases::foreach_ (tryconv);
318 * @brief Try a conversion using static SG_BASES information.
319 * @param tinfo The @a std::type_info of the type to which to convert.
321 * This can all be unfolded at compile time, so is fast, but
322 * doesn't take into account SG_ADD_BASES.
326 void* SG::DataBucket<T>::tryStaticConversion (const std::type_info& tinfo)
328 auto tryconv = [&] (auto* p, bool /*is_virtual*/)
330 using base_t = typename std::remove_pointer_t<decltype(p)>;
331 if (tinfo == typeid(base_t)) {
332 return static_cast<void*> (static_cast<base_t*> (m_ptr));
334 return static_cast<void*> (nullptr);
336 return SG::Bases<T>::bases::foreach_ (tryconv);