ATLAS Offline Software
A/AthLinks/DataLink.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_DATALINK_ICC
6 #define ATHLINKS_DATALINK_ICC
7 
8 // System include(s):
9 #include <stdexcept>
10 
11 // ROOT include(s):
12 #include <TError.h>
13 
14 // EDM include(s):
15 #include "xAODRootAccessInterfaces/TVirtualEvent.h"
16 #include "xAODRootAccessInterfaces/TActiveEvent.h"
17 
18 ////////////////////////////////////////////////////////////////////////////////
19 //
20 // Implementation of the different constructors
21 //
22 
23 /// This constructor creates an object that will either return a null pointer
24 /// when asked for one, or throw an exception when trying to de-reference it.
25 ///
26 template< typename STORABLE >
27 DataLink< STORABLE >::DataLink()
28  : DataLinkBase(), m_object( 0 ), m_event( xAOD::TActiveEvent::event() ) {
29 
30 }
31 
32 /// This constructor allows the user to create a null-pointer that uses an
33 /// alternative TVirtualEvent object as its store.
34 ///
35 /// @param event Pointer to an alternative TVirtualEvent object
36 ///
37 template< typename STORABLE >
38 DataLink< STORABLE >::DataLink( xAOD::TVirtualEvent* event )
39  : DataLinkBase(), m_object( 0 ), m_event( event ) {
40 
41 }
42 
43 /// This constructor can be used to create a valid object based on a reference
44 /// to an existing object, that's already part of the current event. In case
45 /// the object can not be found in the current event, the constructor throws
46 /// an exception.
47 ///
48 /// @param data A constant reference to the object that the smart pointer
49 /// should point to
50 /// @param event Pointer to an alternative TVirtualEvent object
51 ///
52 template< typename STORABLE >
53 DataLink< STORABLE >::DataLink( const_reference data,
54  xAOD::TVirtualEvent* event )
55  : DataLinkBase(), m_object( &data ), m_event( event ) {
56 
57  // Get the active event if the user didn't specify one explicitly:
58  if( ! m_event ) {
59  m_event = xAOD::TActiveEvent::event();
60  }
61 
62  // Find the identifier of the object that we received:
63  findIdentifier();
64 }
65 
66 /// This constructor can be used to create a valid object based on a pointer
67 /// to an existing object, that's already part of the current event. In case
68 /// the object can not be found in the current event, the constructor throws
69 /// an exception.
70 ///
71 /// @param data A constant pointer to the object that the smart pointer
72 /// should point to
73 /// @param event Pointer to an alternative TVirtualEvent object
74 ///
75 template< typename STORABLE >
76 DataLink< STORABLE >::DataLink( const_pointer data, xAOD::TVirtualEvent* event )
77  : DataLinkBase(), m_object( data ), m_event( event ) {
78 
79  // Get the active event if the user didn't specify one explicitly:
80  if( ! m_event ) {
81  m_event = xAOD::TActiveEvent::event();
82  }
83 
84  // Find the identifier of the object that we received:
85  findIdentifier();
86 }
87 
88 /// This is probably the most convenient version of the constructors.
89 /// It receives a string identifier (branch name) for the object that the smart
90 /// pointer should reference.
91 ///
92 /// @param id A string identifier for the object to be referenced
93 /// @param event Pointer to an alternative TVirtualEvent object
94 ///
95 template< typename STORABLE >
96 DataLink< STORABLE >::DataLink( const ID_type& id, xAOD::TVirtualEvent* event )
97  : DataLinkBase(), m_object( 0 ), m_event( event ) {
98 
99  // Get the active event if the user didn't specify one explicitly:
100  if( ! m_event ) {
101  m_event = xAOD::TActiveEvent::event();
102  }
103 
104  // Translate the id into a hashed key:
105  m_persKey = m_event->getHash( id );
106 }
107 
108 /// This is the most cost-effective of the constructors after the default
109 /// one. It relies on the user knowing exactly what hashed key to ask for
110 /// for the target object.
111 ///
112 /// @param key A hashed key identifying the object to be referenced
113 /// @param event Pointer to an alternative TVirtualEvent object
114 ///
115 template< typename STORABLE >
116 DataLink< STORABLE >::DataLink( sgkey_t key, xAOD::TVirtualEvent* event )
117  : DataLinkBase( key ), m_object( 0 ), m_event( event ) {
118 
119  // Get the active event if the user didn't specify one explicitly:
120  if( ! m_event ) {
121  m_event = xAOD::TActiveEvent::event();
122  }
123 }
124 
125 /// Simple copy-constructor. It just copies the persistent information
126 /// from the base class together with the TVirtualEvent pointer that the parent
127 /// class had.
128 ///
129 /// @param parent The parent object to be copied
130 ///
131 template< typename STORABLE >
132 template< typename T >
133 DataLink< STORABLE >::DataLink( const DataLink< T >& parent )
134  : DataLinkBase( parent ), m_object( 0 ), m_event( parent.m_event ) {
135 
136 }
137 
138 //
139 ////////////////////////////////////////////////////////////////////////////////
140 
141 ////////////////////////////////////////////////////////////////////////////////
142 //
143 // Implementation of the different setter functions
144 //
145 
146 /// This function should be used to set up the object when your code has a
147 /// reference to the target object.
148 ///
149 /// The function will throw an exception if the supplied object can't be found
150 /// in the current event.
151 ///
152 /// @param data A reference to the target object
153 ///
154 template< typename STORABLE >
155 void DataLink< STORABLE >::toStorableObject( const_reference data ) {
156 
157  // Remember the pointer:
158  m_object = &data;
159 
160  // Now try to look up the object in the store:
161  findIdentifier();
162 
163  return;
164 }
165 
166 /// This function sets up the object to point at the default object of the
167 /// template type in the event. It can be useful when only one object of a
168 /// given type is available.
169 ///
170 template< typename STORABLE >
171 void DataLink< STORABLE >::toDefaultObject() {
172 
173  // Reset the cached pointer:
174  m_object = 0;
175 
176  // Set a special value for the persistent variable:
177  setPersKey( xAOD::TVirtualEvent::DEFAULT_KEY );
178 
179  return;
180 }
181 
182 /// This is one of the more convenient functions. It sets up the smart pointer
183 /// using a user-readable string idetifier for the target object.
184 ///
185 /// @param id A string identifier (branch name) for the target object
186 ///
187 template< typename STORABLE >
188 void DataLink< STORABLE >::toIdentifiedObject( const ID_type& id ) {
189 
190  // Check if we have a valid event:
191  if( ! m_event ) {
192  throw std::runtime_error( "DataLink::toIdentifiedObject: No valid "
193  "TVirtualEvent pointer available (key: " +
194  id + ")" );
195  }
196 
197  // Reset the cached pointer:
198  m_object = 0;
199 
200  // Set the persistent key using this identifier:
201  m_persKey = m_event->getHash( id );
202 
203  return;
204 }
205 
206 /// This function hardly has to do anything. It just sets the received key as
207 /// the persistent information for the object, and resets its internals.
208 ///
209 /// @param key The hashed key for the target object
210 ///
211 template< typename STORABLE >
212 void DataLink< STORABLE >::toIdentifiedObject( sgkey_t key ) {
213 
214  // Reset the cached pointer:
215  m_object = 0;
216 
217  // Set the persistent key:
218  m_persKey = key;
219 
220  return;
221 }
222 
223 //
224 ////////////////////////////////////////////////////////////////////////////////
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 //
228 // Implementation of the different accessor functions
229 //
230 
231 /// This operator can be used to get a constant reference to the object.
232 /// In most cases though one should probably use the -> operator instead.
233 /// The code throws an exception if the target object is not available.
234 ///
235 /// @returns A constant reference to the target object if available
236 ///
237 template< class STORABLE >
238 typename DataLink< STORABLE >::const_reference
239 DataLink< STORABLE >::operator*() const {
240 
241  // See if we have a valid object:
242  const_pointer ptr = cptr();
243 
244  // If not, throw an exception:
245  if( ! ptr ) {
246  throw std::runtime_error( "DataLink::operator*: No valid target for the "
247  "object" );
248  }
249 
250  // Return the reference. Notice that we're not using the temporary variable
251  // here...
252  return *m_object;
253 }
254 
255 /// This function is doing most of the heavy lifting. It interacts with the
256 /// TVirtualEvent object to deliver a pointer to the target object to the user.
257 ///
258 /// @returns A constant pointer to the target object if available, a
259 /// null pointer if not
260 ///
261 template< class STORABLE >
262 typename DataLink< STORABLE >::const_pointer
263 DataLink< STORABLE >::cptr() const {
264 
265  // If the object is already cached, return right away:
266  if( m_object || ( ! m_event ) ) return m_object;
267 
268  /// Default key, calculated just once:
269  static const uint32_t DEFAULT_KEY = ( xAOD::TVirtualEvent::DEFAULT_KEY &
270  xAOD::TVirtualEvent::KEY_MASK );
271 
272  // If the key is nonsensical, fail silently:
273  if( ( ! persKey() ) || ( persKey() == DEFAULT_KEY ) ) {
274  return 0;
275  }
276 
277  // Ask the event object for the object in question:
278  if( ! m_event->retrieve( m_object, m_persKey ) ) {
279  m_object = 0;
280  }
281 
282  // Return what we acquired:
283  return m_object;
284 }
285 
286 template< class STORABLE >
287 bool DataLink< STORABLE >::isValid() const {
288 
289  // If we have an object already cached, the answer is easy:
290  if( m_object ) {
291  return true;
292  }
293 
294  // If there's no event object, we won't be able to retrieve anything:
295  if( ! m_event ) {
296  return false;
297  }
298 
299  /// Default key, calculated just once:
300  static const uint32_t DEFAULT_KEY = ( xAOD::TVirtualEvent::DEFAULT_KEY &
301  xAOD::TVirtualEvent::KEY_MASK );
302 
303  // Check for non-valid keys:
304  if( ( ! persKey() ) || ( persKey() == DEFAULT_KEY ) ) {
305  return false;
306  }
307 
308  // Try retrieving the object:
309  if( ! m_event->retrieve( m_object, m_persKey, true ) ) {
310  return false;
311  }
312 
313  // Apparently the link can be de-referenced:
314  return true;
315 }
316 
317 template< typename STORABLE >
318 const typename DataLink< STORABLE >::ID_type&
319 DataLink< STORABLE >::dataID() const {
320 
321  return m_event->getName( persKey() );
322 }
323 
324 //
325 ////////////////////////////////////////////////////////////////////////////////
326 
327 /// This function is just here to enable us compiling the same EDM code as
328 /// we do offline. We don't actually need to prepare this object for being
329 /// written out, it's always in a consistent state.
330 ///
331 /// @returns A dummy value. Just to have the same signature as the offline
332 /// function.
333 ///
334 template< class STORABLE >
335 bool DataLink< STORABLE >::toPersistent() {
336 
337  return true;
338 }
339 
340 /// This function just resets the cached pointer when ROOT streams in a new
341 /// object from a TBranch.
342 ///
343 /// @returns A dummy value. Just to have the same signature as the offline
344 /// function.
345 ///
346 template< class STORABLE >
347 bool DataLink< STORABLE >::toTransient() {
348 
349  m_object = 0;
350  return true;
351 }
352 
353 /// This function is used internally to find the hashed identifier for an object
354 /// that was given to the DataLink either by reference or pointer. It throws an
355 /// exception if the object can't be found in the event.
356 ///
357 template< class STORABLE >
358 void DataLink< STORABLE >::findIdentifier() {
359 
360  // Ask the event for the identifier of this object:
361  const sgkey_t key = m_event->getKey( m_object );
362  if( ! key ) {
363  Warning( "DataLink::findIdentifier",
364  "Couldn't find the received object in the current event" );
365  }
366 
367  // Remember this key:
368  m_persKey = key;
369 
370  return;
371 }
372 
373 #endif // ATHLINKS_DATALINK_ICC