ATLAS Offline Software
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 
20 template< typename STORABLE >
21 ElementLink< STORABLE >::ElementLink()
22  : ElementLinkBase(),
23  m_container( 0 ), m_element( 0 ), m_elementCached( false ),
24  m_event( xAOD::TActiveEvent::event() ) {
25 
26 }
27 
28 template< typename STORABLE >
29 ElementLink< STORABLE >::ElementLink( xAOD::TVirtualEvent* event )
30  : ElementLinkBase(),
31  m_container( 0 ), m_element( 0 ), m_elementCached( false ),
32  m_event( event ) {
33 
34 }
35 
36 template< typename STORABLE >
37 ElementLink< 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 
52 template< typename STORABLE >
53 ElementLink< 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 
65 template< typename STORABLE >
66 ElementLink< 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 
82 template< typename STORABLE >
83 ElementLink< 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 
96 template< typename STORABLE >
97 ElementLink< 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 
113 template< typename STORABLE >
114 ElementLink< 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 
132 template< typename STORABLE >
133 ElementLink< 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 
143 template< typename STORABLE >
144 ElementLink< STORABLE >&
145 ElementLink< 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 ///
175 template< typename STORABLE >
176 bool 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 ///
204 template< typename STORABLE >
205 bool 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 ///
233 template< typename STORABLE >
234 bool 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 ///
256 template< typename STORABLE >
257 bool 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 ///
287 template< typename STORABLE >
288 void
289 ElementLink< 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 ///
314 template< typename STORABLE >
315 void
316 ElementLink< 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 
333 template< typename STORABLE >
334 void 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 
351 template< typename STORABLE >
352 typename ElementLink< STORABLE >::BaseConstPointer
353 ElementLink< 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 
361 template< typename STORABLE >
362 typename ElementLink< STORABLE >::BaseConstReference
363 ElementLink< 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 
377 template< typename STORABLE >
378 const typename ElementLink< STORABLE >::ID_type&
379 ElementLink< STORABLE >::dataID() const {
380 
381  return m_event->getName( persKey() );
382 }
383 
384 template< typename STORABLE >
385 bool ElementLink< STORABLE >::operator==( const ElementLink& rhs ) const {
386 
387  return ( ( key() == rhs.key() ) && ( index() == rhs.index() ) );
388 }
389 
390 template< typename STORABLE >
391 bool ElementLink< STORABLE >::operator!=( const ElementLink& rhs ) const {
392 
393  return ( ! ( *this == rhs ) );
394 }
395 
396 template< typename STORABLE >
397 typename ElementLink< STORABLE >::ElementConstReference
398 ElementLink< 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 ///
418 template< typename STORABLE >
419 typename ElementLink< STORABLE >::ElementConstPointer
420 ElementLink< 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 
459 template< typename STORABLE >
460 bool 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 
493 template< typename STORABLE >
494 bool 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 ///
507 template< typename STORABLE >
508 void 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 ///
526 template< typename STORABLE >
527 void 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 
554 template <typename STORABLE>
555 bool 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 
561 template <typename STORABLE>
562 bool operator> (const ElementLink<STORABLE> &lhs,
563  const ElementLink<STORABLE> &rhs)
564 {
565  return rhs < lhs;
566 }
567 
568 #endif // ATHLINKS_ELEMENTLINK_ICC