2 * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
5 * @file StoreGate/WriteDecorHandle.icc
6 * @author scott snyder <snyder@bnl.gov>
8 * @brief Handle class for adding a decoration to an object.
12 #include "CxxUtils/checker_macros.h"
13 #include "StoreGate/exceptions.h"
20 * @brief Constructor from a WriteDecorHandleKey.
21 * @param key The key object holding the clid/key/store/attr.
23 * This will raise an exception if the StoreGate key is blank,
24 * or if the event store cannot be found.
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)
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.
41 * This will raise an exception if the StoreGate key is blank,
42 * or if the event store cannot be found.
44 * If the default event store has been requested, then the thread-specific
45 * store from the event context will be used.
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)
59 * @brief Copy constructor.
61 template <class T, class D>
62 WriteDecorHandle<T, D>::WriteDecorHandle (const WriteDecorHandle& rhs)
64 m_decorKey (rhs.m_decorKey),
72 * @brief Move constructor.
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)),
81 rhs.m_state = NO_ALIAS;
86 * @brief Destructor. This will lock the decoration.
88 template <class T, class D>
89 WriteDecorHandle<T, D>::~WriteDecorHandle()
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();
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());
108 * @brief Assignment operator.
110 template <class T, class D>
111 WriteDecorHandle<T, D>& WriteDecorHandle<T, D>::operator= (const WriteDecorHandle& rhs)
114 *static_cast<Base*>(this) = rhs;
116 m_decorKey = rhs.m_decorKey;
117 m_state = rhs.m_state;
124 * @brief Move operator.
126 template <class T, class D>
127 WriteDecorHandle<T, D>& WriteDecorHandle<T, D>::operator= (WriteDecorHandle&& 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;
141 * @brief Is the referenced container present in SG?
143 * Note that this tests for the presence of the _container_,
144 * not for the decoration.
146 * Const method; the handle does not change as a result of this.
148 template <class T, class D>
149 bool WriteDecorHandle<T, D>::isPresent() const
151 return Base::isPresent();
156 * @brief Explicitly set the event store.
157 * @param store The new event store.
159 * This implicitly does a reset().
161 * We need to override this so that the setting gets made on the container
164 template <class T, class D>
165 StatusCode WriteDecorHandle<T, D>::setProxyDict (IProxyDict* store)
167 if (m_state == MADE_ALIAS) {
170 return Base::setProxyDict (store);
175 * @brief Fetch the variable for one element, as a reference.
176 * @param e The element for which to fetch the variable.
178 template <class T, class D>
179 typename WriteDecorHandle<T, D>::reference_type
180 WriteDecorHandle<T, D>::operator() (const AuxElement& e)
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,
197 * @brief Fetch the variable for one element, as a reference.
198 * @param index The index of the desired element.
200 * This looks up the variable in the object referenced by this handle.
201 * For a standalone object, pass an index of 0.
203 template <class T, class D>
204 typename WriteDecorHandle<T, D>::reference_type
205 WriteDecorHandle<T, D>::operator() (size_t i)
207 if (m_state != RENOUNCED) {
210 return m_acc (*this->vectorData(), i);
215 * @brief Get a pointer to the start of the auxiliary data array,
216 * for the referenced object.
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> >*/ >
222 WriteDecorHandle<T, D>::getDecorationArray()
224 return m_acc.getDecorationArray (*this->vectorData());
229 * @brief Get a span over the auxilary data array,
230 * for the referenced object.
232 template <class T, class D>
234 WriteDecorHandle<T, D>::getDecorationSpan() -> span
236 return m_acc.getDecorationSpan (*this->vectorData());
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).
246 template <class T, class D>
248 bool WriteDecorHandle<T, D>::isAvailable (std::true_type)
250 const T* ptr = this->ptr();
252 const SG::AuxVectorData* obj = ptr->container();
254 return obj->isAvailable (m_acc.auxid());
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).
268 template <class T, class D>
270 bool WriteDecorHandle<T, D>::isAvailable (std::false_type)
272 const T* ptr = this->ptr();
274 return ptr->isAvailable (m_acc.auxid());
282 * @brief Test to see if this variable exists in the store,
283 * for the referenced object.
285 template <class T, class D>
287 bool WriteDecorHandle<T, D>::isAvailable()
290 ReadHandle<T>::typeless_dataPointer_impl (true);
292 // We can't just use vectorData() because that will create the decoration
294 return isAvailable (typename std::is_base_of<SG::AuxElement, T>::type());
299 * @brief Return the aux id for this variable.
301 template <class T, class D>
302 SG::auxid_t WriteDecorHandle<T, D>::auxid() const
304 return m_acc.auxid();
309 * @brief Return the mode (read/write/update) for this handle.
311 template <class T, class D>
313 Gaudi::DataHandle::Mode WriteDecorHandle<T, D>::mode() const
315 return Gaudi::DataHandle::Writer;
320 * @brief Return the name of the decoration alias (CONT.DECOR).
322 template <class T, class D>
324 std::string WriteDecorHandle<T, D>::decorKey() const
331 * @brief Retrieve an object from StoreGate.
332 * @param quiet If true, suppress failure messages.
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.
337 template <class T, class D>
338 void* WriteDecorHandle<T, D>::typeless_dataPointer_impl (bool quiet)
340 if (this->m_ptr && this->m_state != NO_ALIAS)
343 ReadHandle<T>::typeless_dataPointer_impl (quiet);
348 if (m_state == NO_ALIAS) {
349 if (this->alias (WriteHandleKey<T> (this->m_decorKey)).isFailure())
351 m_state = MADE_ALIAS;
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());
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).
368 template <class T, class D>
369 const SG::AuxVectorData* WriteDecorHandle<T, D>::vectorData (std::true_type)
371 return (*this)->container();
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).
380 template <class T, class D>
381 const SG::AuxVectorData* WriteDecorHandle<T, D>::vectorData (std::false_type)
388 * @brief Return the referenced object as a @c SG::AuxVectorData.
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.
394 template <class T, class D>
395 const SG::AuxVectorData* WriteDecorHandle<T, D>::vectorData()
397 return vectorData (typename std::is_base_of<SG::AuxElement, T>::type());
402 * @brief Return a @c WriteDecorHandle referencing @c key.
403 * @param key The key object holding the clid/key/store.
405 * This will raise an exception if the StoreGate key is blank,
406 * or if the event store cannot be found.
408 * The type of the decoration must be included as an explicit template parameter:
411 * auto handle = SG::makeHandle<float> (key);
414 * Note that @c D comes first in the argument list. It's given explicitly,
415 * while @c T is inferred from @c key.
417 template <class D, class T>
418 WriteDecorHandle<T, D> makeHandle (const WriteDecorHandleKey<T>& key)
420 return WriteDecorHandle<T, D> (key);
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.
429 * This will raise an exception if the StoreGate key is blank,
430 * or if the event store cannot be found.
432 * If the default event store has been requested, then the thread-specific
433 * store from the event context will be used.
435 * The type of the decoration must be included as an explicit template parameter:
438 * auto handle = SG::makeHandle<float> (key, ctx);
441 * Note that @c D comes first in the argument list. It's given explicitly,
442 * while @c T is inferred from @c key.
444 template <class D, class T>
445 WriteDecorHandle<T, D> makeHandle (const WriteDecorHandleKey<T>& key,
446 const EventContext& ctx)
448 return WriteDecorHandle<T, D> (key, ctx);
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.
460 void makeHandle (const WriteDecorHandleKey<T>& /*key*/)
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();
468 void makeHandle (const WriteDecorHandleKey<T>& /*key*/,
469 const EventContext& /*ctx*/)
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();