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_state (key.renounced() ? RENOUNCED : NO_ALIAS)
32 {
33 }
34 
35 
36 /**
37  * @brief Constructor from a ReadDecorHandleKey and an explicit event context.
38  * @param key The key object holding the clid/key.
39  * @param ctx The event context.
40  *
41  * This will raise an exception if the StoreGate key is blank,
42  * or if the event store cannot be found.
43  *
44  * If the default event store has been requested, then the thread-specific
45  * store from the event context will be used.
46  */
47 template <class T, class D>
48 WriteDecorHandle<T, D>::WriteDecorHandle (const WriteDecorHandleKey<T>& key,
49  const EventContext& ctx)
50  : Base (key.contHandleKey(), &ctx),
51  m_decorKey (key.key()),
52  m_acc (SG::decorKeyFromKey (key.key())),
53  m_state (key.renounced() ? RENOUNCED : NO_ALIAS)
54 {
55 }
56 
57 
58 /**
59  * @brief Copy constructor.
60  */
61 template <class T, class D>
62 WriteDecorHandle<T, D>::WriteDecorHandle (const WriteDecorHandle& rhs)
63  : Base (rhs),
64  m_decorKey (rhs.m_decorKey),
65  m_acc (rhs.m_acc),
66  m_state (rhs.m_state)
67 {
68 }
69 
70 
71 /**
72  * @brief Move constructor.
73  */
74 template <class T, class D>
75 WriteDecorHandle<T, D>::WriteDecorHandle (WriteDecorHandle&& rhs)
76  : Base (std::move (rhs)),
77  m_decorKey (std::move (rhs.m_decorKey)),
78  m_acc (std::move (rhs.m_acc)),
79  m_state (rhs.m_state)
80 {
81  rhs.m_state = NO_ALIAS;
82 }
83 
84 
85 /**
86  * @brief Destructor. This will lock the decoration.
87  */
88 template <class T, class D>
89 WriteDecorHandle<T, D>::~WriteDecorHandle()
90 {
91  // Lock the decoration. But don't do anything if we haven't touched it.
92  if (m_state == MADE_ALIAS) {
93  const IConstAuxStore* store = this->vectorData()->getConstStore();
94  if (store) {
95  // Lock the decoration and clear its entry in the cache.
96  // Casting away const should be ok because no other thread should
97  // be looking at this decoration yet.
98  auto store_nc ATLAS_THREAD_SAFE = const_cast<IConstAuxStore*> (store);
99  store_nc->lockDecoration (auxid());
100  auto avd_nc ATLAS_THREAD_SAFE = const_cast<SG::AuxVectorData*> (this->vectorData());
101  avd_nc->clearDecorCache (auxid());
102  }
103  }
104 }
105 
106 
107 /**
108  * @brief Assignment operator.
109  */
110 template <class T, class D>
111 WriteDecorHandle<T, D>& WriteDecorHandle<T, D>::operator= (const WriteDecorHandle& rhs)
112 {
113  if (this != &rhs) {
114  *static_cast<Base*>(this) = rhs;
115  m_acc = rhs.m_acc;
116  m_decorKey = rhs.m_decorKey;
117  m_state = rhs.m_state;
118  }
119  return *this;
120 }
121 
122 
123 /**
124  * @brief Move operator.
125  */
126 template <class T, class D>
127 WriteDecorHandle<T, D>& WriteDecorHandle<T, D>::operator= (WriteDecorHandle&& rhs)
128 {
129  if (this != &rhs) {
130  *static_cast<Base*>(this) = std::move (rhs);
131  m_acc = std::move (rhs.m_acc);
132  m_decorKey = std::move (rhs.m_decorKey);
133  m_state = rhs.m_state;
134  rhs.m_state = NO_ALIAS;
135  }
136  return *this;
137 }
138 
139 
140 /**
141  * @brief Is the referenced container present in SG?
142  *
143  * Note that this tests for the presence of the _container_,
144  * not for the decoration.
145  *
146  * Const method; the handle does not change as a result of this.
147  */
148 template <class T, class D>
149 bool WriteDecorHandle<T, D>::isPresent() const
150 {
151  return Base::isPresent();
152 }
153 
154 
155 /**
156  * @brief Explicitly set the event store.
157  * @param store The new event store.
158  *
159  * This implicitly does a reset().
160  *
161  * We need to override this so that the setting gets made on the container
162  * handle as well.
163  */
164 template <class T, class D>
165 StatusCode WriteDecorHandle<T, D>::setProxyDict (IProxyDict* store)
166 {
167  if (m_state == MADE_ALIAS) {
168  m_state = NO_ALIAS;
169  }
170  return Base::setProxyDict (store);
171 }
172 
173 
174 /**
175  * @brief Fetch the variable for one element, as a reference.
176  * @param e The element for which to fetch the variable.
177  */
178 template <class T, class D>
179 typename WriteDecorHandle<T, D>::reference_type
180 WriteDecorHandle<T, D>::operator() (const AuxElement& e)
181 {
182  // Ensure that the element we're given is actually an element
183  // of the container we're writing.
184  // (Note that we need to look up the container in the store independently
185  // of this check. We previously called cptr() here, but that's
186  // redundant with vectorData().
187  if (m_state != RENOUNCED && e.container() != this->vectorData()) {
188  throwExcBadDecorElement (Gaudi::DataHandle::Writer,
189  this->clid(),
190  this->m_decorKey);
191  }
192  return m_acc (e);
193 }
194 
195 
196 /**
197  * @brief Fetch the variable for one element, as a reference.
198  * @param index The index of the desired element.
199  *
200  * This looks up the variable in the object referenced by this handle.
201  * For a standalone object, pass an index of 0.
202  */
203 template <class T, class D>
204 typename WriteDecorHandle<T, D>::reference_type
205 WriteDecorHandle<T, D>::operator() (size_t i)
206 {
207  if (m_state != RENOUNCED) {
208  this->cptr();
209  }
210  return m_acc (*this->vectorData(), i);
211 }
212 
213 
214 /**
215  * @brief Get a pointer to the start of the auxiliary data array,
216  * for the referenced object.
217  */
218 template <class T, class D>
219 template <class POINTER_TYPE /*= container_pointer_type*/,
220  typename /*= std::enable_if_t<!std::is_void_v<POINTER_TYPE> >*/ >
221 POINTER_TYPE
222 WriteDecorHandle<T, D>::getDecorationArray()
223 {
224  return m_acc.getDecorationArray (*this->vectorData());
225 }
226 
227 
228 /**
229  * @brief Get a span over the auxilary data array,
230  * for the referenced object.
231  */
232 template <class T, class D>
233 auto
234 WriteDecorHandle<T, D>::getDecorationSpan() -> span
235 {
236  return m_acc.getDecorationSpan (*this->vectorData());
237 }
238 
239 
240 /**
241  * @brief Test to see if this variable exists in the store,
242  * for the referenced object.
243  * Specialization for the case of a standalone object
244  * (@c T derives from @c SG::AuxElement).
245  */
246 template <class T, class D>
247 inline
248 bool WriteDecorHandle<T, D>::isAvailable (std::true_type)
249 {
250  const T* ptr = this->ptr();
251  if (ptr) {
252  const SG::AuxVectorData* obj = ptr->container();
253  if (obj) {
254  return obj->isAvailable (m_acc.auxid());
255  }
256  }
257 
258  return false;
259 }
260 
261 
262 /**
263  * @brief Test to see if this variable exists in the store,
264  * for the referenced object.
265  * Specialization for the case of a container
266  * (@c T does not derive from @c SG::AuxElement).
267  */
268 template <class T, class D>
269 inline
270 bool WriteDecorHandle<T, D>::isAvailable (std::false_type)
271 {
272  const T* ptr = this->ptr();
273  if (ptr) {
274  return ptr->isAvailable (m_acc.auxid());
275  }
276 
277  return false;
278 }
279 
280 
281 /**
282  * @brief Test to see if this variable exists in the store,
283  * for the referenced object.
284  */
285 template <class T, class D>
286 inline
287 bool WriteDecorHandle<T, D>::isAvailable()
288 {
289  if (!this->m_ptr) {
290  ReadHandle<T>::typeless_dataPointer_impl (true);
291  }
292  // We can't just use vectorData() because that will create the decoration
293  // as a side effect.
294  return isAvailable (typename std::is_base_of<SG::AuxElement, T>::type());
295 }
296 
297 
298 /**
299  * @brief Return the aux id for this variable.
300  */
301 template <class T, class D>
302 SG::auxid_t WriteDecorHandle<T, D>::auxid() const
303 {
304  return m_acc.auxid();
305 }
306 
307 
308 /**
309  * @brief Return the mode (read/write/update) for this handle.
310  */
311 template <class T, class D>
312 inline
313 Gaudi::DataHandle::Mode WriteDecorHandle<T, D>::mode() const
314 {
315  return Gaudi::DataHandle::Writer;
316 }
317 
318 
319 /**
320  * @brief Return the name of the decoration alias (CONT.DECOR).
321  */
322 template <class T, class D>
323 inline
324 std::string WriteDecorHandle<T, D>::decorKey() const
325 {
326  return m_decorKey;
327 }
328 
329 
330 /**
331  * @brief Retrieve an object from StoreGate.
332  * @param quiet If true, suppress failure messages.
333  *
334  * Extended for decoration handles: when we first retrieve the object,
335  * we make an alias for the decoration and also create the decoration itself.
336  */
337 template <class T, class D>
338 void* WriteDecorHandle<T, D>::typeless_dataPointer_impl (bool quiet)
339 {
340  if (this->m_ptr && this->m_state != NO_ALIAS)
341  return this->m_ptr;
342  if (!this->m_ptr) {
343  ReadHandle<T>::typeless_dataPointer_impl (quiet);
344  }
345  if (!this->m_ptr) {
346  return nullptr;
347  }
348  if (m_state == NO_ALIAS) {
349  if (this->alias (WriteHandleKey<T> (this->m_decorKey)).isFailure())
350  return nullptr;
351  m_state = MADE_ALIAS;
352  }
353  // Important to call the base class method above before calling vectorData;
354  // otherwise, we'll get an infinite recursion.
355  // Also don't call getDecorationArray if the container is empty.
356  if (this->m_ptr && this->vectorData()->size_v() > 0) {
357  m_acc.getDecorationSpan (*this->vectorData());
358  }
359  return this->m_ptr;
360 }
361 
362 
363 /**
364  * @brief Return the referenced object as a @c SG::AuxVectorData.
365  * Specialization for the case of a standalone object
366  * (@c T derives from @c SG::AuxElement).
367  */
368 template <class T, class D>
369 const SG::AuxVectorData* WriteDecorHandle<T, D>::vectorData (std::true_type)
370 {
371  return (*this)->container();
372 }
373 
374 
375 /**
376  * @brief Return the referenced object as a @c SG::AuxVectorData.
377  * Specialization for the case of a container
378  * (@c T does not derive from @c SG::AuxElement).
379  */
380 template <class T, class D>
381 const SG::AuxVectorData* WriteDecorHandle<T, D>::vectorData (std::false_type)
382 {
383  return this->cptr();
384 }
385 
386 
387 /**
388  * @brief Return the referenced object as a @c SG::AuxVectorData.
389  *
390  * If @c T is a container object, then this should be the object itself.
391  * But if it is a standalone object, deriving from @c SG::AuxElement,
392  * then we need to call container() on the object.
393  */
394 template <class T, class D>
395 const SG::AuxVectorData* WriteDecorHandle<T, D>::vectorData()
396 {
397  return vectorData (typename std::is_base_of<SG::AuxElement, T>::type());
398 }
399 
400 
401 /**
402  * @brief Return a @c WriteDecorHandle referencing @c key.
403  * @param key The key object holding the clid/key/store.
404  *
405  * This will raise an exception if the StoreGate key is blank,
406  * or if the event store cannot be found.
407  *
408  * The type of the decoration must be included as an explicit template parameter:
409  *
410  *@code
411  * auto handle = SG::makeHandle<float> (key);
412  @endcode
413  *
414  * Note that @c D comes first in the argument list. It's given explicitly,
415  * while @c T is inferred from @c key.
416  */
417 template <class D, class T>
418 WriteDecorHandle<T, D> makeHandle (const WriteDecorHandleKey<T>& key)
419 {
420  return WriteDecorHandle<T, D> (key);
421 }
422 
423 
424 /**
425  * @brief Return a @c WriteDecorHandle referencing @c key for an explicit context.
426  * @param key The key object holding the clid/key/store.
427  * @param ctx The event context.
428  *
429  * This will raise an exception if the StoreGate key is blank,
430  * or if the event store cannot be found.
431  *
432  * If the default event store has been requested, then the thread-specific
433  * store from the event context will be used.
434  *
435  * The type of the decoration must be included as an explicit template parameter:
436  *
437  *@code
438  * auto handle = SG::makeHandle<float> (key, ctx);
439  @endcode
440  *
441  * Note that @c D comes first in the argument list. It's given explicitly,
442  * while @c T is inferred from @c key.
443  */
444 template <class D, class T>
445 WriteDecorHandle<T, D> makeHandle (const WriteDecorHandleKey<T>& key,
446  const EventContext& ctx)
447 {
448  return WriteDecorHandle<T, D> (key, ctx);
449 }
450 
451 
452 /**
453  * @brief These two signatures are to catch cases where the explicit
454  * template argument is omitted from the @c makeHandle call
455  * and give an error tailored to that. Otherwise, the @c makeHandle
456  * call for @c ReadHandle would match, potentially giving a much
457  * more confusing error.
458  */
459 template <class T>
460 void makeHandle (const WriteDecorHandleKey<T>& /*key*/)
461 {
462  // If you see an error from here, you've forgotten the explicit template
463  // argument to @c makeHandle giving the decoration type.
464  // See the examples of @c makeHandle above.
465  return T::makeHandleForDecorationsRequiresExplicitTemplateArgument();
466 }
467 template <class T>
468 void makeHandle (const WriteDecorHandleKey<T>& /*key*/,
469  const EventContext& /*ctx*/)
470 {
471  // If you see an error from here, you've forgotten the explicit template
472  // argument to @c makeHandle giving the decoration type.
473  // See the examples of @c makeHandle above.
474  return T::makeHandleForDecorationsRequiresExplicitTemplateArgument();
475 }
476 
477 
478 } // namespace SG