2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
5 * @file StoreGate/WriteHandle.icc
6 * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov>
7 * @date Updated: Feb, 2016
8 * @brief Handle class for recording to StoreGate.
11 #ifndef STOREGATE_SG_WRITEHANDLE_ICC
12 #define STOREGATE_SG_WRITEHANDLE_ICC 1
15 #include "StoreGate/exceptions.h"
16 #include "AthenaKernel/ClassID_traits.h"
17 #include "AthenaKernel/errorcheck.h"
24 //************************************************************************
30 * @brief Default constructor.
32 * The handle will not be usable until a non-blank key is assigned.
36 WriteHandle<T>::WriteHandle()
37 : VarHandleBase(ClassID_traits<T>::ID(), Gaudi::DataHandle::Writer)
43 * @brief Constructor with full arguments.
44 * @param sgkey StoreGate key of the referenced object.
45 * @param storename Name of the referenced event store.
49 WriteHandle<T>::WriteHandle (const std::string& sgkey,
50 const std::string& storename /* ="StoreGateSvc"*/)
51 : VarHandleBase (ClassID_traits<T>::ID(), sgkey,
52 Gaudi::DataHandle::Writer, storename)
58 * @brief Constructor from a WriteHandleKey.
59 * @param key The key object holding the clid/key/store.
61 * This will raise an exception if the StoreGate key is blank,
62 * or if the event store cannot be found.
66 WriteHandle<T>::WriteHandle (const WriteHandleKey<T>& key)
67 : VarHandleBase (key, nullptr)
73 * @brief Constructor from a WriteHandleKey and an explicit event context.
74 * @param key The key object holding the clid/key.
75 * @param ctx The event context.
77 * This will raise an exception if the StoreGate key is blank,
78 * or if the event store cannot be found.
80 * If the default event store has been requested, then the thread-specific
81 * store from the event context will be used.
85 WriteHandle<T>::WriteHandle (const WriteHandleKey<T>& key,
86 const EventContext& ctx)
87 : VarHandleBase (key, &ctx)
89 // cppcheck-suppress missingReturn; false positive
94 * @brief Copy constructor.
98 WriteHandle<T>::WriteHandle(const WriteHandle& h)
105 * @brief Move constructor.
108 WriteHandle<T>::WriteHandle(WriteHandle&& h)
109 : VarHandleBase(std::move(h))
111 m_lockAuxPending = h.m_lockAuxPending;
112 h.m_lockAuxPending = nullptr;
117 * @brief Assignment operator.
122 // m_lockAuxPending not copied --- want lifetime to stay with the
124 // cppcheck-suppress operatorEqVarError
125 WriteHandle<T>::operator= (const WriteHandle& h)
128 this->VarHandleBase::operator=(h);
134 * @brief Move operator.
139 WriteHandle<T>::operator= (WriteHandle&& h)
142 this->VarHandleBase::operator=(std::move(h));
143 m_lockAuxPending = h.m_lockAuxPending;
144 h.m_lockAuxPending = nullptr;
153 * Lock an aux object if m_lockAuxPending is true.
156 WriteHandle<T>::~WriteHandle()
158 if (m_lockAuxPending) {
159 m_lockAuxPending->setConst();
164 //************************************************************************
165 // Deference. These all return only the cached pointer.
170 * @brief Dereference the pointer.
171 * Returns the cached pointer. Throws ExcNullWriteHandle if null.
175 typename WriteHandle<T>::pointer_type
176 WriteHandle<T>::operator->()
178 return WriteHandle<T>::checkedCachedPtr();
183 * @brief Dereference the pointer.
184 * Returns the cached pointer. Throws ExcNullWriteHandle if null.
188 typename WriteHandle<T>::reference_type
189 WriteHandle<T>::operator*()
191 return *WriteHandle<T>::checkedCachedPtr();
196 * @brief Dereference the pointer.
197 * Returns the cached pointer.
201 typename WriteHandle<T>::const_pointer_type
202 WriteHandle<T>::cptr() const
204 return reinterpret_cast<pointer_type>(this->m_ptr);
209 * @brief Dereference the pointer.
210 * Returns the cached pointer.
214 typename WriteHandle<T>::pointer_type
215 WriteHandle<T>::ptr()
222 * @brief Return the cached pointer directly; no lookup.
226 typename WriteHandle<T>::pointer_type
227 WriteHandle<T>::cachedPtr()
229 return reinterpret_cast<pointer_type>(this->m_ptr);
234 * @brief Can the handle be successfully dereferenced?
238 bool WriteHandle<T>::isValid()
240 return this->m_ptr != nullptr;
244 //************************************************************************
249 * @brief Record a const object to the store.
250 * @param data The object to record.
255 WriteHandle<T>::WriteHandle::record (std::unique_ptr<T> data)
257 return this->doRecord (std::move(data), true, false);
262 * @brief Record a non-const object to the store.
263 * @param data The object to record.
264 * @param isConst If true, record the object as const.
269 WriteHandle<T>::WriteHandle::recordNonConst (std::unique_ptr<T> data)
271 return this->doRecord (std::move(data), false, false);
276 * @brief Record a const object and its auxiliary store to the store.
277 * @param data The object to record.
278 * @param auxstore Auxiliary store object.
281 template <class AUXSTORE>
284 WriteHandle<T>::WriteHandle::record (std::unique_ptr<T> data,
285 std::unique_ptr<AUXSTORE> auxstore)
287 return record (std::move(data), std::move(auxstore), true);
292 * @brief Record a non-const object and its auxiliary store to the store.
293 * @param data The object to record.
294 * @param auxstore Auxiliary store object.
297 template <class AUXSTORE>
300 WriteHandle<T>::WriteHandle::recordNonConst (std::unique_ptr<T> data,
301 std::unique_ptr<AUXSTORE> auxstore)
303 return record (std::move(data), std::move(auxstore), false);
308 * @brief Record a const shared DataObject to the store.
309 * @param data The object to record.
311 * The event store takes shared ownership of the object.
316 WriteHandle<T>::record (SG::DataObjectSharedPtr<T> data)
318 return this->doRecord (std::move(data), true, false);
323 * @brief Record a non-const shared DataObject to the store.
324 * @param data The object to record.
326 * The event store takes shared ownership of the object.
331 WriteHandle<T>::recordNonConst (SG::DataObjectSharedPtr<T> data)
333 return this->doRecord (std::move(data), false, false);
338 * @brief Record an object to the store.
339 * @param data The object to record.
340 * @param returnExisting Allow an existing object?
342 * Unlike record(), this does not change the handle object.
343 * That means that one will not be able to get the object back
344 * by dereferencing the handle.
345 * Returns the object placed in the store, or nullptr if there
347 * If there was already an object in the store with the given key,
348 * then return null, unless @c returnExisting is true, in which case
349 * return success. In either case, @c data is destroyed.
353 typename WriteHandle<T>::const_pointer_type
354 WriteHandle<T>::put (std::unique_ptr<T> data,
355 bool returnExisting /*= false*/) const
357 IProxyDict* store = nullptr;
358 return doPut (nullptr, std::move(data), returnExisting, store);
363 * @brief Record an object to the store.
364 * @param data The object to record.
365 * @param returnExisting Allow an existing object?
367 * Unlike record(), this does not change the handle object.
368 * That means that one will not be able to get the object back
369 * by dereferencing the handle.
370 * Returns the object placed in the store, or nullptr if there
372 * If there was already an object in the store with the given key,
373 * then return null, unless @c returnExisting is true, in which case
374 * return success. In either case, @c data is destroyed.
378 typename WriteHandle<T>::const_pointer_type
379 WriteHandle<T>::put (std::unique_ptr<const T> data,
380 bool returnExisting /*= false*/) const
382 IProxyDict* store = nullptr;
383 return doPut (nullptr, std::move(data), returnExisting, store);
388 * @brief Record an object to the store.
389 * @param data The object to record.
390 * @param returnExisting Allow an existing object?
392 * Unlike record(), this does not change the handle object.
393 * That means that one will not be able to get the object back
394 * by dereferencing the handle.
395 * Returns the object placed in the store, or nullptr if there
397 * If there was already an object in the store with the given key,
398 * then return null, unless @c returnExisting is true, in which case
399 * return success. In either case, @c data is destroyed.
403 typename WriteHandle<T>::const_pointer_type
404 WriteHandle<T>::put (std::unique_ptr<const ConstDataVector<T> > data,
405 bool returnExisting /*= false*/) const
407 IProxyDict* store = nullptr;
408 std::unique_ptr<const T> coll (data.release()->asDataVector());
409 return doPut (nullptr, std::move(coll), returnExisting, store);
414 * @brief Record an object to the store.
415 * @param ctx The event context to use.
416 * @param data The object to record.
417 * @param returnExisting Allow an existing object?
419 * Unlike record(), this does not change the handle object.
420 * That means that one will not be able to get the object back
421 * by dereferencing the handle.
422 * Returns the object placed in the store, or nullptr if there
424 * If there was already an object in the store with the given key,
425 * then return null, unless @c returnExisting is true, in which case
426 * return success. In either case, @c data is destroyed.
430 typename WriteHandle<T>::const_pointer_type
431 WriteHandle<T>::put (const EventContext& ctx,
432 std::unique_ptr<const ConstDataVector<T> > data,
433 bool returnExisting /*= false*/) const
435 IProxyDict* store = nullptr;
436 std::unique_ptr<const T> coll (data.release()->asDataVector());
437 return doPut (&ctx, std::move(coll), returnExisting, store);
442 * @brief Record an object to the store.
443 * @param ctx The event context to use.
444 * @param data The object to record.
445 * @param returnExisting Allow an existing object?
447 * Unlike record(), this does not change the handle object.
448 * That means that one will not be able to get the object back
449 * by dereferencing the handle.
450 * Returns the object placed in the store, or nullptr if there
452 * If there was already an object in the store with the given key,
453 * then return null, unless @c returnExisting is true, in which case
454 * return success. In either case, @c data is destroyed.
458 typename WriteHandle<T>::const_pointer_type
459 WriteHandle<T>::put (const EventContext& ctx,
460 std::unique_ptr<T> data,
461 bool returnExisting /*= false*/) const
463 IProxyDict* store = nullptr;
464 return doPut (&ctx, std::move(data), returnExisting, store);
469 * @brief Record an object to the store.
470 * @param ctx The event context to use.
471 * @param data The object to record.
472 * @param returnExisting Allow an existing object?
474 * Unlike record(), this does not change the handle object.
475 * That means that one will not be able to get the object back
476 * by dereferencing the handle.
477 * Returns the object placed in the store, or nullptr if there
479 * If there was already an object in the store with the given key,
480 * then return null, unless @c returnExisting is true, in which case
481 * return success. In either case, @c data is destroyed.
485 typename WriteHandle<T>::const_pointer_type
486 WriteHandle<T>::put (const EventContext& ctx,
487 std::unique_ptr<const T> data,
488 bool returnExisting /*= false*/) const
490 IProxyDict* store = nullptr;
491 return doPut (&ctx, std::move(data), returnExisting, store);
496 * @brief Record an object to the store.
497 * @param data The object to record.
499 * Unlike record(), this does not change the handle object.
500 * That means that one will not be able to get the object back
501 * by dereferencing the handle.
502 * Returns the object placed in the store, or nullptr if there
505 * The event store takes shared ownership of the object.
509 typename WriteHandle<T>::const_pointer_type
510 WriteHandle<T>::put (SG::DataObjectSharedPtr<T> data) const
512 IProxyDict* store = nullptr;
513 return doPut (nullptr, std::move(data), false, store);
518 * @brief Record an object to the store.
519 * @param ctx The event context to use.
520 * @param data The object to record.
522 * Unlike record(), this does not change the handle object.
523 * That means that one will not be able to get the object back
524 * by dereferencing the handle.
525 * Returns the object placed in the store, or nullptr if there
528 * The event store takes shared ownership of the object.
532 typename WriteHandle<T>::const_pointer_type
533 WriteHandle<T>::put (const EventContext& ctx,
534 SG::DataObjectSharedPtr<T> data) const
536 IProxyDict* store = nullptr;
537 return doPut (&ctx, std::move(data), false, store);
542 * @brief Record an object and its auxiliary store to the store.
543 * @param data The object to record.
544 * @param auxstore Auxiliary store object.
546 * Unlike record(), this does not change the handle object.
547 * That means that one will not be able to get the object back
548 * by dereferencing the handle.
549 * Returns the object placed in the store, or nullptr if there
551 * If there was already an object in the store with the given key,
552 * then return null, and the objects passed in are destroyed.
555 template <class AUXSTORE>
556 typename WriteHandle<T>::const_pointer_type
557 WriteHandle<T>::put (std::unique_ptr<T> data,
558 std::unique_ptr<AUXSTORE> auxstore) const
560 return doPut (nullptr, std::move(data), std::move(auxstore));
566 * @brief Record an object and its auxiliary store to the store.
567 * @param data The object to record.
568 * @param auxstore Auxiliary store object.
570 * Unlike record(), this does not change the handle object.
571 * That means that one will not be able to get the object back
572 * by dereferencing the handle.
573 * Returns the object placed in the store, or nullptr if there
575 * If there was already an object in the store with the given key,
576 * then return null, and the objects passed in are destroyed.
578 * Unlike the version taking unique_ptr<T>, this does not alter the
579 * store pointer of @c data.
582 template <class AUXSTORE>
583 typename WriteHandle<T>::const_pointer_type
584 WriteHandle<T>::put (std::unique_ptr<const T> data,
585 std::unique_ptr<const AUXSTORE> auxstore) const
587 return doPut (nullptr, std::move(data), std::move(auxstore));
592 * @brief Record an object and its auxiliary store to the store.
593 * @param ctx The event context to use.
594 * @param data The object to record.
595 * @param auxstore Auxiliary store object.
597 * Unlike record(), this does not change the handle object.
598 * That means that one will not be able to get the object back
599 * by dereferencing the handle.
600 * Returns the object placed in the store, or nullptr if there
602 * If there was already an object in the store with the given key,
603 * then return null, and the objects passed in are destroyed.
606 template <class AUXSTORE>
607 typename WriteHandle<T>::const_pointer_type
608 WriteHandle<T>::put (const EventContext& ctx,
609 std::unique_ptr<T> data,
610 std::unique_ptr<AUXSTORE> auxstore) const
612 return doPut (&ctx, std::move(data), std::move(auxstore));
617 * @brief Record an object and its auxiliary store to the store.
618 * @param ctx The event context to use.
619 * @param data The object to record.
620 * @param auxstore Auxiliary store object.
622 * Unlike record(), this does not change the handle object.
623 * That means that one will not be able to get the object back
624 * by dereferencing the handle.
625 * Returns the object placed in the store, or nullptr if there
627 * If there was already an object in the store with the given key,
628 * then return null, and the objects passed in are destroyed.
630 * Unlike the version taking unique_ptr<T>, this does not alter the
631 * store pointer of @c data.
634 template <class AUXSTORE>
635 typename WriteHandle<T>::const_pointer_type
636 WriteHandle<T>::put (const EventContext& ctx,
637 std::unique_ptr<const T> data,
638 std::unique_ptr<const AUXSTORE> auxstore) const
640 return doPut (&ctx, std::move(data), std::move(auxstore));
645 * @brief Alternate notation for record. Records a non-const object.
646 * @param data Object to record.
648 * Throws an exception on failure.
652 WriteHandle<T>::operator= (std::unique_ptr<T> data)
654 if (recordNonConst (std::move(data)).isFailure()) {
655 throw std::runtime_error ("WriteHandle<T>::operator=(unique_ptr) Record failed.");
662 * @brief Make an alias.
663 * @param key Alternate key by which the referenced object should be known.
665 * The current handle should be valid and referencing an object
666 * (i.e., @c record should have been called on it).
668 * The object will also be known by the name given in @c key.
671 StatusCode WriteHandle<T>::alias (const WriteHandleKey<T>& key)
673 return symLink_impl (this->clid(), key.key());
678 * @brief Make an explicit link.
679 * @param key Alternate clid by which the referenced object
680 * should be known. The SG key must match the key of the
683 * You should generally not be using this!
685 * The current handle should be valid and referencing an object
686 * (i.e., @c record should have been called on it).
688 * This makes a symlink: the object will be retrievable
689 * as a different type.
691 * Note that if @c T and @c @U are related via @c SG_BASE and/or
692 * @c DATAVECTOR_BASE, then you shouldn't need to explicitly make a symlink;
693 * that should happen automatically.
695 * If a @c U* is not convertable to a @c T* via C++ rules, then you likely
696 * will be, at best, relying on undefined behavior. You will probably
697 * get warnings from the undefined behavior sanitizer when if you try
698 * to dereference the @c U*.
700 * This usage is here mainly to assist in migrating some existing
701 * patterns to MT. You should think several times before using
706 StatusCode WriteHandle<T>::symLink (const WriteHandleKey<U>& other)
708 if (this->key() != other.key()) {
709 REPORT_ERROR (StatusCode::FAILURE)
710 << "symLink: SG keys do not match: " << other.key() << " vs "
712 return StatusCode::FAILURE;
714 return symLink_impl (other.clid(), other.key());
719 * @brief Return the cached pointer directly.
721 * If it is null, throw ExcNullWriteHandle.
724 typename WriteHandle<T>::pointer_type
725 WriteHandle<T>::checkedCachedPtr()
728 throwExcNullWriteHandle (clid(), key(), store());
734 * @brief Helper for record.
735 * @param data The object to record.
736 * @param isConst If true, record the object as const.
737 * @param returnExisting Allow an existing object.
741 StatusCode WriteHandle<T>::doRecord (U data,
745 typedef typename U::element_type elt_t;
747 // make sure the BaseInfo(Base) structure is initialized
748 SG::BaseInfo<elt_t>::baseinfo();
750 // If s_isConst is set for this type, then we want to automatically
751 // make it const when recorded.
752 bool allowMods = !isConst;
753 if (ClassID_traits<elt_t>::s_isConst)
756 void* dataPtr(data.get());
757 std::unique_ptr<DataObject> dobj (SG::asStorable (std::move (data)));
758 return this->record_impl (std::move(dobj), dataPtr, allowMods, returnExisting);
763 * @brief Helper for put.
764 * @param ctx The event context, or nullptr to use the current context.
765 * @param data The object to record.
766 * @param returnExisting Allow an existing object.
767 * @param[out] store The store being used.
769 * Unlike record(), this does not change the handle object.
770 * That means that will not be able to get the object back
771 * by dereferencing the handle.
772 * Returns the object placed in the store, or nullptr if there
774 * If there was already an object in the store with the given key,
775 * then return null, unless @c returnExisting is true, in which case
776 * return success. In either case, @c data is destroyed.
780 typename WriteHandle<T>::const_pointer_type
781 WriteHandle<T>::doPut (const EventContext* ctx,
784 IProxyDict* & store) const
786 //typedef typename U::element_type elt_t;
789 // make sure the BaseInfo(Base) structure is initialized
790 SG::BaseInfo<elt_t>::baseinfo();
792 const void* dataPtr = data.get();
793 std::unique_ptr<DataObject> dobj (SG::asStorable (std::move (data)));
794 return reinterpret_cast<const T*>
795 (this->put_impl (ctx, std::move(dobj), dataPtr, false, returnExisting, store));
800 * @brief Helper for recording an object and its auxiliary store to the store.
801 * @param ctx The event context, or nullptr to use the current context.
802 * @param data The object to record.
803 * @param auxstore Auxiliary store object.
805 * Unlike record(), this does not change the handle object.
806 * That means that will not be able to get the object back
807 * by dereferencing the handle.
808 * Returns the object placed in the store, or nullptr if there
810 * If there was already an object in the store with the given key,
811 * then return null, and the objects passed in are destroyed.
814 template <class AUXSTORE>
815 typename WriteHandle<T>::const_pointer_type
816 WriteHandle<T>::doPut (const EventContext* ctx,
817 std::unique_ptr<T> data,
818 std::unique_ptr<AUXSTORE> auxstore) const
822 // If there's no store association, do it now.
823 if (data->getStore() == nullptr)
824 data->setStore (auxstore.get());
826 IProxyDict* store = nullptr;
827 const T* ptr = this->doPut (ctx, std::move(data), false, store);
828 if (!ptr) return nullptr;
830 SG::DataObjectSharedPtr<DataObject> dobj
831 (SG::asStorable (std::move (auxstore)));
832 SG::DataProxy* proxy = store->recordObject (std::move(dobj),
833 this->name() + "Aux.",
837 REPORT_ERROR (StatusCode::FAILURE)
838 << "recordObject of aux store failed";
840 // If we've failed here, then the aux store object has been deleted,
841 // but not the primary object. Null out the store pointer to prevent
842 // having a dangling pointer to a deleted object.
843 dref.setStore (static_cast<SG::IConstAuxStore*>(nullptr));
852 * @brief Helper for recording an object and its auxiliary store to the store.
853 * @param ctx The event context, or nullptr to use the current context.
854 * @param data The object to record.
855 * @param auxstore Auxiliary store object.
857 * Unlike record(), this does not change the handle object.
858 * That means that will not be able to get the object back
859 * by dereferencing the handle.
860 * Returns the object placed in the store, or nullptr if there
862 * If there was already an object in the store with the given key,
863 * then return null, and the objects passed in are destroyed.
866 template <class AUXSTORE>
867 typename WriteHandle<T>::const_pointer_type
868 WriteHandle<T>::doPut (const EventContext* ctx,
869 std::unique_ptr<const T> data,
870 std::unique_ptr<const AUXSTORE> auxstore) const
872 IProxyDict* store = nullptr;
873 const T* ptr = this->doPut (ctx, std::move(data), false, store);
874 if (!ptr) return nullptr;
876 SG::DataObjectSharedPtr<DataObject> dobj
877 (SG::asStorable (std::move (auxstore)));
878 SG::DataProxy* proxy = store->recordObject (std::move(dobj),
879 this->name() + "Aux.",
883 REPORT_ERROR (StatusCode::FAILURE)
884 << "recordObject of aux store failed";
893 * @brief Record an object and its auxiliary store to the store.
894 * @param data The object to record.
895 * @param auxstore Auxiliary store object.
896 * @param isConst If true, record the objects as const.
899 template <class AUXSTORE>
901 WriteHandle<T>::record (std::unique_ptr<T> data,
902 std::unique_ptr<AUXSTORE> auxstore,
907 // If there's no store association, do it now.
908 if (data->getStore() == nullptr)
909 data->setStore (auxstore.get());
912 // Temporarily clear the store association, in order to prevent
913 // the aux store from being locked at this point.
914 IAuxStore* store = dref.getStore();
916 dref.setStore (static_cast<SG::IAuxStore*>(nullptr));
917 CHECK (this->record(std::move(data)));
918 // Deliberately not using RAII here. If there is an error,
919 // then the object referenced by data will be deleted.
920 dref.setStore (store);
923 CHECK (this->recordNonConst(std::move(data)));
925 // Store and proxy must be valid if we get to this point.
927 SG::DataObjectSharedPtr<DataObject> dobj
928 (SG::asStorable (std::move (auxstore)));
929 SG::DataProxy* proxy = m_store->recordObject (std::move(dobj),
930 this->name() + "Aux.",
934 REPORT_ERROR (StatusCode::FAILURE)
935 << "recordObject of aux store failed";
937 // If we've failed here, then the aux store object has been deleted,
938 // but not the primary object. Null out the store pointer to prevent
939 // having a dangling pointer to a deleted object.
940 dref.setStore (static_cast<SG::IConstAuxStore*>(nullptr));
941 return StatusCode::FAILURE;
944 if (m_proxy->isConst())
945 m_lockAuxPending = proxy;
947 return StatusCode::SUCCESS;
952 * @brief Return a @c WriteHandle referencing @c key.
953 * @param key The key object holding the clid/key/store.
955 * This will raise an exception if the StoreGate key is blank,
956 * or if the event store cannot be found.
959 WriteHandle<T> makeHandle (const WriteHandleKey<T>& key)
961 return WriteHandle<T> (key);
966 * @brief Return a @c WriteHandle referencing @c key for an explicit context.
967 * @param key The key object holding the clid/key/store.
968 * @param ctx The event context.
970 * This will raise an exception if the StoreGate key is blank,
971 * or if the event store cannot be found.
973 * If the default event store has been requested, then the thread-specific
974 * store from the event context will be used.
977 WriteHandle<T> makeHandle (const WriteHandleKey<T>& key,
978 const EventContext& ctx)
980 return WriteHandle<T> (key, ctx);
987 #endif //> !STOREGATE_SG_WRITEHANDLE_ICC