ATLAS Offline Software
StoreGate/StoreGate/WriteHandle.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 /**
5  * @file StoreGate/WriteHandle.icc
6  * @author S. Binet, P. Calafiura, scott snyder <snyder@bnl.gov>
7  * @date Updated: Feb, 2016
8  * @brief Handle class for recording to StoreGate.
9  */
10 
11 #ifndef STOREGATE_SG_WRITEHANDLE_ICC
12 #define STOREGATE_SG_WRITEHANDLE_ICC 1
13 
14 
15 #include "StoreGate/exceptions.h"
16 #include "AthenaKernel/ClassID_traits.h"
17 #include "AthenaKernel/errorcheck.h"
18 #include <stdexcept>
19 
20 
21 namespace SG {
22 
23 
24 //************************************************************************
25 // Constructors, etc.
26 //
27 
28 
29 /**
30  * @brief Default constructor.
31  *
32  * The handle will not be usable until a non-blank key is assigned.
33  */
34 template <class T>
35 inline
36 WriteHandle<T>::WriteHandle()
37  : VarHandleBase(ClassID_traits<T>::ID(), Gaudi::DataHandle::Writer)
38 {
39 }
40 
41 
42 /**
43  * @brief Constructor with full arguments.
44  * @param sgkey StoreGate key of the referenced object.
45  * @param storename Name of the referenced event store.
46  */
47 template <class T>
48 inline
49 WriteHandle<T>::WriteHandle (const std::string& sgkey,
50  const std::string& storename /* ="StoreGateSvc"*/)
51  : VarHandleBase (ClassID_traits<T>::ID(), sgkey,
52  Gaudi::DataHandle::Writer, storename)
53 {
54 }
55 
56 
57 /**
58  * @brief Constructor from a WriteHandleKey.
59  * @param key The key object holding the clid/key/store.
60  *
61  * This will raise an exception if the StoreGate key is blank,
62  * or if the event store cannot be found.
63  */
64 template <class T>
65 inline
66 WriteHandle<T>::WriteHandle (const WriteHandleKey<T>& key)
67  : VarHandleBase (key, nullptr)
68 {
69 }
70 
71 
72 /**
73  * @brief Constructor from a WriteHandleKey and an explicit event context.
74  * @param key The key object holding the clid/key.
75  * @param ctx The event context.
76  *
77  * This will raise an exception if the StoreGate key is blank,
78  * or if the event store cannot be found.
79  *
80  * If the default event store has been requested, then the thread-specific
81  * store from the event context will be used.
82  */
83 template <class T>
84 inline
85 WriteHandle<T>::WriteHandle (const WriteHandleKey<T>& key,
86  const EventContext& ctx)
87  : VarHandleBase (key, &ctx)
88 {
89  // cppcheck-suppress missingReturn; false positive
90 }
91 
92 
93 /**
94  * @brief Copy constructor.
95  */
96 template <class T>
97 inline
98 WriteHandle<T>::WriteHandle(const WriteHandle& h)
99  : VarHandleBase(h)
100 {
101 }
102 
103 
104 /**
105  * @brief Move constructor.
106  */
107 template <class T>
108 WriteHandle<T>::WriteHandle(WriteHandle&& h)
109  : VarHandleBase(std::move(h))
110 {
111  m_lockAuxPending = h.m_lockAuxPending;
112  h.m_lockAuxPending = nullptr;
113 }
114 
115 
116 /**
117  * @brief Assignment operator.
118  */
119 template <class T>
120 inline
121 WriteHandle<T>&
122 // m_lockAuxPending not copied --- want lifetime to stay with the
123 // original WH.
124 // cppcheck-suppress operatorEqVarError
125 WriteHandle<T>::operator= (const WriteHandle& h)
126 {
127  if (this != &h)
128  this->VarHandleBase::operator=(h);
129  return *this;
130 }
131 
132 
133 /**
134  * @brief Move operator.
135  */
136 template <class T>
137 inline
138 WriteHandle<T>&
139 WriteHandle<T>::operator= (WriteHandle&& h)
140 {
141  if (this != &h) {
142  this->VarHandleBase::operator=(std::move(h));
143  m_lockAuxPending = h.m_lockAuxPending;
144  h.m_lockAuxPending = nullptr;
145  }
146  return *this;
147 }
148 
149 
150 /**
151  * @brief Destructor.
152  *
153  * Lock an aux object if m_lockAuxPending is true.
154  */
155 template <class T>
156 WriteHandle<T>::~WriteHandle()
157 {
158  if (m_lockAuxPending) {
159  m_lockAuxPending->setConst();
160  }
161 }
162 
163 
164 //************************************************************************
165 // Deference. These all return only the cached pointer.
166 //
167 
168 
169 /**
170  * @brief Dereference the pointer.
171  * Returns the cached pointer. Throws ExcNullWriteHandle if null.
172  */
173 template <class T>
174 inline
175 typename WriteHandle<T>::pointer_type
176 WriteHandle<T>::operator->()
177 {
178  return WriteHandle<T>::checkedCachedPtr();
179 }
180 
181 
182 /**
183  * @brief Dereference the pointer.
184  * Returns the cached pointer. Throws ExcNullWriteHandle if null.
185  */
186 template <class T>
187 inline
188 typename WriteHandle<T>::reference_type
189 WriteHandle<T>::operator*()
190 {
191  return *WriteHandle<T>::checkedCachedPtr();
192 }
193 
194 
195 /**
196  * @brief Dereference the pointer.
197  * Returns the cached pointer.
198  */
199 template <class T>
200 inline
201 typename WriteHandle<T>::const_pointer_type
202 WriteHandle<T>::cptr() const
203 {
204  return reinterpret_cast<pointer_type>(this->m_ptr);
205 }
206 
207 
208 /**
209  * @brief Dereference the pointer.
210  * Returns the cached pointer.
211  */
212 template <class T>
213 inline
214 typename WriteHandle<T>::pointer_type
215 WriteHandle<T>::ptr()
216 {
217  return cachedPtr();
218 }
219 
220 
221 /**
222  * @brief Return the cached pointer directly; no lookup.
223  */
224 template <class T>
225 inline
226 typename WriteHandle<T>::pointer_type
227 WriteHandle<T>::cachedPtr()
228 {
229  return reinterpret_cast<pointer_type>(this->m_ptr);
230 }
231 
232 
233 /**
234  * @brief Can the handle be successfully dereferenced?
235  */
236 template <class T>
237 inline
238 bool WriteHandle<T>::isValid()
239 {
240  return this->m_ptr != nullptr;
241 }
242 
243 
244 //************************************************************************
245 // Record.
246 
247 
248 /**
249  * @brief Record a const object to the store.
250  * @param data The object to record.
251  */
252 template <class T>
253 inline
254 StatusCode
255 WriteHandle<T>::WriteHandle::record (std::unique_ptr<T> data)
256 {
257  return this->doRecord (std::move(data), true, false);
258 }
259 
260 
261 /**
262  * @brief Record a non-const object to the store.
263  * @param data The object to record.
264  * @param isConst If true, record the object as const.
265  */
266 template <class T>
267 inline
268 StatusCode
269 WriteHandle<T>::WriteHandle::recordNonConst (std::unique_ptr<T> data)
270 {
271  return this->doRecord (std::move(data), false, false);
272 }
273 
274 
275 /**
276  * @brief Record a const object and its auxiliary store to the store.
277  * @param data The object to record.
278  * @param auxstore Auxiliary store object.
279  */
280 template <class T>
281 template <class AUXSTORE>
282 inline
283 StatusCode
284 WriteHandle<T>::WriteHandle::record (std::unique_ptr<T> data,
285  std::unique_ptr<AUXSTORE> auxstore)
286 {
287  return record (std::move(data), std::move(auxstore), true);
288 }
289 
290 
291 /**
292  * @brief Record a non-const object and its auxiliary store to the store.
293  * @param data The object to record.
294  * @param auxstore Auxiliary store object.
295  */
296 template <class T>
297 template <class AUXSTORE>
298 inline
299 StatusCode
300 WriteHandle<T>::WriteHandle::recordNonConst (std::unique_ptr<T> data,
301  std::unique_ptr<AUXSTORE> auxstore)
302 {
303  return record (std::move(data), std::move(auxstore), false);
304 }
305 
306 
307 /**
308  * @brief Record a const shared DataObject to the store.
309  * @param data The object to record.
310  *
311  * The event store takes shared ownership of the object.
312  */
313 template <class T>
314 inline
315 StatusCode
316 WriteHandle<T>::record (SG::DataObjectSharedPtr<T> data)
317 {
318  return this->doRecord (std::move(data), true, false);
319 }
320 
321 
322 /**
323  * @brief Record a non-const shared DataObject to the store.
324  * @param data The object to record.
325  *
326  * The event store takes shared ownership of the object.
327  */
328 template <class T>
329 inline
330 StatusCode
331 WriteHandle<T>::recordNonConst (SG::DataObjectSharedPtr<T> data)
332 {
333  return this->doRecord (std::move(data), false, false);
334 }
335 
336 
337 /**
338  * @brief Record an object to the store.
339  * @param data The object to record.
340  * @param returnExisting Allow an existing object?
341  *
342  * Unlike record(), this does not change the handle object.
343  * That means that one will not be able to get the object back
344  * by dereferencing the handle.
345  * Returns the object placed in the store, or nullptr if there
346  * was an error.
347  * If there was already an object in the store with the given key,
348  * then return null, unless @c returnExisting is true, in which case
349  * return success. In either case, @c data is destroyed.
350  */
351 template <class T>
352 inline
353 typename WriteHandle<T>::const_pointer_type
354 WriteHandle<T>::put (std::unique_ptr<T> data,
355  bool returnExisting /*= false*/) const
356 {
357  IProxyDict* store = nullptr;
358  return doPut (nullptr, std::move(data), returnExisting, store);
359 }
360 
361 
362 /**
363  * @brief Record an object to the store.
364  * @param data The object to record.
365  * @param returnExisting Allow an existing object?
366  *
367  * Unlike record(), this does not change the handle object.
368  * That means that one will not be able to get the object back
369  * by dereferencing the handle.
370  * Returns the object placed in the store, or nullptr if there
371  * was an error.
372  * If there was already an object in the store with the given key,
373  * then return null, unless @c returnExisting is true, in which case
374  * return success. In either case, @c data is destroyed.
375  */
376 template <class T>
377 inline
378 typename WriteHandle<T>::const_pointer_type
379 WriteHandle<T>::put (std::unique_ptr<const T> data,
380  bool returnExisting /*= false*/) const
381 {
382  IProxyDict* store = nullptr;
383  return doPut (nullptr, std::move(data), returnExisting, store);
384 }
385 
386 
387 /**
388  * @brief Record an object to the store.
389  * @param data The object to record.
390  * @param returnExisting Allow an existing object?
391  *
392  * Unlike record(), this does not change the handle object.
393  * That means that one will not be able to get the object back
394  * by dereferencing the handle.
395  * Returns the object placed in the store, or nullptr if there
396  * was an error.
397  * If there was already an object in the store with the given key,
398  * then return null, unless @c returnExisting is true, in which case
399  * return success. In either case, @c data is destroyed.
400  */
401 template <class T>
402 inline
403 typename WriteHandle<T>::const_pointer_type
404 WriteHandle<T>::put (std::unique_ptr<const ConstDataVector<T> > data,
405  bool returnExisting /*= false*/) const
406 {
407  IProxyDict* store = nullptr;
408  std::unique_ptr<const T> coll (data.release()->asDataVector());
409  return doPut (nullptr, std::move(coll), returnExisting, store);
410 }
411 
412 
413 /**
414  * @brief Record an object to the store.
415  * @param ctx The event context to use.
416  * @param data The object to record.
417  * @param returnExisting Allow an existing object?
418  *
419  * Unlike record(), this does not change the handle object.
420  * That means that one will not be able to get the object back
421  * by dereferencing the handle.
422  * Returns the object placed in the store, or nullptr if there
423  * was an error.
424  * If there was already an object in the store with the given key,
425  * then return null, unless @c returnExisting is true, in which case
426  * return success. In either case, @c data is destroyed.
427  */
428 template <class T>
429 inline
430 typename WriteHandle<T>::const_pointer_type
431 WriteHandle<T>::put (const EventContext& ctx,
432  std::unique_ptr<const ConstDataVector<T> > data,
433  bool returnExisting /*= false*/) const
434 {
435  IProxyDict* store = nullptr;
436  std::unique_ptr<const T> coll (data.release()->asDataVector());
437  return doPut (&ctx, std::move(coll), returnExisting, store);
438 }
439 
440 
441 /**
442  * @brief Record an object to the store.
443  * @param ctx The event context to use.
444  * @param data The object to record.
445  * @param returnExisting Allow an existing object?
446  *
447  * Unlike record(), this does not change the handle object.
448  * That means that one will not be able to get the object back
449  * by dereferencing the handle.
450  * Returns the object placed in the store, or nullptr if there
451  * was an error.
452  * If there was already an object in the store with the given key,
453  * then return null, unless @c returnExisting is true, in which case
454  * return success. In either case, @c data is destroyed.
455  */
456 template <class T>
457 inline
458 typename WriteHandle<T>::const_pointer_type
459 WriteHandle<T>::put (const EventContext& ctx,
460  std::unique_ptr<T> data,
461  bool returnExisting /*= false*/) const
462 {
463  IProxyDict* store = nullptr;
464  return doPut (&ctx, std::move(data), returnExisting, store);
465 }
466 
467 
468 /**
469  * @brief Record an object to the store.
470  * @param ctx The event context to use.
471  * @param data The object to record.
472  * @param returnExisting Allow an existing object?
473  *
474  * Unlike record(), this does not change the handle object.
475  * That means that one will not be able to get the object back
476  * by dereferencing the handle.
477  * Returns the object placed in the store, or nullptr if there
478  * was an error.
479  * If there was already an object in the store with the given key,
480  * then return null, unless @c returnExisting is true, in which case
481  * return success. In either case, @c data is destroyed.
482  */
483 template <class T>
484 inline
485 typename WriteHandle<T>::const_pointer_type
486 WriteHandle<T>::put (const EventContext& ctx,
487  std::unique_ptr<const T> data,
488  bool returnExisting /*= false*/) const
489 {
490  IProxyDict* store = nullptr;
491  return doPut (&ctx, std::move(data), returnExisting, store);
492 }
493 
494 
495 /**
496  * @brief Record an object to the store.
497  * @param data The object to record.
498  *
499  * Unlike record(), this does not change the handle object.
500  * That means that one will not be able to get the object back
501  * by dereferencing the handle.
502  * Returns the object placed in the store, or nullptr if there
503  * was an error.
504  *
505  * The event store takes shared ownership of the object.
506  */
507 template <class T>
508 inline
509 typename WriteHandle<T>::const_pointer_type
510 WriteHandle<T>::put (SG::DataObjectSharedPtr<T> data) const
511 {
512  IProxyDict* store = nullptr;
513  return doPut (nullptr, std::move(data), false, store);
514 }
515 
516 
517 /**
518  * @brief Record an object to the store.
519  * @param ctx The event context to use.
520  * @param data The object to record.
521  *
522  * Unlike record(), this does not change the handle object.
523  * That means that one will not be able to get the object back
524  * by dereferencing the handle.
525  * Returns the object placed in the store, or nullptr if there
526  * was an error.
527  *
528  * The event store takes shared ownership of the object.
529  */
530 template <class T>
531 inline
532 typename WriteHandle<T>::const_pointer_type
533 WriteHandle<T>::put (const EventContext& ctx,
534  SG::DataObjectSharedPtr<T> data) const
535 {
536  IProxyDict* store = nullptr;
537  return doPut (&ctx, std::move(data), false, store);
538 }
539 
540 
541 /**
542  * @brief Record an object and its auxiliary store to the store.
543  * @param data The object to record.
544  * @param auxstore Auxiliary store object.
545  *
546  * Unlike record(), this does not change the handle object.
547  * That means that one will not be able to get the object back
548  * by dereferencing the handle.
549  * Returns the object placed in the store, or nullptr if there
550  * was an error.
551  * If there was already an object in the store with the given key,
552  * then return null, and the objects passed in are destroyed.
553  */
554 template <class T>
555 template <class AUXSTORE>
556 typename WriteHandle<T>::const_pointer_type
557 WriteHandle<T>::put (std::unique_ptr<T> data,
558  std::unique_ptr<AUXSTORE> auxstore) const
559 {
560  return doPut (nullptr, std::move(data), std::move(auxstore));
561 }
562 
563 
564 
565 /**
566  * @brief Record an object and its auxiliary store to the store.
567  * @param data The object to record.
568  * @param auxstore Auxiliary store object.
569  *
570  * Unlike record(), this does not change the handle object.
571  * That means that one will not be able to get the object back
572  * by dereferencing the handle.
573  * Returns the object placed in the store, or nullptr if there
574  * was an error.
575  * If there was already an object in the store with the given key,
576  * then return null, and the objects passed in are destroyed.
577  *
578  * Unlike the version taking unique_ptr<T>, this does not alter the
579  * store pointer of @c data.
580  */
581 template <class T>
582 template <class AUXSTORE>
583 typename WriteHandle<T>::const_pointer_type
584 WriteHandle<T>::put (std::unique_ptr<const T> data,
585  std::unique_ptr<const AUXSTORE> auxstore) const
586 {
587  return doPut (nullptr, std::move(data), std::move(auxstore));
588 }
589 
590 
591 /**
592  * @brief Record an object and its auxiliary store to the store.
593  * @param ctx The event context to use.
594  * @param data The object to record.
595  * @param auxstore Auxiliary store object.
596  *
597  * Unlike record(), this does not change the handle object.
598  * That means that one will not be able to get the object back
599  * by dereferencing the handle.
600  * Returns the object placed in the store, or nullptr if there
601  * was an error.
602  * If there was already an object in the store with the given key,
603  * then return null, and the objects passed in are destroyed.
604  */
605 template <class T>
606 template <class AUXSTORE>
607 typename WriteHandle<T>::const_pointer_type
608 WriteHandle<T>::put (const EventContext& ctx,
609  std::unique_ptr<T> data,
610  std::unique_ptr<AUXSTORE> auxstore) const
611 {
612  return doPut (&ctx, std::move(data), std::move(auxstore));
613 }
614 
615 
616 /**
617  * @brief Record an object and its auxiliary store to the store.
618  * @param ctx The event context to use.
619  * @param data The object to record.
620  * @param auxstore Auxiliary store object.
621  *
622  * Unlike record(), this does not change the handle object.
623  * That means that one will not be able to get the object back
624  * by dereferencing the handle.
625  * Returns the object placed in the store, or nullptr if there
626  * was an error.
627  * If there was already an object in the store with the given key,
628  * then return null, and the objects passed in are destroyed.
629  *
630  * Unlike the version taking unique_ptr<T>, this does not alter the
631  * store pointer of @c data.
632  */
633 template <class T>
634 template <class AUXSTORE>
635 typename WriteHandle<T>::const_pointer_type
636 WriteHandle<T>::put (const EventContext& ctx,
637  std::unique_ptr<const T> data,
638  std::unique_ptr<const AUXSTORE> auxstore) const
639 {
640  return doPut (&ctx, std::move(data), std::move(auxstore));
641 }
642 
643 
644 /**
645  * @brief Alternate notation for record. Records a non-const object.
646  * @param data Object to record.
647  *
648  * Throws an exception on failure.
649  */
650 template <class T>
651 WriteHandle<T>&
652 WriteHandle<T>::operator= (std::unique_ptr<T> data)
653 {
654  if (recordNonConst (std::move(data)).isFailure()) {
655  throw std::runtime_error ("WriteHandle<T>::operator=(unique_ptr) Record failed.");
656  }
657  return *this;
658 }
659 
660 
661 /**
662  * @brief Make an alias.
663  * @param key Alternate key by which the referenced object should be known.
664  *
665  * The current handle should be valid and referencing an object
666  * (i.e., @c record should have been called on it).
667  *
668  * The object will also be known by the name given in @c key.
669  */
670 template <class T>
671 StatusCode WriteHandle<T>::alias (const WriteHandleKey<T>& key)
672 {
673  return symLink_impl (this->clid(), key.key());
674 }
675 
676 
677 /**
678  * @brief Make an explicit link.
679  * @param key Alternate clid by which the referenced object
680  * should be known. The SG key must match the key of the
681  * current handle.
682  *
683  * You should generally not be using this!
684  *
685  * The current handle should be valid and referencing an object
686  * (i.e., @c record should have been called on it).
687  *
688  * This makes a symlink: the object will be retrievable
689  * as a different type.
690  *
691  * Note that if @c T and @c @U are related via @c SG_BASE and/or
692  * @c DATAVECTOR_BASE, then you shouldn't need to explicitly make a symlink;
693  * that should happen automatically.
694  *
695  * If a @c U* is not convertable to a @c T* via C++ rules, then you likely
696  * will be, at best, relying on undefined behavior. You will probably
697  * get warnings from the undefined behavior sanitizer when if you try
698  * to dereference the @c U*.
699  *
700  * This usage is here mainly to assist in migrating some existing
701  * patterns to MT. You should think several times before using
702  * in new code.
703  */
704 template <class T>
705 template <class U>
706 StatusCode WriteHandle<T>::symLink (const WriteHandleKey<U>& other)
707 {
708  if (this->key() != other.key()) {
709  REPORT_ERROR (StatusCode::FAILURE)
710  << "symLink: SG keys do not match: " << other.key() << " vs "
711  << this->key();
712  return StatusCode::FAILURE;
713  }
714  return symLink_impl (other.clid(), other.key());
715 }
716 
717 
718 /**
719  * @brief Return the cached pointer directly.
720  *
721  * If it is null, throw ExcNullWriteHandle.
722  */
723 template <class T>
724 typename WriteHandle<T>::pointer_type
725 WriteHandle<T>::checkedCachedPtr()
726 {
727  if (!m_ptr)
728  throwExcNullWriteHandle (clid(), key(), store());
729  return cachedPtr();
730 }
731 
732 
733 /**
734  * @brief Helper for record.
735  * @param data The object to record.
736  * @param isConst If true, record the object as const.
737  * @param returnExisting Allow an existing object.
738  */
739 template <class T>
740 template <class U>
741 StatusCode WriteHandle<T>::doRecord (U data,
742  bool isConst,
743  bool returnExisting)
744 {
745  typedef typename U::element_type elt_t;
746 
747  // make sure the BaseInfo(Base) structure is initialized
748  SG::BaseInfo<elt_t>::baseinfo();
749 
750  // If s_isConst is set for this type, then we want to automatically
751  // make it const when recorded.
752  bool allowMods = !isConst;
753  if (ClassID_traits<elt_t>::s_isConst)
754  allowMods = false;
755 
756  void* dataPtr(data.get());
757  std::unique_ptr<DataObject> dobj (SG::asStorable (std::move (data)));
758  return this->record_impl (std::move(dobj), dataPtr, allowMods, returnExisting);
759 }
760 
761 
762 /**
763  * @brief Helper for put.
764  * @param ctx The event context, or nullptr to use the current context.
765  * @param data The object to record.
766  * @param returnExisting Allow an existing object.
767  * @param[out] store The store being used.
768  *
769  * Unlike record(), this does not change the handle object.
770  * That means that will not be able to get the object back
771  * by dereferencing the handle.
772  * Returns the object placed in the store, or nullptr if there
773  * was an error.
774  * If there was already an object in the store with the given key,
775  * then return null, unless @c returnExisting is true, in which case
776  * return success. In either case, @c data is destroyed.
777  */
778 template <class T>
779 template <class U>
780 typename WriteHandle<T>::const_pointer_type
781 WriteHandle<T>::doPut (const EventContext* ctx,
782  U data,
783  bool returnExisting,
784  IProxyDict* & store) const
785 {
786  //typedef typename U::element_type elt_t;
787  typedef T elt_t;
788 
789  // make sure the BaseInfo(Base) structure is initialized
790  SG::BaseInfo<elt_t>::baseinfo();
791 
792  const void* dataPtr = data.get();
793  std::unique_ptr<DataObject> dobj (SG::asStorable (std::move (data)));
794  return reinterpret_cast<const T*>
795  (this->put_impl (ctx, std::move(dobj), dataPtr, false, returnExisting, store));
796 }
797 
798 
799 /**
800  * @brief Helper for recording an object and its auxiliary store to the store.
801  * @param ctx The event context, or nullptr to use the current context.
802  * @param data The object to record.
803  * @param auxstore Auxiliary store object.
804  *
805  * Unlike record(), this does not change the handle object.
806  * That means that will not be able to get the object back
807  * by dereferencing the handle.
808  * Returns the object placed in the store, or nullptr if there
809  * was an error.
810  * If there was already an object in the store with the given key,
811  * then return null, and the objects passed in are destroyed.
812  */
813 template <class T>
814 template <class AUXSTORE>
815 typename WriteHandle<T>::const_pointer_type
816 WriteHandle<T>::doPut (const EventContext* ctx,
817  std::unique_ptr<T> data,
818  std::unique_ptr<AUXSTORE> auxstore) const
819 {
820  T& dref = *data;
821 
822  // If there's no store association, do it now.
823  if (data->getStore() == nullptr)
824  data->setStore (auxstore.get());
825 
826  IProxyDict* store = nullptr;
827  const T* ptr = this->doPut (ctx, std::move(data), false, store);
828  if (!ptr) return nullptr;
829 
830  SG::DataObjectSharedPtr<DataObject> dobj
831  (SG::asStorable (std::move (auxstore)));
832  SG::DataProxy* proxy = store->recordObject (std::move(dobj),
833  this->name() + "Aux.",
834  false,
835  false);
836  if (!proxy) {
837  REPORT_ERROR (StatusCode::FAILURE)
838  << "recordObject of aux store failed";
839 
840  // If we've failed here, then the aux store object has been deleted,
841  // but not the primary object. Null out the store pointer to prevent
842  // having a dangling pointer to a deleted object.
843  dref.setStore (static_cast<SG::IConstAuxStore*>(nullptr));
844  return nullptr;
845  }
846 
847  return ptr;
848 }
849 
850 
851 /**
852  * @brief Helper for recording an object and its auxiliary store to the store.
853  * @param ctx The event context, or nullptr to use the current context.
854  * @param data The object to record.
855  * @param auxstore Auxiliary store object.
856  *
857  * Unlike record(), this does not change the handle object.
858  * That means that will not be able to get the object back
859  * by dereferencing the handle.
860  * Returns the object placed in the store, or nullptr if there
861  * was an error.
862  * If there was already an object in the store with the given key,
863  * then return null, and the objects passed in are destroyed.
864  */
865 template <class T>
866 template <class AUXSTORE>
867 typename WriteHandle<T>::const_pointer_type
868 WriteHandle<T>::doPut (const EventContext* ctx,
869  std::unique_ptr<const T> data,
870  std::unique_ptr<const AUXSTORE> auxstore) const
871 {
872  IProxyDict* store = nullptr;
873  const T* ptr = this->doPut (ctx, std::move(data), false, store);
874  if (!ptr) return nullptr;
875 
876  SG::DataObjectSharedPtr<DataObject> dobj
877  (SG::asStorable (std::move (auxstore)));
878  SG::DataProxy* proxy = store->recordObject (std::move(dobj),
879  this->name() + "Aux.",
880  false,
881  false);
882  if (!proxy) {
883  REPORT_ERROR (StatusCode::FAILURE)
884  << "recordObject of aux store failed";
885  return nullptr;
886  }
887 
888  return ptr;
889 }
890 
891 
892 /**
893  * @brief Record an object and its auxiliary store to the store.
894  * @param data The object to record.
895  * @param auxstore Auxiliary store object.
896  * @param isConst If true, record the objects as const.
897  */
898 template <class T>
899 template <class AUXSTORE>
900 StatusCode
901 WriteHandle<T>::record (std::unique_ptr<T> data,
902  std::unique_ptr<AUXSTORE> auxstore,
903  bool isConst)
904 {
905  T& dref = *data;
906 
907  // If there's no store association, do it now.
908  if (data->getStore() == nullptr)
909  data->setStore (auxstore.get());
910 
911  if (isConst) {
912  // Temporarily clear the store association, in order to prevent
913  // the aux store from being locked at this point.
914  IAuxStore* store = dref.getStore();
915  if (store)
916  dref.setStore (static_cast<SG::IAuxStore*>(nullptr));
917  CHECK (this->record(std::move(data)));
918  // Deliberately not using RAII here. If there is an error,
919  // then the object referenced by data will be deleted.
920  dref.setStore (store);
921  }
922  else
923  CHECK (this->recordNonConst(std::move(data)));
924 
925  // Store and proxy must be valid if we get to this point.
926 
927  SG::DataObjectSharedPtr<DataObject> dobj
928  (SG::asStorable (std::move (auxstore)));
929  SG::DataProxy* proxy = m_store->recordObject (std::move(dobj),
930  this->name() + "Aux.",
931  true,
932  false);
933  if (!proxy) {
934  REPORT_ERROR (StatusCode::FAILURE)
935  << "recordObject of aux store failed";
936 
937  // If we've failed here, then the aux store object has been deleted,
938  // but not the primary object. Null out the store pointer to prevent
939  // having a dangling pointer to a deleted object.
940  dref.setStore (static_cast<SG::IConstAuxStore*>(nullptr));
941  return StatusCode::FAILURE;
942  }
943 
944  if (m_proxy->isConst())
945  m_lockAuxPending = proxy;
946 
947  return StatusCode::SUCCESS;
948 }
949 
950 
951 /**
952  * @brief Return a @c WriteHandle referencing @c key.
953  * @param key The key object holding the clid/key/store.
954  *
955  * This will raise an exception if the StoreGate key is blank,
956  * or if the event store cannot be found.
957  */
958 template <class T>
959 WriteHandle<T> makeHandle (const WriteHandleKey<T>& key)
960 {
961  return WriteHandle<T> (key);
962 }
963 
964 
965 /**
966  * @brief Return a @c WriteHandle referencing @c key for an explicit context.
967  * @param key The key object holding the clid/key/store.
968  * @param ctx The event context.
969  *
970  * This will raise an exception if the StoreGate key is blank,
971  * or if the event store cannot be found.
972  *
973  * If the default event store has been requested, then the thread-specific
974  * store from the event context will be used.
975  */
976 template <class T>
977 WriteHandle<T> makeHandle (const WriteHandleKey<T>& key,
978  const EventContext& ctx)
979 {
980  return WriteHandle<T> (key, ctx);
981 }
982 
983 
984 } /* namespace SG */
985 
986 
987 #endif //> !STOREGATE_SG_WRITEHANDLE_ICC