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