ATLAS Offline Software
StoreGate/StoreGate/WriteDecorHandle.icc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
3  */
4 /**
5  * @file StoreGate/WriteDecorHandle.icc
6  * @author scott snyder <snyder@bnl.gov>
7  * @date Apr, 2017
8  * @brief Handle class for adding a decoration to an object.
9  */
10 
11 
12 #include "CxxUtils/checker_macros.h"
13 #include "StoreGate/exceptions.h"
14 
15 
16 namespace SG {
17 
18 
19 /**
20  * @brief Constructor from a WriteDecorHandleKey.
21  * @param key The key object holding the clid/key/store/attr.
22  *
23  * This will raise an exception if the StoreGate key is blank,
24  * or if the event store cannot be found.
25  */
26 template <class T, class D>
27 WriteDecorHandle<T, D>::WriteDecorHandle (const WriteDecorHandleKey<T>& key)
28  : Base (key.contHandleKey(), nullptr),
29  m_decorKey (key.key()),
30  m_acc (SG::decorKeyFromKey (key.key())),
31  m_renounced (key.renounced()),
32  m_decorated (false)
33 {
34 }
35 
36 
37 /**
38  * @brief Constructor from a ReadDecorHandleKey and an explicit event context.
39  * @param key The key object holding the clid/key.
40  * @param ctx The event context.
41  *
42  * This will raise an exception if the StoreGate key is blank,
43  * or if the event store cannot be found.
44  *
45  * If the default event store has been requested, then the thread-specific
46  * store from the event context will be used.
47  */
48 template <class T, class D>
49 WriteDecorHandle<T, D>::WriteDecorHandle (const WriteDecorHandleKey<T>& key,
50  const EventContext& ctx)
51  : Base (key.contHandleKey(), &ctx),
52  m_decorKey (key.key()),
53  m_acc (SG::decorKeyFromKey (key.key())),
54  m_renounced (key.renounced()),
55  m_decorated (false)
56 {
57 }
58 
59 
60 /**
61  * @brief Copy constructor.
62  */
63 template <class T, class D>
64 WriteDecorHandle<T, D>::WriteDecorHandle (const WriteDecorHandle& rhs)
65  : Base (rhs),
66  m_decorKey (rhs.m_decorKey),
67  m_acc (rhs.m_acc),
68  m_renounced (rhs.m_renounced),
69  m_decorated (rhs.m_decorated)
70 {
71 }
72 
73 
74 /**
75  * @brief Move constructor.
76  */
77 template <class T, class D>
78 WriteDecorHandle<T, D>::WriteDecorHandle (WriteDecorHandle&& rhs)
79  : Base (std::move (rhs)),
80  m_decorKey (std::move (rhs.m_decorKey)),
81  m_acc (std::move (rhs.m_acc)),
82  m_renounced (rhs.m_renounced),
83  m_decorated (rhs.m_decorated)
84 {
85  rhs.m_decorated = false;
86 }
87 
88 
89 /**
90  * @brief Destructor. This will lock the decoration.
91  */
92 template <class T, class D>
93 WriteDecorHandle<T, D>::~WriteDecorHandle()
94 {
95  // Lock the decoration. But don't do anything if we haven't touched it.
96  if (m_decorated) {
97  const IConstAuxStore* store = this->vectorData()->getConstStore();
98  if (store) {
99  // Lock the decoration and clear its entry in the cache.
100  // Casting away const should be ok because no other thread should
101  // be looking at this decoration yet.
102  auto avd_nc ATLAS_THREAD_SAFE = const_cast<SG::AuxVectorData*> (this->vectorData());
103  avd_nc->lockDecoration (auxid());
104  }
105  }
106 }
107 
108 
109 /**
110  * @brief Assignment operator.
111  */
112 template <class T, class D>
113 WriteDecorHandle<T, D>& WriteDecorHandle<T, D>::operator= (const WriteDecorHandle& rhs)
114 {
115  if (this != &rhs) {
116  *static_cast<Base*>(this) = rhs;
117  m_acc = rhs.m_acc;
118  m_decorKey = rhs.m_decorKey;
119  m_renounced = rhs.m_renounced;
120  m_decorated = rhs.m_decorated;
121  }
122  return *this;
123 }
124 
125 
126 /**
127  * @brief Move operator.
128  */
129 template <class T, class D>
130 WriteDecorHandle<T, D>& WriteDecorHandle<T, D>::operator= (WriteDecorHandle&& rhs)
131 {
132  if (this != &rhs) {
133  *static_cast<Base*>(this) = std::move (rhs);
134  m_acc = std::move (rhs.m_acc);
135  m_decorKey = std::move (rhs.m_decorKey);
136  m_renounced = rhs.m_renounced;
137  m_decorated = rhs.m_decorated;
138  rhs.m_decorated = false;
139  }
140  return *this;
141 }
142 
143 
144 /**
145  * @brief Is the referenced container present in SG?
146  *
147  * Note that this tests for the presence of the _container_,
148  * not for the decoration.
149  *
150  * Const method; the handle does not change as a result of this.
151  */
152 template <class T, class D>
153 bool WriteDecorHandle<T, D>::isPresent() const
154 {
155  return Base::isPresent();
156 }
157 
158 
159 /**
160  * @brief Explicitly set the event store.
161  * @param store The new event store.
162  *
163  * This implicitly does a reset().
164  *
165  * We need to override this so that the setting gets made on the container
166  * handle as well.
167  */
168 template <class T, class D>
169 StatusCode WriteDecorHandle<T, D>::setProxyDict (IProxyDict* store)
170 {
171  m_decorated = false;
172  return Base::setProxyDict (store);
173 }
174 
175 
176 /**
177  * @brief Fetch the variable for one element, as a reference.
178  * @param e The element for which to fetch the variable.
179  */
180 template <class T, class D>
181 typename WriteDecorHandle<T, D>::reference_type
182 WriteDecorHandle<T, D>::operator() (const AuxElement& e)
183 {
184  // Ensure that the element we're given is actually an element
185  // of the container we're writing.
186  if (e.container() != this->vectorData()) {
187  if (!m_renounced) {
188  throwExcBadDecorElement (Gaudi::DataHandle::Writer,
189  this->clid(),
190  this->m_decorKey);
191  }
192  }
193  else if (!m_decorated) {
194  makeDecor (e.container());
195  }
196  return m_acc (e);
197 }
198 
199 
200 /**
201  * @brief Fetch the variable for one element, as a reference.
202  * @param index The index of the desired element.
203  *
204  * This looks up the variable in the object referenced by this handle.
205  * For a standalone object, pass an index of 0.
206  */
207 template <class T, class D>
208 typename WriteDecorHandle<T, D>::reference_type
209 WriteDecorHandle<T, D>::operator() (size_t i)
210 {
211  const AuxVectorData* avd = this->vectorData();
212  if (!m_decorated) makeDecor (avd);
213  return m_acc (*avd, i);
214 }
215 
216 
217 /**
218  * @brief Get a pointer to the start of the auxiliary data array,
219  * for the referenced object.
220  */
221 template <class T, class D>
222 template <class POINTER_TYPE /*= container_pointer_type*/,
223  typename /*= std::enable_if_t<!std::is_void_v<POINTER_TYPE> >*/ >
224 POINTER_TYPE
225 WriteDecorHandle<T, D>::getDecorationArray()
226 {
227  const AuxVectorData* avd = this->vectorData();
228  if (!m_decorated) makeDecor (avd);
229  return m_acc.getDecorationArray (*avd);
230 }
231 
232 
233 /**
234  * @brief Get a span over the auxilary data array,
235  * for the referenced object.
236  */
237 template <class T, class D>
238 auto
239 WriteDecorHandle<T, D>::getDecorationSpan() -> span
240 {
241  const AuxVectorData* avd = this->vectorData();
242  if (!m_decorated) makeDecor (avd);
243  return m_acc.getDecorationSpan (*avd);
244 }
245 
246 
247 /**
248  * @brief Test to see if this variable exists in the store,
249  * for the referenced object.
250  */
251 template <class T, class D>
252 inline
253 bool WriteDecorHandle<T, D>::isAvailable()
254 {
255  return vectorData()->isAvailable (m_acc.auxid());
256 }
257 
258 
259 /**
260  * @brief Return the aux id for this variable.
261  */
262 template <class T, class D>
263 SG::auxid_t WriteDecorHandle<T, D>::auxid() const
264 {
265  return m_acc.auxid();
266 }
267 
268 
269 /**
270  * @brief Return the mode (read/write/update) for this handle.
271  */
272 template <class T, class D>
273 inline
274 Gaudi::DataHandle::Mode WriteDecorHandle<T, D>::mode() const
275 {
276  return Gaudi::DataHandle::Writer;
277 }
278 
279 
280 /**
281  * @brief Return the name of the decoration alias (CONT.DECOR).
282  */
283 template <class T, class D>
284 inline
285 const std::string& WriteDecorHandle<T, D>::decorKey() const
286 {
287  return m_decorKey;
288 }
289 
290 
291 /**
292  * @brief Create the decoration if it doesn't actually exist yet.
293  * Also create the decoration alias in SG (unless this handle
294  * has been renounced).
295  * @param avd The AuxVectorData instance we're decorating.
296  * (May not be the same as this->vectorData() if the
297  * handle has been renounced.)
298  */
299 template <class T, class D>
300 void WriteDecorHandle<T, D>::makeDecor (const AuxVectorData* avd)
301 {
302  if (!avd) return;
303  if (avd->size_v() > 0) {
304  m_acc.getDecorationSpan (*avd);
305  }
306  if (!m_renounced) {
307  this->alias (WriteHandleKey<T> (this->m_decorKey)).ignore();
308  }
309  m_decorated = true;
310 }
311 
312 
313 /**
314  * @brief Return the referenced object as a @c SG::AuxVectorData.
315  * Specialization for the case of a standalone object
316  * (@c T derives from @c SG::AuxElement).
317  */
318 template <class T, class D>
319 const SG::AuxVectorData* WriteDecorHandle<T, D>::vectorData (std::true_type)
320 {
321  return (*this)->container();
322 }
323 
324 
325 /**
326  * @brief Return the referenced object as a @c SG::AuxVectorData.
327  * Specialization for the case of a container
328  * (@c T does not derive from @c SG::AuxElement).
329  */
330 template <class T, class D>
331 const SG::AuxVectorData* WriteDecorHandle<T, D>::vectorData (std::false_type)
332 {
333  return this->cptr();
334 }
335 
336 
337 /**
338  * @brief Return the referenced object as a @c SG::AuxVectorData.
339  *
340  * If @c T is a container object, then this should be the object itself.
341  * But if it is a standalone object, deriving from @c SG::AuxElement,
342  * then we need to call container() on the object.
343  */
344 template <class T, class D>
345 const SG::AuxVectorData* WriteDecorHandle<T, D>::vectorData()
346 {
347  return vectorData (typename std::is_base_of<SG::AuxElement, T>::type());
348 }
349 
350 
351 /**
352  * @brief Return a @c WriteDecorHandle referencing @c key.
353  * @param key The key object holding the clid/key/store.
354  *
355  * This will raise an exception if the StoreGate key is blank,
356  * or if the event store cannot be found.
357  *
358  * The type of the decoration must be included as an explicit template parameter:
359  *
360  *@code
361  * auto handle = SG::makeHandle<float> (key);
362  @endcode
363  *
364  * Note that @c D comes first in the argument list. It's given explicitly,
365  * while @c T is inferred from @c key.
366  */
367 template <class D, class T>
368 WriteDecorHandle<T, D> makeHandle (const WriteDecorHandleKey<T>& key)
369 {
370  return WriteDecorHandle<T, D> (key);
371 }
372 
373 
374 /**
375  * @brief Return a @c WriteDecorHandle referencing @c key for an explicit context.
376  * @param key The key object holding the clid/key/store.
377  * @param ctx The event context.
378  *
379  * This will raise an exception if the StoreGate key is blank,
380  * or if the event store cannot be found.
381  *
382  * If the default event store has been requested, then the thread-specific
383  * store from the event context will be used.
384  *
385  * The type of the decoration must be included as an explicit template parameter:
386  *
387  *@code
388  * auto handle = SG::makeHandle<float> (key, ctx);
389  @endcode
390  *
391  * Note that @c D comes first in the argument list. It's given explicitly,
392  * while @c T is inferred from @c key.
393  */
394 template <class D, class T>
395 WriteDecorHandle<T, D> makeHandle (const WriteDecorHandleKey<T>& key,
396  const EventContext& ctx)
397 {
398  return WriteDecorHandle<T, D> (key, ctx);
399 }
400 
401 
402 /**
403  * @brief These two signatures are to catch cases where the explicit
404  * template argument is omitted from the @c makeHandle call
405  * and give an error tailored to that. Otherwise, the @c makeHandle
406  * call for @c ReadHandle would match, potentially giving a much
407  * more confusing error.
408  */
409 template <class T>
410 void makeHandle (const WriteDecorHandleKey<T>& /*key*/)
411 {
412  // If you see an error from here, you've forgotten the explicit template
413  // argument to @c makeHandle giving the decoration type.
414  // See the examples of @c makeHandle above.
415  return T::makeHandleForDecorationsRequiresExplicitTemplateArgument();
416 }
417 template <class T>
418 void makeHandle (const WriteDecorHandleKey<T>& /*key*/,
419  const EventContext& /*ctx*/)
420 {
421  // If you see an error from here, you've forgotten the explicit template
422  // argument to @c makeHandle giving the decoration type.
423  // See the examples of @c makeHandle above.
424  return T::makeHandleForDecorationsRequiresExplicitTemplateArgument();
425 }
426 
427 
428 } // namespace SG