ATLAS Offline Software
Loading...
Searching...
No Matches
A/AthLinks/ElementLink.icc
Go to the documentation of this file.
1// Dear emacs, this is -*- c++ -*-
2/*
3 Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
4 */
5#ifndef ATHLINKS_ELEMENTLINK_ICC
6#define ATHLINKS_ELEMENTLINK_ICC
7
8// System include(s):
9#include <stdexcept>
10
11// EDM include(s):
12#include "xAODRootAccessInterfaces/TVirtualEvent.h"
13#include "xAODRootAccessInterfaces/TActiveEvent.h"
14
15////////////////////////////////////////////////////////////////////////////////
16//
17// Implementation of the constructors
18//
19
20template< typename STORABLE >
21ElementLink< STORABLE >::ElementLink()
22 : ElementLinkBase(),
23 m_container( 0 ), m_element( 0 ), m_elementCached( false ),
24 m_event( xAOD::TActiveEvent::event() ) {
25
26}
27
28template< typename STORABLE >
29ElementLink< STORABLE >::ElementLink( xAOD::TVirtualEvent* event )
30 : ElementLinkBase(),
31 m_container( 0 ), m_element( 0 ), m_elementCached( false ),
32 m_event( event ) {
33
34}
35
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 ),
41 m_event( event ) {
42
43 // Get the active event if the user didn't specify one explicitly:
44 if( ! m_event ) {
45 m_event = xAOD::TActiveEvent::event();
46 }
47
48 // Translate the id into a hashed key:
49 m_persKey = m_event->getHash( key );
50}
51
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 ),
57 m_event( event ) {
58
59 // Get the active event if the user didn't specify one explicitly:
60 if( ! m_event ) {
61 m_event = xAOD::TActiveEvent::event();
62 }
63}
64
65template< typename STORABLE >
66ElementLink< STORABLE >::ElementLink( const ID_type& key, index_type index,
67 ElementType element,
68 xAOD::TVirtualEvent* event )
69 : ElementLinkBase( 0, index ),
70 m_container( 0 ), m_element( element ), m_elementCached( true ),
71 m_event( event ) {
72
73 // Get the active event if the user didn't specify one explicitly:
74 if( ! m_event ) {
75 m_event = xAOD::TActiveEvent::event();
76 }
77
78 // Translate the id into a hashed key:
79 m_persKey = m_event->getHash( key );
80}
81
82template< typename STORABLE >
83ElementLink< STORABLE >::ElementLink( sgkey_t id, index_type index,
84 ElementType element,
85 xAOD::TVirtualEvent* event )
86 : ElementLinkBase( id, index ),
87 m_container( 0 ), m_element( element ), m_elementCached( true ),
88 m_event( event ) {
89
90 // Get the active event if the user didn't specify one explicitly:
91 if( ! m_event ) {
92 m_event = xAOD::TActiveEvent::event();
93 }
94}
95
96template< typename STORABLE >
97ElementLink< STORABLE >::ElementLink( BaseConstReference container,
98 index_type index,
99 xAOD::TVirtualEvent* event )
100 : ElementLinkBase( 0, index ),
101 m_container( &container ), m_element( 0 ), m_elementCached( false ),
102 m_event( event ) {
103
104 // Get the active event if the user didn't specify one explicitly:
105 if( ! m_event ) {
106 m_event = xAOD::TActiveEvent::event();
107 }
108
109 // Find the identifier of the container that we received:
110 findIdentifier();
111}
112
113template< typename STORABLE >
114ElementLink< STORABLE >::ElementLink( ElementType element,
115 BaseConstReference container,
116 xAOD::TVirtualEvent* event )
117 : ElementLinkBase(),
118 m_container( &container ), m_element( element ), m_elementCached( true ),
119 m_event( event ) {
120
121 // Get the active event if the user didn't specify one explicitly:
122 if( ! m_event ) {
123 m_event = xAOD::TActiveEvent::event();
124 }
125
126 // Find the identifier of the container that we received:
127 findIdentifier();
128 // Find the index of the specified object within the container:
129 findIndex();
130}
131
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 ) {
137
138}
139
140//
141////////////////////////////////////////////////////////////////////////////////
142
143template< typename STORABLE >
144ElementLink< STORABLE >&
145ElementLink< STORABLE >::operator=( const ElementLink< STORABLE >& rhs ) {
146
147 // Copy the contents of the base class:
148 ElementLinkBase::operator=( rhs );
149
150 // Copy the contents of this class:
151 m_container = rhs.m_container;
152 m_element = rhs.m_element;
153 m_elementCached = rhs.m_elementCached;
154 m_event = rhs.m_event;
155
156 // Return this object:
157 return *this;
158}
159
160////////////////////////////////////////////////////////////////////////////////
161//
162// Implementation of the setter functions
163//
164
165/// This function can be used to set up an existing element link to point at
166/// an indexed element of a specific object in memory. The link needs to ask
167/// the event for the ID of the received object, so the function can take a
168/// bit of time.
169///
170/// @param container The container that the link should point to
171/// @param index The index of the element inside the container that the link
172/// needs to point to
173/// @returns A dummy value. Failure is signalled by an exception.
174///
175template< typename STORABLE >
176bool ElementLink< STORABLE >::toIndexedElement( BaseConstReference container,
177 index_type index ) {
178
179 // Remember the specified parameters:
180 m_container = &container;
181 m_persIndex = index;
182
183 // Find the identifier of this object:
184 findIdentifier();
185
186 // The object is no longer cached:
187 m_element = 0;
188 m_elementCached = false;
189
190 return true;
191}
192
193/// This is probably the slowest function of the class. It first needs to look
194/// up the ID of the received container inside the event, and then needs to
195/// find the index of the object within this container.
196///
197/// Avoid using if at all possible!
198///
199/// @param container The container that the link should point to
200/// @param element The element within the container that the link should
201/// point to
202/// @returns A dymmy value. Failure is signalled by an exception.
203///
204template< typename STORABLE >
205bool ElementLink< STORABLE >::toContainedElement( BaseConstReference container,
206 ElementType element ) {
207
208 // Remember the specified parameters:
209 m_container = &container;
210 m_element = element;
211
212 // Find the identifier of this object:
213 findIdentifier();
214 // Find the index of the element inside the object:
215 findIndex();
216
217 // Assume that the object is correctly cached:
218 m_elementCached = true;
219
220 return true;
221}
222
223/// This function can be used to set the link to point to a new element inside
224/// the container that it already points to. The function is slow, as it needs
225/// to find the index of the element inside the container.
226///
227/// Avoid using if at all possible!
228///
229/// @param element The element within the container that the link should
230/// point to
231/// @returns A dymmy value. Failure is signalled by an exception.
232///
233template< typename STORABLE >
234bool ElementLink< STORABLE >::setElement( ElementType element ) {
235
236 // Remember the specified parameter:
237 m_element = element;
238
239 // Find the index of the element inside the object:
240 findIndex();
241
242 // Assume that the object is correctly cached:
243 m_elementCached = true;
244
245 return true;
246}
247
248/// This function tells the object to start using a new container. It should
249/// be used together with the setElement function most of the time. It is
250/// however a slow function, so please avoid it if possible.
251///
252/// @param data The container that the link should point to
253/// @param replace <code>true</code> if the element pointer will be replaced
254/// @returns A dymmy value. Failure is signalled by an exception.
255///
256template< typename STORABLE >
257bool ElementLink< STORABLE >::setStorableObject( BaseConstReference data,
258 bool replace ) {
259
260 // Remember the specified parameter:
261 m_container = &data;
262
263 // Find the identifier of the container:
264 findIdentifier();
265
266 // Do different things based on the second argument:
267 if( replace ) {
268 // Remove the cached element:
269 m_element = 0;
270 m_elementCached = false;
271 m_persKey = 0;
272 } else {
273 // Try to find the cached element inside the container:
274 findIndex();
275 }
276
277 return true;
278}
279
280/// This is probably the most preferred way of setting an existing ElementLink
281/// to point to a new element. It doesn't need to do any costly lookups.
282///
283/// @param key The user-readable key of the container
284/// @param index The index of the element inside its container
285/// @param event An alternative event object to use
286///
287template< typename STORABLE >
288void
289ElementLink< STORABLE >::resetWithKeyAndIndex( const ID_type& key,
290 index_type index,
291 xAOD::TVirtualEvent* event ) {
292
293 // Remember the new event object:
294 m_event = event;
295 if( ! m_event ) {
296 m_event = xAOD::TActiveEvent::event();
297 }
298
299 // Update the persistent variables:
300 setPersKey( m_event->getHash( key ) );
301 setPersIndex( index );
302
303 return;
304}
305
306/// This is the fastest way of setting an existing ElementLink to point to a
307/// new element. It's just a bit more inconvenient than the function receiving
308/// a string identifier for the container.
309///
310/// @param id A hashed identifier for the container
311/// @param index The index of the element inside its container
312/// @param event An alternative event object to use
313///
314template< typename STORABLE >
315void
316ElementLink< STORABLE >::resetWithKeyAndIndex( sgkey_t id,
317 index_type index,
318 xAOD::TVirtualEvent* event ) {
319
320 // Remember the new event object:
321 m_event = event;
322 if( ! m_event ) {
323 m_event = xAOD::TActiveEvent::event();
324 }
325
326 // Update the persistent variables:
327 setPersKey( id );
328 setPersIndex( index );
329
330 return;
331}
332
333template< typename STORABLE >
334void ElementLink< STORABLE >::reset() {
335
336 // Reset the persistent variables:
337 setPersKey( 0 );
338 setPersIndex( 0 );
339
340 return;
341}
342
343//
344////////////////////////////////////////////////////////////////////////////////
345
346////////////////////////////////////////////////////////////////////////////////
347//
348// Implementation of the accessor functions and operators
349//
350
351template< typename STORABLE >
352typename ElementLink< STORABLE >::BaseConstPointer
353ElementLink< STORABLE >::getStorableObjectPointer() const {
354
355 // Trigger the retrieval of the container/element:
356 cptr();
357 // Return the pointer, not caring if it's a null pointer or not:
358 return m_container;
359}
360
361template< typename STORABLE >
362typename ElementLink< STORABLE >::BaseConstReference
363ElementLink< STORABLE >::getStorableObjectRef() const {
364
365 // Trigger the retrieval of the container/element:
366 cptr();
367 // Check if a container is now available:
368 if( ! m_container ) {
369 throw std::runtime_error( "ElementLink::getStorableObjectRef "
370 "No container is available" );
371 }
372
373 // Return a reference to the container:
374 return *m_container;
375}
376
377template< typename STORABLE >
378const typename ElementLink< STORABLE >::ID_type&
379ElementLink< STORABLE >::dataID() const {
380
381 return m_event->getName( persKey() );
382}
383
384template< typename STORABLE >
385bool ElementLink< STORABLE >::operator==( const ElementLink& rhs ) const {
386
387 return ( ( key() == rhs.key() ) && ( index() == rhs.index() ) );
388}
389
390template< typename STORABLE >
391bool ElementLink< STORABLE >::operator!=( const ElementLink& rhs ) const {
392
393 return ( ! ( *this == rhs ) );
394}
395
396template< typename STORABLE >
397typename ElementLink< STORABLE >::ElementConstReference
398ElementLink< STORABLE >::operator*() const {
399
400 // Access the pointer:
401 ElementConstPointer ptr = cptr();
402 // Check if it could be retrieved:
403 if( ! ptr ) {
404 throw std::runtime_error( "ElementLink::operator*() "
405 "Element not available" );
406 }
407
408 // Return the reference:
409 return *ptr;
410}
411
412/// This is the only function in the ElementLink code that tries to retrieve
413/// information from the event.
414///
415/// @returns A constant pointer to the element, or a null pointer if
416/// unsuccessful
417///
418template< typename STORABLE >
419typename ElementLink< STORABLE >::ElementConstPointer
420ElementLink< STORABLE >::cptr() const {
421
422 /// Default key, calculated just once:
423 static const uint32_t DEFAULT_KEY = ( xAOD::TVirtualEvent::DEFAULT_KEY &
424 xAOD::TVirtualEvent::KEY_MASK );
425
426 // If the object is already cached, return right away:
427 if( m_elementCached ) return &m_element;
428 // If we can't retrieve it, sad day for us:
429 if( ( ! m_event ) || ( ! persKey() ) ||
430 ( persKey() == DEFAULT_KEY ) ) return 0;
431
432 // The object should be cached from now on:
433 m_elementCached = true;
434
435 // If the container is cached at least, then things are relatively simple:
436 if( m_container ) {
437 typename STORABLE::size_type index =
438 static_cast< typename STORABLE::size_type >( persIndex() );
439 m_element = ( *m_container )[ index ];
440 return &m_element;
441 }
442
443 // Ask the Event object for the container:
444 if( ! m_event->retrieve( m_container, persKey() ) ) {
445 m_element = 0;
446 m_elementCached = false;
447 return 0;
448 }
449
450 // Get the correct element out of the container:
451 typename STORABLE::size_type index =
452 static_cast< typename STORABLE::size_type >( persIndex() );
453 m_element = ( *m_container )[ index ];
454
455 // Return a pointer to the element:
456 return &m_element;
457}
458
459template< typename STORABLE >
460bool ElementLink< STORABLE >::isValid() const {
461
462 // If we already have the element cached, the answer is simple:
463 if( m_elementCached && m_element ) {
464 return true;
465 }
466
467 /// Default key, calculated just once:
468 static const uint32_t DEFAULT_KEY = ( xAOD::TVirtualEvent::DEFAULT_KEY &
469 xAOD::TVirtualEvent::KEY_MASK );
470
471 // Start with the simple checks:
472 if( ( ! m_event ) || ( ! persKey() ) ||
473 ( persKey() == DEFAULT_KEY ) ) return false;
474
475 // Check whether the container can be accessed:
476 if( ! m_event->retrieve( m_container, persKey(), true ) ) {
477 return false;
478 }
479
480 // Check that the container is large enough:
481 if( m_container->size() <=
482 static_cast< typename STORABLE::size_type >( persIndex() ) ) {
483 return false;
484 }
485
486 // Apparently things should work well:
487 return true;
488}
489
490//
491////////////////////////////////////////////////////////////////////////////////
492
493template< typename STORABLE >
494bool ElementLink< STORABLE >::toTransient() {
495
496 m_container = 0;
497 m_element = 0;
498 m_elementCached = false;
499
500 return true;
501}
502
503/// This function is used internally to find the hashed identifier for a
504/// container that was given to the ElementLink by reference. It throws an
505/// exception if the object can't be found in the event.
506///
507template< typename STORABLE >
508void ElementLink< STORABLE >::findIdentifier() {
509
510 // Ask the event for the identifier of this object:
511 const sgkey_t key = m_event->getKey( m_container );
512 if( ! key ) {
513 throw std::runtime_error( "ElementLink::findIdentifier: Couldn't find "
514 "the received object in the current event" );
515 }
516
517 // Remember this key:
518 m_persKey = key;
519
520 return;
521}
522
523/// This function is used internally to find the index of a given element inside
524/// the container. It has to do a linear search, so it's quite slow...
525///
526template< typename STORABLE >
527void ElementLink< STORABLE >::findIndex() {
528
529 // Check that we have a valid container:
530 if( ! m_container ) {
531 throw std::runtime_error( "ElementLink::findIndex: No valid container" );
532 }
533
534 // Look for the element insied the container:
535 const_iterator el_itr = m_container->begin();
536 const_iterator el_end = m_container->end();
537 for( index_type i = 0; el_itr != el_end; ++el_itr, ++i ) {
538
539 // Check if this is the element that we're looking for:
540 if( *el_itr != m_element ) continue;
541
542 // If yes, we're finished:
543 m_persIndex = i;
544 return;
545 }
546
547 // If we didn't find the element in the container, that's a problem...
548 throw std::runtime_error( "ElementLink::findIndex: Couldn't find element "
549 "in the current container" );
550
551 return;
552}
553
554template <typename STORABLE>
555bool operator< (const ElementLink<STORABLE> &lhs,
556 const ElementLink<STORABLE> &rhs)
557{
558 return std::make_pair(lhs.persKey(), lhs.index()) < std::make_pair(rhs.persKey(), rhs.index());
559}
560
561template <typename STORABLE>
562bool operator> (const ElementLink<STORABLE> &lhs,
563 const ElementLink<STORABLE> &rhs)
564{
565 return rhs < lhs;
566}
567
568#endif // ATHLINKS_ELEMENTLINK_ICC