ATLAS Offline Software
Loading...
Searching...
No Matches
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
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,
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 */
77template <class T>
78inline
79WriteHandle<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 */
95template <class T>
96inline
97WriteHandle<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 */
114template <class T>
115inline
116WriteHandle<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 */
127template <class T>
128inline
129WriteHandle<T>::WriteHandle(const WriteHandle& h)
130 : VarHandleBase(h)
131{
132}
133
134
135/**
136 * @brief Move constructor.
137 */
138template <class T>
139WriteHandle<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 */
150template <class T>
151inline
152WriteHandle<T>&
153// m_lockAuxPending not copied --- want lifetime to stay with the
154// original WH.
155// cppcheck-suppress operatorEqVarError
156WriteHandle<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 */
167template <class T>
168inline
169WriteHandle<T>&
170WriteHandle<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 */
186template <class T>
187WriteHandle<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 */
204template <class T>
205inline
206typename WriteHandle<T>::pointer_type
207WriteHandle<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 */
217template <class T>
218inline
219typename WriteHandle<T>::reference_type
220WriteHandle<T>::operator*()
221{
222 return *WriteHandle<T>::checkedCachedPtr();
223}
224
225
226/**
227 * @brief Dereference the pointer.
228 * Returns the cached pointer.
229 */
230template <class T>
231inline
232typename WriteHandle<T>::const_pointer_type
233WriteHandle<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 */
243template <class T>
244inline
245typename WriteHandle<T>::pointer_type
246WriteHandle<T>::ptr()
247{
248 return cachedPtr();
249}
250
251
252/**
253 * @brief Return the cached pointer directly; no lookup.
254 */
255template <class T>
256inline
257typename WriteHandle<T>::pointer_type
258WriteHandle<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 */
267template <class T>
268inline
269bool 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 */
283template <class T>
284inline
285StatusCode
286WriteHandle<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 */
297template <class T>
298inline
299StatusCode
300WriteHandle<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 */
311template <class T>
312template <class AUXSTORE>
313inline
314StatusCode
315WriteHandle<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 */
327template <class T>
328template <class AUXSTORE>
329inline
330StatusCode
331WriteHandle<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 */
344template <class T>
345template <std::derived_from<DataObject> DOBJ>
346requires std::convertible_to<DOBJ*, T*>
347inline
348StatusCode
349WriteHandle<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 */
361template <class T>
362template <std::derived_from<DataObject> DOBJ>
363requires std::convertible_to<DOBJ*, T*>
364inline
365StatusCode
366WriteHandle<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 */
386template <class T>
387inline
388typename WriteHandle<T>::const_pointer_type
389WriteHandle<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 */
411template <class T>
412inline
413typename WriteHandle<T>::const_pointer_type
414WriteHandle<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 */
436template <class T>
437inline
438typename WriteHandle<T>::const_pointer_type
439WriteHandle<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 */
463template <class T>
464inline
465typename WriteHandle<T>::const_pointer_type
466WriteHandle<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 */
491template <class T>
492inline
493typename WriteHandle<T>::const_pointer_type
494WriteHandle<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 */
518template <class T>
519inline
520typename WriteHandle<T>::const_pointer_type
521WriteHandle<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 */
542template <class T>
543template <std::derived_from<DataObject> DOBJ>
544requires std::convertible_to<DOBJ*, T*>
545inline
546typename WriteHandle<T>::const_pointer_type
547WriteHandle<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 */
567template <class T>
568template <std::derived_from<DataObject> DOBJ>
569requires std::convertible_to<DOBJ*, T*>
570inline
571typename WriteHandle<T>::const_pointer_type
572WriteHandle<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 */
593template <class T>
594template <class AUXSTORE>
595typename WriteHandle<T>::const_pointer_type
596WriteHandle<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 */
620template <class T>
621template <class AUXSTORE>
622typename WriteHandle<T>::const_pointer_type
623WriteHandle<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 */
644template <class T>
645template <class AUXSTORE>
646typename WriteHandle<T>::const_pointer_type
647WriteHandle<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 */
672template <class T>
673template <class AUXSTORE>
674typename WriteHandle<T>::const_pointer_type
675WriteHandle<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 */
689template <class T>
690WriteHandle<T>&
691WriteHandle<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 */
709template <class T>
710StatusCode 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 */
743template <class T>
744template <class U>
745StatusCode 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 */
762template <class T>
763typename WriteHandle<T>::pointer_type
764WriteHandle<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 */
778template <class T>
779template <class U>
780StatusCode 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 */
817template <class T>
818template <class U>
819typename WriteHandle<T>::const_pointer_type
820WriteHandle<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 */
852template <class T>
853template <class AUXSTORE>
854typename WriteHandle<T>::const_pointer_type
855WriteHandle<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 */
904template <class T>
905template <class AUXSTORE>
906typename WriteHandle<T>::const_pointer_type
907WriteHandle<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 */
937template <class T>
938template <class AUXSTORE>
939StatusCode
940WriteHandle<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 */
997template <class T>
998WriteHandle<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 */
1015template <class T>
1016WriteHandle<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