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 inline
346 StatusCode
347 WriteHandle<T>::record (SG::DataObjectSharedPtr<T> data)
348 {
349  return this->doRecord (std::move(data), true, false);
350 }
351 
352 
353 /**
354  * @brief Record a non-const shared DataObject to the store.
355  * @param data The object to record.
356  *
357  * The event store takes shared ownership of the object.
358  */
359 template <class T>
360 inline
361 StatusCode
362 WriteHandle<T>::recordNonConst (SG::DataObjectSharedPtr<T> data)
363 {
364  return this->doRecord (std::move(data), false, false);
365 }
366 
367 
368 /**
369  * @brief Record an object to the store.
370  * @param data The object to record.
371  * @param returnExisting Allow an existing object?
372  *
373  * Unlike record(), this does not change the handle object.
374  * That means that one will not be able to get the object back
375  * by dereferencing the handle.
376  * Returns the object placed in the store, or nullptr if there
377  * was an error.
378  * If there was already an object in the store with the given key,
379  * then return null, unless @c returnExisting is true, in which case
380  * return success. In either case, @c data is destroyed.
381  */
382 template <class T>
383 inline
384 typename WriteHandle<T>::const_pointer_type
385 WriteHandle<T>::put (std::unique_ptr<T> data,
386  bool returnExisting /*= false*/) const
387 {
388  IProxyDict* store = nullptr;
389  return doPut (nullptr, std::move(data), returnExisting, store);
390 }
391 
392 
393 /**
394  * @brief Record an object to the store.
395  * @param data The object to record.
396  * @param returnExisting Allow an existing object?
397  *
398  * Unlike record(), this does not change the handle object.
399  * That means that one will not be able to get the object back
400  * by dereferencing the handle.
401  * Returns the object placed in the store, or nullptr if there
402  * was an error.
403  * If there was already an object in the store with the given key,
404  * then return null, unless @c returnExisting is true, in which case
405  * return success. In either case, @c data is destroyed.
406  */
407 template <class T>
408 inline
409 typename WriteHandle<T>::const_pointer_type
410 WriteHandle<T>::put (std::unique_ptr<const T> data,
411  bool returnExisting /*= false*/) const
412 {
413  IProxyDict* store = nullptr;
414  return doPut (nullptr, std::move(data), returnExisting, store);
415 }
416 
417 
418 /**
419  * @brief Record an object to the store.
420  * @param data The object to record.
421  * @param returnExisting Allow an existing object?
422  *
423  * Unlike record(), this does not change the handle object.
424  * That means that one will not be able to get the object back
425  * by dereferencing the handle.
426  * Returns the object placed in the store, or nullptr if there
427  * was an error.
428  * If there was already an object in the store with the given key,
429  * then return null, unless @c returnExisting is true, in which case
430  * return success. In either case, @c data is destroyed.
431  */
432 template <class T>
433 inline
434 typename WriteHandle<T>::const_pointer_type
435 WriteHandle<T>::put (std::unique_ptr<const ConstDataVector<T> > data,
436  bool returnExisting /*= false*/) const
437 {
438  IProxyDict* store = nullptr;
439  std::unique_ptr<const T> coll (data.release()->asDataVector());
440  return doPut (nullptr, std::move(coll), returnExisting, store);
441 }
442 
443 
444 /**
445  * @brief Record an object to the store.
446  * @param ctx The event context to use.
447  * @param data The object to record.
448  * @param returnExisting Allow an existing object?
449  *
450  * Unlike record(), this does not change the handle object.
451  * That means that one will not be able to get the object back
452  * by dereferencing the handle.
453  * Returns the object placed in the store, or nullptr if there
454  * was an error.
455  * If there was already an object in the store with the given key,
456  * then return null, unless @c returnExisting is true, in which case
457  * return success. In either case, @c data is destroyed.
458  */
459 template <class T>
460 inline
461 typename WriteHandle<T>::const_pointer_type
462 WriteHandle<T>::put (const EventContext& ctx,
463  std::unique_ptr<const ConstDataVector<T> > data,
464  bool returnExisting /*= false*/) const
465 {
466  IProxyDict* store = nullptr;
467  std::unique_ptr<const T> coll (data.release()->asDataVector());
468  return doPut (&ctx, std::move(coll), returnExisting, store);
469 }
470 
471 
472 /**
473  * @brief Record an object to the store.
474  * @param ctx The event context to use.
475  * @param data The object to record.
476  * @param returnExisting Allow an existing object?
477  *
478  * Unlike record(), this does not change the handle object.
479  * That means that one will not be able to get the object back
480  * by dereferencing the handle.
481  * Returns the object placed in the store, or nullptr if there
482  * was an error.
483  * If there was already an object in the store with the given key,
484  * then return null, unless @c returnExisting is true, in which case
485  * return success. In either case, @c data is destroyed.
486  */
487 template <class T>
488 inline
489 typename WriteHandle<T>::const_pointer_type
490 WriteHandle<T>::put (const EventContext& ctx,
491  std::unique_ptr<T> data,
492  bool returnExisting /*= false*/) const
493 {
494  IProxyDict* store = nullptr;
495  return doPut (&ctx, std::move(data), returnExisting, store);
496 }
497 
498 
499 /**
500  * @brief Record an object to the store.
501  * @param ctx The event context to use.
502  * @param data The object to record.
503  * @param returnExisting Allow an existing object?
504  *
505  * Unlike record(), this does not change the handle object.
506  * That means that one will not be able to get the object back
507  * by dereferencing the handle.
508  * Returns the object placed in the store, or nullptr if there
509  * was an error.
510  * If there was already an object in the store with the given key,
511  * then return null, unless @c returnExisting is true, in which case
512  * return success. In either case, @c data is destroyed.
513  */
514 template <class T>
515 inline
516 typename WriteHandle<T>::const_pointer_type
517 WriteHandle<T>::put (const EventContext& ctx,
518  std::unique_ptr<const T> data,
519  bool returnExisting /*= false*/) const
520 {
521  IProxyDict* store = nullptr;
522  return doPut (&ctx, std::move(data), returnExisting, store);
523 }
524 
525 
526 /**
527  * @brief Record an object to the store.
528  * @param data The object to record.
529  *
530  * Unlike record(), this does not change the handle object.
531  * That means that one will not be able to get the object back
532  * by dereferencing the handle.
533  * Returns the object placed in the store, or nullptr if there
534  * was an error.
535  *
536  * The event store takes shared ownership of the object.
537  */
538 template <class T>
539 inline
540 typename WriteHandle<T>::const_pointer_type
541 WriteHandle<T>::put (SG::DataObjectSharedPtr<T> data) const
542 {
543  IProxyDict* store = nullptr;
544  return doPut (nullptr, std::move(data), false, store);
545 }
546 
547 
548 /**
549  * @brief Record an object to the store.
550  * @param ctx The event context to use.
551  * @param data The object to record.
552  *
553  * Unlike record(), this does not change the handle object.
554  * That means that one will not be able to get the object back
555  * by dereferencing the handle.
556  * Returns the object placed in the store, or nullptr if there
557  * was an error.
558  *
559  * The event store takes shared ownership of the object.
560  */
561 template <class T>
562 inline
563 typename WriteHandle<T>::const_pointer_type
564 WriteHandle<T>::put (const EventContext& ctx,
565  SG::DataObjectSharedPtr<T> data) const
566 {
567  IProxyDict* store = nullptr;
568  return doPut (&ctx, std::move(data), false, store);
569 }
570 
571 
572 /**
573  * @brief Record an object and its auxiliary store to the store.
574  * @param data The object to record.
575  * @param auxstore Auxiliary store object.
576  *
577  * Unlike record(), this does not change the handle object.
578  * That means that one will not be able to get the object back
579  * by dereferencing the handle.
580  * Returns the object placed in the store, or nullptr if there
581  * was an error.
582  * If there was already an object in the store with the given key,
583  * then return null, and the objects passed in are destroyed.
584  */
585 template <class T>
586 template <class AUXSTORE>
587 typename WriteHandle<T>::const_pointer_type
588 WriteHandle<T>::put (std::unique_ptr<T> data,
589  std::unique_ptr<AUXSTORE> auxstore) const
590 {
591  return doPut (nullptr, std::move(data), std::move(auxstore));
592 }
593 
594 
595 
596 /**
597  * @brief Record an object and its auxiliary store to the store.
598  * @param data The object to record.
599  * @param auxstore Auxiliary store object.
600  *
601  * Unlike record(), this does not change the handle object.
602  * That means that one will not be able to get the object back
603  * by dereferencing the handle.
604  * Returns the object placed in the store, or nullptr if there
605  * was an error.
606  * If there was already an object in the store with the given key,
607  * then return null, and the objects passed in are destroyed.
608  *
609  * Unlike the version taking unique_ptr<T>, this does not alter the
610  * store pointer of @c data.
611  */
612 template <class T>
613 template <class AUXSTORE>
614 typename WriteHandle<T>::const_pointer_type
615 WriteHandle<T>::put (std::unique_ptr<const T> data,
616  std::unique_ptr<const AUXSTORE> auxstore) const
617 {
618  return doPut (nullptr, std::move(data), std::move(auxstore));
619 }
620 
621 
622 /**
623  * @brief Record an object and its auxiliary store to the store.
624  * @param ctx The event context to use.
625  * @param data The object to record.
626  * @param auxstore Auxiliary store object.
627  *
628  * Unlike record(), this does not change the handle object.
629  * That means that one will not be able to get the object back
630  * by dereferencing the handle.
631  * Returns the object placed in the store, or nullptr if there
632  * was an error.
633  * If there was already an object in the store with the given key,
634  * then return null, and the objects passed in are destroyed.
635  */
636 template <class T>
637 template <class AUXSTORE>
638 typename WriteHandle<T>::const_pointer_type
639 WriteHandle<T>::put (const EventContext& ctx,
640  std::unique_ptr<T> data,
641  std::unique_ptr<AUXSTORE> auxstore) const
642 {
643  return doPut (&ctx, std::move(data), std::move(auxstore));
644 }
645 
646 
647 /**
648  * @brief Record an object and its auxiliary store to the store.
649  * @param ctx The event context to use.
650  * @param data The object to record.
651  * @param auxstore Auxiliary store object.
652  *
653  * Unlike record(), this does not change the handle object.
654  * That means that one will not be able to get the object back
655  * by dereferencing the handle.
656  * Returns the object placed in the store, or nullptr if there
657  * was an error.
658  * If there was already an object in the store with the given key,
659  * then return null, and the objects passed in are destroyed.
660  *
661  * Unlike the version taking unique_ptr<T>, this does not alter the
662  * store pointer of @c data.
663  */
664 template <class T>
665 template <class AUXSTORE>
666 typename WriteHandle<T>::const_pointer_type
667 WriteHandle<T>::put (const EventContext& ctx,
668  std::unique_ptr<const T> data,
669  std::unique_ptr<const AUXSTORE> auxstore) const
670 {
671  return doPut (&ctx, std::move(data), std::move(auxstore));
672 }
673 
674 
675 /**
676  * @brief Alternate notation for record. Records a non-const object.
677  * @param data Object to record.
678  *
679  * Throws an exception on failure.
680  */
681 template <class T>
682 WriteHandle<T>&
683 WriteHandle<T>::operator= (std::unique_ptr<T> data)
684 {
685  if (recordNonConst (std::move(data)).isFailure()) {
686  throw std::runtime_error ("WriteHandle<T>::operator=(unique_ptr) Record failed.");
687  }
688  return *this;
689 }
690 
691 
692 /**
693  * @brief Make an alias.
694  * @param key Alternate key by which the referenced object should be known.
695  *
696  * The current handle should be valid and referencing an object
697  * (i.e., @c record should have been called on it).
698  *
699  * The object will also be known by the name given in @c key.
700  */
701 template <class T>
702 StatusCode WriteHandle<T>::alias (const WriteHandleKey<T>& key)
703 {
704  return symLink_impl (this->clid(), key.key());
705 }
706 
707 
708 /**
709  * @brief Make an explicit link.
710  * @param key Alternate clid by which the referenced object
711  * should be known. The SG key must match the key of the
712  * current handle.
713  *
714  * You should generally not be using this!
715  *
716  * The current handle should be valid and referencing an object
717  * (i.e., @c record should have been called on it).
718  *
719  * This makes a symlink: the object will be retrievable
720  * as a different type.
721  *
722  * Note that if @c T and @c @U are related via @c SG_BASE and/or
723  * @c DATAVECTOR_BASE, then you shouldn't need to explicitly make a symlink;
724  * that should happen automatically.
725  *
726  * If a @c U* is not convertable to a @c T* via C++ rules, then you likely
727  * will be, at best, relying on undefined behavior. You will probably
728  * get warnings from the undefined behavior sanitizer when if you try
729  * to dereference the @c U*.
730  *
731  * This usage is here mainly to assist in migrating some existing
732  * patterns to MT. You should think several times before using
733  * in new code.
734  */
735 template <class T>
736 template <class U>
737 StatusCode WriteHandle<T>::symLink (const WriteHandleKey<U>& other)
738 {
739  if (this->key() != other.key()) {
740  REPORT_ERROR (StatusCode::FAILURE)
741  << "symLink: SG keys do not match: " << other.key() << " vs "
742  << this->key();
743  return StatusCode::FAILURE;
744  }
745  return symLink_impl (other.clid(), other.key());
746 }
747 
748 
749 /**
750  * @brief Return the cached pointer directly.
751  *
752  * If it is null, throw ExcNullWriteHandle.
753  */
754 template <class T>
755 typename WriteHandle<T>::pointer_type
756 WriteHandle<T>::checkedCachedPtr()
757 {
758  if (!m_ptr)
759  throwExcNullWriteHandle (clid(), key(), store());
760  return cachedPtr();
761 }
762 
763 
764 /**
765  * @brief Helper for record.
766  * @param data The object to record.
767  * @param isConst If true, record the object as const.
768  * @param returnExisting Allow an existing object.
769  */
770 template <class T>
771 template <class U>
772 StatusCode WriteHandle<T>::doRecord (U data,
773  bool isConst,
774  bool returnExisting)
775 {
776  typedef typename U::element_type elt_t;
777 
778  // make sure the BaseInfo(Base) structure is initialized
779  SG::BaseInfo<elt_t>::baseinfo();
780 
781  // If s_isConst is set for this type, then we want to automatically
782  // make it const when recorded.
783  bool allowMods = !isConst;
784  if (ClassID_traits<elt_t>::s_isConst)
785  allowMods = false;
786 
787  void* dataPtr(data.get());
788  std::unique_ptr<DataObject> dobj (SG::asStorable (std::move (data)));
789  return this->record_impl (std::move(dobj), dataPtr, allowMods, returnExisting);
790 }
791 
792 
793 /**
794  * @brief Helper for put.
795  * @param ctx The event context, or nullptr to use the current context.
796  * @param data The object to record.
797  * @param returnExisting Allow an existing object.
798  * @param[out] store The store being used.
799  *
800  * Unlike record(), this does not change the handle object.
801  * That means that will not be able to get the object back
802  * by dereferencing the handle.
803  * Returns the object placed in the store, or nullptr if there
804  * was an error.
805  * If there was already an object in the store with the given key,
806  * then return null, unless @c returnExisting is true, in which case
807  * return success. In either case, @c data is destroyed.
808  */
809 template <class T>
810 template <class U>
811 typename WriteHandle<T>::const_pointer_type
812 WriteHandle<T>::doPut (const EventContext* ctx,
813  U data,
814  bool returnExisting,
815  IProxyDict* & store) const
816 {
817  //typedef typename U::element_type elt_t;
818  typedef T elt_t;
819 
820  // make sure the BaseInfo(Base) structure is initialized
821  SG::BaseInfo<elt_t>::baseinfo();
822 
823  const void* dataPtr = data.get();
824  std::unique_ptr<DataObject> dobj (SG::asStorable (std::move (data)));
825  return reinterpret_cast<const T*>
826  (this->put_impl (ctx, std::move(dobj), dataPtr, false, returnExisting, store));
827 }
828 
829 
830 /**
831  * @brief Helper for recording an object and its auxiliary store to the store.
832  * @param ctx The event context, or nullptr to use the current context.
833  * @param data The object to record.
834  * @param auxstore Auxiliary store object.
835  *
836  * Unlike record(), this does not change the handle object.
837  * That means that will not be able to get the object back
838  * by dereferencing the handle.
839  * Returns the object placed in the store, or nullptr if there
840  * was an error.
841  * If there was already an object in the store with the given key,
842  * then return null, and the objects passed in are destroyed.
843  */
844 template <class T>
845 template <class AUXSTORE>
846 typename WriteHandle<T>::const_pointer_type
847 WriteHandle<T>::doPut (const EventContext* ctx,
848  std::unique_ptr<T> data,
849  std::unique_ptr<AUXSTORE> auxstore) const
850 {
851  T& dref = *data;
852 
853  // If there's no store association, do it now.
854  if (data->getStore() == nullptr)
855  data->setStore (auxstore.get());
856 
857  IProxyDict* store = nullptr;
858  const T* ptr = this->doPut (ctx, std::move(data), false, store);
859  if (!ptr) return nullptr;
860 
861  SG::DataObjectSharedPtr<DataObject> dobj
862  (SG::asStorable (std::move (auxstore)));
863  SG::DataProxy* proxy = store->recordObject (std::move(dobj),
864  this->name() + "Aux.",
865  false,
866  false);
867  if (!proxy) {
868  REPORT_ERROR (StatusCode::FAILURE)
869  << "recordObject of aux store failed";
870 
871  // If we've failed here, then the aux store object has been deleted,
872  // but not the primary object. Null out the store pointer to prevent
873  // having a dangling pointer to a deleted object.
874  dref.setStore (static_cast<SG::IConstAuxStore*>(nullptr));
875  return nullptr;
876  }
877 
878  return ptr;
879 }
880 
881 
882 /**
883  * @brief Helper for recording an object and its auxiliary store to the store.
884  * @param ctx The event context, or nullptr to use the current context.
885  * @param data The object to record.
886  * @param auxstore Auxiliary store object.
887  *
888  * Unlike record(), this does not change the handle object.
889  * That means that will not be able to get the object back
890  * by dereferencing the handle.
891  * Returns the object placed in the store, or nullptr if there
892  * was an error.
893  * If there was already an object in the store with the given key,
894  * then return null, and the objects passed in are destroyed.
895  */
896 template <class T>
897 template <class AUXSTORE>
898 typename WriteHandle<T>::const_pointer_type
899 WriteHandle<T>::doPut (const EventContext* ctx,
900  std::unique_ptr<const T> data,
901  std::unique_ptr<const AUXSTORE> auxstore) const
902 {
903  IProxyDict* store = nullptr;
904  const T* ptr = this->doPut (ctx, std::move(data), false, store);
905  if (!ptr) return nullptr;
906 
907  SG::DataObjectSharedPtr<DataObject> dobj
908  (SG::asStorable (std::move (auxstore)));
909  SG::DataProxy* proxy = store->recordObject (std::move(dobj),
910  this->name() + "Aux.",
911  false,
912  false);
913  if (!proxy) {
914  REPORT_ERROR (StatusCode::FAILURE)
915  << "recordObject of aux store failed";
916  return nullptr;
917  }
918 
919  return ptr;
920 }
921 
922 
923 /**
924  * @brief Record an object and its auxiliary store to the store.
925  * @param data The object to record.
926  * @param auxstore Auxiliary store object.
927  * @param isConst If true, record the objects as const.
928  */
929 template <class T>
930 template <class AUXSTORE>
931 StatusCode
932 WriteHandle<T>::record (std::unique_ptr<T> data,
933  std::unique_ptr<AUXSTORE> auxstore,
934  bool isConst)
935 {
936  T& dref = *data;
937 
938  // If there's no store association, do it now.
939  if (data->getStore() == nullptr)
940  data->setStore (auxstore.get());
941 
942  if (isConst) {
943  // Temporarily clear the store association, in order to prevent
944  // the aux store from being locked at this point.
945  IAuxStore* store = dref.getStore();
946  if (store)
947  dref.setStore (static_cast<SG::IAuxStore*>(nullptr));
948  CHECK (this->record(std::move(data)));
949  // Deliberately not using RAII here. If there is an error,
950  // then the object referenced by data will be deleted.
951  dref.setStore (store);
952  }
953  else
954  CHECK (this->recordNonConst(std::move(data)));
955 
956  // Store and proxy must be valid if we get to this point.
957 
958  SG::DataObjectSharedPtr<DataObject> dobj
959  (SG::asStorable (std::move (auxstore)));
960  SG::DataProxy* proxy = m_store->recordObject (std::move(dobj),
961  this->name() + "Aux.",
962  true,
963  false);
964  if (!proxy) {
965  REPORT_ERROR (StatusCode::FAILURE)
966  << "recordObject of aux store failed";
967 
968  // If we've failed here, then the aux store object has been deleted,
969  // but not the primary object. Null out the store pointer to prevent
970  // having a dangling pointer to a deleted object.
971  dref.setStore (static_cast<SG::IConstAuxStore*>(nullptr));
972  return StatusCode::FAILURE;
973  }
974 
975  if (m_proxy->isConst())
976  m_lockAuxPending = proxy;
977 
978  return StatusCode::SUCCESS;
979 }
980 
981 
982 /**
983  * @brief Return a @c WriteHandle referencing @c key.
984  * @param key The key object holding the clid/key/store.
985  *
986  * This will raise an exception if the StoreGate key is blank,
987  * or if the event store cannot be found.
988  */
989 template <class T>
990 WriteHandle<T> makeHandle (const WriteHandleKey<T>& key)
991 {
992  return WriteHandle<T> (key);
993 }
994 
995 
996 /**
997  * @brief Return a @c WriteHandle referencing @c key for an explicit context.
998  * @param key The key object holding the clid/key/store.
999  * @param ctx The event context.
1000  *
1001  * This will raise an exception if the StoreGate key is blank,
1002  * or if the event store cannot be found.
1003  *
1004  * If the default event store has been requested, then the thread-specific
1005  * store from the event context will be used.
1006  */
1007 template <class T>
1008 WriteHandle<T> makeHandle (const WriteHandleKey<T>& key,
1009  const EventContext& ctx)
1010 {
1011  return WriteHandle<T> (key, ctx);
1012 }
1013 
1014 
1015 } /* namespace SG */
1016 
1017 
1018 #endif //> !STOREGATE_SG_WRITEHANDLE_ICC