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