2 Copyright (C) 2002-2025 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"
17 * @brief Return the CLID for the class that we reference.
19 template <class STORABLE>
21 const CLID& ElementLink<STORABLE>::classID()
23 return ClassID_traits<value_type>::ID();
28 * @brief Default constructor. Makes a null link.
30 template <class STORABLE>
32 ElementLink<STORABLE>::ElementLink()
38 * @brief Construct a link from a string storable key and an index. O(1)
39 * @param dataID Key of the object.
40 * @param elemID The index of the element within the container.
41 * @param sg Associated store.
43 * If @c sg is 0, we take the global default.
45 template <class STORABLE>
47 ElementLink<STORABLE>::ElementLink(const ID_type& dataID, index_type elemID,
48 IProxyDict* sg /*= 0*/)
49 : Base (dataID, classID(), elemID, sg)
55 * @brief Construct a link from a string storable key and an index. O(1)
56 * @param dataID Key of the object.
57 * @param elemID The index of the element within the container.
58 * @param ctx Event context for this link.
60 template <class STORABLE>
62 ElementLink<STORABLE>::ElementLink(const ID_type& dataID, index_type elemID,
63 const EventContext& ctx)
64 : Base (dataID, classID(), elemID, Atlas::proxyDictFromEventContext(ctx))
70 * @brief Construct a link from a hashed storable key and an index. O(1)
71 * @param key Hashed key of the object.
72 * @param elemID The index of the element within the container.
73 * @param sg Associated store.
75 * If @c sg is 0, we take the global default.
77 template <class STORABLE>
79 ElementLink<STORABLE>::ElementLink(sgkey_t key, index_type elemID,
80 IProxyDict* sg /*= 0*/)
81 : Base (key, classID(), elemID, sg)
87 * @brief Construct a link from a hashed storable key and an index. O(1)
88 * @param key Hashed key of the object.
89 * @param elemID The index of the element within the container.
90 * @param ctx Event context for this link.
92 template <class STORABLE>
94 ElementLink<STORABLE>::ElementLink(sgkey_t key, index_type elemID,
95 const EventContext& ctx)
96 : Base (key, classID(), elemID, Atlas::proxyDictFromEventContext(ctx))
102 * @brief Construct from a string storable key, index, AND pointer to element. O(1)
103 * @param dataID Key of the object.
104 * @param elemID The index of the element within the container.
105 * @param pEl Pointer to the element.
106 * @param sg Associated store.
108 * USE CAREFULLY: no coherency checks, we just trust you!
110 * If @c sg is 0, we take the global default.
112 template <class STORABLE>
114 ElementLink<STORABLE>::ElementLink(const ID_type& dataID,
117 IProxyDict* sg /*= 0*/)
118 : Base (dataID, classID(), elemID, pEl, sg)
124 * @brief Construct from a string storable key, index, AND pointer to element. O(1)
125 * @param dataID Key of the object.
126 * @param elemID The index of the element within the container.
127 * @param pEl Pointer to the element.
128 * @param ctx Event context for this link.
130 * USE CAREFULLY: no coherency checks, we just trust you!
132 template <class STORABLE>
134 ElementLink<STORABLE>::ElementLink(const ID_type& dataID,
137 const EventContext& ctx)
138 : Base (dataID, classID(), elemID, pEl, Atlas::proxyDictFromEventContext(ctx))
144 * @brief Construct from a hashed storable key, index, AND pointer to element. O(1)
145 * @param key Hashed key of the object.
146 * @param elemID The index of the element within the container.
147 * @param pEl Pointer to the element.
148 * @param sg Associated store.
150 * USE CAREFULLY: no coherency checks, we just trust you!
152 * If @c sg is 0, we take the global default.
154 template <class STORABLE>
156 ElementLink<STORABLE>::ElementLink (sgkey_t key,
159 IProxyDict* sg /*= 0*/)
160 : Base (key, classID(), elemID, pEl, sg)
166 * @brief Construct from a hashed storable key, index, AND pointer to element. O(1)
167 * @param key Hashed key of the object.
168 * @param elemID The index of the element within the container.
169 * @param pEl Pointer to the element.
170 * @param ctx Event context for this link.
172 * USE CAREFULLY: no coherency checks, we just trust you!
174 template <class STORABLE>
176 ElementLink<STORABLE>::ElementLink (sgkey_t key,
179 const EventContext& ctx)
180 : Base (key, classID(), elemID, pEl, Atlas::proxyDictFromEventContext(ctx))
186 * @brief Construct a link from an index and reference to the container. O(1)
187 * @param data Reference to the container (storable).
188 * @param elemID The index of the element within the container.
189 * @param sg Associated store.
191 * If @c sg is 0, we take the global default.
193 template <class STORABLE>
195 ElementLink<STORABLE>::ElementLink (BaseConstReference data,
197 IProxyDict* sg /* = 0*/)
198 : Base (&data, classID(), elemID, sg)
204 * @brief Construct a link from an index and reference to the container. O(1)
205 * @param data Reference to the container (storable).
206 * @param elemID The index of the element within the container.
207 * @param ctx Event context for this link.
209 template <class STORABLE>
211 ElementLink<STORABLE>::ElementLink (BaseConstReference data,
213 const EventContext& ctx)
214 : Base (&data, classID(), elemID, Atlas::proxyDictFromEventContext(ctx))
220 * @brief Construct from an element and reference to the container. O(N)
221 * @param element The element to reference.
222 * @param data Reference to the container (storable).
223 * @param sg Associated store.
225 * Does the same thing as the default ctor followed by @c toContainedElement.
226 * Note the reversed parameter order compared to the previous
227 * constructor. This is to prevent ambiguities in the case that
228 * the contained type is convertable to an int.
230 * Will throw @c SG::ExcElementNotFound if the element is not
233 * If @c sg is 0, we take the global default.
235 template <class STORABLE>
237 ElementLink<STORABLE>::ElementLink (const ElementType& element,
238 BaseConstReference data,
239 IProxyDict* sg /*= 0*/)
241 toContainedElement (data, element, sg);
246 * @brief Construct from an element and reference to the container. O(N)
247 * @param element The element to reference.
248 * @param data Reference to the container (storable).
249 * @param ctx Event context for this link.
251 * Does the same thing as the default ctor followed by @c toContainedElement.
252 * Note the reversed parameter order compared to the previous
253 * constructor. This is to prevent ambiguities in the case that
254 * the contained type is convertable to an int.
256 * Will throw @c SG::ExcElementNotFound if the element is not
259 template <class STORABLE>
261 ElementLink<STORABLE>::ElementLink (const ElementType& element,
262 BaseConstReference data,
263 const EventContext& ctx)
265 toContainedElement (data, element, ctx);
270 * @brief Construct a link from another link, changing the index.
271 * @param other The source link.
272 * @param elemID The index for the new link.
274 * The index being constructed will reference the same container
275 * as @c other, but it will refer to element @c elemID.
277 template <class STORABLE>
279 ElementLink<STORABLE>::ElementLink (const ElementLink& other,
281 : Base (other, elemID)
287 * @brief Construct a link from a DataLink and an index.
288 * @param dlink Link to the container.
289 * @param index The index of the element within the container.
291 template <class STORABLE>
293 ElementLink<STORABLE>::ElementLink (const DataLink<STORABLE>& dlink,
295 : Base (dlink, index)
301 * @brief Constructor allowing a derived -> base conversion.
303 template <class STORABLE>
306 ElementLink<STORABLE>::ElementLink (const ElementLink<U>& other)
308 (SG::ElementLinkTraits<U>*)0,
315 * @brief Return a pointer to the currently-referenced container object.
316 * @return A pointer to an object of the type given by @a clid,
317 * or null on a failure (or if the reference is null).
319 template <class STORABLE>
321 typename ElementLink<STORABLE>::const_pointer
322 ElementLink<STORABLE>::getDataPtr() const
324 return reinterpret_cast<const_pointer> (this->storable());
329 * @brief Return a pointer to the currently-referenced container object.
330 * @return A pointer to an object of the type given by @a clid,
331 * or null on a failure (or if the reference is null).
333 template <class STORABLE>
335 typename ElementLink<STORABLE>::pointer
336 ElementLink<STORABLE>::getDataNonConstPtr()
338 return reinterpret_cast<pointer> (this->storableNonConst());
343 * @brief Return a link to the currently-referenced container object.
345 template <class STORABLE>
347 DataLink<STORABLE> ElementLink<STORABLE>::getDataLink()
349 return DataLink<STORABLE> (this->key(), this->proxyHolder());
354 * @brief Return a link to the currently-referenced container object.
356 template <class STORABLE>
358 const DataLink<STORABLE> ElementLink<STORABLE>::getDataLink() const
360 return DataLink<STORABLE> (this->key(), this->proxyHolder());
365 * @brief Return a pointer to the currently-referenced container object.
367 template <class STORABLE>
369 typename ElementLink<STORABLE>::BaseConstPointer
370 ElementLink<STORABLE>::getStorableObjectPointer() const
377 * @brief Return a reference to the currently-referenced container object.
379 template <class STORABLE>
381 typename ElementLink<STORABLE>::BaseConstReference
382 ElementLink<STORABLE>::getStorableObjectRef() const
384 return *getDataPtr();
389 * @brief Return a pointer to the referenced element.
391 * Be aware: if the element is a pointer, then this will yield
392 * a pointer to a pointer.
394 template <class STORABLE>
396 typename ElementLink<STORABLE>::ElementConstPointer
397 ElementLink<STORABLE>::cptr() const
399 ElementConstPointer ret = 0;
400 if (this->getCachedElement (ret))
403 const STORABLE* ptr = this->getDataPtr();
404 if (ptr && IndexingPolicy::isValid(this->storedIndex())) {
405 this->setCachedElement (IndexingPolicy::lookup(this->storedIndex(), *ptr));
406 (void)this->getCachedElement (ret);
413 * @brief Return a reference to the referenced element.
415 * Will throw an exception if the link is not valid.
417 template <class STORABLE>
419 typename ElementLink<STORABLE>::ElementConstReference
420 ElementLink<STORABLE>::operator* () const
422 ElementConstPointer ptr = cptr();
424 SG::throwExcInvalidLink (classID(), this->dataID(), this->key());
430 * @brief Return a pointer to the referenced element.
432 template <class STORABLE>
434 typename ElementLink<STORABLE>::ElementConstPointer
435 ElementLink<STORABLE>::operator->() const
442 * @brief Convert to a pointer to the referenced element.
444 template <class STORABLE>
446 ElementLink<STORABLE>::operator ElementConstPointer () const
453 * @brief Test to see if the link can be dereferenced.
455 * Will throw an exception if the container is not empty and the
456 * referenced element cannot be retrieved.
458 template <class STORABLE>
460 bool ElementLink<STORABLE>::isValid() const
462 // This used to just call cptr(), but that was leading to dangling-pointer
463 // warnings with gcc12 when we were returning ElementLink's by value,
464 // as in ElementLinkVector. Doing it like this allows us to save
465 // a little work, anyway.
466 if (this->hasCachedElement()) return true;
468 const STORABLE* ptr = this->getDataPtr();
469 if (ptr && !ptr->empty() && IndexingPolicy::isValid(this->storedIndex())) {
470 this->setCachedElement (IndexingPolicy::lookup(this->storedIndex(), *ptr));
478 * @brief Test to see if the link can not be dereferenced.
480 template <class STORABLE>
482 bool ElementLink<STORABLE>::operator!() const
489 * @brief Return the cached element, if any.
491 template <class STORABLE>
493 typename ElementLink<STORABLE>::ElementType
494 ElementLink<STORABLE>::cachedElement() const
496 ElementConstPointer ret = 0;
497 if (this->getCachedElement (ret))
499 return ElementType();
504 * @brief Set the link to an element given by index and pointer to container.
505 * @param data Reference to the container (storable).
506 * @param elemID The index of the element within the container.
507 * @param sg Associated store.
508 * @returns True if the link was changed.
510 * If the link is already set, this will return false and leave the
513 * If @c sg is 0, then we take the store from whatever the link's currently
514 * set to. If the link has no current store, then we take the global
517 template <class STORABLE>
520 ElementLink<STORABLE>::toIndexedElement(BaseConstReference data,
522 IProxyDict* sg /*= 0*/)
524 return Base::toIndexedElement (&data, classID(), elemID, sg);
529 * @brief Set the link to an element given by index and pointer to container.
530 * @param data Reference to the container (storable).
531 * @param elemID The index of the element within the container.
532 * @param ctx The event context.
533 * @returns True if the link was changed.
535 * If the link is already set, this will return false and leave the
538 template <class STORABLE>
541 ElementLink<STORABLE>::toIndexedElement(BaseConstReference data,
543 const EventContext& ctx)
545 return Base::toIndexedElement (&data, classID(), elemID, Atlas::proxyDictFromEventContext(ctx));
550 * @brief Set from element pointer and a reference to the container (storable)
551 * @param data Reference to the container (storable).
552 * @param element The element.
553 * @param sg Associated store.
554 * @returns True if the link was changed.
556 * O(N) for sequences!
558 * If the link is already set, this will return false and leave the
561 * If @c sg is 0, then we take the store from whatever the link's currently
562 * set to. If the link has no current store, then we take the global
565 template <class STORABLE>
567 bool ElementLink<STORABLE>::toContainedElement(BaseConstReference data,
569 IProxyDict* sg /*= 0*/)
571 index_type index = this->index();
572 IndexingPolicy::reverseLookup (data, element, index);
573 bool ret = Base::toIndexedElement (&data, classID(), index, sg);
575 this->storeCachedElement (element);
581 * @brief Set from element pointer and a reference to the container (storable)
582 * @param data Reference to the container (storable).
583 * @param element The element.
584 * @param ctx The event context.
585 * @returns True if the link was changed.
587 * O(N) for sequences!
589 * If the link is already set, this will return false and leave the
592 template <class STORABLE>
594 bool ElementLink<STORABLE>::toContainedElement(BaseConstReference data,
596 const EventContext& ctx)
598 index_type index = this->index();
599 IndexingPolicy::reverseLookup (data, element, index);
600 bool ret = Base::toIndexedElement (&data, classID(), index, Atlas::proxyDictFromEventContext(ctx));
602 this->storeCachedElement (element);
608 * @brief Set to point to an element.
609 * @param element The element.
610 * @returns True if the link was changed.
612 * The collection and the element can be specified independently
613 * using @c setElement and @c setStorableObject.
615 * If the link is already set, this will return false and leave the
618 template <class STORABLE>
620 bool ElementLink<STORABLE>::setElement(ElementType element)
622 if (!this->isDefaultIndex() || this->hasCachedElement())
624 this->storeCachedElement (element);
625 const STORABLE* ptr = this->getDataPtr();
627 index_type index = this->index();
628 IndexingPolicy::reverseLookup (*ptr, element, index);
629 this->setIndex (index);
636 * @brief Set link to point to a new container (storable).
637 * @param data Reference to the container (storable).
638 * @param replace True if we can change an existing link.
639 * @param sg Associated store.
640 * @returns True if the link was changed.
642 * If the link is already set, this will return false and leave the
643 * link unchanged unless @c replace is set. The @c replace argument
644 * should be set if the element is now in a new storable container;
645 * e.g. element ptr has been put in a new view container.
647 * If @c sg is 0, then we take the store from whatever the link's currently
648 * set to. If the link has no current store, then we take the global
651 template <class STORABLE>
653 bool ElementLink<STORABLE>::setStorableObject(BaseConstReference data,
654 bool replace /*= false*/,
655 IProxyDict* sg /*= 0*/)
657 bool ret = Base::setStorableObject (&data, classID(), replace, sg);
659 ElementConstPointer elt = 0;
660 if (this->isDefaultIndex() && this->getCachedElement (elt)) {
661 index_type index = this->index();
662 IndexingPolicy::reverseLookup (data, *elt, index);
663 this->setIndex (index);
672 * @brief Set link to point to a new container (storable).
673 * @param data Reference to the container (storable).
674 * @param replace True if we can change an existing link.
675 * @param ctx The event context.
676 * @returns True if the link was changed.
678 * If the link is already set, this will return false and leave the
679 * link unchanged unless @c replace is set. The @c replace argument
680 * should be set if the element is now in a new storable container;
681 * e.g. element ptr has been put in a new view container.
683 template <class STORABLE>
685 bool ElementLink<STORABLE>::setStorableObject(BaseConstReference data,
687 const EventContext& ctx)
689 bool ret = Base::setStorableObject (&data, classID(), replace, Atlas::proxyDictFromEventContext(ctx));
691 ElementConstPointer elt = 0;
692 if (this->isDefaultIndex() && this->getCachedElement (elt)) {
693 index_type index = this->index();
694 IndexingPolicy::reverseLookup (data, *elt, index);
695 this->setIndex (index);
704 * @brief Set the link to an element given by string key and index.
705 * @param dataID Key of the object.
706 * @param elemID The index of the element within the container.
707 * @param sg Associated store.
709 * If @c sg is 0, then we take the store from whatever the link's currently
710 * set to. If the link has no current store, then we take the global
713 template <class STORABLE>
715 void ElementLink<STORABLE>::resetWithKeyAndIndex(const ID_type& dataID,
717 IProxyDict* sg /*= 0*/)
719 Base::resetWithKeyAndIndex (dataID, classID(), elemID, sg);
724 * @brief Set the link to an element given by string key and index.
725 * @param dataID Key of the object.
726 * @param elemID The index of the element within the container.
727 * @param ctx The event context.
729 template <class STORABLE>
731 void ElementLink<STORABLE>::resetWithKeyAndIndex(const ID_type& dataID,
733 const EventContext& ctx)
735 Base::resetWithKeyAndIndex (dataID, classID(), elemID, Atlas::proxyDictFromEventContext(ctx));
740 * @brief Set the link to an element given by string key and index.
741 * @param key Hashed key of the object.
742 * @param elemID The index of the element within the container.
743 * @param sg Associated store.
745 * If @c sg is 0, then we take the store from whatever the link's currently
746 * set to. If the link has no current store, then we take the global
749 template <class STORABLE>
751 void ElementLink<STORABLE>::resetWithKeyAndIndex(sgkey_t key,
753 IProxyDict* sg /*= 0*/)
755 Base::resetWithKeyAndIndex (key, classID(), elemID, sg);
760 * @brief Set the link to an element given by string key and index.
761 * @param key Hashed key of the object.
762 * @param elemID The index of the element within the container.
763 * @param ctx The event context.
765 template <class STORABLE>
767 void ElementLink<STORABLE>::resetWithKeyAndIndex(sgkey_t key,
769 const EventContext& ctx)
771 Base::resetWithKeyAndIndex (key, classID(), elemID, Atlas::proxyDictFromEventContext(ctx));
776 * @brief Return a (void) pointer to the currently-referenced
778 * @return A pointer to an object of the type given by @a clid,
779 * or null on a failure (or if the reference is null).
781 template <class STORABLE>
783 const void* ElementLink<STORABLE>::storable() const
785 typedef STORABLE* fn_t (SG::DataProxy*);
786 fn_t* fn = &SG::DataProxy_cast<STORABLE>;
787 return this->storableBase (reinterpret_cast<castfn_t*> (fn), classID(), true);
792 * @brief Return a (void) pointer to the currently-referenced
794 * @return A pointer to an object of the type given by @a clid,
795 * or null on a failure (or if the reference is null).
797 template <class STORABLE>
799 void* ElementLink<STORABLE>::storableNonConst()
801 typedef STORABLE* fn_t (SG::DataProxy*);
802 fn_t* fn = &SG::DataProxy_cast<STORABLE>;
803 return this->storableBase (reinterpret_cast<castfn_t*> (fn), classID(), false);
808 * @brief Ordering relation for @c ElementLink (less-than)
809 * @param lhs Left-hand-side EL.
810 * @param rhs Right-hand-side EL.
812 template <typename STORABLE>
813 bool operator < (const ElementLink<STORABLE>& lhs,
814 const ElementLink<STORABLE>& rhs)
816 bool lhsDefault = lhs.isDefault();
817 bool rhsDefault = rhs.isDefault();
818 if (lhsDefault && rhsDefault) return false;
819 if (lhsDefault) return true;
820 if (rhsDefault) return false;
821 if (lhs.key() == 0 || rhs.key() == 0 || lhs.isDefaultIndex() || rhs.isDefaultIndex())
822 SG::throwExcIncomparableEL();
823 if (SG::sgkeyLess (lhs.key(), rhs.key())) return true;
824 if (SG::sgkeyLess (rhs.key(), lhs.key())) return false;
825 if (lhs.index() < rhs.index()) return true;
831 * @brief Ordering relation for @c ElementLink (greater-than)
832 * @param lhs Left-hand-side EL.
833 * @param rhs Right-hand-side EL.
835 template <typename STORABLE>
837 bool operator > (const ElementLink<STORABLE>& lhs,
838 const ElementLink<STORABLE>& rhs)
845 * @brief Equality relation for @c ElementLink.
846 * @param lhs Left-hand-side EL.
847 * @param rhs Right-hand-side EL.
849 template <typename STORABLE>
851 bool operator == (const ElementLink<STORABLE>& lhs,
852 const ElementLink<STORABLE>& rhs)
854 return !((lhs < rhs) || (rhs < lhs));
859 * @brief Inequality relation for @c ElementLink.
860 * @param lhs Left-hand-side EL.
861 * @param rhs Right-hand-side EL.
863 template <typename STORABLE>
865 bool operator != (const ElementLink<STORABLE>& lhs,
866 const ElementLink<STORABLE>& rhs)
868 return !(lhs == rhs);
872 namespace SG_detail {
876 * @brief See if an EL is being remapped.
877 * @param sgkey_in Original hashed key of the EL.
878 * @param dum_in Ignored.
879 * @param sgkey_out[out] New hashed key for the EL.
880 * @param dum_out[out] Ignored.
881 * @return True if there is a remapping; false otherwise.
883 * This version catches the cases where the container index type
884 * isn't a @c size_t. We don't support changing the index in this case.
888 bool checkForRemap (IProxyDict* sg,
889 SG::sgkey_t sgkey_in,
891 SG::sgkey_t& sgkey_out,
896 return checkForRemap (sg, sgkey_in, index_in, sgkey_out, index_out);
900 } // namespace SG_detail