ATLAS Offline Software
Holder.icc
Go to the documentation of this file.
1 // Emacs -*- c++ -*-
2 
3 /*
4  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
5 */
6 
7 #include <iterator>
8 #include <type_traits>
9 
10 #include "GaudiKernel/MsgStream.h"
11 
12 #include "AthenaBaseComps/AthMsgStreamMacros.h"
13 #include "TrigNavigation/TypeMaps.h"
14 #include "TrigNavStructure/BaseHolder.h"
15 
16 #ifndef TrigNavigation_Holder_icc
17 #define TrigNavigation_Holder_icc
18 
19 #define HOLDERLOG(logger,x) if (logger->msgLvl(MSG::x)) logger->msg() << MSG::x
20 
21 /*
22 template<class T>
23 std::string type_real_name() {
24  std::string name(__PRETTY_FUNCTION__);
25  size_t op = name.find('=');
26  size_t cl = name.find(']');
27  return name.substr(op+1, cl-op-1);
28 }
29 */
30 
31 /////////////////////////////////////////////////////////////////////////////
32 // T is for objects, C for container for this objects
33 template<class STORED>
34 HLTNavDetails::Holder<STORED>::Holder() {
35 }
36 
37 /////////////////////////////////////////////////////////////////////////////
38 template<class STORED>
39 HLTNavDetails::Holder<STORED>::Holder(const std::string& prefix, const std::string& label, uint16_t idx) :
40  IHolder(prefix, label, idx)
41 {
42 }
43 
44 
45 /////////////////////////////////////////////////////////////////////////////
46 namespace HLTNavDetails {
47 template<class STORED>
48 Holder<STORED>::~Holder() {
49 }
50 }
51 
52 /////////////////////////////////////////////////////////////////////////////
53 template<class STORED, bool> struct createTemporary;
54 
55 /////////////////////////////////////////////////////////////////////////////
56 template<class STORED>
57 struct createTemporary<STORED, true>
58 {
59  static STORED* do_it() {
60  STORED *s = new STORED;
61  s->clear(SG::VIEW_ELEMENTS);
62  return s;
63  }
64 };
65 
66 /////////////////////////////////////////////////////////////////////////////
67 template<class STORED>
68 struct createTemporary<STORED, false>
69 {
70  static STORED* do_it() {
71  return 0;
72  }
73 };
74 
75 /////////////////////////////////////////////////////////////////////////////
76 template<class STORED>
77 template<class CONTAINER2>
78 bool HLTNavDetails::Holder<STORED>::get( ElementLinkVector<CONTAINER2>& el, HLT::TriggerElement::ObjectIndex idx) {
79  return static_cast<HolderImp<STORED, CONTAINER2>* >(this)->getElementLinks(el, idx);
80 }
81 
82 /////////////////////////////////////////////////////////////////////////////
83 template<class STORED>
84 template<class CONTAINER2>
85 bool HLTNavDetails::Holder<STORED>::get( ElementLinkVector<CONTAINER2>& el ) {
86  return static_cast<HolderImp<STORED, CONTAINER2>* >(this)->getElementLinks(el);
87 }
88 
89 
90 /////////////////////////////////////////////////////////////////////////////
91 // Implementation
92 /////////////////////////////////////////////////////////////////////////////
93 template<class STORED, class CONTAINER>
94 HLTNavDetails::HolderImp<STORED, CONTAINER>::HolderImp()
95  : Holder<STORED>() {
96 }
97 
98 /////////////////////////////////////////////////////////////////////////////
99 template<class STORED, class CONTAINER>
100 HLTNavDetails::HolderImp<STORED, CONTAINER>::HolderImp(const std::string& prefix, const std::string& label, uint16_t idx)
101  : Holder<STORED>(prefix, label, idx),
102  m_key (formatSGkey(prefix, ClassID_traits<CONTAINER>::typeName(), label))
103 {
104 }
105 
106 /////////////////////////////////////////////////////////////////////////////
107 namespace HLTNavDetails {
108 template<class STORED, class CONTAINER>
109 HolderImp<STORED, CONTAINER>::~HolderImp() {
110  //typedef Holder<STORED> H;
111  // Don't touch m_log here --- if we're running global dtors, then
112  // it may have already been deleted.
113  m_memMgr.clear();
114 }
115 }
116 
117 
118 /////////////////////////////////////////////////////////////////////////////
119 template<class STORED, class CONTAINER>
120 HLTNavDetails::IHolder* HLTNavDetails::HolderImp<STORED, CONTAINER>::clone(const std::string& prefix, const std::string& label, uint16_t idx ) const {
121  //typedef Holder<STORED> H;
122  if ( not m_containerProxy.empty() ) {
123  return 0;
124  }
125  HolderImp<STORED, CONTAINER> *imp = new HolderImp<STORED, CONTAINER>(prefix, label, idx);
126  IHolder *h = imp;
127  return h;
128 }
129 
130 template<class AUX>
131 struct auxCLIDOrZero {
132  static CLID get() {
133  return ClassID_traits<AUX>::ID();
134  }
135  static std::string getName() {
136  return ClassID_traits<AUX>::typeName();
137  }
138 };
139 template<>
140 struct auxCLIDOrZero<HLT::TypeInformation::no_aux> {
141  static CLID get() {
142  return 0;
143  }
144  static std::string getName() {
145  return std::string("no_aux");
146  }
147 };
148 
149 /////////////////////////////////////////////////////////////////////////////
150 template<class STORED, class CONTAINER>
151 CLID HLTNavDetails::HolderImp<STORED, CONTAINER>::auxClidOrZero() const {
152  return auxCLIDOrZero<typename Container2Aux<CONTAINER>::type>::get();
153 }
154 
155 /////////////////////////////////////////////////////////////////////////////
156 template<class STORED, class CONTAINER>
157 void HLTNavDetails::HolderImp<STORED, CONTAINER>::prepare(const asg::AsgMessaging& logger, HLT::AccessProxy* sg, IConversionSvc* conversionSvc, bool readonly){
158  typedef Holder<STORED> H;
159  IHolder::prepare(logger,sg,conversionSvc,readonly);
160  CLID auxCLID = auxCLIDOrZero<typename Container2Aux<CONTAINER>::type>::get();
161  if ( auxCLID ) {
162 
163  if(H::m_readonly){
164  ATH_MSG_INFO("HolderImp::prepare using a read-only proxy for aux store");
165  H::m_aux = new TypelessAuxProxy();
166  }
167  else{
168 
169  const auto itr = HLT::TypeMaps::proxies().find(auxCLID);
170  if ( itr == HLT::TypeMaps::proxies().end() ) {
171  ATH_MSG_ERROR("HolderImp::prepare can not find Aux store proxy " << *this);
172  return;
173  }
174 
175  H::m_aux = itr->second->clone();
176  if ( H::m_aux == 0 ) {
177  ATH_MSG_ERROR("HolderImp::prepare can not clone Aux store proxy " << *this);
178  }
179  ATH_MSG_VERBOSE("HolderImp::prepare proxy toAux store ready decorating");
180  }
181  }
182 }
183 
184 
185 /////////////////////////////////////////////////////////////////////////////
186 template<class STORED, class CONTAINER>
187 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::syncWithSG(SG::OwnershipPolicy policy) {
188  ATH_MSG_DEBUG("HolderImp::syncWithSG policy " << policy);
189  typedef Holder<STORED> H;
190  if ( !H::m_storeGate ) {
191  ATH_MSG_WARNING("HolderImp::syncWithSG no SG available " << *this);
192  return false;
193  }
194  ATH_MSG_VERBOSE("HolderImp::syncWithSG syncing holder with SG " << *this);
195 
196  const std::string auxkey = key()+"Aux.";
197  ATH_MSG_VERBOSE("HolderImp::syncWithSG looking in SG for key " << key() << " possible aux should have " << auxkey);
198 
199  const bool transientInSG ( m_containerProxy.transientContains(H::m_storeGate, key() ) );
200  const bool persistentThroughSG ( m_containerProxy.contains(H::m_storeGate, key() ) );
201  if ( transientInSG or persistentThroughSG ) {
202  ATH_MSG_VERBOSE("HolderImp::syncWithSG objects "
203  << ( transientInSG ? "already in" : "available through" )
204  << " SG, syncing to them " << *this);
205 
206 
207  if ( m_containerProxy.sync( H::m_storeGate, key()).isFailure() ) {
208  ATH_MSG_WARNING("HolderImp::syncWithSG objects already in SG, however failed syncing (SG::retrieve) to them " << *this);
209  return false;
210  }
211  if( m_containerProxy.data()->ownPolicy() != SG::VIEW_ELEMENTS && H::m_aux && H::m_aux->sync(H::m_storeGate,auxkey).isFailure()){
212  ATH_MSG_WARNING("HolderImp::syncWithSG objects already in SG, however failed syncing (SG::retrieve) to aux store " << *this);
213  return false;
214  };
215 
216 
217  } else { // SG is empty, we need to put the obj into it
218  ATH_MSG_VERBOSE("HolderImp::syncWithSG objects not in SG, adding them to SG " << *this);
219  if ( m_containerProxy.create().isFailure() ) {
220  ATH_MSG_WARNING("HolderImp::syncWithSG can not create container " << *this);
221  return false;
222  }
223 
224  auto defaultPolicy = m_containerProxy.data()->ownPolicy();
225  m_containerProxy.data()->clear( defaultPolicy == SG::VIEW_ELEMENTS ? SG::VIEW_ELEMENTS : policy);
226 
227 
228  CLID auxCLID = auxCLIDOrZero<typename Container2Aux<CONTAINER>::type>::get();
229  if ( auxCLID and policy != SG::VIEW_ELEMENTS ) {
230  if ( H::m_aux == 0 ) {
231  ATH_MSG_ERROR("HolderImp::syncWithSG can not clone Aux store proxy " << *this);
232  return false;
233  }
234 
235  ATH_MSG_VERBOSE("HolderImp::syncWithSG proxy toAux store ready decorating");
236 
237  if( H::m_aux->create().isFailure() ) {
238  ATH_MSG_WARNING("HolderImp::syncWithSG can not create Aux store for container " << *this);
239  return false;
240  }
241 
242  if( H::m_aux->reg(H::m_storeGate,auxkey).isFailure() ) {
243  ATH_MSG_WARNING("HolderImp::syncWithSG can not register Aux store for container in SG " << *this);
244  return false;
245  }
246 
247  SG::AuxVectorBase* container = m_containerProxy.castAuxVectorBase();
248  SG::IAuxStore* aux = H::m_aux->castIAuxStore();
249  if ( container and aux ) {
250  ATH_MSG_DEBUG("HolderImp::syncWithSG Aux sotore configured for " << *this);
251  container->setStore(aux);
252  } else {
253  ATH_MSG_WARNING("HolderImp::syncWithSG type configured to have Aux store but no appropriate Aux interfaces are implemented AuxVectorBase for container: "
254  << container << " IAuxStore for Aux sotore: " << aux << " "<< *this);
255  return false;
256  }
257  }
258 
259  if ( m_containerProxy.reg( H::m_storeGate, key()).isFailure() ) {
260  ATH_MSG_ERROR("HolderImp::syncWithSG recording collection failed " << *this);
261  return false;
262  }
263  }
264 
265  return true;
266 }
267 
268 /////////////////////////////////////////////////////////////////////////////
269 template<class STORED, class CONTAINER>
270 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::checkAndSetOwnership(SG::OwnershipPolicy policy) {
271  if ( m_containerProxy.empty() )
272  return false;
273 
274  if ( m_containerProxy.data()->empty() ) {
275  m_containerProxy.data()->clear(policy);
276  return true;
277  }
278 
279  if ( m_containerProxy.data()->ownPolicy() == policy )
280  return true;
281 
282  return false;
283 }
284 /////////////////////////////////////////////////////////////////////////////
285 template<class CONTAINER, bool b>
286 struct transferBetweenContainers;
287 
288 
289 // case when the containers can be transfered
290 template <class CONTAINER>
291 struct transferBetweenContainers<CONTAINER, true> {
292  static void do_it(CONTAINER *source, CONTAINER* dest, const asg::AsgMessaging*) {
293  dest->insertMove (dest->end(), *source);
294  }
295 };
296 
297 /////////////////////////////////////////////////////////////////////////////
298 // case when the containers CAN NOT be transfered
299 template <class CONTAINER>
300 struct transferBetweenContainers<CONTAINER, false> {
301  static void do_it(CONTAINER *, CONTAINER*, const asg::AsgMessaging*) {
302  throw std::runtime_error
303  ("TrigNavigation: Tried to attach an owning container of type " +
304  ClassName<CONTAINER>::name() +
305  "; only view containers of this type are supported.");
306  }
307 };
308 
309 /////////////////////////////////////////////////////////////////////////////
310 // code below checks if the transfer of elements between the two OWNING containers can happen
311 // It is based on the check of the type returned by the iterator i.e. if the reference is const or not const (i.e. assignable)
312 //
313 template<class CONTAINER>
314 struct canTransfer {
315  const static bool value = std::is_assignable<typename CONTAINER::iterator::reference,
316  typename CONTAINER::iterator::value_type>::value;
317 };
318 
319 /////////////////////////////////////////////////////////////////////////////
320 template<class STORED, class CONTAINER, bool b> struct insert;
321 
322 /////////////////////////////////////////////////////////////////////////////
323 // implementation if stored and container are the same
324 // this version is suggested by Attila, it has several advantages
325 // 1) the source container is useable after the insertion (important for the monitoring)
326 // 2) ownership of objects is greately simplified (i.e. the event-wise container always own objects,
327 // the roi-wise containers always view objects
328 //
329 template <class STORED, class CONTAINER>
330 struct insert<STORED, CONTAINER, true>{
331  static bool do_it(STORED *source, CONTAINER* dest, bool /*hasAux*/, const asg::AsgMessaging* log) {
332 
333  HOLDERLOG(log, VERBOSE ) << "insert::do_it CONTAINER " << ClassID_traits<STORED>::typeName() << endmsg;
334  HOLDERLOG(log, VERBOSE ) << "Destination is " << (dest->ownPolicy() == SG::VIEW_ELEMENTS ? "VIEW" : "OWN")
335  << " source is " << (source->ownPolicy() == SG::VIEW_ELEMENTS ? "VIEW" : "OWN") << endmsg;
336 
337  // From Scott
338  // - Input container is owning. Output container should also be owning;
339  // ownership should be transferred from input to output container.
340 
341  // - Input is a view container and doesn't track indices
342  // (trackIndices() is false). Output should be a view container.
343  // Aux data are not transferred in this case.
344 
345  // - Input is a view container that does track indices
346  // (trackIndices() is true). Output should be a view container
347  // with ALWAYS_TRACK_INDICES. Aux data are transferred in this case.
348  // (I don't think trigger will see this case.)
349 
350 
351  if ( dest->empty() ) { // empty destination, we can do adaptations
352  if ( source->ownPolicy() == SG::OWN_ELEMENTS ) {
353  dest->clear( SG::OWN_ELEMENTS );
354  }
355 
356  if ( source->ownPolicy() == SG::VIEW_ELEMENTS and source->trackIndices() == false ) {
357  HOLDERLOG(log, VERBOSE ) << "insert::do_it destination container made a VIEW" << endmsg;
358  dest->setStore(static_cast<SG::IAuxStore*>(nullptr));
359  dest->clear( SG::VIEW_ELEMENTS);
360  }
361 
362  if ( source->ownPolicy() == SG::VIEW_ELEMENTS and source->trackIndices() == true ) {
363  HOLDERLOG(log, VERBOSE ) << "insert::do_it destination container made a VIEW wiht indices tracking " << endmsg;
364  // it should be like this but I can not implemnt it like this because many container do not implement second arg dest->clear( SG::VIEW_ELEMENTS, SG::ALWAYS_TRACK_INDICES );
365  dest->clear( SG::VIEW_ELEMENTS );
366  }
367  }
368  if ( source->ownPolicy() != dest->ownPolicy() ) { // a simple check if in case of nonempty container we are dooing consistent insertion
369  HOLDERLOG(log, WARNING ) << "insert::do_it objects can not be inserted because of ownership issues. "
370  << "Destination container has already " << dest->size() << " objects "
371  << " and ownership policy "
372  << (dest->ownPolicy() == SG::OWN_ELEMENTS ? "OWN" : "") // this is dumb code but who knows what other policies will be implemented in the future
373  << (dest->ownPolicy() == SG::VIEW_ELEMENTS ? "VIEW" : "")
374  << " no action is performed, potential memory leak" << endmsg;
375  return false;
376  }
377 
378 
379  if ( source->ownPolicy() == SG::VIEW_ELEMENTS ) {
380  dest->insert(dest->end(), source->begin(), source->end());
381  HOLDERLOG(log, VERBOSE ) << "insert::do_it objects copied, conversion to view container not needed" << endmsg;
382  } else {
383  // We have an owning container. Transfer the element ownership
384  // from SOURCE to DEST. We can only do this if the container
385  // has modifiable iterators. For containers with non-modifiable
386  // iterators (like CaloTowerContainer), we throw an exception.
387  // Such containers should be added only as view containers.
388  transferBetweenContainers<CONTAINER, canTransfer<CONTAINER>::value>
389  ::do_it(source, dest, log);
390  }
391  return true;
392  }
393 };
394 
395 
396 
397 /////////////////////////////////////////////////////////////////////////////
398 // implementation if stored and container are distinct
399 template <class STORED, class CONTAINER>
400 struct insert <STORED, CONTAINER, false>{
401  static bool do_it(STORED *s, CONTAINER* dest, bool /*hasAux*/, const asg::AsgMessaging*) {
402  dest->push_back(s);
403  return true;
404  }
405 };
406 
407 /////////////////////////////////////////////////////////////////////////////
408 template<class STORED, class CONTAINER, bool b> struct remap;
409 template<class STORED, class CONTAINER>
410 struct remap<STORED, CONTAINER, false> {
411  static void do_it(const std::string&, const std::string&, STORED *, CONTAINER*, HLT::AccessProxy*, const asg::AsgMessaging*) {
412 
413  }
414 };
415 
416 /////////////////////////////////////////////////////////////////////////////
417 template<class STORED, class CONTAINER>
418 struct remap<STORED, CONTAINER, true> {
419  static void do_it(const std::string& storedkey , const std::string& contkey, STORED *s, CONTAINER* cont, HLT::AccessProxy *sg, const asg::AsgMessaging* log ) {
420  std::string skey = storedkey;
421  if ( storedkey == "" ) {
422  // we can't do it
423  HOLDERLOG(log, VERBOSE) << "HolderImp::remap trying to discover object key, this is potentially slow and should be avoided, type: " << ClassID_traits<STORED>::typeName() << " from: " << s << " to: " << cont << endmsg;
424  SG::DataProxy* px = sg->proxy((void const* )s);
425  if ( !px ) {
426  HOLDERLOG(log, WARNING) << "HolderImp::remap When remaping containers found no proxy for the object" << s << " of type " << ClassID_traits<STORED>::typeName() << endmsg;
427  return;
428  }
429  if ( !px->isValid() ) {
430  HOLDERLOG(log, WARNING) << "HolderImp::remap When remaping containers found no valid proxy for the object" << s << " of type " << ClassID_traits<STORED>::typeName() << endmsg;
431  return;
432  }
433  skey = px->name();
434  }
435  HOLDERLOG(log, VERBOSE) << "HolderImp::remap remapping collections of type: " << ClassID_traits<STORED>::typeName()
436  << " from: " << skey << " to: " << contkey << " while destination container size is: " << cont->size() << endmsg;
437  sg->remap(ClassID_traits<CONTAINER>::ID(), skey, contkey, cont->size());
438  }
439 };
440 
441 template<class STORED, class CONTAINER, bool>
442 struct destinationOwnPolicy {};
443 
444 template<class STORED, class CONTAINER>
445 struct destinationOwnPolicy<STORED, CONTAINER, false> {
446  static SG::OwnershipPolicy get(const STORED* /*source*/) {
447  return SG::OWN_ELEMENTS;
448  }
449 };
450 
451 template<class STORED, class CONTAINER>
452 struct destinationOwnPolicy<STORED, CONTAINER, true> {
453  static SG::OwnershipPolicy get(const STORED* source) {
454  if ( source->ownPolicy() == SG::VIEW_ELEMENTS )
455  return SG::VIEW_ELEMENTS;
456  return SG::OWN_ELEMENTS;
457  }
458 };
459 
460 
461 
462 /////////////////////////////////////////////////////////////////////////////
463 template<class STORED, class CONTAINER>
464 HLT::TriggerElement::ObjectIndex HLTNavDetails::HolderImp<STORED, CONTAINER>::add ATLAS_NOT_THREAD_SAFE ( const STORED* f_in, bool inSG, const std::string& sgKey ) {
465  // FIXME:
466  // If insertMove is used, then the pointer being recorded cannot be const.
467  // Taking this object by const is anyway wrong because it will be modified
468  // (unless it's a view container).
469  STORED* f = const_cast<STORED*>(f_in);
470  typedef Holder<STORED> H;
471 
472  if ( ! syncWithSG( destinationOwnPolicy<STORED, CONTAINER, std::is_same<STORED, CONTAINER>::value>::get(f) ) )
473  return HLT::TriggerElement::ObjectIndex();
474 
475  uint32_t bidx = m_containerProxy.data()->size();
476 
477  bool wasRecorded = false;
478  std::string thiskey(sgKey);
479  if ( !inSG && std::is_same<STORED, CONTAINER>::value ) { // conditions to place partial containers in SG
480  thiskey = this->getUniqueKey();
481  if ( H::m_storeGate->record(f, thiskey).isFailure() ) {
482  ATH_MSG_WARNING("HolderImp::add object " << f << "and sgKey:" << thiskey << " intended for holder" << *this << " can't be placed directly in SG");
483  } else {
484  inSG = true;
485  wasRecorded = true;
486  ATH_MSG_VERBOSE("HolderImp::add feature SG direct registration succesful with the key:" << thiskey);
487  }
488  }
489 
490  if ( inSG ) { //conditions to add remapping
491  remap<STORED, CONTAINER,
492  std::is_same<STORED, CONTAINER>::value>::do_it (thiskey, key(), f, m_containerProxy.data(), H::m_storeGate, H::m_logger);
493  }
494 
495  bool insertStatus = insert<STORED, CONTAINER, std::is_same<STORED, CONTAINER>::value>
496  ::do_it (f, m_containerProxy.data(), H::m_aux != 0, H::m_logger);
497  if ( insertStatus == false ) {
498  ATH_MSG_WARNING("HolderImp::add insert failed " );
499  return HLT::TriggerElement::ObjectIndex();
500  }
501 
502  uint32_t eidx = m_containerProxy.data()->size();
503  ATH_MSG_VERBOSE("HolderImp::add added object(s) to the container, size increase from : " << bidx << " to: " << eidx);
504  HLT::TriggerElement::ObjectIndex objIdx (H::subTypeIndex(), bidx, eidx );
505 
506  m_memMgr.insert(std::make_pair(objIdx, MemoryMgr(f, inSG||m_containerProxy.data()->ownPolicy() == SG::OWN_ELEMENTS)));
507 
508  if ( wasRecorded ) {
509  if ( H::m_storeGate->setConst(f).isFailure() ) {
510  ATH_MSG_WARNING("HolderImp::add setConst failed " );
511  }
512  }
513 
514  return objIdx;
515 }
516 
517 
518 /////////////////////////////////////////////////////////////////////////////
519 template<class STORED, class CONTAINER, bool b> struct retrieve;
520 
521 /////////////////////////////////////////////////////////////////////////////
522 // implementation if stored and container are the same
523 template <class STORED, class CONTAINER>
524 struct retrieve<STORED, CONTAINER, true>{
525  static bool do_it(const STORED*& dest, CONTAINER* src, HLT::TriggerElement::ObjectIndex idx) {
526  // find 2 iterators
527  if ( src->size() < idx.objectsBegin() || src->size() < idx.objectsEnd()) {
528  REPORT_MESSAGE_WITH_CONTEXT(MSG::VERBOSE,"Holder") << "either begin index or end index is larger than size";
529  REPORT_MESSAGE_WITH_CONTEXT(MSG::VERBOSE,"Holder") << "size: " << src->size() << " begin: " << idx.objectsBegin() << " end: " << idx.objectsEnd();
530  dest = 0;
531  return false;
532  }
533  dest = createTemporary<STORED, std::is_same<STORED, CONTAINER>::value>::do_it();
534  typename CONTAINER::iterator beg = src->begin();
535  typename CONTAINER::iterator end = src->begin();
536  std::advance(beg, idx.objectsBegin());
537  std::advance(end, idx.objectsEnd());
538 
539  // get(Feature) should really not be taking a const reference for the case
540  // where STORED!=CONTAINER as we do have to modify the destination. But the
541  // user is responsible for not filling the same container concurrently anyway.
542  auto nonconst_dest ATLAS_THREAD_SAFE = const_cast<STORED*&>(dest);
543  nonconst_dest->insert(nonconst_dest->end(), beg, end);
544  return true;
545  }
546 };
547 
548 /////////////////////////////////////////////////////////////////////////////
549 // implementation if stored and container are distinct
550 template <class STORED, class CONTAINER>
551 struct retrieve <STORED, CONTAINER, false>{
552  static bool do_it(const STORED*& dest, CONTAINER* src, HLT::TriggerElement::ObjectIndex idx) {
553 
554  if (idx.objectsBegin() < (*src).size()) {
555  dest = src->at(idx.objectsBegin());
556  return true;
557  } else {
558  dest = 0;
559  return false;
560  }
561  }
562 };
563 
564 template<class STORED, class CONTAINER>
565 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::getWithLink(typename set_link<STORED,CONTAINER,std::is_same<STORED,CONTAINER>::value>::type& link,
566  HLT::TriggerElement::ObjectIndex& idx) {
567 
568  const STORED* dest = 0;
569  bool result = this->get(dest,idx);
570  if(!result) return false;
571 
572  link = set_link<STORED,CONTAINER,std::is_same<STORED,CONTAINER>::value>::do_it(dest,m_containerProxy.data(),idx);
573  return true;
574 }
575 
576 /////////////////////////////////////////////////////////////////////////////
577 template<class STORED, class CONTAINER>
578 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::get(const STORED*& dest, HLT::TriggerElement::ObjectIndex idx) {
579  typedef Holder<STORED> H;
580  if ( !syncWithSG() )
581  return false;
582 
583 
584  ATH_MSG_VERBOSE("HolderImp::get getting object(s) from Holder" << *this);
585  typename MemoryMgrMap::const_iterator cache;
586  if ( (cache = m_memMgr.find(idx)) != m_memMgr.end() ) {
587  ATH_MSG_DEBUG("HolderImp::get object found in the cache with address " << idx);
588  dest = cache->second.proxy.data();
589  return true;
590  }
591  else{
592  ATH_MSG_VERBOSE("HolderImp::get getting object from primary collection " << idx);
593  }
594 
595  if ( ! retrieve<STORED, CONTAINER, // short circuited .. retrieve will not run if in cache
596  std::is_same<STORED, CONTAINER>::value>::
597  do_it (dest, m_containerProxy.data(), idx) ) {
598  ATH_MSG_WARNING("HolderImp::get getting chunk of the container failed for Holder: " << *this
599  << " index: " << idx);
600  return false;
601  }
602 
603  if ( std::is_same<STORED, CONTAINER>::value ) { // temporary view containers in SG and cache filling
604 
605  // We don't have an implementation of FeatureProxy that takes a const reference.
606  // But this should be safe (modulo the comments in the do_it method above).
607  auto nonconst_dest ATLAS_THREAD_SAFE = const_cast<STORED*&>(dest);
608  FeatureProxy tempProxy( nonconst_dest );
609 
610  m_memMgr.insert(std::make_pair(idx, MemoryMgr(tempProxy, true))); // store it in the cache for futher uses
611 
612  std::string sgKey = this->generateAliasKey(this->typeClid(), this->subTypeIndex(), this->label(), 0xffffffff );
613 
614  if ( tempProxy.reg(H::m_storeGate, sgKey).isFailure() ) {
615  ATH_MSG_WARNING("HolderImp::get for some reason object can't be placed in SG, key:" << sgKey);
616  return false;
617  }
618  remap<STORED, CONTAINER,
619  std::is_same<STORED, CONTAINER>::value>::do_it (sgKey, key(), tempProxy.data(), m_containerProxy.data(), H::m_storeGate, H::m_logger);
620  ATH_MSG_VERBOSE("Added view collection to SG with defined EL remapping to event-wide colection, key: " << sgKey);
621  }
622  return true;
623 }
624 
625 
626 /////////////////////////////////////////////////////////////////////////////
627 // check if objects in obj are in the container
628 template<class STORED, class CONTAINER, bool b> struct isin;
629 
630 /////////////////////////////////////////////////////////////////////////////
631 // check if the container obj is a subcontainer of cont
632 template <class STORED, class CONTAINER>
633 struct isin<STORED, CONTAINER, true> {
634  static bool do_it(const STORED* obj, const CONTAINER* cont, const asg::AsgMessaging*, uint32_t& begin, uint32_t& end) {
635  typename CONTAINER::const_iterator it = std::search(cont->begin(), cont->end(), obj->begin(), obj->end());
636  if ( it == cont->end() ) {
637  return false;
638  }
639  begin = it - cont->begin();
640  end = begin + obj->size();
641  return true;
642  }
643 };
644 
645 /////////////////////////////////////////////////////////////////////////////
646 // check if the obj is in a container cont
647 template <class STORED, class CONTAINER>
648 struct isin<STORED, CONTAINER, false> {
649  static bool do_it(const STORED* obj, const CONTAINER* cont, const asg::AsgMessaging*, uint32_t& begin, uint32_t& end) {
650  typename CONTAINER::const_iterator it = std::find(cont->begin(), cont->end(), obj);
651  if ( it == cont->end() ) {
652  return false;
653  }
654  begin = it - cont->begin();
655  end = begin+1;
656 
657  return true;
658  }
659 };
660 
661 template<class STORED, class CONTAINER>
662 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::contains(const STORED* obj, HLT::TriggerElement::ObjectIndex& idx) {
663  typedef Holder<STORED> H;
664  if ( !syncWithSG() )
665  return false;
666 
667  ATH_MSG_VERBOSE("HolderImp::contains");
668  uint32_t begin=0;
669  uint32_t end=0;
670  bool ok = isin<STORED, CONTAINER,
671  std::is_same<STORED, CONTAINER>::value>::do_it (obj, m_containerProxy.data(), H::m_logger, begin, end);
672  if ( !ok ) {
673  ATH_MSG_VERBOSE("HolderImp::contains object " << obj << " not in the holder" << *this );
674  return false;
675  }
676  idx = HLT::TriggerElement::ObjectIndex(H::subTypeIndex(),begin,end);
677  ATH_MSG_VERBOSE("HolderImp::contains object " << obj << " found by in holder" << *this << " " << idx);
678  return true;
679 }
680 
681 /////////////////////////////////////////////////////////////////////////////
682 template<class STORED, class CONTAINER>
683 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::getElementLinks(ElementLinkVector<CONTAINER>& cont,
684  HLT::TriggerElement::ObjectIndex idx) {
685  //typedef Holder<STORED> H;
686  if ( !syncWithSG() )
687  return false;
688 
689  ATH_MSG_VERBOSE("HolderImp::getElementLinks(ELV, Index) getting objects");
690  for (unsigned i = idx.objectsBegin(); i != idx.objectsEnd(); ++i ){
691  cont.push_back(ElementLink<CONTAINER>(*(m_containerProxy.data()), i));
692  }
693  return true;
694 }
695 
696 /////////////////////////////////////////////////////////////////////////////
697 template<class STORED, class CONTAINER>
698 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::getElementLinks(ElementLinkVector<CONTAINER>& cont) {
699 
700  //typedef Holder<STORED> H;
701  if ( !syncWithSG() )
702  return false;
703  ATH_MSG_VERBOSE("HolderImp::getElementLinks (ELV) getting all objects");
704  for (unsigned i = 0; i < m_containerProxy.data()->size(); ++i ){
705  cont.push_back(ElementLink<CONTAINER>(*(m_containerProxy.data()), i));
706  }
707  return true;
708 }
709 
710 /////////////////////////////////////////////////////////////////////////////
711 template<class STORED, class CONTAINER>
712 std::string HLTNavDetails::HolderImp<STORED, CONTAINER>::getUniqueKey() {
713  ATH_MSG_VERBOSE("HolderImp::getUniqueKey");
714  if ( !syncWithSG() )
715  return "Bad_Key";
716  return IHolder::generateAliasKey( this->typeClid(), this->subTypeIndex(), this->label(),
717  m_containerProxy.data()->size() );
718 }
719 
720 template<class STORED, class CONTAINER>
721 std::string HLTNavDetails::HolderImp<STORED, CONTAINER>::getNextKey() {
722  ATH_MSG_VERBOSE("HolderImp::getNextKey");
723  return getUniqueKey();
724 }
725 
726 
727 
728 
729 /////////////////////////////////////////////////////////////////////////////
730 template<class STORED, class CONTAINER>
731 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::serialize(std::vector<uint32_t>& output) const {
732  typedef Holder<STORED> H; // this is to make things below shorter
733 
734  ATH_MSG_VERBOSE("HolderImp::serialize " << *this);
735  // if feature to be forgotten then indication of it is simply 0 size of serialized vector
736  H::serialize(output);
737 
738  return true;
739 }
740 
741 /////////////////////////////////////////////////////////////////////////////
742 template<class STORED, class CONTAINER>
743 void HLTNavDetails::HolderImp<STORED, CONTAINER>::print(MsgStream& m) const {
744  IHolder::print(m);
745  if ( not m_containerProxy.empty() )
746  m << " size: " << m_containerProxy.data()->size() << " @"<<m_containerProxy.data();
747  else
748  m << " container not allocated yet";
749 }
750 
751 /////////////////////////////////////////////////////////////////////////////
752 template<class STORED, class CONTAINER>
753 DataObject* HLTNavDetails::HolderImp<STORED, CONTAINER>::getDataObject() {
754  if(!m_containerProxy.data()) return 0;
755  return SG::asStorable(m_containerProxy.data());
756 }
757 
758 #define _IS_AUXTYPE_ !std::is_same<typename Container2Aux<T>::type,HLT::TypeInformation::no_aux>::value
759 
760 struct AuxDataObjectHelper{
761  template<typename T>
762  static typename std::enable_if<!_IS_AUXTYPE_,DataObject*>::type get(HLTNavDetails::ITypeProxy*/* aux*/){
763  return 0;
764  }
765  template<typename T>
766  static typename std::enable_if<_IS_AUXTYPE_,DataObject*>::type get(HLTNavDetails::ITypeProxy* aux){
767  typedef typename Container2Aux<T>::type auxtype;
768  HLTNavDetails::TypeProxy<auxtype>* auxcasted = static_cast<HLTNavDetails::TypeProxy<auxtype>*>(aux);
769  if(auxcasted){
770  if(!auxcasted->data()) return 0;
771  return SG::asStorable(auxcasted->data());
772  }
773  return 0;
774  }
775  template<typename T>
776  static typename std::enable_if<!_IS_AUXTYPE_,bool>::type set(HLTNavDetails::ITypeProxy*,DataObject*){
777  return true;//always success
778  }
779  template<typename T>
780  static typename std::enable_if<_IS_AUXTYPE_,bool>::type set(HLTNavDetails::ITypeProxy* aux, DataObject* dobjaux){
781  typedef typename Container2Aux<T>::type auxtype;
782  HLTNavDetails::TypeProxy<auxtype>* auxcasted = static_cast<HLTNavDetails::TypeProxy<auxtype>*>(aux);
783  if(auxcasted){
784  bool success = SG::fromStorable(dobjaux,auxcasted->data_ref());
785  auxcasted->syncTypeless();
786  REPORT_MESSAGE_WITH_CONTEXT(MSG::VERBOSE,"Holder") << "set from storable " << success << " to address " << auxcasted->data() << std::endl;
787  return success;
788  }
789  return 0;
790  }
791 };
792 
793 template<class STORED, class CONTAINER>
794 DataObject* HLTNavDetails::HolderImp<STORED, CONTAINER>::getAuxDataObject() {
795  return AuxDataObjectHelper::get<CONTAINER>(this->m_aux);
796 }
797 
798 template<class STORED, class CONTAINER>
799 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::setAuxDataObject(DataObject* dobjaux) {
800  bool status = AuxDataObjectHelper::set<CONTAINER>(this->m_aux,dobjaux);
801  ATH_MSG_VERBOSE("container data is: " << m_containerProxy.data());
802  SG::AuxVectorBase* container = m_containerProxy.castAuxVectorBase();
803  if(!this->m_aux or !container){
804  ATH_MSG_ERROR("in aux branch but aux type proxy or container proxy is null");
805  ATH_MSG_ERROR("container is: " << container);
806  ATH_MSG_ERROR("aux is: " << this->m_aux);
807  return false;
808  }
809  SG::IAuxStore* aux = this->m_aux->castIAuxStore();
810  if(!aux){
811  ATH_MSG_ERROR("cast of auxstore failed");
812  }
813  if(container and aux and status){
814  ATH_MSG_VERBOSE("container is: " << container);
815  ATH_MSG_VERBOSE("aux is: " << this->m_aux);
816  container->setStore(aux);
817  return true;
818  }
819  ATH_MSG_WARNING("something went wrong setting aux data object");
820  return false;
821 }
822 
823 
824 /////////////////////////////////////////////////////////////////////////////
825 template<class STORED, class CONTAINER>
826 bool HLTNavDetails::HolderImp<STORED, CONTAINER>::setDataObject(DataObject* dobj) {
827  bool success = SG::fromStorable(dobj, m_containerProxy.data_ref());
828  m_containerProxy.syncTypeless();
829  REPORT_MESSAGE_WITH_CONTEXT(MSG::VERBOSE,"Holder") << "set from storable " << success << " to address " << m_containerProxy.data();
830  return success;
831 }
832 
833 /////////////////////////////////////////////////////////////////////////////
834 template<class STORED, class CONTAINER>
835 HLTNavDetails::HolderImp<STORED, CONTAINER>::MemoryMgr::MemoryMgr(const FeatureProxy& st, bool sg)
836  : proxy(st), inSG(sg)
837 {}
838 
839 /////////////////////////////////////////////////////////////////////////////
840 template<class STORED, class CONTAINER>
841 HLTNavDetails::HolderImp<STORED, CONTAINER>::MemoryMgr::MemoryMgr()
842  : inSG(false)
843 {}
844 
845 /////////////////////////////////////////////////////////////////////////////
846 template<class STORED, class CONTAINER>
847 void HLTNavDetails::HolderImp<STORED, CONTAINER>::MemoryMgr::clear() {
848  // if the thing is not in SG it shoudl not be cleared, if is the SG will take care of it if ( !inSG ) proxy.clear();
849 }
850 
851 /////////////////////////////////////////////////////////////////////////////
852 template<class STORED>
853 MsgStream& HLTNavDetails::operator<< ( MsgStream& m, const HLTNavDetails::Holder<STORED>& h ) {
854  h.print(m);
855  return m;
856 }
857 
858 /////////////////////////////////////////////////////////////////////////////
859 template<class STORED, class CONTAINER>
860 MsgStream& HLTNavDetails::operator<< ( MsgStream& m, const HLTNavDetails::HolderImp<STORED, CONTAINER>& h ) {
861  h.print(m);
862  return m;
863 }
864 
865 #endif