ATLAS Offline Software
ElementLinkCnv_p2.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 /** @file ElementLinkCnv_p2.icc
6  * @brief This file contains the implementation for the ElementLinkCnv_p2 template methods.
7  * @author R.D.Schaffer@cern.ch
8  **/
9 
10 #include <stdexcept>
11 
12 #include "AthLinks/ElementLink.h"
13 #include "ElementLinkContNames_p2.h"
14 #include "AthenaKernel/ThinningCache.h"
15 #include "AthenaKernel/ThinningDecisionBase.h"
16 #include "AthenaKernel/getThinningCache.h"
17 
18 //#define ELLINK_DEBUG
19 
20 
21 template <typename LINK_TYPE>
22 inline
23 ElementLinkCnv_p2<LINK_TYPE>::State::State()
24 {
25  // Init both last names
26  m_lastNameFound = defaultLastName();
27  m_lastNameAdded = *m_lastNameFound;
28 }
29 
30 
31 template <typename LINK_TYPE>
32 inline
33 ElementLinkCnv_p2<LINK_TYPE>::State::State (ElementLinkContNames_p2& lookupTable)
34 {
35  reset (lookupTable);
36 }
37 
38 
39 template <typename LINK_TYPE>
40 inline
41 ElementLinkCnv_p2<LINK_TYPE>::State::State (const ElementLinkContNames_p2& lookupTable)
42 {
43  reset (lookupTable);
44 }
45 
46 
47 template <typename LINK_TYPE>
48 inline
49 const std::string*
50 ElementLinkCnv_p2<LINK_TYPE>::State::defaultLastName () const
51 {
52  static const std::string lastName = "NO LAST NAME";
53  return &lastName;
54 }
55 
56 
57 template <typename LINK_TYPE>
58 inline
59 void
60 ElementLinkCnv_p2<LINK_TYPE>::State::reset(ElementLinkContNames_p2& lookupTable)
61 {
62  // Save lookup table and reset element link index and map
63  m_lookupTable = &lookupTable;
64  m_clookupTable = 0;
65  m_nameIndexMap.clear();
66  m_lastNameFound = defaultLastName();
67  m_lastNameAdded = *m_lastNameFound;
68  m_lastNameIndex = 0;
69 }
70 
71 
72 template <typename LINK_TYPE>
73 inline
74 void
75 ElementLinkCnv_p2<LINK_TYPE>::State::reset(const ElementLinkContNames_p2& lookupTable)
76 {
77  // Save lookup table and reset element link index and map
78  m_lookupTable = 0;
79  m_clookupTable = &lookupTable;
80  m_nameIndexMap.clear();
81  m_lastNameFound = defaultLastName();
82  m_lastNameAdded = *m_lastNameFound;
83  m_lastNameIndex = 0xFFFFFFFF;
84 }
85 
86 
87 //********************************************************************
88 
89 
90 template <typename LINK_TYPE>
91 inline
92 ElementLinkCnv_p2<LINK_TYPE>::
93 ElementLinkCnv_p2()
94  : m_isPersistible (false)
95 {
96 }
97 
98 
99 template <typename LINK_TYPE>
100 inline
101 ElementLinkCnv_p2<LINK_TYPE>::
102 ElementLinkCnv_p2(bool isPersistible)
103  : m_isPersistible (isPersistible)
104 {
105 }
106 
107 
108 template <typename LINK_TYPE>
109 void ElementLinkCnv_p2<LINK_TYPE>::
110 transToPers (State& state,
111  const Link_t& trans,
112  PersLink_t& pers,
113  const SG::ThinningCache* cache,
114  [[maybe_unused]] MsgStream& msg) const
115 {
116 #ifdef ELLINK_DEBUG
117 // trans.printState();
118 #endif
119 
120  static const std::string s_empty = "";
121  if( trans.isDefault() ) {
122  pers.m_contIndex = getNameIndex(state, s_empty); // Must save empty string for default EL
123  pers.m_elementIndex = 0; // value not used, but 0 compresses better
124  return;
125  }
126 
127  // Check for thinning.
128  if (cache) {
129  const SG::ThinningDecisionBase* dec = cache->thinning (trans.key());
130  if (dec) {
131  // here is the problem: in case the ElementLink was directly created w/
132  // only a pointer to the element, _and_ if the the pointed-at element
133  // has been thinned away, EL::index() will throw b/c
134  // IndexingPolicy::setIndex will fail.
135  std::size_t idx = SG::ThinningDecisionBase::RemovedIdx;
136  try {
137  idx = trans.index();
138  } catch ( const SG::maybe_thinning_error& err ) {
139  // ok. that's the corner case we talked about above.
140 #ifdef ELLINK_DEBUG
141  msg << MSG::DEBUG << "caught a maybe_thinning_error: ["
142  << err.what() << "]"
143  << endmsg
144  << "(this is an expected case of the EL-state-phase-space "
145  << "when thinning is active)"
146  << endmsg;
147 #endif
148  }
149  // Get the updated index:
150  const std::size_t persIdx = dec->index( idx );
151  if (SG::ThinningDecisionBase::RemovedIdx == persIdx) {
152  // this element has been thinned away. So the persistent equivalent
153  // of a null pointer is a default persistent pointer.
154 
155  // Must save empty string for default EL
156  pers.m_contIndex = getNameIndex(state, s_empty);
157  // Index value not used, but 0 compresses better
158  pers.m_elementIndex = 0;
159  }
160  else {
161  Link_t tmp = trans;
162  if (!m_isPersistible) {
163  tmp.toPersistent();
164  }
165  if (!state.m_lookupTable) {
166 #ifdef ELLINK_DEBUG
167  msg << MSG::ERROR
168  << "Empty link name table ptr - must use resetForCnv "
169  << endmsg;
170 #endif
171  }
172  else {
173  // Save container name index and element link index
174  pers.m_contIndex = getNameIndex(state, tmp.dataID());
175  pers.m_elementIndex = persIdx;
176  }
177  }
178 #ifdef ELLINK_DEBUG
179  msg << MSG::INFO << "ElementLinkCnv_p3::transToPer(): SG Container="
180  << ", Key Hash=" << pers.m_SGKeyHash
181  << ", IDX=" << pers.m_elementIndex << endmsg;
182 #endif
183  return;
184  }
185  }
186 
187  Link_t tmp = trans;
188  if (!m_isPersistible) {
189  tmp.toPersistent();
190  }
191  // convert string to index
192  if (!state.m_lookupTable) {
193 #ifdef ELLINK_DEBUG
194  msg << MSG::ERROR
195  << "Empty link name table ptr - must use resetForCnv "
196  << endmsg;
197 #endif
198  }
199  else {
200  // Save container name index and element link index
201  pers.m_contIndex = getNameIndex(state, tmp.dataID());
202  pers.m_elementIndex = SG::sgkeyShort (tmp.index());
203  }
204 #ifdef ELLINK_DEBUG
205  msg << MSG::DEBUG << "ElementLinkCnv_p2::transToPer(): KEY= "
206  << trans.dataID() << ", IDX= " << trans.index()
207  << ", pers cont index= " << pers.m_contIndex
208  << ", ele index= " << pers.m_elementIndex
209  << endmsg;
210 #endif
211 }
212 
213 
214 template <typename LINK_TYPE>
215 void ElementLinkCnv_p2<LINK_TYPE>::
216 transToPers (State& state,
217  const Link_t& trans,
218  PersLink_t& pers,
219  MsgStream& msg) const
220 {
221  transToPers (state, trans, pers,
222  SG::getThinningCache(),
223  msg);
224 }
225 
226 
227 template <typename LINK_TYPE >
228 inline
229 void ElementLinkCnv_p2< LINK_TYPE >
230 ::persToTrans(State& state,
231  const PersLink_t& pers,
232  Link_t& trans,
233  MsgStream& log) const
234 {
235  // convert index to string
236  const std::string* contName = 0;
237  // Get container name from name index
238  getContName(state, pers.m_contIndex, contName, log);
239 #ifdef ELLINK_DEBUG
240  if (contName) {
241  log << MSG::DEBUG << "ElementLinkCnv_p2::PersToTrans(): container name" <<
242  (*contName) << endmsg;
243  }
244  else {
245  log << MSG::ERROR << "ElementLinkCnv_p2::PersToTrans(): container name EMPTY"
246  << endmsg;
247  }
248 #endif
249  if( contName->empty() ) {
250  // If container name is empty, this is a default ElementLink
251  // To be safe, reset to the default state, e.g. may be reusing
252  // existing EL from DataPool
253  trans.reset();
254 #ifdef ELLINK_DEBUG
255  log << MSG::DEBUG << "ElementLinkCnv_p2::PersToTrans(): reading EL in Default state" << endmsg;
256 #endif
257  } else {
258  // reset trans ELink with key and index - changeds to identified state
259  trans.resetWithKeyAndIndex((*contName), pers.m_elementIndex);
260 
261 #ifdef ELLINK_DEBUG
262  log << MSG::DEBUG << "ElementLinkCnv_p2::PersToTrans(): KEY="
263  << (*contName) << ", IDX=" << pers.m_elementIndex << endmsg;
264  if ((*contName) == "NO LAST NAME") {
265  log << MSG::ERROR << "ElementLinkCnv_p2::PersToTrans(): INCORRECT KEY KEY="
266  << (*contName) << ", IDX=" << pers.m_elementIndex << endmsg;
267  }
268 #endif
269  }
270 }
271 
272 
273 template <typename LINK_TYPE>
274 inline
275 void
276 ElementLinkCnv_p2<LINK_TYPE>::resetForCnv(ElementLinkContNames_p2& lookupTable)
277 {
278  // Save lookup table and reset element link index and map
279  m_state.reset (lookupTable);
280 }
281 
282 template <typename LINK_TYPE>
283 inline
284 void
285 ElementLinkCnv_p2<LINK_TYPE>::resetForCnv(const ElementLinkContNames_p2& lookupTable)
286 {
287  // Save lookup table and reset element link index and map
288  m_state.reset (lookupTable);
289 }
290 
291 template <typename LINK_TYPE>
292 inline
293 void ElementLinkCnv_p2<LINK_TYPE>::
294 transToPers(const Link_t* trans, PersLink_t* pers,
295  [[maybe_unused]] MsgStream& log)
296 {
297  transToPers (m_state, *trans, *pers, log);
298 }
299 
300 
301 template <typename LINK_TYPE >
302 inline
303 void ElementLinkCnv_p2< LINK_TYPE >
304 ::persToTrans(const PersLink_t* pers, Link_t* trans, MsgStream& log)
305 {
306  persToTrans (m_state, *pers, *trans, log);
307 }
308 
309 
310 
311 
312 template <typename LINK_TYPE >
313 inline
314 void ElementLinkCnv_p2< LINK_TYPE >::
315 persToTrans(const PersLink_t& pers, Link_t& trans, MsgStream& log) {
316  persToTrans( m_state, pers, trans, log);
317 }
318 
319 
320 template <typename LINK_TYPE >
321 inline
322 void ElementLinkCnv_p2< LINK_TYPE >::
323 transToPers(const Link_t& trans, PersLink_t& pers, MsgStream& log) {
324  transToPers( m_state, trans, pers, log);
325 }
326 
327 
328 template <typename LINK_TYPE >
329 inline
330 unsigned int
331 ElementLinkCnv_p2< LINK_TYPE >::getNameIndex (State& state,
332  const std::string& name) const
333 {
334  // Add this name to the lookup table, retrieving and index.
335 
336  unsigned int nameIndex;
337 
338  // Only need to save name if container name has
339  // changed for this element link
340  if (name == state.m_lastNameAdded) return (state.m_lastNameIndex);
341 
342  // check if name has already been added, if so use the index
343  // found, other make a new entry
344 
345  // NOTE: the map is part of this converter object and not the
346  // lookup table itself
347 
348  typename State::IndexMap::const_iterator it =
349  state.m_nameIndexMap.find(name);
350  if (it != state.m_nameIndexMap.end()) {
351  nameIndex = (it->second);
352  }
353  else {
354  // Add new name to lookup table and map
355  nameIndex = state.m_lookupTable->m_names.size();
356  state.m_lookupTable->m_names.push_back(name);
357  state.m_nameIndexMap[name] = nameIndex;
358  }
359 
360  // Save last name and index
361 
362  // Note: state.m_lastNameAdded is a copy of a string and not a ptr into
363  // the lookup table. This is required because the lookup table may
364  // be extended/reallocated elsewhere in memory and thus invalidate
365  // ptrs into it.
366  state.m_lastNameIndex = nameIndex;
367  state.m_lastNameAdded = state.m_lookupTable->m_names[nameIndex];
368  return (nameIndex);
369 }
370 
371 template <typename LINK_TYPE >
372 inline
373 void
374 ElementLinkCnv_p2< LINK_TYPE >::getContName (State& state,
375  unsigned int nameIndex,
376  std::string const *& name,
377  MsgStream& log) const
378 {
379 
380  // Only need to get new name if index has changed for this element
381  // link
382  if (nameIndex == state.m_lastNameIndex) {
383  name = state.m_lastNameFound;
384  return;
385  }
386 
387  // Get the container name with the name index from the lookup table
388  if (!state.m_clookupTable ||
389  state.m_clookupTable->m_names.size() < nameIndex + 1)
390  {
391  if (!state.m_clookupTable) {
392  log << MSG::ERROR << "Empty link name table ptr" << endmsg;
393  }
394  else {
395  log << MSG::ERROR << "Empty name vector in lookup table - looking for index "
396  << nameIndex << " size " << state.m_clookupTable->m_names.size() << endmsg;
397  }
398  return;
399  }
400  name = &(state.m_clookupTable->m_names[nameIndex]);
401 
402  // Save last name and index
403  state.m_lastNameFound = name;
404  state.m_lastNameIndex = nameIndex;
405  return;
406 }