2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
5 * @file AthLinks/ElementLink.h
6 * @author scott snyder <snyder@bnl.gov>
8 * @brief a persistable pointer to an element of a STORABLE (data object)
12 #include "AthLinks/exceptions.h"
13 #include "AthenaKernel/proxyDictFromEventContext.h"
14 #include "AthenaKernel/IProxyDict.h"
18 * @brief Return the CLID for the class that we reference.
20 template <class STORABLE>
22 const CLID& ElementLink<STORABLE>::classID()
24 return ClassID_traits<value_type>::ID();
29 * @brief Default constructor. Makes a null link.
31 template <class STORABLE>
33 ElementLink<STORABLE>::ElementLink()
39 * @brief Construct a link from a string storable key and an index. O(1)
40 * @param dataID Key of the object.
41 * @param elemID The index of the element within the container.
42 * @param sg Associated store.
44 * If @c sg is 0, we take the global default.
46 template <class STORABLE>
48 ElementLink<STORABLE>::ElementLink(const ID_type& dataID, index_type elemID,
49 IProxyDict* sg /*= 0*/)
50 : Base (dataID, classID(), elemID, sg)
56 * @brief Construct a link from a string storable key and an index. O(1)
57 * @param dataID Key of the object.
58 * @param elemID The index of the element within the container.
59 * @param ctx Event context for this link.
61 template <class STORABLE>
63 ElementLink<STORABLE>::ElementLink(const ID_type& dataID, index_type elemID,
64 const EventContext& ctx)
65 : Base (dataID, classID(), elemID, Atlas::proxyDictFromEventContext(ctx))
71 * @brief Construct a link from a hashed storable key and an index. O(1)
72 * @param key Hashed key of the object.
73 * @param elemID The index of the element within the container.
74 * @param sg Associated store.
76 * If @c sg is 0, we take the global default.
78 template <class STORABLE>
80 ElementLink<STORABLE>::ElementLink(sgkey_t key, index_type elemID,
81 IProxyDict* sg /*= 0*/)
82 : Base (key, classID(), elemID, sg)
88 * @brief Construct a link from a hashed storable key and an index. O(1)
89 * @param key Hashed key of the object.
90 * @param elemID The index of the element within the container.
91 * @param ctx Event context for this link.
93 template <class STORABLE>
95 ElementLink<STORABLE>::ElementLink(sgkey_t key, index_type elemID,
96 const EventContext& ctx)
97 : Base (key, classID(), elemID, Atlas::proxyDictFromEventContext(ctx))
103 * @brief Construct from a string storable key, index, AND pointer to element. O(1)
104 * @param dataID Key of the object.
105 * @param elemID The index of the element within the container.
106 * @param pEl Pointer to the element.
107 * @param sg Associated store.
109 * USE CAREFULLY: no coherency checks, we just trust you!
111 * If @c sg is 0, we take the global default.
113 template <class STORABLE>
115 ElementLink<STORABLE>::ElementLink(const ID_type& dataID,
118 IProxyDict* sg /*= 0*/)
119 : Base (dataID, classID(), elemID, pEl, sg)
125 * @brief Construct from a string storable key, index, AND pointer to element. O(1)
126 * @param dataID Key of the object.
127 * @param elemID The index of the element within the container.
128 * @param pEl Pointer to the element.
129 * @param ctx Event context for this link.
131 * USE CAREFULLY: no coherency checks, we just trust you!
133 template <class STORABLE>
135 ElementLink<STORABLE>::ElementLink(const ID_type& dataID,
138 const EventContext& ctx)
139 : Base (dataID, classID(), elemID, pEl, Atlas::proxyDictFromEventContext(ctx))
145 * @brief Construct from a hashed storable key, index, AND pointer to element. O(1)
146 * @param key Hashed key of the object.
147 * @param elemID The index of the element within the container.
148 * @param pEl Pointer to the element.
149 * @param sg Associated store.
151 * USE CAREFULLY: no coherency checks, we just trust you!
153 * If @c sg is 0, we take the global default.
155 template <class STORABLE>
157 ElementLink<STORABLE>::ElementLink (sgkey_t key,
160 IProxyDict* sg /*= 0*/)
161 : Base (key, classID(), elemID, pEl, sg)
167 * @brief Construct from a hashed storable key, index, AND pointer to element. O(1)
168 * @param key Hashed key of the object.
169 * @param elemID The index of the element within the container.
170 * @param pEl Pointer to the element.
171 * @param ctx Event context for this link.
173 * USE CAREFULLY: no coherency checks, we just trust you!
175 template <class STORABLE>
177 ElementLink<STORABLE>::ElementLink (sgkey_t key,
180 const EventContext& ctx)
181 : Base (key, classID(), elemID, pEl, Atlas::proxyDictFromEventContext(ctx))
187 * @brief Construct a link from an index and reference to the container. O(1)
188 * @param data Reference to the container (storable).
189 * @param elemID The index of the element within the container.
190 * @param sg Associated store.
192 * If @c sg is 0, we take the global default.
194 template <class STORABLE>
196 ElementLink<STORABLE>::ElementLink (BaseConstReference data,
198 IProxyDict* sg /* = 0*/)
199 : Base (&data, classID(), elemID, sg)
205 * @brief Construct a link from an index and reference to the container. O(1)
206 * @param data Reference to the container (storable).
207 * @param elemID The index of the element within the container.
208 * @param ctx Event context for this link.
210 template <class STORABLE>
212 ElementLink<STORABLE>::ElementLink (BaseConstReference data,
214 const EventContext& ctx)
215 : Base (&data, classID(), elemID, Atlas::proxyDictFromEventContext(ctx))
221 * @brief Construct from an element and reference to the container. O(N)
222 * @param element The element to reference.
223 * @param data Reference to the container (storable).
224 * @param sg Associated store.
226 * Does the same thing as the default ctor followed by @c toContainedElement.
227 * Note the reversed parameter order compared to the previous
228 * constructor. This is to prevent ambiguities in the case that
229 * the contained type is convertable to an int.
231 * Will throw @c SG::ExcElementNotFound if the element is not
234 * If @c sg is 0, we take the global default.
236 template <class STORABLE>
238 ElementLink<STORABLE>::ElementLink (const ElementType& element,
239 BaseConstReference data,
240 IProxyDict* sg /*= 0*/)
242 toContainedElement (data, element, sg);
247 * @brief Construct from an element and reference to the container. O(N)
248 * @param element The element to reference.
249 * @param data Reference to the container (storable).
250 * @param ctx Event context for this link.
252 * Does the same thing as the default ctor followed by @c toContainedElement.
253 * Note the reversed parameter order compared to the previous
254 * constructor. This is to prevent ambiguities in the case that
255 * the contained type is convertable to an int.
257 * Will throw @c SG::ExcElementNotFound if the element is not
260 template <class STORABLE>
262 ElementLink<STORABLE>::ElementLink (const ElementType& element,
263 BaseConstReference data,
264 const EventContext& ctx)
266 toContainedElement (data, element, ctx);
271 * @brief Construct a link from another link, changing the index.
272 * @param other The source link.
273 * @param elemID The index for the new link.
275 * The index being constructed will reference the same container
276 * as @c other, but it will refer to element @c elemID.
278 template <class STORABLE>
280 ElementLink<STORABLE>::ElementLink (const ElementLink& other,
282 : Base (other, elemID)
288 * @brief Construct a link from a DataLink and an index.
289 * @param dlink Link to the container.
290 * @param index The index of the element within the container.
292 template <class STORABLE>
294 ElementLink<STORABLE>::ElementLink (const DataLink<STORABLE>& dlink,
296 : Base (dlink, index)
302 * @brief Constructor allowing a derived -> base conversion.
304 template <class STORABLE>
307 ElementLink<STORABLE>::ElementLink (const ElementLink<U>& other)
309 (SG::ElementLinkTraits<U>*)0,
316 * @brief Return a pointer to the currently-referenced container object.
317 * @return A pointer to an object of the type given by @a clid,
318 * or null on a failure (or if the reference is null).
320 template <class STORABLE>
322 typename ElementLink<STORABLE>::const_pointer
323 ElementLink<STORABLE>::getDataPtr() const
325 return reinterpret_cast<const_pointer> (this->storable());
330 * @brief Return a pointer to the currently-referenced container object.
331 * @return A pointer to an object of the type given by @a clid,
332 * or null on a failure (or if the reference is null).
334 template <class STORABLE>
336 typename ElementLink<STORABLE>::pointer
337 ElementLink<STORABLE>::getDataNonConstPtr()
339 return reinterpret_cast<pointer> (this->storableNonConst());
344 * @brief Return a link to the currently-referenced container object.
346 template <class STORABLE>
348 DataLink<STORABLE> ElementLink<STORABLE>::getDataLink()
350 return DataLink<STORABLE> (this->key(), this->proxyHolder());
355 * @brief Return a link to the currently-referenced container object.
357 template <class STORABLE>
359 const DataLink<STORABLE> ElementLink<STORABLE>::getDataLink() const
361 return DataLink<STORABLE> (this->key(), this->proxyHolder());
366 * @brief Return a pointer to the currently-referenced container object.
368 template <class STORABLE>
370 typename ElementLink<STORABLE>::BaseConstPointer
371 ElementLink<STORABLE>::getStorableObjectPointer() const
378 * @brief Return a reference to the currently-referenced container object.
380 template <class STORABLE>
382 typename ElementLink<STORABLE>::BaseConstReference
383 ElementLink<STORABLE>::getStorableObjectRef() const
385 return *getDataPtr();
390 * @brief Return a pointer to the referenced element.
392 * Be aware: if the element is a pointer, then this will yield
393 * a pointer to a pointer.
395 template <class STORABLE>
397 typename ElementLink<STORABLE>::ElementConstPointer
398 ElementLink<STORABLE>::cptr() const
400 ElementConstPointer ret = 0;
401 if (this->getCachedElement (ret))
404 const STORABLE* ptr = this->getDataPtr();
405 if (ptr && IndexingPolicy::isValid(this->storedIndex())) {
406 this->setCachedElement (IndexingPolicy::lookup(this->storedIndex(), *ptr));
407 this->getCachedElement (ret);
414 * @brief Return a reference to the referenced element.
416 * Will throw an exception if the link is not valid.
418 template <class STORABLE>
420 typename ElementLink<STORABLE>::ElementConstReference
421 ElementLink<STORABLE>::operator* () const
423 ElementConstPointer ptr = cptr();
425 SG::throwExcInvalidLink (classID(), this->dataID(), this->key());
431 * @brief Return a pointer to the referenced element.
433 template <class STORABLE>
435 typename ElementLink<STORABLE>::ElementConstPointer
436 ElementLink<STORABLE>::operator->() const
443 * @brief Convert to a pointer to the referenced element.
445 template <class STORABLE>
447 ElementLink<STORABLE>::operator ElementConstPointer () const
454 * @brief Test to see if the link can be dereferenced.
456 * Will throw an exception if the container is not empty and the
457 * referenced element cannot be retrieved.
459 template <class STORABLE>
461 bool ElementLink<STORABLE>::isValid() const
463 // This used to just call cptr(), but that was leading to dangling-pointer
464 // warnings with gcc12 when we were returning ElementLink's by value,
465 // as in ElementLinkVector. Doing it like this allows us to save
466 // a little work, anyway.
467 if (this->hasCachedElement()) return true;
469 const STORABLE* ptr = this->getDataPtr();
470 if (ptr && !ptr->empty() && IndexingPolicy::isValid(this->storedIndex())) {
471 this->setCachedElement (IndexingPolicy::lookup(this->storedIndex(), *ptr));
479 * @brief Test to see if the link can not be dereferenced.
481 template <class STORABLE>
483 bool ElementLink<STORABLE>::operator!() const
490 * @brief Return the cached element, if any.
492 template <class STORABLE>
494 typename ElementLink<STORABLE>::ElementType
495 ElementLink<STORABLE>::cachedElement() const
497 ElementConstPointer ret = 0;
498 if (this->getCachedElement (ret))
500 return ElementType();
505 * @brief Set the link to an element given by index and pointer to container.
506 * @param data Reference to the container (storable).
507 * @param elemID The index of the element within the container.
508 * @param sg Associated store.
509 * @returns True if the link was changed.
511 * If the link is already set, this will return false and leave the
514 * If @c sg is 0, then we take the store from whatever the link's currently
515 * set to. If the link has no current store, then we take the global
518 template <class STORABLE>
521 ElementLink<STORABLE>::toIndexedElement(BaseConstReference data,
523 IProxyDict* sg /*= 0*/)
525 return Base::toIndexedElement (&data, classID(), elemID, sg);
530 * @brief Set the link to an element given by index and pointer to container.
531 * @param data Reference to the container (storable).
532 * @param elemID The index of the element within the container.
533 * @param ctx The event context.
534 * @returns True if the link was changed.
536 * If the link is already set, this will return false and leave the
539 template <class STORABLE>
542 ElementLink<STORABLE>::toIndexedElement(BaseConstReference data,
544 const EventContext& ctx)
546 return Base::toIndexedElement (&data, classID(), elemID, Atlas::proxyDictFromEventContext(ctx));
551 * @brief Set from element pointer and a reference to the container (storable)
552 * @param data Reference to the container (storable).
553 * @param element The element.
554 * @param sg Associated store.
555 * @returns True if the link was changed.
557 * O(N) for sequences!
559 * If the link is already set, this will return false and leave the
562 * If @c sg is 0, then we take the store from whatever the link's currently
563 * set to. If the link has no current store, then we take the global
566 template <class STORABLE>
568 bool ElementLink<STORABLE>::toContainedElement(BaseConstReference data,
570 IProxyDict* sg /*= 0*/)
572 index_type index = this->index();
573 IndexingPolicy::reverseLookup (data, element, index);
574 bool ret = Base::toIndexedElement (&data, classID(), index, sg);
576 this->storeCachedElement (element);
582 * @brief Set from element pointer and a reference to the container (storable)
583 * @param data Reference to the container (storable).
584 * @param element The element.
585 * @param ctx The event context.
586 * @returns True if the link was changed.
588 * O(N) for sequences!
590 * If the link is already set, this will return false and leave the
593 template <class STORABLE>
595 bool ElementLink<STORABLE>::toContainedElement(BaseConstReference data,
597 const EventContext& ctx)
599 index_type index = this->index();
600 IndexingPolicy::reverseLookup (data, element, index);
601 bool ret = Base::toIndexedElement (&data, classID(), index, Atlas::proxyDictFromEventContext(ctx));
603 this->storeCachedElement (element);
609 * @brief Set to point to an element.
610 * @param element The element.
611 * @returns True if the link was changed.
613 * The collection and the element can be specified independently
614 * using @c setElement and @c setStorableObject.
616 * If the link is already set, this will return false and leave the
619 template <class STORABLE>
621 bool ElementLink<STORABLE>::setElement(ElementType element)
623 if (!this->isDefaultIndex() || this->hasCachedElement())
625 this->storeCachedElement (element);
626 const STORABLE* ptr = this->getDataPtr();
628 index_type index = this->index();
629 IndexingPolicy::reverseLookup (*ptr, element, index);
630 this->setIndex (index);
637 * @brief Set link to point to a new container (storable).
638 * @param data Reference to the container (storable).
639 * @param replace True if we can change an existing link.
640 * @param sg Associated store.
641 * @returns True if the link was changed.
643 * If the link is already set, this will return false and leave the
644 * link unchanged unless @c replace is set. The @c replace argument
645 * should be set if the element is now in a new storable container;
646 * e.g. element ptr has been put in a new view container.
648 * If @c sg is 0, then we take the store from whatever the link's currently
649 * set to. If the link has no current store, then we take the global
652 template <class STORABLE>
654 bool ElementLink<STORABLE>::setStorableObject(BaseConstReference data,
655 bool replace /*= false*/,
656 IProxyDict* sg /*= 0*/)
658 bool ret = Base::setStorableObject (&data, classID(), replace, sg);
660 ElementConstPointer elt = 0;
661 if (this->isDefaultIndex() && this->getCachedElement (elt)) {
662 index_type index = this->index();
663 IndexingPolicy::reverseLookup (data, *elt, index);
664 this->setIndex (index);
673 * @brief Set link to point to a new container (storable).
674 * @param data Reference to the container (storable).
675 * @param replace True if we can change an existing link.
676 * @param ctx The event context.
677 * @returns True if the link was changed.
679 * If the link is already set, this will return false and leave the
680 * link unchanged unless @c replace is set. The @c replace argument
681 * should be set if the element is now in a new storable container;
682 * e.g. element ptr has been put in a new view container.
684 template <class STORABLE>
686 bool ElementLink<STORABLE>::setStorableObject(BaseConstReference data,
688 const EventContext& ctx)
690 bool ret = Base::setStorableObject (&data, classID(), replace, Atlas::proxyDictFromEventContext(ctx));
692 ElementConstPointer elt = 0;
693 if (this->isDefaultIndex() && this->getCachedElement (elt)) {
694 index_type index = this->index();
695 IndexingPolicy::reverseLookup (data, *elt, index);
696 this->setIndex (index);
705 * @brief Set the link to an element given by string key and index.
706 * @param dataID Key of the object.
707 * @param elemID The index of the element within the container.
708 * @param sg Associated store.
710 * If @c sg is 0, then we take the store from whatever the link's currently
711 * set to. If the link has no current store, then we take the global
714 template <class STORABLE>
716 void ElementLink<STORABLE>::resetWithKeyAndIndex(const ID_type& dataID,
718 IProxyDict* sg /*= 0*/)
720 Base::resetWithKeyAndIndex (dataID, classID(), elemID, sg);
725 * @brief Set the link to an element given by string key and index.
726 * @param dataID Key of the object.
727 * @param elemID The index of the element within the container.
728 * @param ctx The event context.
730 template <class STORABLE>
732 void ElementLink<STORABLE>::resetWithKeyAndIndex(const ID_type& dataID,
734 const EventContext& ctx)
736 Base::resetWithKeyAndIndex (dataID, classID(), elemID, Atlas::proxyDictFromEventContext(ctx));
741 * @brief Set the link to an element given by string key and index.
742 * @param key Hashed key of the object.
743 * @param elemID The index of the element within the container.
744 * @param sg Associated store.
746 * If @c sg is 0, then we take the store from whatever the link's currently
747 * set to. If the link has no current store, then we take the global
750 template <class STORABLE>
752 void ElementLink<STORABLE>::resetWithKeyAndIndex(sgkey_t key,
754 IProxyDict* sg /*= 0*/)
756 Base::resetWithKeyAndIndex (key, classID(), elemID, sg);
761 * @brief Set the link to an element given by string key and index.
762 * @param key Hashed key of the object.
763 * @param elemID The index of the element within the container.
764 * @param ctx The event context.
766 template <class STORABLE>
768 void ElementLink<STORABLE>::resetWithKeyAndIndex(sgkey_t key,
770 const EventContext& ctx)
772 Base::resetWithKeyAndIndex (key, classID(), elemID, Atlas::proxyDictFromEventContext(ctx));
777 * @brief Return a (void) pointer to the currently-referenced
779 * @return A pointer to an object of the type given by @a clid,
780 * or null on a failure (or if the reference is null).
782 template <class STORABLE>
784 const void* ElementLink<STORABLE>::storable() const
786 typedef STORABLE* fn_t (SG::DataProxy*);
787 fn_t* fn = &SG::DataProxy_cast<STORABLE>;
788 return this->storableBase (reinterpret_cast<castfn_t*> (fn), classID(), true);
793 * @brief Return a (void) pointer to the currently-referenced
795 * @return A pointer to an object of the type given by @a clid,
796 * or null on a failure (or if the reference is null).
798 template <class STORABLE>
800 void* ElementLink<STORABLE>::storableNonConst()
802 typedef STORABLE* fn_t (SG::DataProxy*);
803 fn_t* fn = &SG::DataProxy_cast<STORABLE>;
804 return this->storableBase (reinterpret_cast<castfn_t*> (fn), classID(), false);
809 * @brief Ordering relation for @c ElementLink (less-than)
810 * @param lhs Left-hand-side EL.
811 * @param rhs Right-hand-side EL.
813 template <typename STORABLE>
814 bool operator < (const ElementLink<STORABLE>& lhs,
815 const ElementLink<STORABLE>& rhs)
817 bool lhsDefault = lhs.isDefault();
818 bool rhsDefault = rhs.isDefault();
819 if (lhsDefault && rhsDefault) return false;
820 if (lhsDefault) return true;
821 if (rhsDefault) return false;
822 if (lhs.key() == 0 || rhs.key() == 0 || lhs.isDefaultIndex() || rhs.isDefaultIndex())
823 SG::throwExcIncomparableEL();
824 if (SG::sgkeyLess (lhs.key(), rhs.key())) return true;
825 if (SG::sgkeyLess (rhs.key(), lhs.key())) return false;
826 if (lhs.index() < rhs.index()) return true;
832 * @brief Ordering relation for @c ElementLink (greater-than)
833 * @param lhs Left-hand-side EL.
834 * @param rhs Right-hand-side EL.
836 template <typename STORABLE>
838 bool operator > (const ElementLink<STORABLE>& lhs,
839 const ElementLink<STORABLE>& rhs)
846 * @brief Equality relation for @c ElementLink.
847 * @param lhs Left-hand-side EL.
848 * @param rhs Right-hand-side EL.
850 template <typename STORABLE>
852 bool operator == (const ElementLink<STORABLE>& lhs,
853 const ElementLink<STORABLE>& rhs)
855 return !((lhs < rhs) || (rhs < lhs));
860 * @brief Inequality relation for @c ElementLink.
861 * @param lhs Left-hand-side EL.
862 * @param rhs Right-hand-side EL.
864 template <typename STORABLE>
866 bool operator != (const ElementLink<STORABLE>& lhs,
867 const ElementLink<STORABLE>& rhs)
869 return !(lhs == rhs);
873 namespace SG_detail {
877 * @brief See if an EL is being remapped.
878 * @param sgkey_in Original hashed key of the EL.
879 * @param index_in Original index of the EL.
880 * @param sgkey_out[out] New hashed key for the EL.
881 * @param index_out[out] New index for the EL.
882 * @return True if there is a remapping; false otherwise.
884 * This version is for the case where the EL index is a @c size_t.
885 * For other index types, the the templated version below is used
886 * (which doesn't allow remapping indices).
889 bool checkForRemap (IProxyDict* sg,
890 SG::sgkey_t sgkey_in,
892 SG::sgkey_t& sgkey_out,
895 return sg->tryELRemap (sgkey_in, index_in, sgkey_out, index_out);
900 * @brief See if an EL is being remapped.
901 * @param sgkey_in Original hashed key of the EL.
902 * @param dum_in Ignored.
903 * @param sgkey_out[out] New hashed key for the EL.
904 * @param dum_out[out] Ignored.
905 * @return True if there is a remapping; false otherwise.
907 * This version catches the cases where the container index type
908 * isn't a @c size_t. We don't support changing the index in this case.
912 bool checkForRemap (IProxyDict* sg,
913 SG::sgkey_t sgkey_in,
915 SG::sgkey_t& sgkey_out,
920 return sg->tryELRemap (sgkey_in, index_in, sgkey_out, index_out);
924 } // namespace SG_detail