1// Dear emacs, this is -*- c++ -*-
3 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
5#ifndef ATHLINKS_ELEMENTLINK_ICC
6#define ATHLINKS_ELEMENTLINK_ICC
12#include "xAODRootAccessInterfaces/TVirtualEvent.h"
13#include "xAODRootAccessInterfaces/TActiveEvent.h"
15////////////////////////////////////////////////////////////////////////////////
17// Implementation of the constructors
20template< typename STORABLE >
21ElementLink< STORABLE >::ElementLink()
23 m_container( 0 ), m_element( 0 ), m_elementCached( false ),
24 m_event( xAOD::TActiveEvent::event() ) {
28template< typename STORABLE >
29ElementLink< STORABLE >::ElementLink( xAOD::TVirtualEvent* event )
31 m_container( 0 ), m_element( 0 ), m_elementCached( false ),
36template< typename STORABLE >
37ElementLink< STORABLE >::ElementLink( const ID_type& key, index_type index,
38 xAOD::TVirtualEvent* event )
39 : ElementLinkBase( 0, index ),
40 m_container( 0 ), m_element( 0 ), m_elementCached( false ),
43 // Get the active event if the user didn't specify one explicitly:
45 m_event = xAOD::TActiveEvent::event();
48 // Translate the id into a hashed key:
49 m_persKey = m_event->getHash( key );
52template< typename STORABLE >
53ElementLink< STORABLE >::ElementLink( sgkey_t id, index_type index,
54 xAOD::TVirtualEvent* event )
55 : ElementLinkBase( id, index ),
56 m_container( 0 ), m_element( 0 ), m_elementCached( false ),
59 // Get the active event if the user didn't specify one explicitly:
61 m_event = xAOD::TActiveEvent::event();
65template< typename STORABLE >
66ElementLink< STORABLE >::ElementLink( const ID_type& key, index_type index,
68 xAOD::TVirtualEvent* event )
69 : ElementLinkBase( 0, index ),
70 m_container( 0 ), m_element( element ), m_elementCached( true ),
73 // Get the active event if the user didn't specify one explicitly:
75 m_event = xAOD::TActiveEvent::event();
78 // Translate the id into a hashed key:
79 m_persKey = m_event->getHash( key );
82template< typename STORABLE >
83ElementLink< STORABLE >::ElementLink( sgkey_t id, index_type index,
85 xAOD::TVirtualEvent* event )
86 : ElementLinkBase( id, index ),
87 m_container( 0 ), m_element( element ), m_elementCached( true ),
90 // Get the active event if the user didn't specify one explicitly:
92 m_event = xAOD::TActiveEvent::event();
96template< typename STORABLE >
97ElementLink< STORABLE >::ElementLink( BaseConstReference container,
99 xAOD::TVirtualEvent* event )
100 : ElementLinkBase( 0, index ),
101 m_container( &container ), m_element( 0 ), m_elementCached( false ),
104 // Get the active event if the user didn't specify one explicitly:
106 m_event = xAOD::TActiveEvent::event();
109 // Find the identifier of the container that we received:
113template< typename STORABLE >
114ElementLink< STORABLE >::ElementLink( ElementType element,
115 BaseConstReference container,
116 xAOD::TVirtualEvent* event )
118 m_container( &container ), m_element( element ), m_elementCached( true ),
121 // Get the active event if the user didn't specify one explicitly:
123 m_event = xAOD::TActiveEvent::event();
126 // Find the identifier of the container that we received:
128 // Find the index of the specified object within the container:
132template< typename STORABLE >
133ElementLink< STORABLE >::ElementLink( const ElementLink& parent )
134 : ElementLinkBase( parent ),
135 m_container( parent.m_container ), m_element( parent.m_element ),
136 m_elementCached( parent.m_elementCached ), m_event( parent.m_event ) {
140template< typename STORABLE >
142ElementLink< STORABLE >::ElementLink( const ID_type& key, index_type index,
143 const EventContext& )
144 : ElementLink( key, index ) {}
146template< typename STORABLE >
148ElementLink< STORABLE >::ElementLink( sgkey_t id, index_type index,
149 const EventContext& )
150 : ElementLink( id, index ) {}
152template< typename STORABLE >
154ElementLink< STORABLE >::ElementLink( const ID_type& key, index_type index, ElementType element,
155 const EventContext& )
156 : ElementLink( key, index, element ) {}
158template< typename STORABLE >
160ElementLink< STORABLE >::ElementLink( sgkey_t id, index_type index, ElementType element,
161 const EventContext& )
162 : ElementLink( id, index, element ) {}
164template< typename STORABLE >
166ElementLink< STORABLE >::ElementLink( BaseConstReference container, index_type index,
167 const EventContext& )
168 : ElementLink( container, index ) {}
170template< typename STORABLE >
172ElementLink< STORABLE >::ElementLink( ElementType element, BaseConstReference container,
173 const EventContext& )
174 : ElementLink( element, container ) {}
177////////////////////////////////////////////////////////////////////////////////
179template< typename STORABLE >
180ElementLink< STORABLE >&
181ElementLink< STORABLE >::operator=( const ElementLink< STORABLE >& rhs ) {
183 // Copy the contents of the base class:
184 ElementLinkBase::operator=( rhs );
186 // Copy the contents of this class:
187 m_container = rhs.m_container;
188 m_element = rhs.m_element;
189 m_elementCached = rhs.m_elementCached;
190 m_event = rhs.m_event;
192 // Return this object:
196////////////////////////////////////////////////////////////////////////////////
198// Implementation of the setter functions
201/// This function can be used to set up an existing element link to point at
202/// an indexed element of a specific object in memory. The link needs to ask
203/// the event for the ID of the received object, so the function can take a
206/// @param container The container that the link should point to
207/// @param index The index of the element inside the container that the link
209/// @returns A dummy value. Failure is signalled by an exception.
211template< typename STORABLE >
212bool ElementLink< STORABLE >::toIndexedElement( BaseConstReference container,
215 // Remember the specified parameters:
216 m_container = &container;
219 // Find the identifier of this object:
222 // The object is no longer cached:
224 m_elementCached = false;
229/// This is probably the slowest function of the class. It first needs to look
230/// up the ID of the received container inside the event, and then needs to
231/// find the index of the object within this container.
233/// Avoid using if at all possible!
235/// @param container The container that the link should point to
236/// @param element The element within the container that the link should
238/// @returns A dymmy value. Failure is signalled by an exception.
240template< typename STORABLE >
241bool ElementLink< STORABLE >::toContainedElement( BaseConstReference container,
242 ElementType element ) {
244 // Remember the specified parameters:
245 m_container = &container;
248 // Find the identifier of this object:
250 // Find the index of the element inside the object:
253 // Assume that the object is correctly cached:
254 m_elementCached = true;
259/// This function can be used to set the link to point to a new element inside
260/// the container that it already points to. The function is slow, as it needs
261/// to find the index of the element inside the container.
263/// Avoid using if at all possible!
265/// @param element The element within the container that the link should
267/// @returns A dymmy value. Failure is signalled by an exception.
269template< typename STORABLE >
270bool ElementLink< STORABLE >::setElement( ElementType element ) {
272 // Remember the specified parameter:
275 // Find the index of the element inside the object:
278 // Assume that the object is correctly cached:
279 m_elementCached = true;
284/// This function tells the object to start using a new container. It should
285/// be used together with the setElement function most of the time. It is
286/// however a slow function, so please avoid it if possible.
288/// @param data The container that the link should point to
289/// @param replace <code>true</code> if the element pointer will be replaced
290/// @returns A dymmy value. Failure is signalled by an exception.
292template< typename STORABLE >
293bool ElementLink< STORABLE >::setStorableObject( BaseConstReference data,
296 // Remember the specified parameter:
299 // Find the identifier of the container:
302 // Do different things based on the second argument:
304 // Remove the cached element:
306 m_elementCached = false;
309 // Try to find the cached element inside the container:
316/// This is probably the most preferred way of setting an existing ElementLink
317/// to point to a new element. It doesn't need to do any costly lookups.
319/// @param key The user-readable key of the container
320/// @param index The index of the element inside its container
321/// @param event An alternative event object to use
323template< typename STORABLE >
325ElementLink< STORABLE >::resetWithKeyAndIndex( const ID_type& key,
327 xAOD::TVirtualEvent* event ) {
329 // Remember the new event object:
332 m_event = xAOD::TActiveEvent::event();
335 // Update the persistent variables:
336 setPersKey( m_event->getHash( key ) );
337 setPersIndex( index );
342/// This is the fastest way of setting an existing ElementLink to point to a
343/// new element. It's just a bit more inconvenient than the function receiving
344/// a string identifier for the container.
346/// @param id A hashed identifier for the container
347/// @param index The index of the element inside its container
348/// @param event An alternative event object to use
350template< typename STORABLE >
352ElementLink< STORABLE >::resetWithKeyAndIndex( sgkey_t id,
354 xAOD::TVirtualEvent* event ) {
356 // Remember the new event object:
359 m_event = xAOD::TActiveEvent::event();
362 // Update the persistent variables:
364 setPersIndex( index );
369template< typename STORABLE >
370void ElementLink< STORABLE >::reset() {
372 // Reset the persistent variables:
380////////////////////////////////////////////////////////////////////////////////
382////////////////////////////////////////////////////////////////////////////////
384// Implementation of the accessor functions and operators
387template< typename STORABLE >
388typename ElementLink< STORABLE >::BaseConstPointer
389ElementLink< STORABLE >::getStorableObjectPointer() const {
391 // Trigger the retrieval of the container/element:
393 // Return the pointer, not caring if it's a null pointer or not:
397template< typename STORABLE >
398typename ElementLink< STORABLE >::BaseConstReference
399ElementLink< STORABLE >::getStorableObjectRef() const {
401 // Trigger the retrieval of the container/element:
403 // Check if a container is now available:
404 if( ! m_container ) {
405 throw std::runtime_error( "ElementLink::getStorableObjectRef "
406 "No container is available" );
409 // Return a reference to the container:
413template< typename STORABLE >
414const typename ElementLink< STORABLE >::ID_type&
415ElementLink< STORABLE >::dataID() const {
417 return m_event->getName( persKey() );
420template< typename STORABLE >
421bool ElementLink< STORABLE >::operator==( const ElementLink& rhs ) const {
423 return ( ( key() == rhs.key() ) && ( index() == rhs.index() ) );
426template< typename STORABLE >
427bool ElementLink< STORABLE >::operator!=( const ElementLink& rhs ) const {
429 return ( ! ( *this == rhs ) );
432template< typename STORABLE >
433typename ElementLink< STORABLE >::ElementConstReference
434ElementLink< STORABLE >::operator*() const {
436 // Access the pointer:
437 ElementConstPointer ptr = cptr();
438 // Check if it could be retrieved:
440 throw std::runtime_error( "ElementLink::operator*() "
441 "Element not available" );
444 // Return the reference:
448/// This is the only function in the ElementLink code that tries to retrieve
449/// information from the event.
451/// @returns A constant pointer to the element, or a null pointer if
454template< typename STORABLE >
455typename ElementLink< STORABLE >::ElementConstPointer
456ElementLink< STORABLE >::cptr() const {
458 /// Default key, calculated just once:
459 static const uint32_t DEFAULT_KEY = ( xAOD::TVirtualEvent::DEFAULT_KEY &
460 xAOD::TVirtualEvent::KEY_MASK );
462 // If the object is already cached, return right away:
463 if( m_elementCached ) return &m_element;
464 // If we can't retrieve it, sad day for us:
465 if( ( ! m_event ) || ( ! persKey() ) ||
466 ( persKey() == DEFAULT_KEY ) ) return 0;
468 // The object should be cached from now on:
469 m_elementCached = true;
471 // If the container is cached at least, then things are relatively simple:
473 typename STORABLE::size_type index =
474 static_cast< typename STORABLE::size_type >( persIndex() );
475 m_element = ( *m_container )[ index ];
479 // Ask the Event object for the container:
480 if( ! m_event->retrieve( m_container, persKey() ) ) {
482 m_elementCached = false;
486 // Get the correct element out of the container:
487 typename STORABLE::size_type index =
488 static_cast< typename STORABLE::size_type >( persIndex() );
489 m_element = ( *m_container )[ index ];
491 // Return a pointer to the element:
495template< typename STORABLE >
496bool ElementLink< STORABLE >::isValid() const {
498 // If we already have the element cached, the answer is simple:
499 if( m_elementCached && m_element ) {
503 /// Default key, calculated just once:
504 static const uint32_t DEFAULT_KEY = ( xAOD::TVirtualEvent::DEFAULT_KEY &
505 xAOD::TVirtualEvent::KEY_MASK );
507 // Start with the simple checks:
508 if( ( ! m_event ) || ( ! persKey() ) ||
509 ( persKey() == DEFAULT_KEY ) ) return false;
511 // Check whether the container can be accessed:
512 if( ! m_event->retrieve( m_container, persKey(), true ) ) {
516 // Check that the container is large enough:
517 if( m_container->size() <=
518 static_cast< typename STORABLE::size_type >( persIndex() ) ) {
522 // Apparently things should work well:
527////////////////////////////////////////////////////////////////////////////////
529template< typename STORABLE >
530bool ElementLink< STORABLE >::toTransient() {
534 m_elementCached = false;
539/// This function is used internally to find the hashed identifier for a
540/// container that was given to the ElementLink by reference. It throws an
541/// exception if the object can't be found in the event.
543template< typename STORABLE >
544void ElementLink< STORABLE >::findIdentifier() {
546 // Ask the event for the identifier of this object:
547 const sgkey_t key = m_event->getKey( m_container );
549 throw std::runtime_error( "ElementLink::findIdentifier: Couldn't find "
550 "the received object in the current event" );
553 // Remember this key:
559/// This function is used internally to find the index of a given element inside
560/// the container. It has to do a linear search, so it's quite slow...
562template< typename STORABLE >
563void ElementLink< STORABLE >::findIndex() {
565 // Check that we have a valid container:
566 if( ! m_container ) {
567 throw std::runtime_error( "ElementLink::findIndex: No valid container" );
570 // Look for the element insied the container:
571 const_iterator el_itr = m_container->begin();
572 const_iterator el_end = m_container->end();
573 for( index_type i = 0; el_itr != el_end; ++el_itr, ++i ) {
575 // Check if this is the element that we're looking for:
576 if( *el_itr != m_element ) continue;
578 // If yes, we're finished:
583 // If we didn't find the element in the container, that's a problem...
584 throw std::runtime_error( "ElementLink::findIndex: Couldn't find element "
585 "in the current container" );
590template <typename STORABLE>
591bool operator< (const ElementLink<STORABLE> &lhs,
592 const ElementLink<STORABLE> &rhs)
594 return std::make_pair(lhs.persKey(), lhs.index()) < std::make_pair(rhs.persKey(), rhs.index());
597template <typename STORABLE>
598bool operator> (const ElementLink<STORABLE> &lhs,
599 const ElementLink<STORABLE> &rhs)
604#endif // ATHLINKS_ELEMENTLINK_ICC